526a60f847d3d71e6050ad2ea9016ff7c6f7fd60
[framework/web/wrt-plugins-common.git] / src / modules / tizen / Messaging / Email.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /**
17  *
18  *
19  * @file       Email.cpp
20  * @author     Pawel Misiak (p.misiak@samsung.com)
21  * @version    0.1
22  * @brief
23  */
24 #include <cstdio>
25 #include <cstddef>
26 #include <ctime>
27 #include <emf-types.h>
28 #include <Emf_Mapi.h>
29 #include <dpl/log/log.h>
30 #include <dpl/assert.h>
31 #include <dpl/scoped_fclose.h>
32 #include <dpl/scoped_ptr.h>
33 #include <Commons/Exception.h>
34 #include <Commons/StringUtils.h>
35 #include <API/Messaging/MessageFactory.h>
36 #include <API/Messaging/EmailAccountInfo.h>
37 #include "Messaging.h"
38 #include "Email.h"
39 #include "EmailService.h"
40 #include "EmailUtils.h"
41 #include "EmailConverter.h"
42 #include "MailSender.h"
43
44 #define LOG_ENTER LogDebug("---> ENTER");
45 #define LOG_EXIT LogDebug("---> EXIT");
46
47 using namespace std;
48 using namespace WrtDeviceApis::Messaging;
49 using namespace WrtDeviceApis::Messaging::Api;
50
51 namespace WrtDeviceApis {
52 namespace Messaging {
53 namespace {
54 //#define USE_OUTBOX
55
56 #ifdef USE_OUTBOX
57 const Api::FolderType DEFAULT_FOLDER = Api::OUTBOX;
58 //const char* DEFAULT_FOLDER_NAME = EMF_OUTBOX_NAME;
59 #else
60 const Api::FolderType DEFAULT_FOLDER = Api::DRAFTBOX;
61 //const char* DEFAULT_FOLDER_NAME = EMF_DRAFTBOX_NAME;
62 #endif
63 }
64
65 Email::Email(const string& id) : IMessage(Api::EMAIL, id)
66 {
67     LOG_ENTER
68
69     try {
70         if (getIdRef().empty()) {
71             create();
72         }
73         // always read the message (after creation some of attributes change
74         // i.e. body->plain)
75         reload();
76     }
77     catch (const Commons::PlatformException& ex) {
78         LogError("Exception: " << ex.DumpToString());
79     }
80
81     LOG_EXIT
82 }
83
84 Email::~Email()
85 {
86     LogDebug("ENTER");
87 }
88
89 void Email::send()
90 {
91     LOG_ENTER
92
93     update();
94
95     MailSender::getInstance().send(
96         Api::MessageFactory::convertToEmail(SharedFromThis())
97         );
98
99     LOG_EXIT
100 }
101
102 void Email::sendCancel()
103 {
104     LOG_ENTER
105
106     MailSender::getInstance().cancel(getIntId());
107
108     LOG_EXIT
109 }
110
111 void Email::update(bool draftsOnly)
112 {
113     LOG_ENTER
114
115     DPL::Mutex::ScopedLock mx(&m_updateMutex);
116
117     if (!m_mail) {
118         ThrowMsg(Commons::PlatformException, "Mail is NULL.");
119     }
120
121     if (!draftsOnly || (getCurrentFolder() == Api::DRAFTBOX)) {
122         updateBody();
123         updateSubject();
124         updateRecipients();
125         updateFrom();
126         updateAttachments();
127         updatePriority();
128     } else {
129         LogWarning("Updating only read status. Folder: " << getCurrentFolder());
130     }
131     updateReadStatus();
132
133     int error = email_update_message(getIntId(), m_mail.Get());
134     if (EMF_ERROR_NONE != error) {
135         LogWarning("Nothing to update or error. [" << error << "]");
136     }
137
138     LOG_EXIT
139 }
140
141 int Email::getAccountId() const
142 {
143     return m_accountId;
144 }
145
146 void Email::readAllData()
147 {
148     reload();
149 }
150
151 void Email::moveToFolder(const Api::FolderType newFolder)
152 {
153     LOG_ENTER
154
155     moveToFolder(EmailConverter::toMailboxName(newFolder));
156
157     LOG_EXIT
158 }
159
160 void Email::moveToFolder(const string& newFolder)
161 {
162     update();
163
164     int accountId = Messaging::getInstance().getEmailAccountId(getFromRef());
165     ScopedMailbox mailbox(
166         EmailService::createMailbox(accountId, newFolder.c_str())
167         );
168
169     int mailId = getIntId();
170
171     int error = email_move_mail_to_mailbox(&mailId, 1, mailbox.Get());
172     if (EMF_ERROR_NONE != error) {
173         ThrowMsg(
174             Commons::PlatformException,
175             "Couldn't move mail to folder: " << newFolder << ". [" <<
176             error << "]");
177     }
178 }
179
180 void Email::copyToFolder(const FolderType newFolder)
181 {
182     LOG_ENTER
183
184     copyToFolder(EmailConverter::toMailboxName(newFolder));
185
186     LOG_EXIT
187 }
188
189 void Email::copyToFolder(const string& newFolder)
190 {
191     LOG_ENTER
192
193     update();
194
195     int accountId = Messaging::getInstance().getEmailAccountId(getFromRef());
196
197     ScopedMail mail(EmailService::cloneMail(m_mail.Get()));
198     ScopedMailbox mailbox(
199         EmailService::createMailbox(accountId, newFolder.c_str())
200         );
201
202     int mailId = EmailService::addMailToMailbox(mail.Get(), mailbox.Get());
203     // TODO Is following check necessary?
204     if (0 == mailId) {
205         ThrowMsg(Commons::PlatformException, "Cloned mail didn't get new id.");
206     }
207
208     LOG_EXIT
209 }
210
211 void Email::remove()
212 {
213     EmailService::deleteMail(m_accountId, getIntId());
214 }
215
216 void Email::create()
217 {
218     LOG_ENTER
219
220     EmailAccountInfo account = IMessaging::getInstance().getCurrentEmailAccount();
221     ScopedMail mail(EmailService::createMail(account));
222     ScopedMailbox mailbox(
223         EmailService::getMailboxByType(account.getIntId(),
224                                        EMF_MAILBOX_TYPE_DRAFT)
225         );
226     setId(convertId(EmailService::addMailToMailbox(mail.Get(), mailbox.Get())));
227     setFolderType(Api::DRAFTBOX);
228
229     LOG_EXIT
230 }
231
232 void Email::reload()
233 {
234     LOG_ENTER
235
236     EmailAccountInfo account = Messaging::getInstance().getCurrentEmailAccount();
237
238     m_mail.Reset(EmailService::readMail(account.getIntId(), getIntId()));
239
240     if (m_mail->head) { readHeader(); }
241     if (m_mail->body) { readBody(); }
242     if (m_mail->info) { readInfo(); }
243
244     m_mailbox.Reset(
245         EmailService::getMailboxByMailId(account.getIntId(), getIntId())
246         );
247     setFolderType(EmailConverter::toFolderType(m_mailbox->mailbox_type));
248
249     LOG_EXIT
250 }
251
252 void Email::readHeader()
253 {
254     LOG_ENTER
255
256     Assert(m_mail && m_mail->head && "Header is NULL.");
257
258     if (m_mail->head->subject) {
259         setSubject(m_mail->head->subject);
260     }
261
262     if (m_mail->head->to) {
263         appendToRecipients(EmailUtils::stripAddressLine(m_mail->head->to));
264     }
265
266     if (m_mail->head->cc) {
267         appendCcRecipients(EmailUtils::stripAddressLine(m_mail->head->cc));
268     }
269
270     if (m_mail->head->bcc) {
271         appendBccRecipients(EmailUtils::stripAddressLine(m_mail->head->bcc));
272     }
273
274     time_t rawtime;
275     time(&rawtime);
276     struct tm tmpTime = *(localtime(&rawtime));
277     tmpTime.tm_year = m_mail->head->datetime.year;
278     tmpTime.tm_mon = m_mail->head->datetime.month;
279     tmpTime.tm_mday = m_mail->head->datetime.day;
280     tmpTime.tm_hour = m_mail->head->datetime.hour;
281     tmpTime.tm_min = m_mail->head->datetime.minute;
282     tmpTime.tm_sec = m_mail->head->datetime.second;
283     mktime(&tmpTime);
284     setDateTime(tmpTime);
285
286     if (m_mail->head->from) {
287         Recipients from;
288         from.setRecipients(m_mail->head->from);
289         setSourceAddress(from);
290         setSourceAddressValidity(true); //not needed to update in platform
291     }
292
293     LOG_EXIT
294 }
295
296 void Email::readBody()
297 {
298     LOG_ENTER
299
300     Assert(m_mail && m_mail->body && "Body is NULL.");
301
302     if (m_mail->body->plain) {
303         DPL::ScopedFClose file(::fopen(m_mail->body->plain, "r"));
304         if (!file) {
305             ThrowMsg(Commons::PlatformException,
306                      "Cannot read body file: " << m_mail->body->plain);
307         }
308         fseek(file.Get(), 0, SEEK_END);
309         long int size = ftell(file.Get());
310         fseek(file.Get(), 0, SEEK_SET);
311         DPL::ScopedPtr<char> data(new char[size + 1]);
312         memset(data.Get(), 0, size + 1);
313         fread(data.Get(), 1, size, file.Get());
314         setBody(data.Get());
315     }
316
317     if (m_mail->body->attachment && m_mail->body->attachment_num > 0) {
318         LogDebug("reading attachments");
319         emf_attachment_info_t* attach = m_mail->body->attachment;
320         for (int i = 0; i < m_mail->body->attachment_num; ++i) {
321             if (!attach) {
322                 ThrowMsg(Commons::PlatformException,
323                          "Attachment list shorter than expected.");
324             }
325             try {
326                 IAttachmentPtr tmpAtt = appendAttachment(attach->savename,
327                                                          false);
328                 tmpAtt->rename(attach->name);
329                 attach = attach->next;
330             }
331             catch (const Commons::Exception& ex) {
332                 LogError("Error while trying to append attachment " <<
333                          attach->savename << ": " << ex.DumpToString());
334             }
335         }
336     }
337
338     LOG_EXIT
339 }
340
341 void Email::readInfo()
342 {
343     LOG_ENTER
344
345     Assert(m_mail && m_mail->info && "Info is NULL.");
346
347     setReadStatus(m_mail->info->flags.seen == 1);
348
349     m_accountId = m_mail->info->account_id;
350
351     setPriority(
352         EmailConverter::toMessagePriority(
353             m_mail->info->extra_flags.priority
354             )
355         );
356     setSize(m_mail->info->rfc822_size);
357
358     LOG_EXIT
359 }
360
361 void Email::updateBody()
362 {
363     LOG_ENTER
364
365     if (isBodyValid()) { return; }
366
367     if (!m_mail) {
368         ThrowMsg(Commons::PlatformException, "Mail is NULL.");
369     }
370
371     if (!m_mail->body) {
372         ThrowMsg(Commons::PlatformException, "Body is NULL.");
373     }
374     if (!m_mail->body->plain) {
375         ThrowMsg(Commons::PlatformException, "Body file is NULL.");
376     }
377     if (!m_mail->info) {
378         ThrowMsg(Commons::PlatformException, "Info is NULL.");
379     }
380
381     FILE* f = fopen(m_mail->body->plain, "w");
382     if (NULL != f) {
383         fprintf(f, getBodyRef().c_str());
384         fclose(f);
385     }
386     m_mail->info->body_downloaded = true;
387     setBodyValidity(true);
388
389     LOG_EXIT
390 }
391
392 void Email::updateSubject()
393 {
394     LOG_ENTER
395
396     if (isSubjectValid()) { return; }
397
398     LogDebug("update subject, msgId=" << getIdRef());
399
400     if (!m_mail) {
401         ThrowMsg(Commons::PlatformException, "Mail not allocated.");
402     }
403
404     if (!m_mail->head) {
405         m_mail->head = EmailService::alloc<emf_mail_head_t>();
406     }
407
408     m_mail->head->subject = Commons::String::strdup(getSubjectRef());
409     setSubjectValidity(true);
410
411     LOG_EXIT
412 }
413
414 void Email::updateReadStatus()
415 {
416     LOG_ENTER
417
418     if (isReadStatusValid()) { return; }
419
420     LogDebug("update read, msgId=" << getIdRef());
421
422     if (!m_mail) {
423         ThrowMsg(Commons::PlatformException, "Mail not allocated.");
424     }
425
426     if (!m_mail->info) {
427         EmailService::alloc<emf_mail_info_t>();
428     }
429
430     m_mail->info->flags.seen = isRead();
431     setReadStatusValidity(true);
432
433     LOG_EXIT
434 }
435
436 void Email::updateRecipients()
437 {
438     LOG_ENTER
439
440     if (getToValidity() && getCcValidity() && getBccValidity()) { return; }
441
442     if (!m_mail) {
443         ThrowMsg(Commons::PlatformException, "Mail is NULL.");
444     }
445
446     if (!m_mail->head) {
447         m_mail->head = EmailService::alloc<emf_mail_head_t>();
448     }
449
450     if (!getToValidity()) {
451         std::string addressLine = EmailUtils::formatAddressLine(getToRecipients());
452         if (m_mail->head->to) {
453             free(m_mail->head->to);
454         }
455         m_mail->head->to = Commons::String::strdup(addressLine);
456         setToValidity(true);
457     }
458
459     if (!getCcValidity()) {
460         std::string addressLine = EmailUtils::formatAddressLine(getCcRecipients());
461         if (m_mail->head->cc) {
462             free(m_mail->head->cc);
463         }
464         m_mail->head->cc = Commons::String::strdup(addressLine);
465         setCcValidity(true);
466     }
467
468     if (!getBccValidity()) {
469         std::string addressLine = EmailUtils::formatAddressLine(
470                 getBccRecipients());
471         if (m_mail->head->bcc) {
472             free(m_mail->head->bcc);
473         }
474         m_mail->head->bcc = Commons::String::strdup(addressLine);
475         setBccValidity(true);
476     }
477
478     LOG_EXIT
479 }
480
481 void Email::updateFrom()
482 {
483     LOG_ENTER
484
485     if (getFromValidity()) { return; }
486
487     if (!m_mail) {
488         ThrowMsg(Commons::PlatformException, "Mail is NULL.");
489     }
490
491     if (!m_mail->info) {
492         EmailService::alloc<emf_mail_info_t>();
493     }
494
495     m_mail->info->account_id = Messaging::getInstance().getEmailAccountId(
496             getFrom());
497     // TODO Update m_mail->head->from as well
498
499     setFromValidity(true);
500
501     LOG_EXIT
502 }
503
504 void Email::updateAttachments()
505 {
506     LOG_ENTER
507
508     if (isAttachmentsValid()) { return; }
509
510     if (!m_mail) {
511         ThrowMsg(Commons::PlatformException, "Mail is NULL.");
512     }
513
514     emf_attachment_info_t* attachment = NULL;
515     Try {
516         LogDebug("update attachments, msgId=" << getIdRef());
517
518         if (!m_mail->body) {
519             m_mail->body = EmailService::alloc<emf_mail_body_t>();
520         } else {
521             m_mail->body->attachment_num = 0;
522             if (NULL != m_mail->body->attachment) {
523                 EmailService::freeAttachment(m_mail->body->attachment);
524                 m_mail->body->attachment = NULL;
525             }
526         }
527
528         std::size_t attachmentSize = getAttachmentsCount();
529         if (attachmentSize > 0) {
530             if (!m_mail->info) {
531                 ThrowMsg(Commons::PlatformException, "Mail info is NULL.");
532             }
533
534             for (std::size_t i = 0; i < attachmentSize; ++i) {
535                 IAttachmentPtr att = getAttachment(i);
536                 if (!att) {
537                     continue;
538                 }
539
540                 LogDebug("updating attachment=" << att->getShortName());
541
542                 attachment = EmailService::alloc<emf_attachment_info_t>();
543                 attachment->name = Commons::String::strdup(att->getShortName());
544                 attachment->savename = Commons::String::strdup(
545                         att->getFullPath()
546                         );
547                 attachment->downloaded = true;
548                 attachment->next = NULL;
549
550                 int error = email_add_attachment(m_mailbox.Get(),
551                                                  m_mail->info->uid,
552                                                  attachment);
553                 if (EMF_ERROR_NONE != error) {
554                     ThrowMsg(Commons::PlatformException,
555                              "Error while adding attachment. [" << error << "]");
556                 }
557
558                 EmailService::freeAttachment(attachment);
559             }
560
561             setAttachmentsValidity(true);
562         }
563     }
564     Catch(Commons::PlatformException) {
565         EmailService::freeAttachment(attachment);
566         throw;
567     }
568
569     LOG_EXIT
570 }
571
572 void Email::updatePriority()
573 {
574     LOG_ENTER
575
576     if (isPriorityValid()) { return; }
577
578     if (!m_mail) {
579         ThrowMsg(Commons::PlatformException, "Mail not allocated.");
580     }
581
582     if (!m_mail->info) {
583         m_mail->info = EmailService::alloc<emf_mail_info_t>();
584     }
585
586     m_mail->info->extra_flags.priority = EmailConverter::toMailPriority(
587             getPriority());
588     setPriorityValid(true);
589
590     LOG_EXIT
591 }
592
593 int Email::getIntId() const
594 {
595     return convertId(getIdRef());
596 }
597 }
598 }