pbap.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * OBEX Client
  5. *
  6. * Copyright (C) 2007-2010 Intel Corporation
  7. * Copyright (C) 2007-2010 Marcel Holtmann <marcel@holtmann.org>
  8. *
  9. *
  10. */
  11. #ifdef HAVE_CONFIG_H
  12. #include <config.h>
  13. #endif
  14. #define _GNU_SOURCE
  15. #include <errno.h>
  16. #include <string.h>
  17. #include <stdio.h>
  18. #include <glib.h>
  19. #include "lib/bluetooth.h"
  20. #include "lib/sdp.h"
  21. #include "gobex/gobex-apparam.h"
  22. #include "gdbus/gdbus.h"
  23. #include "obexd/src/log.h"
  24. #include "transfer.h"
  25. #include "session.h"
  26. #include "driver.h"
  27. #include "pbap.h"
  28. #define OBEX_PBAP_UUID \
  29. "\x79\x61\x35\xF0\xF0\xC5\x11\xD8\x09\x66\x08\x00\x20\x0C\x9A\x66"
  30. #define OBEX_PBAP_UUID_LEN 16
  31. #define FORMAT_VCARD21 0x0
  32. #define FORMAT_VCARD30 0x1
  33. #define ORDER_INDEXED 0x0
  34. #define ORDER_ALPHANUMERIC 0x1
  35. #define ORDER_PHONETIC 0x2
  36. #define ATTRIB_NAME 0x0
  37. #define ATTRIB_NUMBER 0x1
  38. #define ATTRIB_SOUND 0x2
  39. #define DEFAULT_COUNT 65535
  40. #define DEFAULT_OFFSET 0
  41. #define PULLPHONEBOOK 0x1
  42. #define GETPHONEBOOKSIZE 0x2
  43. #define ORDER_TAG 0x01
  44. #define SEARCHVALUE_TAG 0x02
  45. #define SEARCHATTRIB_TAG 0x03
  46. #define MAXLISTCOUNT_TAG 0x04
  47. #define LISTSTARTOFFSET_TAG 0x05
  48. #define FILTER_TAG 0x06
  49. #define FORMAT_TAG 0X07
  50. #define PHONEBOOKSIZE_TAG 0X08
  51. #define NEWMISSEDCALLS_TAG 0X09
  52. #define PRIMARY_COUNTER_TAG 0X0A
  53. #define SECONDARY_COUNTER_TAG 0X0B
  54. #define DATABASEID_TAG 0X0D
  55. #define SUPPORTED_FEATURES_TAG 0x10
  56. #define DOWNLOAD_FEATURE 0x00000001
  57. #define BROWSE_FEATURE 0x00000002
  58. #define DATABASEID_FEATURE 0x00000004
  59. #define FOLDER_VERSION_FEATURE 0x00000008
  60. #define VCARD_SELECTING_FEATURE 0x00000010
  61. #define ENHANCED_CALLS_FEATURE 0x00000020
  62. #define UCI_FEATURE 0x00000040
  63. #define UID_FEATURE 0x00000080
  64. #define REFERENCING_FEATURE 0x00000100
  65. #define DEFAULT_IMAGE_FEATURE 0x00000200
  66. static const char *filter_list[] = {
  67. "VERSION",
  68. "FN",
  69. "N",
  70. "PHOTO",
  71. "BDAY",
  72. "ADR",
  73. "LABEL",
  74. "TEL",
  75. "EMAIL",
  76. "MAILER",
  77. "TZ",
  78. "GEO",
  79. "TITLE",
  80. "ROLE",
  81. "LOGO",
  82. "AGENT",
  83. "ORG",
  84. "NOTE",
  85. "REV",
  86. "SOUND",
  87. "URL",
  88. "UID",
  89. "KEY",
  90. "NICKNAME",
  91. "CATEGORIES",
  92. "PROID",
  93. "CLASS",
  94. "SORT-STRING",
  95. "X-IRMC-CALL-DATETIME",
  96. "X-BT-SPEEDDIALKEY",
  97. "X-BT-UCI",
  98. "X-BT-UID",
  99. NULL
  100. };
  101. #define FILTER_BIT_MAX 63
  102. #define FILTER_ALL 0xFFFFFFFFFFFFFFFFULL
  103. #define PBAP_INTERFACE "org.bluez.obex.PhonebookAccess1"
  104. #define ERROR_INTERFACE "org.bluez.obex.Error"
  105. #define PBAP_UUID "0000112f-0000-1000-8000-00805f9b34fb"
  106. struct pbap_data {
  107. struct obc_session *session;
  108. char *path;
  109. uint16_t version;
  110. uint32_t supported_features;
  111. uint8_t databaseid[16];
  112. uint8_t primary[16];
  113. uint8_t secondary[16];
  114. };
  115. struct pending_request {
  116. struct pbap_data *pbap;
  117. DBusMessage *msg;
  118. };
  119. static DBusConnection *conn = NULL;
  120. static struct pending_request *pending_request_new(struct pbap_data *pbap,
  121. DBusMessage *message)
  122. {
  123. struct pending_request *p;
  124. p = g_new0(struct pending_request, 1);
  125. p->pbap = pbap;
  126. p->msg = dbus_message_ref(message);
  127. return p;
  128. }
  129. static void pending_request_free(struct pending_request *p)
  130. {
  131. dbus_message_unref(p->msg);
  132. g_free(p);
  133. }
  134. static void listing_element(GMarkupParseContext *ctxt,
  135. const char *element,
  136. const char **names,
  137. const char **values,
  138. gpointer user_data,
  139. GError **gerr)
  140. {
  141. DBusMessageIter *item = user_data, entry;
  142. char **key;
  143. const char *handle = NULL, *vcardname = NULL;
  144. if (g_str_equal(element, "card") != TRUE)
  145. return;
  146. for (key = (char **) names; *key; key++, values++) {
  147. if (g_str_equal(*key, "handle") == TRUE)
  148. handle = *values;
  149. else if (g_str_equal(*key, "name") == TRUE)
  150. vcardname = *values;
  151. }
  152. if (!handle || !vcardname)
  153. return;
  154. dbus_message_iter_open_container(item, DBUS_TYPE_STRUCT, NULL, &entry);
  155. dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &handle);
  156. dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &vcardname);
  157. dbus_message_iter_close_container(item, &entry);
  158. }
  159. static const GMarkupParser listing_parser = {
  160. listing_element,
  161. NULL,
  162. NULL,
  163. NULL,
  164. NULL
  165. };
  166. static char *build_phonebook_path(const char *location, const char *item)
  167. {
  168. char *path = NULL, *tmp, *tmp1;
  169. gboolean internal = FALSE;
  170. if (!g_ascii_strcasecmp(location, "int") ||
  171. !g_ascii_strcasecmp(location, "internal")) {
  172. path = g_strdup("/telecom");
  173. internal = TRUE;
  174. } else if (!g_ascii_strncasecmp(location, "sim", 3)) {
  175. if (strlen(location) == 3)
  176. tmp = g_strdup("sim1");
  177. else
  178. tmp = g_ascii_strup(location, 4);
  179. path = g_build_filename("/", tmp, "telecom", NULL);
  180. g_free(tmp);
  181. } else
  182. return NULL;
  183. if (!g_ascii_strcasecmp(item, "pb") ||
  184. !g_ascii_strcasecmp(item, "ich") ||
  185. !g_ascii_strcasecmp(item, "och") ||
  186. !g_ascii_strcasecmp(item, "mch") ||
  187. !g_ascii_strcasecmp(item, "cch") ||
  188. (internal && !g_ascii_strcasecmp(item, "spd")) ||
  189. (internal && !g_ascii_strcasecmp(item, "fav"))) {
  190. tmp = path;
  191. tmp1 = g_ascii_strdown(item, -1);
  192. path = g_build_filename(tmp, tmp1, NULL);
  193. g_free(tmp);
  194. g_free(tmp1);
  195. } else {
  196. g_free(path);
  197. return NULL;
  198. }
  199. return path;
  200. }
  201. /* should only be called inside pbap_set_path */
  202. static void pbap_reset_path(struct pbap_data *pbap)
  203. {
  204. if (!pbap->path)
  205. return;
  206. obc_session_setpath(pbap->session, pbap->path, NULL, NULL, NULL);
  207. }
  208. static void pbap_setpath_cb(struct obc_session *session,
  209. struct obc_transfer *transfer,
  210. GError *err, void *user_data)
  211. {
  212. struct pending_request *request = user_data;
  213. struct pbap_data *pbap = request->pbap;
  214. if (err != NULL)
  215. pbap_reset_path(pbap);
  216. else
  217. g_dbus_emit_property_changed(conn,
  218. obc_session_get_path(pbap->session),
  219. PBAP_INTERFACE, "Folder");
  220. if (err) {
  221. DBusMessage *reply = g_dbus_create_error(request->msg,
  222. ERROR_INTERFACE ".Failed",
  223. "%s", err->message);
  224. g_dbus_send_message(conn, reply);
  225. } else
  226. g_dbus_send_reply(conn, request->msg, DBUS_TYPE_INVALID);
  227. pending_request_free(request);
  228. }
  229. static void read_version(struct pbap_data *pbap, GObexApparam *apparam)
  230. {
  231. const guint8 *data;
  232. uint8_t value[16];
  233. gsize len;
  234. if (!(pbap->supported_features & FOLDER_VERSION_FEATURE))
  235. return;
  236. if (!g_obex_apparam_get_bytes(apparam, PRIMARY_COUNTER_TAG, &data,
  237. &len)) {
  238. len = sizeof(value);
  239. memset(value, 0, len);
  240. data = value;
  241. }
  242. if (memcmp(pbap->primary, data, len)) {
  243. memcpy(pbap->primary, data, len);
  244. g_dbus_emit_property_changed(conn,
  245. obc_session_get_path(pbap->session),
  246. PBAP_INTERFACE, "PrimaryCounter");
  247. }
  248. if (!g_obex_apparam_get_bytes(apparam, SECONDARY_COUNTER_TAG, &data,
  249. &len)) {
  250. len = sizeof(value);
  251. memset(value, 0, len);
  252. data = value;
  253. }
  254. if (memcmp(pbap->secondary, data, len)) {
  255. memcpy(pbap->secondary, data, len);
  256. g_dbus_emit_property_changed(conn,
  257. obc_session_get_path(pbap->session),
  258. PBAP_INTERFACE, "SecondaryCounter");
  259. }
  260. }
  261. static void read_databaseid(struct pbap_data *pbap, GObexApparam *apparam)
  262. {
  263. const guint8 *data;
  264. guint8 value[16];
  265. gsize len;
  266. if (!(pbap->supported_features & DATABASEID_FEATURE))
  267. return;
  268. if (!g_obex_apparam_get_bytes(apparam, DATABASEID_TAG, &data, &len)) {
  269. len = sizeof(value);
  270. memset(value, 0, len);
  271. data = value;
  272. }
  273. if (memcmp(data, pbap->databaseid, len)) {
  274. memcpy(pbap->databaseid, data, len);
  275. g_dbus_emit_property_changed(conn,
  276. obc_session_get_path(pbap->session),
  277. PBAP_INTERFACE, "DatabaseIdentifier");
  278. }
  279. }
  280. static void read_return_apparam(struct obc_transfer *transfer,
  281. struct pbap_data *pbap,
  282. guint16 *phone_book_size,
  283. guint8 *new_missed_calls)
  284. {
  285. GObexApparam *apparam;
  286. *phone_book_size = 0;
  287. *new_missed_calls = 0;
  288. apparam = obc_transfer_get_apparam(transfer);
  289. if (apparam == NULL)
  290. return;
  291. g_obex_apparam_get_uint16(apparam, PHONEBOOKSIZE_TAG,
  292. phone_book_size);
  293. g_obex_apparam_get_uint8(apparam, NEWMISSEDCALLS_TAG,
  294. new_missed_calls);
  295. read_version(pbap, apparam);
  296. read_databaseid(pbap, apparam);
  297. }
  298. static void phonebook_size_callback(struct obc_session *session,
  299. struct obc_transfer *transfer,
  300. GError *err, void *user_data)
  301. {
  302. struct pending_request *request = user_data;
  303. DBusMessage *reply;
  304. guint16 phone_book_size;
  305. guint8 new_missed_calls;
  306. if (err) {
  307. reply = g_dbus_create_error(request->msg,
  308. ERROR_INTERFACE ".Failed",
  309. "%s", err->message);
  310. goto send;
  311. }
  312. reply = dbus_message_new_method_return(request->msg);
  313. read_return_apparam(transfer, request->pbap, &phone_book_size,
  314. &new_missed_calls);
  315. if (dbus_message_is_method_call(request->msg, PBAP_INTERFACE,
  316. "GetSize"))
  317. dbus_message_append_args(reply,
  318. DBUS_TYPE_UINT16, &phone_book_size,
  319. DBUS_TYPE_INVALID);
  320. send:
  321. g_dbus_send_message(conn, reply);
  322. pending_request_free(request);
  323. }
  324. static void pull_vcard_listing_callback(struct obc_session *session,
  325. struct obc_transfer *transfer,
  326. GError *err, void *user_data)
  327. {
  328. struct pending_request *request = user_data;
  329. GMarkupParseContext *ctxt;
  330. DBusMessage *reply;
  331. DBusMessageIter iter, array;
  332. char *contents;
  333. size_t size;
  334. int perr;
  335. if (err) {
  336. reply = g_dbus_create_error(request->msg,
  337. ERROR_INTERFACE ".Failed",
  338. "%s", err->message);
  339. goto send;
  340. }
  341. perr = obc_transfer_get_contents(transfer, &contents, &size);
  342. if (perr < 0) {
  343. reply = g_dbus_create_error(request->msg,
  344. ERROR_INTERFACE ".Failed",
  345. "Error reading contents: %s",
  346. strerror(-perr));
  347. goto send;
  348. }
  349. reply = dbus_message_new_method_return(request->msg);
  350. dbus_message_iter_init_append(reply, &iter);
  351. dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
  352. DBUS_STRUCT_BEGIN_CHAR_AS_STRING
  353. DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
  354. DBUS_STRUCT_END_CHAR_AS_STRING, &array);
  355. ctxt = g_markup_parse_context_new(&listing_parser, 0, &array, NULL);
  356. g_markup_parse_context_parse(ctxt, contents, size, NULL);
  357. g_markup_parse_context_free(ctxt);
  358. dbus_message_iter_close_container(&iter, &array);
  359. g_free(contents);
  360. send:
  361. g_dbus_send_message(conn, reply);
  362. pending_request_free(request);
  363. }
  364. static GObexApparam *parse_format(GObexApparam *apparam, DBusMessageIter *iter)
  365. {
  366. const char *string;
  367. guint8 format;
  368. if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
  369. return NULL;
  370. dbus_message_iter_get_basic(iter, &string);
  371. if (!string || g_str_equal(string, ""))
  372. format = FORMAT_VCARD21;
  373. else if (!g_ascii_strcasecmp(string, "vcard21"))
  374. format = FORMAT_VCARD21;
  375. else if (!g_ascii_strcasecmp(string, "vcard30"))
  376. format = FORMAT_VCARD30;
  377. else
  378. return NULL;
  379. return g_obex_apparam_set_uint8(apparam, FORMAT_TAG, format);
  380. }
  381. static GObexApparam *parse_order(GObexApparam *apparam, DBusMessageIter *iter)
  382. {
  383. const char *string;
  384. guint8 order;
  385. if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
  386. return NULL;
  387. dbus_message_iter_get_basic(iter, &string);
  388. if (!string || g_str_equal(string, ""))
  389. order = ORDER_INDEXED;
  390. else if (!g_ascii_strcasecmp(string, "indexed"))
  391. order = ORDER_INDEXED;
  392. else if (!g_ascii_strcasecmp(string, "alphanumeric"))
  393. order = ORDER_ALPHANUMERIC;
  394. else if (!g_ascii_strcasecmp(string, "phonetic"))
  395. order = ORDER_PHONETIC;
  396. else
  397. return NULL;
  398. return g_obex_apparam_set_uint8(apparam, ORDER_TAG, order);
  399. }
  400. static GObexApparam *parse_offset(GObexApparam *apparam, DBusMessageIter *iter)
  401. {
  402. guint16 num;
  403. if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
  404. return NULL;
  405. dbus_message_iter_get_basic(iter, &num);
  406. return g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG, num);
  407. }
  408. static GObexApparam *parse_max_count(GObexApparam *apparam,
  409. DBusMessageIter *iter)
  410. {
  411. guint16 num;
  412. if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
  413. return NULL;
  414. dbus_message_iter_get_basic(iter, &num);
  415. return g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG, num);
  416. }
  417. static uint64_t get_filter_mask(const char *filterstr)
  418. {
  419. int i, bit = -1;
  420. if (!filterstr)
  421. return 0;
  422. if (!g_ascii_strcasecmp(filterstr, "ALL"))
  423. return FILTER_ALL;
  424. for (i = 0; filter_list[i] != NULL; i++)
  425. if (!g_ascii_strcasecmp(filterstr, filter_list[i]))
  426. return 1ULL << i;
  427. if (strlen(filterstr) < 4 || strlen(filterstr) > 5
  428. || g_ascii_strncasecmp(filterstr, "bit", 3) != 0)
  429. return 0;
  430. sscanf(&filterstr[3], "%d", &bit);
  431. if (bit >= 0 && bit <= FILTER_BIT_MAX)
  432. return 1ULL << bit;
  433. else
  434. return 0;
  435. }
  436. static int set_field(guint64 *filter, const char *filterstr)
  437. {
  438. guint64 mask;
  439. mask = get_filter_mask(filterstr);
  440. if (mask == 0)
  441. return -EINVAL;
  442. *filter |= mask;
  443. return 0;
  444. }
  445. static GObexApparam *parse_fields(GObexApparam *apparam, DBusMessageIter *iter)
  446. {
  447. DBusMessageIter array;
  448. guint64 filter = 0;
  449. if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
  450. return NULL;
  451. dbus_message_iter_recurse(iter, &array);
  452. while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
  453. const char *string;
  454. dbus_message_iter_get_basic(&array, &string);
  455. if (set_field(&filter, string) < 0)
  456. return NULL;
  457. dbus_message_iter_next(&array);
  458. }
  459. return g_obex_apparam_set_uint64(apparam, FILTER_TAG, filter);
  460. }
  461. static GObexApparam *parse_filters(GObexApparam *apparam,
  462. DBusMessageIter *iter)
  463. {
  464. DBusMessageIter array;
  465. if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
  466. return NULL;
  467. dbus_message_iter_recurse(iter, &array);
  468. while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
  469. const char *key;
  470. DBusMessageIter value, entry;
  471. dbus_message_iter_recurse(&array, &entry);
  472. dbus_message_iter_get_basic(&entry, &key);
  473. dbus_message_iter_next(&entry);
  474. dbus_message_iter_recurse(&entry, &value);
  475. if (strcasecmp(key, "Format") == 0) {
  476. if (parse_format(apparam, &value) == NULL)
  477. return NULL;
  478. } else if (strcasecmp(key, "Order") == 0) {
  479. if (parse_order(apparam, &value) == NULL)
  480. return NULL;
  481. } else if (strcasecmp(key, "Offset") == 0) {
  482. if (parse_offset(apparam, &value) == NULL)
  483. return NULL;
  484. } else if (strcasecmp(key, "MaxCount") == 0) {
  485. if (parse_max_count(apparam, &value) == NULL)
  486. return NULL;
  487. } else if (strcasecmp(key, "Fields") == 0) {
  488. if (parse_fields(apparam, &value) == NULL)
  489. return NULL;
  490. }
  491. dbus_message_iter_next(&array);
  492. }
  493. return apparam;
  494. }
  495. static DBusMessage *pull_phonebook(struct pbap_data *pbap,
  496. DBusMessage *message,
  497. guint8 type,
  498. const char *targetfile,
  499. GObexApparam *apparam)
  500. {
  501. struct pending_request *request;
  502. struct obc_transfer *transfer;
  503. char *name;
  504. session_callback_t func;
  505. DBusMessage *reply;
  506. GError *err = NULL;
  507. name = g_strconcat(g_path_skip_root(pbap->path), ".vcf", NULL);
  508. transfer = obc_transfer_get("x-bt/phonebook", name, targetfile, &err);
  509. if (transfer == NULL) {
  510. g_obex_apparam_free(apparam);
  511. goto fail;
  512. }
  513. switch (type) {
  514. case PULLPHONEBOOK:
  515. func = NULL;
  516. request = NULL;
  517. break;
  518. case GETPHONEBOOKSIZE:
  519. func = phonebook_size_callback;
  520. request = pending_request_new(pbap, message);
  521. break;
  522. default:
  523. error("Unexpected type : 0x%2x", type);
  524. return NULL;
  525. }
  526. obc_transfer_set_apparam(transfer, apparam);
  527. if (!obc_session_queue(pbap->session, transfer, func, request, &err)) {
  528. if (request != NULL)
  529. pending_request_free(request);
  530. goto fail;
  531. }
  532. g_free(name);
  533. if (targetfile == NULL)
  534. return NULL;
  535. return obc_transfer_create_dbus_reply(transfer, message);
  536. fail:
  537. g_free(name);
  538. reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
  539. err->message);
  540. g_error_free(err);
  541. return reply;
  542. }
  543. static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
  544. DBusMessage *message, const char *name,
  545. GObexApparam *apparam)
  546. {
  547. struct pending_request *request;
  548. struct obc_transfer *transfer;
  549. GError *err = NULL;
  550. DBusMessage *reply;
  551. transfer = obc_transfer_get("x-bt/vcard-listing", name, NULL, &err);
  552. if (transfer == NULL) {
  553. g_obex_apparam_free(apparam);
  554. goto fail;
  555. }
  556. obc_transfer_set_apparam(transfer, apparam);
  557. request = pending_request_new(pbap, message);
  558. if (obc_session_queue(pbap->session, transfer,
  559. pull_vcard_listing_callback, request, &err))
  560. return NULL;
  561. pending_request_free(request);
  562. fail:
  563. reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
  564. err->message);
  565. g_error_free(err);
  566. return reply;
  567. }
  568. static DBusMessage *pbap_select(DBusConnection *connection,
  569. DBusMessage *message, void *user_data)
  570. {
  571. struct pbap_data *pbap = user_data;
  572. const char *item, *location;
  573. char *path;
  574. struct pending_request *request;
  575. GError *err = NULL;
  576. if (dbus_message_get_args(message, NULL,
  577. DBUS_TYPE_STRING, &location,
  578. DBUS_TYPE_STRING, &item,
  579. DBUS_TYPE_INVALID) == FALSE)
  580. return g_dbus_create_error(message,
  581. ERROR_INTERFACE ".InvalidArguments", NULL);
  582. path = build_phonebook_path(location, item);
  583. if (path == NULL)
  584. return g_dbus_create_error(message,
  585. ERROR_INTERFACE ".InvalidArguments",
  586. "Invalid path");
  587. if (pbap->path != NULL && g_str_equal(pbap->path, path)) {
  588. g_free(path);
  589. return dbus_message_new_method_return(message);
  590. }
  591. request = pending_request_new(pbap, message);
  592. obc_session_setpath(pbap->session, path, pbap_setpath_cb, request,
  593. &err);
  594. if (err != NULL) {
  595. DBusMessage *reply;
  596. reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed",
  597. "%s", err->message);
  598. g_error_free(err);
  599. g_free(path);
  600. pending_request_free(request);
  601. return reply;
  602. }
  603. g_free(pbap->path);
  604. pbap->path = path;
  605. return NULL;
  606. }
  607. static DBusMessage *pbap_pull_all(DBusConnection *connection,
  608. DBusMessage *message, void *user_data)
  609. {
  610. struct pbap_data *pbap = user_data;
  611. const char *targetfile;
  612. GObexApparam *apparam;
  613. DBusMessageIter args;
  614. if (!pbap->path)
  615. return g_dbus_create_error(message,
  616. ERROR_INTERFACE ".Forbidden",
  617. "Call Select first of all");
  618. dbus_message_iter_init(message, &args);
  619. if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
  620. return g_dbus_create_error(message,
  621. ERROR_INTERFACE ".InvalidArguments", NULL);
  622. dbus_message_iter_get_basic(&args, &targetfile);
  623. dbus_message_iter_next(&args);
  624. apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
  625. DEFAULT_COUNT);
  626. apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
  627. DEFAULT_OFFSET);
  628. if (parse_filters(apparam, &args) == NULL) {
  629. g_obex_apparam_free(apparam);
  630. return g_dbus_create_error(message,
  631. ERROR_INTERFACE ".InvalidArguments", NULL);
  632. }
  633. return pull_phonebook(pbap, message, PULLPHONEBOOK, targetfile,
  634. apparam);
  635. }
  636. static DBusMessage *pull_vcard(struct pbap_data *pbap, DBusMessage *message,
  637. const char *name, const char *targetfile,
  638. GObexApparam *apparam)
  639. {
  640. struct obc_transfer *transfer;
  641. DBusMessage *reply;
  642. GError *err = NULL;
  643. transfer = obc_transfer_get("x-bt/vcard", name, targetfile, &err);
  644. if (transfer == NULL) {
  645. g_obex_apparam_free(apparam);
  646. goto fail;
  647. }
  648. obc_transfer_set_apparam(transfer, apparam);
  649. if (!obc_session_queue(pbap->session, transfer, NULL, NULL, &err))
  650. goto fail;
  651. return obc_transfer_create_dbus_reply(transfer, message);
  652. fail:
  653. reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
  654. err->message);
  655. g_error_free(err);
  656. return reply;
  657. }
  658. static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
  659. DBusMessage *message, void *user_data)
  660. {
  661. struct pbap_data *pbap = user_data;
  662. GObexApparam *apparam;
  663. const char *name, *targetfile;
  664. DBusMessageIter args;
  665. if (!pbap->path)
  666. return g_dbus_create_error(message,
  667. ERROR_INTERFACE ".Forbidden",
  668. "Call Select first of all");
  669. dbus_message_iter_init(message, &args);
  670. if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
  671. return g_dbus_create_error(message,
  672. ERROR_INTERFACE ".InvalidArguments", NULL);
  673. dbus_message_iter_get_basic(&args, &name);
  674. dbus_message_iter_next(&args);
  675. if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
  676. return g_dbus_create_error(message,
  677. ERROR_INTERFACE ".InvalidArguments", NULL);
  678. dbus_message_iter_get_basic(&args, &targetfile);
  679. dbus_message_iter_next(&args);
  680. apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
  681. DEFAULT_COUNT);
  682. apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
  683. DEFAULT_OFFSET);
  684. if (parse_filters(apparam, &args) == NULL) {
  685. g_obex_apparam_free(apparam);
  686. return g_dbus_create_error(message,
  687. ERROR_INTERFACE ".InvalidArguments", NULL);
  688. }
  689. return pull_vcard(pbap, message, name, targetfile, apparam);
  690. }
  691. static DBusMessage *pbap_list(DBusConnection *connection,
  692. DBusMessage *message, void *user_data)
  693. {
  694. struct pbap_data *pbap = user_data;
  695. GObexApparam *apparam;
  696. DBusMessageIter args;
  697. if (!pbap->path)
  698. return g_dbus_create_error(message,
  699. ERROR_INTERFACE ".Forbidden",
  700. "Call Select first of all");
  701. dbus_message_iter_init(message, &args);
  702. apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
  703. DEFAULT_COUNT);
  704. apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
  705. DEFAULT_OFFSET);
  706. if (parse_filters(apparam, &args) == NULL) {
  707. g_obex_apparam_free(apparam);
  708. return g_dbus_create_error(message,
  709. ERROR_INTERFACE ".InvalidArguments", NULL);
  710. }
  711. return pull_vcard_listing(pbap, message, "", apparam);
  712. }
  713. static GObexApparam *parse_attribute(GObexApparam *apparam, const char *field)
  714. {
  715. guint8 attrib;
  716. if (!field || g_str_equal(field, ""))
  717. attrib = ATTRIB_NAME;
  718. else if (!g_ascii_strcasecmp(field, "name"))
  719. attrib = ATTRIB_NAME;
  720. else if (!g_ascii_strcasecmp(field, "number"))
  721. attrib = ATTRIB_NUMBER;
  722. else if (!g_ascii_strcasecmp(field, "sound"))
  723. attrib = ATTRIB_SOUND;
  724. else
  725. return NULL;
  726. return g_obex_apparam_set_uint8(apparam, SEARCHATTRIB_TAG, attrib);
  727. }
  728. static DBusMessage *pbap_search(DBusConnection *connection,
  729. DBusMessage *message, void *user_data)
  730. {
  731. struct pbap_data *pbap = user_data;
  732. char *field, *value;
  733. GObexApparam *apparam;
  734. DBusMessageIter args;
  735. if (!pbap->path)
  736. return g_dbus_create_error(message,
  737. ERROR_INTERFACE ".Forbidden",
  738. "Call Select first of all");
  739. dbus_message_iter_init(message, &args);
  740. if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
  741. return g_dbus_create_error(message,
  742. ERROR_INTERFACE ".InvalidArguments", NULL);
  743. dbus_message_iter_get_basic(&args, &field);
  744. dbus_message_iter_next(&args);
  745. apparam = parse_attribute(NULL, field);
  746. if (apparam == NULL)
  747. return g_dbus_create_error(message,
  748. ERROR_INTERFACE ".InvalidArguments", NULL);
  749. if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
  750. return g_dbus_create_error(message,
  751. ERROR_INTERFACE ".InvalidArguments", NULL);
  752. dbus_message_iter_get_basic(&args, &value);
  753. dbus_message_iter_next(&args);
  754. apparam = g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG,
  755. DEFAULT_COUNT);
  756. apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
  757. DEFAULT_OFFSET);
  758. apparam = g_obex_apparam_set_string(apparam, SEARCHVALUE_TAG, value);
  759. if (parse_filters(apparam, &args) == NULL) {
  760. g_obex_apparam_free(apparam);
  761. return g_dbus_create_error(message,
  762. ERROR_INTERFACE ".InvalidArguments", NULL);
  763. }
  764. return pull_vcard_listing(pbap, message, "", apparam);
  765. }
  766. static DBusMessage *pbap_get_size(DBusConnection *connection,
  767. DBusMessage *message, void *user_data)
  768. {
  769. struct pbap_data *pbap = user_data;
  770. GObexApparam *apparam;
  771. DBusMessageIter args;
  772. if (!pbap->path)
  773. return g_dbus_create_error(message,
  774. ERROR_INTERFACE ".Forbidden",
  775. "Call Select first of all");
  776. dbus_message_iter_init(message, &args);
  777. apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG, 0);
  778. apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
  779. DEFAULT_OFFSET);
  780. return pull_phonebook(pbap, message, GETPHONEBOOKSIZE, NULL, apparam);
  781. }
  782. static char **get_filter_strs(uint64_t filter, int *size)
  783. {
  784. char **list, **item;
  785. int i;
  786. list = g_malloc0(sizeof(char **) * (FILTER_BIT_MAX + 2));
  787. item = list;
  788. for (i = 0; filter_list[i] != NULL; i++)
  789. if (filter & (1ULL << i))
  790. *(item++) = g_strdup(filter_list[i]);
  791. for (; i <= FILTER_BIT_MAX; i++)
  792. if (filter & (1ULL << i))
  793. *(item++) = g_strdup_printf("%s%d", "BIT", i);
  794. *item = NULL;
  795. *size = item - list;
  796. return list;
  797. }
  798. static DBusMessage *pbap_list_filter_fields(DBusConnection *connection,
  799. DBusMessage *message, void *user_data)
  800. {
  801. char **filters = NULL;
  802. int size;
  803. DBusMessage *reply;
  804. filters = get_filter_strs(FILTER_ALL, &size);
  805. reply = dbus_message_new_method_return(message);
  806. dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
  807. DBUS_TYPE_STRING, &filters, size,
  808. DBUS_TYPE_INVALID);
  809. g_strfreev(filters);
  810. return reply;
  811. }
  812. static DBusMessage *pbap_update_version(DBusConnection *connection,
  813. DBusMessage *message, void *user_data)
  814. {
  815. struct pbap_data *pbap = user_data;
  816. if (!(pbap->supported_features & FOLDER_VERSION_FEATURE))
  817. return g_dbus_create_error(message,
  818. ERROR_INTERFACE ".NotSupported",
  819. "Operation is not supported");
  820. return pbap_get_size(connection, message, user_data);
  821. }
  822. static const GDBusMethodTable pbap_methods[] = {
  823. { GDBUS_ASYNC_METHOD("Select",
  824. GDBUS_ARGS({ "location", "s" }, { "phonebook", "s" }),
  825. NULL, pbap_select) },
  826. { GDBUS_METHOD("PullAll",
  827. GDBUS_ARGS({ "targetfile", "s" },
  828. { "filters", "a{sv}" }),
  829. GDBUS_ARGS({ "transfer", "o" },
  830. { "properties", "a{sv}" }),
  831. pbap_pull_all) },
  832. { GDBUS_METHOD("Pull",
  833. GDBUS_ARGS({ "vcard", "s" }, { "targetfile", "s" },
  834. { "filters", "a{sv}" }),
  835. GDBUS_ARGS({ "transfer", "o" },
  836. { "properties", "a{sv}" }),
  837. pbap_pull_vcard) },
  838. { GDBUS_ASYNC_METHOD("List",
  839. GDBUS_ARGS({ "filters", "a{sv}" }),
  840. GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
  841. pbap_list) },
  842. { GDBUS_ASYNC_METHOD("Search",
  843. GDBUS_ARGS({ "field", "s" }, { "value", "s" },
  844. { "filters", "a{sv}" }),
  845. GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
  846. pbap_search) },
  847. { GDBUS_ASYNC_METHOD("GetSize",
  848. NULL, GDBUS_ARGS({ "size", "q" }),
  849. pbap_get_size) },
  850. { GDBUS_METHOD("ListFilterFields",
  851. NULL, GDBUS_ARGS({ "fields", "as" }),
  852. pbap_list_filter_fields) },
  853. { GDBUS_ASYNC_METHOD("UpdateVersion", NULL, NULL,
  854. pbap_update_version) },
  855. { }
  856. };
  857. static gboolean folder_exists(const GDBusPropertyTable *property, void *data)
  858. {
  859. struct pbap_data *pbap = data;
  860. return pbap->path != NULL;
  861. }
  862. static gboolean get_folder(const GDBusPropertyTable *property,
  863. DBusMessageIter *iter, void *data)
  864. {
  865. struct pbap_data *pbap = data;
  866. if (!pbap->path)
  867. return FALSE;
  868. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &pbap->path);
  869. return TRUE;
  870. }
  871. static gboolean databaseid_exists(const GDBusPropertyTable *property,
  872. void *data)
  873. {
  874. struct pbap_data *pbap = data;
  875. return pbap->supported_features & DATABASEID_FEATURE;
  876. }
  877. static int u128_to_string(uint8_t *data, char *str, size_t len)
  878. {
  879. return snprintf(str, len, "%02X%02X%02X%02X%02X%02X%02X%02X"
  880. "%02X%02X%02X%02X%02X%02X%02X%02X",
  881. data[0], data[1], data[2], data[3],
  882. data[3], data[5], data[6], data[7],
  883. data[8], data[9], data[10], data[11],
  884. data[12], data[13], data[14], data[15]);
  885. }
  886. static gboolean get_databaseid(const GDBusPropertyTable *property,
  887. DBusMessageIter *iter, void *data)
  888. {
  889. struct pbap_data *pbap = data;
  890. char value[33];
  891. const char *pvalue = value;
  892. if (u128_to_string(pbap->databaseid, value, sizeof(value)) < 0)
  893. return FALSE;
  894. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &pvalue);
  895. return TRUE;
  896. }
  897. static gboolean version_exists(const GDBusPropertyTable *property,
  898. void *data)
  899. {
  900. struct pbap_data *pbap = data;
  901. return pbap->supported_features & FOLDER_VERSION_FEATURE;
  902. }
  903. static gboolean get_primary(const GDBusPropertyTable *property,
  904. DBusMessageIter *iter, void *data)
  905. {
  906. struct pbap_data *pbap = data;
  907. char value[33];
  908. const char *pvalue = value;
  909. if (u128_to_string(pbap->primary, value, sizeof(value)) < 0)
  910. return FALSE;
  911. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &pvalue);
  912. return TRUE;
  913. }
  914. static gboolean get_secondary(const GDBusPropertyTable *property,
  915. DBusMessageIter *iter, void *data)
  916. {
  917. struct pbap_data *pbap = data;
  918. char value[33];
  919. const char *pvalue = value;
  920. if (u128_to_string(pbap->secondary, value, sizeof(value)) < 0)
  921. return FALSE;
  922. dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &pvalue);
  923. return TRUE;
  924. }
  925. static gboolean image_size_exists(const GDBusPropertyTable *property,
  926. void *data)
  927. {
  928. struct pbap_data *pbap = data;
  929. return pbap->supported_features & DEFAULT_IMAGE_FEATURE;
  930. }
  931. static gboolean get_image_size(const GDBusPropertyTable *property,
  932. DBusMessageIter *iter, void *data)
  933. {
  934. dbus_bool_t value = TRUE;
  935. dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
  936. return TRUE;
  937. }
  938. static const GDBusPropertyTable pbap_properties[] = {
  939. { "Folder", "s", get_folder, NULL, folder_exists },
  940. { "DatabaseIdentifier", "s", get_databaseid, NULL, databaseid_exists },
  941. { "PrimaryCounter", "s", get_primary, NULL, version_exists },
  942. { "SecondaryCounter", "s", get_secondary, NULL, version_exists },
  943. { "FixedImageSize", "b", get_image_size, NULL, image_size_exists },
  944. { }
  945. };
  946. static void pbap_free(void *data)
  947. {
  948. struct pbap_data *pbap = data;
  949. obc_session_unref(pbap->session);
  950. g_free(pbap->path);
  951. g_free(pbap);
  952. }
  953. static void parse_service_record(struct pbap_data *pbap)
  954. {
  955. const void *data;
  956. /* Version */
  957. data = obc_session_get_attribute(pbap->session,
  958. SDP_ATTR_PFILE_DESC_LIST);
  959. if (!data)
  960. return;
  961. pbap->version = GPOINTER_TO_UINT(data);
  962. /*
  963. * If the PbapSupportedFeatures attribute is not present
  964. * 0x00000003 shall be assumed for a remote PSE.
  965. */
  966. pbap->supported_features = 0x00000003;
  967. if (pbap->version < 0x0102)
  968. return;
  969. /* Supported Feature Bits */
  970. data = obc_session_get_attribute(pbap->session,
  971. SDP_ATTR_PBAP_SUPPORTED_FEATURES);
  972. if (data)
  973. pbap->supported_features = *(uint32_t *) data;
  974. }
  975. static void *pbap_supported_features(struct obc_session *session)
  976. {
  977. const void *data;
  978. uint16_t version;
  979. /* Version */
  980. data = obc_session_get_attribute(session, SDP_ATTR_PFILE_DESC_LIST);
  981. if (!data)
  982. return NULL;
  983. version = GPOINTER_TO_UINT(data);
  984. if (version < 0x0102)
  985. return NULL;
  986. /* Supported Feature Bits */
  987. data = obc_session_get_attribute(session,
  988. SDP_ATTR_PBAP_SUPPORTED_FEATURES);
  989. if (!data)
  990. return NULL;
  991. return g_obex_apparam_set_uint32(NULL, SUPPORTED_FEATURES_TAG,
  992. DOWNLOAD_FEATURE |
  993. BROWSE_FEATURE |
  994. DATABASEID_FEATURE |
  995. FOLDER_VERSION_FEATURE |
  996. VCARD_SELECTING_FEATURE |
  997. ENHANCED_CALLS_FEATURE |
  998. UCI_FEATURE |
  999. UID_FEATURE |
  1000. REFERENCING_FEATURE |
  1001. DEFAULT_IMAGE_FEATURE);
  1002. }
  1003. static int pbap_probe(struct obc_session *session)
  1004. {
  1005. struct pbap_data *pbap;
  1006. const char *path;
  1007. path = obc_session_get_path(session);
  1008. DBG("%s", path);
  1009. pbap = g_try_new0(struct pbap_data, 1);
  1010. if (!pbap)
  1011. return -ENOMEM;
  1012. pbap->session = obc_session_ref(session);
  1013. parse_service_record(pbap);
  1014. DBG("%s, version 0x%04x supported features 0x%08x", path, pbap->version,
  1015. pbap->supported_features);
  1016. if (!g_dbus_register_interface(conn, path, PBAP_INTERFACE, pbap_methods,
  1017. NULL, pbap_properties, pbap,
  1018. pbap_free)) {
  1019. pbap_free(pbap);
  1020. return -ENOMEM;
  1021. }
  1022. return 0;
  1023. }
  1024. static void pbap_remove(struct obc_session *session)
  1025. {
  1026. const char *path = obc_session_get_path(session);
  1027. DBG("%s", path);
  1028. g_dbus_unregister_interface(conn, path, PBAP_INTERFACE);
  1029. }
  1030. static struct obc_driver pbap = {
  1031. .service = "PBAP",
  1032. .uuid = PBAP_UUID,
  1033. .target = OBEX_PBAP_UUID,
  1034. .target_len = OBEX_PBAP_UUID_LEN,
  1035. .supported_features = pbap_supported_features,
  1036. .probe = pbap_probe,
  1037. .remove = pbap_remove
  1038. };
  1039. int pbap_init(void)
  1040. {
  1041. int err;
  1042. DBG("");
  1043. conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
  1044. if (!conn)
  1045. return -EIO;
  1046. err = obc_driver_register(&pbap);
  1047. if (err < 0) {
  1048. dbus_connection_unref(conn);
  1049. conn = NULL;
  1050. return err;
  1051. }
  1052. return 0;
  1053. }
  1054. void pbap_exit(void)
  1055. {
  1056. DBG("");
  1057. dbus_connection_unref(conn);
  1058. conn = NULL;
  1059. obc_driver_unregister(&pbap);
  1060. }