1 module libutterfly.client; 2 3 import std.socket; 4 import bmessage; 5 import std.json; 6 import libutterfly.exceptions : ButterflyException; 7 8 public final class ButterflyClient 9 { 10 11 /** 12 * Socket connection to the server 13 */ 14 private Socket connection; 15 16 /** 17 * Creates a new ButterflyClient connected 18 * to the butterfly server specified by the 19 * Address `endpoint`. 20 */ 21 this(Address endpoint) 22 { 23 /** 24 * Connect to the remote server 25 */ 26 connection = new Socket(AddressFamily.INET, SocketType.STREAM, ProtocolType.TCP); 27 connection.connect(endpoint); 28 } 29 30 /** 31 * Authenticate to the server with the given `username` 32 * and `password`. 33 * 34 * Throws a ButterflyException if the authentication 35 * details are incorrect. 36 */ 37 public void authenticate(string username, string password) 38 { 39 /** 40 * Construct the command. 41 */ 42 JSONValue commandBlock; 43 commandBlock["command"] = "authenticate"; 44 45 JSONValue requestBlock; 46 requestBlock["username"] = username; 47 requestBlock["password"] = password; 48 49 commandBlock["request"] = requestBlock; 50 51 /* Send the command */ 52 sendMessage(connection, cast(byte[])toJSON(commandBlock)); 53 54 /* Get the status */ 55 JSONValue response; 56 57 byte[] receivedBytes; 58 receiveMessage(connection, receivedBytes); 59 response = parseJSON(cast(string)receivedBytes); 60 61 if(response["status"]["code"].integer() == 0) 62 { 63 /* TODO: Good */ 64 } 65 else 66 { 67 /* Throw an exception */ 68 throw new ButterflyException(response["status"]["message"].str(), response["status"]["code"].integer()); 69 } 70 } 71 72 73 public string editMail(string mailPath, JSONValue messageBlock) 74 { 75 string mailID; 76 77 78 /** 79 * Construct the command. 80 */ 81 JSONValue commandBlock; 82 commandBlock["command"] = "editMail"; 83 84 JSONValue requestBlock; 85 requestBlock["message"] = mailPath; 86 requestBlock["mail"] = messageBlock; 87 88 commandBlock["request"] = requestBlock; 89 90 /* Send the command */ 91 sendMessage(connection, cast(byte[])toJSON(commandBlock)); 92 93 /* Get the status */ 94 JSONValue response; 95 96 byte[] receivedBytes; 97 receiveMessage(connection, receivedBytes); 98 response = parseJSON(cast(string)receivedBytes); 99 100 if(response["status"]["code"].integer() == 0) 101 { 102 /* TODO: Good */ 103 } 104 else 105 { 106 /* Throw an exception */ 107 throw new ButterflyException(response["status"]["message"].str(), response["status"]["code"].integer()); 108 } 109 110 111 return mailID; 112 } 113 114 115 /** 116 * Send the provided JSONValue mail `messageBlock` 117 * 118 * Throws a ButterflyException if the mail sending 119 * fails. 120 */ 121 public void sendMail(JSONValue messageBlock) 122 { 123 /** 124 * Construct the command. 125 */ 126 JSONValue commandBlock; 127 commandBlock["command"] = "sendMail"; 128 129 JSONValue requestBlock; 130 requestBlock["mail"] = messageBlock; 131 132 commandBlock["request"] = requestBlock; 133 134 /* Send the command */ 135 sendMessage(connection, cast(byte[])toJSON(commandBlock)); 136 137 /* Get the status */ 138 JSONValue response; 139 140 byte[] receivedBytes; 141 receiveMessage(connection, receivedBytes); 142 response = parseJSON(cast(string)receivedBytes); 143 144 if(response["status"]["code"].integer() == 0) 145 { 146 /* TODO: Good */ 147 } 148 else 149 { 150 /* Throw an exception */ 151 throw new ButterflyException(response["status"]["message"].str(), response["status"]["code"].integer()); 152 } 153 } 154 155 /** 156 * Returns a string[] of the folder names in the given 157 * folder, `folderPath` 158 * 159 * Throws a ButterflyException if the lookup fails. 160 */ 161 public string[] listFolder(string folderPath) 162 { 163 /** 164 * Construct the command. 165 */ 166 JSONValue commandBlock; 167 commandBlock["command"] = "listFolder"; 168 169 JSONValue requestBlock; 170 requestBlock["folderName"] = folderPath; 171 172 commandBlock["request"] = requestBlock; 173 174 /* Send the command */ 175 sendMessage(connection, cast(byte[])toJSON(commandBlock)); 176 177 /* Get the status */ 178 JSONValue response; 179 180 byte[] receivedBytes; 181 receiveMessage(connection, receivedBytes); 182 response = parseJSON(cast(string)receivedBytes); 183 184 if(response["status"]["code"].integer() == 0) 185 { 186 /* TODO: Good */ 187 string[] folderNames; 188 foreach(JSONValue folderName; response["response"]["folders"].array()) 189 { 190 folderNames ~= folderName.str(); 191 } 192 return folderNames; 193 } 194 else 195 { 196 /* Throw an exception */ 197 throw new ButterflyException(response["status"]["message"].str(), response["status"]["code"].integer()); 198 } 199 } 200 201 /** 202 * Deletes an existing folder under the path specified 203 * by `folderPath`. 204 * 205 * Throws a ButterflyException if the folder deletion 206 * fails. 207 */ 208 public void deleteFolder(string folderPath) 209 { 210 /** 211 * Construct the command. 212 */ 213 JSONValue commandBlock; 214 commandBlock["command"] = "deleteFolder"; 215 216 JSONValue requestBlock; 217 requestBlock["folderName"] = folderPath; 218 219 commandBlock["request"] = requestBlock; 220 221 /* Send the command */ 222 sendMessage(connection, cast(byte[])toJSON(commandBlock)); 223 224 /* Get the status */ 225 JSONValue response; 226 227 byte[] receivedBytes; 228 receiveMessage(connection, receivedBytes); 229 response = parseJSON(cast(string)receivedBytes); 230 231 if(response["status"]["code"].integer() == 0) 232 { 233 /* TODO: Good */ 234 } 235 else 236 { 237 /* Throw an exception */ 238 throw new ButterflyException(response["status"]["message"].str(), response["status"]["code"].integer()); 239 } 240 } 241 242 /** 243 * Creates a new folder under the path specified 244 * by `folderPath`. 245 * 246 * Throws a ButterflyException if the folder creation 247 * fails. 248 */ 249 public void createFolder(string folderPath) 250 { 251 /** 252 * Construct the command. 253 */ 254 JSONValue commandBlock; 255 commandBlock["command"] = "createFolder"; 256 257 JSONValue requestBlock; 258 requestBlock["folderName"] = folderPath; 259 260 commandBlock["request"] = requestBlock; 261 262 /* Send the command */ 263 sendMessage(connection, cast(byte[])toJSON(commandBlock)); 264 265 /* Get the status */ 266 JSONValue response; 267 268 byte[] receivedBytes; 269 receiveMessage(connection, receivedBytes); 270 response = parseJSON(cast(string)receivedBytes); 271 272 if(response["status"]["code"].integer() == 0) 273 { 274 /* TODO: Good */ 275 } 276 else 277 { 278 /* Throw an exception */ 279 throw new ButterflyException(response["status"]["message"].str(), response["status"]["code"].integer()); 280 } 281 } 282 283 /** 284 * Returns a string[] of the mail IDs within the 285 * given folder, `folderPath`. 286 * 287 * Throws a ButterflyException if the lookup fails. 288 */ 289 public string[] listMail(string folderPath) 290 { 291 /** 292 * Construct the command. 293 */ 294 JSONValue commandBlock; 295 commandBlock["command"] = "listMail"; 296 297 JSONValue requestBlock; 298 requestBlock["folderName"] = folderPath; 299 300 commandBlock["request"] = requestBlock; 301 302 /* Send the command */ 303 sendMessage(connection, cast(byte[])toJSON(commandBlock)); 304 305 /* Get the status */ 306 JSONValue response; 307 308 byte[] receivedBytes; 309 receiveMessage(connection, receivedBytes); 310 response = parseJSON(cast(string)receivedBytes); 311 312 if(response["status"]["code"].integer() == 0) 313 { 314 /* TODO: Good */ 315 string[] mailIDs; 316 foreach(JSONValue mailID; response["response"]["mailIDs"].array()) 317 { 318 mailIDs ~= mailID.str(); 319 } 320 return mailIDs; 321 } 322 else 323 { 324 /* Throw an exception */ 325 throw new ButterflyException(response["status"]["message"].str(), response["status"]["code"].integer()); 326 } 327 } 328 329 public string storeMail(string folderPath, JSONValue messageBlock) 330 { 331 string mailID; 332 333 334 /** 335 * Construct the command. 336 */ 337 JSONValue commandBlock; 338 commandBlock["command"] = "storeMail"; 339 340 JSONValue requestBlock; 341 requestBlock["folder"] = folderPath; 342 requestBlock["mail"] = messageBlock; 343 344 commandBlock["request"] = requestBlock; 345 346 /* Send the command */ 347 sendMessage(connection, cast(byte[])toJSON(commandBlock)); 348 349 /* Get the status */ 350 JSONValue response; 351 352 byte[] receivedBytes; 353 receiveMessage(connection, receivedBytes); 354 response = parseJSON(cast(string)receivedBytes); 355 356 if(response["status"]["code"].integer() == 0) 357 { 358 /* TODO: Good */ 359 mailID = response["response"]["mailID"].str(); 360 } 361 else 362 { 363 /* Throw an exception */ 364 throw new ButterflyException(response["status"]["message"].str(), response["status"]["code"].integer()); 365 } 366 367 368 return mailID; 369 } 370 371 /** 372 * Fetches the message block (mail message JSON) of the 373 * mail message specified by `mailID` located in the 374 * folder specified by `folderPath`. Returns it as a 375 * JSONValue. 376 * 377 * Throws a ButterflyException if the mail fetch fails. 378 */ 379 public JSONValue fetchMail(string folderPath, string mailID) 380 { 381 /** 382 * Construct the command. 383 */ 384 JSONValue commandBlock; 385 commandBlock["command"] = "fetchMail"; 386 387 JSONValue requestBlock; 388 requestBlock["folder"] = folderPath; 389 requestBlock["id"] = mailID; 390 391 commandBlock["request"] = requestBlock; 392 393 /* Send the command */ 394 sendMessage(connection, cast(byte[])toJSON(commandBlock)); 395 396 /* Get the status */ 397 JSONValue response; 398 399 byte[] receivedBytes; 400 receiveMessage(connection, receivedBytes); 401 response = parseJSON(cast(string)receivedBytes); 402 403 if(response["status"]["code"].integer() == 0) 404 { 405 /* TODO: Good */ 406 return response["response"]["mail"]; 407 } 408 else 409 { 410 /* Throw an exception */ 411 throw new ButterflyException(response["status"]["message"].str(), response["status"]["code"].integer()); 412 } 413 } 414 415 /** 416 * Registers a new account with the given `username` 417 * and `password`. 418 * 419 * Throws a ButterflyException if the account creation 420 * fails. 421 */ 422 public void register(string username, string password) 423 { 424 /** 425 * Construct the command. 426 */ 427 JSONValue commandBlock; 428 commandBlock["command"] = "register"; 429 430 JSONValue requestBlock; 431 requestBlock["username"] = username; 432 requestBlock["password"] = password; 433 434 commandBlock["request"] = requestBlock; 435 436 /* Send the command */ 437 sendMessage(connection, cast(byte[])toJSON(commandBlock)); 438 439 /* Get the status */ 440 JSONValue response; 441 442 byte[] receivedBytes; 443 receiveMessage(connection, receivedBytes); 444 response = parseJSON(cast(string)receivedBytes); 445 446 if(response["status"]["code"].integer() == 0) 447 { 448 /* TODO: Good */ 449 } 450 else 451 { 452 /* Throw an exception */ 453 throw new ButterflyException(response["status"]["message"].str(), response["status"]["code"].integer()); 454 } 455 } 456 }