1 module skoenlapper.client; 2 3 import std.stdio; 4 import skoenlapper.configurator; 5 import libutterfly.client; 6 import libutterfly.exceptions; 7 import gogga; 8 import std.conv : to; 9 import std.json; 10 import std.file : exists, mkdir; 11 import core.thread : Thread, dur; 12 import std.socket : Address; 13 14 /* */ 15 void viewMail(string[] mailPaths, string configFile, ulong accountIndex = 0) 16 { 17 /* Read in configurstion */ 18 Configuration configuration = new Configuration(getConfiguration(configFile)); 19 20 /* Get the account to be used (TODO: Bounds check) */ 21 Account chosenAccount = configuration.getAccount(accountIndex); 22 23 /* Read in the mail message */ 24 File mailFile; 25 mailFile.open(mailPaths[0]); 26 byte[] mailData; 27 mailData.length = mailFile.size(); 28 mailData = mailFile.rawRead(mailData); 29 mailFile.close(); 30 31 /* Display the mail message */ 32 JSONValue mailMessage = parseJSON(cast(string)mailData); 33 writeln("From: "~mailMessage["from"].str()); 34 writeln("Subject: "~mailMessage["subject"].str()~"\n"); 35 writeln(mailMessage["body"].str()); 36 37 /* TODO: Read stdin here for next line */ 38 } 39 40 41 /** 42 * Runs the mail daemon which creates a local directory 43 * structure mirroring that of the server's mailbox, 44 * filling each folder and sub-folder with ist respective 45 * contents and watching for any new mail that comes in 46 * 47 * Assumes that the first active account is to be used (this can be changed)addresses 48 */ 49 void mailDaemon(string configFile, ulong accountIndex = 0) 50 { 51 /* Read in configurstion */ 52 Configuration configuration = new Configuration(getConfiguration(configFile)); 53 54 /* Get the account to be used (TODO: Bounds check) */ 55 Account chosenAccount = configuration.getAccount(accountIndex); 56 57 /* Authenticate a new session (TODO: Error handling in library and then catch here) */ 58 gprintln("Opening connection to "~to!(string)(chosenAccount.getServer())); 59 ButterflyClient client = new ButterflyClient(chosenAccount.getServer()); 60 61 /* Authenticate (TODO: Error) */ 62 gprintln("Authenticating with server..."); 63 client.authenticate(chosenAccount.getUsername(), chosenAccount.getPassword()); 64 65 string[] root = client.listFolder("/"); 66 gprintln("Found folders: "~to!(string)(root)); 67 68 /* Check if the directory for this account exists (if not then create it) */ 69 if(!exists(chosenAccount.getMailbox())) 70 { 71 mkdir(chosenAccount.getMailbox()); 72 } 73 74 /* Preiodically check for new mail */ 75 while(true) 76 { 77 /* Create folder structure every now and then (skipping already present stuff) */ 78 gprintln("Starting mail check cycle..."); 79 createFolderStructures(chosenAccount.getMailbox(), "/", client); 80 gprintln("Mail check cycle completed"); 81 Thread.sleep(dur!("seconds")(5)); 82 } 83 } 84 85 /** 86 * Creates the folder structure in the mailbox for the 87 * specified account 88 */ 89 void createFolderStructures(string mailboxDirectory, string currentFolder, ButterflyClient client) 90 { 91 /* Get all folders */ 92 string[] folders = client.listFolder(currentFolder); 93 94 /* Loop through each directory of the current `root` */ 95 foreach(string directory; folders) 96 { 97 /* Create the directory */ 98 gprintln("Checking for local directory for remote directory '"~directory~"'..."); 99 if(!exists(mailboxDirectory~currentFolder~"/"~directory)) 100 { 101 gprintln("Creating local directory for remote directory '"~directory~"'..."); 102 mkdir(mailboxDirectory~currentFolder~"/"~directory); 103 } 104 105 /* List all mail in the current folder */ 106 string[] mailIDs = client.listMail(currentFolder~"/"~directory); 107 foreach(string mailID; mailIDs) 108 { 109 /* If the mail exists then skip it */ 110 if(exists(mailboxDirectory~currentFolder~"/"~directory~"/"~mailID)) 111 { 112 continue; 113 } 114 115 /* Fetch the mail message */ 116 gprintln("Fetching mail message '"~mailID~"'..."); 117 string mail = client.fetchMail(currentFolder~"/"~directory, mailID).toPrettyString(); 118 119 /* Store mail message */ 120 File file; 121 file.open(mailboxDirectory~currentFolder~"/"~directory~"/"~mailID, "wb"); 122 file.rawWrite(cast(byte[])mail); 123 file.close(); 124 } 125 126 /* TODO: Clean up any mail no longer present on server */ 127 /* TODO: Clean up any folders no longer present on server */ 128 129 /* Do the same on the current folder */ 130 createFolderStructures(mailboxDirectory, currentFolder~"/"~directory, client); 131 } 132 } 133 134 /** 135 * Sends mail provided the subject, address(es) and body 136 * 137 * Assumes that the first active account is to be used (this can be changed)addresses 138 */ 139 void sendMail(string configFile, string subject, string[] addresses, string bodyText, ulong accountIndex = 0) 140 { 141 /* Read in configurstion */ 142 Configuration configuration = new Configuration(getConfiguration(configFile)); 143 144 /* Get the account to be used (TODO: Bounds check) */ 145 Account chosenAccount = configuration.getAccount(accountIndex); 146 147 /* Authenticate a new session (TODO: Error handling in library and then catch here) */ 148 gprintln("Opening connection to "~to!(string)(chosenAccount.getServer())); 149 ButterflyClient client = new ButterflyClient(chosenAccount.getServer()); 150 151 /* Authenticate (TODO: Error) */ 152 gprintln("Authenticating with server..."); 153 client.authenticate(chosenAccount.getUsername(), chosenAccount.getPassword()); 154 155 /* Construct the mail */ 156 JSONValue mailMessage; 157 mailMessage["recipients"] = parseJSON(to!(string)(addresses)); 158 mailMessage["subject"] = subject; 159 mailMessage["body"] = bodyText; 160 161 /* Send the mail */ 162 gprintln("Sending mail..."); 163 client.sendMail(mailMessage); 164 gprintln("Mail sent!"); 165 } 166 167 string composeMail() 168 { 169 /* Read in from the tty */ 170 File tty; 171 tty.open("/dev/stdin", "rb"); 172 173 /* Body lines */ 174 string bodyLines; 175 176 while(true) 177 { 178 /* Read in 30-bute strides */ 179 byte[] bodyLine; 180 bodyLine.length = 30; 181 182 /* Read a line */ 183 bodyLine = tty.rawRead(bodyLine); 184 185 /** 186 * Read returns then we are done reading, either the bodyLine.length 187 * is non-zero but if it is zero then nothing was read (hence an EOF) 188 * signal 189 */ 190 if(bodyLine.length == 0) 191 { 192 /* Close the file and stop loop */ 193 tty.close(); 194 break; 195 } 196 197 /* Store the line */ 198 bodyLines ~= bodyLine; 199 } 200 201 return bodyLines; 202 } 203 204 /** 205 * Register 206 */ 207 void register(Address server, string username, string password) 208 { 209 /* Open a new session (TODO: Error handling in library and then catch here) */ 210 gprintln("Opening connection to "~to!(string)(server)); 211 ButterflyClient client = new ButterflyClient(server); 212 213 /* Register (TODO: Error) */ 214 gprintln("Registering with server..."); 215 try 216 { 217 client.register(username, password); 218 gprintln("Registration succeeded"); 219 } 220 catch(ButterflyException e) 221 { 222 gprintln("Registration failed", DebugType.ERROR); 223 } 224 225 /* TODO: Perhaps add an entry to the configuration file */ 226 }