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