5 * Copyright (C) 2009-2010 Intel Corporation
6 * Copyright (C) 2007-2010 Marcel Holtmann <marcel@holtmann.org>
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.
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.
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
35 #include <dbus/dbus.h>
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"
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"
47 struct message_folder {
54 struct message_folder *folder;
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,
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);
72 static struct message_folder *folder_tree = NULL;
74 static struct message_folder *get_folder(const char *folder)
76 GSList *folders = folder_tree->subfolders;
77 struct message_folder *last = NULL;
81 if (g_strcmp0(folder, "/") == 0)
84 path = g_strsplit(folder, "/", 0);
86 for (i = 1; path[i] != NULL; i++) {
87 gboolean match_found = FALSE;
90 for (l = folders; l != NULL; l = g_slist_next(l)) {
91 struct message_folder *folder = l->data;
93 if (g_ascii_strncasecmp(folder->name, path[i],
94 strlen(folder->name)) == 0) {
97 folders = folder->subfolders;
113 static void destroy_folder_tree(void *root)
115 struct message_folder *folder = root;
121 g_free(folder->name);
123 tmp = folder->subfolders;
124 while (tmp != NULL) {
125 next = g_slist_next(tmp);
126 destroy_folder_tree(tmp->data);
129 g_slist_free(folder->subfolders);
133 static struct message_folder *create_folder(const char *name)
135 struct message_folder *folder = g_new0(struct message_folder, 1);
137 folder->name = g_strdup(name);
141 static void create_folder_tree()
144 struct message_folder *parent, *child;
146 folder_tree = create_folder("/");
148 parent = create_folder("telecom");
149 folder_tree->subfolders = g_slist_append(folder_tree->subfolders,
152 child = create_folder("msg");
153 parent->subfolders = g_slist_append(parent->subfolders, child);
156 int messages_init(void)
158 create_folder_tree();
162 void messages_exit(void)
164 destroy_folder_tree(folder_tree);
167 static void message_get_folder_list(DBusPendingCall *call, void *user_data)
169 DBusMessage *reply = dbus_pending_call_steal_reply(call);
170 DBusMessageIter iter;
171 DBusMessageIter iter_struct;
172 DBusMessageIter entry;
174 const char *name = NULL;
175 struct message_folder *parent = {0,}, *child = {0,};
178 DBG("message_get_folder_list \n");
180 for (l = folder_tree->subfolders; l != NULL; l = parent->subfolders)
183 DBG("Last child folder = %s \n", parent->name);
184 dbus_error_init(&derr);
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);
190 dbus_message_iter_init(reply, &iter);
191 dbus_message_iter_recurse(&iter, &iter_struct);
193 while (dbus_message_iter_get_arg_type(&iter_struct) ==
195 dbus_message_iter_recurse(&iter_struct, &entry);
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,
202 dbus_message_iter_next(&iter_struct);
205 dbus_message_unref(reply);
208 static void message_get_msg_list(DBusPendingCall *call, void *user_data)
210 DBusMessage *reply = dbus_pending_call_steal_reply(call);
211 DBusMessageIter iter;
212 DBusMessageIter iter_struct;
213 DBusMessageIter entry;
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);
221 DBG("message_get_msg_list \n");
223 dbus_error_init(&derr);
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);
229 dbus_message_iter_init(reply, &iter);
230 dbus_message_iter_recurse(&iter, &iter_struct);
232 while (dbus_message_iter_get_arg_type(&iter_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);
249 session->msg_list_cb(session, -EAGAIN, 1,
253 dbus_message_iter_next(&iter_struct);
255 session->msg_list_cb(session, 0, 0,
260 dbus_message_unref(reply);
263 static void message_get_msg(DBusPendingCall *call, void *user_data)
265 DBusMessage *reply = dbus_pending_call_steal_reply(call);
266 DBusMessageIter iter;
267 DBusMessageIter iter_struct;
268 DBusMessageIter entry;
270 struct session *session = user_data;
273 DBG("message_get_msg \n");
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);
280 dbus_message_iter_init(reply, &iter);
281 dbus_message_iter_recurse(&iter, &iter_struct);
283 if (dbus_message_iter_get_arg_type(&iter_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);
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);
294 dbus_message_unref(reply);
297 int messages_connect(void **s)
299 struct session *session = g_new0(struct session, 1);
301 session->cwd = g_strdup("/");
302 session->folder = folder_tree;
306 DBusConnection *conn;
307 DBusPendingCall *call;
308 DBusMessage *message;
311 conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
313 error("Can't get on session bus");
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);
322 error("Can't allocate new message");
323 dbus_connection_unref(conn);
327 if (dbus_connection_send_with_reply(conn, message, &call, -1) ==
329 error("Could not send dbus message");
330 dbus_message_unref(message);
331 dbus_connection_unref(conn);
335 dbus_pending_call_set_notify(call, message_get_folder_list, session,
337 dbus_message_unref(message);
338 dbus_connection_unref(conn);
342 void messages_disconnect(void *s)
344 struct session *session = s;
346 g_free(session->cwd);
350 int messages_set_notification_registration(void *session,
351 void (*send_event)(void *session,
352 const struct messages_event *event, void *user_data),
358 int messages_set_folder(void *s, const char *name, gboolean cdup)
360 struct session *session = s;
365 if (name && (strchr(name, '/') || strcmp(name, "..") == 0))
369 if (session->cwd[0] == 0)
372 newrel = g_path_get_dirname(session->cwd);
374 /* We use empty string for indication of the root directory */
375 if (newrel[0] == '.' && newrel[1] == 0)
380 if (!cdup && (!name || name[0] == 0))
381 newrel = g_strdup("");
383 newrel = g_build_filename(newrel ? newrel : session->cwd, name,
387 if (newrel[0] != '/')
388 newabs = g_build_filename("/", newrel, NULL);
390 newabs = g_strdup(newrel);
392 session->folder = get_folder(newabs);
393 if (session->folder == NULL) {
401 g_free(session->cwd);
402 session->cwd = newabs;
407 static gboolean async_get_folder_listing(void *s)
409 struct session *session = s;
410 gboolean count = FALSE;
411 int folder_count = 0;
413 struct message_folder *folder;
416 if (session->name && strchr(session->name, '/') != NULL)
419 path = g_build_filename(session->cwd, session->name, NULL);
421 if (path == NULL || strlen(path) == 0)
424 folder = get_folder(path);
429 if (session->max == 0) {
430 session->max = 0xffff;
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;
440 if (count == FALSE && session->offset <= folder_count)
441 session->folder_list_cb(session, -EAGAIN, 0,
442 dir_data->name, session->user_data);
446 session->folder_list_cb(session, 0, folder_count, NULL,
450 g_free(session->name);
455 int messages_get_folder_listing(void *s, const char *name,
456 uint16_t max, uint16_t offset,
457 messages_folder_listing_cb callback,
460 struct session *session = s;
461 session->name = g_strdup(name);
463 session->offset = offset;
464 session->folder_list_cb = callback;
465 session->user_data = user_data;
467 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, async_get_folder_listing,
473 int messages_get_messages_listing(void *data,
475 uint16_t max, uint16_t offset,
476 const struct messages_filter *filter,
477 messages_get_messages_listing_cb callback,
480 DBusConnection *conn;
481 DBusPendingCall *call;
482 DBusMessage *message;
483 struct session *s = data;
484 struct session *request = g_new0(struct session, 1);
487 if (strlen(name) != 0)
488 request->name = g_strdup(name);
490 request->name = g_strdup(s->cwd);
492 folder_name = g_strdup(request->name);
494 request->offset = offset;
495 request->filter = filter;
496 request->msg_list_cb = (void *)callback;
497 request->user_data = user_data;
499 DBG("messages_get_messages_listing \n");
501 conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
503 error("Can't get on session bus");
505 g_free(request->name);
509 message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
510 BT_MAP_SERVICE_OBJECT_PATH,
511 BT_MAP_SERVICE_INTERFACE,
514 error("Can't allocate new message");
515 dbus_connection_unref(conn);
517 g_free(request->name);
520 dbus_message_append_args(message, DBUS_TYPE_STRING, &folder_name,
523 if (dbus_connection_send_with_reply(conn, message, &call, -1) ==
525 error("Could not send dbus message");
526 dbus_message_unref(message);
527 dbus_connection_unref(conn);
529 g_free(request->name);
532 dbus_pending_call_set_notify(call, message_get_msg_list, request, NULL);
533 dbus_message_unref(message);
534 dbus_connection_unref(conn);
536 g_free(request->name);
540 int messages_get_message(void *session,
543 messages_get_message_cb callback,
546 DBusConnection *conn;
547 DBusPendingCall *call;
548 DBusMessage *message;
549 struct session *s = session;
553 if (NULL != handle) {
554 message_name = g_strdup(handle);
555 DBG("Message handle = %s\n", handle);
559 s->get_msg_cb = callback;
560 s->user_data = user_data;
562 DBG("messages_get_message \n");
564 conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
566 error("Can't get on session bus");
567 g_free(message_name);
571 message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
572 BT_MAP_SERVICE_OBJECT_PATH,
573 BT_MAP_SERVICE_INTERFACE,
576 error("Can't allocate new message");
577 dbus_connection_unref(conn);
578 g_free(message_name);
581 dbus_message_append_args(message, DBUS_TYPE_STRING, &message_name,
584 if (dbus_connection_send_with_reply(conn, message, &call, -1) ==
586 error("Could not send dbus message");
587 dbus_message_unref(message);
588 dbus_connection_unref(conn);
589 g_free(message_name);
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);
599 static void message_update_msg(DBusPendingCall *call, void *user_data)
601 DBusMessage *reply = dbus_pending_call_steal_reply(call);
602 DBusMessageIter iter;
604 struct session *session = user_data;
607 DBG("message_get_msg \n");
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);
614 dbus_message_iter_init(reply, &iter);
615 if (dbus_message_iter_get_arg_type(&iter) ==
617 dbus_message_iter_get_basic(&iter, &err);
618 DBG("Error : %d\n", err);
619 session->msg_update_cb(session, err,
623 dbus_message_unref(reply);
627 int messages_update_inbox(void *session,
628 messages_update_inbox_cb callback,
631 DBusConnection *conn;
632 DBusPendingCall *call;
633 DBusMessage *message;
634 struct session *s = session;
636 DBG("messages_update_inbox 123\n");
638 conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
640 error("Can't get on session bus");
644 s->msg_update_cb = callback;
645 s->user_data = user_data;
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);
652 error("Can't allocate new message");
653 dbus_connection_unref(conn);
657 if (dbus_connection_send_with_reply(conn, message, &call, -1) ==
659 error("Could not send dbus message");
660 dbus_message_unref(message);
661 dbus_connection_unref(conn);
664 dbus_pending_call_set_notify(call, message_update_msg, s, NULL);
665 dbus_message_unref(message);
666 dbus_connection_unref(conn);
670 static void message_status_msg(DBusPendingCall *call, void *user_data)
672 DBusMessage *reply = dbus_pending_call_steal_reply(call);
673 DBusMessageIter iter;
675 struct session *session = user_data;
678 DBG("message_get_msg \n");
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);
685 dbus_message_iter_init(reply, &iter);
686 if (dbus_message_iter_get_arg_type(&iter) ==
688 dbus_message_iter_get_basic(&iter, &err);
689 DBG("Error : %d\n", err);
690 session->msg_status_cb(session, err,
694 dbus_message_unref(reply);
697 int messages_set_message_status(void *session, const char *handle,
698 int indicator, int value,
699 messages_set_message_status_cb callback,
702 DBusConnection *conn;
703 DBusPendingCall *call;
704 DBusMessage *message;
705 struct session *s = session;
708 DBG("messages_set_message_status \n");
710 if (NULL != handle) {
711 message_name = g_strdup(handle);
712 DBG("Message handle = %s\n", handle);
717 s->msg_status_cb = callback;
718 s->user_data = user_data;
720 conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
722 error("Can't get on session bus");
723 g_free(message_name);
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);
732 error("Can't allocate new message");
733 g_free(message_name);
734 dbus_connection_unref(conn);
737 dbus_message_append_args(message, DBUS_TYPE_STRING, &message_name,
738 DBUS_TYPE_INT32, &indicator,
739 DBUS_TYPE_INT32, &value,
742 if (dbus_connection_send_with_reply(conn, message, &call, -1) ==
744 error("Could not send dbus message");
745 g_free(message_name);
746 dbus_message_unref(message);
747 dbus_connection_unref(conn);
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);
757 void messages_abort(void *session)