5 * Copyright (C) 2007-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 <bluetooth/bluetooth.h>
44 #define OBEX_PBAP_UUID \
45 "\x79\x61\x35\xF0\xF0\xC5\x11\xD8\x09\x66\x08\x00\x20\x0C\x9A\x66"
46 #define OBEX_PBAP_UUID_LEN 16
48 #define ERROR_INF PBAP_INTERFACE ".Error"
50 #define FORMAT_VCARD21 0x0
51 #define FORMAT_VCARD30 0x1
53 #define ORDER_INDEXED 0x0
54 #define ORDER_ALPHANUMERIC 0x1
55 #define ORDER_PHONETIC 0x2
57 #define ATTRIB_NAME 0x0
58 #define ATTRIB_NUMBER 0x1
59 #define ATTRIB_SOUND 0x2
61 #define DEFAULT_COUNT 65535
62 #define DEFAULT_OFFSET 0
64 #define PULLPHONEBOOK 0x1
65 #define GETPHONEBOOKSIZE 0x2
67 #define ORDER_TAG 0x01
68 #define SEARCHVALUE_TAG 0x02
69 #define SEARCHATTRIB_TAG 0x03
70 #define MAXLISTCOUNT_TAG 0x04
71 #define LISTSTARTOFFSET_TAG 0x05
72 #define FILTER_TAG 0x06
73 #define FORMAT_TAG 0X07
74 #define PHONEBOOKSIZE_TAG 0X08
75 #define NEWMISSEDCALLS_TAG 0X09
77 /* The following length is in the unit of byte */
79 #define SEARCHATTRIB_LEN 1
80 #define MAXLISTCOUNT_LEN 2
81 #define LISTSTARTOFFSET_LEN 2
84 #define PHONEBOOKSIZE_LEN 2
85 #define NEWMISSEDCALLS_LEN 1
87 #define get_be16(val) GUINT16_FROM_BE(bt_get_unaligned((guint16 *) val))
89 static const char *filter_list[] = {
118 "X-IRMC-CALL-DATETIME",
122 #define FILTER_BIT_MAX 63
123 #define FILTER_ALL 0xFFFFFFFFFFFFFFFFULL
125 #define PBAP_INTERFACE "org.openobex.PhonebookAccess"
126 #define PBAP_UUID "0000112f-0000-1000-8000-00805f9b34fb"
129 struct obc_session *session;
137 struct pullphonebook_apparam {
144 uint8_t maxlistcount_tag;
145 uint8_t maxlistcount_len;
146 uint16_t maxlistcount;
147 uint8_t liststartoffset_tag;
148 uint8_t liststartoffset_len;
149 uint16_t liststartoffset;
150 } __attribute__ ((packed));
152 struct pullvcardentry_apparam {
159 } __attribute__ ((packed));
165 } __attribute__ ((packed));
167 #define APPARAM_HDR_SIZE 2
169 static DBusConnection *conn = NULL;
171 static void listing_element(GMarkupParseContext *ctxt,
172 const gchar *element,
174 const gchar **values,
178 DBusMessageIter *item = user_data, entry;
180 const gchar *handle = NULL, *vcardname = NULL;
182 if (g_str_equal(element, "card") != TRUE)
185 for (key = (gchar **) names; *key; key++, values++) {
186 if (g_str_equal(*key, "handle") == TRUE)
188 else if (g_str_equal(*key, "name") == TRUE)
192 if (!handle || !vcardname)
195 dbus_message_iter_open_container(item, DBUS_TYPE_STRUCT, NULL, &entry);
196 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &handle);
197 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &vcardname);
198 dbus_message_iter_close_container(item, &entry);
201 static const GMarkupParser listing_parser = {
208 static gchar *build_phonebook_path(const char *location, const char *item)
210 gchar *path = NULL, *tmp, *tmp1;
212 if (!g_ascii_strcasecmp(location, "INT") ||
213 !g_ascii_strcasecmp(location, "INTERNAL"))
214 path = g_strdup("telecom");
215 else if (!g_ascii_strncasecmp(location, "SIM", 3)) {
216 if (strlen(location) == 3)
217 tmp = g_strdup("SIM1");
219 tmp = g_ascii_strup(location, 4);
221 path = g_build_filename(tmp, "telecom", NULL);
226 if (!g_ascii_strcasecmp(item, "PB") ||
227 !g_ascii_strcasecmp(item, "ICH") ||
228 !g_ascii_strcasecmp(item, "OCH") ||
229 !g_ascii_strcasecmp(item, "MCH") ||
230 !g_ascii_strcasecmp(item, "CCH")) {
232 tmp1 = g_ascii_strdown(item, -1);
233 path = g_build_filename(tmp, tmp1, NULL);
244 typedef void (*setpath_cb_t) (GError *err, gpointer user_data);
246 struct setpath_data {
253 static void setpath_complete(GError *err, struct setpath_data *data)
256 data->func(err, data->user_data);
257 g_strfreev(data->remaining);
261 static void setpath_cb(GObex *obex, GError *err, GObexPacket *rsp,
264 struct setpath_data *data = user_data;
268 setpath_complete(err, data);
272 next = data->remaining[data->index];
274 setpath_complete(NULL, data);
280 g_obex_setpath(obex, next, setpath_cb, data, &err);
282 setpath_complete(err, data);
287 static gboolean setpath(GObex *obex, const char *path, size_t max_elem,
288 setpath_cb_t func, gpointer user_data)
291 struct setpath_data *data;
293 data = g_new0(struct setpath_data, 1);
295 g_obex_setpath(obex, "", setpath_cb, data, &err);
297 error("set_path: %s", err->message);
304 data->user_data = user_data;
305 data->remaining = g_strsplit(path, "/", max_elem);
310 /* should only be called inside pbap_set_path */
311 static void pbap_reset_path(struct pbap_data *pbap)
313 GObex *obex = obc_session_get_obex(pbap->session);
318 setpath(obex, pbap->path, 3, NULL, NULL);
321 static void pbap_setpath_cb(GError *err, gpointer user_data)
323 struct pbap_data *pbap = user_data;
326 pbap_reset_path(user_data);
328 if (pbap->msg == NULL)
332 DBusMessage *reply= g_dbus_create_error(pbap->msg,
335 g_dbus_send_message(conn, reply);
337 g_dbus_send_reply(conn, pbap->msg, DBUS_TYPE_INVALID);
339 dbus_message_unref(pbap->msg);
343 static int pbap_set_path(struct pbap_data *pbap, const char *path)
345 GObex *obex = obc_session_get_obex(pbap->session);
348 return G_OBEX_RSP_BAD_REQUEST;
350 if (pbap->path != NULL && g_str_equal(pbap->path, path))
353 if (!setpath(obex, path, 3, pbap_setpath_cb, pbap))
354 return G_OBEX_RSP_INTERNAL_SERVER_ERROR;
357 pbap->path = g_strdup(path);
359 return G_OBEX_RSP_SUCCESS;
362 static void read_return_apparam(struct obc_session *session,
363 guint16 *phone_book_size, guint8 *new_missed_calls)
365 struct obc_transfer *transfer = obc_session_get_transfer(session);
366 struct obc_transfer_params params;
370 *phone_book_size = 0;
371 *new_missed_calls = 0;
373 if (obc_transfer_get_params(transfer, ¶ms) < 0)
376 if (params.size < APPARAM_HDR_SIZE)
379 while (size > APPARAM_HDR_SIZE) {
380 struct apparam_hdr *hdr = (struct apparam_hdr *) params.data;
382 if (hdr->len > size - APPARAM_HDR_SIZE) {
383 error("Unexpected PBAP pullphonebook app"
384 " length, tag %d, len %d",
390 case PHONEBOOKSIZE_TAG:
391 if (hdr->len == PHONEBOOKSIZE_LEN) {
393 memcpy(&val, hdr->val, sizeof(val));
394 *phone_book_size = get_be16(&val);
397 case NEWMISSEDCALLS_TAG:
398 if (hdr->len == NEWMISSEDCALLS_LEN)
399 *new_missed_calls = hdr->val[0];
402 error("Unexpected PBAP pullphonebook app"
403 " parameter, tag %d, len %d",
407 buf += APPARAM_HDR_SIZE + hdr->len;
408 size -= APPARAM_HDR_SIZE + hdr->len;
412 static void pull_phonebook_callback(struct obc_session *session,
413 GError *err, void *user_data)
415 struct obc_transfer *transfer = obc_session_get_transfer(session);
416 struct pbap_data *pbap = user_data;
421 if (pbap->msg == NULL)
425 reply = g_dbus_create_error(pbap->msg,
426 "org.openobex.Error.Failed",
431 reply = dbus_message_new_method_return(pbap->msg);
433 buf = obc_transfer_get_buffer(transfer, &size);
437 dbus_message_append_args(reply,
438 DBUS_TYPE_STRING, &buf,
441 obc_transfer_clear_buffer(transfer);
444 g_dbus_send_message(conn, reply);
445 dbus_message_unref(pbap->msg);
449 obc_transfer_unregister(transfer);
452 static void phonebook_size_callback(struct obc_session *session,
453 GError *err, void *user_data)
455 struct obc_transfer *transfer = obc_session_get_transfer(session);
456 struct pbap_data *pbap = user_data;
458 guint16 phone_book_size;
459 guint8 new_missed_calls;
461 if (pbap->msg == NULL)
465 reply = g_dbus_create_error(pbap->msg,
466 "org.openobex.Error.Failed",
471 reply = dbus_message_new_method_return(pbap->msg);
473 read_return_apparam(session, &phone_book_size, &new_missed_calls);
475 dbus_message_append_args(reply,
476 DBUS_TYPE_UINT16, &phone_book_size,
479 obc_transfer_clear_buffer(transfer);
482 g_dbus_send_message(conn, reply);
483 dbus_message_unref(pbap->msg);
487 obc_transfer_unregister(transfer);
490 static void pull_vcard_listing_callback(struct obc_session *session,
491 GError *err, void *user_data)
493 struct obc_transfer *transfer = obc_session_get_transfer(session);
494 struct pbap_data *pbap = user_data;
495 GMarkupParseContext *ctxt;
497 DBusMessageIter iter, array;
501 if (pbap->msg == NULL)
505 reply = g_dbus_create_error(pbap->msg,
506 "org.openobex.Error.Failed",
511 reply = dbus_message_new_method_return(pbap->msg);
513 buf = obc_transfer_get_buffer(transfer, &size);
517 dbus_message_iter_init_append(reply, &iter);
518 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
519 DBUS_STRUCT_BEGIN_CHAR_AS_STRING
520 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
521 DBUS_STRUCT_END_CHAR_AS_STRING, &array);
522 ctxt = g_markup_parse_context_new(&listing_parser, 0, &array, NULL);
523 g_markup_parse_context_parse(ctxt, buf, strlen(buf) - 1, NULL);
524 g_markup_parse_context_free(ctxt);
525 dbus_message_iter_close_container(&iter, &array);
527 obc_transfer_clear_buffer(transfer);
530 g_dbus_send_message(conn, reply);
531 dbus_message_unref(pbap->msg);
534 obc_transfer_unregister(transfer);
537 static DBusMessage *pull_phonebook(struct pbap_data *pbap,
538 DBusMessage *message, guint8 type,
539 const char *name, uint64_t filter,
540 guint8 format, guint16 maxlistcount,
541 guint16 liststartoffset)
543 struct pullphonebook_apparam apparam;
544 session_callback_t func;
547 return g_dbus_create_error(message,
548 "org.openobex.Error.InProgress",
549 "Transfer in progress");
551 apparam.filter_tag = FILTER_TAG;
552 apparam.filter_len = FILTER_LEN;
553 apparam.filter = GUINT64_TO_BE(filter);
554 apparam.format_tag = FORMAT_TAG;
555 apparam.format_len = FORMAT_LEN;
556 apparam.format = format;
557 apparam.maxlistcount_tag = MAXLISTCOUNT_TAG;
558 apparam.maxlistcount_len = MAXLISTCOUNT_LEN;
559 apparam.maxlistcount = GUINT16_TO_BE(maxlistcount);
560 apparam.liststartoffset_tag = LISTSTARTOFFSET_TAG;
561 apparam.liststartoffset_len = LISTSTARTOFFSET_LEN;
562 apparam.liststartoffset = GUINT16_TO_BE(liststartoffset);
566 func = pull_phonebook_callback;
568 case GETPHONEBOOKSIZE:
569 func = phonebook_size_callback;
572 error("Unexpected type : 0x%2x", type);
576 if (obc_session_get(pbap->session, "x-bt/phonebook", name, NULL,
577 (guint8 *) &apparam, sizeof(apparam),
579 return g_dbus_create_error(message,
580 "org.openobex.Error.Failed",
583 pbap->msg = dbus_message_ref(message);
588 static guint8 *fill_apparam(guint8 *dest, void *buf, guint8 tag, guint8 len)
593 memcpy(dest, buf, len);
600 static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
601 DBusMessage *message, const char *name,
602 guint8 order, char *searchval, guint8 attrib,
603 guint16 count, guint16 offset)
605 guint8 *p, *apparam = NULL;
610 return g_dbus_create_error(message,
611 "org.openobex.Error.InProgress",
612 "Transfer in progress");
614 /* trunc the searchval string if it's length exceed the max value of guint8 */
615 if (strlen(searchval) > 254)
616 searchval[255] = '\0';
618 apparam_size = APPARAM_HDR_SIZE + ORDER_LEN +
619 (APPARAM_HDR_SIZE + strlen(searchval) + 1) +
620 (APPARAM_HDR_SIZE + SEARCHATTRIB_LEN) +
621 (APPARAM_HDR_SIZE + MAXLISTCOUNT_LEN) +
622 (APPARAM_HDR_SIZE + LISTSTARTOFFSET_LEN);
623 apparam = g_try_malloc0(apparam_size);
625 return g_dbus_create_error(message,
626 ERROR_INF ".Failed", "No Memory");
630 p = fill_apparam(p, &order, ORDER_TAG, ORDER_LEN);
631 p = fill_apparam(p, searchval, SEARCHVALUE_TAG, strlen(searchval) + 1);
632 p = fill_apparam(p, &attrib, SEARCHATTRIB_TAG, SEARCHATTRIB_LEN);
634 count = GUINT16_TO_BE(count);
635 p = fill_apparam(p, &count, MAXLISTCOUNT_TAG, MAXLISTCOUNT_LEN);
637 offset = GUINT16_TO_BE(offset);
638 p = fill_apparam(p, &offset, LISTSTARTOFFSET_TAG, LISTSTARTOFFSET_LEN);
640 err = obc_session_get(pbap->session, "x-bt/vcard-listing", name, NULL,
641 apparam, apparam_size,
642 pull_vcard_listing_callback, pbap);
645 return g_dbus_create_error(message,
646 "org.openobex.Error.Failed",
649 pbap->msg = dbus_message_ref(message);
654 static int set_format(struct pbap_data *pbap, const char *formatstr)
656 if (!formatstr || g_str_equal(formatstr, "")) {
657 pbap->format = FORMAT_VCARD21;
661 if (!g_ascii_strcasecmp(formatstr, "vcard21"))
662 pbap->format = FORMAT_VCARD21;
663 else if (!g_ascii_strcasecmp(formatstr, "vcard30"))
664 pbap->format = FORMAT_VCARD30;
671 static int set_order(struct pbap_data *pbap, const char *orderstr)
673 if (!orderstr || g_str_equal(orderstr, "")) {
674 pbap->order = ORDER_INDEXED;
678 if (!g_ascii_strcasecmp(orderstr, "indexed"))
679 pbap->order = ORDER_INDEXED;
680 else if (!g_ascii_strcasecmp(orderstr, "alphanumeric"))
681 pbap->order = ORDER_ALPHANUMERIC;
682 else if (!g_ascii_strcasecmp(orderstr, "phonetic"))
683 pbap->order = ORDER_PHONETIC;
690 static uint64_t get_filter_mask(const char *filterstr)
697 if (!g_ascii_strcasecmp(filterstr, "ALL"))
700 for (i = 0; filter_list[i] != NULL; i++)
701 if (!g_ascii_strcasecmp(filterstr, filter_list[i]))
704 if (strlen(filterstr) < 4 || strlen(filterstr) > 5
705 || g_ascii_strncasecmp(filterstr, "bit", 3) != 0)
708 sscanf(&filterstr[3], "%d", &bit);
709 if (bit >= 0 && bit <= FILTER_BIT_MAX)
715 static int add_filter(struct pbap_data *pbap, const char *filterstr)
719 mask = get_filter_mask(filterstr);
724 pbap->filter |= mask;
728 static int remove_filter(struct pbap_data *pbap, const char *filterstr)
732 mask = get_filter_mask(filterstr);
737 pbap->filter &= ~mask;
741 static gchar **get_filter_strs(uint64_t filter, gint *size)
743 gchar **list, **item;
745 gint filter_list_size = sizeof(filter_list) / sizeof(filter_list[0]) - 1;
747 list = g_try_malloc0(sizeof(gchar **) * (FILTER_BIT_MAX + 2));
754 for (i = 0; i < filter_list_size; i++)
755 if (filter & (1ULL << i))
756 *(item++) = g_strdup(filter_list[i]);
758 for (i = filter_list_size; i <= FILTER_BIT_MAX; i++)
759 if (filter & (1ULL << i))
760 *(item++) = g_strdup_printf("%s%d", "BIT", i);
767 static DBusMessage *pbap_select(DBusConnection *connection,
768 DBusMessage *message, void *user_data)
770 struct pbap_data *pbap = user_data;
771 const char *item, *location;
775 if (dbus_message_get_args(message, NULL,
776 DBUS_TYPE_STRING, &location,
777 DBUS_TYPE_STRING, &item,
778 DBUS_TYPE_INVALID) == FALSE)
779 return g_dbus_create_error(message,
780 ERROR_INF ".InvalidArguments", NULL);
782 path = build_phonebook_path(location, item);
784 return g_dbus_create_error(message,
785 ERROR_INF ".InvalidArguments", "InvalidPhonebook");
787 err = pbap_set_path(pbap, path);
789 if (err != G_OBEX_RSP_SUCCESS)
790 return g_dbus_create_error(message,
794 pbap->msg = dbus_message_ref(message);
799 static DBusMessage *pbap_pull_all(DBusConnection *connection,
800 DBusMessage *message, void *user_data)
802 struct pbap_data *pbap = user_data;
807 return g_dbus_create_error(message,
808 ERROR_INF ".Forbidden", "Call Select first of all");
810 name = g_strconcat(pbap->path, ".vcf", NULL);
812 err = pull_phonebook(pbap, message, PULLPHONEBOOK, name,
813 pbap->filter, pbap->format,
814 DEFAULT_COUNT, DEFAULT_OFFSET);
819 static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
820 DBusMessage *message, void *user_data)
822 struct pbap_data *pbap = user_data;
823 struct pullvcardentry_apparam apparam;
827 return g_dbus_create_error(message,
828 ERROR_INF ".Forbidden",
829 "Call Select first of all");
831 if (dbus_message_get_args(message, NULL,
832 DBUS_TYPE_STRING, &name,
833 DBUS_TYPE_INVALID) == FALSE)
834 return g_dbus_create_error(message,
835 ERROR_INF ".InvalidArguments", NULL);
838 return g_dbus_create_error(message,
839 "org.openobex.Error.InProgress",
840 "Transfer in progress");
842 apparam.filter_tag = FILTER_TAG;
843 apparam.filter_len = FILTER_LEN;
844 apparam.filter = GUINT64_TO_BE(pbap->filter);
845 apparam.format_tag = FORMAT_TAG;
846 apparam.format_len = FORMAT_LEN;
847 apparam.format = pbap->format;
849 if (obc_session_get(pbap->session, "x-bt/vcard", name, NULL,
850 (guint8 *)&apparam, sizeof(apparam),
851 pull_phonebook_callback, pbap) < 0)
852 return g_dbus_create_error(message,
853 "org.openobex.Error.Failed",
856 pbap->msg = dbus_message_ref(message);
861 static DBusMessage *pbap_list(DBusConnection *connection,
862 DBusMessage *message, void *user_data)
864 struct pbap_data *pbap = user_data;
867 return g_dbus_create_error(message,
868 ERROR_INF ".Forbidden", "Call Select first of all");
870 return pull_vcard_listing(pbap, message, "", pbap->order, "",
871 ATTRIB_NAME, DEFAULT_COUNT, DEFAULT_OFFSET);
874 static DBusMessage *pbap_search(DBusConnection *connection,
875 DBusMessage *message, void *user_data)
877 struct pbap_data *pbap = user_data;
881 if (dbus_message_get_args(message, NULL,
882 DBUS_TYPE_STRING, &field,
883 DBUS_TYPE_STRING, &value,
884 DBUS_TYPE_INVALID) == FALSE)
885 return g_dbus_create_error(message,
886 ERROR_INF ".InvalidArguments", NULL);
889 return g_dbus_create_error(message,
890 ERROR_INF ".Forbidden", "Call Select first of all");
892 if (!field || g_str_equal(field, ""))
893 attrib = ATTRIB_NAME;
894 else if (!g_ascii_strcasecmp(field, "name"))
895 attrib = ATTRIB_NAME;
896 else if (!g_ascii_strcasecmp(field, "number"))
897 attrib = ATTRIB_NUMBER;
898 else if (!g_ascii_strcasecmp(field, "sound"))
899 attrib = ATTRIB_SOUND;
901 return g_dbus_create_error(message,
902 ERROR_INF ".InvalidArguments", NULL);
904 return pull_vcard_listing(pbap, message, "", pbap->order, value,
905 attrib, DEFAULT_COUNT, DEFAULT_OFFSET);
908 static DBusMessage *pbap_get_size(DBusConnection *connection,
909 DBusMessage *message, void *user_data)
911 struct pbap_data *pbap = user_data;
916 return g_dbus_create_error(message,
917 ERROR_INF ".Forbidden", "Call Select first of all");
919 name = g_strconcat(pbap->path, ".vcf", NULL);
921 err = pull_phonebook(pbap, message, GETPHONEBOOKSIZE, name,
922 pbap->filter, pbap->format, 0,
928 static DBusMessage *pbap_set_format(DBusConnection *connection,
929 DBusMessage *message, void *user_data)
931 struct pbap_data *pbap = user_data;
934 if (dbus_message_get_args(message, NULL,
935 DBUS_TYPE_STRING, &format,
936 DBUS_TYPE_INVALID) == FALSE)
937 return g_dbus_create_error(message,
938 ERROR_INF ".InvalidArguments", NULL);
940 if (set_format(pbap, format) < 0)
941 return g_dbus_create_error(message,
942 ERROR_INF ".InvalidArguments", "InvalidFormat");
944 return dbus_message_new_method_return(message);
947 static DBusMessage *pbap_set_order(DBusConnection *connection,
948 DBusMessage *message, void *user_data)
950 struct pbap_data *pbap = user_data;
953 if (dbus_message_get_args(message, NULL,
954 DBUS_TYPE_STRING, &order,
955 DBUS_TYPE_INVALID) == FALSE)
956 return g_dbus_create_error(message,
957 ERROR_INF ".InvalidArguments", NULL);
959 if (set_order(pbap, order) < 0)
960 return g_dbus_create_error(message,
961 ERROR_INF ".InvalidArguments", "InvalidFilter");
963 return dbus_message_new_method_return(message);
966 static DBusMessage *pbap_set_filter(DBusConnection *connection,
967 DBusMessage *message, void *user_data)
969 struct pbap_data *pbap = user_data;
970 char **filters, **item;
972 uint64_t oldfilter = pbap->filter;
974 if (dbus_message_get_args(message, NULL, DBUS_TYPE_ARRAY,
975 DBUS_TYPE_STRING, &filters, &size,
976 DBUS_TYPE_INVALID) == FALSE)
977 return g_dbus_create_error(message,
978 ERROR_INF ".InvalidArguments", NULL);
980 remove_filter(pbap, "ALL");
984 for (item = filters; *item; item++) {
985 if (add_filter(pbap, *item) < 0) {
986 pbap->filter = oldfilter;
988 return g_dbus_create_error(message,
989 ERROR_INF ".InvalidArguments", "InvalidFilters");
995 return dbus_message_new_method_return(message);
998 static DBusMessage *pbap_get_filter(DBusConnection *connection,
999 DBusMessage *message, void *user_data)
1001 struct pbap_data *pbap = user_data;
1002 gchar **filters = NULL;
1006 filters = get_filter_strs(pbap->filter, &size);
1007 reply = dbus_message_new_method_return(message);
1008 dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
1009 DBUS_TYPE_STRING, &filters, size,
1012 g_strfreev(filters);
1016 static DBusMessage *pbap_list_filter_fields(DBusConnection *connection,
1017 DBusMessage *message, void *user_data)
1019 gchar **filters = NULL;
1023 filters = get_filter_strs(FILTER_ALL, &size);
1024 reply = dbus_message_new_method_return(message);
1025 dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
1026 DBUS_TYPE_STRING, &filters, size,
1029 g_strfreev(filters);
1033 static GDBusMethodTable pbap_methods[] = {
1034 { "Select", "ss", "", pbap_select,
1035 G_DBUS_METHOD_FLAG_ASYNC },
1036 { "PullAll", "", "s", pbap_pull_all,
1037 G_DBUS_METHOD_FLAG_ASYNC },
1038 { "Pull", "s", "s", pbap_pull_vcard,
1039 G_DBUS_METHOD_FLAG_ASYNC },
1040 { "List", "", "a(ss)", pbap_list,
1041 G_DBUS_METHOD_FLAG_ASYNC },
1042 { "Search", "ss", "a(ss)", pbap_search,
1043 G_DBUS_METHOD_FLAG_ASYNC },
1044 { "GetSize", "", "q", pbap_get_size,
1045 G_DBUS_METHOD_FLAG_ASYNC },
1046 { "SetFormat", "s", "", pbap_set_format },
1047 { "SetOrder", "s", "", pbap_set_order },
1048 { "SetFilter", "as", "", pbap_set_filter },
1049 { "GetFilter", "", "as", pbap_get_filter },
1050 { "ListFilterFields", "", "as", pbap_list_filter_fields },
1054 static void pbap_free(void *data)
1056 struct pbap_data *pbap = data;
1058 obc_session_unref(pbap->session);
1062 static int pbap_probe(struct obc_session *session)
1064 struct pbap_data *pbap;
1067 path = obc_session_get_path(session);
1071 pbap = g_try_new0(struct pbap_data, 1);
1075 pbap->session = obc_session_ref(session);
1077 if (!g_dbus_register_interface(conn, path, PBAP_INTERFACE, pbap_methods,
1078 NULL, NULL, pbap, pbap_free)) {
1086 static void pbap_remove(struct obc_session *session)
1088 const char *path = obc_session_get_path(session);
1092 g_dbus_unregister_interface(conn, path, PBAP_INTERFACE);
1095 static struct obc_driver pbap = {
1098 .target = OBEX_PBAP_UUID,
1099 .target_len = OBEX_PBAP_UUID_LEN,
1100 .probe = pbap_probe,
1101 .remove = pbap_remove
1109 conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
1113 err = obc_driver_register(&pbap);
1115 dbus_connection_unref(conn);
1123 void pbap_exit(void)
1127 dbus_connection_unref(conn);
1130 obc_driver_unregister(&pbap);