a894bad44629e5cfb64a41acedcca4e717db8f56
[motion.git] / server / config / imap / imap.js
1 'use strict';
2
3 var _ = require('lodash');
4 var path = require('path');
5 var config = require('../environment');
6 var ImapListener = require("mail-listener2");
7 var MailServerIn = require('../../models').MailServerIn;
8 var MailMessage = require('../../models').MailMessage;
9 var MailRoom = require('../../models').MailRoom;
10 var Contact = require('../../models').Contact;
11 var ContactEmail = require('../../models').ContactEmail;
12 var sequelize = require('../../models').sequelize;
13
14 // Public
15 module.exports = {
16   create: function (doc) {
17
18     var imap;
19
20     function onUpdate(doc) {
21       if (!doc.changed('state') && !doc.changed('source') && doc.username === imap.imap._config.user) {
22         console.log("MAIL - Account " + doc.username + " IMAP UPDATED");
23         imap.stop();
24         onSave(doc);
25       }
26     }
27
28     function onRemove(doc) {
29       if (doc.username === imap.imap._config.user) {
30         console.log("MAIL - Account " + doc.username + " IMAP DESTROY");
31         imap.stop();
32         imap = null;
33       }
34     }
35
36     function onSave(doc) {
37
38       if (imap) {
39         imap.stop(doc);
40         imap = null;
41       }
42
43       imap = new ImapListener({
44         username: doc.username,
45         password: doc.password,
46         host: doc.host,
47         port: doc.port,
48         tls: doc.ssl,
49         tlsOptions: {
50           rejectUnauthorized: false
51         },
52         mailbox: doc.mailbox, // mailbox to monitor
53         searchFilter: [doc.filter], // the search filter being used after an IDLE notification has been retrieved
54         markSeen: true, // all fetched email willbe marked as seen and not fetched next time
55         fetchUnreadOnStart: true, // use it only if you want to get all unread email on lib start. Default is `false`,,
56         mailParserOptions: {
57           streamAttachments: false
58         }, // options to be passed to mailParser lib.
59         attachments: true, // download attachments as they are encountered to the project directory
60         attachmentOptions: {
61           directory: path.join(config.root, 'server', 'files', 'attachments', '/')
62         } // specify a download directory for attachments
63       });
64
65       imap.start();
66
67       imap.on("server:connected", function () {
68         console.log("MAIL - Account " + doc.username + " IMAP CONNECTED");
69         // SETUP CONNECTED STATUS
70         return MailServerIn
71           .findById(doc.id)
72           .then(function (msi) {
73             return msi
74               .update({
75                 state: 'CONNECTED'
76               });
77           })
78           .catch(function (err) {
79             console.error(err);
80           });
81       });
82
83       imap.on("server:disconnected", function () {
84         console.log("MAIL - Account " + doc.MailAccountId + " IMAP DISCONNECTED");
85         MailServerIn
86           .findById(doc.id)
87           .then(function (msi) {
88             msi
89               .updateAttributes({
90                 state: 'DISCONNECTED'
91               });
92           })
93           .catch(function (err) {
94             console.error(err);
95           });
96       });
97
98       imap.on("error", function (err) {
99         console.log("MAIL - Account " + doc.MailAccountId + " IMAP ERROR", err);
100         MailServerIn
101           .findById(doc.id)
102           .then(function (msi) {
103             msi
104               .updateAttributes({
105                 state: 'ERROR',
106                 source: err.source
107               });
108           })
109           .catch(function (err) {
110             console.error(err);
111           });
112       });
113
114       imap.on("mail", function (msg, seqno, attributes) {
115         var _mRoom;
116         var _mMessage;
117         var _mFrom, _mTo, _mCc, _mBcc;
118
119         function createMailMessage(mailRoom) {
120           _mRoom = mailRoom;
121
122           return MailMessage
123             .create({
124               messageId: msg.messageId,
125               subject: msg.subject,
126               from: _.pluck(msg.from, 'address').join(';'),
127               to: msg.to ? _.pluck(msg.to, 'address').join(';') : null,
128               cc: msg.cc ? _.pluck(msg.cc, 'address').join(';') : null,
129               bcc: msg.cc ? _.pluck(msg.bcc, 'address').join(';') : null,
130               status: 'RECEIVED',
131               html: msg.html || null,
132               text: msg.text || null,
133               MailAttachments: msg.attachments || [],
134               MailRoomId: mailRoom.id,
135             });
136         }
137
138         function createFrom(mailMessage) {
139           _mMessage = mailMessage;
140
141           return ContactEmail
142             .findOrCreate({
143               where: {
144                 email: _mMessage.from
145               },
146               defaults: {
147                 email: _mMessage.from
148               }
149             });
150         }
151
152         function createTo(mFrom, created) {
153           var promises = [];
154           var tos = _mMessage.to ? _.pluck(msg.to, 'address') : [];
155           _mFrom = mFrom;
156
157           tos.forEach(function (email) {
158             promises.push(ContactEmail
159               .findOrCreate({
160                 where: {
161                   email: email
162                 },
163                 defaults: {
164                   email: email
165                 }
166               }));
167           });
168
169           return promises;
170         }
171
172         function createCc(mTo) {
173           var promises = [];
174           var ccs = _mMessage.cc ? _.pluck(msg.cc, 'address') : [];
175           _mTo = _.map(mTo, function (elm) {
176             return elm[0];
177           });
178
179           ccs.forEach(function (email) {
180             promises.push(ContactEmail
181               .findOrCreate({
182                 where: {
183                   email: email
184                 },
185                 defaults: {
186                   email: email
187                 }
188               }));
189           });
190
191           return promises;
192         }
193
194         function createBcc(mCc) {
195           var promises = [];
196           var bccs = _mMessage.bcc ? _.pluck(msg.bcc, 'address') : [];
197           _mCc = _.map(mCc, function (elm) {
198             return elm[0];
199           });
200
201           bccs.forEach(function (email) {
202             promises.push(ContactEmail
203               .findOrCreate({
204                 where: {
205                   email: email
206                 },
207                 defaults: {
208                   email: email
209                 }
210               }));
211           });
212
213           return promises;
214         }
215
216         function setBcc(mBcc) {
217           _mBcc = _.map(mBcc, function (elm) {
218             return elm[0];
219           });
220
221           return;
222         }
223
224         return sequelize.transaction(function (t) {
225           if (msg.inReplyTo) {
226             console.log('msg', msg);
227             return MailMessage
228               .findOne({
229                 where: {
230                   messageId: msg.inReplyTo[0]
231                 },
232                 include: [{
233                   all: true
234                 }]
235               })
236               .then(function (mailMessageParent) {
237                 return mailMessageParent
238                   .getMailRoom();
239               })
240               .then(function (mailRoom) {
241                 _mRoom = mailRoom;
242
243                 return MailMessage
244                   .create({
245                     messageId: msg.messageId,
246                     subject: msg.subject,
247                     from: _.pluck(msg.from, 'address').join(';'),
248                     to: msg.to ? _.pluck(msg.to, 'address').join(';') : null,
249                     cc: msg.cc ? _.pluck(msg.cc, 'address').join(';') : null,
250                     bcc: msg.cc ? _.pluck(msg.bcc, 'address').join(';') : null,
251                     status: 'RECEIVED',
252                     html: msg.html || null,
253                     text: msg.text || null,
254                     MailAttachments: msg.attachments || [],
255                     MailRoomId: mailRoom.id,
256                   }, {
257                     include: [{
258                       all: true
259                     }],
260                     transaction: t
261                   });
262               })
263               .then(function (mailMessage) {
264                 _mMessage = mailMessage;
265
266                 return ContactEmail
267                   .findOrCreate({
268                     where: {
269                       email: _mMessage.from
270                     },
271                     defaults: {
272                       email: _mMessage.from
273                     },
274                     transaction: t
275                   });
276               })
277               .spread(function (mFrom, created) {
278                 var promises = [];
279                 var tos = _mMessage.to ? _.pluck(msg.to, 'address') : [];
280                 _mFrom = mFrom;
281
282                 tos.forEach(function (email) {
283                   promises.push(ContactEmail
284                     .findOrCreate({
285                       where: {
286                         email: email
287                       },
288                       defaults: {
289                         email: email
290                       },
291                       transaction: t
292                     }));
293                 });
294
295                 return promises;
296               })
297               .all()
298               .then(function (mTo) {
299                 var promises = [];
300                 var ccs = _mMessage.cc ? _.pluck(msg.cc, 'address') : [];
301                 _mTo = _.map(mTo, function (elm) {
302                   return elm[0];
303                 });
304
305                 ccs.forEach(function (email) {
306                   promises.push(ContactEmail
307                     .findOrCreate({
308                       where: {
309                         email: email
310                       },
311                       defaults: {
312                         email: email
313                       },
314                       transaction: t
315                     }));
316                 });
317
318                 return promises;
319               })
320               .all()
321               .then(function (mCc) {
322                 var promises = [];
323                 var bccs = _mMessage.bcc ? _.pluck(msg.bcc, 'address') : [];
324                 _mCc = _.map(mCc, function (elm) {
325                   return elm[0];
326                 });
327
328                 bccs.forEach(function (email) {
329                   promises.push(ContactEmail
330                     .findOrCreate({
331                       where: {
332                         email: email
333                       },
334                       defaults: {
335                         email: email
336                       },
337                       transaction: t
338                     }));
339                 });
340
341                 return promises;
342               })
343               .all()
344               .then(function (mBcc) {
345                 _mBcc = _.map(mBcc, function (elm) {
346                   return elm[0];
347                 });
348
349                 return;
350               })
351               .then(function () {
352                 return _mMessage
353                   .setFrom(_mFrom, {
354                     transaction: t
355                   });
356               })
357               .then(function () {
358                 return _mMessage
359                   .setTo(_mTo, {
360                     transaction: t
361                   });
362               })
363               .then(function () {
364                 return _mMessage
365                   .setCc(_mCc, {
366                     transaction: t
367                   });
368               })
369               .then(function () {
370                 return _mMessage
371                   .setBcc(_mBcc, {
372                     transaction: t
373                   });
374               });
375
376           } else {
377             return MailRoom
378               .create({
379                 roomId: msg.messageId,
380                 subject: msg.subject,
381                 from: _.pluck(msg.from, 'address').join(';'),
382                 MailAccountId: doc.MailAccountId
383               }, {
384                 transaction: t
385               })
386               .then(function (mailRoom) {
387                 _mRoom = mailRoom;
388
389                 return MailMessage
390                   .create({
391                     messageId: msg.messageId,
392                     subject: msg.subject,
393                     from: _.pluck(msg.from, 'address').join(';'),
394                     to: msg.to ? _.pluck(msg.to, 'address').join(';') : null,
395                     cc: msg.cc ? _.pluck(msg.cc, 'address').join(';') : null,
396                     bcc: msg.cc ? _.pluck(msg.bcc, 'address').join(';') : null,
397                     status: 'RECEIVED',
398                     html: msg.html || null,
399                     text: msg.text || null,
400                     MailAttachments: msg.attachments || [],
401                     MailRoomId: mailRoom.id,
402                   }, {
403                     include: [{
404                       all: true
405                     }],
406                     transaction: t
407                   });
408               })
409               .then(function (mailMessage) {
410                 _mMessage = mailMessage;
411
412                 return ContactEmail
413                   .findOrCreate({
414                     where: {
415                       email: _mMessage.from
416                     },
417                     defaults: {
418                       email: _mMessage.from
419                     },
420                     transaction: t
421                   });
422               })
423               .spread(function (mFrom, created) {
424                 var promises = [];
425                 var tos = _mMessage.to ? _.pluck(msg.to, 'address') : [];
426                 _mFrom = mFrom;
427
428                 tos.forEach(function (email) {
429                   promises.push(ContactEmail
430                     .findOrCreate({
431                       where: {
432                         email: email
433                       },
434                       defaults: {
435                         email: email
436                       },
437                       transaction: t
438                     }));
439                 });
440
441                 return promises;
442               })
443               .all()
444               .then(function (mTo) {
445                 var promises = [];
446                 var ccs = _mMessage.cc ? _.pluck(msg.cc, 'address') : [];
447                 _mTo = _.map(mTo, function (elm) {
448                   return elm[0];
449                 });
450
451                 ccs.forEach(function (email) {
452                   promises.push(ContactEmail
453                     .findOrCrredieate({
454                       where: {
455                         email: email
456                       },
457                       defaults: {
458                         email: email
459                       },
460                       transaction: t
461                     }));
462                 });
463
464                 return promises;
465               })
466               .all()
467               .then(function (mCc) {
468                 var promises = [];
469                 var bccs = _mMessage.bcc ? _.pluck(msg.bcc, 'address') : [];
470                 _mCc = _.map(mCc, function (elm) {
471                   return elm[0];
472                 });
473
474                 bccs.forEach(function (email) {
475                   promises.push(ContactEmail
476                     .findOrCreate({
477                       where: {
478                         email: email
479                       },
480                       defaults: {
481                         email: email
482                       },
483                       transaction: t
484                     }));
485                 });
486
487                 return promises;
488               })
489               .all()
490               .then(function (mBcc) {
491                 _mBcc = _.map(mBcc, function (elm) {
492                   return elm[0];
493                 });
494
495                 return;
496               })
497               .then(function () {
498                 return _mMessage
499                   .setFrom(_mFrom, {
500                     transaction: t
501                   });
502               })
503               .then(function () {
504                 return _mMessage
505                   .setTo(_mTo, {
506                     transaction: t
507                   });
508               })
509               .then(function () {
510                 return _mMessage
511                   .setCc(_mCc, {
512                     transaction: t
513                   });
514               })
515               .then(function () {
516                 return _mMessage
517                   .setBcc(_mBcc, {
518                     transaction: t
519                   });
520               });
521           }
522         }).then(function (result) {
523           // Transaction has been committed
524           // result is whatever the result of the promise chain returned to the transaction callback
525           console.log(result);
526         }).catch(function (err) {
527           // Transaction has been rolled back
528           // err is whatever rejected the promise chain returned to the transaction callback
529           console.error(err);
530         });
531       });
532
533       imap.on("attachment", function (attachment) {
534         console.log(attachment.path);
535       });
536     }
537
538     onSave(doc);
539
540     MailServerIn.afterCreate(function (doc) {
541       onSave(doc);
542     });
543     // HANDLE ACCOUNT UPDATE/DELETE
544     MailServerIn.afterUpdate(function (doc) {
545       onUpdate(doc);
546     });
547     MailServerIn.afterDestroy(function (doc) {
548       onRemove(doc);
549     });
550   }
551 };