upload tizen1.0 source
[profile/ivi/obexd.git] / plugins / messages-tizen.c
1 /*
2  *
3  *  OBEX Server
4  *
5  *  Copyright (C) 2009-2010  Intel Corporation
6  *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
7  *
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License as published by
11  *  the Free Software Foundation; either version 2 of the License, or
12  *  (at your option) any later version.
13  *
14  *  This program is distributed in the hope that it will be useful,
15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *  GNU General Public License for more details.
18  *
19  *  You should have received a copy of the GNU General Public License
20  *  along with this program; if not, write to the Free Software
21  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
22  *
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #include <errno.h>
30 #include <glib.h>
31 #include <string.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_UPDATE_MESSAGE "UpdateMessage"
41 #define QUERY_MESSAGE_STATUS "MessageStatus"
42
43 #define BT_MAP_SERVICE_OBJECT_PATH "/org/bluez/map_agent"
44 #define BT_MAP_SERVICE_NAME "org.bluez.map_agent"
45 #define BT_MAP_SERVICE_INTERFACE "org.bluez.MapAgent"
46
47 struct message_folder {
48         char *name;
49         GSList *subfolders;
50 };
51
52 struct session {
53         char *cwd;
54         struct message_folder *folder;
55         char *name;
56         uint16_t max;
57         uint16_t offset;
58         void *user_data;
59         void (*folder_list_cb)(void *session, int err, uint16_t size,
60                                         const char *name, void *user_data);
61         struct messages_message *msg;
62         const struct messages_filter *filter;
63         void (*msg_list_cb)(void *session, int err, int size, gboolean newmsg,
64                                 const struct messages_message *entry,
65                                 void *user_data);
66         void (*get_msg_cb)(void *session, int err, gboolean fmore,
67                                 const char *chunk, void *user_data);
68         void (*msg_update_cb)(void *session, int err, void *user_data);
69         void (*msg_status_cb)(void *session, int err, void *user_data);
70 };
71
72 static struct message_folder *folder_tree = NULL;
73
74 static struct message_folder *get_folder(const char *folder)
75 {
76         GSList *folders = folder_tree->subfolders;
77         struct message_folder *last = NULL;
78         char **path;
79         int i;
80
81         if (g_strcmp0(folder, "/") == 0)
82                 return folder_tree;
83
84         path = g_strsplit(folder, "/", 0);
85
86         for (i = 1; path[i] != NULL; i++) {
87                 gboolean match_found = FALSE;
88                 GSList *l;
89
90                 for (l = folders; l != NULL; l = g_slist_next(l)) {
91                         struct message_folder *folder = l->data;
92
93                         if (g_ascii_strncasecmp(folder->name, path[i],
94                                         strlen(folder->name)) == 0) {
95                                 match_found = TRUE;
96                                 last = l->data;
97                                 folders = folder->subfolders;
98                                 break;
99                         }
100                 }
101
102                 if (!match_found) {
103                         g_strfreev(path);
104                         return NULL;
105                 }
106         }
107
108         g_strfreev(path);
109
110         return last;
111 }
112
113 static void destroy_folder_tree(void *root)
114 {
115         struct message_folder *folder = root;
116         GSList *tmp, *next;
117
118         if (folder == NULL)
119                 return;
120
121         g_free(folder->name);
122
123         tmp = folder->subfolders;
124         while (tmp != NULL) {
125                 next = g_slist_next(tmp);
126                 destroy_folder_tree(tmp->data);
127                 tmp = next;
128         }
129         g_slist_free(folder->subfolders);
130         g_free(folder);
131 }
132
133 static struct message_folder *create_folder(const char *name)
134 {
135         struct message_folder *folder = g_new0(struct message_folder, 1);
136
137         folder->name = g_strdup(name);
138         return folder;
139 }
140
141 static void create_folder_tree()
142 {
143
144         struct message_folder *parent, *child;
145
146         folder_tree = create_folder("/");
147
148         parent = create_folder("telecom");
149         folder_tree->subfolders = g_slist_append(folder_tree->subfolders,
150                                                                 parent);
151
152         child = create_folder("msg");
153         parent->subfolders = g_slist_append(parent->subfolders, child);
154 }
155
156 int messages_init(void)
157 {
158         create_folder_tree();
159         return 0;
160 }
161
162 void messages_exit(void)
163 {
164         destroy_folder_tree(folder_tree);
165 }
166
167 static void message_get_folder_list(DBusPendingCall *call, void *user_data)
168 {
169         DBusMessage *reply = dbus_pending_call_steal_reply(call);
170         DBusMessageIter iter;
171         DBusMessageIter iter_struct;
172         DBusMessageIter entry;
173         DBusError derr;
174         const char *name = NULL;
175         struct message_folder *parent = {0,}, *child = {0,};
176         GSList *l;
177
178         DBG("message_get_folder_list \n");
179
180         for (l = folder_tree->subfolders; l != NULL; l = parent->subfolders)
181                 parent = l->data;
182
183         DBG("Last child folder = %s \n", parent->name);
184         dbus_error_init(&derr);
185
186         if (dbus_set_error_from_message(&derr, reply)) {
187                 error("Replied with an error: %s, %s", derr.name, derr.message);
188                 dbus_error_free(&derr);
189         } else {
190                 dbus_message_iter_init(reply, &iter);
191                 dbus_message_iter_recurse(&iter, &iter_struct);
192
193                 while (dbus_message_iter_get_arg_type(&iter_struct) ==
194                                                         DBUS_TYPE_STRUCT) {
195                         dbus_message_iter_recurse(&iter_struct, &entry);
196
197                         dbus_message_iter_get_basic(&entry, &name);
198                         DBG("Folder name = %s \n", name);
199                         child = create_folder(name);
200                         parent->subfolders = g_slist_append(parent->subfolders,
201                                                         child);
202                         dbus_message_iter_next(&iter_struct);
203                 }
204         }
205         dbus_message_unref(reply);
206 }
207
208 static void message_get_msg_list(DBusPendingCall *call, void *user_data)
209 {
210         DBusMessage *reply = dbus_pending_call_steal_reply(call);
211         DBusMessageIter iter;
212         DBusMessageIter iter_struct;
213         DBusMessageIter entry;
214         DBusError derr;
215         const char *msg_handle;
216         const char *msg_type;
217         const char *msg_time;
218         struct session *session = user_data;
219         struct messages_message *data = g_new0(struct messages_message, 1);
220
221         DBG("message_get_msg_list \n");
222
223         dbus_error_init(&derr);
224
225         if (dbus_set_error_from_message(&derr, reply)) {
226                 error("Replied with an error: %s, %s", derr.name, derr.message);
227                 dbus_error_free(&derr);
228         } else {
229                 dbus_message_iter_init(reply, &iter);
230                 dbus_message_iter_recurse(&iter, &iter_struct);
231
232                 while (dbus_message_iter_get_arg_type(&iter_struct) ==
233                                                         DBUS_TYPE_STRUCT) {
234                         dbus_message_iter_recurse(&iter_struct, &entry);
235                         dbus_message_iter_get_basic(&entry, &msg_handle);
236                         DBG("Msg handle = %s \n", msg_handle);
237                         data->handle = g_strdup(msg_handle);
238                         dbus_message_iter_next(&entry);
239                         dbus_message_iter_get_basic(&entry, &msg_type);
240                         DBG("Msg Type = %s \n", msg_type);
241                         data->mask |= PMASK_TYPE;
242                         data->type = g_strdup(msg_type);
243                         dbus_message_iter_next(&entry);
244                         dbus_message_iter_get_basic(&entry, &msg_time);
245                         DBG("Msg date & time = %s \n", msg_time);
246                         data->mask |= PMASK_DATETIME;
247                         data->datetime = g_strdup(msg_time);
248
249                         session->msg_list_cb(session, -EAGAIN, 1,
250                                         TRUE,
251                                         data,
252                                         session->user_data);
253                         dbus_message_iter_next(&iter_struct);
254                 }
255                 session->msg_list_cb(session, 0, 0,
256                                         FALSE,
257                                         NULL,
258                                         session->user_data);
259         }
260         dbus_message_unref(reply);
261 }
262
263 static void message_get_msg(DBusPendingCall *call, void *user_data)
264 {
265         DBusMessage *reply = dbus_pending_call_steal_reply(call);
266         DBusMessageIter iter;
267         DBusMessageIter iter_struct;
268         DBusMessageIter entry;
269         DBusError derr;
270         struct session *session = user_data;
271         char *msg_body;
272
273         DBG("message_get_msg \n");
274
275         dbus_error_init(&derr);
276         if (dbus_set_error_from_message(&derr, reply)) {
277                 error("Replied with an error: %s, %s", derr.name, derr.message);
278                 dbus_error_free(&derr);
279         } else {
280                 dbus_message_iter_init(reply, &iter);
281                 dbus_message_iter_recurse(&iter, &iter_struct);
282
283                 if (dbus_message_iter_get_arg_type(&iter_struct) ==
284                                                         DBUS_TYPE_STRUCT) {
285                         dbus_message_iter_recurse(&iter_struct, &entry);
286                         dbus_message_iter_get_basic(&entry, &msg_body);
287                         DBG("Msg handle = %s \n", msg_body);
288                 }
289                 session->get_msg_cb(session, -EAGAIN, FALSE,
290                                         msg_body, session->user_data);
291                 session->get_msg_cb(session, 0, FALSE,
292                                         NULL, session->user_data);
293         }
294         dbus_message_unref(reply);
295 }
296
297 int messages_connect(void **s)
298 {
299         struct session *session = g_new0(struct session, 1);
300
301         session->cwd = g_strdup("/");
302         session->folder = folder_tree;
303
304         *s = session;
305
306         DBusConnection *conn;
307         DBusPendingCall *call;
308         DBusMessage *message;
309
310
311         conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
312         if (!conn) {
313                 error("Can't get on session bus");
314                 return -1;
315         }
316
317         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
318                                                 BT_MAP_SERVICE_OBJECT_PATH,
319                                                 BT_MAP_SERVICE_INTERFACE,
320                                                 QUERY_GET_FOLDER_TREE);
321         if (!message) {
322                 error("Can't allocate new message");
323                 dbus_connection_unref(conn);
324                 return -1;
325         }
326
327         if (dbus_connection_send_with_reply(conn, message, &call, -1) ==
328                         FALSE) {
329                 error("Could not send dbus message");
330                 dbus_message_unref(message);
331                 dbus_connection_unref(conn);
332                 return -1;
333         }
334
335         dbus_pending_call_set_notify(call, message_get_folder_list, session,
336                                                 NULL);
337         dbus_message_unref(message);
338         dbus_connection_unref(conn);
339         return 0;
340 }
341
342 void messages_disconnect(void *s)
343 {
344         struct session *session = s;
345
346         g_free(session->cwd);
347         g_free(session);
348 }
349
350 int messages_set_notification_registration(void *session,
351                 void (*send_event)(void *session,
352                         const struct messages_event *event, void *user_data),
353                 void *user_data)
354 {
355         return -EINVAL;
356 }
357
358 int messages_set_folder(void *s, const char *name, gboolean cdup)
359 {
360         struct session *session = s;
361         char *newrel = NULL;
362         char *newabs;
363         char *tmp;
364
365         if (name && (strchr(name, '/') || strcmp(name, "..") == 0))
366                 return -EBADR;
367
368         if (cdup) {
369                 if (session->cwd[0] == 0)
370                         return -ENOENT;
371
372                 newrel = g_path_get_dirname(session->cwd);
373
374                 /* We use empty string for indication of the root directory */
375                 if (newrel[0] == '.' && newrel[1] == 0)
376                         newrel[0] = 0;
377         }
378
379         tmp = newrel;
380         if (!cdup && (!name || name[0] == 0))
381                 newrel = g_strdup("");
382         else
383                 newrel = g_build_filename(newrel ? newrel : session->cwd, name,
384                                                                         NULL);
385         g_free(tmp);
386
387         if (newrel[0] != '/')
388                 newabs = g_build_filename("/", newrel, NULL);
389         else
390                 newabs = g_strdup(newrel);
391
392         session->folder = get_folder(newabs);
393         if (session->folder == NULL) {
394                 g_free(newrel);
395                 g_free(newabs);
396
397                 return -ENOENT;
398         }
399
400         g_free(newrel);
401         g_free(session->cwd);
402         session->cwd = newabs;
403
404         return 0;
405 }
406
407 static gboolean async_get_folder_listing(void *s)
408 {
409         struct session *session = s;
410         gboolean count = FALSE;
411         int folder_count = 0;
412         char *path = NULL;
413         struct message_folder *folder;
414         GSList *dir;
415
416         if (session->name && strchr(session->name, '/') != NULL)
417                 goto done;
418
419         path = g_build_filename(session->cwd, session->name, NULL);
420
421         if (path == NULL || strlen(path) == 0)
422                 goto done;
423
424         folder = get_folder(path);
425
426         if (folder == NULL)
427                 goto done;
428
429         if (session->max == 0) {
430                 session->max = 0xffff;
431                 session->offset = 0;
432                 count = TRUE;
433         }
434
435         for (dir = folder->subfolders; dir &&
436                                 (folder_count - session->offset) < session->max;
437                                 folder_count++, dir = g_slist_next(dir)) {
438                 struct message_folder *dir_data = dir->data;
439
440                 if (count == FALSE && session->offset <= folder_count)
441                         session->folder_list_cb(session, -EAGAIN, 0,
442                                         dir_data->name, session->user_data);
443         }
444
445  done:
446         session->folder_list_cb(session, 0, folder_count, NULL,
447                                                         session->user_data);
448
449         g_free(path);
450         g_free(session->name);
451
452         return FALSE;
453 }
454
455 int messages_get_folder_listing(void *s, const char *name,
456                                         uint16_t max, uint16_t offset,
457                                         messages_folder_listing_cb callback,
458                                         void *user_data)
459 {
460         struct session *session = s;
461         session->name = g_strdup(name);
462         session->max = max;
463         session->offset = offset;
464         session->folder_list_cb = callback;
465         session->user_data = user_data;
466
467         g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, async_get_folder_listing,
468                                                 session, NULL);
469
470         return 0;
471 }
472
473 int messages_get_messages_listing(void *data,
474                                 const char *name,
475                                 uint16_t max, uint16_t offset,
476                                 const struct messages_filter *filter,
477                                 messages_get_messages_listing_cb callback,
478                                 void *user_data)
479 {
480         DBusConnection *conn;
481         DBusPendingCall *call;
482         DBusMessage *message;
483         struct session *s = data;
484         struct session *request =  g_new0(struct session, 1);
485         char *folder_name;
486
487         if (strlen(name) != 0)
488                 request->name = g_strdup(name);
489          else
490                 request->name = g_strdup(s->cwd);
491
492         folder_name = g_strdup(request->name);
493         request->max = max;
494         request->offset = offset;
495         request->filter = filter;
496         request->msg_list_cb = (void *)callback;
497         request->user_data = user_data;
498
499         DBG("messages_get_messages_listing \n");
500
501         conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
502         if (!conn) {
503                 error("Can't get on session bus");
504                 g_free(folder_name);
505                 g_free(request->name);
506                 return -1;
507         }
508
509         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
510                                                 BT_MAP_SERVICE_OBJECT_PATH,
511                                                 BT_MAP_SERVICE_INTERFACE,
512                                                 QUERY_GET_MSG_LIST);
513         if (!message) {
514                 error("Can't allocate new message");
515                 dbus_connection_unref(conn);
516                 g_free(folder_name);
517                 g_free(request->name);
518                 return -1;
519         }
520         dbus_message_append_args(message, DBUS_TYPE_STRING, &folder_name,
521                                                         DBUS_TYPE_INVALID);
522
523         if (dbus_connection_send_with_reply(conn, message, &call, -1) ==
524                                         FALSE) {
525                 error("Could not send dbus message");
526                 dbus_message_unref(message);
527                 dbus_connection_unref(conn);
528                 g_free(folder_name);
529                 g_free(request->name);
530                 return -1;
531         }
532         dbus_pending_call_set_notify(call, message_get_msg_list, request, NULL);
533         dbus_message_unref(message);
534         dbus_connection_unref(conn);
535         g_free(folder_name);
536         g_free(request->name);
537         return 1;
538 }
539
540 int messages_get_message(void *session,
541                                         const char *handle,
542                                         unsigned long flags,
543                                         messages_get_message_cb callback,
544                                         void *user_data)
545 {
546         DBusConnection *conn;
547         DBusPendingCall *call;
548         DBusMessage *message;
549         struct session *s = session;
550         char *message_name;
551
552
553         if (NULL != handle) {
554                 message_name =  g_strdup(handle);
555                 DBG("Message handle = %s\n", handle);
556         } else {
557                 return -1;
558         }
559         s->get_msg_cb = callback;
560         s->user_data = user_data;
561
562         DBG("messages_get_message \n");
563
564         conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
565         if (!conn) {
566                 error("Can't get on session bus");
567                 g_free(message_name);
568                 return -1;
569         }
570
571         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
572                                                 BT_MAP_SERVICE_OBJECT_PATH,
573                                                 BT_MAP_SERVICE_INTERFACE,
574                                                 QUERY_GET_MESSAGE);
575         if (!message) {
576                 error("Can't allocate new message");
577                 dbus_connection_unref(conn);
578                 g_free(message_name);
579                 return -1;
580         }
581         dbus_message_append_args(message, DBUS_TYPE_STRING, &message_name,
582                                                         DBUS_TYPE_INVALID);
583
584         if (dbus_connection_send_with_reply(conn, message, &call, -1) ==
585                                         FALSE) {
586                 error("Could not send dbus message");
587                 dbus_message_unref(message);
588                 dbus_connection_unref(conn);
589                 g_free(message_name);
590                 return -1;
591         }
592         dbus_pending_call_set_notify(call, message_get_msg, s, NULL);
593         dbus_message_unref(message);
594         dbus_connection_unref(conn);
595         g_free(message_name);
596         return 1;
597 }
598
599 static void message_update_msg(DBusPendingCall *call, void *user_data)
600 {
601         DBusMessage *reply = dbus_pending_call_steal_reply(call);
602         DBusMessageIter iter;
603         DBusError derr;
604         struct session *session = user_data;
605         int err;
606
607         DBG("message_get_msg \n");
608
609         dbus_error_init(&derr);
610         if (dbus_set_error_from_message(&derr, reply)) {
611                 error("Replied with an error: %s, %s", derr.name, derr.message);
612                 dbus_error_free(&derr);
613         } else {
614                 dbus_message_iter_init(reply, &iter);
615                 if (dbus_message_iter_get_arg_type(&iter) ==
616                                                         DBUS_TYPE_INT32) {
617                         dbus_message_iter_get_basic(&iter, &err);
618                         DBG("Error : %d\n", err);
619                         session->msg_update_cb(session, err,
620                                                 session->user_data);
621                 }
622         }
623         dbus_message_unref(reply);
624 }
625
626
627 int messages_update_inbox(void *session,
628                                         messages_update_inbox_cb callback,
629                                         void *user_data)
630 {
631         DBusConnection *conn;
632         DBusPendingCall *call;
633         DBusMessage *message;
634         struct session *s = session;
635
636         DBG("messages_update_inbox 123\n");
637
638         conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
639         if (!conn) {
640                 error("Can't get on session bus");
641                 return -1;
642         }
643
644         s->msg_update_cb = callback;
645         s->user_data = user_data;
646
647         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
648                                                 BT_MAP_SERVICE_OBJECT_PATH,
649                                                 BT_MAP_SERVICE_INTERFACE,
650                                                 QUERY_UPDATE_MESSAGE);
651         if (!message) {
652                 error("Can't allocate new message");
653                 dbus_connection_unref(conn);
654                 return -1;
655         }
656
657         if (dbus_connection_send_with_reply(conn, message, &call, -1) ==
658                                         FALSE) {
659                 error("Could not send dbus message");
660                 dbus_message_unref(message);
661                 dbus_connection_unref(conn);
662                 return -1;
663         }
664         dbus_pending_call_set_notify(call, message_update_msg, s, NULL);
665         dbus_message_unref(message);
666         dbus_connection_unref(conn);
667         return 1;
668 }
669
670 static void message_status_msg(DBusPendingCall *call, void *user_data)
671 {
672         DBusMessage *reply = dbus_pending_call_steal_reply(call);
673         DBusMessageIter iter;
674         DBusError derr;
675         struct session *session = user_data;
676         int err;
677
678         DBG("message_get_msg \n");
679
680         dbus_error_init(&derr);
681         if (dbus_set_error_from_message(&derr, reply)) {
682                 error("Replied with an error: %s, %s", derr.name, derr.message);
683                 dbus_error_free(&derr);
684         } else {
685                 dbus_message_iter_init(reply, &iter);
686                 if (dbus_message_iter_get_arg_type(&iter) ==
687                                                         DBUS_TYPE_INT32) {
688                         dbus_message_iter_get_basic(&iter, &err);
689                         DBG("Error : %d\n", err);
690                         session->msg_status_cb(session, err,
691                                                 session->user_data);
692                 }
693         }
694         dbus_message_unref(reply);
695 }
696
697 int messages_set_message_status(void *session, const char *handle,
698                                         int indicator, int value,
699                                         messages_set_message_status_cb callback,
700                                         void *user_data)
701 {
702         DBusConnection *conn;
703         DBusPendingCall *call;
704         DBusMessage *message;
705         struct session *s = session;
706         char *message_name;
707
708         DBG("messages_set_message_status \n");
709
710         if (NULL != handle) {
711                 message_name =  g_strdup(handle);
712                 DBG("Message handle = %s\n", handle);
713         } else {
714                 return -1;
715         }
716
717         s->msg_status_cb = callback;
718         s->user_data = user_data;
719
720         conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
721         if (!conn) {
722                 error("Can't get on session bus");
723                 g_free(message_name);
724                 return -1;
725         }
726
727         message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
728                                                 BT_MAP_SERVICE_OBJECT_PATH,
729                                                 BT_MAP_SERVICE_INTERFACE,
730                                                 QUERY_MESSAGE_STATUS);
731         if (!message) {
732                 error("Can't allocate new message");
733                 g_free(message_name);
734                 dbus_connection_unref(conn);
735                 return -1;
736         }
737         dbus_message_append_args(message, DBUS_TYPE_STRING, &message_name,
738                                                 DBUS_TYPE_INT32, &indicator,
739                                                 DBUS_TYPE_INT32, &value,
740                                                 DBUS_TYPE_INVALID);
741
742         if (dbus_connection_send_with_reply(conn, message, &call, -1) ==
743                                         FALSE) {
744                 error("Could not send dbus message");
745                 g_free(message_name);
746                 dbus_message_unref(message);
747                 dbus_connection_unref(conn);
748                 return -1;
749         }
750         dbus_pending_call_set_notify(call, message_status_msg, s, NULL);
751         dbus_message_unref(message);
752         dbus_connection_unref(conn);
753         g_free(message_name);
754         return 1;
755 }
756
757 void messages_abort(void *session)
758 {
759 }
760