[Messaging] Deprecated whole module
[platform/core/api/webapi-plugins.git] / src / messaging / messaging_api.js
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 var validator_ = xwalk.utils.validator;
18 var types_ = validator_.Types;
19 var T_ = xwalk.utils.type;
20 var native = new xwalk.utils.NativeManager(extension);
21 var privUtils_ = xwalk.utils;
22
23 var Property = {
24     WRITEABLE: 1 << 0,
25     ENUMERABLE: 1 << 1,
26     CONFIGURABLE: 1 << 2
27 };
28
29 function addTypeToFilter_(data) {
30     var filter = {};
31
32     for (var field in data) {
33         filter[field] = data[field];
34     }
35
36     if (data instanceof tizen.AttributeFilter) {
37         filter.filterType = 'AttributeFilter';
38     } else if (data instanceof tizen.AttributeRangeFilter) {
39         filter.filterType = 'AttributeRangeFilter';
40     } else if (data instanceof tizen.CompositeFilter) {
41         filter.filterType = 'CompositeFilter';
42         // recursively convert all sub-filters
43         filter.filters = [];
44         for (var i = 0; i < data.filters.length; ++i) {
45             filter.filters[i] = addTypeToFilter_(data.filters[i]);
46         }
47     } else {
48         filter.filterType = 'Unknown';
49     }
50
51     return filter;
52 }
53
54 function propertyFactory_(that, name, value, flags, options) {
55     flags = flags || 0;
56     if (options === null || typeof options !== 'object') {
57         options = {};
58     }
59     if (!options.get && !options.set) {
60         options.value = value;
61     }
62     if ((flags & Property.WRITEABLE) != 0) {
63         options.writable = true;
64     }
65     if ((flags & Property.ENUMERABLE) != 0) {
66         options.enumerable = true;
67     }
68     if ((flags & Property.CONFIGURABLE) != 0) {
69         options.configurable = true;
70     }
71     Object.defineProperty(that, name, options);
72 }
73
74 function InternalValues_(data) {
75     if (!(this instanceof InternalValues_)) {
76         return new InternalValues_(data);
77     }
78     for (var key in data) {
79         if (data.hasOwnProperty(key)) {
80             this[key] = data[key];
81         }
82     }
83 }
84
85 function updateInternal_(internal, data) {
86     var values = new InternalValues_(data);
87     for (var key in data) {
88         if (values.hasOwnProperty(key) && internal.hasOwnProperty(key)) {
89             internal[key] = values;
90         }
91     }
92 }
93
94 var MessageServiceTag = {
95     SMS: 'messaging.sms',
96     MMS: 'messaging.mms',
97     EMAIL: 'messaging.email'
98 };
99
100 function Message(type, data) {
101     privUtils_.deprecationWarn(
102         'Message() is deprecated and will be ' +
103         'removed from next release without any alternatives. ',
104         '8.0'
105     );
106     validator_.isConstructorCall(this, Message);
107
108     if (Object.values(MessageServiceTag).indexOf(type) == -1) {
109         throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR);
110     }
111
112     if (!data || typeof data !== 'object') {
113         data = {};
114     }
115
116     var internal = data instanceof MessageInit_,
117         id = internal ? data.id : null,
118         conversationId = internal ? data.conversationId : null,
119         folderId = internal ? data.folderId : null,
120         timestamp = internal ? data.timestamp : null,
121         from = internal ? data.from : null,
122         hasAttachment = internal ? data.hasAttachment : false,
123         isRead = internal ? data.isRead : false,
124         inResponseTo = internal ? data.inResponseTo : null;
125
126     var body = new MessageBody({
127         messageId: id,
128         plainBody: data.plainBody,
129         htmlBody: data.htmlBody
130     });
131
132     var to = data.to;
133     if (!(to instanceof Array)) {
134         to = [];
135     }
136
137     var cc = data.cc;
138     if (!(cc instanceof Array)) {
139         cc = [];
140     }
141
142     var bcc = data.bcc;
143     if (!(bcc instanceof Array)) {
144         bcc = [];
145     }
146
147     var attachments = (internal ? data.attachments : []) || [];
148
149     var _internal = {
150         id: id || null,
151         conversationId: conversationId || null,
152         folderId: folderId || null,
153         type: type,
154         timestamp: timestamp || null,
155         from: from,
156         to: to || [],
157         cc: cc || [],
158         bcc: bcc || [],
159         body: body,
160         isRead: isRead || false,
161         hasAttachment: hasAttachment || false,
162         isHighPriority: data.isHighPriority || false,
163         subject: data.subject || '',
164         inResponseTo: inResponseTo || null,
165         attachments: attachments
166     };
167
168     Object.defineProperty(this, 'id', {
169         get: function() {
170             return _internal.id;
171         },
172         set: function(value) {
173             if (value instanceof InternalValues_) _internal.id = value.id;
174         },
175         enumerable: true
176     });
177
178     Object.defineProperty(this, 'conversationId', {
179         get: function() {
180             return _internal.conversationId;
181         },
182         set: function(value) {
183             if (value instanceof InternalValues_)
184                 _internal.conversationId = value.conversationId;
185         },
186         enumerable: true
187     });
188
189     Object.defineProperty(this, 'folderId', {
190         get: function() {
191             return _internal.folderId;
192         },
193         set: function(value) {
194             if (value instanceof InternalValues_) _internal.folderId = value.folderId;
195         },
196         enumerable: true
197     });
198
199     Object.defineProperty(this, 'type', {
200         get: function() {
201             return _internal.type;
202         },
203         set: function(value) {
204             return;
205         },
206         enumerable: true
207     });
208
209     Object.defineProperty(this, 'timestamp', {
210         get: function() {
211             return _internal.timestamp
212                 ? new Date(_internal.timestamp * 1000)
213                 : _internal.timestamp;
214         },
215         set: function(value) {
216             if (value instanceof InternalValues_) {
217                 _internal.timestamp = value.timestamp;
218             }
219         },
220         enumerable: true
221     });
222
223     Object.defineProperty(this, 'from', {
224         get: function() {
225             return _internal.from;
226         },
227         set: function(value) {
228             if (value instanceof InternalValues_) _internal.from = value.from;
229         },
230         enumerable: true
231     });
232
233     Object.defineProperty(this, 'to', {
234         get: function() {
235             return _internal.to;
236         },
237         set: function(value) {
238             if (value instanceof InternalValues_) value = value.to;
239             if (value instanceof Array) _internal.to = value;
240         },
241         enumerable: true
242     });
243
244     Object.defineProperty(this, 'cc', {
245         get: function() {
246             return _internal.cc;
247         },
248         set: function(value) {
249             if (value instanceof InternalValues_) value = value.cc;
250             if (value instanceof Array) _internal.cc = value;
251         },
252         enumerable: true
253     });
254
255     Object.defineProperty(this, 'bcc', {
256         get: function() {
257             return _internal.bcc;
258         },
259         set: function(value) {
260             if (value instanceof InternalValues_) value = value.bcc;
261             if (value instanceof Array) _internal.bcc = value;
262         },
263         enumerable: true
264     });
265
266     Object.defineProperty(this, 'body', {
267         get: function() {
268             return _internal.body;
269         },
270         set: function(value) {
271             if (value instanceof InternalValues_)
272                 _internal.body = new MessageBody(value.body);
273             if (value instanceof MessageBody) _internal.body = value;
274         },
275         enumerable: true
276     });
277
278     Object.defineProperty(this, 'isRead', {
279         get: function() {
280             return _internal.isRead;
281         },
282         set: function(value) {
283             if (value instanceof InternalValues_) {
284                 value = value.isRead;
285             }
286             _internal.isRead = !!value;
287         },
288         enumerable: true
289     });
290
291     Object.defineProperty(this, 'hasAttachment', {
292         get: function() {
293             return _internal.attachments.length > 0;
294         },
295         set: function(value) {
296             if (value instanceof InternalValues_)
297                 _internal.hasAttachment = value.hasAttachment;
298         },
299         enumerable: true
300     });
301
302     Object.defineProperty(this, 'isHighPriority', {
303         get: function() {
304             return _internal.isHighPriority;
305         },
306         set: function(value) {
307             if (value instanceof InternalValues_) value = value.isHighPriority;
308             _internal.isHighPriority = !!value;
309         },
310         enumerable: true
311     });
312
313     Object.defineProperty(this, 'subject', {
314         get: function() {
315             return _internal.subject;
316         },
317         set: function(value) {
318             if (value instanceof InternalValues_) value = value.subject;
319             _internal.subject = String(value);
320         },
321         enumerable: true
322     });
323
324     Object.defineProperty(this, 'inResponseTo', {
325         get: function() {
326             return _internal.inResponseTo;
327         },
328         set: function(value) {
329             if (value instanceof InternalValues_)
330                 _internal.inResponseTo = value.inResponseTo;
331         },
332         enumerable: true
333     });
334
335     Object.defineProperty(this, 'messageStatus', {
336         get: function() {
337             if (_internal.id) {
338                 var callArgs = {
339                     id: _internal.id,
340                     type: _internal.type
341                 };
342                 var result = native.callSync('MessageGetMessageStatus', callArgs);
343                 if (native.isSuccess(result)) {
344                     return native.getResultObject(result);
345                 }
346             }
347             return '';
348         },
349         set: function(value) {
350             return;
351         },
352         enumerable: true
353     });
354
355     Object.defineProperty(this, 'attachments', {
356         get: function() {
357             return _internal.attachments;
358         },
359         set: function(value) {
360             if (value instanceof InternalValues_) {
361                 value = value.attachments;
362                 for (var k = 0; k < value.length; ++k) {
363                     if (!(value[k] instanceof tizen.MessageAttachment)) {
364                         if (_internal.attachments[k]) {
365                             updateInternal_(_internal.attachments[k], value[k]);
366                         } else {
367                             _internal.attachments[k] = new MessageAttachment(
368                                 new InternalValues_(value[k])
369                             );
370                         }
371                     } else {
372                         _internal.attachments[k] = value[k];
373                     }
374                 }
375                 // if new array is shorter than the old one, remove excess elements
376                 if (value.length < _internal.length) {
377                     _internal.splice(value.length, _internal.length - value.length);
378                 }
379             } else if (T_.isArray(value)) {
380                 for (var k = 0; k < value.length; ++k) {
381                     if (!(value[k] instanceof tizen.MessageAttachment)) {
382                         return;
383                     }
384                 }
385                 _internal.attachments = value;
386             }
387         },
388         enumerable: true
389     });
390 }
391
392 function MessageInit_(data) {
393     if (!(this instanceof MessageInit_)) {
394         return new MessageInit_(data);
395     }
396     if (!data || typeof data !== 'object') {
397         data = {};
398     }
399     this.id = data.id || null;
400     this.conversationId = data.conversationId || null;
401     this.folderId = data.folderId || null;
402     this.timestamp = data.timestamp || null;
403     this.from = data.from || '';
404     this.to = data.to || [];
405     this.cc = data.cc || [];
406     this.bcc = data.bcc || [];
407     this.isRead = data.isRead || false;
408     this.hasAttachment = data.hasAttachment || null;
409     this.isHighPriority = data.isHighPriority || false;
410     this.subject = data.subject || '';
411     this.inResponseTo = data.inResponseTo || null;
412     this.attachments = [];
413     this.plainBody = data.body ? data.body.plainBody : '';
414     this.htmlBody = data.body ? data.body.htmlBody : '';
415
416     var self = this;
417     if (data.attachments && data.attachments.constructor === Array) {
418         data.attachments.forEach(function(el) {
419             if (!el) return;
420
421             if (el.constructor === MessageAttachment) {
422                 self.attachments.push(el);
423             } else {
424                 self.attachments.push(new MessageAttachment(new InternalValues_(el)));
425             }
426         });
427     }
428 }
429
430 function MessageBody(data) {
431     if (!this instanceof MessageBody) {
432         return new MessageBody(data);
433     }
434     if (data === null || typeof data !== 'object') {
435         data = {};
436     }
437
438     var _internal = {
439         messageId: data.messageId || null,
440         loaded: data.loaded || false,
441         plainBody: data.plainBody || '',
442         htmlBody: data.htmlBody || '',
443         inlineAttachments: data.inlineAttachments || []
444     };
445
446     Object.defineProperty(this, 'messageId', {
447         get: function() {
448             return _internal.messageId;
449         },
450         set: function(value) {
451             if (value instanceof InternalValues_) _internal.messageId = value.messageId;
452         },
453         enumerable: true
454     });
455
456     Object.defineProperty(this, 'loaded', {
457         get: function() {
458             return _internal.loaded;
459         },
460         set: function(value) {
461             if (value instanceof InternalValues_) _internal.loaded = value.loaded;
462         },
463         enumerable: true
464     });
465
466     Object.defineProperty(this, 'plainBody', {
467         get: function() {
468             return _internal.plainBody;
469         },
470         set: function(value) {
471             if (value instanceof InternalValues_) {
472                 _internal.plainBody = String(value.plainBody);
473             } else {
474                 _internal.plainBody = String(value);
475             }
476         },
477         enumerable: true
478     });
479
480     Object.defineProperty(this, 'htmlBody', {
481         get: function() {
482             return _internal.htmlBody;
483         },
484         set: function(value) {
485             if (value instanceof InternalValues_) {
486                 _internal.htmlBody = String(value.htmlBody);
487             } else {
488                 _internal.htmlBody = String(value);
489             }
490         },
491         enumerable: true
492     });
493
494     Object.defineProperty(this, 'inlineAttachments', {
495         get: function() {
496             return _internal.inlineAttachments;
497         },
498         set: function(value) {
499             if (value instanceof InternalValues_) {
500                 _internal.inlineAttachments = value.inlineAttachments;
501             } else if (T_.isArray(value)) {
502                 _internal.inlineAttachments = value;
503             }
504         },
505         enumerable: true
506     });
507 }
508
509 var messageAttachmentsLoaded = {};
510
511 function MessageAttachment(first, second) {
512     privUtils_.deprecationWarn(
513         'MessageAttachment() is deprecated and will be ' +
514         'removed from next release without any alternatives. ',
515         '8.0'
516     );
517     validator_.isConstructorCall(this, MessageAttachment);
518     if (!this instanceof MessageAttachment) {
519         return new MessageAttachment(data);
520     }
521
522     var internalConstructor = first instanceof InternalValues_;
523     var _internal = {
524         messageId: internalConstructor ? first.messageId : null,
525         id: internalConstructor ? first.id : null,
526         mimeType: internalConstructor
527             ? first.mimeType
528             : undefined == second
529                 ? null
530                 : second,
531         filePath: internalConstructor ? first.filePath : first
532     };
533
534     Object.defineProperty(this, 'messageId', {
535         get: function() {
536             return _internal.messageId;
537         },
538         set: function(value) {
539             if (value instanceof InternalValues_) _internal.messageId = value.messageId;
540         },
541         enumerable: true
542     });
543
544     Object.defineProperty(this, 'id', {
545         get: function() {
546             return _internal.id;
547         },
548         set: function(value) {
549             if (value instanceof InternalValues_) _internal.id = value.id;
550         },
551         enumerable: true
552     });
553
554     Object.defineProperty(this, 'mimeType', {
555         get: function() {
556             return _internal.mimeType;
557         },
558         set: function(value) {
559             if (value instanceof InternalValues_) _internal.mimeType = value.mimeType;
560         },
561         enumerable: true
562     });
563
564     Object.defineProperty(this, 'filePath', {
565         get: function() {
566             if (_internal.id && !messageAttachmentsLoaded[_internal.id]) {
567                 return null;
568             }
569
570             return _internal.filePath;
571         },
572         set: function(value) {
573             if (value instanceof InternalValues_) _internal.filePath = value.filePath;
574         },
575         enumerable: true
576     });
577 }
578
579 function Messaging() {}
580
581 Messaging.prototype.getMessageServices = function() {
582     privUtils_.deprecationWarn(
583         'getMessageServices() is deprecated and will be ' +
584         'removed from next release without any alternatives. ',
585         '8.0'
586     );
587     var args = validator_.validateArgs(arguments, [
588         {
589             name: 'messageServiceType',
590             type: types_.ENUM,
591             values: Object.values(MessageServiceTag)
592         },
593         { name: 'successCallback', type: types_.FUNCTION },
594         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
595     ]);
596
597     var callArgs = { messageServiceType: args.messageServiceType };
598     var callback = function(result) {
599         if (native.isFailure(result)) {
600             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
601         } else {
602             var data = native.getResultObject(result);
603             var servicesArr = [];
604             data.forEach(function(e) {
605                 servicesArr.push(new MessageService(e));
606             });
607             args.successCallback(servicesArr);
608         }
609     };
610     var result = native.call('GetMessageServices', callArgs, callback);
611     if (native.isFailure(result)) {
612         throw native.getErrorObject(result);
613     }
614 };
615
616 function MessageStorage() {}
617 function MessageService(data) {
618     propertyFactory_(this, 'id', data.id, Property.ENUMERABLE);
619     propertyFactory_(this, 'type', data.type, Property.ENUMERABLE);
620     propertyFactory_(this, 'name', data.name, Property.ENUMERABLE);
621     propertyFactory_(
622         this,
623         'messageStorage',
624         new MessageStorage(this),
625         Property.ENUMERABLE
626     );
627 }
628
629 MessageService.prototype.sendMessage = function() {
630     privUtils_.deprecationWarn(
631         'sendMessage() is deprecated and will be ' +
632         'removed from next release without any alternatives. ',
633         '8.0'
634     );
635     var args = validator_.validateArgs(arguments, [
636         { name: 'message', type: types_.PLATFORM_OBJECT, values: tizen.Message },
637         {
638             name: 'successCallback',
639             type: types_.FUNCTION,
640             optional: true,
641             nullable: true
642         },
643         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
644         { name: 'simIndex', type: types_.LONG, optional: true, nullable: true }
645     ]);
646
647     if (args.message.type != this.type) {
648         throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR);
649     }
650
651     var self = this;
652
653     var callArgs = {
654         message: args.message,
655         simIndex: args.simIndex || 1,
656         serviceId: self.id
657     };
658     var callback = function(result) {
659         if (native.isFailure(result)) {
660             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
661         } else {
662             var data = native.getResultObject(result);
663             var message = data.message;
664             if (message) {
665                 var body = message.body;
666                 if (body) {
667                     updateInternal_(args.message.body, body);
668                     delete message.body;
669                 }
670                 updateInternal_(args.message, message);
671             }
672             native.callIfPossible(args.successCallback, data.recipients);
673         }
674     };
675     var result = native.call('MessageServiceSendMessage', callArgs, callback);
676     if (native.isFailure(result)) {
677         throw native.getErrorObject(result);
678     }
679 };
680
681 MessageService.prototype.loadMessageBody = function() {
682     privUtils_.deprecationWarn(
683         'loadMessageBody() is deprecated and will be ' +
684         'removed from next release without any alternatives. ',
685         '8.0'
686     );
687     var args = validator_.validateArgs(arguments, [
688         { name: 'message', type: types_.PLATFORM_OBJECT, values: tizen.Message },
689         { name: 'successCallback', type: types_.FUNCTION },
690         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
691     ]);
692
693     if (args.message.type != this.type) {
694         throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR);
695     }
696
697     var self = this;
698
699     var callArgs = {
700         message: args.message,
701         serviceId: self.id
702     };
703
704     var callback = function(result) {
705         if (native.isFailure(result)) {
706             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
707         } else {
708             var data = native.getResultObject(result);
709             var body = data.messageBody;
710             if (body) {
711                 updateInternal_(args.message.body, body);
712             }
713
714             args.successCallback(args.message);
715         }
716     };
717
718     var result = native.call('MessageServiceLoadMessageBody', callArgs, callback);
719
720     if (native.isFailure(result)) {
721         throw native.getErrorObject(result);
722     }
723 };
724 MessageService.prototype.loadMessageAttachment = function() {
725     privUtils_.deprecationWarn(
726         'loadMessageAttachment() is deprecated and will be ' +
727         'removed from next release without any alternatives. ',
728         '8.0'
729     );
730     var args = validator_.validateArgs(arguments, [
731         { name: 'attachment', type: types_.PLATFORM_OBJECT, values: MessageAttachment },
732         { name: 'successCallback', type: types_.FUNCTION },
733         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
734     ]);
735
736     var self = this;
737     var firstCall = false;
738     if (!messageAttachmentsLoaded[args.attachment.id]) {
739         firstCall = true;
740         messageAttachmentsLoaded[args.attachment.id] = true;
741     }
742
743     var callArgs = {
744         attachment: args.attachment,
745         serviceId: self.id
746     };
747
748     var callback = function(result) {
749         if (native.isFailure(result)) {
750             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
751         } else {
752             var data = native.getResultObject(result);
753             var messageAttachment = data.messageAttachment;
754             if (messageAttachment) {
755                 updateInternal_(args.attachment, messageAttachment);
756             }
757
758             args.successCallback(args.attachment);
759         }
760     };
761
762     var result = native.call('MessageServiceLoadMessageAttachment', callArgs, callback);
763
764     if (native.isFailure(result)) {
765         throw native.getErrorObject(result);
766     }
767 };
768
769 MessageService.prototype.sync = function() {
770     privUtils_.deprecationWarn(
771         'sync() is deprecated and will be ' +
772         'removed from next release without any alternatives. ',
773         '8.0'
774     );
775     var args = validator_.validateArgs(arguments, [
776         {
777             name: 'successCallback',
778             type: types_.FUNCTION,
779             optional: true,
780             nullable: true
781         },
782         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
783         { name: 'limit', type: types_.UNSIGNED_LONG, optional: true, nullable: true }
784     ]);
785
786     var self = this;
787
788     var callArgs = {
789         id: self.id,
790         limit: args.limit || null
791     };
792
793     var callback = function(result) {
794         if (native.isFailure(result)) {
795             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
796         } else {
797             native.callIfPossible(args.successCallback);
798         }
799     };
800
801     var result = native.call('MessageServiceSync', callArgs, callback);
802
803     if (native.isFailure(result)) {
804         throw native.getErrorObject(result);
805     }
806
807     return native.getResultObject(result);
808 };
809
810 MessageService.prototype.syncFolder = function() {
811     privUtils_.deprecationWarn(
812         'syncFolder() is deprecated and will be ' +
813         'removed from next release without any alternatives. ',
814         '8.0'
815     );
816     var args = validator_.validateArgs(arguments, [
817         { name: 'folder', type: types_.PLATFORM_OBJECT, values: MessageFolder },
818         {
819             name: 'successCallback',
820             type: types_.FUNCTION,
821             optional: true,
822             nullable: true
823         },
824         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
825         { name: 'limit', type: types_.UNSIGNED_LONG, optional: true, nullable: true }
826     ]);
827
828     var self = this;
829
830     var callArgs = {
831         id: self.id,
832         folder: args.folder,
833         limit: args.limit || null
834     };
835
836     var callback = function(result) {
837         if (native.isFailure(result)) {
838             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
839         } else {
840             native.callIfPossible(args.successCallback);
841         }
842     };
843
844     var result = native.call('MessageServiceSyncFolder', callArgs, callback);
845
846     if (native.isFailure(result)) {
847         throw native.getErrorObject(result);
848     }
849
850     return native.getResultObject(result);
851 };
852
853 MessageService.prototype.stopSync = function() {
854     privUtils_.deprecationWarn(
855         'stopSync() is deprecated and will be ' +
856         'removed from next release without any alternatives. ',
857         '8.0'
858     );
859     var args = validator_.validateArgs(arguments, [{ name: 'opId', type: types_.LONG }]);
860
861     var self = this;
862     var callArgs = {
863         id: self.id,
864         opId: args.opId
865     };
866     var result = native.callSync('MessageServiceStopSync', callArgs);
867     if (native.isFailure(result)) {
868         throw native.getErrorObject(result);
869     }
870 };
871
872 function MessageStorage(service) {
873     propertyFactory_(this, 'service', service);
874 }
875
876 MessageStorage.prototype.addDraftMessage = function() {
877     privUtils_.deprecationWarn(
878         'addDraftMessage() is deprecated and will be ' +
879         'removed from next release without any alternatives. ',
880         '8.0'
881     );
882     var args = validator_.validateArgs(arguments, [
883         { name: 'message', type: types_.PLATFORM_OBJECT, values: tizen.Message },
884         {
885             name: 'successCallback',
886             type: types_.FUNCTION,
887             optional: true,
888             nullable: true
889         },
890         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
891     ]);
892
893     if (args.message.type != this.service.type) {
894         throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR);
895     }
896
897     var self = this;
898
899     var callArgs = {
900         message: args.message,
901         serviceId: self.service.id
902     };
903     var callback = function(result) {
904         if (native.isFailure(result)) {
905             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
906         } else {
907             var data = native.getResultObject(result);
908             var message = data.message;
909             if (message) {
910                 var body = message.body;
911                 if (body) {
912                     updateInternal_(args.message.body, body);
913                     delete message.body;
914                 }
915                 var attachments = message.attachments;
916                 if (attachments) {
917                     for (var i = 0; i < attachments.length; i++) {
918                         messageAttachmentsLoaded[attachments[i].id] = true;
919                     }
920                 }
921                 updateInternal_(args.message, message);
922             }
923             native.callIfPossible(args.successCallback, data.recipients);
924         }
925     };
926     var result = native.call('MessageStorageAddDraftMessage', callArgs, callback);
927     if (native.isFailure(result)) {
928         throw native.getErrorObject(result);
929     }
930 };
931
932 MessageStorage.prototype.findMessages = function() {
933     privUtils_.deprecationWarn(
934         'findMessages() is deprecated and will be ' +
935         'removed from next release without any alternatives. ',
936         '8.0'
937     );
938     var args = validator_.validateArgs(arguments, [
939         {
940             name: 'filter',
941             type: types_.PLATFORM_OBJECT,
942             values: [
943                 tizen.AttributeFilter,
944                 tizen.AttributeRangeFilter,
945                 tizen.CompositeFilter
946             ]
947         },
948         { name: 'successCallback', type: types_.FUNCTION },
949         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
950         {
951             name: 'sort',
952             type: types_.PLATFORM_OBJECT,
953             values: tizen.SortMode,
954             optional: true,
955             nullable: true
956         },
957         { name: 'limit', type: types_.UNSIGNED_LONG, optional: true, nullable: true },
958         { name: 'offset', type: types_.UNSIGNED_LONG, optional: true, nullable: true }
959     ]);
960
961     var self = this;
962
963     var callArgs = {
964         filter: addTypeToFilter_(args.filter) || null,
965         sort: args.sort || null,
966         limit: args.limit || null,
967         offset: args.offset || null,
968         serviceId: self.service.id,
969         type: self.service.type
970     };
971     var callback = function(result) {
972         if (native.isFailure(result)) {
973             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
974         } else {
975             var data = native.getResultObject(result);
976             var messages = [];
977             data.forEach(function(el) {
978                 messages.push(new tizen.Message(el.type, new MessageInit_(el)));
979             });
980             native.callIfPossible(args.successCallback, messages);
981         }
982     };
983     var result = native.call('MessageStorageFindMessages', callArgs, callback);
984     if (native.isFailure(result)) {
985         throw native.getErrorObject(result);
986     }
987 };
988
989 MessageStorage.prototype.removeMessages = function() {
990     privUtils_.deprecationWarn(
991         'removeMessages() is deprecated and will be ' +
992         'removed from next release without any alternatives. ',
993         '8.0'
994     );
995     var args = validator_.validateArgs(arguments, [
996         { name: 'messages', type: types_.ARRAY, values: Message },
997         {
998             name: 'successCallback',
999             type: types_.FUNCTION,
1000             optional: true,
1001             nullable: true
1002         },
1003         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
1004     ]);
1005
1006     var self = this;
1007
1008     args.messages.forEach(function(msg) {
1009         if (msg.type != self.service.type) {
1010             throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR);
1011         }
1012     });
1013
1014     var callArgs = {
1015         messages: args.messages,
1016         serviceId: self.service.id,
1017         type: self.service.type
1018     };
1019     var callback = function(result) {
1020         if (native.isFailure(result)) {
1021             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
1022         } else {
1023             native.callIfPossible(args.successCallback);
1024         }
1025     };
1026     var result = native.call('MessageStorageRemoveMessages', callArgs, callback);
1027     if (native.isFailure(result)) {
1028         throw native.getErrorObject(result);
1029     }
1030 };
1031
1032 MessageStorage.prototype.updateMessages = function() {
1033     privUtils_.deprecationWarn(
1034         'updateMessages() is deprecated and will be ' +
1035         'removed from next release without any alternatives. ',
1036         '8.0'
1037     );
1038     var args = validator_.validateArgs(arguments, [
1039         { name: 'messages', type: types_.ARRAY, values: Message },
1040         {
1041             name: 'successCallback',
1042             type: types_.FUNCTION,
1043             optional: true,
1044             nullable: true
1045         },
1046         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
1047     ]);
1048
1049     var self = this;
1050
1051     args.messages.forEach(function(msg) {
1052         if (msg.type != self.service.type) {
1053             throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR);
1054         }
1055     });
1056
1057     var callArgs = {
1058         messages: args.messages,
1059         serviceId: self.service.id
1060     };
1061     var callback = function(result) {
1062         if (native.isFailure(result)) {
1063             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
1064         } else {
1065             var data = native.getResultObject(result);
1066             var originals = {},
1067                 i = args.messages.length,
1068                 m;
1069             while (i--) {
1070                 m = args.messages[i];
1071                 if (m.id) {
1072                     originals[m.id] = m;
1073                 }
1074             }
1075
1076             i = data.length;
1077             while (i--) {
1078                 m = data[i];
1079                 if (originals[m.oldId]) {
1080                     var body = m.body;
1081                     if (body) {
1082                         updateInternal_(originals[m.oldId].body, body);
1083                         delete m.body;
1084                     }
1085                     updateInternal_(originals[m.oldId], m);
1086                 }
1087             }
1088
1089             native.callIfPossible(args.successCallback);
1090         }
1091     };
1092     var result = native.call('MessageStorageUpdateMessages', callArgs, callback);
1093     if (native.isFailure(result)) {
1094         throw native.getErrorObject(result);
1095     }
1096 };
1097
1098 MessageStorage.prototype.findConversations = function() {
1099     privUtils_.deprecationWarn(
1100         'findConversations() is deprecated and will be ' +
1101         'removed from next release without any alternatives. ',
1102         '8.0'
1103     );
1104     var args = validator_.validateArgs(arguments, [
1105         {
1106             name: 'filter',
1107             type: types_.PLATFORM_OBJECT,
1108             values: [
1109                 tizen.AttributeFilter,
1110                 tizen.AttributeRangeFilter,
1111                 tizen.CompositeFilter
1112             ]
1113         },
1114         { name: 'successCallback', type: types_.FUNCTION },
1115         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true },
1116         {
1117             name: 'sort',
1118             type: types_.PLATFORM_OBJECT,
1119             values: tizen.SortMode,
1120             optional: true,
1121             nullable: true
1122         },
1123         { name: 'limit', type: types_.UNSIGNED_LONG, optional: true, nullable: true },
1124         { name: 'offset', type: types_.UNSIGNED_LONG, optional: true, nullable: true }
1125     ]);
1126
1127     var self = this;
1128
1129     var callArgs = {
1130         filter: addTypeToFilter_(args.filter),
1131         sort: args.sort || null,
1132         limit: args.limit || null,
1133         offset: args.offset || null,
1134         serviceId: self.service.id
1135     };
1136     var callback = function(result) {
1137         if (native.isFailure(result)) {
1138             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
1139         } else {
1140             var data = native.getResultObject(result);
1141             var conversations = [];
1142             data.forEach(function(el) {
1143                 conversations.push(new MessageConversation(el));
1144             });
1145             args.successCallback(conversations);
1146         }
1147     };
1148     var result = native.call('MessageStorageFindConversations', callArgs, callback);
1149     if (native.isFailure(result)) {
1150         throw native.getErrorObject(result);
1151     }
1152 };
1153
1154 MessageStorage.prototype.removeConversations = function() {
1155     privUtils_.deprecationWarn(
1156         'removeConversations() is deprecated and will be ' +
1157         'removed from next release without any alternatives. ',
1158         '8.0'
1159     );
1160     var args = validator_.validateArgs(arguments, [
1161         { name: 'conversations', type: types_.ARRAY },
1162         {
1163             name: 'successCallback',
1164             type: types_.FUNCTION,
1165             optional: true,
1166             nullable: true
1167         },
1168         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
1169     ]);
1170
1171     args.conversations.forEach(function(el) {
1172         if (!el || el.constructor !== MessageConversation) {
1173             throw new WebAPIException(WebAPIException.TYPE_MISMATCH_ERR);
1174         }
1175     });
1176
1177     var self = this;
1178
1179     var callArgs = {
1180         conversations: args.conversations,
1181         serviceId: self.service.id,
1182         type: self.service.type
1183     };
1184     var callback = function(result) {
1185         if (native.isFailure(result)) {
1186             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
1187         } else {
1188             native.callIfPossible(args.successCallback);
1189         }
1190     };
1191     var result = native.call('MessageStorageRemoveConversations', callArgs, callback);
1192     if (native.isFailure(result)) {
1193         throw native.getErrorObject(result);
1194     }
1195 };
1196
1197 MessageStorage.prototype.findFolders = function() {
1198     privUtils_.deprecationWarn(
1199         'findFolders() is deprecated and will be ' +
1200         'removed from next release without any alternatives. ',
1201         '8.0'
1202     );
1203     var args = validator_.validateArgs(arguments, [
1204         {
1205             name: 'filter',
1206             type: types_.PLATFORM_OBJECT,
1207             values: [
1208                 tizen.AttributeFilter,
1209                 tizen.AttributeRangeFilter,
1210                 tizen.CompositeFilter
1211             ]
1212         },
1213         { name: 'successCallback', type: types_.FUNCTION },
1214         { name: 'errorCallback', type: types_.FUNCTION, optional: true, nullable: true }
1215     ]);
1216
1217     var self = this;
1218
1219     var callArgs = {
1220         filter: addTypeToFilter_(args.filter),
1221         sort: args.sort || null,
1222         limit: args.limit || null,
1223         offset: args.offset || null,
1224         serviceId: self.service.id
1225     };
1226     var callback = function(result) {
1227         if (native.isFailure(result)) {
1228             native.callIfPossible(args.errorCallback, native.getErrorObject(result));
1229         } else {
1230             var data = native.getResultObject(result);
1231             var folders = [];
1232             data.forEach(function(el) {
1233                 folders.push(new MessageFolder(el));
1234             });
1235             args.successCallback(folders);
1236         }
1237     };
1238     var result = native.call('MessageStorageFindFolders', callArgs, callback);
1239     if (native.isFailure(result)) {
1240         throw native.getErrorObject(result);
1241     }
1242 };
1243
1244 function pushMessage(messages, el) {
1245     messages.push(new tizen.Message(el.type, new MessageInit_(el)));
1246 }
1247
1248 function pushConversation(conversations, el) {
1249     conversations.push(new MessageConversation(el));
1250 }
1251
1252 function pushFolder(folders, el) {
1253     folders.push(new MessageFolder(el));
1254 }
1255
1256 function getListenerFunction(listenerMap, pushMethod) {
1257     return function(msg) {
1258         var action = msg.action;
1259         var data = native.getResultObject(msg);
1260         var messages = [];
1261         data.forEach(function(el) {
1262             pushMethod(messages, el);
1263         });
1264
1265         for (var key in listenerMap) {
1266             if (listenerMap.hasOwnProperty(key)) {
1267                 native.callIfPossible(listenerMap[key][action], messages);
1268             }
1269         }
1270     };
1271 }
1272
1273 var MESSAGES_CHANGE_LISTENER = 'MessagesChangeListener';
1274 var MessagesChangeListeners = {};
1275 native.addListener(
1276     MESSAGES_CHANGE_LISTENER,
1277     getListenerFunction(MessagesChangeListeners, pushMessage)
1278 );
1279
1280 var CONVERSATIONS_CHANGE_LISTENER = 'ConversationsChangeListener';
1281 var ConversationsChangeListeners = {};
1282 native.addListener(
1283     CONVERSATIONS_CHANGE_LISTENER,
1284     getListenerFunction(ConversationsChangeListeners, pushConversation)
1285 );
1286
1287 var FOLDERS_CHANGE_LISTENER = 'FoldersChangeListener';
1288 var FoldersChangeListeners = {};
1289 native.addListener(
1290     FOLDERS_CHANGE_LISTENER,
1291     getListenerFunction(FoldersChangeListeners, pushFolder)
1292 );
1293
1294 MessageStorage.prototype.addMessagesChangeListener = function() {
1295     privUtils_.deprecationWarn(
1296         'addMessagesChangeListener() is deprecated and will be ' +
1297         'removed from next release without any alternatives. ',
1298         '8.0'
1299     );
1300     var args = validator_.validateArgs(arguments, [
1301         {
1302             name: 'messagesChangeCallback',
1303             type: types_.LISTENER,
1304             values: ['messagesadded', 'messagesupdated', 'messagesremoved']
1305         },
1306         {
1307             name: 'filter',
1308             type: types_.PLATFORM_OBJECT,
1309             values: [
1310                 tizen.AttributeFilter,
1311                 tizen.AttributeRangeFilter,
1312                 tizen.CompositeFilter
1313             ],
1314             optional: true,
1315             nullable: true
1316         }
1317     ]);
1318
1319     var self = this;
1320
1321     var callArgs = {
1322         filter: args.filter ? addTypeToFilter_(args.filter) : null,
1323         serviceId: self.service.id
1324     };
1325     var result = native.callSync('MessageStorageAddMessagesChangeListener', callArgs);
1326     if (native.isFailure(result)) {
1327         throw native.getErrorObject(result);
1328     } else {
1329         var opId = native.getResultObject(result);
1330         MessagesChangeListeners[opId] = args.messagesChangeCallback;
1331         return opId;
1332     }
1333 };
1334
1335 MessageStorage.prototype.addConversationsChangeListener = function() {
1336     privUtils_.deprecationWarn(
1337         'addConversationsChangeListener() is deprecated and will be ' +
1338         'removed from next release without any alternatives. ',
1339         '8.0'
1340     );
1341     var args = validator_.validateArgs(arguments, [
1342         {
1343             name: 'conversationsChangeCallback',
1344             type: types_.LISTENER,
1345             values: ['conversationsadded', 'conversationsupdated', 'conversationsremoved']
1346         },
1347         {
1348             name: 'filter',
1349             type: types_.PLATFORM_OBJECT,
1350             values: [
1351                 tizen.AttributeFilter,
1352                 tizen.AttributeRangeFilter,
1353                 tizen.CompositeFilter
1354             ],
1355             optional: true,
1356             nullable: true
1357         }
1358     ]);
1359
1360     var self = this;
1361
1362     var callArgs = {
1363         filter: args.filter ? addTypeToFilter_(args.filter) : null,
1364         serviceId: self.service.id
1365     };
1366     var result = native.callSync(
1367         'MessageStorageAddConversationsChangeListener',
1368         callArgs
1369     );
1370     if (native.isFailure(result)) {
1371         throw native.getErrorObject(result);
1372     } else {
1373         var opId = native.getResultObject(result);
1374         ConversationsChangeListeners[opId] = args.conversationsChangeCallback;
1375         return opId;
1376     }
1377 };
1378
1379 MessageStorage.prototype.addFoldersChangeListener = function() {
1380     privUtils_.deprecationWarn(
1381         'addFoldersChangeListener() is deprecated and will be ' +
1382         'removed from next release without any alternatives. ',
1383         '8.0'
1384     );
1385     var args = validator_.validateArgs(arguments, [
1386         {
1387             name: 'foldersChangeCallback',
1388             type: types_.LISTENER,
1389             values: ['foldersadded', 'foldersupdated', 'foldersremoved']
1390         },
1391         {
1392             name: 'filter',
1393             type: types_.PLATFORM_OBJECT,
1394             values: [
1395                 tizen.AttributeFilter,
1396                 tizen.AttributeRangeFilter,
1397                 tizen.CompositeFilter
1398             ],
1399             optional: true,
1400             nullable: true
1401         }
1402     ]);
1403
1404     var self = this;
1405
1406     var callArgs = {
1407         filter: args.filter ? addTypeToFilter_(args.filter) : null,
1408         serviceId: self.service.id
1409     };
1410     var result = native.callSync('MessageStorageAddFolderChangeListener', callArgs);
1411     if (native.isFailure(result)) {
1412         throw native.getErrorObject(result);
1413     } else {
1414         var opId = native.getResultObject(result);
1415         FoldersChangeListeners[opId] = args.foldersChangeCallback;
1416         return opId;
1417     }
1418 };
1419
1420 MessageStorage.prototype.removeChangeListener = function() {
1421     privUtils_.deprecationWarn(
1422         'removeChangeListener() is deprecated and will be ' +
1423         'removed from next release without any alternatives. ',
1424         '8.0'
1425     );
1426     var args = validator_.validateArgs(arguments, [
1427         { name: 'watchId', type: types_.LONG }
1428     ]);
1429
1430     var self = this;
1431
1432     var callArgs = {
1433         watchId: args.watchId,
1434         serviceId: self.service.id
1435     };
1436     var result = native.callSync('MessageStorageRemoveChangeListener', callArgs);
1437     if (native.isFailure(result)) {
1438         throw native.getErrorObject(result);
1439     } else {
1440         if (MessagesChangeListeners.hasOwnProperty(args.watchId)) {
1441             delete MessagesChangeListeners[args.watchId];
1442         } else if (ConversationsChangeListeners.hasOwnProperty(args.watchId)) {
1443             delete ConversationsChangeListeners[args.watchId];
1444         } else if (FoldersChangeListeners.hasOwnProperty(args.watchId)) {
1445             delete FoldersChangeListeners[args.watchId];
1446         }
1447     }
1448 };
1449
1450 function MessageConversation(data) {
1451     propertyFactory_(this, 'id', data.id || null, Property.ENUMERABLE);
1452     propertyFactory_(this, 'type', data.type || '', Property.ENUMERABLE);
1453     propertyFactory_(
1454         this,
1455         'timestamp',
1456         data.timestamp ? new Date(data.timestamp * 1000) : null,
1457         Property.ENUMERABLE
1458     );
1459     propertyFactory_(this, 'messageCount', data.messageCount || 0, Property.ENUMERABLE);
1460     propertyFactory_(
1461         this,
1462         'unreadMessages',
1463         data.unreadMessages || 0,
1464         Property.ENUMERABLE
1465     );
1466     propertyFactory_(this, 'preview', data.preview || '', Property.ENUMERABLE);
1467     propertyFactory_(this, 'subject', data.subject || '', Property.ENUMERABLE);
1468     propertyFactory_(this, 'isRead', data.isRead || false, Property.ENUMERABLE);
1469     propertyFactory_(this, 'from', data.from || null, Property.ENUMERABLE);
1470     propertyFactory_(this, 'to', data.to || [], Property.ENUMERABLE);
1471     propertyFactory_(this, 'cc', data.cc || [], Property.ENUMERABLE);
1472     propertyFactory_(this, 'bcc', data.bcc || [], Property.ENUMERABLE);
1473     propertyFactory_(
1474         this,
1475         'lastMessageId',
1476         data.lastMessageId || null,
1477         Property.ENUMERABLE
1478     );
1479 }
1480
1481 function MessageFolder(data) {
1482     var _internal = {
1483         id: data.id || null,
1484         parentId: data.parentId || null,
1485         serviceId: data.serviceId || '',
1486         contentType: data.contentType || '',
1487         name: data.name || '',
1488         path: data.path || '',
1489         type: data.type || '',
1490         synchronizable: data.synchronizable || false
1491     };
1492
1493     Object.defineProperty(this, 'id', {
1494         get: function() {
1495             return _internal.id;
1496         },
1497         enumerable: true
1498     });
1499
1500     Object.defineProperty(this, 'parentId', {
1501         get: function() {
1502             return _internal.parentId;
1503         },
1504         enumerable: true
1505     });
1506
1507     Object.defineProperty(this, 'serviceId', {
1508         get: function() {
1509             return _internal.serviceId;
1510         },
1511         enumerable: true
1512     });
1513
1514     Object.defineProperty(this, 'contentType', {
1515         get: function() {
1516             return _internal.contentType;
1517         },
1518         enumerable: true
1519     });
1520
1521     Object.defineProperty(this, 'name', {
1522         get: function() {
1523             return _internal.name;
1524         },
1525         set: function(value) {
1526             if (value) _internal.name = value;
1527         },
1528         enumerable: true
1529     });
1530
1531     Object.defineProperty(this, 'path', {
1532         get: function() {
1533             return _internal.path;
1534         },
1535         enumerable: true
1536     });
1537
1538     Object.defineProperty(this, 'type', {
1539         get: function() {
1540             return _internal.type;
1541         },
1542         enumerable: true
1543     });
1544
1545     Object.defineProperty(this, 'synchronizable', {
1546         get: function() {
1547             return _internal.synchronizable;
1548         },
1549         set: function(value) {
1550             _internal.synchronizable = Boolean(value);
1551         },
1552         enumerable: true
1553     });
1554 }
1555
1556 tizen.Message = Message;
1557
1558 tizen.MessageAttachment = MessageAttachment;
1559
1560 exports = new Messaging();