User:B-bot/source

The source code for User:B-bot uses the DotNetWikiBot framework. For the sake of brevity, I have omitted the things like my test functions or routine utility functions. (If a BAG member needs the whole thing, please let me know and perhaps I can email you the entire solution.)

__TOC__

Source code for individual tasks

Each task has its own class and they are all derived from a common class that has some shared functions that do things like checking for {{tl|bots}} tags, unescaping strings (which oddly, though I tried to find a built-in method, there didn't seem to be one), managing connections and delay times, and other miscellanea.

The source code for tasks of this bot can be found at these pages:

{{special:prefixindex/User:B-bot/source}}

Bot edit permitted

This is the code used by any bot I create to check to see if a bot is permitted to edit a user page to leave a notification. It handles some possibilities that the examples at {{tl|bots}} do not.

///

/// This function will remove commented uses of the {{nobots}} or {{bots}} template so that they are

/// not considered in the BotEditPermitted() function.

///

///

///

///

///

private static String RemoveComment(String PageText, String CommentStart, String CommentEnd)

{

// Remove anything that is inside of ... or

for (int nowiki = PageText.IndexOf(CommentStart, StringComparison.CurrentCultureIgnoreCase); 0 <= nowiki; nowiki = PageText.IndexOf(CommentStart, StringComparison.CurrentCultureIgnoreCase))

{

int endnowiki = PageText.IndexOf(CommentEnd, nowiki, StringComparison.CurrentCultureIgnoreCase);

if (0 <= endnowiki)

{

String NewText = "";

if (0 < nowiki)

{

NewText = PageText.Substring(0, nowiki);

}

if (endnowiki + CommentEnd.Length < PageText.Length)

{

NewText += PageText.Substring(endnowiki + CommentEnd.Length);

}

PageText = NewText;

}

else

{

// If the comment doesn't end, then we're done

return PageText;

}

}

return PageText;

}

///

/// This function attempts to parse the page text for the {{bots}} and {{nobots}} templates.

///

/// {{nobots}} will be checked for allow=BotUserName or optin=BotNotificationType

/// {{nobots}} can also be superseded by a {{bots|allow=BotUserName}} or {{bots|optin=BotNotificationType}}

///

/// {{bots|allow=Bot1,Bot2}} is interpreted as disallowing everything but Bot1 and Bot2 unless another {{bots}} statement is found

///

/// The page text to be parsed.

/// This bot's username, this function will check for it in "allow" or "deny". IMPORTANT:

/// The type of notification this bot is sending, e.g. nosource, nolicense, orfud.

/// Returns true if this bot is permitted to edit the page and false if it is not.

public static bool BotEditPermitted(string PageText, string BotUserName, string BotNotificationType)

{

try

{

// Remove comments from consideration

PageText = RemoveComment(PageText, "", "");

PageText = RemoveComment(PageText, "", "");

PageText = RemoveComment(PageText, "

", "
");

PageText = RemoveComment(PageText, "");

// Find all of the bots or nobots tags

MatchCollection matches = Regex.Matches(PageText, @"\{\{\s*(nobots|bots|deceased wikipedian)[^\}\{]*\}\}", RegexOptions.IgnoreCase);

if (null != matches && matches.Count > 0)

{

List commands = new List();

foreach (Match m in matches)

{

if (0 < m.Length)

{

// This is an individual bots tag to process

commands.Add(PageText.Substring(m.Index, m.Length).Trim());

}

}

// Rule #1: if any command denies this bot by name, then disallow the edit

if (!String.IsNullOrWhiteSpace(BotUserName))

{

foreach (String str in commands)

{

if (Regex.IsMatch(str, @"\{\{\s*(nobots|bots).*deny\s*\=\s*([^\|]*\,|)\s*" + Regex.Escape(BotUserName) + @"\s*(\,[^\|]*|)(\|.*|)\s*\}\}", RegexOptions.IgnoreCase))

{

return false;

}

}

}

// Rule #2 - if any command opts out of this notification type by name, then disallow the edit

if (!String.IsNullOrWhiteSpace(BotNotificationType))

{

foreach (String str in commands)

{

if (Regex.IsMatch(str, @"\{\{\s*(nobots|bots).*optout\s*\=\s*([^\|]*\,|)\s*" + Regex.Escape(BotNotificationType) + @"\s*(\,[^\|]*|)(\|.*|)\s*\}\}", RegexOptions.IgnoreCase))

{

return false;

}

}

}

// Rule #3 - if any command allows this bot by name, then allow the edit

if (!String.IsNullOrWhiteSpace(BotUserName))

{

foreach (String str in commands)

{

if (Regex.IsMatch(str, @"\{\{\s*(nobots|bots).*allow\s*\=\s*([^\|]*\,|)\s*" + Regex.Escape(BotUserName) + @"\s*(\,[^\|]*|)(\|.*|)\s*\}\}", RegexOptions.IgnoreCase))

{

return true;

}

}

}

// Rule #4 - if any command opts in to this notification type by name, then allow the edit

if (!String.IsNullOrWhiteSpace(BotNotificationType))

{

foreach (String str in commands)

{

if (Regex.IsMatch(str, @"\{\{\s*(nobots|bots).*optin\s*\=\s*([^\|]*\,|)\s*" + Regex.Escape(BotNotificationType) + @"\s*(\,[^\|]*|)(\|.*|)\s*\}\}", RegexOptions.IgnoreCase))

{

return true;

}

}

}

// Rule #5 - if we have a {{bots|allow=all}} or {{nobots|allow=all}}, then allow the edit (does anyone do this?)

foreach (String str in commands)

{

if (Regex.IsMatch(str, @"\{\{\s*(nobots|bots).*allow\s*\=\s*([^\|]*\,|)\s*all\s*(\,[^\|]*|)(\|.*|)\s*\}\}", RegexOptions.IgnoreCase))

{

return true;

}

}

// Rule #6 - if we have a {{(no)bots|allow=none}} or {{(no)bots|deny=all}}, then disallow the edit

foreach (String str in commands)

{

if (Regex.IsMatch(str, @"\{\{\s*(nobots|bots).*(allow\s*\=\s*([^\|]*\,|)\s*none|deny\s*\=\s*([^\|]*\,|)\s*all)\s*(\,[^\|]*|)(\|.*|)\s*\}\}", RegexOptions.IgnoreCase))

{

return false;

}

}

// Rule #7 - if we have a {{nobots}} of any sort or a {{deceased wikipedian}} and we haven't found one of the exemptions above, then disallow the edit

foreach (String str in commands)

{

if (Regex.IsMatch(str, @"\{\{\s*(nobots|deceased wikipedian).*\}\}", RegexOptions.IgnoreCase))

{

return false;

}

}

// Rule #8 - if we have a {{bots|allow=anything}} and we are not mentioned by name, then disallow the edit

foreach (String str in commands)

{

if (Regex.IsMatch(str, @"\{\{\s*(nobots|bots).*allow\s*\=\s*.*\}\}", RegexOptions.IgnoreCase))

{

return false;

}

}

}

}

catch (Exception ex)

{

Console.WriteLine(ex.ToString());

}

return true;

}