18180803dce452c0b4574d98e66c79ccf27f6020
[framework/web/wrt-plugins-tizen.git] / src / Messaging / ConverterMessage.cpp
1 //
2 // Tizen Web Device API
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 // http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17
18 #include <dpl/assert.h>
19 #include <Commons/Exception.h>
20 #include <CommonsJavaScript/PrivateObject.h>
21 #include <CommonsJavaScript/Validator.h>
22 #include <CommonsJavaScript/JSUtils.h>
23 #include <CommonsJavaScript/JSDOMExceptionFactory.h>
24 #include "ConverterMessage.h"
25 #include "JSMessage.h"
26 #include "JSMessagePrivateObject.h"
27 #include "JSRecipientArray.h"
28 #include "MessagingListener.h"
29 #include <CommonsJavaScript/ScopedJSStringRef.h>
30 #include "JSMessageAttachment.h"
31 #include "JSConversation.h"
32 #include "JSMessageFolder.h"
33
34 #include <JSWebAPIError.h>
35 #include <Logger.h>
36
37 #if 0 // MESSAGING ATTACHMENT IS BLOCKED
38 #include <JSFile.h>
39 #endif
40
41 using namespace std;
42 using namespace WrtDeviceApis::Commons;
43 using namespace WrtDeviceApis::CommonsJavaScript;
44
45 namespace {
46 const char* SEND_PROPERTY_ONSUCCESS = "onsuccess";
47 const char* SEND_PROPERTY_ONMESSAGESENDSUCCESS = "onmessagesendsuccess";
48 const char* SEND_PROPERTY_ONMESSAGESENDERROR = "onmessagesenderror";
49 }
50
51 namespace DeviceAPI {
52 namespace Messaging {
53
54 MessageFunctions ConverterMessage::m_callbackNames[MESSAGING_MULTI_FUNTION_MAX]
55 {
56     {"messagesadded", "messagesupdated", "messagesremoved"},
57     {"conversationsadded", "conversationsupdated", "conversationsremoved"},
58     {"foldersadded", "foldersupdated", "foldersremoved"}
59 };
60
61 ConverterMessage::ConverterMessage(JSContextRef context) :
62     Converter(context)
63 {
64 }
65
66 ConverterMessage::~ConverterMessage()
67 {
68 }
69
70 JSContextRef ConverterMessage::toJSGlobalContext(JSObjectRef arg)
71 {
72     // get private object
73     WrtDeviceApis::CommonsJavaScript::PrivateObjectT<void>::Type* priv =
74         static_cast<WrtDeviceApis::CommonsJavaScript::PrivateObjectT<void>::Type*>(JSObjectGetPrivate(
75                                                               arg));
76     if (!priv) {
77         LoggerE("Private object not initialized");
78         ThrowMsg(WrtDeviceApis::Commons::NullPointerException,
79                  "Private object not initialized");
80     }
81     return priv->getContext();
82 }
83
84 JSValueRef ConverterMessage::toJSValueRef(FolderType arg)
85 {
86     switch (arg) {
87     case INBOX:
88         return toJSValueRef(messageFolderInbox);
89     case OUTBOX:
90         return toJSValueRef(messageFolderOutbox);
91     case DRAFTBOX:
92         return toJSValueRef(messageFolderDrafts);
93     case SENTBOX:
94         return toJSValueRef(messageFolderSentbox);
95     default:
96         ThrowMsg(WrtDeviceApis::Commons::ConversionException, "folder not supported");
97     }
98 }
99
100 JSValueRef ConverterMessage::toJSValueRef(MessageType arg)
101 {
102     switch (arg) {
103     case SMS:
104         return toJSValueRef(messageTypeSms);
105     case MMS:
106         return toJSValueRef(messageTypeMms);
107     case EMAIL:
108         return toJSValueRef(messageTypeEmail);
109     default:
110         ThrowMsg(WrtDeviceApis::Commons::ConversionException, "message type not supported");
111     }
112 }
113
114 JSValueRef ConverterMessage::toJSValueRef(const IMessagePtr& arg)
115 {
116     switch (arg->getMessageType()) {
117     case SMS:
118     case MMS:
119     case EMAIL:
120     case EMPTY_MESSAGE: 
121         return JSMessage::createJSObject(m_context, arg);
122
123     default:
124         LoggerE("unknown type");
125         Throw(WrtDeviceApis::Commons::ConversionException);
126     }
127 }
128
129 JSValueRef ConverterMessage::toJSValueRef(const IMessagePtr& arg,
130         EventUpdateMessageAnswerReceiver* listener)
131 {
132     switch (arg->getMessageType()) {
133     case SMS:
134     case MMS:
135     case EMAIL:
136     case EMPTY_MESSAGE: 
137         return JSMessage::createJSObject(m_context, arg, listener);
138
139     default:
140         LoggerE("unknown type");
141         Throw(WrtDeviceApis::Commons::ConversionException);
142     }
143 }
144
145 JSValueRef ConverterMessage::toJSValueRef(
146         const std::vector<IMessagePtr>& arg,
147         EventUpdateMessageAnswerReceiver* listener)
148 {
149     vector<JSValueRef> msgsJS;
150     for (size_t i = 0; i < arg.size(); i++) {
151         msgsJS.push_back(toJSValueRef(arg[i], listener));
152     }
153     return toJSValueRef(msgsJS);
154 }
155
156 JSValueRef ConverterMessage::toJSValueRef(const std::vector<IConversationPtr>& conversations)
157 {
158     vector<JSValueRef> conversationJS;
159
160     for (size_t i = 0; i < conversations.size(); i++)
161     {
162         JSValueRef value = JSConversation::createJSObject(m_context, conversations[i]);
163         conversationJS.push_back(value);
164     }
165
166     return toJSValueRef(conversationJS);
167 }
168
169 JSValueRef ConverterMessage::toJSValueRef(const std::vector<IMessageFolderPtr>& messagefolders)
170 {
171     vector<JSValueRef> messagefolderJS;
172
173     for (size_t i = 0; i < messagefolders.size(); i++)
174     {
175         JSValueRef value = JSMessageFolder::createJSObject(m_context, messagefolders[i]);
176         messagefolderJS.push_back(value);
177     }
178
179     return toJSValueRef(messagefolderJS);
180 }
181
182 JSValueRef ConverterMessage::toJSValueRef(const MessagePriority& arg)
183 {
184     switch (arg.getPriority()) {
185     case MessagePriority::LOW:
186         return toJSValueRef(false);
187         break;
188     case MessagePriority::NORMAL:
189         return toJSValueRef(false);
190         break;
191     case MessagePriority::HIGH:
192         return toJSValueRef(true);
193         break;
194     default:
195         ThrowMsg(WrtDeviceApis::Commons::ConversionException, "Unknown priority");
196         break;
197     }
198 }
199
200 JSValueRef ConverterMessage::toJSValueRef(const IAttachmentPtr& arg)
201 {
202     return JSMessageAttachment::createJS(m_context, arg);
203 }
204
205 JSValueRef ConverterMessage::keyToJSValue(JSValueRef value,
206         const string& key)
207 {
208     JSValueRef retVal = NULL;
209
210     if (NULL == value) {
211         LoggerE("jsValue null");
212         Throw(WrtDeviceApis::Commons::ConversionException);
213     }
214     JSObjectRef argObj = JSValueToObject(m_context, value, NULL);
215     if (NULL == argObj) {
216         LoggerE("conversion to jsobject fail");
217         Throw(WrtDeviceApis::Commons::ConversionException);
218     }
219     const JSStringRef keyJSStr = JSStringCreateWithUTF8CString(key.c_str());
220     retVal = JSObjectGetProperty(m_context, argObj, keyJSStr, NULL);
221     JSStringRelease(keyJSStr);
222     if (NULL == retVal) {
223         LoggerW("key \"" << key << "\" not found in JSValue map");
224     }
225     // return NULL if no key in map
226     return retVal;
227 }
228
229 IMessagePtr ConverterMessage::toIMessage(JSValueRef arg)
230 {
231     return toIMessage(toJSObjectRef(arg));
232 }
233
234 IMessagePtr ConverterMessage::toIMessage(JSObjectRef arg)
235 {
236     LoggerD("message object=" << arg);
237     if (!arg) {
238         LoggerE("Object is null");
239         ThrowMsg(WrtDeviceApis::Commons::NullPointerException,
240                  "Private object not initialized");
241     }
242     IMessagePtr retVal;
243     // get private object
244     JSMessagePrivateObject* priv =
245         static_cast<JSMessagePrivateObject*>(JSObjectGetPrivate(arg));
246     if (!priv) {
247         LoggerE("Private object not initialized");
248         ThrowMsg(WrtDeviceApis::Commons::NullPointerException,
249                  "Private object not initialized");
250     }
251     retVal = priv->getObject();
252     if (!retVal) {
253         LoggerE("Message private object not initialized");
254         ThrowMsg(WrtDeviceApis::Commons::NullPointerException,
255                  "Private object not initialized");
256     }
257     return retVal;
258 }
259
260 IAttachmentPtr ConverterMessage::toIAttachment(JSValueRef arg)
261 {
262     return toIAttachment(toJSObjectRef(arg));
263 }
264
265 IAttachmentPtr ConverterMessage::toIAttachment(JSObjectRef arg)
266 {
267     if (!arg)
268     {
269         LoggerE("Object is Null");
270         ThrowMsg(WrtDeviceApis::Commons::NullPointerException, "Private object not initialized");
271     }
272
273     IAttachmentPtr retVal;
274     JSMessageAttachmentPrivate* priv =
275         static_cast<JSMessageAttachmentPrivate*>(JSObjectGetPrivate(arg));
276
277     if (!priv) {
278         LoggerE("Private object not initialized");
279         ThrowMsg(WrtDeviceApis::Commons::NullPointerException,
280                  "Private object not initialized");
281         }
282
283     retVal = priv->getObject();
284         if (!retVal) {
285         LoggerE("Message private object not initialized");
286         ThrowMsg(WrtDeviceApis::Commons::NullPointerException,
287                  "Private object not initialized");
288         }
289         return retVal;
290 }
291
292 IMessageFolderPtr ConverterMessage::toIMessageFolder(JSValueRef arg)
293 {
294     return toIMessageFolder(toJSObjectRef(arg));
295 }
296
297 IMessageFolderPtr ConverterMessage::toIMessageFolder(JSObjectRef arg)
298 {
299     if (!arg)
300     {
301         LoggerE("Object is Null");
302         ThrowMsg(WrtDeviceApis::Commons::NullPointerException, "Private object not initialized");
303     }
304
305     IMessageFolderPtr retVal;
306     JSMessageFolderPriv* priv =
307         static_cast<JSMessageFolderPriv*>(JSObjectGetPrivate(arg));
308
309     if (!priv) {
310         LoggerE("Private object not initialized");
311         ThrowMsg(WrtDeviceApis::Commons::NullPointerException,
312                  "Private object not initialized");
313         }
314
315     retVal = priv->getObject();
316         if (!retVal) {
317         LoggerE("Message private object not initialized");
318         ThrowMsg(WrtDeviceApis::Commons::NullPointerException,
319                  "Private object not initialized");
320         }
321         return retVal;
322 }
323
324 Recipients ConverterMessage::toRecipients(JSValueRef arg)
325 {
326     if (JSValueIsObjectOfClass(m_context, arg,
327                                JSRecipientArray::getClassRef())) {
328         RecipientsPtr recipients =
329             JSRecipientArray::getRecipients(m_context, toJSObjectRef(arg));
330         if (!recipients) {
331             Throw(WrtDeviceApis::Commons::ConversionException);
332         }
333         return *recipients;
334     }
335     Recipients retVal;
336     // convert JS value to vector of recipient addresses
337     vector<string> recip = toVectorOfStrings(arg);
338     retVal.setRecipients(recip);
339     return retVal;
340 }
341
342 OnMessagesChanged ConverterMessage::toMessageMultifunctions(JSValueRef argument, int multiFuntionType)
343 {
344         LoggerD("Enter");
345
346         LoggerD("multiFuntionType : " << multiFuntionType);
347
348         OnMessagesChanged result;
349         Validator validator(m_context);
350         JSObjectRef objectCallbacks = toJSObjectRef(argument);
351
352         ScopedJSStringRef propNameAdded(toJSStringRef(m_callbackNames[multiFuntionType].addedFunction));
353         ScopedJSStringRef propNameUpdated(toJSStringRef(m_callbackNames[multiFuntionType].updatedFunction));
354         ScopedJSStringRef propNameRemoved(toJSStringRef(m_callbackNames[multiFuntionType].removedFunction));
355
356         if(JSObjectHasProperty(m_context, objectCallbacks, propNameAdded.get()))
357         {
358                 LoggerD("added exist");
359                 result.messagesAdded = JSUtils::getJSPropertyOrUndefined(m_context, objectCallbacks, m_callbackNames[multiFuntionType].addedFunction);
360                 if (validator.isNullOrUndefined(result.messagesAdded))
361             result.messagesAdded = NULL;
362         else if (!validator.isCallback(result.messagesAdded)) {
363                         LoggerD("is not Callback");
364             ThrowMsg(ConversionException, "1nd argument's onsuccess attribute is not a 'function'");
365         }
366         }
367         if(JSObjectHasProperty(m_context, objectCallbacks, propNameUpdated.get()))
368         {
369                 LoggerD("updated exist");
370                 result.messagesUpdated = JSUtils::getJSPropertyOrUndefined(m_context, objectCallbacks, m_callbackNames[multiFuntionType].updatedFunction);
371                 if (validator.isNullOrUndefined(result.messagesUpdated))
372             result.messagesUpdated = NULL;
373         else if (!validator.isCallback(result.messagesUpdated)) {
374                         LoggerD("is not Callback");
375             ThrowMsg(ConversionException, "2nd argument's onsuccess attribute is not a 'function'");
376         }
377         }
378         if(JSObjectHasProperty(m_context, objectCallbacks, propNameRemoved.get()))
379         {
380                 LoggerD("removed exist");
381                 result.messagesRemoved = JSUtils::getJSPropertyOrUndefined(m_context, objectCallbacks, m_callbackNames[multiFuntionType].removedFunction);
382                 if (validator.isNullOrUndefined(result.messagesRemoved))
383             result.messagesRemoved = NULL;
384         else if (!validator.isCallback(result.messagesRemoved)) {
385                         LoggerD("is not Callback");
386             ThrowMsg(ConversionException, "3nd argument's onsuccess attribute is not a 'function'");
387         }
388         }
389
390         if(result.messagesAdded != NULL || result.messagesUpdated != NULL || result.messagesRemoved != NULL)
391         {
392             result.functionIndex = multiFuntionType;
393         }
394
395     return result;
396 }
397
398
399 std::vector<FolderType> ConverterMessage::toVectorOfFolderTypes(
400         JSValueRef arg)
401 {
402     return toVectorOfT_(arg, &ConverterMessage::toFolderType, this);
403 }
404
405 FolderType ConverterMessage::toFolderType(const JSValueRef& arg)
406 {
407     // convert JS value to folder type
408     messageFolders folder = static_cast<messageFolders>(toInt(arg));
409     switch (folder) {
410     case messageFolderInbox:
411         return INBOX;
412     case messageFolderOutbox:
413         return OUTBOX;
414     case messageFolderDrafts:
415         return DRAFTBOX;
416     case messageFolderSentbox:
417         return SENTBOX;
418     default:
419         ThrowMsg(WrtDeviceApis::Commons::InvalidArgumentException, "folder not supported");
420     }
421 }
422
423 MessageType ConverterMessage::toMessageType(JSValueRef arg)
424 {
425      return toMessageType(toJSObjectRef(arg));
426 }
427
428 MessageType ConverterMessage::toMessageType(JSObjectRef arg)
429 {
430     // convert JSvalue to message type enum
431     std::string strMsgType = toString(arg);
432     LoggerD("Messasge Type : " << strMsgType);
433
434     if ( strMsgType.compare("messaging.sms") == 0 )
435     {
436         return SMS;
437     }
438     else if ( strMsgType.compare("messaging.mms") == 0 )
439     {
440         return MMS;
441     }
442     else if ( strMsgType.compare("messaging.email") == 0 )
443     {
444         return EMAIL;
445     }
446     else
447     {
448         ThrowMsg(WrtDeviceApis::Commons::ConversionException, "message type not supported");
449     }
450
451 }
452
453 std::string ConverterMessage::toMessageType( long msgtype )
454 {
455     LoggerD("Messasge Type : " << msgtype);
456
457     switch (msgtype)
458     {
459         case SMS:
460             return "messaging.sms";
461         case MMS:
462             return "messaging.mms";
463         case EMAIL:
464             return "messaging.email";
465         default :
466             ThrowMsg(WrtDeviceApis::Commons::ConversionException, "message type not supported");
467     }
468 }
469
470 MessageType ConverterMessage::toMessageType(std::string arg)
471 {
472     LoggerD("Messasge Type : " << arg);
473
474     if ( arg.compare("messaging.sms") == 0 )
475     {
476         return SMS;
477     }
478     else if ( arg.compare("messaging.mms") == 0 )
479     {
480         return MMS;
481     }
482     else if ( arg.compare("messaging.email") == 0 )
483     {
484         return EMAIL;
485     }
486     else
487     {
488         std::string message = "Message type " + arg + " not supported.";
489         throw DeviceAPI::Common::TypeMismatchException(message.c_str());
490     }
491
492 }
493
494 std::string ConverterMessage::toMessageStatusType( long msgstatus )
495 {
496     LoggerD("Messasge Status : " << msgstatus);
497
498     switch (msgstatus)
499     {
500         case MESSAGE_STATUS_SENT:
501             return "SENT";
502         case MESSAGE_STATUS_SENDING:
503             return "SENDING";
504         case MESSAGE_STATUS_FAILED:
505             return "FAILED";
506         case MESSAGE_STATUS_DRAFT:
507             return "DRAFT";
508         case MESSAGE_STATUS_CREATED:
509         case MESSAGE_STATUS_LOADED:
510             return "";
511         default :
512             ThrowMsg(WrtDeviceApis::Commons::ConversionException, "message status not supported");
513     }
514 }
515
516 std::string ConverterMessage::convertIntToString( int msgInt )
517 {
518     LoggerD("input int : " << msgInt);
519     std::stringstream stream;
520     stream << msgInt;
521     return stream.str();
522 }
523
524 IConversationPtr ConverterMessage::toConversation(const JSValueRef& arg)
525 {
526     return JSConversation::getConversation(m_context, arg);
527 }
528
529 std::vector<IConversationPtr> ConverterMessage::toVectorOfConversation(const JSValueRef& arg)
530 {
531     std::vector<IConversationPtr> result;
532
533     JSObjectRef jsObject = toJSObjectRef(arg);
534
535     if(    JSGetArrayLength(m_context, jsObject) == 0)
536     {
537         LoggerE("this is empty conversation");
538         Throw(WrtDeviceApis::Commons::ConversionException);
539     }
540
541     for (std::size_t i = 0; i < JSGetArrayLength(m_context, jsObject); ++i)
542     {
543         JSValueRef element = JSGetArrayElement(m_context, jsObject, i);
544         result.push_back(toConversation(element));
545     }
546
547     return result;
548
549 }
550 AddressType ConverterMessage::toAddressType(JSValueRef arg)
551 {
552     // convert JSvalue to address type enum
553     string addressType = toString(arg);
554     if ("destination" == addressType) {
555         return TO_ADDRESS;
556     } else if ("cc" == addressType) {
557         return CC_ADDRESS;
558     } else if ("bcc" == addressType) {
559         return BCC_ADDRESS;
560     } else {
561         LoggerE("unknown address type");
562         Throw(WrtDeviceApis::Commons::InvalidArgumentException);
563     }
564 }
565
566 MessagePriority::Priority ConverterMessage::toMessagePriority(
567         JSValueRef arg)
568 {
569     if (toBool(arg)) {
570         return MessagePriority::HIGH;
571     } else {
572         return MessagePriority::NORMAL;
573     }
574 }
575
576 #if 0 // MESSAGING ATTACHMENT IS BLOCKED
577 DeviceAPI::Filesystem::INodePtr ConverterMessage::toFilesystemNode(JSValueRef arg)
578 {
579     // TODO It doesn't work even when object IS a JS File, not sure what to do?
580     //    if (!JSValueIsObjectOfClass(m_context, arg, JSFile::getClassRef())) {
581     //        ThrowMsg(WrtDeviceApis::Commons::ConversionException, "Not a JSFile object.");
582     //    }
583
584     JSObjectRef attObj = toJSObjectRef(arg);
585     JSFile::PrivateObject* privateObject =
586         static_cast<JSFile::PrivateObject*>(JSObjectGetPrivate(attObj));
587     if (!privateObject) {
588         ThrowMsg(WrtDeviceApis::Commons::NullPointerException, "Private object is NULL.");
589     }
590
591     DeviceAPI::Filesystem::INodePtr result = privateObject->getObject();
592     if (!result) {
593         ThrowMsg(WrtDeviceApis::Commons::NullPointerException, "Node object is NULL.");
594     }
595
596     return result;
597 }
598 #endif
599
600 JSValueRef ConverterMessage::toFunctionOrNull(const JSValueRef& arg)
601 {
602     Assert(arg && "Argument is NULL.");
603
604     if (Validator(m_context).isCallback(arg)) {
605         return arg;
606     } else if (!JSValueIsNull(m_context, arg) ) {
607         ThrowMsg(ConversionException, "Not a function nor JS null.");
608     }
609     return NULL;
610 }
611
612 JSValueRef ConverterMessage::toFunction(const JSValueRef& arg)
613 {
614     Assert(arg && "Argument is NULL.");
615
616     if (Validator(m_context).isCallback(arg)) {
617         return arg;
618     } else if (JSValueIsNull(m_context, 
619         arg) || JSValueIsUndefined(m_context, arg)) {
620         ThrowMsg(InvalidArgumentException, "JS null passed as function.");
621     }
622     ThrowMsg(ConversionException, "Not a function nor JS null.");
623 }
624
625 MessageSendCallback
626 ConverterMessage::toMessageSendCallback(const JSValueRef& arg)
627 {
628     JSObjectRef object = toJSObjectRef(arg);
629
630     MessageSendCallback result;
631     Validator validator(m_context);
632
633     result.onSuccess = JSUtils::getJSPropertyOrUndefined(
634             m_context, object, SEND_PROPERTY_ONSUCCESS
635             );
636     if (!validator.isNullOrUndefined(result.onSuccess) &&
637         !validator.isCallback(result.onSuccess)) {
638         ThrowMsg(WrtDeviceApis::Commons::ConversionException, "Not a valid callback.");
639     }
640
641     result.onMessageSendSuccess = JSUtils::getJSPropertyOrUndefined(
642             m_context, object, SEND_PROPERTY_ONMESSAGESENDSUCCESS
643             );
644     if (!validator.isNullOrUndefined(result.onMessageSendSuccess) &&
645         !validator.isCallback(result.onMessageSendSuccess)) {
646         ThrowMsg(WrtDeviceApis::Commons::ConversionException, "Not a valid callback.");
647     }
648
649     result.onMessageSendError = JSUtils::getJSPropertyOrUndefined(
650             m_context, object, SEND_PROPERTY_ONMESSAGESENDERROR
651             );
652     if (!validator.isNullOrUndefined(result.onMessageSendError) &&
653         !validator.isCallback(result.onMessageSendError)) {
654         ThrowMsg(WrtDeviceApis::Commons::ConversionException, "Not a valid callback.");
655     }
656
657     return result;
658 }
659 }
660 }