The topic of User:B-bot/source is a topic of great relevance in today's society. This is an issue that affects a large number of people, and that arouses great interest and concern in the population. It is a topic that has been the subject of numerous studies, research and debates in recent years, demonstrating its importance and the need to address it appropriately. In this article, we will analyze User:B-bot/source in depth, exploring its causes, consequences and possible solutions, with the aim of offering a broad and complete vision of this very relevant topic.
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.)
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 {{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:
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 {{bots}} do not.
/// <summary>
/// This function will remove commented uses of the {{nobots}} or {{bots}} template so that they are
/// not considered in the BotEditPermitted() function.
/// </summary>
/// <param name="PageText"></param>
/// <param name="CommentStart"></param>
/// <param name="CommentEnd"></param>
/// <returns></returns>
private static String RemoveComment(String PageText, String CommentStart, String CommentEnd)
{
// Remove anything that is inside of <nowiki> ... <nowiki> 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;
}
/// <summary>
/// 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
/// </summary>
/// <param name="PageText">The page text to be parsed.</param>
/// <param name="BotUserName">This bot's username, this function will check for it in "allow" or "deny". IMPORTANT: </param>
/// <param name="BotNotificationType">The type of notification this bot is sending, e.g. nosource, nolicense, orfud.</param>
/// <returns>Returns true if this bot is permitted to edit the page and false if it is not.</returns>
public static bool BotEditPermitted(string PageText, string BotUserName, string BotNotificationType)
{
try
{
// Remove comments from consideration
PageText = RemoveComment(PageText, "<nowiki>", "</nowiki>");
PageText = RemoveComment(PageText, "<code>", "</code>");
PageText = RemoveComment(PageText, "<pre>", "</pre>");
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<string> commands = new List<string>();
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;
}