User:A2569875-bot/Code/Util.cs
外观
public class Site
{
public Site(string address, string userName,
string userPass, string userDomain) : address(address), userName(userName),
userPass(userPass), userDomain(userDomain) {}
public List<string> getPageNamesFromCategory(string category, int limit)
{
List<string> page_list = new List<string>();
int category_count = getCategoryCount(category);
if(category_count <= 0) return page_list;
string post_data_url = apiPath + "?action=query&list=categorymembers&cmtitle=Category:" + category + "&cmlimit=" +
(limit <= 0 ? 1: limit) + "&format=xml";
if(limit == 0) post_data_url = apiPath + "?action=query&list=categorymembers&cmtitle=Category:" + category + "&cmlimit=" + category_count + "&format=xml";
string tokenXmlSrc = PostDataAndGetResult(post_data_url, "", true, true);
XElement tokenXml, categoryToken;
try
{
tokenXml = XElement.Parse(tokenXmlSrc);
categoryToken = tokenXml.Element("query").Element("categorymembers");
foreach (var page_it in categoryToken.Elements())
{
//只作主名字空間
if (page_it.Attribute("ns").Value != "0") continue;
page_list.Add(page_it.Attribute("title").Value);
}
}
catch
{
}
return page_list;
}
public int getCategoryCount(string category)
{
List<string> page_list = new List<string>();
//參考[[mw:API:Categoryinfo]]
string post_data_url = apiPath + "?action=query&prop=categoryinfo&titles=Category:" + category + "&format=xml";
string tokenXmlSrc = PostDataAndGetResult(post_data_url, "", true, true);
XElement tokenXml, categoryToken;
try
{
tokenXml = XElement.Parse(tokenXmlSrc);
categoryToken = (tokenXml.Element("query").Element("pages").Elements().First<XElement>())
.Element("categoryinfo");
return Int32.Parse(categoryToken.Attribute("pages").Value);
}
catch
{
//反正等一下就return 0了
}
return 0;
}
//Bug 大魔王: "沒使用Https ,HttpS,httpssssss,Ssssssssssssssss!!!"
//Api-User-Agent = "A2569875 / 1.0(http://website, a2569875@yahoo.com.tw)"
private void LogIn()
{
if (!useApi)
{
string loginPageSrc = PostDataAndGetResult(indexPath +
"?title=Special:Userlogin", "", true, true);
string loginToken = "";
int loginTokenPos = loginPageSrc.IndexOf(
"<input type=\"hidden\" name=\"wpLoginToken\" value=\"");
if (loginTokenPos != -1)
loginToken = loginPageSrc.Substring(loginTokenPos + 48, 32);
string postData = string.Format("wpName={0}&wpPassword={1}&wpDomain={2}" +
"&wpLoginToken={3}&wpRemember=1&wpLoginattempt=Log+in",
Bot.UrlEncode(userName), Bot.UrlEncode(userPass),
Bot.UrlEncode(userDomain), Bot.UrlEncode(loginToken));
string respStr = PostDataAndGetResult(indexPath +
"?title=Special:Userlogin&action=submitlogin&type=login",
postData, true, false);
if (respStr.Contains("<div class=\"errorbox\">"))
throw new WikiBotException(
"\n\n" + Bot.Msg("Login failed. Check your username and password.") + "\n");
Console.WriteLine(Bot.Msg("Logged in as {0}."), userName);
}
else
{
string postData =
string.Format("lgname={0}&lgpassword={1}",
Bot.UrlEncode(userName), Bot.UrlEncode(userPass));
//Debug =
//string.Format("lgname={0}&lgpassword={1}&lgdomain={2}",
// Bot.UrlEncode(userName), Bot.UrlEncode(userPass),
// Bot.UrlEncode(userDomain));
//string postData = string.Format("lgname={0}&lgpassword={1}",
// Bot.UrlEncode(userName), Bot.UrlEncode(userPass));
string post_data_url = apiPath + "?action=query&meta=tokens&type=login&format=xml";
string tokenXmlSrc = PostDataAndGetResult(post_data_url, "", true,
//允許重定向
true);
XElement tokenXml;
try
{
tokenXml = XElement.Parse(tokenXmlSrc);
}
catch
{
//try to init
//執行到這裏的話,tokenXml將缺少初值
//這裡其實是為了設中斷點
}
string respStr = "", loginToken = "";
try
{
tokenXml = XElement.Parse(tokenXmlSrc);
//[[WP:製作機器人]]肯定已陳舊,需要更新
//不然照做只會Error、Error、Error、Error、Error、Error
loginToken = tokenXml.Element("query").Element("tokens")
.Attribute("logintoken").Value;
}
catch
{
// 和藍桌討論這裡貌似非問題
respStr = PostDataAndGetResult(apiPath +
"?action=login&format=xml", postData, true, true);
if (respStr.Contains("result=\"Success\""))
{
Console.WriteLine(Bot.Msg("Logged in as {0}."), userName);
return;
}
int tokenPos = respStr.IndexOf("token=\"");
if (tokenPos < 1)
throw new WikiBotException(
"\n\n" + Bot.Msg("Login failed. Check your username and password.") + "\n");
loginToken = respStr.Substring(tokenPos + 7, 32);
}
postData += "&lgtoken=" + Bot.UrlEncode(loginToken);
//postData += "&lgtoken=" + loginToken;
post_data_url = apiPath + "?action=login&format=xml";//&format=xml";
respStr = PostDataAndGetResult(post_data_url, postData, true, true);
if (!respStr.Contains("result=\"Success\""))
throw new WikiBotException(
"\n\n" + Bot.Msg("Login failed. Check your username and password.") + "\n");
Console.WriteLine(Bot.Msg("Logged in as {0}."), userName);
}
}
//Api-User-Agent = "A2569875 / 1.0(http://website, a2569875@yahoo.com.tw)"
public string PostDataAndGetResult(string pageURL, string postData, bool getCookies,
bool allowRedirect)
{
if (string.IsNullOrEmpty(pageURL))
throw new ArgumentNullException("pageURL", Bot.Msg("No URL specified."));
if (pageURL.StartsWith("/") && !pageURL.StartsWith("//"))
pageURL = address + pageURL;
int retryDelaySeconds = 60;
HttpWebResponse webResp = null;
for (int errorCounter = 0; true; errorCounter++)
{
HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(pageURL);
webReq.Proxy.Credentials = CredentialCache.DefaultCredentials;
webReq.UseDefaultCredentials = true;
webReq.ContentType = "application/x-www-form-urlencoded";
webReq.Headers.Add("Cache-Control", "no-cache, must-revalidate");
webReq.Headers.Add("Api-User-Agent", "A2569875 / 1.0(http://website, a2569875@yahoo.com.tw)");
//MyCoolTool/1.1 (https://example.org/MyCoolTool/; MyCoolTool@example.org) BasedOnSuperLib/1.4
webReq.UserAgent = "A2569875 / 1.0(http://website, a2569875@yahoo.com.tw)";
//Debug....
//webReq.UserAgent = "MyCoolTool/1.1 (https://example.org/MyCoolTool/; MyCoolTool@example.org) BasedOnSuperLib/1.4";
// webReq.Headers.Add("Api-User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36");
//webReq.Headers.Add("Api-User-Agent", "MyCoolTool/1.1 (https://example.org/MyCoolTool/; MyCoolTool@example.org) BasedOnSuperLib/1.4");
webReq.AllowAutoRedirect = allowRedirect;
if (cookies.Count == 0)
webReq.CookieContainer = new CookieContainer();
else
webReq.CookieContainer = cookies;
if (Bot.unsafeHttpHeaderParsingUsed == 0)
{
webReq.ProtocolVersion = HttpVersion.Version10;
webReq.KeepAlive = false;
}
if (!Bot.isRunningOnMono) webReq.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");
//Debug
//webReq.Method = "POST";
if (!string.IsNullOrEmpty(postData))
{
webReq.Method = WebRequestMethods.Http.Post;
//don't need.
//webReq.Timeout = 180000;
postData += "&maxlag=" + maxLag;
//Debug (和藍桌在IRC上討論的)
//Try any Encoding
//Encoding.UTF8
//Encoding.ASCII
byte[] postBytes = Encoding.UTF8.GetBytes(postData);
webReq.ContentLength = postBytes.Length;
Stream reqStrm = webReq.GetRequestStream();
reqStrm.Write(postBytes, 0, postBytes.Length);
reqStrm.Close();
}
try
{
webResp = (HttpWebResponse)webReq.GetResponse();
if (webResp.Headers["Retry-After"] != null)
throw new WebException("Service is unavailable due to high load.");
// API can return HTTP code 200 (OK) along with "Retry-After"
break;
}
catch (WebException e)
{
if (webResp == null)
throw;
if (webReq.AllowAutoRedirect == false &&
webResp.StatusCode == HttpStatusCode.Redirect) // Mono bug 636219 evasion
return "";
if (e.Message.Contains("Section=ResponseStatusLine"))
{ // Known Squid problem
Bot.SwitchUnsafeHttpHeaderParsing(true);
return PostDataAndGetResult(pageURL, postData, getCookies, allowRedirect);
}
if (webResp.Headers["Retry-After"] != null)
{ // Server is very busy
if (errorCounter > retryTimes)
throw;
// See https://www.mediawiki.org/wiki/Manual:Maxlag_parameter
int seconds;
Int32.TryParse(webResp.Headers["Retry-After"], out seconds);
if (seconds > 0)
retryDelaySeconds = seconds;
Console.Error.WriteLine(e.Message);
Console.Error.WriteLine(string.Format(Bot.Msg(
"Retrying in {0} seconds..."), retryDelaySeconds));
Bot.Wait(retryDelaySeconds);
}
else if (e.Status == WebExceptionStatus.ProtocolError)
{
int code = (int)webResp.StatusCode;
if (code == 500 || code == 502 || code == 503 || code == 504)
{
// Remote server problem, retry
if (errorCounter > retryTimes)
throw;
Console.Error.WriteLine(e.Message);
Console.Error.WriteLine(string.Format(Bot.Msg(
"Retrying in {0} seconds..."), retryDelaySeconds));
Bot.Wait(retryDelaySeconds);
}
else
throw;
}
else
throw;
}
}
Stream respStream = webResp.GetResponseStream();
if (webResp.ContentEncoding.ToLower().Contains("gzip"))
respStream = new GZipStream(respStream, CompressionMode.Decompress);
else if (webResp.ContentEncoding.ToLower().Contains("deflate"))
respStream = new DeflateStream(respStream, CompressionMode.Decompress);
if (getCookies == true)
{
Uri siteUri = new Uri(address);
foreach (Cookie cookie in webResp.Cookies)
{
if (cookie.Domain[0] == '.' &&
cookie.Domain.Substring(1) == siteUri.Host)
cookie.Domain = cookie.Domain.TrimStart(new char[] { '.' });
cookies.Add(cookie);
}
}
StreamReader strmReader = new StreamReader(respStream, Encoding.UTF8);
string respStr = strmReader.ReadToEnd();
strmReader.Close();
webResp.Close();
return respStr;
}
}