using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Threading.Tasks; using S22.Xmpp; using S22.Xmpp.Client; using S22.Xmpp.Im; namespace RhinoReminds { public class ProgramSettings { public string AllowedDomain = "*"; public string Filepath = "./reminders.xml"; public string Jid = null; public string AvatarFilepath = string.Empty; public string PidFile = null; public string Password = null; } public static class Program { private static ProgramSettings settings = new ProgramSettings(); public static int Main(string[] args) { List extras = new List(); for (int i = 0; i < args.Length; i++) { if (!args[i].StartsWith("-")) { extras.Add(args[i]); continue; } switch (args[i]) { case "-h": case "--help": Console.WriteLine("--- RhinoReminds ---"); Console.WriteLine("> An XMPP reminder bot"); Console.WriteLine(" By Starbeamrainbowlabs"); Console.WriteLine(); Console.WriteLine("Usage:"); Console.WriteLine(" mono RhinoReminds.exe {options}"); Console.WriteLine(); Console.WriteLine("Options:"); Console.WriteLine(" -h --help Show this message"); Console.WriteLine($" -f --file Specify where to save reminders (default: {settings.Filepath})"); Console.WriteLine(" --domain {domain} Set the domain users are allowed to originate at. Defaults to any domain."); Console.WriteLine(" --avatar Update the XMPP account's avatar to the specified image. By default the avatar is not updated."); Console.WriteLine(" --pidfile Save our process ID to the specified file, and delete it on exit"); Console.WriteLine(); Console.WriteLine("Environment Variables:"); Console.WriteLine(" XMPP_JID The JID to login to"); Console.WriteLine(" XMPP_PASSWORD The password to login with"); return 0; case "--jid": settings.Jid = args[++i]; break; case "-d": case "--domain": settings.AllowedDomain = args[++i]; break; case "--avatar": settings.AvatarFilepath = args[++i]; break; case "--pidfile": settings.PidFile = args[++i]; break; default: Console.Error.WriteLine($"Error: Unknown argument '{args[i]}'."); return 14; } } settings.Jid = Environment.GetEnvironmentVariable("XMPP_JID"); settings.Password = Environment.GetEnvironmentVariable("XMPP_PASSWORD"); if (settings.Jid == null) { Console.Error.WriteLine("Error: No JID specified to login with."); Console.Error.WriteLine("Do so with the XMPP_JID environment variable!"); return 15; } if (settings.Password == null) { Console.Error.WriteLine("Error: No password specified to login with."); Console.Error.WriteLine("Do so with the XMPP_PASSWORD environment variable!"); return 16; } if (settings.PidFile != null) setupPidFile(); run(); // We shouldn't ever end up here, but just in case..... cleanupPidFile(); return 0; } private static void setupPidFile() { File.WriteAllText(settings.PidFile, Process.GetCurrentProcess().Id.ToString()); AppDomain.CurrentDomain.ProcessExit += (object sender, EventArgs e) => cleanupPidFile(); AppDomain.CurrentDomain.DomainUnload += (object sender, EventArgs e) => cleanupPidFile(); } private static void cleanupPidFile() { // Make sure we only do cleanup once if (settings.PidFile == null) return; File.Delete(settings.PidFile); settings.PidFile = null; } private static void run() { ClientListener client = new ClientListener(settings.Jid, settings.Password) { ReminderFilePath = settings.Filepath }; client.AllowedDomains.Add(settings.AllowedDomain); // Update the avatar if appropriate if (settings.AvatarFilepath != string.Empty) { OnConnectedHandler handler = null; handler = (object sender, OnConnectedEventArgs eventArgs) => { client.SetAvatar(settings.AvatarFilepath); Console.WriteLine($"[Program] Set avatar to '{settings.AvatarFilepath}'."); client.OnConnected -= handler; }; client.OnConnected += handler; } // Connect to the server & start listening // Make sure the program doesn't exit whilst we're connected try { client.Start().Wait(); } catch (Exception) { // Ensure we tidy up after ourselves by deleting the PID file if (settings.PidFile != null) cleanupPidFile(); // Re-throw the error throw; } } } }