Tizen 2.4 SDK Rev6 Release
[framework/connectivity/bluez.git] / obexd / plugins / messages-tizen.c
1 /*
2  *
3  * OBEX Server
4  *
5  * Copyright (c) 2000-2016 Samsung Electronics Co., Ltd. All rights reserved.
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License along
19  * with this program; if not, write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <errno.h>
29 #include <glib.h>
30 #include <string.h>
31 #include <stdio.h>
32 #include "log.h"
33 #include "messages.h"
34
35 #include <dbus/dbus.h>
36
37 #define QUERY_GET_FOLDER_TREE "GetFolderTree"
38 #define QUERY_GET_MSG_LIST "GetMessageList"
39 #define QUERY_GET_MESSAGE "GetMessage"
40 #define QUERY_PUSH_MESSAGE "PushMessage"
41 #define QUERY_PUSH_MESSAGE_DATA "PushMessageData"
42 #define QUERY_UPDATE_MESSAGE "UpdateMessage"
43 #define QUERY_SET_READ_STATUS "SetReadStatus"
44 #define QUERY_SET_DELETE_STATUS "SetDeleteStatus"
45 #define QUERY_NOTI_REGISTRATION "NotiRegistration"
46 #define QUERY_DESTROY_AGENT "DestroyAgent"
47
48 #define BT_MAP_SERVICE_OBJECT_PATH "/org/bluez/map_agent"
49 #define BT_MAP_SERVICE_NAME "org.bluez.map_agent"
50 #define BT_MAP_SERVICE_INTERFACE "org.bluez.MapAgent"
51
52 /* Added as per MAP specification */
53 #define BT_MAP_LIST_ITEM_MAX_LEN 256
54
55 static DBusConnection *g_conn = NULL;
56
57 struct mns_reg_data {
58         uint8_t notification_status;
59         char *remote_addr;
60 };
61
62 struct message_folder {
63         char *name;
64         GSList *subfolders;
65 };
66
67 struct session {
68         char *cwd;
69         struct message_folder *folder;
70         char *name;
71         uint16_t max;
72         uint16_t offset;
73         void *user_data;
74         struct messages_filter *filter;
75         struct messages_message *msg;
76         void (*folder_list_cb)(void *session, int err, uint16_t size,
77                                         const char *name, void *user_data);
78         void (*msg_list_cb)(void *session, int err, int size, gboolean newmsg,
79                                         const struct messages_message *entry,
80                                         void *user_data);
81         void (*push_msg_cb)(void *session, int err, guint64 handle,
82                                 void *user_data);
83         void (*get_msg_cb)(void *session, int err, gboolean fmore,
84                                 const char *chunk, void *user_data);
85         void (*msg_update_cb)(void *session, int err, void *user_data);
86         void (*msg_status_cb)(void *session, int err, void *user_data);
87 };
88
89 static struct message_folder *folder_tree = NULL;
90
91 static void message_list_item_free(struct messages_message *data)
92 {
93         DBG("+");
94         g_free(data->handle);
95         data->handle = NULL;
96
97         g_free(data->subject);
98         data->subject = NULL;
99
100         g_free(data->datetime);
101         data->datetime = NULL;
102
103         g_free(data->sender_name);
104         data->sender_name = NULL;
105
106         g_free(data->sender_addressing);
107         data->sender_addressing = NULL;
108
109         g_free(data->replyto_addressing);
110         data->replyto_addressing = NULL;
111
112         g_free(data->recipient_name);
113         data->recipient_name = NULL;
114
115         g_free(data->recipient_addressing);
116         data->recipient_addressing = NULL;
117
118         g_free(data->type);
119         data->type = NULL;
120
121         g_free(data->reception_status);
122         data->reception_status = NULL;
123
124         g_free(data->size);
125         data->size = NULL;
126
127         g_free(data->attachment_size);
128         data->attachment_size = NULL;
129         DBG("-");
130 }
131
132 static void session_filter_free(struct messages_filter *data)
133 {
134         DBG("+");
135         if (NULL == data)
136                 return;
137
138         g_free((gpointer)data->period_begin);
139         g_free((gpointer)data->period_end);
140         g_free((gpointer)data->recipient);
141         g_free((gpointer)data->originator);
142         g_free(data);
143         DBG("-");
144 }
145
146 static gboolean is_time_in_period(char *ref_time, char *period)
147 {
148         guint64 ref_date_val;
149         guint64 date_val;
150
151         guint64 ref_time_val;
152         guint64 time_val;
153
154         char *start;
155         char *end = NULL;
156
157         char temp[20];
158
159         start = strtok_r(ref_time, "T", &end);
160         if (NULL == start || NULL == end)
161                 return FALSE;
162
163         snprintf(temp, sizeof(temp), "%s", start);
164         ref_date_val = g_ascii_strtoull(temp, NULL, 16);
165         snprintf(temp, sizeof(temp), "%s", end);
166         ref_time_val = g_ascii_strtoull(temp, NULL, 16);
167
168         start = strtok_r(period, "T", &end);
169         if (NULL == start || NULL == end)
170                 return FALSE;
171
172         snprintf(temp, sizeof(temp), "%s", start);
173         date_val = g_ascii_strtoull(temp, NULL, 16);
174         snprintf(temp, sizeof(temp), "%s", end);
175         time_val = g_ascii_strtoull(temp, NULL, 16);
176
177         if (ref_date_val < date_val) {
178                 return TRUE;
179         } else if (ref_date_val > date_val) {
180                 return FALSE;
181         } else {
182                 if (ref_time_val <= time_val)
183                         return TRUE;
184                 else
185                         return FALSE;
186         }
187 }
188
189 static gboolean __filter_timebased(char *begin, char *end, char *time)
190 {
191         gboolean ret = 0;
192
193         if (!begin && !end) {
194                 /* If start and stop are not specified
195                 do not filter. */
196
197                 return TRUE;
198         } else if (!end && begin) {
199                 /* If "FilterPeriodEnd" is not specified the returned
200                 message listing shall include the messages from
201                 "FilterPeriodBegin" to current time */
202
203                 return is_time_in_period(begin, time);
204         } else if (!begin && end) {
205                 /* If "FilterPeriodBegin" is not specified the returned
206                 message listing shall include the messages older than
207                 "FilterPeriodEnd" */
208
209                 return is_time_in_period(time, end);
210         } else {
211
212                 if (TRUE == is_time_in_period(end, begin))
213                         return FALSE;
214
215                 ret = is_time_in_period(begin, time);
216                 if (ret == TRUE)
217                         return is_time_in_period(time, end);
218                 else
219                         return FALSE;
220         }
221 }
222
223 static uint8_t get_type_val(const char *type)
224 {
225         if (!g_strcmp0(type, "SMS_GSM"))
226                 return 0x01;
227         else if (!g_strcmp0(type, "SMS_CDMA"))
228                 return 0x02;
229         else if (!g_strcmp0(type, "EMAIL"))
230                 return 0x04;
231         else if (!g_strcmp0(type, "MMS"))
232                 return 0x08;
233         else
234                 return 0x00;
235 }
236
237 static uint8_t get_read_status_val(gboolean read)
238 {
239         if (read)
240                 return 0x02; /* Read messages */
241         else
242                 return 0x01; /* Unread messages */
243 }
244
245 static uint8_t get_priority_val(gboolean priority)
246 {
247         if (priority)
248                 return 0x01; /* High priority */
249         else
250                 return 0x02; /* Low priority */
251 }
252
253 static struct message_folder *get_folder(const char *folder)
254 {
255         GSList *folders = folder_tree->subfolders;
256         struct message_folder *last = NULL;
257         char **path;
258         int i;
259
260         if (g_strcmp0(folder, "/") == 0)
261                 return folder_tree;
262
263         path = g_strsplit(folder, "/", 0);
264
265         for (i = 1; path[i] != NULL; i++) {
266                 gboolean match_found = FALSE;
267                 GSList *l;
268
269                 for (l = folders; l != NULL; l = g_slist_next(l)) {
270                         struct message_folder *folder = l->data;
271
272                         if (g_ascii_strncasecmp(folder->name, path[i],
273                                         strlen(folder->name)) == 0) {
274                                 match_found = TRUE;
275                                 last = l->data;
276                                 folders = folder->subfolders;
277                                 break;
278                         }
279                 }
280
281                 if (!match_found) {
282                         g_strfreev(path);
283                         return NULL;
284                 }
285         }
286
287         g_strfreev(path);
288
289         return last;
290 }
291
292 static void destroy_folder_tree(void *root)
293 {
294         struct message_folder *folder = root;
295         GSList *tmp, *next;
296
297         if (folder == NULL)
298                 return;
299
300         g_free(folder->name);
301
302         tmp = folder->subfolders;
303         while (tmp != NULL) {
304                 next = g_slist_next(tmp);
305                 destroy_folder_tree(tmp->data);
306                 tmp = next;
307         }
308         g_slist_free(folder->subfolders);
309         g_free(folder);
310 }
311
312 static struct message_folder *create_folder(const char *name)
313 {
314         struct message_folder *folder = g_new0(struct message_folder, 1);
315
316         folder->name = g_strdup(name);
317         return folder;
318 }
319
320 static void create_folder_tree()
321 {
322
323         struct message_folder *parent, *child;
324
325         folder_tree = create_folder("/");
326
327         parent = create_folder("telecom");
328         folder_tree->subfolders = g_slist_append(folder_tree->subfolders,
329                                                                 parent);
330
331         child = create_folder("msg");
332         parent->subfolders = g_slist_append(parent->subfolders, child);
333 }
334
335 int messages_init(void)
336 {
337         g_conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
338         if (!g_conn) {
339                 error("Can't get on session bus");
340                 return -1;
341         }
342
343         return 0;
344 }
345
346 void messages_exit(void)
347 {
348         if (g_conn) {
349                 dbus_connection_unref(g_conn);
350                 g_conn = NULL;
351         }
352 }
353
354 static void message_get_folder_list(DBusMessage *reply, void *user_data)
355 {
356         DBusMessageIter iter;
357         DBusMessageIter iter_struct;
358         DBusMessageIter entry;
359         DBusError derr;
360         const char *name = NULL;
361         struct message_folder *parent = {0,}, *child = {0,};
362         GSList *l;
363
364         DBG("+\n");
365
366         for (l = folder_tree->subfolders; l != NULL; l = parent->subfolders)
367                 parent = l->data;
368
369         DBG("Last child folder = %s \n", parent->name);
370         dbus_error_init(&derr);
371
372         if (dbus_set_error_from_message(&derr, reply)) {
373                 error("Replied with an error: %s, %s", derr.name, derr.message);
374                 dbus_error_free(&derr);
375         } else {
376                 dbus_message_iter_init(reply, &iter);
377                 dbus_message_iter_recurse(&iter, &iter_struct);
378
379                 while (dbus_message_iter_get_arg_type(&iter_struct) ==
380                                                         DBUS_TYPE_STRUCT) {
381                         dbus_message_iter_recurse(&iter_struct, &entry);
382
383                         dbus_message_iter_get_basic(&entry, &name);
384                         DBG("Folder name = %s \n", name);
385                         child = create_folder(name);
386                         parent->subfolders = g_slist_append(parent->subfolders,
387                                                         child);
388                         dbus_message_iter_next(&iter_struct);
389                 }
390         }
391         dbus_message_unref(reply);
392         DBG("-\n");
393 }
394
395 static void message_get_msg_list(DBusPendingCall *call, void *user_data)
396 {
397         DBusMessage *reply = dbus_pending_call_steal_reply(call);
398         DBusMessageIter iter;
399         DBusMessageIter iter_struct;
400         DBusMessageIter entry;
401         DBusError derr;
402         const char *msg_handle;
403         const char *subject;
404         const char *datetime;
405         const char *sender_name;
406         const char *sender_addressing;
407         const char *replyto_addressing;
408         const char *recipient_name;
409         const char *recipient_addressing;
410         const char *type;
411         const char *reception_status;
412         const char *size;
413         const char *attachment_size;
414         gboolean text;
415         gboolean read;
416         gboolean sent;
417         gboolean protect;
418         gboolean priority;
419         gboolean newmessage;
420         guint64 count;
421         uint8_t type_val;
422         uint8_t read_val;
423         uint8_t priority_val;
424         uint32_t mask;
425
426         struct session *session = user_data;
427         struct messages_message *data = g_new0(struct messages_message, 1);
428
429         DBG("+\n");
430         DBG("parameter_mask = %x; type = %d; period_begin = %s;"
431                 "period_end = %s; read_status = %d; recipient = %s;"
432                 "originator = %s; priority = %d",
433                 session->filter->parameter_mask, session->filter->type,
434                 session->filter->period_begin, session->filter->period_end,
435                 session->filter->read_status, session->filter->recipient,
436                 session->filter->originator, session->filter->priority);
437
438         dbus_error_init(&derr);
439
440         if (dbus_set_error_from_message(&derr, reply)) {
441                 error("Replied with an error: %s, %s", derr.name, derr.message);
442                 dbus_error_free(&derr);
443                 session->msg_list_cb(session, -ENOENT, 0,
444                                 FALSE, data, session->user_data);
445
446                 g_free(data);
447                 g_free(session->name);
448                 session_filter_free(session->filter);
449                 dbus_message_unref(reply);
450
451                 return;
452         }
453
454         dbus_message_iter_init(reply, &iter);
455         dbus_message_iter_get_basic(&iter, &newmessage);
456         dbus_message_iter_next(&iter);
457         dbus_message_iter_get_basic(&iter, &count);
458         dbus_message_iter_next(&iter);
459
460         if (session->max == 0)
461                 goto done;
462
463         dbus_message_iter_recurse(&iter, &iter_struct);
464
465         if (session->filter->parameter_mask == 0)
466                 mask = ~session->filter->parameter_mask;
467         else
468                 mask = session->filter->parameter_mask;
469
470         while (dbus_message_iter_get_arg_type(&iter_struct) ==
471                                                 DBUS_TYPE_STRUCT) {
472                 dbus_message_iter_recurse(&iter_struct, &entry);
473                 dbus_message_iter_get_basic(&entry, &msg_handle);
474
475                 if (msg_handle == NULL) {
476                         dbus_message_iter_next(&iter_struct);
477                         continue;
478                 }
479
480                 DBG("Msg handle = %s \n", msg_handle);
481                 data->handle = g_strdup(msg_handle);
482
483                 dbus_message_iter_next(&entry);
484                 dbus_message_iter_get_basic(&entry, &subject);
485
486                 if (mask & PMASK_SUBJECT) {
487                         DBG("subject = %s\n", subject);
488                         data->subject = g_strndup(subject,
489                                                 BT_MAP_LIST_ITEM_MAX_LEN);
490                         data->mask |= PMASK_SUBJECT;
491                 }
492
493                 dbus_message_iter_next(&entry);
494                 dbus_message_iter_get_basic(&entry, &datetime);
495
496                 if ((mask & PMASK_DATETIME) && (NULL != datetime)) {
497                         DBG("datetime = %s\n", datetime);
498                         char *begin = g_strdup(session->filter->period_begin);
499                         char *end = g_strdup(session->filter->period_end);
500                         char *time = g_strdup(datetime);
501                         gboolean filter;
502
503                         filter = __filter_timebased(begin, end, time);
504
505                         g_free(begin);
506                         g_free(end);
507                         g_free(time);
508
509                         if (TRUE == filter) {
510                                 data->datetime = g_strdup(datetime);
511                                 data->mask |= PMASK_DATETIME;
512                         } else {
513                                 message_list_item_free(data);
514                                 dbus_message_iter_next(&iter_struct);
515                                 continue;
516                         }
517                 }
518
519                 dbus_message_iter_next(&entry);
520                 dbus_message_iter_get_basic(&entry, &sender_name);
521
522                 if ((mask & PMASK_SENDER_NAME) &&
523                                 (NULL != session->filter->originator)) {
524                         DBG("sender_name = %s \n", sender_name);
525
526                         if (g_strstr_len(sender_name, -1,
527                                         session->filter->originator)) {
528                                 data->sender_name = g_strndup(sender_name,
529                                                 BT_MAP_LIST_ITEM_MAX_LEN);
530                                 data->mask |= PMASK_SENDER_NAME;
531                         } else {
532                                 message_list_item_free(data);
533                                 dbus_message_iter_next(&iter_struct);
534                                 continue;
535                         }
536                 }
537
538                 dbus_message_iter_next(&entry);
539                 dbus_message_iter_get_basic(&entry, &sender_addressing);
540
541                 if ((mask & PMASK_SENDER_ADDRESSING) &&
542                                                 (NULL != sender_addressing)) {
543                         DBG("sender_addressing = %s \n", sender_addressing);
544
545                         data->sender_addressing = g_strndup(sender_addressing,
546                                                 BT_MAP_LIST_ITEM_MAX_LEN);
547                                 data->mask |= PMASK_SENDER_ADDRESSING;
548                 }
549
550                 dbus_message_iter_next(&entry);
551                 dbus_message_iter_get_basic(&entry, &recipient_name);
552
553                 if ((mask & PMASK_RECIPIENT_NAME) &&
554                                 (NULL != session->filter->recipient)) {
555                         DBG("recipient_name = %s \n", recipient_name);
556
557                         if (g_strstr_len(recipient_name, -1,
558                                         session->filter->recipient)) {
559                                 data->recipient_name =
560                                         g_strndup(recipient_name,
561                                         BT_MAP_LIST_ITEM_MAX_LEN);
562                                 data->mask |= PMASK_RECIPIENT_NAME;
563                         } else {
564                                 message_list_item_free(data);
565                                 dbus_message_iter_next(&iter_struct);
566                                 continue;
567                         }
568                 }
569
570                 dbus_message_iter_next(&entry);
571                 dbus_message_iter_get_basic(&entry, &recipient_addressing);
572
573                 if ((mask & PMASK_RECIPIENT_ADDRESSING) &&
574                                 (NULL != recipient_addressing)) {
575                         DBG("recipient_addressing=%s\n", recipient_addressing);
576
577                         data->recipient_addressing =
578                                         g_strndup(recipient_addressing,
579                                         BT_MAP_LIST_ITEM_MAX_LEN);
580                         data->mask |= PMASK_RECIPIENT_ADDRESSING;
581                 }
582
583                 dbus_message_iter_next(&entry);
584                 dbus_message_iter_get_basic(&entry, &type);
585
586                 if ((mask & PMASK_TYPE) && (NULL != type)) {
587                         DBG("type = %s \n", type);
588
589                         type_val = get_type_val(type);
590                         if (!(session->filter->type & type_val)) {
591                                 data->type = g_strdup(type);
592                                 data->mask |= PMASK_TYPE;
593                         }
594                 }
595
596                 dbus_message_iter_next(&entry);
597                 dbus_message_iter_get_basic(&entry, &size);
598
599                 if ((mask & PMASK_SIZE) && (NULL != size)) {
600                         DBG("size = %s \n", size);
601
602                         data->size = g_strdup(size);
603                         data->mask |= PMASK_SIZE;
604                 }
605
606                 dbus_message_iter_next(&entry);
607                 dbus_message_iter_get_basic(&entry, &reception_status);
608
609                 if (mask & PMASK_RECEPTION_STATUS) {
610                         DBG("reception_status = %s \n", reception_status);
611
612                         data->reception_status = g_strdup(reception_status);
613                         data->mask |= PMASK_RECEPTION_STATUS;
614                 }
615
616                 dbus_message_iter_next(&entry);
617                 dbus_message_iter_get_basic(&entry, &text);
618
619                 if (mask & PMASK_TEXT) {
620                         DBG("text = %d \n", text);
621                         data->text = text;
622                         data->mask |= PMASK_TEXT;
623                 }
624
625                 dbus_message_iter_next(&entry);
626                 dbus_message_iter_get_basic(&entry, &attachment_size);
627
628                 if (mask & PMASK_ATTACHMENT_SIZE) {
629                         DBG("attachment_size = %s\n", attachment_size);
630
631                         data->attachment_size = g_strdup(attachment_size);
632                         data->mask |= PMASK_ATTACHMENT_SIZE;
633                 }
634
635                 dbus_message_iter_next(&entry);
636                 dbus_message_iter_get_basic(&entry, &priority);
637
638                 if (mask & PMASK_PRIORITY) {
639                         DBG("priority = %d \n", priority);
640
641                         priority_val = get_priority_val(priority);
642                         if ((session->filter->priority == 0) ||
643                                 (session->filter->priority & priority_val)) {
644                                 data->priority = priority;
645                                 data->mask |= PMASK_PRIORITY;
646                         } else {
647                                 message_list_item_free(data);
648                                 dbus_message_iter_next(&iter_struct);
649                                 continue;
650                         }
651                 }
652
653                 dbus_message_iter_next(&entry);
654                 dbus_message_iter_get_basic(&entry, &read);
655
656                 if (mask & PMASK_READ) {
657                         DBG("read = %d \n", read);
658
659                         read_val = get_read_status_val(read);
660
661                         if ((session->filter->read_status == 0) ||
662                                 (session->filter->read_status & read_val)) {
663                                 data->read = read;
664                                 data->mask |= PMASK_READ;
665                         } else {
666                                 message_list_item_free(data);
667                                 dbus_message_iter_next(&iter_struct);
668                                 continue;
669                         }
670                 }
671
672                 dbus_message_iter_next(&entry);
673                 dbus_message_iter_get_basic(&entry, &sent);
674
675                 if (mask & PMASK_SENT) {
676                         DBG("sent = %d \n", sent);
677                         data->sent = sent;
678                         data->mask |= PMASK_SENT;
679                 }
680
681                 dbus_message_iter_next(&entry);
682                 dbus_message_iter_get_basic(&entry, &protect);
683
684                 if (mask & PMASK_PROTECTED) {
685                         DBG("protect = %d \n", protect);
686                         data->protect = protect;
687                         data->mask |= PMASK_PROTECTED;
688                 }
689
690                 dbus_message_iter_next(&entry);
691                 dbus_message_iter_get_basic(&entry, &replyto_addressing);
692
693                 if ((mask & PMASK_REPLYTO_ADDRESSING) &&
694                                                 (0x04 == get_type_val(type))) {
695
696                         DBG("replyto_addressing = %s \n", replyto_addressing);
697                         if (replyto_addressing)
698                                 data->replyto_addressing =
699                                                 g_strdup(replyto_addressing);
700                         else
701                                 data->replyto_addressing = g_strdup("");
702
703                         data->mask |= PMASK_REPLYTO_ADDRESSING;
704                 }
705
706                 session->msg_list_cb(session, -EAGAIN, 1, newmessage, data,
707                                                         session->user_data);
708
709                 message_list_item_free(data);
710                 dbus_message_iter_next(&iter_struct);
711         }
712
713 done:
714         session->msg_list_cb(session, 0, count, newmessage, NULL,
715                                                         session->user_data);
716
717         g_free(data);
718         g_free(session->name);
719         session_filter_free(session->filter);
720         dbus_message_unref(reply);
721         DBG("-\n");
722 }
723
724 static void message_get_msg(DBusPendingCall *call, void *user_data)
725 {
726         DBusMessage *reply = dbus_pending_call_steal_reply(call);
727         DBusMessageIter iter;
728         DBusError derr;
729         struct session *session = user_data;
730         char *msg_body;
731         gboolean fraction_deliver;
732
733         DBG("+\n");
734
735         dbus_error_init(&derr);
736         if (dbus_set_error_from_message(&derr, reply)) {
737                 error("Replied with an error: %s, %s", derr.name, derr.message);
738                 dbus_error_free(&derr);
739         } else {
740                 dbus_message_iter_init(reply, &iter);
741                 dbus_message_iter_get_basic(&iter, &fraction_deliver);
742                 dbus_message_iter_next(&iter);
743                 dbus_message_iter_get_basic(&iter, &msg_body);
744                 DBG("msg_body %s\n", msg_body);
745
746                 session->get_msg_cb(session, -EAGAIN, fraction_deliver,
747                                         msg_body, session->user_data);
748                 session->get_msg_cb(session, 0, fraction_deliver,
749                                         NULL, session->user_data);
750         }
751         dbus_message_unref(reply);
752         DBG("-\n");
753 }
754
755 int messages_connect(void **s)
756 {
757         DBusMessage *message;
758         DBusMessage *reply;
759         DBusError err;
760         DBG("+\n");
761
762         struct session *session = g_new0(struct session, 1);
763
764         create_folder_tree();
765
766         session->cwd = g_strdup("/");
767         session->folder = folder_tree;
768
769         *s = session;
770
771         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
772                                                 BT_MAP_SERVICE_OBJECT_PATH,
773                                                 BT_MAP_SERVICE_INTERFACE,
774                                                 QUERY_GET_FOLDER_TREE);
775         if (!message) {
776                 error("Can't allocate new message");
777                 return -1;
778         }
779
780         dbus_error_init(&err);
781
782         reply = dbus_connection_send_with_reply_and_block(g_conn, message,
783                                                 DBUS_TIMEOUT_USE_DEFAULT, &err);
784         if (!reply) {
785                 DBG(" Reply failed");
786                 if (dbus_error_is_set(&err)) {
787                         DBG("%s", err.message);
788                         dbus_error_free(&err);
789                 }
790
791                 dbus_message_unref(message);
792                 return -1;
793         }
794
795         message_get_folder_list(reply, session);
796
797         dbus_message_unref(message);
798         DBG("-\n");
799         return 0;
800 }
801
802 void messages_disconnect(void *s)
803 {
804         DBusMessage *message;
805         struct session *session = s;
806         DBG("+\n");
807
808         destroy_folder_tree(folder_tree);
809         folder_tree = NULL;
810         g_free(session->cwd);
811         g_free(session);
812
813         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
814                                                 BT_MAP_SERVICE_OBJECT_PATH,
815                                                 BT_MAP_SERVICE_INTERFACE,
816                                                 QUERY_DESTROY_AGENT);
817
818         if (!message) {
819                 error("Can't allocate new message");
820                 return;
821         }
822
823         if (dbus_connection_send(g_conn, message, NULL) == FALSE)
824                 error("Could not send dbus message");
825
826         dbus_message_unref(message);
827
828         DBG("-\n");
829 }
830
831 static gboolean notification_registration(gpointer user_data)
832 {
833         DBG("+\n");
834         DBusMessage *message = NULL;
835         gboolean reg;
836         struct mns_reg_data *data = (struct mns_reg_data *)user_data;
837
838         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
839                                         BT_MAP_SERVICE_OBJECT_PATH,
840                                         BT_MAP_SERVICE_INTERFACE,
841                                         QUERY_NOTI_REGISTRATION);
842         if (!message) {
843                 error("Can't allocate new message");
844                 goto done;
845         }
846
847         DBG("data->notification_status = %d\n", data->notification_status);
848
849         if (data->notification_status == 1)
850                 reg = TRUE;
851         else
852                 reg = FALSE;
853
854         dbus_message_append_args(message, DBUS_TYPE_STRING, &data->remote_addr,
855                                                 DBUS_TYPE_BOOLEAN, &reg,
856                                                 DBUS_TYPE_INVALID);
857
858         if (dbus_connection_send(g_conn, message, NULL) == FALSE)
859                 error("Could not send dbus message");
860
861         dbus_message_unref(message);
862
863 done:
864         g_free(data->remote_addr);
865         g_free(data);
866
867         DBG("-\n");
868         return FALSE;
869 }
870
871 int messages_set_notification_registration(void *session,
872                                 char *address, uint8_t status,
873                                 void *user_data)
874 {
875         DBG("+\n");
876         struct mns_reg_data *data = g_new0(struct mns_reg_data, 1);
877         data->notification_status = status;
878         data->remote_addr = g_strdup(address);
879
880         DBG("status = %d\n", status);
881
882         g_idle_add(notification_registration, data);
883         DBG("-\n");
884         return 1;
885 }
886
887 int messages_set_folder(void *s, const char *name, gboolean cdup)
888 {
889         struct session *session = s;
890         char *newrel = NULL;
891         char *newabs;
892         char *tmp;
893
894         if (name && (strchr(name, '/') || strcmp(name, "..") == 0))
895                 return -EBADR;
896
897         if (cdup) {
898                 if (session->cwd[0] == 0)
899                         return -ENOENT;
900
901                 newrel = g_path_get_dirname(session->cwd);
902
903                 /* We use empty string for indication of the root directory */
904                 if (newrel[0] == '.' && newrel[1] == 0)
905                         newrel[0] = 0;
906         }
907
908         tmp = newrel;
909         if (!cdup && (!name || name[0] == 0))
910                 newrel = g_strdup("");
911         else
912                 newrel = g_build_filename(newrel ? newrel : session->cwd, name,
913                                                                         NULL);
914         g_free(tmp);
915
916         if (newrel[0] != '/')
917                 newabs = g_build_filename("/", newrel, NULL);
918         else
919                 newabs = g_strdup(newrel);
920
921         session->folder = get_folder(newabs);
922         if (session->folder == NULL) {
923                 g_free(newrel);
924                 g_free(newabs);
925
926                 return -ENOENT;
927         }
928
929         g_free(newrel);
930         g_free(session->cwd);
931         session->cwd = newabs;
932
933         return 0;
934 }
935
936 static gboolean async_get_folder_listing(void *s)
937 {
938         struct session *session = s;
939         int i;
940         uint16_t folder_list_size = 0;
941         char *path = NULL;
942         struct message_folder *folder;
943         GSList *dir;
944
945         if (session->name && strchr(session->name, '/') != NULL)
946                 goto done;
947
948         path = g_build_filename(session->cwd, session->name, NULL);
949
950         if (path == NULL || strlen(path) == 0)
951                 goto done;
952
953         folder = get_folder(path);
954
955         if (folder == NULL)
956                 goto done;
957
958         if (session->max == 0) {
959                 folder_list_size = g_slist_length(folder->subfolders);
960                 goto done;
961         }
962
963         dir = folder->subfolders;
964
965         /* move to offset */
966         for (i = 0; i < session->offset; i++) {
967                 if (dir == NULL)
968                         goto done;
969
970                 dir = g_slist_next(dir);
971         }
972
973         for (i = 0; i < session->max; i++) {
974                 struct message_folder *dir_data;
975
976                 if (dir == NULL)
977                         goto done;
978
979                 dir_data = dir->data;
980                 session->folder_list_cb(session, -EAGAIN, 0,
981                                 dir_data->name, session->user_data);
982
983                 dir = g_slist_next(dir);
984         }
985
986  done:
987         session->folder_list_cb(session, 0, folder_list_size,
988                         NULL, session->user_data);
989
990         g_free(path);
991         g_free(session->name);
992
993         return FALSE;
994 }
995
996 int messages_get_folder_listing(void *s, const char *name,
997                                         uint16_t max, uint16_t offset,
998                                         messages_folder_listing_cb callback,
999                                         void *user_data)
1000 {
1001         DBG("+\n");
1002         struct session *session = s;
1003         session->name = g_strdup(name);
1004         session->max = max;
1005         session->offset = offset;
1006         session->folder_list_cb = callback;
1007         session->user_data = user_data;
1008
1009         g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, async_get_folder_listing,
1010                                                 session, NULL);
1011
1012         DBG("-\n");
1013         return 0;
1014 }
1015
1016 int messages_get_messages_listing(void *session, const char *name,
1017                                 uint16_t max, uint16_t offset,
1018                                 uint8_t subject_len,
1019                                 const struct messages_filter *filter,
1020                                 messages_get_messages_listing_cb callback,
1021                                 void *user_data)
1022 {
1023         DBusPendingCall *call;
1024         DBusMessage *message;
1025         struct session *s = session;
1026
1027         if (name != NULL && strlen(name))
1028                 s->name = g_strdup(name);
1029         else
1030                 s->name = g_strdup(s->cwd);
1031
1032         s->max = max;
1033         s->offset = offset;
1034
1035         s->filter = g_new0(struct messages_filter, 1);
1036         s->filter->parameter_mask = filter->parameter_mask;
1037         s->filter->type = filter->type;
1038         s->filter->period_begin = g_strdup(filter->period_begin);
1039         s->filter->period_end = g_strdup(filter->period_end);
1040         s->filter->read_status = filter->read_status;
1041         s->filter->recipient = g_strdup(filter->recipient);
1042         s->filter->originator = g_strdup(filter->originator);
1043         s->filter->priority = filter->priority;
1044
1045         s->msg_list_cb = (void *)callback;
1046         s->user_data = user_data;
1047
1048         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
1049                                                 BT_MAP_SERVICE_OBJECT_PATH,
1050                                                 BT_MAP_SERVICE_INTERFACE,
1051                                                 QUERY_GET_MSG_LIST);
1052         if (!message) {
1053                 error("Can't allocate new message");
1054                 g_free(s->name);
1055                 session_filter_free(s->filter);
1056                 return -1;
1057         }
1058
1059         dbus_message_append_args(message, DBUS_TYPE_STRING, &s->name,
1060                                                 DBUS_TYPE_UINT16, &s->max,
1061                                                 DBUS_TYPE_INVALID);
1062
1063         if (dbus_connection_send_with_reply(g_conn, message, &call,
1064                                         DBUS_TIMEOUT_INFINITE) == FALSE) {
1065                 error("Could not send dbus message");
1066                 dbus_message_unref(message);
1067                 g_free(s->name);
1068                 session_filter_free(s->filter);
1069                 return -1;
1070         }
1071         dbus_pending_call_set_notify(call, message_get_msg_list, s, NULL);
1072         dbus_message_unref(message);
1073         DBG("-\n");
1074         return 1;
1075 }
1076
1077 int messages_push_message(void *session, const char *folder,
1078                                         uint8_t transparent, uint8_t retry,
1079                                         uint8_t charset,
1080                                         messages_push_message_cb callback,
1081                                         void *user_data)
1082 {
1083         DBusMessage *message;
1084         DBusMessage *reply;
1085         DBusError err;
1086         struct session *s = session;
1087
1088         gboolean save_copy = FALSE;  /* As per specs default value */
1089         gboolean retry_send = TRUE; /* As per specs default value */
1090         gboolean native = FALSE;
1091         gchar *folder_path = NULL;
1092         guint64 handle = 0;
1093
1094         DBG("+\n");
1095
1096         DBG("session->cwd %s +\n", s->cwd);
1097
1098         if (folder)
1099                 folder_path = g_strdup(folder);
1100         else
1101                 folder_path = g_strdup(s->cwd);
1102
1103         s->push_msg_cb = callback;
1104         s->user_data = user_data;
1105
1106         if (transparent & 0x1)
1107                 save_copy = TRUE;
1108
1109         if (!(retry & 0x1)) {
1110                 retry_send = FALSE;
1111                 DBG("Retry send %d\n", retry_send);
1112         }
1113
1114         if (charset & 0x1) {
1115                 native = TRUE;
1116                 DBG("native send %d\n", native);
1117         }
1118
1119         DBG("save_copy  %d\n", save_copy);
1120         DBG("retry_send %d\n", retry_send);
1121         DBG("native %d\n", native);
1122
1123         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
1124                                                 BT_MAP_SERVICE_OBJECT_PATH,
1125                                                 BT_MAP_SERVICE_INTERFACE,
1126                                                 QUERY_PUSH_MESSAGE);
1127         if (!message) {
1128                 error("Can't allocate new message");
1129                 g_free(folder_path);
1130                 return -1;
1131         }
1132
1133         dbus_message_append_args(message, DBUS_TYPE_BOOLEAN, &save_copy,
1134                                                 DBUS_TYPE_BOOLEAN, &retry_send,
1135                                                 DBUS_TYPE_BOOLEAN, &native,
1136                                                 DBUS_TYPE_STRING, &folder_path,
1137                                                 DBUS_TYPE_INVALID);
1138
1139         dbus_error_init(&err);
1140
1141         reply = dbus_connection_send_with_reply_and_block(
1142                                         g_conn, message,
1143                                         DBUS_TIMEOUT_USE_DEFAULT, &err);
1144         if (!reply) {
1145                 DBG(" Reply failed");
1146
1147                 if (dbus_error_is_set(&err)) {
1148                         DBG("%s", err.message);
1149                         dbus_error_free(&err);
1150                 }
1151                 g_free(folder_path);
1152                 dbus_message_unref(message);
1153                 return -1;
1154         }
1155
1156         if (!dbus_message_get_args(reply, &err, DBUS_TYPE_UINT64,
1157                                                 &handle, DBUS_TYPE_INVALID)) {
1158                 if (dbus_error_is_set(&err)) {
1159                         error("err %s\n", err.message);
1160                         dbus_error_free(&err);
1161                 }
1162                 g_free(folder_path);
1163                 dbus_message_unref(message);
1164                 dbus_message_unref(reply);
1165                 return -1;
1166         }
1167
1168         DBG("uint64 handle %"G_GUINT64_FORMAT"\n", handle);
1169         s->push_msg_cb(s, 0, handle, s->user_data);
1170
1171         g_free(folder_path);
1172         dbus_message_unref(message);
1173         dbus_message_unref(reply);
1174
1175         DBG("-\n");
1176         return 1;
1177 }
1178
1179 int messages_push_message_data(void *session, const char *bmsg, void *user_data)
1180 {
1181         DBusMessage *message;
1182
1183         DBG("+\n");
1184
1185         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
1186                                                 BT_MAP_SERVICE_OBJECT_PATH,
1187                                                 BT_MAP_SERVICE_INTERFACE,
1188                                                 QUERY_PUSH_MESSAGE_DATA);
1189         if (!message) {
1190                 error("Can't allocate new message");
1191                 return -1;
1192         }
1193
1194         dbus_message_append_args(message, DBUS_TYPE_STRING, &bmsg,
1195                                                         DBUS_TYPE_INVALID);
1196
1197         if (dbus_connection_send(g_conn, message, NULL) == FALSE) {
1198                 error("Could not send dbus message");
1199                 dbus_message_unref(message);
1200                 return -1;
1201         }
1202
1203         dbus_message_unref(message);
1204         DBG("-\n");
1205         return 1;
1206 }
1207
1208 int messages_get_message(void *session,
1209                                         const char *handle,
1210                                         uint8_t attachment, uint8_t charset,
1211                                         uint8_t fraction_request,
1212                                         messages_get_message_cb callback,
1213                                         void *user_data)
1214 {
1215         DBusPendingCall *call;
1216         DBusMessage *message;
1217         struct session *s = session;
1218         char *message_name;
1219         gboolean attach = FALSE;
1220         gboolean transcode = FALSE;
1221         gboolean first_request = TRUE;
1222
1223         DBG("+\n");
1224
1225         if (NULL != handle) {
1226                 message_name =  g_strdup(handle);
1227                 DBG("Message handle = %s\n", handle);
1228         } else {
1229                 return -1;
1230         }
1231         s->get_msg_cb = callback;
1232         s->user_data = user_data;
1233
1234         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
1235                                                 BT_MAP_SERVICE_OBJECT_PATH,
1236                                                 BT_MAP_SERVICE_INTERFACE,
1237                                                 QUERY_GET_MESSAGE);
1238         if (!message) {
1239                 error("Can't allocate new message");
1240                 g_free(message_name);
1241                 return -1;
1242         }
1243
1244         if (attachment & 0x1)
1245                 attach = TRUE;
1246
1247         if (charset & 0x1)
1248                 transcode = TRUE;
1249
1250         if (fraction_request & 0x1)
1251                 first_request = FALSE;
1252
1253         dbus_message_append_args(message, DBUS_TYPE_STRING, &message_name,
1254                                         DBUS_TYPE_BOOLEAN, &attach,
1255                                         DBUS_TYPE_BOOLEAN, &transcode,
1256                                         DBUS_TYPE_BOOLEAN, &first_request,
1257                                         DBUS_TYPE_INVALID);
1258
1259         if (dbus_connection_send_with_reply(g_conn, message, &call, -1) ==
1260                                         FALSE) {
1261                 error("Could not send dbus message");
1262                 dbus_message_unref(message);
1263                 g_free(message_name);
1264                 return -1;
1265         }
1266         dbus_pending_call_set_notify(call, message_get_msg, s, NULL);
1267         dbus_message_unref(message);
1268         g_free(message_name);
1269         DBG("-\n");
1270         return 1;
1271 }
1272
1273 #ifndef SUPPORT_SMS_ONLY
1274 static void message_update_msg(DBusPendingCall *call, void *user_data)
1275 {
1276         DBusMessage *reply = dbus_pending_call_steal_reply(call);
1277         DBusMessageIter iter;
1278         DBusError derr;
1279         struct session *session = user_data;
1280         int err;
1281         DBG("+\n");
1282
1283         dbus_error_init(&derr);
1284         if (dbus_set_error_from_message(&derr, reply)) {
1285                 error("Replied with an error: %s, %s", derr.name, derr.message);
1286                 dbus_error_free(&derr);
1287         } else {
1288                 dbus_message_iter_init(reply, &iter);
1289                 if (dbus_message_iter_get_arg_type(&iter) ==
1290                                                         DBUS_TYPE_INT32) {
1291                         dbus_message_iter_get_basic(&iter, &err);
1292                         DBG("Error : %d\n", err);
1293                         session->msg_update_cb(session, err,
1294                                                 session->user_data);
1295                 }
1296         }
1297         dbus_message_unref(reply);
1298         DBG("-\n");
1299 }
1300 #endif
1301
1302 int messages_update_inbox(void *session,
1303                                         messages_status_cb callback,
1304                                         void *user_data)
1305 {
1306 #ifdef SUPPORT_SMS_ONLY
1307         /* MAP.TS.1.0.3 : TP/MMB/BV-16-I
1308            Currently support is only for SMS, Since SMS service does not
1309            allow the polling of its mailbox, it must return Not implemented */
1310
1311         return -ENOSYS;
1312 #else
1313         DBusPendingCall *call;
1314         DBusMessage *message;
1315         struct session *s = session;
1316
1317         DBG("+\n");
1318
1319         s->msg_update_cb = callback;
1320         s->user_data = user_data;
1321
1322         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
1323                                                 BT_MAP_SERVICE_OBJECT_PATH,
1324                                                 BT_MAP_SERVICE_INTERFACE,
1325                                                 QUERY_UPDATE_MESSAGE);
1326         if (!message) {
1327                 error("Can't allocate new message");
1328                 return -1;
1329         }
1330
1331         if (dbus_connection_send_with_reply(g_conn, message, &call, -1) ==
1332                                         FALSE) {
1333                 error("Could not send dbus message");
1334                 dbus_message_unref(message);
1335                 return -1;
1336         }
1337         dbus_pending_call_set_notify(call, message_update_msg, s, NULL);
1338         dbus_message_unref(message);
1339         DBG("-\n");
1340         return 1;
1341 #endif
1342 }
1343
1344 static void message_status_msg(DBusPendingCall *call, void *user_data)
1345 {
1346         DBusMessage *reply = dbus_pending_call_steal_reply(call);
1347         DBusMessageIter iter;
1348         DBusError derr;
1349         struct session *session = user_data;
1350         int err;
1351
1352         DBG("+\n");
1353
1354         dbus_error_init(&derr);
1355         if (dbus_set_error_from_message(&derr, reply)) {
1356                 error("Replied with an error: %s, %s", derr.name, derr.message);
1357                 dbus_error_free(&derr);
1358         } else {
1359                 dbus_message_iter_init(reply, &iter);
1360                 if (dbus_message_iter_get_arg_type(&iter) ==
1361                                                         DBUS_TYPE_INT32) {
1362                         dbus_message_iter_get_basic(&iter, &err);
1363                         DBG("Error : %d\n", err);
1364                         session->msg_status_cb(session, err,
1365                                                 session->user_data);
1366                 }
1367         }
1368         dbus_message_unref(reply);
1369         DBG("-\n");
1370 }
1371
1372 int messages_set_read(void *session, const char *handle, uint8_t value,
1373                 messages_status_cb callback, void *user_data)
1374 {
1375         DBusPendingCall *call;
1376         DBusMessage *message;
1377         struct session *s = session;
1378         char *message_name;
1379         gboolean read;
1380
1381         DBG("+\n");
1382
1383         if (NULL == handle)
1384                 return -1;
1385
1386         DBG("Message handle = %s\n", handle);
1387         message_name = g_strdup(handle);
1388
1389         s->msg_status_cb = callback;
1390         s->user_data = user_data;
1391
1392         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
1393                                                 BT_MAP_SERVICE_OBJECT_PATH,
1394                                                 BT_MAP_SERVICE_INTERFACE,
1395                                                 QUERY_SET_READ_STATUS);
1396         if (!message) {
1397                 error("Can't allocate new message");
1398                 g_free(message_name);
1399                 return -1;
1400         }
1401
1402         read = value ? TRUE : FALSE;
1403
1404         dbus_message_append_args(message, DBUS_TYPE_STRING, &message_name,
1405                                                 DBUS_TYPE_BOOLEAN, &read,
1406                                                 DBUS_TYPE_INVALID);
1407
1408         if (dbus_connection_send_with_reply(g_conn, message, &call, -1) ==
1409                                         FALSE) {
1410                 error("Could not send dbus message");
1411                 g_free(message_name);
1412                 dbus_message_unref(message);
1413                 return -1;
1414         }
1415
1416         dbus_pending_call_set_notify(call, message_status_msg, s, NULL);
1417         dbus_message_unref(message);
1418         g_free(message_name);
1419         DBG("-\n");
1420         return 1;
1421 }
1422
1423 int messages_set_delete(void *session, const char *handle,
1424                                         uint8_t value,
1425                                         messages_status_cb callback,
1426                                         void *user_data)
1427 {
1428         DBusPendingCall *call;
1429         DBusMessage *message;
1430         struct session *s = session;
1431         char *message_name;
1432         gboolean del;
1433
1434         DBG("+\n");
1435
1436         if (NULL == handle)
1437                 return -1;
1438
1439         DBG("Message handle = %s\n", handle);
1440         message_name = g_strdup(handle);
1441
1442         s->msg_status_cb = callback;
1443         s->user_data = user_data;
1444
1445         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
1446                                                 BT_MAP_SERVICE_OBJECT_PATH,
1447                                                 BT_MAP_SERVICE_INTERFACE,
1448                                                 QUERY_SET_DELETE_STATUS);
1449         if (!message) {
1450                 error("Can't allocate new message");
1451                 g_free(message_name);
1452                 return -1;
1453         }
1454
1455         del = value ? TRUE : FALSE;
1456
1457         dbus_message_append_args(message, DBUS_TYPE_STRING, &message_name,
1458                                                 DBUS_TYPE_BOOLEAN, &del,
1459                                                 DBUS_TYPE_INVALID);
1460
1461         if (dbus_connection_send_with_reply(g_conn, message, &call, -1) ==
1462                                         FALSE) {
1463                 error("Could not send dbus message");
1464                 g_free(message_name);
1465                 dbus_message_unref(message);
1466                 return -1;
1467         }
1468
1469         dbus_pending_call_set_notify(call, message_status_msg, s, NULL);
1470         dbus_message_unref(message);
1471         g_free(message_name);
1472         DBG("-\n");
1473         return 1;
1474 }
1475
1476 void messages_abort(void *session)
1477 {
1478 }