internal static void RemindExpiries(DateTime dateExpiry) { Organizations orgs = Organizations.GetAll(); foreach (Organization org in orgs) { Memberships memberships = Memberships.GetExpiring(org, dateExpiry); // Mail each expiring member foreach (Membership membership in memberships) { try { SendReminderMail(membership); PWLog.Write(PWLogItem.Person, membership.PersonId, PWLogAction.MembershipRenewReminder, "Mail was sent to " + membership.Person.Mail + " reminding to renew membership in " + membership.Organization.Name + ".", string.Empty); } catch (Exception ex) { ExceptionMail.Send( new Exception("Failed to create reminder mail for person " + membership.PersonId, ex)); } } } }
private static void OnMondayMorning() { try { // Detect and log any forex difference exceeding 100 cents. FinancialAccounts allAccounts = FinancialAccounts.GetAll(); // across ALL ORGS! foreach (FinancialAccount account in allAccounts) { // For every account, if it's based on foreign currency, check for forex gains/losses if (account.ForeignCurrency != null) { account.CheckForexProfitLoss(); } } } catch (Exception e) { ExceptionMail.Send(e, true); if (testMode) { Console.WriteLine(e.ToString()); } } }
public static void Run() { Database database = new Database(Globals.DatabaseConnectString); ForumDatabase forumDatabase = new ForumDatabase(Globals.ForumDatabaseConnectString); Hashtable memberAccounts = new Hashtable(); Member[] members = database.GetAllMembers(); foreach (Member member in members) { try { if (member.ForumAccountId != 0) { if (!forumDatabase.IsPartyMember(member.ForumAccountId)) { // This guy is not listed as a party member, but should be. forumDatabase.SetPartyMember(member.ForumAccountId); } memberAccounts [member.ForumAccountId] = true; } } catch (Exception) { // The forum account probably doesn't exist. Just remove it from the profile. try { database.SetMemberForumAccountId(member.MemberId, 0); } catch (Exception e2) { ExceptionMail.Send(e2); } } } // Now that we have flagged all member accounts as member accounts, flag the rest as // non-party members. int[] accountIds = forumDatabase.GetAccountList(); foreach (int accountId in accountIds) { if (!memberAccounts.ContainsKey(accountId)) { if (forumDatabase.IsPartyMember(accountId)) { forumDatabase.SetPartyNonmember(accountId); } } } }
private static void OnEveryTenSeconds() { try { BotLog.Write(0, "MainCycle", "Ten-second entry"); SystemSettings.HeartbeatBackend = (ulong)DateTime.UtcNow.ToUnix(); CommsTransmitter.Run(); BroadcastTimestamp(); try { /*TestTrace("Running EventProcessor.Run()..."); * EventProcessor.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running MailResolver.Run()..."); * MailResolver.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running MailProcessor.Run()..."); * MailProcessor.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } BotLog.Write(0, "MainCycle", "Ten-second exit"); } catch (Exception e) { ExceptionMail.Send(e, true); } }
private static void OnEveryTenSeconds() { try { BotLog.Write(0, "MainCycle", "Ten-second entry"); CommsTransmitter.Run(); try { /*TestTrace("Running EventProcessor.Run()..."); * EventProcessor.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running MailResolver.Run()..."); * MailResolver.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running MailProcessor.Run()..."); * MailProcessor.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } BotLog.Write(0, "MainCycle", "Ten-second exit"); } catch (Exception e) { ExceptionMail.Send(e, true); } }
private static void OnTuesdayMorning() { try { //TestTrace("Running ActivityMailer.Run()..."); // PirateWeb.Utility.BotCode.ActivityMailer.Run(); //TestTrace(" done.\r\n"); } catch (Exception e) { ExceptionMail.Send(e, true); if (testMode) { Console.WriteLine(e.ToString()); } } }
private static void OnMondayMorning() { try { Dictionary <int, bool> accountTested = new Dictionary <int, bool>(); // Check the bitcoin hotwallets for forex profit/loss. Organizations allOrganizations = Organizations.GetAll(); foreach (Organization organization in allOrganizations) { FinancialAccount hotWalletAccount = organization.FinancialAccounts.AssetsBitcoinHot; if (hotWalletAccount != null) { BitcoinUtility.CheckHotwalletForexProfitLoss(hotWalletAccount); accountTested[hotWalletAccount.Identity] = true; } } // Detect and log any forex difference exceeding 100 cents. FinancialAccounts allAccounts = FinancialAccounts.GetAll(); // across ALL ORGS! foreach (FinancialAccount account in allAccounts) { // For every account, if it's based on foreign currency, and not already checked, // then check for forex gains/losses if (account.ForeignCurrency != null && !accountTested.ContainsKey(account.Identity)) { account.CheckForexProfitLoss(); } } } catch (Exception e) { ExceptionMail.Send(e, true); if (testMode) { Console.WriteLine(e.ToString()); } } }
/// <summary> /// Asynchronous callback method. Not in use. /// </summary> /// <param name="result"></param> internal static void MessageSent(IAsyncResult result) { MailTransmissionDelegate asyncTransmitter = (MailTransmitter.MailTransmissionDelegate)result.AsyncState; try { asyncTransmitter.EndInvoke(result); } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.ToString()); ExceptionMail.Send(e); } lock (lockObject) { outstandingTransmissions--; } }
private static void OnMondayMorning() { try { // Detect and log any forex difference exceeding 100 cents. FinancialAccounts allAccounts = FinancialAccounts.GetAll(); // across ALL ORGS! foreach (FinancialAccount account in allAccounts) { // For every account, if it's based on foreign currency, check for forex gains/losses if (account.ForeignCurrency != null) { account.CheckForexProfitLoss(); } } // Also check the bitcoin hotwallets for forex profit/loss as a special case of the above. Organizations allOrganizations = Organizations.GetAll(); foreach (Organization organization in allOrganizations) { FinancialAccount hotWalletAccount = organization.FinancialAccounts.AssetsBitcoinHot; if (hotWalletAccount != null) { BitcoinUtility.CheckHotwalletForexProfitLoss(hotWalletAccount); } } } catch (Exception e) { ExceptionMail.Send(e, true); if (testMode) { Console.WriteLine(e.ToString()); } } }
private static void OnEveryFiveMinutes() { try { BotLog.Write(0, "MainCycle", "Five-minute entry"); try { /*BotLog.Write(1, "FiveMinute", "Starting press release checker"); * TestTrace("Running PressReleaseChecker.Run()..."); * PressReleaseChecker.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*BotLog.Write(1, "FiveMinute", "Starting newsletter checker"); * TestTrace("Running NewsletterChecker.Run()..."); * NewsletterChecker.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*BotLog.Write(1, "FiveMinute", "Starting turnaround tracker"); * TestTrace("Running TurnaroundTracker.Run()..."); * TurnaroundTracker.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { // TestTrace(" done.\r\nRunning UpdateStatsCache.Run()..."); // UpdateStatsCache.Run(); /*TestTrace(" done.\r\nRunning TranslateUrls()..."); * TranslateUrls();*/ // Added during election rush 2010: clean up support database every five minutes instead of once a day // SMS notifications for bounces are turned off, so people don't get SMS notifications in the middle of the night } catch (Exception e) { TraceAndReport(e); } try { /*BotLog.Write(1, "FiveMinute", "Closing delay warnings"); * TestTrace("Running SupportDatabase.CloseDelayWarnings()..."); * SupportDatabase.CloseDelayWarnings(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running SupportDatabase.NotifyBouncingEmails()..."); * BotLog.Write(1, "FiveMinute", "Notifying bouncing emails"); * SupportDatabase.NotifyBouncingEmails(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running SupportMailReview.Run()..."); * BotLog.Write(1, "FiveMinute", "Running support mail review"); * SupportMailReview.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } BotLog.Write(0, "MainCycle", "Five-minute exit"); } catch (Exception e) { ExceptionMail.Send(e, true); TestTrace(e.ToString()); } }
private static void Main(string[] args) { testMode = false; UnixSignal[] killSignals = { new UnixSignal(Signum.SIGINT), new UnixSignal(Signum.SIGTERM) }; BotLog.Write(0, "MainCycle", string.Empty); BotLog.Write(0, "MainCycle", "-----------------------------------------------"); BotLog.Write(0, "MainCycle", string.Empty); if (args.Length > 0) { if (args[0].ToLower() == "test") { /* * BotLog.Write(0, "MainCycle", "Running self-tests"); * HeartBeater.Instance.Beat(heartbeatFile); // Otherwise Heartbeater.Beat() will fail in various places * * testMode = true; * Console.WriteLine("Testing All Maintenance Processes (except membership-changing ones)."); * PWLog.Write(PWLogItem.None, 0, PWLogAction.SystemTest, string.Empty, string.Empty); * * Console.WriteLine("\r\n10-second intervals:"); * OnEveryTenSeconds(); * Console.WriteLine("\r\nEvery minute:"); * OnEveryMinute(); * Console.WriteLine("\r\nEvery five minutes:"); * OnEveryFiveMinutes(); * Console.WriteLine("\r\nEvery hour:"); * OnEveryHour(); * Console.WriteLine("\r\nNoon:"); * OnNoon(); * Console.WriteLine("\r\nMidnight:"); * OnMidnight(); */ Console.WriteLine("Testing database access..."); Console.WriteLine(SwarmDb.GetDatabaseForReading().GetPerson(1).Name); Console.WriteLine(SwarmDb.GetDatabaseForReading().GetPerson(1).PasswordHash); Console.WriteLine("Creating OutboundComm..."); OutboundComm.CreateNotification(null, NotificationResource.System_Startup); Console.WriteLine("Transmitting..."); OutboundComms comms = OutboundComms.GetOpen(); Console.WriteLine("{0} open items in outbound comms.", comms.Count); foreach (OutboundComm comm in comms) { if (comm.TransmitterClass != "Swarmops.Utility.Communications.CommsTransmitterMail") { throw new NotImplementedException(); } ICommsTransmitter transmitter = new CommsTransmitterMail(); OutboundCommRecipients recipients = comm.Recipients; PayloadEnvelope envelope = PayloadEnvelope.FromXml(comm.PayloadXml); foreach (OutboundCommRecipient recipient in recipients) { transmitter.Transmit(envelope, recipient.Person); } } Console.Write("\r\nAll tests run. Waiting for mail queue to flush... "); while (!MailTransmitter.CanExit) { Thread.Sleep(50); } Console.WriteLine("done."); BotLog.Write(0, "MainCycle", "Exiting self-tests"); return; } if (args[0].ToLower() == "console") { Console.WriteLine("\r\nRunning Swarmops-Backend in CONSOLE mode.\r\n"); // ------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------- // ----------------------- INSERT ANY ONE-OFF ACTIONS HERE ------------------------- Console.Write("\r\nWaiting for mail queue to flush... "); while (!MailTransmitter.CanExit) { Thread.Sleep(50); } Console.WriteLine("done."); return; } if (args[0].ToLower() == "rsm") { Console.WriteLine("Testing character encoding: räksmörgås RÄKSMÖRGÅS"); return; } } /* * MailMessage message = new MailMessage(); * message.From = new MailAddress(Strings.MailSenderAddress, Strings.MailSenderName); * message.To.Add (new MailAddress ("*****@*****.**", "Rick Falkvinge (Piratpartiet)")); * message.Subject = "Räksmörgåsarnas ékÖNÖMÏåvdëlnïng"; * message.Body = "Hejsan hoppsan Räksmörgåsar."; * message.BodyEncoding = Encoding.Default; * message.SubjectEncoding = Encoding.Default; * * SmtpClient smtpClient = new SmtpClient ("localhost"); * smtpClient.Credentials = null; // mono bug * smtpClient.Send (message);*/ Console.WriteLine(" * Swarmops Backend starting"); BotLog.Write(0, "MainCycle", "Backend STARTING"); OutboundComm.CreateNotification(null, NotificationResource.System_Startup); // Checking for schemata upgrade DatabaseMaintenance.UpgradeSchemata(); // Check for existence of installation ID. If not, create one. Warning: has privacy implications when communicated. if (Persistence.Key["SwarmopsInstallationId"] == string.Empty) { Persistence.Key["SwarmopsInstallationId"] = Guid.NewGuid().ToString(); } DateTime cycleStartTime = DateTime.Now; int lastSecond = cycleStartTime.Second; int lastMinute = cycleStartTime.Minute; int lastHour = cycleStartTime.Hour; bool exitFlag = false; while (!exitFlag) // exit is handled by signals handling at end of loop { BotLog.Write(0, "MainCycle", "Cycle Start"); cycleStartTime = DateTime.Now; try { OnEveryTenSeconds(); if (cycleStartTime.Second < lastSecond) { OnEveryMinute(); if (cycleStartTime.Minute % 5 == 0) { OnEveryFiveMinutes(); } } if (cycleStartTime.Minute < lastMinute) { OnEveryHour(); if (DateTime.Now.Hour == 10 && DateTime.Today.DayOfWeek == DayOfWeek.Tuesday) { OnTuesdayMorning(); } } if (cycleStartTime.Hour >= 12 && lastHour < 12) { OnNoon(); } if (cycleStartTime.Hour < lastHour) { OnMidnight(); } } catch (Exception e) { // Note each "OnEvery..." catches its own errors and sends Exception mails, // so that failure in one should not stop the others from running. This particular // code should never run. ExceptionMail.Send(new Exception("Failed in swarmops-backend main loop", e), true); } lastSecond = cycleStartTime.Second; lastMinute = cycleStartTime.Minute; lastHour = cycleStartTime.Hour; // Wait for a maximum of ten seconds while (DateTime.Now < cycleStartTime.AddSeconds(10) && !exitFlag) { // block until a SIGINT or SIGTERM signal is generated, or one second has passed. int signalIndex = UnixSignal.WaitAny(killSignals, 1000); if (signalIndex < 1000) { exitFlag = true; Console.WriteLine("Caught signal " + killSignals[signalIndex].Signum + ", exiting"); BotLog.Write(0, "MainCycle", "EXIT SIGNAL (" + killSignals[signalIndex].Signum + "), terminating backend"); } } } Console.WriteLine(" * Swarmops Backend stopping"); BotLog.Write(0, "MainCycle", "BACKEND EXITING, sending backend-termination notices"); /* * if (HeartBeater.Instance.WasKilled) * { * // removed unconditional delete, cron job that restarts bot uses it to know that it is intentionally down. * ExceptionMail.Send(new Exception("HeartBeater triggered restart of Swarmops Backend. Will commence after 800 seconds."), false); * }*/ BotLog.Write(0, "MainCycle", "...done"); /* * while (!MailTransmitter.CanExit) * { * System.Threading.Thread.Sleep(50); * }*/ Thread.Sleep(2000); }
public static void Run() { BotLog.Write(1, "SeForumCheck", "Entering"); Memberships memberships = Memberships.ForOrganization(Organization.PPSE); IForumDatabase forumDatabase = SwedishForumDatabase.GetDatabase(); int[] accountIds; try { accountIds = forumDatabase.GetAccountList(); } catch (Exception e) { ExceptionMail.Send(new Exception("Failed to connect to vBulletin", e), true); BotLog.Write(1, "SeForumCheck", "Failed to connect -- exiting"); return; } BotLog.Write(1, "SeForumCheck", "Primed db - entering promotion cycle"); Dictionary <int, bool> memberAccountLookup = new Dictionary <int, bool>(); // This is kind of suboptimal, but hey, it only runs once a night in the wolf hour. Person currentMember = null; foreach (Membership membership in memberships) { if (!membership.Active) { continue; } currentMember = membership.Person; try { if (currentMember.SwedishForumAccountId != 0) { if (!forumDatabase.IsPartyMember(currentMember.SwedishForumAccountId)) { // This guy is not listed as a party member, but should be. BotLog.Write(2, "SeForumCheck", "Promoting " + currentMember.Name); forumDatabase.SetPartyMember(currentMember.SwedishForumAccountId); } memberAccountLookup[currentMember.SwedishForumAccountId] = true; } } catch (Exception e) { // The forum account probably doesn't exist. Just remove it from the profile. BotLog.Write(2, "SeForumCheck", "Exception reading " + currentMember.Name + ": " + e.ToString()); try { currentMember.SwedishForumAccountId = 0; } catch (Exception e2) { string logMessage = "Exception removing " + currentMember.Name + "'s forum account: " + e2.ToString(); BotLog.Write(2, "SeForumCheck", logMessage); ExceptionMail.Send(new Exception(logMessage, e2)); } } } // Now that we have flagged all member accounts as member accounts, flag the rest as // non-party members. BotLog.Write(1, "SeForumCheck", "Promotion cycle done - entering demotion cycle"); foreach (int accountId in accountIds) { if (!memberAccountLookup.ContainsKey(accountId)) { if (forumDatabase.IsPartyMember(accountId)) { BotLog.Write(2, "SeForumCheck", "Demoting forum account " + forumDatabase.GetAccountName(accountId)); forumDatabase.SetPartyNonmember(accountId); } } } BotLog.Write(1, "SeForumCheck", "Demotion cycle complete -- exiting"); }
private static void TraceAndReport(Exception e) { TestTrace(" failed.\r\n"); ExceptionMail.Send(e, true); TestTrace(e.ToString()); }
public static void RemindExpiriesMail() { // Get expiring Console.WriteLine("Inside RemindExpiriesMail()"); Organizations orgs = Organizations.GetAll(); Dictionary <int, bool> personLookup = new Dictionary <int, bool>(); Dictionary <string, int> dateLookup = new Dictionary <string, int>(); DateTime lowerBound = DateTime.Today; DateTime upperBound = lowerBound.AddDays(31); List <string> failedReminders = new List <string>(); int weekDayInteger = (int)DateTime.Today.DayOfWeek; foreach (Organization org in orgs) { Memberships memberships = Memberships.GetExpiring(org, lowerBound, upperBound); foreach (Membership membership in memberships) { if (membership.OrganizationId % 7 != weekDayInteger) { continue; } try { Console.Write("Reminding " + membership.Person.Canonical + " about " + membership.Organization.Name + "."); SendReminderMail(membership); Console.Write("."); PWLog.Write(PWLogItem.Person, membership.PersonId, PWLogAction.MembershipRenewReminder, "Mail was sent to " + membership.Person.Mail + " reminding to renew membership in " + membership.Organization.Name + ".", string.Empty); Console.Write("."); string dateString = membership.Expires.ToString("yyyy-MM-dd"); if (!dateLookup.ContainsKey(dateString)) { dateLookup[dateString] = 0; } dateLookup[dateString]++; Console.WriteLine(" done."); } catch (Exception x) { string logText = "FAILED sending mail to " + membership.Person.Mail + " for reminder of pending renewal in " + membership.Organization.Name + "."; failedReminders.Add(membership.Person.Canonical); PWLog.Write(PWLogItem.Person, membership.PersonId, PWLogAction.MembershipRenewReminder, logText, string.Empty); ExceptionMail.Send(new Exception(logText, x)); } } } string notifyBody = String.Format("Sending renewal reminders to {0} people:\r\n\r\n", personLookup.Count); Console.WriteLine("Sending renewal reminders to {0} people", personLookup.Count); List <string> dateSummary = new List <string>(); int total = 0; foreach (string dateString in dateLookup.Keys) { dateSummary.Add(string.Format("{0}: {1,5}", dateString, dateLookup[dateString])); total += dateLookup[dateString]; } dateSummary.Sort(); foreach (string dateString in dateSummary) { notifyBody += dateString + "\r\n"; Console.WriteLine(dateString); } notifyBody += string.Format("Total sent: {0,5}\r\n\r\n", total); Console.WriteLine("Total sent: {0,5}\r\n\r\n", total); notifyBody += "FAILED reminders:\r\n"; Console.WriteLine("FAILED reminders:"); foreach (string failed in failedReminders) { notifyBody += failed + "\r\n"; Console.WriteLine(failed); } if (failedReminders.Count == 0) { notifyBody += "none.\r\n"; Console.WriteLine("none."); } /* no. just no. we should do a global search for "FromIdentity(1)" * Person.FromIdentity(1).SendOfficerNotice("Reminders sent today", notifyBody, 1); */ }
private static void Main(string[] args) { // Are we running yet? if (!SystemSettings.DatabaseInitialized) { // will restart the service every 15s until db initialized on OOBE // also, the read of DatabaseInitialized can and will fail if // we're not initalized enough to even have a database throw new InvalidOperationException(); } // Checking for schemata upgrade first of all, after seeing that db exists int startupDbVersion = Database.SwarmDb.DbVersion; DatabaseMaintenance.UpgradeSchemata(); testMode = false; SystemSettings.BackendHostname = Dns.GetHostName(); // Other one-time initializations FinancialTransactions.FixAllUnsequenced(); SupportFunctions.OperatingTopology = OperatingTopology.Backend; // Begin main loop UnixSignal[] killSignals = null; if (!Debugger.IsAttached) { killSignals = new UnixSignal[] { new UnixSignal(Signum.SIGINT), new UnixSignal(Signum.SIGTERM) }; } BotLog.Write(0, "MainCycle", string.Empty); BotLog.Write(0, "MainCycle", "-----------------------------------------------"); BotLog.Write(0, "MainCycle", string.Empty); if (args.Length > 0) { if (args[0].ToLower() == "test") { /* * BotLog.Write(0, "MainCycle", "Running self-tests"); * HeartBeater.Instance.Beat(heartbeatFile); // Otherwise Heartbeater.Beat() will fail in various places * * testMode = true; * Console.WriteLine("Testing All Maintenance Processes (except membership-changing ones)."); * PWLog.Write(PWLogItem.None, 0, PWLogAction.SystemTest, string.Empty, string.Empty); * * Console.WriteLine("\r\n10-second intervals:"); * OnEveryTenSeconds(); * Console.WriteLine("\r\nEvery minute:"); * OnEveryMinute(); * Console.WriteLine("\r\nEvery five minutes:"); * OnEveryFiveMinutes(); * Console.WriteLine("\r\nEvery hour:"); * OnEveryHour(); * Console.WriteLine("\r\nNoon:"); * OnNoon(); * Console.WriteLine("\r\nMidnight:"); * OnMidnight(); */ Console.WriteLine("Testing database access..."); Console.WriteLine(SwarmDb.GetDatabaseForReading().GetPerson(1).Name); Console.WriteLine(SwarmDb.GetDatabaseForReading().GetPerson(1).PasswordHash); Console.WriteLine("Creating OutboundComm..."); OutboundComm.CreateNotification(null, NotificationResource.System_Startup_Backend); Console.WriteLine("Transmitting..."); OutboundComms comms = OutboundComms.GetOpen(); Console.WriteLine("{0} open items in outbound comms.", comms.Count); foreach (OutboundComm comm in comms) { if (comm.TransmitterClass != "Swarmops.Utility.Communications.CommsTransmitterMail") { throw new NotImplementedException(); } ICommsTransmitter transmitter = new CommsTransmitterMail(); OutboundCommRecipients recipients = comm.Recipients; PayloadEnvelope envelope = PayloadEnvelope.FromXml(comm.PayloadXml); foreach (OutboundCommRecipient recipient in recipients) { transmitter.Transmit(envelope, recipient.Person); } } Console.Write("\r\nAll tests run. Waiting for mail queue to flush... "); while (!MailTransmitter.CanExit) { Thread.Sleep(50); } Console.WriteLine("done."); BotLog.Write(0, "MainCycle", "Exiting self-tests"); return; } if (args[0].ToLower() == "console") { Console.WriteLine("\r\nRunning Swarmops-Backend in CONSOLE mode.\r\n"); // ------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------- // ------------------------------------------------------------------------------------- // ----------------------- INSERT ANY ONE-OFF ACTIONS HERE ------------------------- Console.Write("\r\nWaiting for mail queue to flush... "); while (!MailTransmitter.CanExit) { Thread.Sleep(50); } Console.WriteLine("done."); return; } if (args[0].ToLowerInvariant() == "pdfregen") { if (args.Length > 1) { int docId = Int32.Parse(args[1]); PdfProcessor.Rerasterize(Document.FromIdentity(docId)); } else { Console.WriteLine("Regenerating all bitmaps from PDF uploads."); PdfProcessor.RerasterizeAll(); Console.WriteLine("Done."); } return; } if (args[0].ToLower() == "rsm") { Console.WriteLine("Testing character encoding: räksmörgås RÄKSMÖRGÅS"); return; } } /* * MailMessage message = new MailMessage(); * message.From = new MailAddress(Strings.MailSenderAddress, Strings.MailSenderName); * message.To.Add (new MailAddress ("*****@*****.**", "Rick Falkvinge (Piratpartiet)")); * message.Subject = "Räksmörgåsarnas ékÖNÖMÏåvdëlnïng"; * message.Body = "Hejsan hoppsan Räksmörgåsar."; * message.BodyEncoding = Encoding.Default; * message.SubjectEncoding = Encoding.Default; * * SmtpClient smtpClient = new SmtpClient ("localhost"); * smtpClient.Credentials = null; // mono bug * smtpClient.Send (message);*/ Console.WriteLine(" * Swarmops Backend starting"); BotLog.Write(0, "MainCycle", "Backend STARTING"); // Disable certificate checking due to Mono not installing with a certificate repository - this is UTTERLY broken SupportFunctions.DisableSslCertificateChecks(); // MONO BUG/MISFEATURE: Mono has no root certificates, so can't verify cert // Tell sysop we're starting OutboundComm.CreateNotification(null, NotificationResource.System_Startup_Backend); // Check for existence of installation ID. If not, create one. Warning: has privacy implications when communicated. if (Persistence.Key["SwarmopsInstallationId"] == string.Empty) { Persistence.Key["SwarmopsInstallationId"] = Guid.NewGuid().ToString(); } // Check for existence of bitcoin hotwallet root BitcoinUtility.VerifyBitcoinHotWallet(); // Initialize backend socket server int backendSocketPort = SystemSettings.WebsocketPortBackend; _socketServer = new WebSocketServer(backendSocketPort); _socketServer.AddWebSocketService <BackendServices>("/Backend"); _socketServer.Start(); // Initialize socket client to Blockchain.Info (pending our own services) using ( _blockChainInfoSocket = new WebSocket("wss://ws.blockchain.info/inv?api_code=" + SystemSettings.BlockchainSwarmopsApiKey)) { // Begin maintenance loop DateTime cycleStartTime = DateTime.UtcNow; DateTime cycleEndTime; int lastSecond = cycleStartTime.Second; int lastMinute = cycleStartTime.Minute; int lastHour = cycleStartTime.Hour; bool exitFlag = false; _blockChainInfoSocket.OnOpen += new EventHandler(OnBlockchainOpen); _blockChainInfoSocket.OnError += new EventHandler <ErrorEventArgs>(OnBlockchainError); _blockChainInfoSocket.OnClose += new EventHandler <CloseEventArgs>(OnBlockchainClose); _blockChainInfoSocket.OnMessage += new EventHandler <MessageEventArgs>(OnBlockchainMessage); _blockChainInfoSocket.Connect(); while (!exitFlag) // exit is handled by signals handling at end of loop { BotLog.Write(0, "MainCycle", "Cycle Start"); cycleStartTime = DateTime.UtcNow; cycleEndTime = cycleStartTime.AddSeconds(10); try { OnEveryTenSeconds(); if (cycleStartTime.Second < lastSecond) { OnEveryMinute(); if (cycleStartTime.Minute % 5 == 0) { OnEveryFiveMinutes(); } } if (cycleStartTime.Minute < lastMinute) { OnEveryHour(); if (DateTime.Now.Hour == 10 && DateTime.Today.DayOfWeek == DayOfWeek.Tuesday) { OnTuesdayMorning(); } if (DateTime.Now.Hour == 7 && DateTime.Today.DayOfWeek == DayOfWeek.Monday) { OnMondayMorning(); } } if (cycleStartTime.Hour >= 12 && lastHour < 12) { OnNoon(); } if (cycleStartTime.Hour < lastHour) { OnMidnight(); } } catch (Exception e) { // Note each "OnEvery..." catches its own errors and sends Exception mails, // so that failure in one should not stop the others from running. This particular // code should never run. ExceptionMail.Send(new Exception("Failed in swarmops-backend main loop", e), true); } lastSecond = cycleStartTime.Second; lastMinute = cycleStartTime.Minute; lastHour = cycleStartTime.Hour; // Wait for a maximum of ten seconds (the difference between cycleStartTime and cycleEndTime) int iterationCount = 0; DateTime utcNow = DateTime.UtcNow; while (utcNow < cycleEndTime && !exitFlag) { int signalIndex = 250; // Handle important service orders (those that can't be lost in a random loss // of connection of a socket): BackendServiceOrders backendOrders = BackendServiceOrders.GetNextBatch(5); backendOrders.Execute(); // takes at most 250ms per BSO reqs // Block until a SIGINT or SIGTERM signal is generated, or 1/4 second has passed. // However, we can't do that in a development environment - it won't have the // Mono.Posix assembly, and won't understand UnixSignals. So people running this in // a dev environment will need to stop it manually. if (!Debugger.IsAttached) { signalIndex = UnixSignal.WaitAny(killSignals, 250); } else { TimeSpan timeLeft = (cycleEndTime - utcNow); BotLog.Write(0, "MainCycle Debug", string.Format(CultureInfo.InvariantCulture, "Waiting for {0:F2} more seconds for cycle end", timeLeft.TotalMilliseconds / 1000.0)); Thread.Sleep(250); } if (signalIndex < 250) { exitFlag = true; Console.WriteLine("Caught signal " + killSignals[signalIndex].Signum + ", exiting"); BotLog.Write(0, "MainCycle", "EXIT SIGNAL (" + killSignals[signalIndex].Signum + "), terminating backend"); } utcNow = DateTime.UtcNow; // Every second, send an internal heartbeat if (iterationCount++ % 4 == 0) { InternalHeartbeat(); } } } } Console.WriteLine(" * Swarmops Backend stopping"); BotLog.Write(0, "MainCycle", "BACKEND EXITING, sending backend-termination notices"); /* * if (HeartBeater.Instance.WasKilled) * { * // removed unconditional delete, cron job that restarts bot uses it to know that it is intentionally down. * ExceptionMail.Send(new Exception("HeartBeater triggered restart of Swarmops Backend. Will commence after 800 seconds."), false); * }*/ BotLog.Write(0, "MainCycle", "...done"); /* * while (!MailTransmitter.CanExit) * { * System.Threading.Thread.Sleep(50); * }*/ _socketServer.Stop(); Thread.Sleep(2000); }
private static void OnMidnight() { try { BotLog.Write(0, "MainCycle", "Midnight entry"); try { if (!testMode) { /*TestTrace("Running RosterHousekeeping.ChurnExpiredMembers()..."); * RosterHousekeeping.ChurnExpiredMembers(); * TestTrace(" done.\r\n");*/ } ExchangeRateSnapshot.Create(); } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running InternalPollMaintenance.Run()..."); * InternalPollMaintenance.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running SwedishForumMemberCheck.Run()..."); * SwedishForumMemberCheck.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running SalaryProcessor.Run()..."); * SalaryProcessor.Run(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running TurnaroundTracker.Housekeeping()..."); * TurnaroundTracker.Housekeeping(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running Mappery.CreateUngPiratUptakeMap()..."); * Mappery.CreateUngPiratUptakeMap(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } try { /*TestTrace("Running RosterHousekeeping.TimeoutVolunteers()..."); * RosterHousekeeping.TimeoutVolunteers(); * TestTrace(" done.\r\n");*/ } catch (Exception e) { TraceAndReport(e); } BotLog.Write(0, "MainCycle", "Midnight exit"); } catch (Exception e) { ExceptionMail.Send(e, true); TestTrace(e.ToString()); } }
internal static OutboundMailRecipient TransmitOneMail(OutboundMailRecipient recipient) { try { // If the mail address in illegal format, do not try to send anything: if (!Formatting.ValidateEmailFormat(recipient.EmailPerson.Email.Trim())) { string msg = "Invalid email address:\r\nEmailPerson [" + recipient.EmailPerson.Identity + "], mail [" + recipient.EmailPerson.Email + "]\r\nwill not send mail:" + recipient.OutboundMail.Title; throw new InvalidRecipientException(msg, null); } // If the mail address is marked as unreachable, do not try to send anything if (recipient.Person != null && recipient.Person.MailUnreachable) { string msg = "MailUnreachable email address:\r\nEmailPerson [" + recipient.EmailPerson.Identity + "], mail [" + recipient.EmailPerson.Email + "]\r\nwill not send mail:" + recipient.OutboundMail.Title; throw new InvalidRecipientException(msg, null); } // If the mail address is marked as unreachable, do not try to send anything if (recipient.Person != null && recipient.Person.NeverMail) { string msg = "NeverMail email address:\r\nEmailPerson [" + recipient.EmailPerson.Identity + "], mail [" + recipient.EmailPerson.Email + "]\r\nwill not send mail:" + recipient.OutboundMail.Title; throw new IgnoreRecipientException(msg, null); } // Otherwise, let's start processing OutboundMail mail = recipient.OutboundMail; bool limitToLatin1 = false; bool limitToText = false; Encoding currentEncoding = Encoding.UTF8; string email = recipient.EmailPerson.Email.ToLower(); if (mail.MailType == 0 || mail.TemplateName.EndsWith("Plain")) { limitToText = true; } // TEST: Does this user require the use of a text-only message (as opposed to multipart/alternative)? if (recipient.Person != null && recipient.Person.LimitMailToText) { limitToText = true; } // This is supposedly not a problem anymore //if (email.EndsWith("@hotmail.com") || email.EndsWith("@msn.com")) //{ // limitToLatin1 = true; //} // TEST: Does this user require the limited use of the Latin-1 charset (as opposed to Unicode?) if (recipient.Person != null && recipient.Person.LimitMailToLatin1) { limitToLatin1 = true; } // Capability tests end here if (limitToLatin1) { currentEncoding = Encoding.GetEncoding("ISO-8859-1"); } else { currentEncoding = Encoding.UTF8; } QuotedPrintable qp = QuotedPrintableEncoder[currentEncoding]; MailMessage message = new MailMessage(); if (mail.AuthorType == MailAuthorType.Person) { try { message.From = new MailAddress(mail.Author.PartyEmail, qp.EncodeMailHeaderString(mail.Author.Name + " (" + mail.Organization.MailPrefixInherited + ")"), currentEncoding); if (mail.Author.Identity == 1) { //TODO: Create alternative party mail optional data field, or organization chairman (based on roles) differently // Ugly hack message.From = new MailAddress("*****@*****.**", qp.EncodeMailHeaderString(mail.Author.Name + " (" + mail.Organization.MailPrefixInherited + ")"), currentEncoding); } } catch (Exception ex) { throw new InvalidSenderException( "Invalid author address in MailProcessor.TransmitOneMail:" + (mail.AuthorPersonId) + ";" + mail.Author.PartyEmail, ex); } } else { try { FunctionalMail.AddressItem aItem = mail.Organization.GetFunctionalMailAddressInh(mail.AuthorType); message.From = new MailAddress(aItem.Email, qp.EncodeMailHeaderString(aItem.Name), currentEncoding); } catch (Exception ex) { throw new InvalidSenderException( "Unknown MailAuthorType in MailProcessor.TransmitOneMail:" + ((int)mail.AuthorType), ex); } } if (recipient.AsOfficer && recipient.Person != null) { try { message.To.Add(new MailAddress(recipient.Person.PartyEmail, qp.EncodeMailHeaderString(recipient.Person.Name + " (" + mail.Organization.MailPrefixInherited + ")"), currentEncoding)); } catch (FormatException e) { string msg = "Invalid officer email address:\r\nperson [" + recipient.Person.Identity + "], mail [" + recipient.Person.PartyEmail + "]\r\nwill not send mail:" + recipient.OutboundMail.Title; throw new InvalidRecipientException(msg, e); } } else { try { message.To.Add(new MailAddress(recipient.EmailPerson.Email, qp.EncodeMailHeaderString(recipient.EmailPerson.Name), currentEncoding)); } catch (FormatException e) { string msg = "Invalid email address:\r\nEmailPerson [" + recipient.EmailPerson.Identity + "], mail [" + recipient.EmailPerson.Email + "]\r\nwill not send mail:" + recipient.OutboundMail.Title; throw new InvalidRecipientException(msg, e); } } string culture = mail.Organization.DefaultCountry.Culture; // UGLY UGLY UGLY HACK, NEEDS TO CHANGE ASAP: // We need to determine the culture of the recipient in order to use the right template. However, this is also dependent on the text body, which needs to be // in the same culture. At this point, we don't have the mail/recipient cultures in the schema. This would be the correct solution. // The INCORRECT but working solution is to do as we do here and check if a) it's a reporter and b) the reporter has International/English as a category. If so, // we change the culture to en-US. It's an ugly as all hell hack but it should work as a temporary stopgap. if (recipient.Reporter != null) { MediaCategories categories = recipient.Reporter.MediaCategories; foreach (MediaCategory category in categories) { if (category.Name == "International/English") { culture = Strings.InternationalCultureCode; break; } } } if (limitToText) { // if just text, then just add a plaintext body; string text = ""; //Cant really see any reson the HtmlAgilityPack shouldn't be thread safe, but what the heck, just in case.. lock (lockObject) { try { text = mail.RenderText(recipient.EmailPerson, culture); } catch (Exception ex) { throw new RemoveRecipientException( "TextRendering failed for " + mail.Title + " to " + recipient.EmailPerson.Email + " will not retry.\n", ex); } } message.BodyEncoding = currentEncoding; message.Body = text; } else { // otherwise, add a multipart/alternative with text and HTML string text = ""; string html = ""; //Cant really see any reson the HtmlAgilityPack shouldn't be thread safe, but what the heck, just in case.. Exception ex = null; lock (lockObject) { try { text = mail.RenderText(recipient.EmailPerson, culture); html = mail.RenderHtml(recipient.EmailPerson, culture); } catch (Exception e) { ex = e; } } if (text == "") { throw new RemoveRecipientException( "Rendering (text) failed for " + mail.Title + " to " + recipient.EmailPerson.Email + " will not retry.\n", ex); } if (html == "" || ex != null) { throw new RemoveRecipientException( "Rendering (html) failed for " + mail.Title + " to " + recipient.EmailPerson.Email + " will not retry.\n", ex); } ContentType textContentType = new ContentType(MediaTypeNames.Text.Plain); textContentType.CharSet = currentEncoding.BodyName; ContentType htmlContentType = new ContentType(MediaTypeNames.Text.Html); htmlContentType.CharSet = currentEncoding.BodyName; AlternateView textView = null; AlternateView htmlView = null; if (limitToLatin1) { textView = new AlternateView(new MemoryStream(currentEncoding.GetBytes(text)), textContentType); htmlView = new AlternateView(new MemoryStream(currentEncoding.GetBytes(text)), htmlContentType); } else { textView = AlternateView.CreateAlternateViewFromString(text, textContentType); htmlView = AlternateView.CreateAlternateViewFromString(html, htmlContentType); } // A f*****g stupid Mono bug forces us to transfer-encode in base64: it can't encode qp properly // (the "=" is not encoded to "=3D") htmlView.TransferEncoding = TransferEncoding.Base64; textView.TransferEncoding = TransferEncoding.Base64; // Add the views in increasing order of preference message.AlternateViews.Add(textView); message.AlternateViews.Add(htmlView); } if (mail.AuthorType == MailAuthorType.PirateWeb) { message.Subject = mail.Title; } else if (mail.MailType == 0) { message.Subject = mail.Organization.MailPrefixInherited + ": " + mail.Title; } else { //Title is set up in template processing in OutboundMail rendering. message.Subject = mail.Title; } message.SubjectEncoding = currentEncoding; string smtpServer = ConfigurationManager.AppSettings["SmtpServer"]; if (Debugger.IsAttached) { Debug.WriteLine("sending " + message.Subject + " to " + recipient.EmailPerson.Email); Thread.Sleep(200); //simulate delay } if (smtpServer.ToLower() != "none") { if (smtpServer == null || smtpServer.Length < 2) { smtpServer = "localhost"; } try { SmtpClient client = new SmtpClient(smtpServer, 25); client.Send(message); } catch (SmtpException e) { if (e.ToString().StartsWith("System.Net.Mail.SmtpException: 4")) { // Temporary error (SMTP 4xx). Try again. Thread.Sleep(2000); // Allow 2 seconds pause to wait for smtp-server to become available throw new ReportAndRetryRecipientException("Temporary smtp error, will retry.", e); } // Otherwise, bad recipient (assume so). Have the mail removed from the queue. List <string> recipients = new List <string>(); foreach (MailAddress address in message.To) { recipients.Add(address.Address); } ExceptionMail.Send( new ArgumentException( "Bad Recipients when sending to " + recipient.EmailPerson.Email + ": " + String.Join(", ", recipients.ToArray()), e)); if (mail.AuthorType == MailAuthorType.Person) { try { mail.Author.SendOfficerNotice( "Failed recipient(s): " + String.Join(", ", recipients.ToArray()), "Some recipients failed inexplicably in a mail from you.", 1); } catch (Exception ex) { throw new Exception("Failed to SendOfficerNotice to :" + mail.AuthorPersonId, ex); } } } } return(recipient); // To pass this object onto the we're-done callback } catch (InvalidRecipientException ex) { throw ex; } catch (RetryRecipientException ex) { Thread.Sleep(2000); // Allow 2 seconds pause to avoid flooding the errorlog too fast in case of a permanent failure throw ex; } catch (Exception ex) { throw ex; } }
internal static void MailSent(IAsyncResult result) { lock (lockObject) { MailTransmissionAsyncState asyncState = (MailTransmissionAsyncState)result.AsyncState; MailTransmissionDelegate asyncTransmitter = asyncState.dlgt; OutboundMailRecipient recipient = asyncState.recipient; try { asyncTransmitter.EndInvoke(result); try { recipient.Delete(); recipient.OutboundMail.IncrementSuccesses(); } catch (Exception ex) { // whatever.. The mail is sent, but we couldn't mark it as such, probably a database failure. asyncState.exception = new RemoveRecipientException("Couldn't remove mail recipient.", ex); ExceptionMail.Send(asyncState.exception, true); } } catch (ReportAndRetryRecipientException e) { asyncState.exception = e; Debug.WriteLine(e.ToString()); ExceptionMail.Send(e, true); } catch (RetryRecipientException e) { // No action - handled in async delegate - retry this mail asyncState.exception = e; } catch (Exception e) { asyncState.exception = e; try { recipient.Delete(); recipient.OutboundMail.IncrementFailures(); if (e is InvalidRecipientException) { if (recipient.Person != null && recipient.Person.EMailIsInvalid == false) { //Mark address as invalid. recipient.Person.EMailIsInvalid = true; } } } catch (Exception ex) { // Return this exception in asyncState since it is important to stop flooding. asyncState.exception = new RemoveRecipientException("Couldn't remove mail recipient after exception.", ex); ExceptionMail.Send(asyncState.exception, true); //Report the secondary exception } Debug.WriteLine(e.ToString()); ExceptionMail.Send(e, true); } asyncState.callbackCompleted = true; } }
private static void CheckOneFeed(string readerUrl, string persistAsKey, int orgIdForTemplate) { string persistenceKey = String.Format("Pressrelease-Highwater-{0}", persistAsKey); DateTime highWaterMark = DateTime.MinValue; RssReader reader = null; try { string highWaterMarkString = Persistence.Key[persistenceKey]; if (string.IsNullOrEmpty(highWaterMarkString)) { //Initialize highwatermark if never used highWaterMark = DateTime.Now; Persistence.Key[persistenceKey] = DateTime.Now.ToString(); } else { try { highWaterMark = DateTime.Parse(highWaterMarkString); } catch (Exception ex) { HeartBeater.Instance.SuggestRestart(); throw new Exception( "Triggered restart. Unable to read/parse old highwater mark from database in PressReleaseChecker.Run(), from key:" + persistenceKey + ", loaded string was '" + highWaterMarkString + "' expected format is " + DateTime.Now, ex); } } DateTime storedHighWaterMark = highWaterMark; reader = new RssReader(readerUrl); Rss rss = reader.Read(); foreach (RssChannelItem item in rss.Channel.Items) { // Ignore any items older than the highwater mark. // Also ignore if older than two days if (item.PubDate < highWaterMark || item.PubDate < DateTime.Now.AddDays(-2)) { continue; } // This is an item we should publish. // Set highwater datetime mark. We do this first, BEFORE processing, as a defense against mail floods, // if should something go wrong and unexpected exceptions happen. // We used to add 70 minutes as a defense against mistakes on DST switch in spring and fall (yes, it has happened), but have reduced to two. if (item.PubDate > storedHighWaterMark) { Persistence.Key[persistenceKey] = item.PubDate.AddMinutes(2).ToString(); storedHighWaterMark = item.PubDate.AddMinutes(2); // Verify that it was written correctly to database. This is defensive programming to avoid a mail flood, // in case we can't write to the database for some reason. string newStoredHighWaterString = ""; try { newStoredHighWaterString = Persistence.Key[persistenceKey]; DateTime temp = DateTime.Parse(newStoredHighWaterString); } catch (Exception ex) { throw new Exception( "Unable to commit/parse new highwater mark to database in PressReleaseChecker.Run(), loaded string was '" + newStoredHighWaterString + "'", ex); } if (DateTime.Parse(Persistence.Key[persistenceKey]) < item.PubDate) { throw new Exception( "Unable to commit new highwater mark to database in PressReleaseChecker.Run()"); } } bool allReporters = false; bool international = false; MediaCategories categories = new MediaCategories(); foreach (RssCategory category in item.Categories) { if (category.Name == "Alla") { allReporters = true; } else if (category.Name == "Uncategorized") { } else { try { MediaCategory mediaCategory = MediaCategory.FromName(category.Name); categories.Add(mediaCategory); if (category.Name.StartsWith("International")) { international = true; } } catch (Exception) { ExceptionMail.Send( new Exception("Unrecognized media category in press release: " + category.Name)); } } } string mailText = Blog2Mail(item.Content); // Create recipient list of relevant reporters Reporters reporters = null; if (allReporters) { reporters = Reporters.GetAll(); } else { reporters = Reporters.FromMediaCategories(categories); } // Add officers if not int'l People officers = new People(); Dictionary <int, bool> officerLookup = new Dictionary <int, bool>(); if (!international) { int[] officerIds = Roles.GetAllDownwardRoles(1, 1); foreach (int officerId in officerIds) { officerLookup[officerId] = true; } } else { officerLookup[1] = true; } // Send press release //TODO: hardcoded geo ... using World Organization org = Organization.FromIdentity(orgIdForTemplate); Geography geo = Geography.Root; PressReleaseMail pressreleasemail = new PressReleaseMail(); pressreleasemail.pSubject = item.Title; pressreleasemail.pDate = DateTime.Now; pressreleasemail.pBodyContent = Blog2Mail(item.Content); pressreleasemail.pOrgName = org.MailPrefixInherited; if (allReporters) { pressreleasemail.pPostedToCategories = "Alla"; // TODO: TRANSLATE } else if (international) { pressreleasemail.pPostedToCategories = "International/English"; // TODO: THIS IS HARDCODED } else { pressreleasemail.pPostedToCategories = PressReleaseMail.GetConcatenatedCategoryString(categories); } OutboundMail newMail = pressreleasemail.CreateFunctionalOutboundMail(MailAuthorType.PressService, OutboundMail.PriorityHighest, org, geo); int recipientCount = 0; foreach (Reporter recipient in reporters) { if (!Formatting.ValidateEmailFormat(recipient.Email)) { continue; } ++recipientCount; newMail.AddRecipient(recipient); } foreach (int key in officerLookup.Keys) { Person recipient = Person.FromIdentity(key); if (!Formatting.ValidateEmailFormat(recipient.Mail)) { continue; } ++recipientCount; newMail.AddRecipient(recipient, true); } newMail.SetRecipientCount(recipientCount); newMail.SetResolved(); newMail.SetReadyForPickup(); } } catch (Exception ex) { ExceptionMail.Send( new Exception("PressReleaseChecker failed:" + ex.Message + "\r\nwhen checking " + readerUrl, ex)); } finally { reader.Close(); } }
public static void Send(Newsletter newsletter, string forumUrl) { string directory = "content" + Path.DirectorySeparatorChar + "mailtemplate-" + newsletter.TemplateId; string htmlTemplate = "Failed to read HTML mail template."; using ( StreamReader reader = new StreamReader(directory + Path.DirectorySeparatorChar + "template.html", Encoding.Default)) { htmlTemplate = reader.ReadToEnd(); } /* * using (StreamReader reader = new StreamReader(textTemplateFile, System.Text.Encoding.Default)) * { * textTemplate = reader.ReadToEnd(); * }*/ // PREPARE DATE // assume Swedish CultureInfo culture = new CultureInfo("sv-SE"); string date = DateTime.Today.ToString("d MMMM yyyy", culture); // PREPARE HTML VIEW: // Write in the title, intro, and body htmlTemplate = htmlTemplate. Replace("%TITLE%", HttpUtility.HtmlEncode(newsletter.Title.ToUpper())). Replace("%title%", HttpUtility.HtmlEncode(newsletter.Title)). Replace("%date%", HttpUtility.HtmlEncode(date)). Replace("%DATE%", HttpUtility.HtmlEncode(date.ToUpper())). Replace("%forumposturl%", forumUrl); string body = newsletter.Body; body = body. Replace("<", "({[("). Replace(">", ")}])"). Replace("\"", "quotQUOTquot"); body = HttpUtility.HtmlEncode(body); body = body. Replace("({[(", "<"). Replace(")}])", ">"). Replace("quotQUOTquot", "\""). Replace("&#", "&#"); htmlTemplate = htmlTemplate.Replace("%body%", body); // Embed any inline images directly into the message string newsletterIdentifier = DateTime.Now.ToString("yyyyMMddhhMMssfff") + "@piratpartiet.se"; // TODO: Read the replacements from a config file htmlTemplate = htmlTemplate.Replace("header-pp-logo.png", "cid:pplogo" + newsletterIdentifier); /* * htmlTemplate = htmlTemplate.Replace("TopRight.png", "cid:topright" + newsletterIdentifier); * htmlTemplate = htmlTemplate.Replace("MiddleRight.png", "cid:middleright" + newsletterIdentifier); * htmlTemplate = htmlTemplate.Replace("BottomRight.png", "cid:bottomright" + newsletterIdentifier); * htmlTemplate = htmlTemplate.Replace("TopLeft.png", "cid:topleft" + newsletterIdentifier); * htmlTemplate = htmlTemplate.Replace("MiddleLeft.png", "cid:middleleft" + newsletterIdentifier); * htmlTemplate = htmlTemplate.Replace("BottomLeft.png", "cid:bottomleft" + newsletterIdentifier); * htmlTemplate = htmlTemplate.Replace("TopMiddle.png", "cid:topmiddle" + newsletterIdentifier); * htmlTemplate = htmlTemplate.Replace("BottomMiddle.png", "cid:bottommiddle" + newsletterIdentifier); * htmlTemplate = htmlTemplate.Replace("PPShield.png", "cid:ppshield" + newsletterIdentifier); * htmlTemplate = htmlTemplate.Replace("Rick.png", "cid:rick" + newsletterIdentifier); * htmlTemplate = htmlTemplate.Replace("RFe-signature.gif", "cid:rick-signature" + newsletterIdentifier);*/ // MemoryStream memStream = new MemoryStream(); AlternateView htmlView = AlternateView.CreateAlternateViewFromString(htmlTemplate, new ContentType( MediaTypeNames.Text.Html)); htmlView.TransferEncoding = TransferEncoding.Base64; /* * LinkedResource image = new LinkedResource(directory + Path.DirectorySeparatorChar + "header-pp-logo.png"); * image.ContentId = "pplogo" + newsletterIdentifier; * htmlView.LinkedResources.Add(image);*/ /* * -- DISABLED -- code writing a forum-style text file * * * // PREPARE FORUM FILE: * * string forumTemplate = textTemplate. * Replace("%TITLE%", "[h1]" + title.ToUpper() + "[/h1]"). * Replace("%title%", "[h1]" + title + "[/h1]"). * Replace("%intro%", intro). * Replace("%body%", mailBody); * * // Replace "<a href="http://link">Text</a>" with "Text (http://link)" * * Regex regexLinksForum = new Regex("(?s)\\[a\\s+href=\\\"(?<link>[^\\\"]+)\\\"\\](?<description>[^\\[]+)\\[/a\\]", RegexOptions.Multiline); * * forumTemplate = regexLinksForum.Replace(forumTemplate, new MatchEvaluator(NewsletterTransmitter2.RewriteUrlsInForum)); * * using (StreamWriter writer = new StreamWriter(directory + "\\" + "forum.txt", false, System.Text.Encoding.Default)) * { * writer.WriteLine(forumTemplate); * }*/ /* * -- DISABLED -- no text view * * * * // PREPARE TEXT VIEW: * * // Write in the title, intro, and body * * textTemplate = textTemplate. * Replace("%TITLE%", title.ToUpper()). * Replace("%title%", title). * Replace("%intro%", intro). * Replace("%body%", mailBody); * * // Replace "<a href="http://link">Text</a>" with "Text (http://link)" * * Regex regexLinks = new Regex("(?s)\\[a\\s+href=\\\"(?<link>[^\\\"]+)\\\"\\](?<description>[^\\[]+)\\[/a\\]", RegexOptions.Multiline); * * textTemplate = regexLinks.Replace(textTemplate, new MatchEvaluator(NewsletterTransmitter2.RewriteUrlsInText)); * * Regex regexHtmlCodes = new Regex("(?s)\\[[^\\[]+\\]", RegexOptions.Multiline); * * textTemplate = regexHtmlCodes.Replace(textTemplate, string.Empty); * * ContentType typeUnicode = new ContentType(MediaTypeNames.Text.Plain); * typeUnicode.CharSet = "utf-8"; * * AlternateView textUnicodeView = AlternateView.CreateAlternateViewFromString(textTemplate, typeUnicode); * * ContentType typeIsoLatin1 = new ContentType(MediaTypeNames.Text.Plain); * typeIsoLatin1.CharSet = "iso-8859-1"; * * AlternateView textHotmailView = new AlternateView(new MemoryStream(Encoding.Default.GetBytes(textTemplate)), typeIsoLatin1); * * */ foreach (Person recipient in newsletter.Recipients) { //Console.Write (recipient.Name + "(#" + recipient.Identity.ToString() + ")... "); if (recipient.Mail.Length < 2) { //Console.WriteLine("canceled."); continue; // no email on file } if (recipient.NeverMail) { //Console.WriteLine("canceled."); continue; // This person has a total mail block on his or her mail } try { SmtpClient client = new SmtpClient(Config.SmtpHost, Config.SmtpPort); client.Credentials = null; MailMessage message = new MailMessage( new MailAddress(newsletter.SenderAddress, qp8859.EncodeMailHeaderString(newsletter.SenderName), Encoding.GetEncoding("ISO-8859-1")), new MailAddress(recipient.Mail, qp8859.EncodeMailHeaderString(recipient.Name), Encoding.GetEncoding("ISO-8859-1"))); message.Subject = "Piratpartiet: Nyhetsbrev " + DateTime.Today.ToString("yyyy-MM-dd"); // HACK message.Body = htmlTemplate; message.BodyEncoding = Encoding.ASCII; message.IsBodyHtml = true; // COMPENSATE FOR MONO BUG -- put logo online instead of attached message.Body = message.Body.Replace("cid:pplogo" + newsletterIdentifier, "http://docs.piratpartiet.se/banners/newsletter-banner-pp-logo.png"); /* * Attachment attachment = new Attachment(directory + Path.DirectorySeparatorChar + "header-pp-logo.png", "image/png"); * attachment.ContentId = "pplogo" + newsletterIdentifier; * attachment.ContentDisposition.Inline = true; * message.Attachments.Add(attachment);*/ string personEmail = recipient.Mail.Trim().ToLower(); string identifier = " [PP" + recipient.HexIdentifier() + "]"; message.Subject += identifier; bool successOrPermanentFail = false; while (!successOrPermanentFail) { try { client.Send(message); successOrPermanentFail = true; } catch (SmtpException e) { if (!(e.ToString().StartsWith("System.Net.Mail.SmtpException: 4"))) { // This is NOT a temporary error (SMTP 4xx). Fail. successOrPermanentFail = true; throw e; } // Otherwise, sleep for a while and try again. Thread.Sleep(1000); } } //Console.WriteLine("ok"); } catch (Exception e) { //Console.WriteLine("FAIL! <" + recipient.Email + ">"); ExceptionMail.Send( new Exception( "Error sending mail to " + recipient.Name + " (#" + recipient.Identity + ") <" + recipient.Mail + ">:", e)); } } }
public void Send() { //Send method now sending syncronously. //List to keep track of started async send's List <IAsyncResult> sendInProgress = new List <IAsyncResult>(); foreach (Person recipient in recipients) { try { MailMessage message = null; if (toOfficers && recipient.Country.Identity == 1) // HACK until PirateWeb Exchange server up { if (!Formatting.ValidateEmailFormat(recipient.PartyEmail.Trim())) { if (recipient.Identity == 13354) { // HACK - UP auditor continue; } Person.FromIdentity(1).SendOfficerNotice("PirateBot Warning", String.Format("The officer {0} (#{1}) does not have a party email.", recipient.Name, recipient.Identity), 1); continue; } message = new MailMessage(new MailAddress(fromAddress, qp8859.EncodeMailHeaderString(fromName), Encoding.Default), new MailAddress(recipient.PartyEmail, qp8859.EncodeMailHeaderString(recipient.Name + " (Piratpartiet)"), Encoding.Default)); } else { if (!Formatting.ValidateEmailFormat(recipient.Mail.Trim())) { continue; } message = new MailMessage(new MailAddress(fromAddress, qpUTF8.EncodeMailHeaderString(fromName), Encoding.UTF8), new MailAddress(recipient.Mail, qpUTF8.EncodeMailHeaderString(recipient.Name), Encoding.UTF8)); } if (message == null) { continue; } message.Subject = subject; message.Body = bodyPlain; message.SubjectEncoding = Encoding.UTF8; message.BodyEncoding = Encoding.UTF8; // Start the transmission process, synchronously #region Commented out asynchronous sending //lock (lockObject) //{ // MailTransmissionDelegate asyncTransmitter = new MailTransmissionDelegate(TransmitOneMessage); // outstandingTransmissions++; // sendInProgress.Add(asyncTransmitter.BeginInvoke(message, null, asyncTransmitter)); //} //System.Threading.Thread.Sleep(25); // Allow some time #endregion TransmitOneMessage(message); // Sending synchronosly } catch (Exception e) { System.Diagnostics.Debug.WriteLine(e.ToString()); ExceptionMail.Send(new Exception("Excepton in Mailtransmitter.Send:", e), true); } } #region Commented out handling of wait for asyncronous completion (Wich isn't even good...) //// now wait for them to finish; //int numberStillExecuting = sendInProgress.Count; //int numberExecutingLast = numberStillExecuting + 1; //DateTime lastProgress = DateTime.Now; //while (numberStillExecuting > 0) //{ // System.Threading.Thread.Sleep(25); // Allow some time // numberStillExecuting = 0; // for (int i = 0; i < sendInProgress.Count; ++i) // { // IAsyncResult iares = sendInProgress[i]; // if (iares != null) // { // if (!iares.IsCompleted) // { // numberStillExecuting++; // } // else // { // MessageSent(iares); // sendInProgress[i] = null; // } // } // } // if (numberExecutingLast != numberStillExecuting) // lastProgress = DateTime.Now; // numberExecutingLast = numberStillExecuting; // if (lastProgress.AddSeconds(60) < DateTime.Now) // { // //60 seconds since last change, something must have hanged // lock (lockObject) // { // outstandingTransmissions = -1000; // } // throw new Exception("Timeout in MailTransmitter"); // } //} #endregion }
public static void RemindChangeOrg() { HeartBeater.Instance.Beat(); // Get expiring DateTime starttime = DateTime.Now; Organizations orgs = Organization.FromIdentity(Organization.UPSEid).GetTree(); Dictionary <int, Person> personLookup = new Dictionary <int, Person>(); Dictionary <int, Memberships> personMembershipsLookup = new Dictionary <int, Memberships>(); Dictionary <int, Organization> orgLookup = new Dictionary <int, Organization>(); Dictionary <int, Organization> mostLocalOrganizationCache = new Dictionary <int, Organization>(); List <ChangeOrgReport> report = new List <ChangeOrgReport>(); foreach (Organization org in orgs) { orgLookup[org.OrganizationId] = org; } Memberships allMemberships = Memberships.ForOrganizations(orgs); foreach (Membership ms in allMemberships) { //Handle defunct Memberships.ForOrganizations if (orgLookup.ContainsKey(ms.OrganizationId)) { if (!personLookup.ContainsKey(ms.PersonId)) { personLookup[ms.PersonId] = null; personMembershipsLookup[ms.PersonId] = new Memberships(); } personMembershipsLookup[ms.PersonId].Add(ms); } } allMemberships = null; People peeps = People.FromIdentities((new List <int>(personLookup.Keys)).ToArray()); foreach (Person p in peeps) { personLookup[p.PersonId] = p; } if (Debugger.IsAttached) { Console.WriteLine("Found " + personLookup.Count + " people"); } int processedCounter = 0; int sentCounter = 0; int failCounter = 0; DateTime lastDisplay = DateTime.Now; foreach (Person person in personLookup.Values) { ++processedCounter; if ((processedCounter % 50) == 0) { HeartBeater.Instance.Beat(); if (Debugger.IsAttached) { Console.WriteLine("Processed " + processedCounter + " t=" + DateTime.Now.Subtract(lastDisplay).TotalSeconds); } lastDisplay = DateTime.Now; } int geoid = person.GeographyId; //check for error, geography broken. if (person.GeographyId == 0) { geoid = person.Geography.GeographyId; //Will force resolve Geography if (geoid != 0) { person.Geography = person.Geography; } ; //repair person. } if (geoid == 0) { continue; //give up on that... } Organization expectedLowOrg = null; if (mostLocalOrganizationCache.ContainsKey(geoid)) { expectedLowOrg = mostLocalOrganizationCache[geoid]; } else { expectedLowOrg = Organizations.GetMostLocalOrganization(geoid, Organization.UPSEid); mostLocalOrganizationCache[geoid] = expectedLowOrg; } bool found = false; Dictionary <int, Membership> personMS = new Dictionary <int, Membership>(); foreach (Membership ms in personMembershipsLookup[person.PersonId]) { if (orgLookup.ContainsKey(ms.OrganizationId)) { //Its an UP org personMS[ms.OrganizationId] = ms; } if (ms.OrganizationId == expectedLowOrg.Identity) { found = true; break; } } if (found == false) { //OK we didnt find the recommended org. Find out why. // loop thru the persons up orgs to find an inactive List <Organization> foundInactiveOrg = new List <Organization>(); List <Organization> foundActiveOrg = new List <Organization>(); Membership membership = null; try { Organization org = null; foreach (Membership ms in personMS.Values) { org = orgLookup[ms.OrganizationId]; if (org.AcceptsMembers == false) { foundInactiveOrg.Add(org); } else if (org.AutoAssignNewMembers == true) { foundActiveOrg.Add(org); } } if (foundInactiveOrg.Count > 0) { //inactive membership = personMS[foundInactiveOrg[0].Identity]; } else if (foundActiveOrg.Count > 0) { //change membership = personMS[foundActiveOrg[0].Identity]; } else { //already a member but not of an autoassign org if (Debugger.IsAttached) { Console.WriteLine("Debug:nochange " + person.Name + ";" + person.Geography.Name + ";" + (org != null ? org.Name : "UnknownOrg") + ";" + expectedLowOrg.Name); } continue; } DateTime lastReminder = PWLog.CheckLatest(PWLogItem.Person, membership.PersonId, PWLogAction.MembershipRenewReminder); if (DateTime.Now.Subtract(lastReminder).TotalDays > 25) { if (Debugger.IsAttached) { Console.Write("Debug:" + person.Name + ";" + person.Geography.Name + ";" + membership.Organization.Name + ";" + expectedLowOrg.Name); foreach (var o in foundActiveOrg) { Console.Write(";" + o.Name); } Console.WriteLine(""); } SendChangeOrgMail(person, membership, expectedLowOrg); report.Add(new ChangeOrgReport { FromOrg = membership.Organization, ToOrg = expectedLowOrg }); ++sentCounter; PWLog.Write(PWLogItem.Person, membership.PersonId, PWLogAction.MembershipRenewReminder, "Mail was sent to " + membership.Person.Mail + " for recommendation of organisation change in " + membership.Organization.Name + ".", membership.Organization.Identity.ToString() + "/" + expectedLowOrg.Identity.ToString()); } } catch (Exception x) { ++failCounter; string logText = "FAILED sending mail to " + membership.Person.Mail + " for recommendation of organisation change in " + membership.Organization.Name + "."; PWLog.Write(PWLogItem.Person, membership.PersonId, PWLogAction.MembershipRenewReminder, logText, string.Empty); ExceptionMail.Send(new Exception(logText, x)); } } } Dictionary <Organization, Dictionary <Organization, int> > fromdict = new Dictionary <Organization, Dictionary <Organization, int> >(); StringBuilder fromOrgReport = new StringBuilder(); report.ForEach(delegate(ChangeOrgReport r) { if (!fromdict.ContainsKey(r.FromOrg)) { fromdict[r.FromOrg] = new Dictionary <Organization, int>(); } if (!fromdict[r.FromOrg].ContainsKey(r.ToOrg)) { fromdict[r.FromOrg][r.ToOrg] = 0; } fromdict[r.FromOrg][r.ToOrg]++; }); foreach (var fd in fromdict.Keys) { StringBuilder tmp = new StringBuilder(); int cnt = 0; foreach (var td in fromdict[fd].Keys) { tmp.Append(", " + td.Name); cnt += fromdict[fd][td]; } fromOrgReport.Append("\r\nFrån " + fd.Name + " (" + cnt + " st) till " + tmp.ToString().Substring(2)); } Dictionary <Organization, Dictionary <Organization, int> > todict = new Dictionary <Organization, Dictionary <Organization, int> >(); StringBuilder toOrgReport = new StringBuilder(); report.ForEach(delegate(ChangeOrgReport r) { if (!todict.ContainsKey(r.ToOrg)) { todict[r.ToOrg] = new Dictionary <Organization, int>(); } if (!todict[r.ToOrg].ContainsKey(r.FromOrg)) { todict[r.ToOrg][r.FromOrg] = 0; } todict[r.ToOrg][r.FromOrg]++; }); foreach (var td in todict.Keys) { StringBuilder tmp = new StringBuilder(); int cnt = 0; foreach (var fd in todict[td].Keys) { tmp.Append(", " + fd.Name); cnt += todict[td][fd]; } toOrgReport.Append("\r\nTill " + td.Name + " (" + cnt + " st) från " + tmp.ToString().Substring(2)); } string reportMessage = string.Format( "Result from running recommendation to change org mails:\r\n" + "Time: {0,10:#0.0} minutes. \r\n" + "Checked: {1,10:g}\r\n" + "Sent: {2,10:g}\r\n" + "Failed: {3,10:g}\r\n", DateTime.Now.Subtract(starttime).TotalMinutes, processedCounter, sentCounter, failCounter) + fromOrgReport + "\r\n" + toOrgReport; BasicPersonRole[] UPSecretary = SwarmDb.GetDatabaseForReading().GetPeopleWithRoleType(RoleType.OrganizationSecretary, new int[] { Organization.UPSEid }, new int[] { }); if (UPSecretary.Length > 0) { Person.FromIdentity(UPSecretary[0].PersonId).SendOfficerNotice("ChangeOrg Mails Job report", reportMessage, Organization.UPSEid); } Person.FromIdentity(7838).SendOfficerNotice("ChangeOrgMails run", reportMessage, Organization.UPSEid);//Debug }