2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
22 * @author Pawel Misiak (p.misiak@samsung.com)
30 #include <emf-types.h>
32 #include <dpl/log/log.h>
33 #include <dpl/assert.h>
34 #include <dpl/scoped_fclose.h>
35 #include <dpl/scoped_ptr.h>
36 #include <Commons/Exception.h>
37 #include <Commons/StringUtils.h>
38 #include <API/Messaging/MessageFactory.h>
39 #include <API/Messaging/EmailAccountInfo.h>
40 #include "Messaging.h"
42 #include "EmailService.h"
43 #include "EmailUtils.h"
44 #include "EmailConverter.h"
45 #include "MailSender.h"
47 #include "MessagingService.h"
48 #include "MessagingServiceManager.h"
49 #include "Attachment.h"
51 #define LOG_ENTER LogDebug("---> ENTER");
52 #define LOG_EXIT LogDebug("---> EXIT");
55 using namespace TizenApis::Api::Messaging;
56 using namespace WrtDeviceApis::Commons;
67 const Api::Messaging::FolderType DEFAULT_FOLDER = Api::Messaging::OUTBOX;
68 const char* DEFAULT_FOLDER_NAME = EMF_OUTBOX_NAME;
70 const Api::Messaging::FolderType DEFAULT_FOLDER = Api::Messaging::DRAFTBOX;
71 const char* DEFAULT_FOLDER_NAME = EMF_DRAFTBOX_NAME;
77 const char* TEMP_FOLDER = "/tmp";
78 const char* COMMAND_NAME = "/bin/cp";
79 const char* COMMAND_SWITCH_RECURSIVE = "-r";
80 const char* COMMAND_SWITCH_FORCE = "-f";
83 Email::Email(const string& id) :
88 if (getIdRef().empty()) {
91 // always read the message (after creation some of attributes change
97 } catch (const WrtDeviceApis::Commons::PlatformException& ex) {
98 LogError("Exception: " << ex.DumpToString());
104 Email::Email(const std::string& id, int accountId) :
110 // always read the message (after creation some of attributes change
114 LogDebug("Account ID = " << accountId);
115 m_accountId = accountId;
118 } catch (const WrtDeviceApis::Commons::PlatformException& ex) {
119 LogError("Exception: " << ex.DumpToString());
126 Email::Email(Api::Messaging::EmailAccountInfo& account) : IMessage(EMAIL)
131 if (getIdRef().empty()) {
134 // always read the message (after creation some of attributes change
138 catch (const WrtDeviceApis::Commons::PlatformException& ex) {
139 LogError("Exception: " << ex.DumpToString());
156 int handle = MailSender::getInstance().send(
157 Api::Messaging::MessageFactory::convertToEmail(SharedFromThis())
164 void Email::sendCancel(int handle)
168 MailSender::getInstance().cancel(handle);
173 int Email::downloadBody()
177 return MailSync::getInstance().downloadBody( Api::Messaging::MessageFactory::convertToEmail(SharedFromThis()) );
182 void Email::downloadBodyCancel( int handle)
188 int Email::downloadAttachment( const Api::Messaging::IAttachmentPtr& attachment)
192 return MailSync::getInstance().downloadAttachment( Api::Messaging::MessageFactory::convertToEmail(SharedFromThis()), attachment );
197 void Email::update(bool draftsOnly)
201 DPL::Mutex::ScopedLock mx(&m_updateMutex);
204 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Mail is NULL.");
207 LogDebug("getCurrentFolder() = " << getCurrentFolder() );
208 if (!draftsOnly || (getCurrentFolder() == Api::Messaging::DRAFTBOX)) {
216 LogWarning("Updating only read status. Folder: " << getCurrentFolder());
220 int error = email_update_message(getIntId(), m_mail.Get());
221 if (EMF_ERROR_NONE != error) {
222 LogWarning("Nothing to update or error. [" << error << "]");
228 int Email::getAccountID()
233 return m_mail->info->account_id;
245 return m_mail->info->uid;
252 int Email::isBodyDownloaded()
256 return m_mail->info->body_downloaded;
261 void Email::readAllData()
266 void Email::moveToFolder(const FolderType newFolder)
270 moveToFolder(EmailConverter::toMailboxName(newFolder));
275 void Email::moveToFolder(const string& newFolder)
279 int accountId = Messaging::getInstance().getEmailAccountId(getFromRef());
280 ScopedMailbox mailbox(
281 EmailService::createMailbox(accountId, newFolder.c_str())
284 int mailId = getIntId();
286 int error = email_move_mail_to_mailbox(&mailId, 1, mailbox.Get());
287 if (EMF_ERROR_NONE != error) {
289 WrtDeviceApis::Commons::PlatformException,
290 "Couldn't move mail to folder: " << newFolder << ". [" <<
295 void Email::copyToFolder(const FolderType newFolder)
299 copyToFolder(EmailConverter::toMailboxName(newFolder));
304 void Email::copyToFolder(const string& newFolder)
310 int accountId = Messaging::getInstance().getEmailAccountId(getFromRef());
312 ScopedMail mail(EmailService::cloneMail(m_mail.Get()));
313 ScopedMailbox mailbox(
314 EmailService::createMailbox(accountId, newFolder.c_str())
317 int mailId = EmailService::addMailToMailbox(mail.Get(), mailbox.Get());
318 // TODO Is following check necessary?
320 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Cloned mail didn't get new id.");
328 EmailService::deleteMail(m_accountId, getIntId());
335 EmailAccountInfo account = IMessaging::getInstance().getCurrentEmailAccount();
336 m_accountId = account.getIntId();
337 ScopedMail mail(EmailService::createMail(account));
338 ScopedMailbox mailbox(
339 EmailService::getMailboxByType(account.getIntId(),
340 EMF_MAILBOX_TYPE_DRAFT)
342 setId(convertId(EmailService::addMailToMailbox(mail.Get(), mailbox.Get())));
343 setFolderType(Api::Messaging::DRAFTBOX);
344 setMessageStatus(Api::Messaging::MESSAGE_STATUS_DRAFT);
349 void Email::create( Api::Messaging::EmailAccountInfo& account )
353 m_accountId = account.getIntId();
354 MailSender::getInstance();
356 LogDebug("account ID : " << m_accountId);
357 ScopedMail mail(EmailService::createMail(account));
358 ScopedMailbox mailbox(EmailService::getMailboxByType(account.getIntId(), EMF_MAILBOX_TYPE_DRAFT));
359 setId(convertId(EmailService::addMailToMailbox(mail.Get(), mailbox.Get())));
360 setFolderType(Api::Messaging::DRAFTBOX);
361 setMessageStatus(Api::Messaging::MESSAGE_STATUS_DRAFT);
370 //EmailAccountInfo account = Messaging::getInstance().getCurrentEmailAccount();
371 LogDebug("account ID :" << m_accountId);
372 m_mail.Reset(EmailService::readMail(m_accountId, getIntId()));
374 if (m_mail->head) { readHeader(); }
375 if (m_mail->body) { readBody(); }
376 if (m_mail->info) { readInfo(); }
378 m_mailbox.Reset(EmailService::getMailboxByMailId(m_accountId, getIntId()) );
379 setFolderType(EmailConverter::toFolderType(m_mailbox->mailbox_type));
384 void Email::readHeader()
388 Assert(m_mail && m_mail->head && "Header is NULL.");
390 if (m_mail->head->subject) {
391 setSubject(m_mail->head->subject);
394 if (m_mail->head->to) {
395 appendToRecipients(EmailUtils::stripAddressLine(m_mail->head->to));
398 if (m_mail->head->cc) {
399 appendCcRecipients(EmailUtils::stripAddressLine(m_mail->head->cc));
402 if (m_mail->head->bcc) {
403 appendBccRecipients(EmailUtils::stripAddressLine(m_mail->head->bcc));
408 struct tm tmpTime = *(localtime(&rawtime));
409 tmpTime.tm_year = m_mail->head->datetime.year;
410 tmpTime.tm_mon = m_mail->head->datetime.month;
411 tmpTime.tm_mday = m_mail->head->datetime.day;
412 tmpTime.tm_hour = m_mail->head->datetime.hour;
413 tmpTime.tm_min = m_mail->head->datetime.minute;
414 tmpTime.tm_sec = m_mail->head->datetime.second;
416 setDateTime(tmpTime);
418 if (m_mail->head->from) {
420 from.setRecipients(m_mail->head->from);
421 setSourceAddress(from);
422 setSourceAddressValidity(true); //not needed to update in platform
428 void Email::readBody() {
431 Assert(m_mail && m_mail->body && "Body is NULL.");
433 if (m_mail->body->plain) {
434 DPL::ScopedFClose file(::fopen(m_mail->body->plain, "r"));
436 ThrowMsg(WrtDeviceApis::Commons::PlatformException,
437 "Cannot read body file: " << m_mail->body->plain);
439 fseek(file.Get(), 0, SEEK_END);
440 long int size = ftell(file.Get());
441 fseek(file.Get(), 0, SEEK_SET);
442 DPL::ScopedPtr<char> data(new char[size + 1]);
443 memset(data.Get(), 0, size + 1);
444 fread(data.Get(), 1, size, file.Get());
449 if (m_mail->body->html) {
450 DPL::ScopedFClose file(::fopen(m_mail->body->html, "r")); //auto close, scopedFClose
452 ThrowMsg(WrtDeviceApis::Commons::PlatformException,
453 "Cannot read html body file: " << m_mail->body->html);
456 fseek(file.Get(), 0, SEEK_END);
457 long int size = ftell(file.Get());
458 fseek(file.Get(), 0, SEEK_SET);
459 DPL::ScopedPtr<char> data(new char[size + 1]);
460 memset(data.Get(), 0, size + 1);
461 fread(data.Get(), 1, size, file.Get());
462 setHtmlBody(data.Get()); //setHtmlBody declarate in Email Calss.
465 if (m_mail->body->attachment && m_mail->body->attachment_num > 0) {
466 LogDebug("reading attachments , attahcment count = " << m_mail->body->attachment_num);
467 emf_attachment_info_t* attach = m_mail->body->attachment;
468 for (int i = 0; i < m_mail->body->attachment_num; ++i) {
470 LogDebug("throw platform exception");
471 ThrowMsg(WrtDeviceApis::Commons::PlatformException,
472 "Attachment list shorter than expected.");
477 LogError("id :" << attach->attachment_id << " name :" << attach->name << " download :" << attach->downloaded << " savefile :" << attach->savename );
479 IAttachmentPtr tmpAtt(new Attachment(attach));
480 LogError(" create new attachment ");
483 //tmpAtt->setMessage(SharedFromThis()); //set IMessagePtr
484 tmpAtt->rename(attach->name);
485 tmpAtt->setAttachmentID(attach->attachment_id);
486 tmpAtt->setDownloaded(attach->downloaded);
488 appendAttachment(tmpAtt);
489 LogError(" append complete");
492 attach = attach->next;
494 catch (const WrtDeviceApis::Commons::Exception& ex) {
495 LogError("Error while trying to append attachment " <<
496 attach->savename << ": " << ex.DumpToString());
504 void Email::readInfo()
508 Assert(m_mail && m_mail->info && "Info is NULL.");
510 setReadStatus(m_mail->info->flags.seen == 1);
512 m_accountId = m_mail->info->account_id;
515 EmailConverter::toMessagePriority( m_mail->info->extra_flags.priority )
517 setSize(m_mail->info->rfc822_size);
522 void Email::updateBody()
526 if (isBodyValid()) { return; }
529 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Mail is NULL.");
533 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Body is NULL.");
535 if (!m_mail->body->plain) {
536 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Body file is NULL.");
539 if (!m_mail->body->html) {
540 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Html Body file is NULL.");
544 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Info is NULL.");
548 FILE* f = fopen(m_mail->body->plain, "w");
550 //fprintf(f, getBodyRef().c_str());
551 fwrite(getBodyRef().c_str(), strlen(getBodyRef().c_str()), 1, f);
556 LogDebug("Plain Body file is NULL.");
559 if (m_mail->body->html) {
561 f = fopen(m_mail->body->html, "w");
563 //fprintf(f, getHtmlBody().c_str());
564 fwrite(getHtmlBody().c_str(), strlen(getHtmlBody().c_str()), 1, f);
570 LogDebug("Html Body file is NULL.");
573 m_mail->info->body_downloaded = true;
574 setBodyValidity(true);
579 void Email::updateSubject()
583 if (isSubjectValid()) { return; }
585 LogDebug("update subject, msgId=" << getIdRef());
588 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Mail not allocated.");
592 m_mail->head = EmailService::alloc<emf_mail_head_t>();
595 m_mail->head->subject = String::strdup(getSubjectRef());
596 setSubjectValidity(true);
601 void Email::updateReadStatus()
605 if (isReadStatusValid()) { return; }
607 LogDebug("update read, msgId=" << getIdRef());
610 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Mail not allocated.");
614 EmailService::alloc<emf_mail_info_t>();
617 m_mail->info->flags.seen = isRead();
618 setReadStatusValidity(true);
623 void Email::updateIsRead()
626 if (isReadChangeStatusValid()) {
627 // do not update if not changed
631 EmailService::updateSeenFlag(getAccountID(), getIntId(), isReadChangeStatus());
632 setisReadChangeStatusValidity(true);
636 void Email::addMessageToDraft()
640 DPL::Mutex::ScopedLock mx(&m_updateMutex);
643 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Mail is NULL.");
652 int error = email_update_message(getIntId(), m_mail.Get());
653 LogDebug("add finished, mailId = " << error);
657 void Email::updateRecipients()
661 if (getToValidity() && getCcValidity() && getBccValidity()) { return; }
664 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Mail is NULL.");
668 m_mail->head = EmailService::alloc<emf_mail_head_t>();
671 if (!getToValidity()) {
672 std::string addressLine = EmailUtils::formatAddressLine(getToRecipients());
673 if (m_mail->head->to) {
674 free(m_mail->head->to);
676 m_mail->head->to = String::strdup(addressLine);
680 if (!getCcValidity()) {
681 std::string addressLine = EmailUtils::formatAddressLine(getCcRecipients());
682 if (m_mail->head->cc) {
683 free(m_mail->head->cc);
685 m_mail->head->cc = String::strdup(addressLine);
689 if (!getBccValidity()) {
690 std::string addressLine = EmailUtils::formatAddressLine(
692 if (m_mail->head->bcc) {
693 free(m_mail->head->bcc);
695 m_mail->head->bcc = String::strdup(addressLine);
696 setBccValidity(true);
702 void Email::updateFrom()
706 if (getFromValidity()) { return; }
709 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Mail is NULL.");
713 EmailService::alloc<emf_mail_info_t>();
716 m_mail->info->account_id = m_accountId;
717 // TODO Update m_mail->head->from as well
719 setFromValidity(true);
724 void Email::updateAttachments()
728 if (isAttachmentsValid()) { return; }
731 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Mail is NULL.");
734 emf_attachment_info_t* attachment = NULL;
736 LogDebug("update attachments, msgId=" << getIdRef());
739 m_mail->body = EmailService::alloc<emf_mail_body_t>();
742 int i = m_mail->body->attachment_num;
743 LogDebug("clean attachment, attachment count=" << i);
744 attachment = m_mail->body->attachment;
745 std::stringstream stream;
749 LogDebug("delete file :" << attachment->name << " saved name :" << attachment->savename );
750 int aId = attachment->attachment_id;
751 char* mId = m_mail->head->mid;
757 LogDebug("mID :" << n_mId << " Attachment Id :" << aId );
759 int error = email_delete_attachment(m_mailbox.Get(), n_mId, (const char*)(stream.str()).c_str());
760 if (EMF_ERROR_NONE != error) {
761 LogDebug("Error Num = " << error);
762 ThrowMsg(WrtDeviceApis::Commons::PlatformException,
763 "Error while adding attachment. [" << error << "]");
765 attachment = attachment->next;
768 m_mail->body->attachment_num = 0;
769 if (NULL != m_mail->body->attachment) {
770 EmailService::freeAttachment(m_mail->body->attachment);
771 m_mail->body->attachment = NULL;
775 std::size_t attachmentSize = getAttachmentsCount();
776 LogDebug("update attachments, attachmentSize=" << attachmentSize);
777 if (attachmentSize > 0) {
779 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Mail info is NULL.");
782 for (std::size_t i = 0; i < attachmentSize; ++i) {
783 IAttachmentPtr att = getAttachment(i);
788 //copy attachment file
789 std::stringstream to_oss;
790 to_oss << TEMP_FOLDER << "/" << att->getShortName();
791 LogDebug("temp file=" << to_oss.str());
793 std::stringstream cp_oss;
794 cp_oss << COMMAND_NAME;
795 cp_oss << " " << COMMAND_SWITCH_RECURSIVE;
796 cp_oss << " \"" << att->getFullPath() << "\"";
797 cp_oss << " \"" << to_oss.str() << "\"";
799 attachment = EmailService::alloc<emf_attachment_info_t>(); //create attachment struct
800 attachment->name = String::strdup(att->getShortName());
801 //attachment->savename = String::strdup( att->getFullPath() );
802 attachment->savename = String::strdup( to_oss.str().c_str() );
804 attachment->next = NULL;
805 attachment->downloaded = true;
807 int result = system(cp_oss.str().c_str());
809 if (0 != WIFEXITED(result)) {
810 if (0 != WEXITSTATUS(result)) {
811 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Command failed.");
814 ThrowMsg(WrtDeviceApis::Commons::PlatformException,
815 "Command terminated abnormally.");
818 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Couldn't launch command.");
821 LogDebug( "mailbox type = " << m_mailbox.Get()->mailbox_type);
823 int error = email_add_attachment(m_mailbox.Get(),
826 if (EMF_ERROR_NONE != error) {
827 ThrowMsg(WrtDeviceApis::Commons::PlatformException,
828 "Error while adding attachment. [" << error << "]");
832 LogDebug(" attachment id : " << attachment->attachment_id);
833 //IMessagePtr msg = DPL::DynamicPointerCast<IMessage>(this);
834 att->setDownloaded(true);
835 att->setAttachmentID(attachment->attachment_id);
836 att->setMessage(SharedFromThis());
840 EmailService::freeAttachment(attachment);
843 setAttachmentsValidity(true);
846 Catch(WrtDeviceApis::Commons::PlatformException) {
847 EmailService::freeAttachment(attachment);
854 void Email::updatePriority()
858 if (isPriorityValid()) { return; }
861 ThrowMsg(WrtDeviceApis::Commons::PlatformException, "Mail not allocated.");
865 m_mail->info = EmailService::alloc<emf_mail_info_t>();
868 m_mail->info->extra_flags.priority = EmailConverter::toMailPriority(
870 setPriorityValid(true);
875 int Email::getIntId() const
877 return convertId(getIdRef());