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;
136 struct pending_request {
137 struct pbap_data *pbap;
141 struct pullphonebook_apparam {
148 uint8_t maxlistcount_tag;
149 uint8_t maxlistcount_len;
150 uint16_t maxlistcount;
151 uint8_t liststartoffset_tag;
152 uint8_t liststartoffset_len;
153 uint16_t liststartoffset;
154 } __attribute__ ((packed));
156 struct pullvcardentry_apparam {
163 } __attribute__ ((packed));
169 } __attribute__ ((packed));
171 #define APPARAM_HDR_SIZE 2
173 static DBusConnection *conn = NULL;
175 static struct pending_request *pending_request_new(struct pbap_data *pbap,
176 DBusMessage *message)
178 struct pending_request *p;
180 p = g_new0(struct pending_request, 1);
182 p->msg = dbus_message_ref(message);
187 static void pending_request_free(struct pending_request *p)
189 dbus_message_unref(p->msg);
193 static void listing_element(GMarkupParseContext *ctxt,
194 const gchar *element,
196 const gchar **values,
200 DBusMessageIter *item = user_data, entry;
202 const gchar *handle = NULL, *vcardname = NULL;
204 if (g_str_equal(element, "card") != TRUE)
207 for (key = (gchar **) names; *key; key++, values++) {
208 if (g_str_equal(*key, "handle") == TRUE)
210 else if (g_str_equal(*key, "name") == TRUE)
214 if (!handle || !vcardname)
217 dbus_message_iter_open_container(item, DBUS_TYPE_STRUCT, NULL, &entry);
218 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &handle);
219 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &vcardname);
220 dbus_message_iter_close_container(item, &entry);
223 static const GMarkupParser listing_parser = {
230 static gchar *build_phonebook_path(const char *location, const char *item)
232 gchar *path = NULL, *tmp, *tmp1;
234 if (!g_ascii_strcasecmp(location, "INT") ||
235 !g_ascii_strcasecmp(location, "INTERNAL"))
236 path = g_strdup("telecom");
237 else if (!g_ascii_strncasecmp(location, "SIM", 3)) {
238 if (strlen(location) == 3)
239 tmp = g_strdup("SIM1");
241 tmp = g_ascii_strup(location, 4);
243 path = g_build_filename(tmp, "telecom", NULL);
248 if (!g_ascii_strcasecmp(item, "PB") ||
249 !g_ascii_strcasecmp(item, "ICH") ||
250 !g_ascii_strcasecmp(item, "OCH") ||
251 !g_ascii_strcasecmp(item, "MCH") ||
252 !g_ascii_strcasecmp(item, "CCH")) {
254 tmp1 = g_ascii_strdown(item, -1);
255 path = g_build_filename(tmp, tmp1, NULL);
266 /* should only be called inside pbap_set_path */
267 static void pbap_reset_path(struct pbap_data *pbap)
272 obc_session_setpath(pbap->session, pbap->path, NULL, NULL, NULL);
275 static void pbap_setpath_cb(struct obc_session *session,
276 struct obc_transfer *transfer,
277 GError *err, void *user_data)
279 struct pending_request *request = user_data;
280 struct pbap_data *pbap = request->pbap;
283 pbap_reset_path(pbap);
286 DBusMessage *reply = g_dbus_create_error(request->msg,
289 g_dbus_send_message(conn, reply);
291 g_dbus_send_reply(conn, request->msg, DBUS_TYPE_INVALID);
293 pending_request_free(request);
296 static void read_return_apparam(struct obc_transfer *transfer,
297 guint16 *phone_book_size, guint8 *new_missed_calls)
299 const struct apparam_hdr *hdr;
302 *phone_book_size = 0;
303 *new_missed_calls = 0;
305 hdr = obc_transfer_get_params(transfer, &size);
309 if (size < APPARAM_HDR_SIZE)
312 while (size > APPARAM_HDR_SIZE) {
313 if (hdr->len > size - APPARAM_HDR_SIZE) {
314 error("Unexpected PBAP pullphonebook app"
315 " length, tag %d, len %d",
321 case PHONEBOOKSIZE_TAG:
322 if (hdr->len == PHONEBOOKSIZE_LEN) {
324 memcpy(&val, hdr->val, sizeof(val));
325 *phone_book_size = get_be16(&val);
328 case NEWMISSEDCALLS_TAG:
329 if (hdr->len == NEWMISSEDCALLS_LEN)
330 *new_missed_calls = hdr->val[0];
333 error("Unexpected PBAP pullphonebook app"
334 " parameter, tag %d, len %d",
338 size -= APPARAM_HDR_SIZE + hdr->len;
339 hdr += APPARAM_HDR_SIZE + hdr->len;
343 static void pull_phonebook_callback(struct obc_session *session,
344 struct obc_transfer *transfer,
345 GError *err, void *user_data)
347 struct pending_request *request = user_data;
354 reply = g_dbus_create_error(request->msg,
355 "org.openobex.Error.Failed",
360 perr = obc_transfer_get_contents(transfer, &contents, &size);
362 reply = g_dbus_create_error(request->msg,
363 "org.openobex.Error.Failed",
364 "Error reading contents: %s",
369 reply = dbus_message_new_method_return(request->msg);
371 dbus_message_append_args(reply,
372 DBUS_TYPE_STRING, &contents,
378 g_dbus_send_message(conn, reply);
379 pending_request_free(request);
382 static void phonebook_size_callback(struct obc_session *session,
383 struct obc_transfer *transfer,
384 GError *err, void *user_data)
386 struct pending_request *request = user_data;
388 guint16 phone_book_size;
389 guint8 new_missed_calls;
392 reply = g_dbus_create_error(request->msg,
393 "org.openobex.Error.Failed",
398 reply = dbus_message_new_method_return(request->msg);
400 read_return_apparam(transfer, &phone_book_size, &new_missed_calls);
402 dbus_message_append_args(reply,
403 DBUS_TYPE_UINT16, &phone_book_size,
407 g_dbus_send_message(conn, reply);
408 pending_request_free(request);
411 static void pull_vcard_listing_callback(struct obc_session *session,
412 struct obc_transfer *transfer,
413 GError *err, void *user_data)
415 struct pending_request *request = user_data;
416 GMarkupParseContext *ctxt;
418 DBusMessageIter iter, array;
424 reply = g_dbus_create_error(request->msg,
425 "org.openobex.Error.Failed",
430 perr = obc_transfer_get_contents(transfer, &contents, &size);
432 reply = g_dbus_create_error(request->msg,
433 "org.openobex.Error.Failed",
434 "Error reading contents: %s",
439 reply = dbus_message_new_method_return(request->msg);
441 dbus_message_iter_init_append(reply, &iter);
442 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
443 DBUS_STRUCT_BEGIN_CHAR_AS_STRING
444 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
445 DBUS_STRUCT_END_CHAR_AS_STRING, &array);
446 ctxt = g_markup_parse_context_new(&listing_parser, 0, &array, NULL);
447 g_markup_parse_context_parse(ctxt, contents, size, NULL);
448 g_markup_parse_context_free(ctxt);
449 dbus_message_iter_close_container(&iter, &array);
453 g_dbus_send_message(conn, reply);
454 pending_request_free(request);
457 static DBusMessage *pull_phonebook(struct pbap_data *pbap,
458 DBusMessage *message, guint8 type,
459 const char *name, uint64_t filter,
460 guint8 format, guint16 maxlistcount,
461 guint16 liststartoffset)
463 struct pending_request *request;
464 struct pullphonebook_apparam apparam;
465 struct obc_transfer *transfer;
466 session_callback_t func;
470 transfer = obc_transfer_get("x-bt/phonebook", name, NULL, &err);
471 if (transfer == NULL)
474 apparam.filter_tag = FILTER_TAG;
475 apparam.filter_len = FILTER_LEN;
476 apparam.filter = GUINT64_TO_BE(filter);
477 apparam.format_tag = FORMAT_TAG;
478 apparam.format_len = FORMAT_LEN;
479 apparam.format = format;
480 apparam.maxlistcount_tag = MAXLISTCOUNT_TAG;
481 apparam.maxlistcount_len = MAXLISTCOUNT_LEN;
482 apparam.maxlistcount = GUINT16_TO_BE(maxlistcount);
483 apparam.liststartoffset_tag = LISTSTARTOFFSET_TAG;
484 apparam.liststartoffset_len = LISTSTARTOFFSET_LEN;
485 apparam.liststartoffset = GUINT16_TO_BE(liststartoffset);
489 func = pull_phonebook_callback;
491 case GETPHONEBOOKSIZE:
492 func = phonebook_size_callback;
495 error("Unexpected type : 0x%2x", type);
499 request = pending_request_new(pbap, message);
501 obc_transfer_set_params(transfer, &apparam, sizeof(apparam));
503 if (obc_session_queue(pbap->session, transfer, func, request, &err))
506 pending_request_free(request);
509 reply = g_dbus_create_error(message, "org.openobex.Error.Failed", "%s",
515 static guint8 *fill_apparam(guint8 *dest, void *buf, guint8 tag, guint8 len)
520 memcpy(dest, buf, len);
527 static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
528 DBusMessage *message, const char *name,
529 guint8 order, char *searchval, guint8 attrib,
530 guint16 count, guint16 offset)
532 struct pending_request *request;
533 struct obc_transfer *transfer;
534 guint8 *p, apparam[272];
539 transfer = obc_transfer_get("x-bt/vcard-listing", name, NULL, &err);
540 if (transfer == NULL)
543 /* trunc the searchval string if it's length exceed the max value of guint8 */
544 if (strlen(searchval) > 254)
545 searchval[255] = '\0';
547 apparam_size = APPARAM_HDR_SIZE + ORDER_LEN +
548 (APPARAM_HDR_SIZE + strlen(searchval) + 1) +
549 (APPARAM_HDR_SIZE + SEARCHATTRIB_LEN) +
550 (APPARAM_HDR_SIZE + MAXLISTCOUNT_LEN) +
551 (APPARAM_HDR_SIZE + LISTSTARTOFFSET_LEN);
555 p = fill_apparam(p, &order, ORDER_TAG, ORDER_LEN);
556 p = fill_apparam(p, searchval, SEARCHVALUE_TAG, strlen(searchval) + 1);
557 p = fill_apparam(p, &attrib, SEARCHATTRIB_TAG, SEARCHATTRIB_LEN);
559 count = GUINT16_TO_BE(count);
560 p = fill_apparam(p, &count, MAXLISTCOUNT_TAG, MAXLISTCOUNT_LEN);
562 offset = GUINT16_TO_BE(offset);
563 p = fill_apparam(p, &offset, LISTSTARTOFFSET_TAG, LISTSTARTOFFSET_LEN);
565 request = pending_request_new(pbap, message);
567 obc_transfer_set_params(transfer, apparam, apparam_size);
569 if (obc_session_queue(pbap->session, transfer,
570 pull_vcard_listing_callback, request, &err))
573 pending_request_free(request);
576 reply = g_dbus_create_error(message, "org.openobex.Error.Failed", "%s",
582 static int set_format(struct pbap_data *pbap, const char *formatstr)
584 if (!formatstr || g_str_equal(formatstr, "")) {
585 pbap->format = FORMAT_VCARD21;
589 if (!g_ascii_strcasecmp(formatstr, "vcard21"))
590 pbap->format = FORMAT_VCARD21;
591 else if (!g_ascii_strcasecmp(formatstr, "vcard30"))
592 pbap->format = FORMAT_VCARD30;
599 static int set_order(struct pbap_data *pbap, const char *orderstr)
601 if (!orderstr || g_str_equal(orderstr, "")) {
602 pbap->order = ORDER_INDEXED;
606 if (!g_ascii_strcasecmp(orderstr, "indexed"))
607 pbap->order = ORDER_INDEXED;
608 else if (!g_ascii_strcasecmp(orderstr, "alphanumeric"))
609 pbap->order = ORDER_ALPHANUMERIC;
610 else if (!g_ascii_strcasecmp(orderstr, "phonetic"))
611 pbap->order = ORDER_PHONETIC;
618 static uint64_t get_filter_mask(const char *filterstr)
625 if (!g_ascii_strcasecmp(filterstr, "ALL"))
628 for (i = 0; filter_list[i] != NULL; i++)
629 if (!g_ascii_strcasecmp(filterstr, filter_list[i]))
632 if (strlen(filterstr) < 4 || strlen(filterstr) > 5
633 || g_ascii_strncasecmp(filterstr, "bit", 3) != 0)
636 sscanf(&filterstr[3], "%d", &bit);
637 if (bit >= 0 && bit <= FILTER_BIT_MAX)
643 static int add_filter(struct pbap_data *pbap, const char *filterstr)
647 mask = get_filter_mask(filterstr);
652 pbap->filter |= mask;
656 static int remove_filter(struct pbap_data *pbap, const char *filterstr)
660 mask = get_filter_mask(filterstr);
665 pbap->filter &= ~mask;
669 static gchar **get_filter_strs(uint64_t filter, gint *size)
671 gchar **list, **item;
673 gint filter_list_size = sizeof(filter_list) / sizeof(filter_list[0]) - 1;
675 list = g_try_malloc0(sizeof(gchar **) * (FILTER_BIT_MAX + 2));
682 for (i = 0; i < filter_list_size; i++)
683 if (filter & (1ULL << i))
684 *(item++) = g_strdup(filter_list[i]);
686 for (i = filter_list_size; i <= FILTER_BIT_MAX; i++)
687 if (filter & (1ULL << i))
688 *(item++) = g_strdup_printf("%s%d", "BIT", i);
695 static DBusMessage *pbap_select(DBusConnection *connection,
696 DBusMessage *message, void *user_data)
698 struct pbap_data *pbap = user_data;
699 const char *item, *location;
701 struct pending_request *request;
704 if (dbus_message_get_args(message, NULL,
705 DBUS_TYPE_STRING, &location,
706 DBUS_TYPE_STRING, &item,
707 DBUS_TYPE_INVALID) == FALSE)
708 return g_dbus_create_error(message,
709 ERROR_INF ".InvalidArguments", NULL);
711 path = build_phonebook_path(location, item);
713 return g_dbus_create_error(message,
714 ERROR_INF ".InvalidArguments", "Invalid path");
716 if (pbap->path != NULL && g_str_equal(pbap->path, path)) {
718 return dbus_message_new_method_return(message);
721 request = pending_request_new(pbap, message);
723 obc_session_setpath(pbap->session, path, pbap_setpath_cb, request,
727 reply = g_dbus_create_error(message, ERROR_INF ".Failed",
731 pending_request_free(request);
741 static DBusMessage *pbap_pull_all(DBusConnection *connection,
742 DBusMessage *message, void *user_data)
744 struct pbap_data *pbap = user_data;
749 return g_dbus_create_error(message,
750 ERROR_INF ".Forbidden", "Call Select first of all");
752 name = g_strconcat(pbap->path, ".vcf", NULL);
754 err = pull_phonebook(pbap, message, PULLPHONEBOOK, name,
755 pbap->filter, pbap->format,
756 DEFAULT_COUNT, DEFAULT_OFFSET);
761 static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
762 DBusMessage *message, void *user_data)
764 struct pbap_data *pbap = user_data;
765 struct pullvcardentry_apparam apparam;
767 struct pending_request *request;
768 struct obc_transfer *transfer;
773 return g_dbus_create_error(message,
774 ERROR_INF ".Forbidden",
775 "Call Select first of all");
777 if (dbus_message_get_args(message, NULL,
778 DBUS_TYPE_STRING, &name,
779 DBUS_TYPE_INVALID) == FALSE)
780 return g_dbus_create_error(message,
781 ERROR_INF ".InvalidArguments", NULL);
783 transfer = obc_transfer_get("x-bt/vcard", name, NULL, &err);
784 if (transfer == NULL)
787 apparam.filter_tag = FILTER_TAG;
788 apparam.filter_len = FILTER_LEN;
789 apparam.filter = GUINT64_TO_BE(pbap->filter);
790 apparam.format_tag = FORMAT_TAG;
791 apparam.format_len = FORMAT_LEN;
792 apparam.format = pbap->format;
794 request = pending_request_new(pbap, message);
796 obc_transfer_set_params(transfer, &apparam, sizeof(apparam));
798 if (obc_session_queue(pbap->session, transfer, pull_phonebook_callback,
802 pending_request_free(request);
805 reply = g_dbus_create_error(message, "org.openobex.Error.Failed", "%s",
811 static DBusMessage *pbap_list(DBusConnection *connection,
812 DBusMessage *message, void *user_data)
814 struct pbap_data *pbap = user_data;
817 return g_dbus_create_error(message,
818 ERROR_INF ".Forbidden", "Call Select first of all");
820 return pull_vcard_listing(pbap, message, "", pbap->order, "",
821 ATTRIB_NAME, DEFAULT_COUNT, DEFAULT_OFFSET);
824 static DBusMessage *pbap_search(DBusConnection *connection,
825 DBusMessage *message, void *user_data)
827 struct pbap_data *pbap = user_data;
831 if (dbus_message_get_args(message, NULL,
832 DBUS_TYPE_STRING, &field,
833 DBUS_TYPE_STRING, &value,
834 DBUS_TYPE_INVALID) == FALSE)
835 return g_dbus_create_error(message,
836 ERROR_INF ".InvalidArguments", NULL);
839 return g_dbus_create_error(message,
840 ERROR_INF ".Forbidden", "Call Select first of all");
842 if (!field || g_str_equal(field, ""))
843 attrib = ATTRIB_NAME;
844 else if (!g_ascii_strcasecmp(field, "name"))
845 attrib = ATTRIB_NAME;
846 else if (!g_ascii_strcasecmp(field, "number"))
847 attrib = ATTRIB_NUMBER;
848 else if (!g_ascii_strcasecmp(field, "sound"))
849 attrib = ATTRIB_SOUND;
851 return g_dbus_create_error(message,
852 ERROR_INF ".InvalidArguments", NULL);
854 return pull_vcard_listing(pbap, message, "", pbap->order, value,
855 attrib, DEFAULT_COUNT, DEFAULT_OFFSET);
858 static DBusMessage *pbap_get_size(DBusConnection *connection,
859 DBusMessage *message, void *user_data)
861 struct pbap_data *pbap = user_data;
866 return g_dbus_create_error(message,
867 ERROR_INF ".Forbidden", "Call Select first of all");
869 name = g_strconcat(pbap->path, ".vcf", NULL);
871 err = pull_phonebook(pbap, message, GETPHONEBOOKSIZE, name,
872 pbap->filter, pbap->format, 0,
878 static DBusMessage *pbap_set_format(DBusConnection *connection,
879 DBusMessage *message, void *user_data)
881 struct pbap_data *pbap = user_data;
884 if (dbus_message_get_args(message, NULL,
885 DBUS_TYPE_STRING, &format,
886 DBUS_TYPE_INVALID) == FALSE)
887 return g_dbus_create_error(message,
888 ERROR_INF ".InvalidArguments", NULL);
890 if (set_format(pbap, format) < 0)
891 return g_dbus_create_error(message,
892 ERROR_INF ".InvalidArguments", "InvalidFormat");
894 return dbus_message_new_method_return(message);
897 static DBusMessage *pbap_set_order(DBusConnection *connection,
898 DBusMessage *message, void *user_data)
900 struct pbap_data *pbap = user_data;
903 if (dbus_message_get_args(message, NULL,
904 DBUS_TYPE_STRING, &order,
905 DBUS_TYPE_INVALID) == FALSE)
906 return g_dbus_create_error(message,
907 ERROR_INF ".InvalidArguments", NULL);
909 if (set_order(pbap, order) < 0)
910 return g_dbus_create_error(message,
911 ERROR_INF ".InvalidArguments", "InvalidFilter");
913 return dbus_message_new_method_return(message);
916 static DBusMessage *pbap_set_filter(DBusConnection *connection,
917 DBusMessage *message, void *user_data)
919 struct pbap_data *pbap = user_data;
920 char **filters, **item;
922 uint64_t oldfilter = pbap->filter;
924 if (dbus_message_get_args(message, NULL, DBUS_TYPE_ARRAY,
925 DBUS_TYPE_STRING, &filters, &size,
926 DBUS_TYPE_INVALID) == FALSE)
927 return g_dbus_create_error(message,
928 ERROR_INF ".InvalidArguments", NULL);
930 remove_filter(pbap, "ALL");
934 for (item = filters; *item; item++) {
935 if (add_filter(pbap, *item) < 0) {
936 pbap->filter = oldfilter;
938 return g_dbus_create_error(message,
939 ERROR_INF ".InvalidArguments", "InvalidFilters");
945 return dbus_message_new_method_return(message);
948 static DBusMessage *pbap_get_filter(DBusConnection *connection,
949 DBusMessage *message, void *user_data)
951 struct pbap_data *pbap = user_data;
952 gchar **filters = NULL;
956 filters = get_filter_strs(pbap->filter, &size);
957 reply = dbus_message_new_method_return(message);
958 dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
959 DBUS_TYPE_STRING, &filters, size,
966 static DBusMessage *pbap_list_filter_fields(DBusConnection *connection,
967 DBusMessage *message, void *user_data)
969 gchar **filters = NULL;
973 filters = get_filter_strs(FILTER_ALL, &size);
974 reply = dbus_message_new_method_return(message);
975 dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
976 DBUS_TYPE_STRING, &filters, size,
983 static GDBusMethodTable pbap_methods[] = {
984 { "Select", "ss", "", pbap_select,
985 G_DBUS_METHOD_FLAG_ASYNC },
986 { "PullAll", "", "s", pbap_pull_all,
987 G_DBUS_METHOD_FLAG_ASYNC },
988 { "Pull", "s", "s", pbap_pull_vcard,
989 G_DBUS_METHOD_FLAG_ASYNC },
990 { "List", "", "a(ss)", pbap_list,
991 G_DBUS_METHOD_FLAG_ASYNC },
992 { "Search", "ss", "a(ss)", pbap_search,
993 G_DBUS_METHOD_FLAG_ASYNC },
994 { "GetSize", "", "q", pbap_get_size,
995 G_DBUS_METHOD_FLAG_ASYNC },
996 { "SetFormat", "s", "", pbap_set_format },
997 { "SetOrder", "s", "", pbap_set_order },
998 { "SetFilter", "as", "", pbap_set_filter },
999 { "GetFilter", "", "as", pbap_get_filter },
1000 { "ListFilterFields", "", "as", pbap_list_filter_fields },
1004 static void pbap_free(void *data)
1006 struct pbap_data *pbap = data;
1008 obc_session_unref(pbap->session);
1013 static int pbap_probe(struct obc_session *session)
1015 struct pbap_data *pbap;
1018 path = obc_session_get_path(session);
1022 pbap = g_try_new0(struct pbap_data, 1);
1026 pbap->session = obc_session_ref(session);
1028 if (!g_dbus_register_interface(conn, path, PBAP_INTERFACE, pbap_methods,
1029 NULL, NULL, pbap, pbap_free)) {
1037 static void pbap_remove(struct obc_session *session)
1039 const char *path = obc_session_get_path(session);
1043 g_dbus_unregister_interface(conn, path, PBAP_INTERFACE);
1046 static struct obc_driver pbap = {
1049 .target = OBEX_PBAP_UUID,
1050 .target_len = OBEX_PBAP_UUID_LEN,
1051 .probe = pbap_probe,
1052 .remove = pbap_remove
1061 conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
1065 err = obc_driver_register(&pbap);
1067 dbus_connection_unref(conn);
1075 void pbap_exit(void)
1079 dbus_connection_unref(conn);
1082 obc_driver_unregister(&pbap);