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