a297056617aaaea4f04c1b0bb6d7f9b8122c65bc
[framework/web/wrt-plugins-common.git] / src / modules / tizen / Messaging / Sms.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /**
17  *
18  *
19  * @file       Sms.cpp
20  * @author     Pawel Misiak (p.misiak@samsung.com)
21  * @version    0.1
22  * @brief
23  */
24 #include "Sms.h"
25 #include <dpl/log/log.h>
26 #include <Commons/Exception.h>
27 #include <API/Messaging/ReqReceiverMessage.h>
28 #include "Messaging.h"
29 #include "CallbackMgr.h"
30 #include "MsgServiceHandleMgr.h"
31
32 extern "C" {
33 #include <MapiStorage.h>
34 #include <MapiMessage.h>
35 }
36
37 using namespace std;
38 using namespace WrtDeviceApis::Messaging;
39 using namespace WrtDeviceApis::Messaging::Api;
40
41 namespace {
42 const char* EMPTY_ID = "0";
43 }
44
45 namespace WrtDeviceApis {
46 namespace Messaging {
47 Sms::Sms(const string& id) :
48     IMessage(SMS, id),
49     m_messageData(NULL)
50 {
51     LogDebug("enter");
52     LogDebug("m_id=" << getIdRef());
53     LogDebug("m_msgType=" << getMessageType());
54
55     if (getIdRef().empty()) {
56         createNewMessage();
57     } else {
58         readExistingMessage();
59     }
60
61     Touch();
62 }
63
64 Sms::~Sms()
65 {
66     LogDebug("enter");
67
68     if (m_messageData) {
69         // release platform message structure
70         msg_release_message(&m_messageData);
71     }
72 }
73
74 void Sms::update(bool draftsOnly)
75 {
76     LogDebug("updating m_id=" << getIdRef());
77
78     if (!m_messageData) {
79         //error if platform message not exists
80         LogError("message can not be updated");
81         Throw(Commons::PlatformException);
82     }
83
84     //update all sms data
85     if (!draftsOnly || getCurrentFolder() == Api::DRAFTBOX) {
86         updateBody();
87         updateFrom();
88         updateTo();
89         updateSourceAddress();
90     }
91     updateReadStatus();
92 }
93
94 void Sms::readAllData()
95 {
96     readExistingMessage();
97 }
98
99 void Sms::moveToFolder(const FolderType newFolder)
100 {
101     update();
102
103     Try
104     {
105         const MSG_FOLDER_ID_T platfromFolderId =
106             Messaging::convertFolderToPlatform(newFolder);
107
108         //call platform api to move message to other folder
109         if (msg_move_msg_to_folder(MsgGetCommonHandle(), convertId(getId()),
110                                    platfromFolderId) != MSG_SUCCESS) {
111             Throw(Commons::PlatformException);
112         }
113     }
114
115     Catch(Commons::PlatformException) {
116         LogError("remove message error");
117         throw;
118     }
119 }
120
121 void Sms::moveToFolder(const std::string& /*newFolder*/)
122 {
123     update();
124     //TODO
125 }
126
127 void Sms::copyToFolder(const FolderType newFolder)
128 {
129     update();
130
131     msg_message_t msg = msg_new_message();
132
133     Try
134     {
135         MSG_SENDINGOPT_S option;
136         memset(&option, 0, sizeof(MSG_SENDINGOPT_S));
137         option.option.smsSendOpt.bReplyPath = true;
138         // trying to get message from platform
139         if (MSG_SUCCESS ==
140             msg_get_message(MsgGetCommonHandle(), convertId(getIdRef()), msg,
141                             &option))
142         {
143             const MSG_FOLDER_ID_T platfromFolderId =
144                 Messaging::convertFolderToPlatform(newFolder);
145             // new id will me set (initialize to 0)
146             msg_set_message_id(msg, 0);
147             msg_set_folder_id(msg, platfromFolderId);
148
149             // trying to add message
150             int error = msg_add_message(MsgGetCommonHandle(), msg, &option);
151             if (error != MSG_SUCCESS) {
152                 LogError("msg_add_message failed, error code=" << error);
153                 Throw(Commons::PlatformException);
154             }
155
156             //releasing platform message structure
157             msg_release_message(&msg);
158         }
159     }
160
161     Catch(Commons::PlatformException) {
162         LogError("remove message error");
163         if (msg) {
164             //releasing platform message structure
165             msg_release_message(&msg);
166         }
167         throw;
168     }
169 }
170
171 void Sms::copyToFolder(const std::string& /*newFolder*/)
172 {
173     update();
174     //TODO
175 }
176
177 void Sms::send()
178 {
179     LogDebug("sending message, id=" << getIdRef());
180
181     //prepare for sending sms
182     update();
183
184     // split the message
185     LogDebug("Start Sending Message...");
186     LogDebug("msgId=" << msg_get_message_id(m_messageData));
187     LogDebug("subject: " << msg_get_subject(m_messageData));
188     LogDebug("recipient count: " << msg_get_address_count(m_messageData));
189
190     SendRequest req;
191
192     for (int i = 0; i < msg_get_address_count(m_messageData); ++i) {
193         if (MSG_RECIPIENTS_TYPE_TO !=
194             msg_get_ith_recipient_type(m_messageData, i))
195         {
196             continue;
197         }
198         msg_message_t msg = createNewCopyOfPLatformMsg(m_messageData);
199
200         // remove all addresses except ith
201         msg_reset_address(msg);
202         const char* to = msg_get_ith_address(m_messageData, i);
203         msg_add_address(msg, to, MSG_RECIPIENTS_TYPE_TO);
204
205         LogDebug("recipient: " << msg_get_ith_address(msg, 0));
206         LogDebug("body: " << msg_sms_get_message_body(msg));
207
208         req.queue.push(msg);
209     }
210
211     DPL::Mutex::ScopedLock lock(&m_mutex);
212     m_sendRequests.push(req);
213
214     // schedule sending
215     PostEvent(0);
216
217     LogDebug("sending method finished");
218 }
219
220 void Sms::sendingCallback(MSG_SENT_STATUS_S *sent_status)
221 {
222     LogInfo(
223         "sendingCallback callback received. Req id = " <<
224         sent_status->reqId << " Status = " << (int)sent_status->status <<
225         ", Recipient=" << getRecipient());
226
227     DPL::Mutex::ScopedLock lock(&m_mutex);
228     if (sent_status->status != MSG_NETWORK_SEND_SUCCESS)
229     {
230         m_sendRequests.front().failed = true; // TODO mutex
231         //send callback, error for recipient
232         setSendingStatusFailed();
233     }
234     else
235     {
236         setSendingStatusOk();
237     }
238     msg_release_message(&currentQueue().front());
239     currentQueue().pop();
240
241     //schedule another sub message send
242     PostEvent(0);
243 }
244
245 void Sms::OnEventReceived(const int&)
246 {
247     LogDebug("enter");
248     // send another one
249     sendSubMessage();
250 }
251
252 Api::FolderType Sms::toFolder(const std::string &folder)
253 {
254     if (folder == "INBOX") {
255         return INBOX;
256     } else if (folder == "OUTBOX") {
257         return OUTBOX;
258     } else if (folder == "SENTBOX") {
259         return SENTBOX;
260     } else if (folder == "DRAFTBOX") {
261         return DRAFTBOX;
262     }
263     ThrowMsg(Commons::PlatformException, "Invalid folder");
264 }
265
266 void Sms::sendSubMessage()
267 {
268     LogDebug("enter");
269
270     DPL::Mutex::ScopedLock lock(&m_mutex);
271
272     // if current request queue gets empty, try next one
273     while (!m_sendRequests.empty()) {
274         // send as long as the sending fails until there are no more messages
275         for (MSG_ERROR_T err = MSG_ERR_UNKNOWN;
276              err != MSG_SUCCESS && !currentQueue().empty();)
277         {
278             err = CallbackMgrSingleton::Instance().registerAndSend(
279                     msg_sms_send_message,
280                     currentQueue().front(),
281                     this);
282             LogInfo("Sending Message (submit request) result:" << err);
283             if (err != MSG_SUCCESS) {
284                 LogError(
285                     "Sending Message (submit request) failed!!! err=" << err);
286                 msg_release_message(&currentQueue().front());
287                 currentQueue().pop();
288                 m_sendRequests.front().failed = true;
289                 //send callback, error for recipient
290                 setSendingStatusFailed();
291             }
292         }
293
294         // empty queue -> notify about results
295         if (currentQueue().empty()) {
296             auto event = getSendMessageEvent();
297             if (m_sendRequests.front().failed)
298             {
299                 event->setExceptionCode(
300                         Commons::ExceptionCodes::UnknownException);
301             }
302
303             ReqReceiverMessage *requestReceiver = getRequestReceiver();
304             if (requestReceiver)
305             {
306                 requestReceiver->
307                         Commons::EventRequestReceiver<EventSendMessage>::
308                                 ManualAnswer(event);
309             }
310
311             // this request is finished, try next one
312             m_sendRequests.pop();
313             continue;
314         }
315         break;
316     }
317 }
318
319 void Sms::setSendingStatusOk()
320 {
321     LogDebug("enter");
322     //success callback should be executed here
323     ReqReceiverMessage *requestReceiver = getRequestReceiver();
324     if (requestReceiver) {
325         LogInfo("calling JS success callback");
326         EventSendMessagePtr event = getSendMessageEvent();
327         event->addRecipientSendResult(getRecipient(), true);
328     }
329 }
330
331 void Sms::setSendingStatusFailed()
332 {
333     LogDebug("enter");
334     //error callback should be executed here
335     EventOnSendingFailedEmitterPtr emitter = getEmitter();
336     if (emitter) {
337         EventOnSendingFailedPtr event(new EventOnSendingFailed);
338         event->setError(EventOnSendingFailed::UNKNOWN); // TODO error codes
339         emitter->emit(event);
340     } else {
341         ReqReceiverMessage *requestReceiver = getRequestReceiver();
342         if (requestReceiver) {
343             LogError("calling JS error callback");
344             EventSendMessagePtr event = getSendMessageEvent();
345             event->addRecipientSendResult(getRecipient(), false);
346         }
347     }
348 }
349
350 void Sms::remove()
351 {
352     Try
353     {
354         // delete message from platform
355         if (msg_delete_message(MsgGetCommonHandle(),
356                                convertId(getId())) != MSG_SUCCESS)
357         {
358             LogError("delete message failed");
359             Throw(Commons::PlatformException);
360         } else {
361             LogDebug("message deleted succesfully");
362         }
363     }
364
365     Catch(Commons::PlatformException) {
366         LogError("remove message error");
367         throw;
368     }
369 }
370
371 void Sms::createNewMessage()
372 {
373     if (m_messageData) {
374         // release platform message if it was created previously
375         msg_release_message(&m_messageData);
376         m_messageData = NULL;
377     }
378     // create new platform message
379     m_messageData = msg_new_message();
380     Try
381     {
382         MSG_SENDINGOPT_S option;
383         memset(&option, 0, sizeof(MSG_SENDINGOPT_S));
384         option.option.smsSendOpt.bReplyPath = true;
385
386         //default message initialization
387         msg_set_message_id(m_messageData, 0); // It should be set 0
388         msg_set_folder_id(m_messageData, MSG_DRAFT_ID);
389         msg_set_message_type(m_messageData, MSG_TYPE_SMS);
390         msg_set_storage_id(m_messageData, MSG_STORAGE_PHONE);
391         msg_set_network_status(m_messageData, MSG_NETWORK_NOT_SEND);
392
393         // update sms data
394         updateBody();
395         updateTo();
396
397         tm dateT = getDateTime();
398         msg_set_time(m_messageData, mktime(&dateT));
399
400         LogDebug("Message created successfully, msgId=" << getId());
401     }
402
403     Catch(Commons::PlatformException) {
404         LogError("Problem with message creation, cleaning");
405     }
406 }
407
408 void Sms::readExistingMessage()
409 {
410     if (getIdRef().empty() || (EMPTY_ID == getIdRef())) {
411         ThrowMsg(Commons::PlatformException, "Empty id.");
412     }
413
414     Try {
415         MSG_SENDINGOPT_S option;
416         memset(&option, 0, sizeof(MSG_SENDINGOPT_S));
417         option.option.smsSendOpt.bReplyPath = true;
418
419         // release old data
420         msg_release_message(&m_messageData);
421         m_messageData = NULL;
422         // create new platform structure
423         m_messageData = msg_new_message();
424
425         MSG_MESSAGE_ID_T l_id = convertId(getIdRef());
426         LogDebug("reading message id=" << l_id);
427         // trying to get message from platform
428         if (MSG_SUCCESS ==
429             msg_get_message(MsgGetCommonHandle(), l_id, m_messageData,
430                             &option))
431         {
432             LogDebug("message found with msgId=" << getIdRef());
433
434             // read all mms dat to abstraction layer
435             readRecipientList(m_messageData);
436             readBody(m_messageData);
437             readFolder(m_messageData);
438             readDateTime(m_messageData);
439             readReadStatus(m_messageData);
440             readSize(m_messageData);
441         } else {
442             LogError("message not found with msgId=" << getIdRef());
443             setId("");
444         }
445     }
446     Catch(Commons::PlatformException) {
447         // nothing to do
448     }
449 }
450
451 void Sms::updateBody()
452 {
453     // check if abstraction body value has been changed
454     if (isBodyValid()) {
455         return;
456     }
457     LogInfo("updating platfoprm body");
458
459     // change body value in platform structure
460     msg_sms_set_message_body(m_messageData, getBodyRef().c_str(),
461                              getBodyRef().length());
462
463     // set flag as true - platform synchronized with abstraction
464     setBodyValidity(true);
465 }
466
467 void Sms::updateTo()
468 {
469     // check if abstraction recipient (to) value has been changed
470     if (getToRecipients().isValid()) {
471         return;
472     }
473     LogInfo("updating platform to");
474
475     // change recipient value in platform structure
476     msg_reset_address(m_messageData);
477     vector<string> to = getToRecipients().getRecipients();
478     LogInfo("updating to");
479     for (size_t i = 0; i < to.size(); i++) {
480         if (i >= MAX_TO_ADDRESS_CNT) {
481             LogError("max number of recipient exceeded");
482             break;
483         }
484         LogDebug("adding to[" << i << "]=" << to[i]);
485         string tmpAddr = to[i];
486         // function for validating phone number
487         if (validatePhoneNumber(tmpAddr)) {
488             // add phone number to platform message struncture
489             if (msg_add_address(m_messageData, tmpAddr.c_str(),
490                                 MSG_RECIPIENTS_TYPE_TO) != MSG_SUCCESS)
491             {
492                 LogError("problem witgh add address");
493                 Throw(Commons::PlatformException);
494             }
495         } else {
496             //nothing to do if wrong format
497             LogError("wrong phone number format");
498         }
499     }
500
501     // set flag as true - platform synchronized with abstraction
502     setToValidity(true);
503 }
504
505 void Sms::updateFrom()
506 {
507     // check if abstraction from field value has been changed
508     if (getFromValidity()) {
509         // do not update if not changed
510         return;
511     }
512     LogInfo("updating platform from");
513
514     //TODO
515
516     // set flag as true - platform synchronized with abstraction
517     setFromValidity(true);
518 }
519
520 void Sms::updateSourceAddress()
521 {
522     // check if abstraction source address value has been changed
523     if (getSourceAddressValidity()) {
524         // do not update if not changed
525         return;
526     }
527     LogInfo("updating platform source address");
528
529     //TODO
530
531     // set flag as true - platform synchronized with abstraction
532     setSourceAddressValidity(true);
533 }
534
535 void Sms::updateReadStatus()
536 {
537     LogInfo("updating platform read status: " << isRead());
538     if (isReadStatusValid()) {
539         // do not update if not changed
540         return;
541     }
542
543     if (MSG_SUCCESS != msg_set_read_status(m_messageData, isRead())) {
544         LogError("problem with setting subject");
545         ThrowMsg(Commons::PlatformException, "Problem with setting subject");
546     }
547     setReadStatusValidity(true);
548 }
549
550 void Sms::readRecipientList(msg_message_t& messageData)
551 {
552     LogDebug("Adding recipients to message, count=" <<
553              msg_get_address_count(messageData));
554     // iterate for all address and store in abstraction
555     for (int i = 0; i < msg_get_address_count(messageData); i++) {
556         string tmp = msg_get_ith_address(messageData, i);
557         int type = msg_get_direction_info(messageData);
558
559         if (MSG_DIRECTION_TYPE_MT == type) {
560             if (validatePhoneNumber(tmp)) {
561                 setSourceAddress(tmp);
562                 setFrom(tmp);
563             }
564         } else if (MSG_DIRECTION_TYPE_MO == type) {
565             appendToRecipients(tmp);
566         } else {
567             ThrowMsg(Commons::PlatformException, "Wrong type of recipient.");
568         }
569     }
570 }
571
572 void Sms::readBody(msg_message_t& messageData)
573 {
574     //set abstraction body value
575     const char* body = msg_sms_get_message_body(messageData);
576     if (NULL == body) {
577       ThrowMsg(Commons::PlatformException,
578                "Body is NULL. Probably message is invalid.");
579     }
580     setBody(body);
581 }
582
583 void Sms::readFolder(msg_message_t& messageData)
584 {
585     switch (msg_get_folder_id(messageData)) {
586     case MSG_INBOX_ID:
587         setFolderType(Api::INBOX);
588         break;
589     case MSG_OUTBOX_ID:
590         setFolderType(Api::OUTBOX);
591         break;
592     case MSG_SENTBOX_ID:
593         setFolderType(Api::SENTBOX);
594         break;
595     case MSG_DRAFT_ID:
596         setFolderType(Api::DRAFTBOX);
597         break;
598     case MSG_SPAMBOX_ID:
599         setFolderType(Api::SPAMBOX);
600         break;
601     default:
602         LogError("Wrong folder id");
603         ThrowMsg(Commons::PlatformException, "Unsupported folder id.");
604     }
605 }
606
607 void Sms::readDateTime(msg_message_t& messageData)
608 {
609     tm* time = localtime(msg_get_time(messageData));
610     if (!time) {
611         LogError("localtime failed");
612         Throw(Commons::PlatformException);
613     }
614     setDateTime(*time);
615 }
616
617 void Sms::readReadStatus(msg_message_t& messageData)
618 {
619     // get read status
620     setReadStatus(msg_is_read(messageData));
621 }
622
623 void Sms::readSize(msg_message_t& messageData)
624 {
625     setSize(msg_get_message_body_size(messageData));
626 }
627
628 msg_message_t Sms::createNewCopyOfPLatformMsg(const msg_message_t src) const
629 {
630     msg_message_t msg = msg_new_message();
631
632     msg_set_message_id(msg, 0);
633     msg_set_storage_id(msg, msg_get_storage_id(src));
634     msg_set_message_type(msg, msg_get_message_type(src));
635     msg_set_folder_id(msg, msg_get_folder_id(src));
636     for (int i = 0; i < msg_get_address_count(src); i++) {
637         msg_add_address(msg, msg_get_ith_address(src,
638                                                  i),
639                         msg_get_ith_recipient_type(src, i));
640     }
641     msg_sms_set_message_body(msg, msg_sms_get_message_body(
642                                  src), msg_get_message_body_size(src));
643     msg_set_subject(msg, msg_get_subject(src));
644     msg_set_time(msg, *msg_get_time(src));
645     msg_set_network_status(msg, msg_get_network_status(src));
646     msg_set_encode_type(msg, msg_get_encode_type(src));
647     msg_set_read_status(msg, msg_is_read(src));
648     msg_set_protect_status(msg, msg_is_protected(src));
649     msg_set_priority_info(msg, msg_get_priority_info(src));
650     msg_set_direction_info(msg, msg_get_direction_info(src));
651     msg_set_port(msg, msg_get_dest_port(src), msg_get_src_port(src));
652     msg_set_scheduled_time(msg, *msg_get_scheduled_time(src));
653
654     return msg;
655 }
656 }
657 }