d7b07f3c0d5987d8026aba034b794bbe9ed679d7
[platform/core/api/webapi-plugins.git] / src / messaging / email_manager.cc
1 /*
2  * Copyright (c) 2015 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 //#include <JSWebAPIErrorFactory.h>
18 //#include <JSWebAPIError.h>
19 //#include <JSUtil.h>
20 #include <chrono>
21 #include <list>
22 #include <memory>
23 #include <sstream>
24 #include <thread>
25 #include "common/logger.h"
26 #include "common/platform_exception.h"
27 #include "common/scope_exit.h"
28 //#include <GlobalContextManager.h>
29
30 #include "MsgCommon/AbstractFilter.h"
31
32 #include <email-api-account.h>
33 #include <email-api-mail.h>
34 #include <email-api-mailbox.h>
35 #include <email-api-network.h>
36
37 #include "email_manager.h"
38 #include "message.h"
39 #include "message_conversation.h"
40 #include "message_service.h"
41 #include "messaging_util.h"
42 //#include "MessageCallbackUserData.h"
43 //#include "MessagesCallbackUserData.h"
44 #include "conversation_callback_data.h"
45 #include "find_msg_callback_user_data.h"
46 #include "message_email.h"
47 #include "messaging_database_manager.h"
48
49 //#include "JSMessage.h"
50 //#include "JSMessageConversation.h"
51 //#include "JSMessageFolder.h"
52
53 #include <email-api.h>
54 #include <vconf.h>
55
56 //#include "DBus/SyncProxy.h"
57 #include "DBus/LoadBodyProxy.h"
58 //#include "DBus/LoadAttachmentProxy.h"
59
60 #include <sstream>
61 #include "MsgCommon/FilterIterator.h"
62
63 #include "common/scope_exit.h"
64 #include "messaging/DBus/DBusTypes.h"
65
66 using namespace common;
67 using namespace extension::tizen;
68 using namespace std::chrono_literals;
69
70 namespace extension {
71 namespace messaging {
72
73 namespace {
74 const int ACCOUNT_ID_NOT_INITIALIZED = -1;
75 const std::string FIND_FOLDERS_ATTRIBUTE_ACCOUNTID_NAME = "serviceId";
76
77 bool isFirstInThread(const Message* message) {
78   ScopeLogger();
79   return message->getId() == message->getConversationId();
80 }
81
82 bool isFirstInThread(const email_mail_data_t* mail_data) {
83   ScopeLogger();
84   return mail_data->mail_id == mail_data->thread_id;
85 }
86 }  // anonymous namespace
87
88 EmailManager::EmailManager() : m_slot_size(-1), m_is_initialized(false) {
89   ScopeLogger();
90 }
91
92 #define CHECK_ERROR(ret, message) \
93   if (ret.IsError()) {            \
94     LoggerE(message);             \
95     return ret;                   \
96   }
97
98 PlatformResult EmailManager::InitializeEmailService() {
99   ScopeLogger();
100
101   if (!m_is_initialized) {
102     getUniqueOpId();
103
104     int ntv_ret = email_service_begin();
105     if (ntv_ret != EMAIL_ERROR_NONE) {
106       return LogAndCreateResult(
107           ErrorCode::UNKNOWN_ERR, "Email service failed to begin",
108           ("email_service_begin error: %d (%s)", ntv_ret, get_error_message(ntv_ret)));
109     }
110
111     ntv_ret = email_open_db();
112     if (ntv_ret != EMAIL_ERROR_NONE) {
113       return LogAndCreateResult(
114           ErrorCode::UNKNOWN_ERR, "Email DB failed to open",
115           ("email_open_db error: %d (%s)", ntv_ret, get_error_message(ntv_ret)));
116     }
117
118     int slot_size = -1;
119     ntv_ret = vconf_get_int("db/private/email-service/slot_size", &(slot_size));
120
121     if (0 == ntv_ret && slot_size > 0) {
122       m_slot_size = slot_size;
123     }
124
125     PlatformResult ret = DBus::SyncProxy::create(DBus::kDBusPathNetworkStatus,
126                                                  DBus::kDBusIfaceNetworkStatus, &m_proxy_sync);
127     CHECK_ERROR(ret, "create sync proxy failed");
128     if (!m_proxy_sync) {
129       LoggerE("Sync proxy is null");
130       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Sync proxy is null");
131     }
132     m_proxy_sync->signalSubscribe();
133
134     ret = DBus::LoadBodyProxy::create(DBus::kDBusPathNetworkStatus, DBus::kDBusIfaceNetworkStatus,
135                                       &m_proxy_load_body);
136     CHECK_ERROR(ret, "create load body proxy failed");
137     if (!m_proxy_load_body) {
138       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Load body proxy is null");
139     }
140     m_proxy_load_body->signalSubscribe();
141
142     //    ret = DBus::LoadAttachmentProxy::create(DBus::Proxy::DBUS_PATH_NETWORK_STATUS,
143     //                                            DBus::Proxy::DBUS_IFACE_NETWORK_STATUS,
144     //                                            &m_proxy_load_attachment);
145     //    CHECK_ERROR(ret, "create load attachment proxy failed");
146     //    if (!m_proxy_load_attachment) {
147     //        LoggerE("Load attachment proxy is null");
148     //        return PlatformResult(ErrorCode::UNKNOWN_ERR, "Load attachment proxy is null");
149     //    }
150     //    m_proxy_load_attachment->signalSubscribe();
151
152     ret = DBus::MessageProxy::create(*this, &m_proxy_messageStorage);
153     CHECK_ERROR(ret, "create message proxy failed");
154     if (!m_proxy_messageStorage) {
155       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Message proxy is null");
156     }
157     m_proxy_messageStorage->signalSubscribe();
158
159     ret = DBus::SendProxy::create(*this, &m_proxy_send);
160     CHECK_ERROR(ret, "create send proxy failed");
161     if (!m_proxy_send) {
162       return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Send proxy is null");
163     }
164     m_proxy_send->signalSubscribe();
165
166     m_is_initialized = true;
167   }
168
169   return PlatformResult(ErrorCode::NO_ERROR);
170 }
171
172 EmailManager::~EmailManager() {
173   ScopeLogger();
174 }
175
176 PlatformResult EmailManager::addDraftMessagePlatform(int account_id,
177                                                      std::shared_ptr<Message> message) {
178   ScopeLogger();
179   return addMessagePlatform(account_id, message, EMAIL_MAILBOX_TYPE_DRAFT);
180 }
181
182 PlatformResult EmailManager::addOutboxMessagePlatform(int account_id,
183                                                       std::shared_ptr<Message> message) {
184   ScopeLogger();
185   return addMessagePlatform(account_id, message, EMAIL_MAILBOX_TYPE_OUTBOX);
186 }
187
188 PlatformResult EmailManager::addMessagePlatform(int account_id, std::shared_ptr<Message> message,
189                                                 email_mailbox_type_e mailbox_type) {
190   ScopeLogger();
191   email_mail_data_t* mail_data = NULL;
192   email_mail_data_t* mail_data_final = NULL;
193   email_mailbox_t* mailbox_data = NULL;
194   email_account_t* account = NULL;
195
196   SCOPE_EXIT {
197     if (mail_data_final) {
198       email_free_mail_data(&mail_data_final, 1);
199     }
200     if (mail_data) {
201       email_free_mail_data(&mail_data, 1);
202     }
203     if (mailbox_data) {
204       email_free_mailbox(&mailbox_data, 1);
205     }
206     if (account) {
207       email_free_account(&account, 1);
208     }
209   };
210
211   int err = EMAIL_ERROR_NONE;
212
213   PlatformResult ret = Message::convertPlatformEmail(message, &mail_data);
214   if (ret.IsError()) return ret;
215
216   mail_data->account_id = account_id;
217
218   // Adding "from" email address
219   err = email_get_account(account_id, GET_FULL_DATA_WITHOUT_PASSWORD, &account);
220   if (EMAIL_ERROR_NONE != err) {
221     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Cannot retrieve email account information",
222                               ("email_get_account error: %d (%s)", err, get_error_message(err)));
223   }
224   LoggerE("FROM %s", account->user_email_address);
225   std::stringstream ss;
226   ss << "<" << account->user_email_address << ">";
227   std::string address_from;
228   ss >> address_from;
229   mail_data->full_address_from = strdup(address_from.c_str());
230   LoggerE("FROM %s", mail_data->full_address_from);
231
232   // Setting mailbox id
233   err = email_get_mailbox_by_mailbox_type(account_id, mailbox_type, &mailbox_data);
234   if (EMAIL_ERROR_NONE != err) {
235     return LogAndCreateResult(
236         ErrorCode::UNKNOWN_ERR, "Cannot retrieve draft mailbox",
237         ("email_get_mailbox_by_mailbox_type error: %d (%s)", err, get_error_message(err)));
238   } else {
239     LoggerD("email_get_mailbox_by_mailbox_type success.\n");
240     mail_data->mailbox_id = mailbox_data->mailbox_id;
241     mail_data->mailbox_type = mailbox_data->mailbox_type;
242   }
243
244   mail_data->report_status = EMAIL_MAIL_REPORT_NONE;
245   mail_data->save_status = EMAIL_MAIL_STATUS_SAVED;
246   mail_data->flags_draft_field = 1;
247
248   // adding email without attachments
249   err = email_add_mail(mail_data, NULL, 0, NULL, 0);
250   if (EMAIL_ERROR_NONE != err) {
251     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Couldn't add message to draft mailbox",
252                               ("email_add_mail error: %d (%s)", err, get_error_message(err)));
253   } else {
254     LoggerD("email_add_mail success.\n");
255   }
256
257   LoggerD("saved mail without attachments id = [%d]\n", mail_data->mail_id);
258
259   message->setId(mail_data->mail_id);
260   message->setMessageStatus(MessageStatus::STATUS_DRAFT);
261
262   if (message->getHasAttachment()) {
263     ret = Message::addEmailAttachments(message);
264     if (ret.IsError()) {
265       return ret;
266     }
267   }
268
269   /*
270    * If the message is first in its thread (its mail_id == thread_id)
271    * and it has an attachment, there is some delay between addEmailAttachments
272    * return and the corresponding update of message's record in the internal
273    * email DB.
274    *
275    * The internal DB is queried for mail_data_final below, but due to
276    * the mentioned delay, it may return mail_data_final, that is not
277    * up-to-date, i.e with mail_id != thread_id).
278    * If such situation occurs, up to MAX_RETRIES retries of calling
279    * email_get_mail_data are performed.
280    * If returned mail_data_final is up-to-date before reaching retries limit,
281    * the returned value is used to set mail properties.
282    * If returned mail_data_final is still not up-to-date, thread_id of the message
283    * is set manually to mail_id.
284    */
285
286   if (isFirstInThread(mail_data)) {
287     int retry = 0;
288     const int MAX_RETRIES = 5;
289     for (; retry < MAX_RETRIES; ++retry) {
290       err = email_get_mail_data(message->getId(), &mail_data_final);
291
292       if (EMAIL_ERROR_NONE != err) {
293         /*
294          * TODO: in the case of email_get_mail_data failure,
295          * the message should be removed from the databse
296          */
297         return LogAndCreateResult(
298             ErrorCode::UNKNOWN_ERR, "Couldn't add message to draft mailbox",
299             ("email_get_mail_data error: %d (%s)", err, get_error_message(err)));
300       }
301
302       if (isFirstInThread(mail_data) && isFirstInThread(mail_data_final)) {
303         LoggerD("Message adding process finished after %d retries. mail_id == thread_id", retry);
304         break;
305       }
306
307       int free_error = email_free_mail_data(&mail_data_final, 1);
308       if (EMAIL_ERROR_NONE != free_error) {
309         LoggerW("email_free_mail_data error: %d, %s", free_error, get_error_message(free_error));
310       }
311       LoggerD("Retry number %d failed", retry);
312       std::this_thread::sleep_for(100ms);
313     }
314
315     if (MAX_RETRIES == retry) {
316       LoggerD(
317           "Message adding process not finished after %d retries. Setting proper conversationId "
318           "manually",
319           retry);
320       mail_data_final->thread_id = mail_data_final->mail_id;
321     }
322   } else {
323     err = email_get_mail_data(message->getId(), &mail_data_final);
324     if (EMAIL_ERROR_NONE != err) {
325       return LogAndCreateResult(
326           ErrorCode::UNKNOWN_ERR, "Couldn't add message to draft mailbox",
327           ("email_get_mail_data error: %d (%s)", err, get_error_message(err)));
328     }
329   }
330
331   ret = message->updateEmailMessage(*mail_data_final);
332   if (ret.IsError()) {
333     return ret;
334   }
335
336   return PlatformResult(ErrorCode::NO_ERROR);
337 }
338
339 static gboolean addDraftMessageCompleteCB(void* data) {
340   ScopeLogger();
341   MessageCallbackUserData* callback = static_cast<MessageCallbackUserData*>(data);
342   if (!callback) {
343     LoggerE("Callback is null");
344     return false;
345   }
346
347   if (callback->IsError()) {
348     LoggerD("Calling error callback");
349     callback->getMessage()->setMessageStatus(MessageStatus::STATUS_FAILED);
350   } else {
351     LoggerD("Calling success callback");
352
353     picojson::object args;
354     args[JSON_DATA_MESSAGE] = MessagingUtil::messageToJson(callback->getMessage());
355     callback->SetSuccess(picojson::value(args));
356   }
357
358   callback->Post();
359
360   delete callback;
361   callback = NULL;
362
363   return false;
364 }
365
366 void EmailManager::addDraftMessage(MessageCallbackUserData* callback) {
367   ScopeLogger();
368
369   if (!callback) {
370     LoggerE("Callback is null");
371     return;
372   }
373   {
374     std::lock_guard<std::mutex> lock(m_mutex);
375     std::shared_ptr<Message> message = callback->getMessage();
376     PlatformResult ret = addDraftMessagePlatform(callback->getAccountId(), message);
377     if (ret.IsError()) {
378       callback->SetError(ret);
379     }
380   }
381   // Complete task
382   if (!g_idle_add(addDraftMessageCompleteCB, static_cast<void*>(callback))) {
383     LoggerE("g_idle addition failed");
384     delete callback;
385     callback = NULL;
386   }
387 }
388
389 //**** sending email ****
390 static gboolean sendEmailCompleteCB(void* user_data) {
391   ScopeLogger();
392
393   MessageRecipientsCallbackData* callback = static_cast<MessageRecipientsCallbackData*>(user_data);
394   if (!callback) {
395     LoggerE("Callback is null");
396     return false;
397   }
398
399   if (callback->IsError()) {
400     LoggerD("Calling error callback");
401     callback->getMessage()->setMessageStatus(MessageStatus::STATUS_FAILED);
402   } else {
403     LoggerD("Calling success callback");
404
405     std::vector<picojson::value> recipients;
406     auto addToRecipients = [&recipients](std::string& e) -> void {
407       recipients.push_back(picojson::value(e));
408     };
409
410     auto toVect = callback->getMessage()->getTO();
411     std::for_each(toVect.begin(), toVect.end(), addToRecipients);
412
413     auto ccVect = callback->getMessage()->getCC();
414     std::for_each(ccVect.begin(), ccVect.end(), addToRecipients);
415
416     auto bccVect = callback->getMessage()->getBCC();
417     std::for_each(bccVect.begin(), bccVect.end(), addToRecipients);
418
419     picojson::object data;
420     data[JSON_DATA_RECIPIENTS] = picojson::value(recipients);
421     data[JSON_DATA_MESSAGE] = MessagingUtil::messageToJson(callback->getMessage());
422
423     callback->SetSuccess(picojson::value(data));
424     callback->getMessage()->setMessageStatus(MessageStatus::STATUS_SENT);
425   }
426
427   callback->Post();
428
429   delete callback;
430   callback = NULL;
431
432   return false;
433 }
434
435 PlatformResult EmailManager::sendMessage(MessageRecipientsCallbackData* callback) {
436   ScopeLogger();
437
438   if (!callback) {
439     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Callback is null");
440   }
441
442   int err = EMAIL_ERROR_NONE;
443   email_mail_data_t* mail_data = NULL;
444
445   PlatformResult platform_result(ErrorCode::NO_ERROR);
446
447   std::shared_ptr<Message> message = callback->getMessage();
448
449   if (message) {
450     if (!(message->is_id_set())) {
451       platform_result = addOutboxMessagePlatform(callback->getAccountId(), message);
452     }
453
454     if (platform_result) {
455       err = email_get_mail_data(message->getId(), &mail_data);
456       if (EMAIL_ERROR_NONE != err) {
457         platform_result =
458             LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Failed to get platform email structure",
459                                ("email_get_mail_data %d (%s)", err, get_error_message(err)));
460       } else {
461         LoggerD("email_get_mail_data success.\n");
462
463         // Sending EMAIL
464         mail_data->save_status = EMAIL_MAIL_STATUS_SENDING;
465
466         int req_id = 0;
467         err = email_send_mail(mail_data->mail_id, &req_id);
468
469         if (EMAIL_ERROR_NONE != err) {
470           platform_result =
471               LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Failed to send message",
472                                  ("email_send_mail error: %d (%s)", err, get_error_message(err)));
473         } else {
474           LoggerD("req_id: %d", req_id);
475           callback->getMessage()->setMessageStatus(MessageStatus::STATUS_SENDING);
476           m_sendRequests[req_id] = callback;
477         }
478       }
479     }
480   } else {
481     LoggerE("Message is null");
482     platform_result = LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Message is null");
483   }
484
485   if (!platform_result) {
486     LoggerE("Message send failed");
487
488     callback->SetError(platform_result);
489
490     if (!g_idle_add(sendEmailCompleteCB, static_cast<void*>(callback))) {
491       LoggerE("g_idle addition failed");
492       delete callback;
493       callback = NULL;
494     }
495   }
496
497   if (mail_data) {
498     err = email_free_mail_data(&mail_data, 1);
499
500     if (EMAIL_ERROR_NONE != err) {
501       LoggerE("Failed to free mail data memory");
502     }
503   }
504
505   return platform_result;
506 }
507
508 void EmailManager::sendStatusCallback(int mail_id, email_noti_on_network_event status,
509                                       int error_code) {
510   ScopeLogger();
511
512   std::lock_guard<std::mutex> lock(m_mutex);
513   // find first request for this mail_id
514   SendReqMapIterator it = getSendRequest(mail_id);
515   if (it != m_sendRequests.end()) {
516     LoggerD("Found request");
517     MessageRecipientsCallbackData* callback = it->second;
518     m_sendRequests.erase(it);
519
520     if (NOTI_SEND_FAIL == status) {
521       LoggerD("Failed to send message, set proper error");
522       switch (error_code) {
523         case EMAIL_ERROR_NO_SIM_INSERTED:
524         case EMAIL_ERROR_SOCKET_FAILURE:
525         case EMAIL_ERROR_CONNECTION_FAILURE:
526         case EMAIL_ERROR_CONNECTION_BROKEN:
527         case EMAIL_ERROR_NO_SUCH_HOST:
528         case EMAIL_ERROR_NETWORK_NOT_AVAILABLE:
529         case EMAIL_ERROR_INVALID_STREAM:
530         case EMAIL_ERROR_NO_RESPONSE: {
531           callback->SetError(LogAndCreateResult(
532               ErrorCode::NETWORK_ERR, "Failed to send message",
533               ("Network error: %d (%s)", error_code, get_error_message(error_code))));
534           break;
535         }
536         default:
537           callback->SetError(LogAndCreateResult(
538               ErrorCode::UNKNOWN_ERR, "Failed to send message",
539               ("Unknown error: %d (%s)", error_code, get_error_message(error_code))));
540           break;
541       }
542     } else if (NOTI_SEND_FINISH == status) {
543       LoggerD("Message sent successfully");
544     }
545
546     if (!g_idle_add(sendEmailCompleteCB, static_cast<void*>(callback))) {
547       LoggerE("g_idle addition failed");
548       delete callback;
549       callback = NULL;
550     }
551   } else {
552     LoggerW("No matching request found");
553   }
554 }
555
556 email_mail_data_t* EmailManager::loadMessage(int msg_id) {
557   ScopeLogger();
558   email_mail_data_t* mail_data = NULL;
559   int err = email_get_mail_data(msg_id, &mail_data);
560   if (EMAIL_ERROR_NONE != err) {
561     LoggerE("email_get_mail_data failed. [%d] (%s)", err, get_error_message(err));
562   } else {
563     LoggerD("email_get_mail_data success.");
564   }
565   return mail_data;
566 }
567
568 EmailManager::SendReqMapIterator EmailManager::getSendRequest(int mail_id) {
569   ScopeLogger();
570   for (auto it = m_sendRequests.begin(); it != m_sendRequests.end(); it++) {
571     if (it->second->getMessage()->getId() == mail_id) {
572       return it;
573     }
574   }
575   return m_sendRequests.end();
576 }
577
578 void EmailManager::freeMessage(email_mail_data_t* mail_data) {
579   ScopeLogger();
580   if (!mail_data) {
581     return;
582   }
583
584   int err = email_free_mail_data(&mail_data, 1);
585   if (EMAIL_ERROR_NONE != err) {
586     LoggerE("Could not free mail data!");
587   }
588 }
589
590 void EmailManager::loadMessageBody(MessageBodyCallbackData* callback) {
591   ScopeLogger();
592   if (!callback) {
593     LoggerE("Callback is null");
594     return;
595   }
596
597   if (!callback->getMessage()) {
598     LoggerE("Callback's message is null");
599     return;
600   }
601
602   m_proxy_load_body->addCallback(callback);
603
604   const int mailId = callback->getMessage()->getId();
605
606   int op_handle = -1;
607   int err = email_download_body(mailId, 0, &op_handle);
608   if (EMAIL_ERROR_NONE != err) {
609     LoggerE("Email download body failed, %d (%s)", err, get_error_message(err));
610     m_proxy_load_body->removeCallback(callback);
611     return;
612   }
613   callback->setOperationHandle(op_handle);
614 }
615
616 PlatformResult EmailManager::loadMessageAttachment(MessageAttachmentCallbackData* callback) {
617   ScopeLogger();
618
619   if (!callback) {
620     return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "Callback is null");
621   }
622
623   if (!callback->getMessageAttachment()) {
624     return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR,
625                               "Callback's message attachment is null");
626   }
627
628   std::shared_ptr<MessageAttachment> msgAttachment = callback->getMessageAttachment();
629   LoggerD("attachmentId: [%d] mailId: [%d]", msgAttachment->getId(), msgAttachment->getMessageId());
630
631   email_mail_data_t* mail_data = EmailManager::loadMessage(msgAttachment->getMessageId());
632
633   SCOPE_EXIT {
634     EmailManager::freeMessage(mail_data);
635   };
636
637   if (!mail_data) {
638     return LogAndCreateResult(
639         ErrorCode::UNKNOWN_ERR, "Couldn't load message.",
640         ("Couldn't get email_mail_data_t for messageId: %d", msgAttachment->getMessageId()));
641   }
642
643   AttachmentPtrVector attachments;
644   auto platform_result = Message::convertEmailToMessageAttachment(*mail_data, &attachments);
645
646   if (!platform_result) {
647     return platform_result;
648   }
649
650   LoggerD("Mail: [%d] contains: [%zu] attachments", msgAttachment->getMessageId(),
651           attachments.size());
652
653   auto it = attachments.begin();
654   int attachmentIndex = -1;
655   for (int i = 0; it != attachments.end(); ++i, ++it) {
656     if ((*it)->getId() == msgAttachment->getId()) {
657       attachmentIndex = i;
658       break;
659     }
660   }
661
662   if (attachmentIndex < 0) {
663     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Couldn't find attachment.",
664                               ("Attachment with id: %d not found", msgAttachment->getId()));
665   }
666
667   LoggerD("Attachment with id: [%d] is located at index: [%d]", msgAttachment->getId(),
668           attachmentIndex);
669
670   int op_handle = -1;
671   const int nth = attachmentIndex + 1;  // in documentation: the minimum number is "1"
672   callback->setNth(nth);
673
674   int err = email_download_attachment(msgAttachment->getMessageId(), nth, &op_handle);
675
676   if (EMAIL_ERROR_NONE != err) {
677     return LogAndCreateResult(
678         ErrorCode::UNKNOWN_ERR, "Failed to load attachment.",
679         ("Download email attachment failed with error: %d (%s)", err, get_error_message(err)));
680   } else {
681     LoggerD("email_download_attachment returned handle: [%d]", op_handle);
682     callback->setOperationHandle(op_handle);
683     m_proxy_load_attachment->addCallback(callback);
684     return PlatformResult(ErrorCode::NO_ERROR);
685   }
686 }
687
688 //#################################### sync: ###################################
689
690 void EmailManager::sync(void* data) {
691   ScopeLogger();
692
693   SyncCallbackData* callback = static_cast<SyncCallbackData*>(data);
694
695   if (!callback) {
696     LoggerE("Callback is null");
697     return;
698   }
699
700   long op_id = callback->getOpId();
701   m_proxy_sync->addCallback(op_id, callback);
702
703   int err = EMAIL_ERROR_NONE;
704   int limit = callback->getLimit();
705   int slot_size = -1;
706   int account_id = callback->getAccountId();
707
708   if (limit < 0) {
709     slot_size = m_slot_size;
710   } else {
711     slot_size = limit;
712   }
713
714   err = email_set_mail_slot_size(0, 0, slot_size);
715
716   if (EMAIL_ERROR_NONE != err) {
717     LoggerE("Email set slot size failed, %d (%s)", err, get_error_message(err));
718     m_proxy_sync->removeCallback(op_id);
719     return;
720   }
721
722   int op_handle = -1;
723   err = email_sync_header(account_id, 0, &op_handle);
724
725   if (EMAIL_ERROR_NONE != err) {
726     LoggerE("Email sync header failed, %d (%s)", err, get_error_message(err));
727     m_proxy_sync->removeCallback(op_id);
728   } else {
729     callback->setOperationHandle(op_handle);
730   }
731 }
732
733 //#################################### ^sync ###################################
734
735 //################################## syncFolder: ###############################
736
737 void EmailManager::syncFolder(SyncFolderCallbackData* callback) {
738   ScopeLogger();
739
740   if (!callback) {
741     LoggerE("Callback is null");
742     return;
743   }
744
745   const long op_id = callback->getOpId();
746   m_proxy_sync->addCallback(op_id, callback);
747
748   if (!callback->getMessageFolder()) {
749     LoggerE("Callback's messageFolder is null");
750     m_proxy_sync->removeCallback(op_id);
751     return;
752   }
753
754   email_mailbox_t* mailbox = NULL;
755
756   const std::string folder_id_str = callback->getMessageFolder()->getId();
757   int folder_id = 0;
758   std::istringstream(folder_id_str) >> folder_id;
759
760   int err = email_get_mailbox_by_mailbox_id(folder_id, &mailbox);
761
762   if (EMAIL_ERROR_NONE != err || NULL == mailbox) {
763     LoggerE("Couldn't get mailbox, error code: %d (%s)", err, get_error_message(err));
764     m_proxy_sync->removeCallback(op_id);
765     return;
766   }
767
768   const int limit = callback->getLimit();
769   int slot_size = -1;
770
771   if (limit < 0) {
772     slot_size = m_slot_size;
773   } else {
774     slot_size = limit;
775   }
776
777   err = email_set_mail_slot_size(0, 0, slot_size);
778   if (EMAIL_ERROR_NONE != err) {
779     LoggerE("Email set slot size failed, %d (%s)", err, get_error_message(err));
780   } else {
781     int op_handle = -1;
782     const int account_id = callback->getAccountId();
783
784     err = email_sync_header(account_id, mailbox->mailbox_id, &op_handle);
785
786     if (EMAIL_ERROR_NONE != err) {
787       LoggerE("Email sync header failed, %d (%s)", err, get_error_message(err));
788       m_proxy_sync->removeCallback(op_id);
789     } else {
790       callback->setOperationHandle(op_handle);
791     }
792   }
793
794   if (NULL != mailbox) {
795     err = email_free_mailbox(&mailbox, 1);
796     if (EMAIL_ERROR_NONE != err) {
797       LoggerE("Failed to email_free_mailbox - err: %d (%s)", err, get_error_message(err));
798     }
799     mailbox = NULL;
800   }
801 }
802
803 //#################################### ^syncFolder #############################
804
805 //################################## stopSync: #################################
806
807 void EmailManager::stopSync(long op_id) {
808   ScopeLogger();
809
810   SyncCallbackData* callback = static_cast<SyncCallbackData*>(m_proxy_sync->getCallback(op_id));
811
812   if (!callback) {
813     LoggerE("Callback is null");
814     return;
815   }
816
817   int err = email_cancel_job(callback->getAccountId(), callback->getOperationHandle(),
818                              EMAIL_CANCELED_BY_USER);
819
820   if (EMAIL_ERROR_NONE != err) {
821     LoggerE("Email cancel job failed, %d (%s)", err, get_error_message(err));
822   }
823
824   callback->SetError(LogAndCreateResult(ErrorCode::ABORT_ERR, "Sync aborted by user"));
825
826   callback->Post();
827   m_proxy_sync->removeCallback(op_id);
828 }
829
830 //################################## ^stopSync #################################
831
832 void EmailManager::RemoveSyncCallback(long op_id) {
833   ScopeLogger();
834   m_proxy_sync->removeCallback(op_id);
835 }
836
837 void EmailManager::RemoveCallbacksByQueue(const PostQueue& q) {
838   ScopeLogger();
839
840   for (auto it = m_sendRequests.begin(); it != m_sendRequests.end();) {
841     if (it->second->HasQueue(q)) {
842       delete it->second;
843       m_sendRequests.erase(it++);
844     } else {
845       ++it;
846     }
847   }
848 }
849
850 void removeEmailCompleteCB(MessagesCallbackUserData* callback) {
851   ScopeLogger();
852   if (!callback) {
853     LoggerE("Callback is null");
854     return;
855   }
856
857   if (callback->IsError()) {
858     LoggerD("Calling error callback");
859
860   } else {
861     LoggerD("Calling success callback");
862
863     callback->SetSuccess();
864   }
865
866   callback->Post();
867
868   delete callback;
869   callback = NULL;
870 }
871
872 EmailManager::DeleteReqVector::iterator EmailManager::getDeleteRequest(
873     const std::vector<int>& ids) {
874   ScopeLogger();
875   for (auto idIt = ids.begin(); idIt != ids.end(); ++idIt) {
876     for (auto reqIt = m_deleteRequests.begin(); reqIt != m_deleteRequests.end(); ++reqIt) {
877       MessagePtrVector msgs = reqIt->callback->getMessages();
878       for (auto msgIt = msgs.begin(); msgIt != msgs.end(); ++msgIt) {
879         if ((*msgIt)->getId() == *idIt) {
880           return reqIt;
881         }
882       }
883     }
884   }
885   return m_deleteRequests.end();
886 }
887
888 void EmailManager::removeStatusCallback(const std::vector<int>& ids,
889                                         email_noti_on_storage_event status) {
890   ScopeLogger();
891   std::lock_guard<std::mutex> lock(m_mutex);
892   DeleteReqVector::iterator it = getDeleteRequest(ids);
893   if (it != m_deleteRequests.end()) {
894     LoggerD("Found request");
895     if (NOTI_MAIL_DELETE_FINISH == status) {
896       LoggerD("Successfully removed %zu mails", ids.size());
897       it->messagesDeleted += ids.size();
898     }
899     MessagesCallbackUserData* callback = it->callback;
900     if (NOTI_MAIL_DELETE_FAIL == status) {
901       callback->SetError(LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Messages remove failed"));
902     }
903     // if one of mails failed, call error callback
904     // if all mails are deleted, call success.
905     // >= is used in case of duplicated dbus messages
906     if (NOTI_MAIL_DELETE_FAIL == status ||
907         static_cast<unsigned int>(it->messagesDeleted) >= it->callback->getMessages().size()) {
908       LoggerD("Calling callback");
909       m_deleteRequests.erase(it);
910       m_mutex.unlock();
911       removeEmailCompleteCB(callback);
912     } else {
913       LoggerD("Not all messages are removed, waiting for next callback");
914     }
915   } else {
916     LoggerD("Request not found, ignoring");
917   }
918 }
919
920 PlatformResult EmailManager::RemoveMessagesPlatform(MessagesCallbackUserData* callback) {
921   ScopeLogger();
922   int error;
923   email_mail_data_t* mail = NULL;
924
925   std::lock_guard<std::mutex> lock(m_mutex);
926   std::vector<std::shared_ptr<Message>> messages = callback->getMessages();
927   MessageType type = callback->getMessageServiceType();
928   for (auto it = messages.begin(); it != messages.end(); ++it) {
929     if ((*it)->getType() != type) {
930       return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR, "Error while deleting email",
931                                 ("Invalid message type %d", (*it)->getType()));
932     }
933   }
934   for (auto it = messages.begin(); it != messages.end(); ++it) {
935     error = email_get_mail_data((*it)->getId(), &mail);
936     if (EMAIL_ERROR_NONE != error) {
937       return LogAndCreateResult(
938           ErrorCode::UNKNOWN_ERR, "Error while deleting mail",
939           ("Couldn't retrieve mail data: %d (%s)", error, get_error_message(error)));
940     }
941
942     // This task (_EMAIL_API_DELETE_MAIL) is for async
943     error = email_delete_mail(mail->mailbox_id, &mail->mail_id, 1, 0);
944     if (EMAIL_ERROR_NONE != error) {
945       email_free_mail_data(&mail, 1);
946       return LogAndCreateResult(
947           ErrorCode::UNKNOWN_ERR, "Error while deleting mail",
948           ("email_delete_mail error: %d (%s)", error, get_error_message(error)));
949     }
950     email_free_mail_data(&mail, 1);
951   }
952   // store delete request and wait for dbus response
953   DeleteReq request;
954   request.callback = callback;
955   request.messagesDeleted = 0;
956   m_deleteRequests.push_back(request);
957
958   return PlatformResult(ErrorCode::NO_ERROR);
959 }
960
961 void EmailManager::removeMessages(MessagesCallbackUserData* callback) {
962   ScopeLogger();
963
964   if (!callback) {
965     LoggerE("Callback is null");
966     return;
967   }
968
969   PlatformResult ret = RemoveMessagesPlatform(callback);
970   if (ret.IsError()) {
971     LoggerE("%d (%s)", static_cast<int>(ret.error_code()), (ret.message()).c_str());
972     callback->SetError(ret);
973     removeEmailCompleteCB(callback);
974   }
975 }
976
977 PlatformResult EmailManager::UpdateMessagesPlatform(MessagesCallbackUserData* callback) {
978   ScopeLogger();
979   int error;
980   email_mail_data_t* mail = NULL;
981   SCOPE_EXIT {
982     if (mail) {
983       email_free_mail_data(&mail, 1);
984       mail = NULL;
985     }
986   };
987
988   std::lock_guard<std::mutex> lock(m_mutex);
989   std::vector<std::shared_ptr<Message>> messages = callback->getMessages();
990   std::list<std::shared_ptr<Message>> firstInThreadAndHasAttachment;
991   MessageType type = callback->getMessageServiceType();
992   for (auto it = messages.begin(); it != messages.end(); ++it) {
993     if ((*it)->getType() != type) {
994       return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR, "Error while updating message",
995                                 ("Invalid message type: %d", (*it)->getType()));
996     }
997   }
998   for (auto it = messages.begin(); it != messages.end(); ++it) {
999     PlatformResult ret = Message::convertPlatformEmail((*it), &mail);
1000     if (ret.IsError()) return ret;
1001
1002     if ((*it)->getHasAttachment()) {
1003       if (isFirstInThread(it->get())) {
1004         // Messages with attachments, that are first in their threads are added
1005         // to the container, to be processed later in this function
1006         firstInThreadAndHasAttachment.push_back(*it);
1007       }
1008       // Update of mail on server using function email_update_mail() is not possible.
1009       // Attachment is updated only locally (can't be later loaded from server),
1010       // so use of workaround is needed:
1011       // 1. add new mail
1012       // 2. delete old mail
1013
1014       // adding message again after changes
1015       PlatformResult ret = addDraftMessagePlatform(mail->account_id, (*it));
1016       if (ret.IsError()) {
1017         return ret;
1018       }
1019       LoggerD("mail added - new id = [%d]\n", (*it)->getId());
1020
1021       // storing old message id
1022       (*it)->setOldId(mail->mail_id);
1023       // deleting old mail
1024       error = email_delete_mail(mail->mailbox_id, &mail->mail_id, 1, 1);
1025       LoggerD("mail deleted = [%d]\n", mail->mail_id);
1026       if (EMAIL_ERROR_NONE != error) {
1027         return LogAndCreateResult(
1028             ErrorCode::UNKNOWN_ERR, "Error while deleting old mail on update",
1029             ("email_delete_mail error: %d (%s)", error, get_error_message(error)));
1030       }
1031     } else {
1032       LoggerD("There are no attachments, updating only email data.");
1033       error = email_update_mail(mail, NULL, 0, NULL, 0);
1034       if (EMAIL_ERROR_NONE != error) {
1035         return LogAndCreateResult(
1036             ErrorCode::UNKNOWN_ERR, "Error while updating mail",
1037             ("email_update_mail error: %d (%s)", error, get_error_message(error)));
1038       }
1039     }
1040   }
1041
1042   if (firstInThreadAndHasAttachment.size() == 0) {
1043     return PlatformResult(ErrorCode::NO_ERROR);
1044   }
1045
1046   /*
1047    * If a message with attachment, that is first in its thread was updated,
1048    * the update process consists of adding a new message - updated version
1049    * of the original and removing the original.
1050    *
1051    * After the original mail is deleted, the thread_id of the updated version
1052    * changes - it is now identical to the mail_id of the new message.
1053    * The change should be reflected in the updated message, sent to the JS
1054    * layer. The code below sets proper thread_id for such messages and unsets
1055    * inResponseTo fields.
1056    *
1057    * A few retries with sleeps between them are performed, to ensure, that after
1058    * this function returns, messages returned to the JS layer and
1059    * corresponding records in the mail DB have the same thread_ids. Due to a
1060    * delay between calling email_delete_mail function and the update of records
1061    * in the database, some time is needed.
1062    */
1063   email_mail_data_t* mail_data{nullptr};
1064   int retry = 0;
1065   const int MAX_RETRIES = 5;
1066   for (; retry < MAX_RETRIES; ++retry) {
1067     std::this_thread::sleep_for(100ms);
1068     auto it = firstInThreadAndHasAttachment.begin();
1069     while (it != firstInThreadAndHasAttachment.end()) {
1070       error = email_get_mail_data((*it)->getId(), &mail_data);
1071       if (EMAIL_ERROR_NONE != error) {
1072         return LogAndCreateResult(
1073             ErrorCode::UNKNOWN_ERR, "Couldn't add message to draft mailbox",
1074             ("email_get_mail_data error: %d (%s)", error, get_error_message(error)));
1075       }
1076
1077       if (isFirstInThread(mail_data)) {
1078         (*it)->setConversationId(mail_data->thread_id);
1079         (*it)->unsetInResponseTo();
1080         it = firstInThreadAndHasAttachment.erase(it);
1081       } else {
1082         ++it;
1083       }
1084
1085       int free_error = email_free_mail_data(&mail_data, 1);
1086       if (EMAIL_ERROR_NONE != free_error) {
1087         LoggerW("email_free_mail_data error: %d, %s", free_error, get_error_message(free_error));
1088       }
1089     }
1090
1091     if (firstInThreadAndHasAttachment.size() == 0) {
1092       LoggerD("Message updating process finished after %d retries", retry);
1093       break;
1094     }
1095
1096     LoggerD("Message update retry number %d finished", retry);
1097   }
1098
1099   if (MAX_RETRIES == retry) {
1100     LoggerW("Message updating process not finished after %d retries.", retry);
1101     for (auto& message : firstInThreadAndHasAttachment) {
1102       LoggerD("Setting proper conversationId manually, message id: %d", message->getId());
1103       message->setConversationId(message->getId());
1104       message->unsetInResponseTo();
1105     }
1106   }
1107
1108   return PlatformResult(ErrorCode::NO_ERROR);
1109 }
1110
1111 void EmailManager::updateMessages(MessagesCallbackUserData* callback) {
1112   ScopeLogger();
1113
1114   if (!callback) {
1115     LoggerE("Callback is null");
1116     return;
1117   }
1118
1119   PlatformResult ret = UpdateMessagesPlatform(callback);
1120   if (ret.IsError()) {
1121     LoggerE("%d (%s)", static_cast<int>(ret.error_code()), (ret.message()).c_str());
1122     callback->SetError(ret);
1123   }
1124
1125   if (callback->IsError()) {
1126     LoggerD("Calling error callback");
1127   } else {
1128     LoggerD("Calling success callback");
1129
1130     picojson::array array;
1131     auto messages = callback->getMessages();
1132     size_t messages_size = messages.size();
1133     for (size_t i = 0; i < messages_size; ++i) {
1134       array.push_back(MessagingUtil::messageToJson(messages[i]));
1135     }
1136
1137     callback->SetSuccess(picojson::value(array));
1138   }
1139
1140   callback->Post();
1141
1142   delete callback;
1143   callback = NULL;
1144 }
1145
1146 PlatformResult EmailManager::FindMessagesPlatform(FindMsgCallbackUserData* callback) {
1147   ScopeLogger();
1148   email_mail_data_t* mailList = NULL;
1149   int mailListCount = 0;
1150
1151   SCOPE_EXIT {
1152     if (mailListCount > 0 && mailList != NULL) {
1153       if (EMAIL_ERROR_NONE != email_free_mail_data(&mailList, mailListCount)) {
1154         LoggerW("Failed to free mailList");
1155       }
1156     }
1157   };
1158
1159   std::lock_guard<std::mutex> lock(m_mutex);
1160   std::pair<int, email_mail_data_t*> emails;
1161   PlatformResult ret = MessagingDatabaseManager::getInstance().findEmails(callback, &emails);
1162   if (ret.IsError()) return ret;
1163   mailListCount = emails.first;
1164   LoggerD("Found %d mails", mailListCount);
1165
1166   mailList = emails.second;
1167   email_mail_data_t* nth_email = mailList;
1168
1169   for (int i = 0; i < mailListCount; ++i) {
1170     std::shared_ptr<Message> email;
1171     ret = Message::convertPlatformEmailToObject(*nth_email, &email);
1172     if (ret.IsError()) return ret;
1173     callback->addMessage(email);
1174     nth_email++;
1175   }
1176   return PlatformResult(ErrorCode::NO_ERROR);
1177 }
1178
1179 void EmailManager::findMessages(FindMsgCallbackUserData* callback) {
1180   ScopeLogger();
1181
1182   if (!callback) {
1183     LoggerE("Callback is null");
1184     return;
1185   }
1186
1187   PlatformResult ret = FindMessagesPlatform(callback);
1188   if (ret.IsError()) {
1189     LoggerE("%d (%s)", static_cast<int>(ret.error_code()), (ret.message()).c_str());
1190     callback->SetError(ret);
1191   }
1192
1193   // Complete task
1194   LoggerD("callback: %p error: %d messages.size() = %zu", callback, callback->IsError(),
1195           callback->getMessages().size());
1196
1197   if (callback->IsError()) {
1198     LoggerD("Calling error callback");
1199
1200   } else {
1201     LoggerD("Calling success callback");
1202     std::vector<picojson::value> response;
1203     auto messages = callback->getMessages();
1204     std::for_each(messages.begin(), messages.end(), [&response](MessagePtr& message) {
1205       response.push_back(MessagingUtil::messageToJson(message));
1206     });
1207
1208     callback->SetSuccess(picojson::value(response));
1209   }
1210
1211   callback->Post();
1212
1213   delete callback;
1214   callback = NULL;
1215 }
1216
1217 PlatformResult EmailManager::FindConversationsPlatform(ConversationCallbackData* callback) {
1218   ScopeLogger();
1219
1220   std::lock_guard<std::mutex> lock(m_mutex);
1221   std::vector<std::shared_ptr<MessageConversation>> conversationsInfo;
1222   PlatformResult ret =
1223       MessagingDatabaseManager::getInstance().findEmailConversations(*callback, &conversationsInfo);
1224   if (ret.IsError()) return ret;
1225
1226   LoggerD("Found %zu conversations", conversationsInfo.size());
1227
1228   for (const auto& conversation : conversationsInfo) {
1229     callback->addConversation(conversation);
1230   }
1231
1232   return PlatformResult(ErrorCode::NO_ERROR);
1233 }
1234
1235 void EmailManager::findConversations(ConversationCallbackData* callback) {
1236   ScopeLogger();
1237
1238   if (!callback) {
1239     LoggerE("Callback is null");
1240     return;
1241   }
1242
1243   PlatformResult ret = FindConversationsPlatform(callback);
1244   if (ret.IsError()) {
1245     LoggerE("%d (%s)", static_cast<int>(ret.error_code()), (ret.message()).c_str());
1246     callback->SetError(ret);
1247   }
1248
1249   // Complete task
1250   LoggerD("callback: %p error:%d conversations.size()=%zu", callback, callback->IsError(),
1251           callback->getConversations().size());
1252
1253   if (callback->IsError()) {
1254     LoggerD("Calling error callback");
1255   } else {
1256     LoggerD("Calling success callback");
1257
1258     std::vector<picojson::value> response;
1259     auto messages = callback->getConversations();
1260     std::for_each(messages.begin(), messages.end(),
1261                   [&response](std::shared_ptr<MessageConversation>& conversation) {
1262                     response.push_back(MessagingUtil::conversationToJson(conversation));
1263                   });
1264
1265     callback->SetSuccess(picojson::value(response));
1266   }
1267
1268   callback->Post();
1269
1270   delete callback;
1271   callback = NULL;
1272 }
1273
1274 long EmailManager::getUniqueOpId() {
1275   ScopeLogger();
1276   // mutex is created only on first call (first call added to constructor
1277   // to initialize mutex correctly)
1278   static std::mutex op_id_mutex;
1279   std::lock_guard<std::mutex> lock(op_id_mutex);
1280   static long op_id = 0;
1281   return op_id++;
1282 }
1283
1284 PlatformResult EmailManager::FindFoldersPlatform(FoldersCallbackData* callback) {
1285   ScopeLogger();
1286   int ret = EMAIL_ERROR_UNKNOWN;
1287   int account_id = ACCOUNT_ID_NOT_INITIALIZED;
1288   email_mailbox_t* mailboxes = NULL;
1289   email_mailbox_t* nth_mailbox = NULL;
1290   int mailboxes_count;
1291
1292   SCOPE_EXIT {
1293     if (mailboxes != NULL) {
1294       if (EMAIL_ERROR_NONE != email_free_mailbox(&mailboxes, mailboxes_count)) {
1295         LoggerW("Free mailboxes failed: %d", ret);
1296       }
1297     }
1298   };
1299
1300   std::lock_guard<std::mutex> lock(m_mutex);
1301
1302   tizen::AbstractFilterPtr filter = callback->getFilter();
1303   if (!filter) {
1304     return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Filter not provided");
1305   }
1306
1307   for (FilterIterator it(filter); false == it.isEnd(); it++) {
1308     if (FIS_COMPOSITE_START == it.getState()) {
1309       CompositeFilterPtr cf = castToCompositeFilter((*it));
1310       if (cf && INTERSECTION != cf->getType()) {
1311         return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR, "Invalid Filter Type",
1312                                   ("Invalid Filter type: %d", cf->getType()));
1313       }
1314     } else if (FIS_ATTRIBUTE_FILTER == it.getState()) {
1315       AttributeFilterPtr attrf = castToAttributeFilter((*it));
1316       if (attrf) {
1317         const std::string attr_name = attrf->getAttributeName();
1318         if (FIND_FOLDERS_ATTRIBUTE_ACCOUNTID_NAME == attr_name) {
1319           account_id = static_cast<int>(attrf->getMatchValue()->toLong());
1320         } else {
1321           return LogAndCreateResult(ErrorCode::INVALID_VALUES_ERR, "The attribute name is invalid",
1322                                     ("The attribute name: %s is invalid", attr_name.c_str()));
1323         }
1324       }
1325     }
1326   }
1327
1328   LoggerD("Listing folders for account ID: %d", account_id);
1329   if (account_id > 0) {
1330     ret = email_get_mailbox_list(account_id, -1, &mailboxes, &mailboxes_count);
1331     if (EMAIL_ERROR_NONE != ret || !mailboxes) {
1332       return LogAndCreateResult(
1333           ErrorCode::UNKNOWN_ERR, "Platform error, cannot get folders",
1334           ("email_get_mailbox_list error: %d (%s)", ret, get_error_message(ret)));
1335     }
1336
1337     if (mailboxes_count <= 0) {
1338       LoggerD("Empty mailboxes");
1339     } else {
1340       LoggerD("Founded mailboxes: %d", mailboxes_count);
1341
1342       nth_mailbox = mailboxes;
1343       for (int i = 0; i < mailboxes_count; ++i) {
1344         std::shared_ptr<MessageFolder> fd;
1345         fd = std::make_shared<MessageFolder>(*nth_mailbox);
1346         callback->addFolder(fd);
1347         nth_mailbox++;
1348       }
1349     }
1350   }
1351   return PlatformResult(ErrorCode::NO_ERROR);
1352 }
1353
1354 void EmailManager::findFolders(FoldersCallbackData* callback) {
1355   ScopeLogger();
1356
1357   if (!callback) {
1358     LoggerE("Callback is null");
1359     return;
1360   }
1361
1362   PlatformResult ret = FindFoldersPlatform(callback);
1363   if (ret.IsError()) {
1364     LoggerE("%d (%s)", static_cast<int>(ret.error_code()), (ret.message()).c_str());
1365     callback->SetError(ret);
1366   }
1367
1368   // Complete task
1369   LoggerD("callback: %p error:%d folders.size()=%zu", callback, callback->IsError(),
1370           callback->getFolders().size());
1371
1372   if (callback->IsError()) {
1373     LoggerD("Calling error callback");
1374   } else {
1375     LoggerD("Calling success callback");
1376
1377     std::vector<picojson::value> response;
1378     auto folders = callback->getFolders();
1379     std::for_each(folders.begin(), folders.end(),
1380                   [&response](std::shared_ptr<MessageFolder>& folder) {
1381                     response.push_back(MessagingUtil::folderToJson(folder));
1382                   });
1383
1384     callback->SetSuccess(picojson::value(response));
1385   }
1386
1387   callback->Post();
1388
1389   delete callback;
1390   callback = NULL;
1391 }
1392
1393 PlatformResult EmailManager::RemoveConversationsPlatform(ConversationCallbackData* callback) {
1394   ScopeLogger();
1395   int error;
1396   std::lock_guard<std::mutex> lock(m_mutex);
1397   std::vector<std::shared_ptr<MessageConversation>> conversations = callback->getConversations();
1398   MessageType type = callback->getMessageServiceType();
1399
1400   int thread_id = 0;
1401   for (auto it = conversations.begin(); it != conversations.end(); ++it) {
1402     if ((*it)->getType() != type) {
1403       return LogAndCreateResult(ErrorCode::TYPE_MISMATCH_ERR,
1404                                 "Error while deleting email conversation",
1405                                 ("Invalid message type %d", (*it)->getType()));
1406     }
1407   }
1408
1409   for (auto it = conversations.begin(); it != conversations.end(); ++it) {
1410     thread_id = (*it)->getConversationId();
1411     error = email_delete_thread(thread_id, false);
1412     if (EMAIL_ERROR_NONE != error) {
1413       return LogAndCreateResult(
1414           ErrorCode::TYPE_MISMATCH_ERR, "Error while deleting email conversation",
1415           ("Couldn't delete email conversation data %d (%s)", error, get_error_message(error)));
1416     }
1417
1418     // for now, there is no way to recognize deleting email thread job is completed.
1419     // so use polling to wait the thread is removed.
1420     email_mail_data_t* thread_info = NULL;
1421     do {
1422       struct timespec sleep_time = {0, 300L * 1000L * 1000L};
1423       nanosleep(&sleep_time, nullptr);
1424       LoggerD("Waiting to delete this email thread...");
1425       error = email_get_thread_information_by_thread_id(thread_id, &thread_info);
1426
1427       if (thread_info != NULL) {
1428         free(thread_info);
1429         thread_info = NULL;
1430       }
1431     } while (error != EMAIL_ERROR_MAIL_NOT_FOUND);
1432   }
1433   return PlatformResult(ErrorCode::NO_ERROR);
1434 }
1435
1436 void EmailManager::removeConversations(ConversationCallbackData* callback) {
1437   ScopeLogger();
1438
1439   if (!callback) {
1440     LoggerE("Callback is null");
1441     return;
1442   }
1443
1444   PlatformResult ret = RemoveConversationsPlatform(callback);
1445   if (ret.IsError()) {
1446     LoggerE("%d (%s)", static_cast<int>(ret.error_code()), (ret.message()).c_str());
1447     callback->SetError(ret);
1448   }
1449
1450   if (callback->IsError()) {
1451     LoggerD("Calling error callback");
1452   } else {
1453     LoggerD("Calling success callback");
1454
1455     callback->SetSuccess();
1456   }
1457
1458   callback->Post();
1459
1460   delete callback;
1461   callback = NULL;
1462 }
1463
1464 std::string EmailManager::getMessageStatus(int id) {
1465   ScopeLogger();
1466
1467   email_mail_data_t* mail = nullptr;
1468   MessageStatus status = MessageStatus::STATUS_UNDEFINED;
1469
1470   int ret = email_get_mail_data(id, &mail);
1471   if (EMAIL_ERROR_NONE != ret || !mail) {
1472     LoggerD("Failed to get data %d (%s)", ret, get_error_message(ret));
1473     return "";
1474   }
1475
1476   switch (mail->save_status) {
1477     case EMAIL_MAIL_STATUS_SENT:
1478       status = MessageStatus::STATUS_SENT;
1479       break;
1480     case EMAIL_MAIL_STATUS_SENDING:
1481       status = MessageStatus::STATUS_SENDING;
1482       break;
1483     case EMAIL_MAIL_STATUS_SAVED:
1484       status = MessageStatus::STATUS_DRAFT;
1485       break;
1486     case EMAIL_MAIL_STATUS_SEND_FAILURE:
1487       status = MessageStatus::STATUS_FAILED;
1488       break;
1489     default:
1490       status = MessageStatus::STATUS_UNDEFINED;
1491       break;
1492   }
1493
1494   ret = email_free_mail_data(&mail, 1);
1495   if (EMAIL_ERROR_NONE != ret) {
1496     LoggerD("Failed to free mail data %d (%s)", ret, get_error_message(ret));
1497   }
1498
1499   return MessagingUtil::messageStatusToString(status);
1500 }
1501
1502 }  // Messaging
1503 }  // DeviceAPI