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"
42 #define QUERY_NOTI_REGISTRATION "NotiRegistration"
44 #define BT_MAP_SERVICE_OBJECT_PATH "/org/bluez/map_agent"
45 #define BT_MAP_SERVICE_NAME "org.bluez.map_agent"
46 #define BT_MAP_SERVICE_INTERFACE "org.bluez.MapAgent"
48 static DBusConnection *g_conn = NULL;
51 int notification_status;
55 struct message_folder {
62 struct message_folder *folder;
67 void (*folder_list_cb)(void *session, int err, uint16_t size,
68 const char *name, void *user_data);
69 struct messages_message *msg;
70 const struct messages_filter *filter;
71 void (*msg_list_cb)(void *session, int err, int size, gboolean newmsg,
72 const struct messages_message *entry,
74 void (*get_msg_cb)(void *session, int err, gboolean fmore,
75 const char *chunk, void *user_data);
76 void (*msg_update_cb)(void *session, int err, void *user_data);
77 void (*msg_status_cb)(void *session, int err, void *user_data);
80 static struct message_folder *folder_tree = NULL;
82 static struct message_folder *get_folder(const char *folder)
84 GSList *folders = folder_tree->subfolders;
85 struct message_folder *last = NULL;
89 if (g_strcmp0(folder, "/") == 0)
92 path = g_strsplit(folder, "/", 0);
94 for (i = 1; path[i] != NULL; i++) {
95 gboolean match_found = FALSE;
98 for (l = folders; l != NULL; l = g_slist_next(l)) {
99 struct message_folder *folder = l->data;
101 if (g_ascii_strncasecmp(folder->name, path[i],
102 strlen(folder->name)) == 0) {
105 folders = folder->subfolders;
121 static void destroy_folder_tree(void *root)
123 struct message_folder *folder = root;
129 g_free(folder->name);
131 tmp = folder->subfolders;
132 while (tmp != NULL) {
133 next = g_slist_next(tmp);
134 destroy_folder_tree(tmp->data);
137 g_slist_free(folder->subfolders);
141 static struct message_folder *create_folder(const char *name)
143 struct message_folder *folder = g_new0(struct message_folder, 1);
145 folder->name = g_strdup(name);
149 static void create_folder_tree()
152 struct message_folder *parent, *child;
154 folder_tree = create_folder("/");
156 parent = create_folder("telecom");
157 folder_tree->subfolders = g_slist_append(folder_tree->subfolders,
160 child = create_folder("msg");
161 parent->subfolders = g_slist_append(parent->subfolders, child);
164 int messages_init(void)
166 g_conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
168 error("Can't get on session bus");
172 create_folder_tree();
176 void messages_exit(void)
178 destroy_folder_tree(folder_tree);
181 dbus_connection_unref(g_conn);
186 static void message_get_folder_list(DBusPendingCall *call, void *user_data)
188 DBusMessage *reply = dbus_pending_call_steal_reply(call);
189 DBusMessageIter iter;
190 DBusMessageIter iter_struct;
191 DBusMessageIter entry;
193 const char *name = NULL;
194 struct message_folder *parent = {0,}, *child = {0,};
199 for (l = folder_tree->subfolders; l != NULL; l = parent->subfolders)
202 DBG("Last child folder = %s \n", parent->name);
203 dbus_error_init(&derr);
205 if (dbus_set_error_from_message(&derr, reply)) {
206 error("Replied with an error: %s, %s", derr.name, derr.message);
207 dbus_error_free(&derr);
209 dbus_message_iter_init(reply, &iter);
210 dbus_message_iter_recurse(&iter, &iter_struct);
212 while (dbus_message_iter_get_arg_type(&iter_struct) ==
214 dbus_message_iter_recurse(&iter_struct, &entry);
216 dbus_message_iter_get_basic(&entry, &name);
217 DBG("Folder name = %s \n", name);
218 child = create_folder(name);
219 parent->subfolders = g_slist_append(parent->subfolders,
221 dbus_message_iter_next(&iter_struct);
224 dbus_message_unref(reply);
228 static void message_get_msg_list(DBusPendingCall *call, void *user_data)
230 DBusMessage *reply = dbus_pending_call_steal_reply(call);
231 DBusMessageIter iter;
232 DBusMessageIter iter_struct;
233 DBusMessageIter entry;
235 const char *msg_handle;
236 const char *msg_type;
237 const char *msg_time;
238 struct session *session = user_data;
239 struct messages_message *data = g_new0(struct messages_message, 1);
243 dbus_error_init(&derr);
245 if (dbus_set_error_from_message(&derr, reply)) {
246 error("Replied with an error: %s, %s", derr.name, derr.message);
247 dbus_error_free(&derr);
249 dbus_message_iter_init(reply, &iter);
250 dbus_message_iter_recurse(&iter, &iter_struct);
252 while (dbus_message_iter_get_arg_type(&iter_struct) ==
254 dbus_message_iter_recurse(&iter_struct, &entry);
255 dbus_message_iter_get_basic(&entry, &msg_handle);
256 DBG("Msg handle = %s \n", msg_handle);
257 data->handle = g_strdup(msg_handle);
258 dbus_message_iter_next(&entry);
259 dbus_message_iter_get_basic(&entry, &msg_type);
260 DBG("Msg Type = %s \n", msg_type);
261 data->mask |= PMASK_TYPE;
262 data->type = g_strdup(msg_type);
263 dbus_message_iter_next(&entry);
264 dbus_message_iter_get_basic(&entry, &msg_time);
265 DBG("Msg date & time = %s \n", msg_time);
266 data->mask |= PMASK_DATETIME;
267 data->datetime = g_strdup(msg_time);
269 session->msg_list_cb(session, -EAGAIN, 1,
273 dbus_message_iter_next(&iter_struct);
275 session->msg_list_cb(session, 0, 0,
280 dbus_message_unref(reply);
284 static void message_get_msg(DBusPendingCall *call, void *user_data)
286 DBusMessage *reply = dbus_pending_call_steal_reply(call);
287 DBusMessageIter iter;
288 DBusMessageIter iter_struct;
289 DBusMessageIter entry;
291 struct session *session = user_data;
296 dbus_error_init(&derr);
297 if (dbus_set_error_from_message(&derr, reply)) {
298 error("Replied with an error: %s, %s", derr.name, derr.message);
299 dbus_error_free(&derr);
301 dbus_message_iter_init(reply, &iter);
302 dbus_message_iter_recurse(&iter, &iter_struct);
304 if (dbus_message_iter_get_arg_type(&iter_struct) ==
306 dbus_message_iter_recurse(&iter_struct, &entry);
307 dbus_message_iter_get_basic(&entry, &msg_body);
308 DBG("Msg handle = %s \n", msg_body);
310 session->get_msg_cb(session, -EAGAIN, FALSE,
311 msg_body, session->user_data);
312 session->get_msg_cb(session, 0, FALSE,
313 NULL, session->user_data);
315 dbus_message_unref(reply);
319 int messages_connect(void **s)
321 DBusPendingCall *call;
322 DBusMessage *message;
325 struct session *session = g_new0(struct session, 1);
327 session->cwd = g_strdup("/");
328 session->folder = folder_tree;
332 message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
333 BT_MAP_SERVICE_OBJECT_PATH,
334 BT_MAP_SERVICE_INTERFACE,
335 QUERY_GET_FOLDER_TREE);
337 error("Can't allocate new message");
341 if (dbus_connection_send_with_reply(g_conn, message, &call, -1) ==
343 error("Could not send dbus message");
344 dbus_message_unref(message);
348 dbus_pending_call_set_notify(call, message_get_folder_list, session,
350 dbus_message_unref(message);
355 void messages_disconnect(void *s)
358 struct session *session = s;
360 g_free(session->cwd);
366 int messages_set_notification_registration(void *session,
367 void (*send_event)(void *session,
368 const struct messages_event *event, void *user_data),
374 int messages_set_folder(void *s, const char *name, gboolean cdup)
376 struct session *session = s;
381 if (name && (strchr(name, '/') || strcmp(name, "..") == 0))
385 if (session->cwd[0] == 0)
388 newrel = g_path_get_dirname(session->cwd);
390 /* We use empty string for indication of the root directory */
391 if (newrel[0] == '.' && newrel[1] == 0)
396 if (!cdup && (!name || name[0] == 0))
397 newrel = g_strdup("");
399 newrel = g_build_filename(newrel ? newrel : session->cwd, name,
403 if (newrel[0] != '/')
404 newabs = g_build_filename("/", newrel, NULL);
406 newabs = g_strdup(newrel);
408 session->folder = get_folder(newabs);
409 if (session->folder == NULL) {
417 g_free(session->cwd);
418 session->cwd = newabs;
423 static gboolean async_get_folder_listing(void *s)
425 struct session *session = s;
426 gboolean count = FALSE;
427 int folder_count = 0;
429 struct message_folder *folder;
432 if (session->name && strchr(session->name, '/') != NULL)
435 path = g_build_filename(session->cwd, session->name, NULL);
437 if (path == NULL || strlen(path) == 0)
440 folder = get_folder(path);
445 if (session->max == 0) {
446 session->max = 0xffff;
451 for (dir = folder->subfolders; dir &&
452 (folder_count - session->offset) < session->max;
453 folder_count++, dir = g_slist_next(dir)) {
454 struct message_folder *dir_data = dir->data;
456 if (count == FALSE && session->offset <= folder_count)
457 session->folder_list_cb(session, -EAGAIN, 0,
458 dir_data->name, session->user_data);
462 session->folder_list_cb(session, 0, folder_count, NULL,
466 g_free(session->name);
471 int messages_get_folder_listing(void *s, const char *name,
472 uint16_t max, uint16_t offset,
473 messages_folder_listing_cb callback,
477 struct session *session = s;
478 session->name = g_strdup(name);
480 session->offset = offset;
481 session->folder_list_cb = callback;
482 session->user_data = user_data;
484 g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, async_get_folder_listing,
491 int messages_get_messages_listing(void *session, const char *name,
492 uint16_t max, uint16_t offset, uint8_t subject_len,
493 const struct messages_filter *filter,
494 messages_get_messages_listing_cb callback,
497 DBusPendingCall *call;
498 DBusMessage *message;
499 struct session *s = session;
501 if (strlen(name) != 0)
502 s->name = g_strdup(name);
504 s->name = g_strdup(s->cwd);
509 s->msg_list_cb = (void *)callback;
510 s->user_data = user_data;
512 message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
513 BT_MAP_SERVICE_OBJECT_PATH,
514 BT_MAP_SERVICE_INTERFACE,
517 error("Can't allocate new message");
521 dbus_message_append_args(message, DBUS_TYPE_STRING, &s->name,
524 if (dbus_connection_send_with_reply(g_conn, message, &call, -1) ==
526 error("Could not send dbus message");
527 dbus_message_unref(message);
531 dbus_pending_call_set_notify(call, message_get_msg_list, s, NULL);
532 dbus_message_unref(message);
538 int messages_get_message(void *session,
541 messages_get_message_cb callback,
544 DBusPendingCall *call;
545 DBusMessage *message;
546 struct session *s = session;
550 if (NULL != handle) {
551 message_name = g_strdup(handle);
552 DBG("Message handle = %s\n", handle);
556 s->get_msg_cb = callback;
557 s->user_data = user_data;
559 message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
560 BT_MAP_SERVICE_OBJECT_PATH,
561 BT_MAP_SERVICE_INTERFACE,
564 error("Can't allocate new message");
565 g_free(message_name);
568 dbus_message_append_args(message, DBUS_TYPE_STRING, &message_name,
571 if (dbus_connection_send_with_reply(g_conn, message, &call, -1) ==
573 error("Could not send dbus message");
574 dbus_message_unref(message);
575 g_free(message_name);
578 dbus_pending_call_set_notify(call, message_get_msg, s, NULL);
579 dbus_message_unref(message);
580 g_free(message_name);
585 static void message_update_msg(DBusPendingCall *call, void *user_data)
587 DBusMessage *reply = dbus_pending_call_steal_reply(call);
588 DBusMessageIter iter;
590 struct session *session = user_data;
594 dbus_error_init(&derr);
595 if (dbus_set_error_from_message(&derr, reply)) {
596 error("Replied with an error: %s, %s", derr.name, derr.message);
597 dbus_error_free(&derr);
599 dbus_message_iter_init(reply, &iter);
600 if (dbus_message_iter_get_arg_type(&iter) ==
602 dbus_message_iter_get_basic(&iter, &err);
603 DBG("Error : %d\n", err);
604 session->msg_update_cb(session, err,
608 dbus_message_unref(reply);
612 int messages_update_inbox(void *session,
613 messages_update_inbox_cb callback,
616 DBusPendingCall *call;
617 DBusMessage *message;
618 struct session *s = session;
622 s->msg_update_cb = callback;
623 s->user_data = user_data;
625 message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
626 BT_MAP_SERVICE_OBJECT_PATH,
627 BT_MAP_SERVICE_INTERFACE,
628 QUERY_UPDATE_MESSAGE);
630 error("Can't allocate new message");
634 if (dbus_connection_send_with_reply(g_conn, message, &call, -1) ==
636 error("Could not send dbus message");
637 dbus_message_unref(message);
640 dbus_pending_call_set_notify(call, message_update_msg, s, NULL);
641 dbus_message_unref(message);
646 static void message_status_msg(DBusPendingCall *call, void *user_data)
648 DBusMessage *reply = dbus_pending_call_steal_reply(call);
649 DBusMessageIter iter;
651 struct session *session = user_data;
656 dbus_error_init(&derr);
657 if (dbus_set_error_from_message(&derr, reply)) {
658 error("Replied with an error: %s, %s", derr.name, derr.message);
659 dbus_error_free(&derr);
661 dbus_message_iter_init(reply, &iter);
662 if (dbus_message_iter_get_arg_type(&iter) ==
664 dbus_message_iter_get_basic(&iter, &err);
665 DBG("Error : %d\n", err);
666 session->msg_status_cb(session, err,
670 dbus_message_unref(reply);
674 int messages_set_message_status(void *session, const char *handle,
675 int indicator, int value,
676 messages_set_message_status_cb callback,
679 DBusPendingCall *call;
680 DBusMessage *message;
681 struct session *s = session;
686 if (NULL != handle) {
687 message_name = g_strdup(handle);
688 DBG("Message handle = %s\n", handle);
693 s->msg_status_cb = callback;
694 s->user_data = user_data;
696 message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
697 BT_MAP_SERVICE_OBJECT_PATH,
698 BT_MAP_SERVICE_INTERFACE,
699 QUERY_MESSAGE_STATUS);
701 error("Can't allocate new message");
702 g_free(message_name);
706 dbus_message_append_args(message, DBUS_TYPE_STRING, &message_name,
707 DBUS_TYPE_INT32, &indicator,
708 DBUS_TYPE_INT32, &value,
711 if (dbus_connection_send_with_reply(g_conn, message, &call, -1) ==
713 error("Could not send dbus message");
714 g_free(message_name);
715 dbus_message_unref(message);
718 dbus_pending_call_set_notify(call, message_status_msg, s, NULL);
719 dbus_message_unref(message);
720 g_free(message_name);
725 static gboolean notification_registration(gpointer user_data)
728 DBusMessage *message = NULL;
730 struct mns_reg_data *data = (struct mns_reg_data *)user_data;
732 message = dbus_message_new_method_call(BT_MAP_SERVICE_NAME,
733 BT_MAP_SERVICE_OBJECT_PATH,
734 BT_MAP_SERVICE_INTERFACE,
735 QUERY_NOTI_REGISTRATION);
737 error("Can't allocate new message");
741 DBG("data->notification_status = %d\n", data->notification_status);
743 if (data->notification_status == 1)
748 dbus_message_append_args(message, DBUS_TYPE_STRING, &data->remote_addr,
749 DBUS_TYPE_BOOLEAN, ®,
752 if (dbus_connection_send(g_conn, message, NULL) == FALSE)
753 error("Could not send dbus message");
757 dbus_message_unref(message);
759 g_free(data->remote_addr);
766 int messages_notification_registration(void *session,
767 char *address, int status,
768 messages_notification_registration_cb callback,
772 struct mns_reg_data *data = g_new0(struct mns_reg_data, 1);
773 data->notification_status = status;
774 data->remote_addr = g_strdup(address);
776 DBG("status = %d\n", status);
778 g_idle_add(notification_registration, data);
783 void messages_abort(void *session)