public string DelPageFromWatchlist(string item, string project) { // First, if this is not a wiktionary, uppercase the first letter if (!project.EndsWith("wiktionary")) { item = Ucfirst(item); } // If this is a local watchlist, translate the namespace if (project != "") { item = Project.TranslateNamespace(project, item); } if (IsWatchedArticle(item, project).Success) { using (IDbCommand dbCmd = dbcon.CreateCommand()) { dbCmd.CommandText = "DELETE FROM watchlist WHERE article='" + item.Replace("'", "''") + "' AND project='" + project + "'"; lock (dbtoken) dbCmd.ExecuteNonQuery(); return(Program.GetFormatMessage(16101, item, FriendlyProject(project), FriendlyList(10))); } } return(Program.GetFormatMessage(16009, item, FriendlyProject(project), FriendlyList(10))); }
public string ShowPageOnWatchlist(string item, string project) { // First, if this is not a wiktionary, uppercase the first letter if (!project.EndsWith("wiktionary")) { item = Ucfirst(item); } // If this is a local watchlist, translate the namespace if (project != "") { item = Project.TranslateNamespace(project, item); } using (IDbCommand cmd = dbcon.CreateCommand()) { cmd.CommandText = "SELECT adder, reason, expiry FROM watchlist WHERE article='" + item.Replace("'", "''") + "' AND project='" + project + "' AND ((expiry > '" + DateTime.Now.Ticks.ToString() + "') OR (expiry = '0')) LIMIT 1"; lock (dbtoken) { using (IDataReader idr = cmd.ExecuteReader()) if (idr.Read()) { string result = Program.GetFormatMessage(16004, item, FriendlyProject(project), FriendlyList(10), idr.GetString(0), ParseExpiryDate(idr.GetInt64(2)), idr.GetString(1)); return(result); } return(Program.GetFormatMessage(16009, item, FriendlyProject(project), FriendlyList(10))); } } }
public string AddPageToWatchlist(string item, string project, string adder, string reason, int expiry) { // First, if this is not a Wiktionary, uppercase the first letter if (!project.EndsWith("wiktionary")) { item = Ucfirst(item); } // If this is a local watchlist, translate the namespace if (project != "") { item = Project.TranslateNamespace(project, item); } using (IDbCommand cmd = dbcon.CreateCommand()) { // First, check if item is already on watchlist if (IsWatchedArticle(item, project).Success) { // Item is already on same watchlist, need to update cmd.CommandText = "UPDATE watchlist SET adder='" + adder.Replace("'", "''") + "', reason='" + reason.Replace("'", "''") + "', expiry='" + GetExpiryDate(expiry) + "' WHERE article='" + item.Replace("'", "''") + "' AND project='" + project + "'"; lock (dbtoken) cmd.ExecuteNonQuery(); return(Program.GetFormatMessage(16104, ShowPageOnWatchlist(item, project))); } // Item is not on the watchlist yet, can do simple insert cmd.CommandText = "INSERT INTO watchlist (article, project, adder, reason, expiry) VALUES('" + item.Replace("'", "''") + "', '" + project + "', '" + adder.Replace("'", "''") + "', '" + reason.Replace("'", "''") + "', '" + GetExpiryDate(expiry) + "')"; lock (dbtoken) cmd.ExecuteNonQuery(); return(Program.GetFormatMessage(16103, ShowPageOnWatchlist(item, project))); } }
void Rcirc_OnChannelMessage(object sender, IrcEventArgs e) { lastMessage = DateTime.Now; // Based on RCParser.py->parseRCmsg() // Example message from 2017-10-13 from #en.wikipedia // 01> #00314 [[ // 02> #00307 Special:Log/newusers // 03> #00314 ]] // 04> #0034 create2 // 05> #00310 // 06> #00302 // 07> #003 // 08> #0035 * // 09> #003 // 10> #00303 Ujju.19788 // 11> #003 // 12> #0035 * // 13> #003 // 14> #00310 created new account User:Upendhare // 15> #003 string strippedmsg = stripBold.Replace(stripColours.Replace(CVNBotUtils.ReplaceStrMax(e.Data.Message, '\x03', '\x04', 14), "\x03"), ""); string[] fields = strippedmsg.Split(new char[] { '\x03' }, 15); if (fields.Length == 15) { if (fields[14].EndsWith("\x03")) { fields[14] = fields[14].Substring(0, fields[14].Length - 1); } } else { // Probably really long article title or something that got cut off; we can't handle these return; } try { RCEvent rce; rce.eventtype = RCEvent.EventType.unknown; rce.blockLength = ""; rce.movedTo = ""; rce.project = e.Data.Channel.Substring(1); rce.title = Project.TranslateNamespace(rce.project, fields[2]); rce.url = CVNBotUtils.RootUrl(fields[6]); rce.user = fields[10]; Project project = ((Project)Program.prjlist[rce.project]); // At the moment, fields[14] contains IRC colour codes. For plain edits, remove just the \x03's. For logs, remove using the regex. Match titlemo = project.rSpecialLogRegex.Match(fields[2]); if (!titlemo.Success) { // This is a regular edit rce.minor = fields[4].Contains("M"); rce.newpage = fields[4].Contains("N"); rce.botflag = fields[4].Contains("B"); rce.eventtype = RCEvent.EventType.edit; rce.comment = fields[14].Replace("\x03", ""); } else { // This is a log edit; check for type string logType = titlemo.Groups[1].Captures[0].Value; // Fix comments rce.comment = stripColours2.Replace(fields[14], ""); switch (logType) { case "newusers": // Could be a user creating their own account, or a user creating a sockpuppet // Example message as of 2016-11-02 on #nl.wikipedia (with log comment after colon) // > [[Speciaal:Log/newusers]] create2 * BRPots * created new account Gebruiker:BRPwiki: eerder fout gemaakt // Example message as of 2016-11-02 on #nl.wikipedia (without log comment) // > [[Speciaal:Log/newusers]] create2 * Sherani koster * created new account Gebruiker:Rani farah koster // Example message as of 2017-10-13 on #en.wikipedia: // > [[Special:Log/newusers]] create2 * Ujju.19788 * created new account User:Upendhare if (fields[4].Contains("create2")) { Match mc2 = project.rCreate2Regex.Match(rce.comment); if (mc2.Success) { rce.title = mc2.Groups[1].Captures[0].Value; rce.eventtype = RCEvent.EventType.newuser2; } else { logger.Warn("Unmatched create2 event in " + rce.project + ": " + e.Data.Message); } } else { if (fields[4].Contains("autocreate")) { rce.eventtype = RCEvent.EventType.autocreate; } else { rce.eventtype = RCEvent.EventType.newuser; } } break; case "block": // Example message from October 2017 on #en.wikipedia: // > [[Special:Log/block]] reblock * Yamla * changed block settings for [[User:Jeb BushDid911]] (account creation blocked, email disabled, cannot edit own talk page) with an expiry time of indefinite: {{uw-ublock}} // // Example message from October 2017 on #en.wikipedia // > [[Special:Log/block]] reblock * DeltaQuad * changed block settings for [[User:208.111.64.0/19]] (anon. only, account creation blocked) with an expiry time of 06:21, February 2, 2019: {{colocationwebhost}} if (fields[4].Contains("unblock")) { Match ubm = project.runblockRegex.Match(rce.comment); if (ubm.Success) { rce.eventtype = RCEvent.EventType.unblock; rce.title = ubm.Groups["item1"].Captures[0].Value; try { rce.comment = ubm.Groups["comment"].Captures[0].Value; } catch (ArgumentOutOfRangeException) { } } else { logger.Warn("Unmatched block/unblock type in " + rce.project + ": " + e.Data.Message); return; } } else if (fields[4].Contains("reblock")) { Match rbm = project.rreblockRegex.Match(rce.comment); if (rbm.Success) { // Treat reblock the same as a new block for simplicity rce.eventtype = RCEvent.EventType.block; rce.title = rbm.Groups["item1"].Captures[0].Value; } else { logger.Warn("Unmatched block/reblock type in " + rce.project + ": " + e.Data.Message); return; } } else { Match bm = project.rblockRegex.Match(rce.comment); if (bm.Success) { rce.eventtype = RCEvent.EventType.block; rce.title = bm.Groups["item1"].Captures[0].Value; // Assume default value of 24 hours in case the on-wiki message override // is missing expiry ($2) from its interface messag rce.blockLength = "24 hours"; try { rce.blockLength = bm.Groups["item2"].Captures[0].Value; } catch (ArgumentOutOfRangeException) { } try { rce.comment = bm.Groups["comment"].Captures[0].Value; } catch (ArgumentOutOfRangeException) { } } else { logger.Warn("Unmatched block type in " + rce.project + ": " + e.Data.Message); return; } } break; case "protect": // Could be a protect, modifyprotect or unprotect; need to parse regex Match pm = project.rprotectRegex.Match(rce.comment); Match modpm = project.rmodifyprotectRegex.Match(rce.comment); Match upm = project.runprotectRegex.Match(rce.comment); if (pm.Success) { rce.eventtype = RCEvent.EventType.protect; rce.title = Project.TranslateNamespace(rce.project, pm.Groups["item1"].Captures[0].Value); try { rce.comment = pm.Groups["comment"].Captures[0].Value; } catch (ArgumentOutOfRangeException) { } } else if (modpm.Success) { rce.eventtype = RCEvent.EventType.modifyprotect; rce.title = Project.TranslateNamespace(rce.project, modpm.Groups["item1"].Captures[0].Value); try { rce.comment = modpm.Groups["comment"].Captures[0].Value; } catch (ArgumentOutOfRangeException) { } } else { if (upm.Success) { rce.eventtype = RCEvent.EventType.unprotect; rce.title = Project.TranslateNamespace(rce.project, upm.Groups["item1"].Captures[0].Value); try { rce.comment = upm.Groups["comment"].Captures[0].Value; } catch (ArgumentOutOfRangeException) { } } else { logger.Warn("Unmatched protect type in " + rce.project + ": " + e.Data.Message); return; } } break; case "rights": // Ignore event return; //break; case "delete": // Could be a delete or restore; need to parse regex Match dm = project.rdeleteRegex.Match(rce.comment); if (dm.Success) { rce.eventtype = RCEvent.EventType.delete; rce.title = Project.TranslateNamespace(rce.project, dm.Groups["item1"].Captures[0].Value); try { rce.comment = dm.Groups["comment"].Captures[0].Value; } catch (ArgumentOutOfRangeException) { } } else { Match udm = project.rrestoreRegex.Match(rce.comment); if (udm.Success) { rce.eventtype = RCEvent.EventType.restore; rce.title = Project.TranslateNamespace(rce.project, udm.Groups["item1"].Captures[0].Value); try { rce.comment = udm.Groups["comment"].Captures[0].Value; } catch (ArgumentOutOfRangeException) { } } else { // Could be 'revision' (change visibility of revision) or something else // Ignore event return; } } break; case "upload": Match um = project.ruploadRegex.Match(rce.comment); if (um.Success) { rce.eventtype = RCEvent.EventType.upload; rce.title = Project.TranslateNamespace(rce.project, um.Groups["item1"].Captures[0].Value); try { rce.comment = um.Groups["comment"].Captures[0].Value; } catch (ArgumentOutOfRangeException) { } } else { // Could be 'overwrite' (upload new version) or something else // Ignore event return; } break; case "move": //Is a move rce.eventtype = RCEvent.EventType.move; //Check "move over redirect" first: it's longer, and plain "move" may match both (e.g., en-default) Match mrm = project.rmoveredirRegex.Match(rce.comment); if (mrm.Success) { rce.title = Project.TranslateNamespace(rce.project, mrm.Groups["item1"].Captures[0].Value); rce.movedTo = Project.TranslateNamespace(rce.project, mrm.Groups["item2"].Captures[0].Value); //We use the unused blockLength field to store our "moved from" URL rce.blockLength = CVNBotUtils.RootUrl(project.rooturl) + "wiki/" + CVNBotUtils.WikiEncode(mrm.Groups["item1"].Captures[0].Value); try { rce.comment = mrm.Groups["comment"].Captures[0].Value; } catch (ArgumentOutOfRangeException) { } } else { Match mm = project.rmoveRegex.Match(rce.comment); if (mm.Success) { rce.title = Project.TranslateNamespace(rce.project, mm.Groups["item1"].Captures[0].Value); rce.movedTo = Project.TranslateNamespace(rce.project, mm.Groups["item2"].Captures[0].Value); //We use the unused blockLength field to store our "moved from" URL rce.blockLength = CVNBotUtils.RootUrl(project.rooturl) + "wiki/" + CVNBotUtils.WikiEncode(mm.Groups["item1"].Captures[0].Value); try { rce.comment = mm.Groups["comment"].Captures[0].Value; } catch (ArgumentOutOfRangeException) { } } else { logger.Warn("Unmatched move type in " + rce.project + ": " + e.Data.Message); return; } } break; case "import": //rce.eventtype = RCEvent.EventType.import; // Ignore event return; //break; default: // Ignore event return; } // These flags don't apply to log events, but must be initialized rce.minor = false; rce.newpage = false; rce.botflag = false; } // Deal with the diff size Match n = rszDiff.Match(fields[13]); if (n.Success) { if (n.Groups[1].Captures[0].Value == "+") { rce.szdiff = Convert.ToInt32(n.Groups[2].Captures[0].Value); } else { rce.szdiff = 0 - Convert.ToInt32(n.Groups[2].Captures[0].Value); } } else { rce.szdiff = 0; } try { Program.ReactToRCEvent(rce); } catch (Exception exce) { logger.Error("Failed to handle RCEvent", exce); Program.BroadcastDD("ERROR", "ReactorException", exce.Message, e.Data.Channel + " " + e.Data.Message); } } catch (ArgumentOutOfRangeException eor) { // Broadcast this for Distributed Debugging logger.Error("Failed to process incoming message", eor); Program.BroadcastDD("ERROR", "RCR_AOORE", eor.Message, e.Data.Channel + "/" + e.Data.Message + "Fields: " + fields); } }