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