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 FORMAT_VCARD21 0x0
49 #define FORMAT_VCARD30 0x1
51 #define ORDER_INDEXED 0x0
52 #define ORDER_ALPHANUMERIC 0x1
53 #define ORDER_PHONETIC 0x2
55 #define ATTRIB_NAME 0x0
56 #define ATTRIB_NUMBER 0x1
57 #define ATTRIB_SOUND 0x2
59 #define DEFAULT_COUNT 65535
60 #define DEFAULT_OFFSET 0
62 #define PULLPHONEBOOK 0x1
63 #define GETPHONEBOOKSIZE 0x2
65 #define ORDER_TAG 0x01
66 #define SEARCHVALUE_TAG 0x02
67 #define SEARCHATTRIB_TAG 0x03
68 #define MAXLISTCOUNT_TAG 0x04
69 #define LISTSTARTOFFSET_TAG 0x05
70 #define FILTER_TAG 0x06
71 #define FORMAT_TAG 0X07
72 #define PHONEBOOKSIZE_TAG 0X08
73 #define NEWMISSEDCALLS_TAG 0X09
75 /* The following length is in the unit of byte */
77 #define SEARCHATTRIB_LEN 1
78 #define MAXLISTCOUNT_LEN 2
79 #define LISTSTARTOFFSET_LEN 2
82 #define PHONEBOOKSIZE_LEN 2
83 #define NEWMISSEDCALLS_LEN 1
85 #define get_be16(val) GUINT16_FROM_BE(bt_get_unaligned((guint16 *) val))
87 static const char *filter_list[] = {
116 "X-IRMC-CALL-DATETIME",
120 #define FILTER_BIT_MAX 63
121 #define FILTER_ALL 0xFFFFFFFFFFFFFFFFULL
123 #define PBAP_INTERFACE "org.bluez.obex.PhonebookAccess"
124 #define ERROR_INTERFACE "org.bluez.obex.Error"
125 #define PBAP_UUID "0000112f-0000-1000-8000-00805f9b34fb"
128 struct obc_session *session;
135 struct pending_request {
136 struct pbap_data *pbap;
140 struct pullphonebook_apparam {
147 uint8_t maxlistcount_tag;
148 uint8_t maxlistcount_len;
149 uint16_t maxlistcount;
150 uint8_t liststartoffset_tag;
151 uint8_t liststartoffset_len;
152 uint16_t liststartoffset;
153 } __attribute__ ((packed));
155 struct pullvcardentry_apparam {
162 } __attribute__ ((packed));
168 } __attribute__ ((packed));
170 #define APPARAM_HDR_SIZE 2
172 static DBusConnection *conn = NULL;
174 static struct pending_request *pending_request_new(struct pbap_data *pbap,
175 DBusMessage *message)
177 struct pending_request *p;
179 p = g_new0(struct pending_request, 1);
181 p->msg = dbus_message_ref(message);
186 static void pending_request_free(struct pending_request *p)
188 dbus_message_unref(p->msg);
192 static void listing_element(GMarkupParseContext *ctxt,
193 const gchar *element,
195 const gchar **values,
199 DBusMessageIter *item = user_data, entry;
201 const gchar *handle = NULL, *vcardname = NULL;
203 if (g_str_equal(element, "card") != TRUE)
206 for (key = (gchar **) names; *key; key++, values++) {
207 if (g_str_equal(*key, "handle") == TRUE)
209 else if (g_str_equal(*key, "name") == TRUE)
213 if (!handle || !vcardname)
216 dbus_message_iter_open_container(item, DBUS_TYPE_STRUCT, NULL, &entry);
217 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &handle);
218 dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &vcardname);
219 dbus_message_iter_close_container(item, &entry);
222 static const GMarkupParser listing_parser = {
229 static gchar *build_phonebook_path(const char *location, const char *item)
231 gchar *path = NULL, *tmp, *tmp1;
233 if (!g_ascii_strcasecmp(location, "INT") ||
234 !g_ascii_strcasecmp(location, "INTERNAL"))
235 path = g_strdup("telecom");
236 else if (!g_ascii_strncasecmp(location, "SIM", 3)) {
237 if (strlen(location) == 3)
238 tmp = g_strdup("SIM1");
240 tmp = g_ascii_strup(location, 4);
242 path = g_build_filename(tmp, "telecom", NULL);
247 if (!g_ascii_strcasecmp(item, "PB") ||
248 !g_ascii_strcasecmp(item, "ICH") ||
249 !g_ascii_strcasecmp(item, "OCH") ||
250 !g_ascii_strcasecmp(item, "MCH") ||
251 !g_ascii_strcasecmp(item, "CCH")) {
253 tmp1 = g_ascii_strdown(item, -1);
254 path = g_build_filename(tmp, tmp1, NULL);
265 /* should only be called inside pbap_set_path */
266 static void pbap_reset_path(struct pbap_data *pbap)
271 obc_session_setpath(pbap->session, pbap->path, NULL, NULL, NULL);
274 static void pbap_setpath_cb(struct obc_session *session,
275 struct obc_transfer *transfer,
276 GError *err, void *user_data)
278 struct pending_request *request = user_data;
279 struct pbap_data *pbap = request->pbap;
282 pbap_reset_path(pbap);
285 DBusMessage *reply = g_dbus_create_error(request->msg,
286 ERROR_INTERFACE ".Failed",
288 g_dbus_send_message(conn, reply);
290 g_dbus_send_reply(conn, request->msg, DBUS_TYPE_INVALID);
292 pending_request_free(request);
295 static void read_return_apparam(struct obc_transfer *transfer,
296 guint16 *phone_book_size, guint8 *new_missed_calls)
298 const struct apparam_hdr *hdr;
301 *phone_book_size = 0;
302 *new_missed_calls = 0;
304 hdr = obc_transfer_get_params(transfer, &size);
308 if (size < APPARAM_HDR_SIZE)
311 while (size > APPARAM_HDR_SIZE) {
312 if (hdr->len > size - APPARAM_HDR_SIZE) {
313 error("Unexpected PBAP pullphonebook app"
314 " length, tag %d, len %d",
320 case PHONEBOOKSIZE_TAG:
321 if (hdr->len == PHONEBOOKSIZE_LEN) {
323 memcpy(&val, hdr->val, sizeof(val));
324 *phone_book_size = get_be16(&val);
327 case NEWMISSEDCALLS_TAG:
328 if (hdr->len == NEWMISSEDCALLS_LEN)
329 *new_missed_calls = hdr->val[0];
332 error("Unexpected PBAP pullphonebook app"
333 " parameter, tag %d, len %d",
337 size -= APPARAM_HDR_SIZE + hdr->len;
338 hdr += APPARAM_HDR_SIZE + hdr->len;
342 static void phonebook_size_callback(struct obc_session *session,
343 struct obc_transfer *transfer,
344 GError *err, void *user_data)
346 struct pending_request *request = user_data;
348 guint16 phone_book_size;
349 guint8 new_missed_calls;
352 reply = g_dbus_create_error(request->msg,
353 ERROR_INTERFACE ".Failed",
358 reply = dbus_message_new_method_return(request->msg);
360 read_return_apparam(transfer, &phone_book_size, &new_missed_calls);
362 dbus_message_append_args(reply,
363 DBUS_TYPE_UINT16, &phone_book_size,
367 g_dbus_send_message(conn, reply);
368 pending_request_free(request);
371 static void pull_vcard_listing_callback(struct obc_session *session,
372 struct obc_transfer *transfer,
373 GError *err, void *user_data)
375 struct pending_request *request = user_data;
376 GMarkupParseContext *ctxt;
378 DBusMessageIter iter, array;
384 reply = g_dbus_create_error(request->msg,
385 ERROR_INTERFACE ".Failed",
390 perr = obc_transfer_get_contents(transfer, &contents, &size);
392 reply = g_dbus_create_error(request->msg,
393 ERROR_INTERFACE ".Failed",
394 "Error reading contents: %s",
399 reply = dbus_message_new_method_return(request->msg);
401 dbus_message_iter_init_append(reply, &iter);
402 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
403 DBUS_STRUCT_BEGIN_CHAR_AS_STRING
404 DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
405 DBUS_STRUCT_END_CHAR_AS_STRING, &array);
406 ctxt = g_markup_parse_context_new(&listing_parser, 0, &array, NULL);
407 g_markup_parse_context_parse(ctxt, contents, size, NULL);
408 g_markup_parse_context_free(ctxt);
409 dbus_message_iter_close_container(&iter, &array);
413 g_dbus_send_message(conn, reply);
414 pending_request_free(request);
417 static struct obc_transfer *pull_phonebook(struct pbap_data *pbap,
418 DBusMessage *message,
419 guint8 type, const char *name,
420 const char *targetfile,
421 uint64_t filter, guint8 format,
422 guint16 maxlistcount,
423 guint16 liststartoffset,
426 struct pending_request *request;
427 struct obc_transfer *transfer;
428 struct pullphonebook_apparam apparam;
429 session_callback_t func;
431 transfer = obc_transfer_get("x-bt/phonebook", name, targetfile, err);
432 if (transfer == NULL)
435 apparam.filter_tag = FILTER_TAG;
436 apparam.filter_len = FILTER_LEN;
437 apparam.filter = GUINT64_TO_BE(filter);
438 apparam.format_tag = FORMAT_TAG;
439 apparam.format_len = FORMAT_LEN;
440 apparam.format = format;
441 apparam.maxlistcount_tag = MAXLISTCOUNT_TAG;
442 apparam.maxlistcount_len = MAXLISTCOUNT_LEN;
443 apparam.maxlistcount = GUINT16_TO_BE(maxlistcount);
444 apparam.liststartoffset_tag = LISTSTARTOFFSET_TAG;
445 apparam.liststartoffset_len = LISTSTARTOFFSET_LEN;
446 apparam.liststartoffset = GUINT16_TO_BE(liststartoffset);
453 case GETPHONEBOOKSIZE:
454 func = phonebook_size_callback;
455 request = pending_request_new(pbap, message);
458 error("Unexpected type : 0x%2x", type);
462 obc_transfer_set_params(transfer, &apparam, sizeof(apparam));
464 if (!obc_session_queue(pbap->session, transfer, func, request, err)) {
466 pending_request_free(request);
475 static guint8 *fill_apparam(guint8 *dest, void *buf, guint8 tag, guint8 len)
480 memcpy(dest, buf, len);
487 static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
488 DBusMessage *message, const char *name,
489 guint8 order, char *searchval, guint8 attrib,
490 guint16 count, guint16 offset)
492 struct pending_request *request;
493 struct obc_transfer *transfer;
494 guint8 *p, apparam[272];
499 transfer = obc_transfer_get("x-bt/vcard-listing", name, NULL, &err);
500 if (transfer == NULL)
503 /* trunc the searchval string if it's length exceed the max value of guint8 */
504 if (strlen(searchval) > 254)
505 searchval[255] = '\0';
507 apparam_size = APPARAM_HDR_SIZE + ORDER_LEN +
508 (APPARAM_HDR_SIZE + strlen(searchval) + 1) +
509 (APPARAM_HDR_SIZE + SEARCHATTRIB_LEN) +
510 (APPARAM_HDR_SIZE + MAXLISTCOUNT_LEN) +
511 (APPARAM_HDR_SIZE + LISTSTARTOFFSET_LEN);
515 p = fill_apparam(p, &order, ORDER_TAG, ORDER_LEN);
516 p = fill_apparam(p, searchval, SEARCHVALUE_TAG, strlen(searchval) + 1);
517 p = fill_apparam(p, &attrib, SEARCHATTRIB_TAG, SEARCHATTRIB_LEN);
519 count = GUINT16_TO_BE(count);
520 p = fill_apparam(p, &count, MAXLISTCOUNT_TAG, MAXLISTCOUNT_LEN);
522 offset = GUINT16_TO_BE(offset);
523 fill_apparam(p, &offset, LISTSTARTOFFSET_TAG, LISTSTARTOFFSET_LEN);
525 request = pending_request_new(pbap, message);
527 obc_transfer_set_params(transfer, apparam, apparam_size);
529 if (obc_session_queue(pbap->session, transfer,
530 pull_vcard_listing_callback, request, &err))
533 pending_request_free(request);
536 reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
542 static int set_format(struct pbap_data *pbap, const char *formatstr)
544 if (!formatstr || g_str_equal(formatstr, "")) {
545 pbap->format = FORMAT_VCARD21;
549 if (!g_ascii_strcasecmp(formatstr, "vcard21"))
550 pbap->format = FORMAT_VCARD21;
551 else if (!g_ascii_strcasecmp(formatstr, "vcard30"))
552 pbap->format = FORMAT_VCARD30;
559 static int set_order(struct pbap_data *pbap, const char *orderstr)
561 if (!orderstr || g_str_equal(orderstr, "")) {
562 pbap->order = ORDER_INDEXED;
566 if (!g_ascii_strcasecmp(orderstr, "indexed"))
567 pbap->order = ORDER_INDEXED;
568 else if (!g_ascii_strcasecmp(orderstr, "alphanumeric"))
569 pbap->order = ORDER_ALPHANUMERIC;
570 else if (!g_ascii_strcasecmp(orderstr, "phonetic"))
571 pbap->order = ORDER_PHONETIC;
578 static uint64_t get_filter_mask(const char *filterstr)
585 if (!g_ascii_strcasecmp(filterstr, "ALL"))
588 for (i = 0; filter_list[i] != NULL; i++)
589 if (!g_ascii_strcasecmp(filterstr, filter_list[i]))
592 if (strlen(filterstr) < 4 || strlen(filterstr) > 5
593 || g_ascii_strncasecmp(filterstr, "bit", 3) != 0)
596 sscanf(&filterstr[3], "%d", &bit);
597 if (bit >= 0 && bit <= FILTER_BIT_MAX)
603 static int add_filter(struct pbap_data *pbap, const char *filterstr)
607 mask = get_filter_mask(filterstr);
612 pbap->filter |= mask;
616 static int remove_filter(struct pbap_data *pbap, const char *filterstr)
620 mask = get_filter_mask(filterstr);
625 pbap->filter &= ~mask;
629 static gchar **get_filter_strs(uint64_t filter, gint *size)
631 gchar **list, **item;
633 gint filter_list_size = sizeof(filter_list) / sizeof(filter_list[0]) - 1;
635 list = g_malloc0(sizeof(gchar **) * (FILTER_BIT_MAX + 2));
639 for (i = 0; i < filter_list_size; i++)
640 if (filter & (1ULL << i))
641 *(item++) = g_strdup(filter_list[i]);
643 for (i = filter_list_size; i <= FILTER_BIT_MAX; i++)
644 if (filter & (1ULL << i))
645 *(item++) = g_strdup_printf("%s%d", "BIT", i);
652 static DBusMessage *pbap_select(DBusConnection *connection,
653 DBusMessage *message, void *user_data)
655 struct pbap_data *pbap = user_data;
656 const char *item, *location;
658 struct pending_request *request;
661 if (dbus_message_get_args(message, NULL,
662 DBUS_TYPE_STRING, &location,
663 DBUS_TYPE_STRING, &item,
664 DBUS_TYPE_INVALID) == FALSE)
665 return g_dbus_create_error(message,
666 ERROR_INTERFACE ".InvalidArguments", NULL);
668 path = build_phonebook_path(location, item);
670 return g_dbus_create_error(message,
671 ERROR_INTERFACE ".InvalidArguments",
674 if (pbap->path != NULL && g_str_equal(pbap->path, path)) {
676 return dbus_message_new_method_return(message);
679 request = pending_request_new(pbap, message);
681 obc_session_setpath(pbap->session, path, pbap_setpath_cb, request,
685 reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed",
689 pending_request_free(request);
699 static DBusMessage *pbap_pull_all(DBusConnection *connection,
700 DBusMessage *message, void *user_data)
702 struct pbap_data *pbap = user_data;
703 struct obc_transfer *transfer;
704 const char *targetfile;
709 return g_dbus_create_error(message,
710 ERROR_INTERFACE ".Forbidden",
711 "Call Select first of all");
713 if (dbus_message_get_args(message, NULL,
714 DBUS_TYPE_STRING, &targetfile,
715 DBUS_TYPE_INVALID) == FALSE)
716 return g_dbus_create_error(message,
717 ERROR_INTERFACE ".InvalidArguments", NULL);
719 name = g_strconcat(pbap->path, ".vcf", NULL);
721 transfer = pull_phonebook(pbap, message, PULLPHONEBOOK, name,
722 targetfile, pbap->filter, pbap->format,
723 DEFAULT_COUNT, DEFAULT_OFFSET, &err);
726 if (transfer == NULL) {
727 DBusMessage *reply = g_dbus_create_error(message,
728 ERROR_INTERFACE ".Failed", "%s",
734 return obc_transfer_create_dbus_reply(transfer, message);
737 static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
738 DBusMessage *message, void *user_data)
740 struct pbap_data *pbap = user_data;
741 struct obc_transfer *transfer;
742 struct pullvcardentry_apparam apparam;
743 const char *name, *targetfile;
748 return g_dbus_create_error(message,
749 ERROR_INTERFACE ".Forbidden",
750 "Call Select first of all");
752 if (dbus_message_get_args(message, NULL,
753 DBUS_TYPE_STRING, &name,
754 DBUS_TYPE_STRING, &targetfile,
755 DBUS_TYPE_INVALID) == FALSE)
756 return g_dbus_create_error(message,
757 ERROR_INTERFACE ".InvalidArguments", NULL);
759 transfer = obc_transfer_get("x-bt/vcard", name, targetfile, &err);
760 if (transfer == NULL)
763 apparam.filter_tag = FILTER_TAG;
764 apparam.filter_len = FILTER_LEN;
765 apparam.filter = GUINT64_TO_BE(pbap->filter);
766 apparam.format_tag = FORMAT_TAG;
767 apparam.format_len = FORMAT_LEN;
768 apparam.format = pbap->format;
770 obc_transfer_set_params(transfer, &apparam, sizeof(apparam));
772 if (!obc_session_queue(pbap->session, transfer, NULL, NULL, &err))
775 return obc_transfer_create_dbus_reply(transfer, message);
778 reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
784 static DBusMessage *pbap_list(DBusConnection *connection,
785 DBusMessage *message, void *user_data)
787 struct pbap_data *pbap = user_data;
790 return g_dbus_create_error(message,
791 ERROR_INTERFACE ".Forbidden",
792 "Call Select first of all");
794 return pull_vcard_listing(pbap, message, "", pbap->order, "",
795 ATTRIB_NAME, DEFAULT_COUNT, DEFAULT_OFFSET);
798 static DBusMessage *pbap_search(DBusConnection *connection,
799 DBusMessage *message, void *user_data)
801 struct pbap_data *pbap = user_data;
805 if (dbus_message_get_args(message, NULL,
806 DBUS_TYPE_STRING, &field,
807 DBUS_TYPE_STRING, &value,
808 DBUS_TYPE_INVALID) == FALSE)
809 return g_dbus_create_error(message,
810 ERROR_INTERFACE ".InvalidArguments", NULL);
813 return g_dbus_create_error(message,
814 ERROR_INTERFACE ".Forbidden",
815 "Call Select first of all");
817 if (!field || g_str_equal(field, ""))
818 attrib = ATTRIB_NAME;
819 else if (!g_ascii_strcasecmp(field, "name"))
820 attrib = ATTRIB_NAME;
821 else if (!g_ascii_strcasecmp(field, "number"))
822 attrib = ATTRIB_NUMBER;
823 else if (!g_ascii_strcasecmp(field, "sound"))
824 attrib = ATTRIB_SOUND;
826 return g_dbus_create_error(message,
827 ERROR_INTERFACE ".InvalidArguments", NULL);
829 return pull_vcard_listing(pbap, message, "", pbap->order, value,
830 attrib, DEFAULT_COUNT, DEFAULT_OFFSET);
833 static DBusMessage *pbap_get_size(DBusConnection *connection,
834 DBusMessage *message, void *user_data)
836 struct pbap_data *pbap = user_data;
838 struct obc_transfer *transfer;
843 return g_dbus_create_error(message,
844 ERROR_INTERFACE ".Forbidden",
845 "Call Select first of all");
847 name = g_strconcat(pbap->path, ".vcf", NULL);
849 transfer = pull_phonebook(pbap, message, GETPHONEBOOKSIZE, name, NULL,
850 pbap->filter, pbap->format, 0,
851 DEFAULT_OFFSET, &err);
855 if (transfer != NULL)
858 reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
864 static DBusMessage *pbap_set_format(DBusConnection *connection,
865 DBusMessage *message, void *user_data)
867 struct pbap_data *pbap = user_data;
870 if (dbus_message_get_args(message, NULL,
871 DBUS_TYPE_STRING, &format,
872 DBUS_TYPE_INVALID) == FALSE)
873 return g_dbus_create_error(message,
874 ERROR_INTERFACE ".InvalidArguments", NULL);
876 if (set_format(pbap, format) < 0)
877 return g_dbus_create_error(message,
878 ERROR_INTERFACE ".InvalidArguments",
881 return dbus_message_new_method_return(message);
884 static DBusMessage *pbap_set_order(DBusConnection *connection,
885 DBusMessage *message, void *user_data)
887 struct pbap_data *pbap = user_data;
890 if (dbus_message_get_args(message, NULL,
891 DBUS_TYPE_STRING, &order,
892 DBUS_TYPE_INVALID) == FALSE)
893 return g_dbus_create_error(message,
894 ERROR_INTERFACE ".InvalidArguments", NULL);
896 if (set_order(pbap, order) < 0)
897 return g_dbus_create_error(message,
898 ERROR_INTERFACE ".InvalidArguments",
901 return dbus_message_new_method_return(message);
904 static DBusMessage *pbap_set_filter(DBusConnection *connection,
905 DBusMessage *message, void *user_data)
907 struct pbap_data *pbap = user_data;
908 char **filters, **item;
910 uint64_t oldfilter = pbap->filter;
912 if (dbus_message_get_args(message, NULL, DBUS_TYPE_ARRAY,
913 DBUS_TYPE_STRING, &filters, &size,
914 DBUS_TYPE_INVALID) == FALSE)
915 return g_dbus_create_error(message,
916 ERROR_INTERFACE ".InvalidArguments", NULL);
918 remove_filter(pbap, "ALL");
922 for (item = filters; *item; item++) {
923 if (add_filter(pbap, *item) < 0) {
924 pbap->filter = oldfilter;
926 return g_dbus_create_error(message,
927 ERROR_INTERFACE ".InvalidArguments",
934 return dbus_message_new_method_return(message);
937 static DBusMessage *pbap_get_filter(DBusConnection *connection,
938 DBusMessage *message, void *user_data)
940 struct pbap_data *pbap = user_data;
941 gchar **filters = NULL;
945 filters = get_filter_strs(pbap->filter, &size);
946 reply = dbus_message_new_method_return(message);
947 dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
948 DBUS_TYPE_STRING, &filters, size,
955 static DBusMessage *pbap_list_filter_fields(DBusConnection *connection,
956 DBusMessage *message, void *user_data)
958 gchar **filters = NULL;
962 filters = get_filter_strs(FILTER_ALL, &size);
963 reply = dbus_message_new_method_return(message);
964 dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
965 DBUS_TYPE_STRING, &filters, size,
972 static const GDBusMethodTable pbap_methods[] = {
973 { GDBUS_ASYNC_METHOD("Select",
974 GDBUS_ARGS({ "location", "s" }, { "phonebook", "s" }),
975 NULL, pbap_select) },
976 { GDBUS_METHOD("PullAll",
977 GDBUS_ARGS({ "targetfile", "s" }),
978 GDBUS_ARGS({ "transfer", "o" },
979 { "properties", "a{sv}" }),
981 { GDBUS_METHOD("Pull",
982 GDBUS_ARGS({ "vcard", "s" }, { "targetfile", "s" }),
983 GDBUS_ARGS({ "transfer", "o" },
984 { "properties", "a{sv}" }),
986 { GDBUS_ASYNC_METHOD("List",
987 NULL, GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
989 { GDBUS_ASYNC_METHOD("Search",
990 GDBUS_ARGS({ "field", "s" }, { "value", "s" }),
991 GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
993 { GDBUS_ASYNC_METHOD("GetSize",
994 NULL, GDBUS_ARGS({ "size", "q" }),
996 { GDBUS_METHOD("SetFormat",
997 GDBUS_ARGS({ "format", "s" }), NULL,
999 { GDBUS_METHOD("SetOrder",
1000 GDBUS_ARGS({ "order", "s" }), NULL,
1002 { GDBUS_METHOD("SetFilter",
1003 GDBUS_ARGS({ "fields", "as" }), NULL,
1005 { GDBUS_METHOD("GetFilter",
1006 NULL, GDBUS_ARGS({ "fields", "as" }),
1008 { GDBUS_METHOD("ListFilterFields",
1009 NULL, GDBUS_ARGS({ "fields", "as" }),
1010 pbap_list_filter_fields) },
1014 static void pbap_free(void *data)
1016 struct pbap_data *pbap = data;
1018 obc_session_unref(pbap->session);
1023 static int pbap_probe(struct obc_session *session)
1025 struct pbap_data *pbap;
1028 path = obc_session_get_path(session);
1032 pbap = g_try_new0(struct pbap_data, 1);
1036 pbap->session = obc_session_ref(session);
1038 if (!g_dbus_register_interface(conn, path, PBAP_INTERFACE, pbap_methods,
1039 NULL, NULL, pbap, pbap_free)) {
1047 static void pbap_remove(struct obc_session *session)
1049 const char *path = obc_session_get_path(session);
1053 g_dbus_unregister_interface(conn, path, PBAP_INTERFACE);
1056 static struct obc_driver pbap = {
1059 .target = OBEX_PBAP_UUID,
1060 .target_len = OBEX_PBAP_UUID_LEN,
1061 .probe = pbap_probe,
1062 .remove = pbap_remove
1071 conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
1075 err = obc_driver_register(&pbap);
1077 dbus_connection_unref(conn);
1085 void pbap_exit(void)
1089 dbus_connection_unref(conn);
1092 obc_driver_unregister(&pbap);