pbap.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. *
  4. * OBEX Server
  5. *
  6. * Copyright (C) 2009-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. #include <stdio.h>
  15. #include <string.h>
  16. #include <errno.h>
  17. #include <glib.h>
  18. #include <stdlib.h>
  19. #include <unistd.h>
  20. #include <arpa/inet.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <fcntl.h>
  24. #include <inttypes.h>
  25. #include "gobex/gobex.h"
  26. #include "gobex/gobex-apparam.h"
  27. #include "obexd/src/obexd.h"
  28. #include "obexd/src/plugin.h"
  29. #include "obexd/src/log.h"
  30. #include "obexd/src/obex.h"
  31. #include "obexd/src/service.h"
  32. #include "obexd/src/manager.h"
  33. #include "obexd/src/mimetype.h"
  34. #include "phonebook.h"
  35. #include "filesystem.h"
  36. #define PHONEBOOK_TYPE "x-bt/phonebook"
  37. #define VCARDLISTING_TYPE "x-bt/vcard-listing"
  38. #define VCARDENTRY_TYPE "x-bt/vcard"
  39. #define ORDER_TAG 0x01
  40. #define SEARCHVALUE_TAG 0x02
  41. #define SEARCHATTRIB_TAG 0x03
  42. #define MAXLISTCOUNT_TAG 0x04
  43. #define LISTSTARTOFFSET_TAG 0x05
  44. #define FILTER_TAG 0x06
  45. #define FORMAT_TAG 0X07
  46. #define PHONEBOOKSIZE_TAG 0X08
  47. #define NEWMISSEDCALLS_TAG 0X09
  48. struct cache {
  49. gboolean valid;
  50. uint32_t index;
  51. GSList *entries;
  52. };
  53. struct cache_entry {
  54. uint32_t handle;
  55. char *id;
  56. char *name;
  57. char *sound;
  58. char *tel;
  59. };
  60. struct pbap_session {
  61. struct apparam_field *params;
  62. char *folder;
  63. uint32_t find_handle;
  64. struct cache cache;
  65. struct pbap_object *obj;
  66. };
  67. struct pbap_object {
  68. GString *buffer;
  69. GObexApparam *apparam;
  70. gboolean firstpacket;
  71. gboolean lastpart;
  72. struct pbap_session *session;
  73. void *request;
  74. };
  75. static const uint8_t PBAP_TARGET[TARGET_SIZE] = {
  76. 0x79, 0x61, 0x35, 0xF0, 0xF0, 0xC5, 0x11, 0xD8,
  77. 0x09, 0x66, 0x08, 0x00, 0x20, 0x0C, 0x9A, 0x66 };
  78. typedef int (*cache_entry_find_f) (const struct cache_entry *entry,
  79. const char *value);
  80. static void cache_entry_free(void *data)
  81. {
  82. struct cache_entry *entry = data;
  83. g_free(entry->id);
  84. g_free(entry->name);
  85. g_free(entry->sound);
  86. g_free(entry->tel);
  87. g_free(entry);
  88. }
  89. static gboolean entry_name_find(const struct cache_entry *entry,
  90. const char *value)
  91. {
  92. char *name;
  93. gboolean ret;
  94. if (!entry->name)
  95. return FALSE;
  96. if (strlen(value) == 0)
  97. return TRUE;
  98. name = g_utf8_strdown(entry->name, -1);
  99. ret = (g_strstr_len(name, -1, value) ? TRUE : FALSE);
  100. g_free(name);
  101. return ret;
  102. }
  103. static gboolean entry_sound_find(const struct cache_entry *entry,
  104. const char *value)
  105. {
  106. if (!entry->sound)
  107. return FALSE;
  108. return (g_strstr_len(entry->sound, -1, value) ? TRUE : FALSE);
  109. }
  110. static gboolean entry_tel_find(const struct cache_entry *entry,
  111. const char *value)
  112. {
  113. if (!entry->tel)
  114. return FALSE;
  115. return (g_strstr_len(entry->tel, -1, value) ? TRUE : FALSE);
  116. }
  117. static const char *cache_find(struct cache *cache, uint32_t handle)
  118. {
  119. GSList *l;
  120. for (l = cache->entries; l; l = l->next) {
  121. struct cache_entry *entry = l->data;
  122. if (entry->handle == handle)
  123. return entry->id;
  124. }
  125. return NULL;
  126. }
  127. static void cache_clear(struct cache *cache)
  128. {
  129. g_slist_free_full(cache->entries, cache_entry_free);
  130. cache->entries = NULL;
  131. }
  132. static void phonebook_size_result(const char *buffer, size_t bufsize,
  133. int vcards, int missed,
  134. gboolean lastpart, void *user_data)
  135. {
  136. struct pbap_session *pbap = user_data;
  137. uint16_t phonebooksize;
  138. if (pbap->obj->request) {
  139. phonebook_req_finalize(pbap->obj->request);
  140. pbap->obj->request = NULL;
  141. }
  142. if (vcards < 0)
  143. vcards = 0;
  144. DBG("vcards %d", vcards);
  145. phonebooksize = vcards;
  146. pbap->obj->apparam = g_obex_apparam_set_uint16(NULL, PHONEBOOKSIZE_TAG,
  147. phonebooksize);
  148. pbap->obj->firstpacket = TRUE;
  149. if (missed > 0) {
  150. DBG("missed %d", missed);
  151. pbap->obj->apparam = g_obex_apparam_set_uint16(
  152. pbap->obj->apparam,
  153. NEWMISSEDCALLS_TAG,
  154. missed);
  155. }
  156. obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
  157. }
  158. static void query_result(const char *buffer, size_t bufsize, int vcards,
  159. int missed, gboolean lastpart, void *user_data)
  160. {
  161. struct pbap_session *pbap = user_data;
  162. DBG("");
  163. if (pbap->obj->request && lastpart) {
  164. phonebook_req_finalize(pbap->obj->request);
  165. pbap->obj->request = NULL;
  166. }
  167. pbap->obj->lastpart = lastpart;
  168. if (vcards < 0) {
  169. obex_object_set_io_flags(pbap->obj, G_IO_ERR, -ENOENT);
  170. return;
  171. }
  172. if (!pbap->obj->buffer)
  173. pbap->obj->buffer = g_string_new_len(buffer, bufsize);
  174. else
  175. pbap->obj->buffer = g_string_append_len(pbap->obj->buffer,
  176. buffer, bufsize);
  177. if (missed > 0) {
  178. DBG("missed %d", missed);
  179. pbap->obj->firstpacket = TRUE;
  180. pbap->obj->apparam = g_obex_apparam_set_uint16(
  181. pbap->obj->apparam,
  182. NEWMISSEDCALLS_TAG,
  183. missed);
  184. }
  185. obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
  186. }
  187. static void cache_entry_notify(const char *id, uint32_t handle,
  188. const char *name, const char *sound,
  189. const char *tel, void *user_data)
  190. {
  191. struct pbap_session *pbap = user_data;
  192. struct cache_entry *entry = g_new0(struct cache_entry, 1);
  193. struct cache *cache = &pbap->cache;
  194. if (handle != PHONEBOOK_INVALID_HANDLE)
  195. entry->handle = handle;
  196. else
  197. entry->handle = ++pbap->cache.index;
  198. entry->id = g_strdup(id);
  199. entry->name = g_strdup(name);
  200. entry->sound = g_strdup(sound);
  201. entry->tel = g_strdup(tel);
  202. cache->entries = g_slist_append(cache->entries, entry);
  203. }
  204. static int alpha_sort(gconstpointer a, gconstpointer b)
  205. {
  206. const struct cache_entry *e1 = a;
  207. const struct cache_entry *e2 = b;
  208. return g_strcmp0(e1->name, e2->name);
  209. }
  210. static int indexed_sort(gconstpointer a, gconstpointer b)
  211. {
  212. const struct cache_entry *e1 = a;
  213. const struct cache_entry *e2 = b;
  214. return (e1->handle - e2->handle);
  215. }
  216. static int phonetical_sort(gconstpointer a, gconstpointer b)
  217. {
  218. const struct cache_entry *e1 = a;
  219. const struct cache_entry *e2 = b;
  220. /* SOUND attribute is optional. Use Indexed sort if not present. */
  221. if (!e1->sound || !e2->sound)
  222. return indexed_sort(a, b);
  223. return g_strcmp0(e1->sound, e2->sound);
  224. }
  225. static GSList *sort_entries(GSList *l, uint8_t order, uint8_t search_attrib,
  226. const char *value)
  227. {
  228. GSList *sorted = NULL;
  229. cache_entry_find_f find;
  230. GCompareFunc sort;
  231. char *searchval;
  232. /*
  233. * Default sorter is "Indexed". Some backends doesn't inform the index,
  234. * for this case a sequential internal index is assigned.
  235. * 0x00 = indexed
  236. * 0x01 = alphanumeric
  237. * 0x02 = phonetic
  238. */
  239. switch (order) {
  240. case 0x01:
  241. sort = alpha_sort;
  242. break;
  243. case 0x02:
  244. sort = phonetical_sort;
  245. break;
  246. default:
  247. sort = indexed_sort;
  248. break;
  249. }
  250. /*
  251. * This implementation checks if the given field CONTAINS the
  252. * search value(case insensitive). Name is the default field
  253. * when the attribute is not provided.
  254. */
  255. switch (search_attrib) {
  256. /* Number */
  257. case 1:
  258. find = entry_tel_find;
  259. break;
  260. /* Sound */
  261. case 2:
  262. find = entry_sound_find;
  263. break;
  264. default:
  265. find = entry_name_find;
  266. break;
  267. }
  268. searchval = value ? g_utf8_strdown(value, -1) : NULL;
  269. for (; l; l = l->next) {
  270. struct cache_entry *entry = l->data;
  271. if (searchval && !find(entry, (const char *) searchval))
  272. continue;
  273. sorted = g_slist_insert_sorted(sorted, entry, sort);
  274. }
  275. g_free(searchval);
  276. return sorted;
  277. }
  278. static int generate_response(void *user_data)
  279. {
  280. struct pbap_session *pbap = user_data;
  281. GSList *sorted;
  282. GSList *l;
  283. uint16_t max = pbap->params->maxlistcount;
  284. DBG("");
  285. if (max == 0) {
  286. /* Ignore all other parameter and return PhoneBookSize */
  287. uint16_t size = g_slist_length(pbap->cache.entries);
  288. pbap->obj->firstpacket = TRUE;
  289. pbap->obj->apparam = g_obex_apparam_set_uint16(
  290. pbap->obj->apparam,
  291. PHONEBOOKSIZE_TAG,
  292. size);
  293. return 0;
  294. }
  295. /*
  296. * Don't free the sorted list content: this list contains
  297. * only the reference for the "real" cache entry.
  298. */
  299. sorted = sort_entries(pbap->cache.entries, pbap->params->order,
  300. pbap->params->searchattrib,
  301. (const char *) pbap->params->searchval);
  302. /* Computing offset considering first entry of the phonebook */
  303. l = g_slist_nth(sorted, pbap->params->liststartoffset);
  304. pbap->obj->buffer = g_string_new(VCARD_LISTING_BEGIN);
  305. for (; l && max; l = l->next, max--) {
  306. const struct cache_entry *entry = l->data;
  307. char *escaped_name = g_markup_escape_text(entry->name, -1);
  308. g_string_append_printf(pbap->obj->buffer,
  309. VCARD_LISTING_ELEMENT, entry->handle, escaped_name);
  310. g_free(escaped_name);
  311. }
  312. pbap->obj->buffer = g_string_append(pbap->obj->buffer,
  313. VCARD_LISTING_END);
  314. g_slist_free(sorted);
  315. return 0;
  316. }
  317. static void cache_ready_notify(void *user_data)
  318. {
  319. struct pbap_session *pbap = user_data;
  320. DBG("");
  321. phonebook_req_finalize(pbap->obj->request);
  322. pbap->obj->request = NULL;
  323. pbap->cache.valid = TRUE;
  324. generate_response(pbap);
  325. obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
  326. }
  327. static void cache_entry_done(void *user_data)
  328. {
  329. struct pbap_session *pbap = user_data;
  330. const char *id;
  331. int ret;
  332. DBG("");
  333. pbap->cache.valid = TRUE;
  334. id = cache_find(&pbap->cache, pbap->find_handle);
  335. if (id == NULL) {
  336. DBG("Entry %d not found on cache", pbap->find_handle);
  337. obex_object_set_io_flags(pbap->obj, G_IO_ERR, -ENOENT);
  338. return;
  339. }
  340. phonebook_req_finalize(pbap->obj->request);
  341. pbap->obj->request = phonebook_get_entry(pbap->folder, id,
  342. pbap->params, query_result, pbap, &ret);
  343. if (ret < 0)
  344. obex_object_set_io_flags(pbap->obj, G_IO_ERR, ret);
  345. }
  346. static struct apparam_field *parse_aparam(const uint8_t *buffer, uint32_t hlen)
  347. {
  348. GObexApparam *apparam;
  349. struct apparam_field *param;
  350. apparam = g_obex_apparam_decode(buffer, hlen);
  351. if (apparam == NULL)
  352. return NULL;
  353. param = g_new0(struct apparam_field, 1);
  354. /*
  355. * As per spec when client doesn't include MAXLISTCOUNT_TAG then it
  356. * should be assume as Maximum value in vcardlisting 65535
  357. */
  358. param->maxlistcount = UINT16_MAX;
  359. g_obex_apparam_get_uint8(apparam, ORDER_TAG, &param->order);
  360. g_obex_apparam_get_uint8(apparam, SEARCHATTRIB_TAG,
  361. &param->searchattrib);
  362. g_obex_apparam_get_uint8(apparam, FORMAT_TAG, &param->format);
  363. g_obex_apparam_get_uint16(apparam, MAXLISTCOUNT_TAG,
  364. &param->maxlistcount);
  365. g_obex_apparam_get_uint16(apparam, LISTSTARTOFFSET_TAG,
  366. &param->liststartoffset);
  367. g_obex_apparam_get_uint64(apparam, FILTER_TAG, &param->filter);
  368. param->searchval = g_obex_apparam_get_string(apparam, SEARCHVALUE_TAG);
  369. DBG("o %x sa %x sv %s fil %" G_GINT64_MODIFIER "x for %x max %x off %x",
  370. param->order, param->searchattrib, param->searchval,
  371. param->filter, param->format, param->maxlistcount,
  372. param->liststartoffset);
  373. g_obex_apparam_free(apparam);
  374. return param;
  375. }
  376. static void *pbap_connect(struct obex_session *os, int *err)
  377. {
  378. struct pbap_session *pbap;
  379. manager_register_session(os);
  380. pbap = g_new0(struct pbap_session, 1);
  381. pbap->folder = g_strdup("/");
  382. pbap->find_handle = PHONEBOOK_INVALID_HANDLE;
  383. if (err)
  384. *err = 0;
  385. return pbap;
  386. }
  387. static int pbap_get(struct obex_session *os, void *user_data)
  388. {
  389. struct pbap_session *pbap = user_data;
  390. const char *type = obex_get_type(os);
  391. const char *name = obex_get_name(os);
  392. struct apparam_field *params;
  393. const uint8_t *buffer;
  394. char *path;
  395. ssize_t rsize;
  396. int ret;
  397. DBG("name %s type %s pbap %p", name, type, pbap);
  398. if (type == NULL)
  399. return -EBADR;
  400. rsize = obex_get_apparam(os, &buffer);
  401. if (rsize < 0) {
  402. if (g_ascii_strcasecmp(type, VCARDENTRY_TYPE) != 0)
  403. return -EBADR;
  404. rsize = 0;
  405. }
  406. /* Workaround for PTS client not sending mandatory apparams */
  407. if (!rsize && g_ascii_strcasecmp(type, VCARDLISTING_TYPE) == 0) {
  408. static const uint8_t default_apparams[] = {
  409. 0x04, 0x02, 0xff, 0xff
  410. };
  411. buffer = default_apparams;
  412. rsize = sizeof(default_apparams);
  413. } else if (!rsize && g_ascii_strcasecmp(type, VCARDENTRY_TYPE) == 0) {
  414. static const uint8_t default_apparams[] = {
  415. 0x07, 0x01, 0x00
  416. };
  417. buffer = default_apparams;
  418. rsize = sizeof(default_apparams);
  419. }
  420. params = parse_aparam(buffer, rsize);
  421. if (params == NULL)
  422. return -EBADR;
  423. if (pbap->params) {
  424. g_free(pbap->params->searchval);
  425. g_free(pbap->params);
  426. }
  427. pbap->params = params;
  428. if (g_ascii_strcasecmp(type, PHONEBOOK_TYPE) == 0) {
  429. /* Always contains the absolute path */
  430. if (g_path_is_absolute(name))
  431. path = g_strdup(name);
  432. else
  433. path = g_build_filename("/", name, NULL);
  434. } else if (g_ascii_strcasecmp(type, VCARDLISTING_TYPE) == 0) {
  435. /* Always relative */
  436. if (!name || strlen(name) == 0) {
  437. /* Current folder */
  438. path = g_strdup(pbap->folder);
  439. } else {
  440. /* Current folder + relative path */
  441. path = g_build_filename(pbap->folder, name, NULL);
  442. /* clear cache */
  443. pbap->cache.valid = FALSE;
  444. pbap->cache.index = 0;
  445. cache_clear(&pbap->cache);
  446. }
  447. } else if (g_ascii_strcasecmp(type, VCARDENTRY_TYPE) == 0) {
  448. /* File name only */
  449. path = g_strdup(name);
  450. } else
  451. return -EBADR;
  452. if (path == NULL)
  453. return -EBADR;
  454. ret = obex_get_stream_start(os, path);
  455. g_free(path);
  456. return ret;
  457. }
  458. static int pbap_setpath(struct obex_session *os, void *user_data)
  459. {
  460. struct pbap_session *pbap = user_data;
  461. const char *name;
  462. const uint8_t *nonhdr;
  463. char *fullname;
  464. int err;
  465. if (obex_get_non_header_data(os, &nonhdr) != 2) {
  466. error("Set path failed: flag and constants not found!");
  467. return -EBADMSG;
  468. }
  469. name = obex_get_name(os);
  470. DBG("name %s folder %s nonhdr 0x%x%x", name, pbap->folder,
  471. nonhdr[0], nonhdr[1]);
  472. fullname = phonebook_set_folder(pbap->folder, name, nonhdr[0], &err);
  473. if (err < 0)
  474. return err;
  475. g_free(pbap->folder);
  476. pbap->folder = fullname;
  477. /*
  478. * FIXME: Define a criteria to mark the cache as invalid
  479. */
  480. pbap->cache.valid = FALSE;
  481. pbap->cache.index = 0;
  482. cache_clear(&pbap->cache);
  483. return 0;
  484. }
  485. static void pbap_disconnect(struct obex_session *os, void *user_data)
  486. {
  487. struct pbap_session *pbap = user_data;
  488. manager_unregister_session(os);
  489. if (pbap->obj)
  490. pbap->obj->session = NULL;
  491. if (pbap->params) {
  492. g_free(pbap->params->searchval);
  493. g_free(pbap->params);
  494. }
  495. cache_clear(&pbap->cache);
  496. g_free(pbap->folder);
  497. g_free(pbap);
  498. }
  499. static int pbap_chkput(struct obex_session *os, void *user_data)
  500. {
  501. /* Rejects all PUTs */
  502. return -EBADR;
  503. }
  504. static struct obex_service_driver pbap = {
  505. .name = "Phonebook Access server",
  506. .service = OBEX_PBAP,
  507. .target = PBAP_TARGET,
  508. .target_size = TARGET_SIZE,
  509. .connect = pbap_connect,
  510. .get = pbap_get,
  511. .setpath = pbap_setpath,
  512. .disconnect = pbap_disconnect,
  513. .chkput = pbap_chkput
  514. };
  515. static struct pbap_object *vobject_create(struct pbap_session *pbap,
  516. void *request)
  517. {
  518. struct pbap_object *obj;
  519. obj = g_new0(struct pbap_object, 1);
  520. obj->session = pbap;
  521. pbap->obj = obj;
  522. obj->request = request;
  523. return obj;
  524. }
  525. static void *vobject_pull_open(const char *name, int oflag, mode_t mode,
  526. void *context, size_t *size, int *err)
  527. {
  528. struct pbap_session *pbap = context;
  529. phonebook_cb cb;
  530. int ret;
  531. void *request;
  532. DBG("name %s context %p maxlistcount %d", name, context,
  533. pbap->params->maxlistcount);
  534. if (oflag != O_RDONLY) {
  535. ret = -EPERM;
  536. goto fail;
  537. }
  538. if (name == NULL) {
  539. ret = -EBADR;
  540. goto fail;
  541. }
  542. if (pbap->params->maxlistcount == 0)
  543. cb = phonebook_size_result;
  544. else
  545. cb = query_result;
  546. request = phonebook_pull(name, pbap->params, cb, pbap, &ret);
  547. if (ret < 0)
  548. goto fail;
  549. /* reading first part of results from backend */
  550. ret = phonebook_pull_read(request);
  551. if (ret < 0)
  552. goto fail;
  553. if (err)
  554. *err = 0;
  555. return vobject_create(pbap, request);
  556. fail:
  557. if (err)
  558. *err = ret;
  559. return NULL;
  560. }
  561. static int vobject_close(void *object)
  562. {
  563. struct pbap_object *obj = object;
  564. DBG("");
  565. if (obj->session)
  566. obj->session->obj = NULL;
  567. if (obj->buffer)
  568. g_string_free(obj->buffer, TRUE);
  569. if (obj->apparam)
  570. g_obex_apparam_free(obj->apparam);
  571. if (obj->request)
  572. phonebook_req_finalize(obj->request);
  573. g_free(obj);
  574. return 0;
  575. }
  576. static void *vobject_list_open(const char *name, int oflag, mode_t mode,
  577. void *context, size_t *size, int *err)
  578. {
  579. struct pbap_session *pbap = context;
  580. struct pbap_object *obj = NULL;
  581. int ret;
  582. void *request;
  583. if (name == NULL) {
  584. ret = -EBADR;
  585. goto fail;
  586. }
  587. DBG("name %s context %p valid %d", name, context, pbap->cache.valid);
  588. if (oflag != O_RDONLY) {
  589. ret = -EPERM;
  590. goto fail;
  591. }
  592. /* PullvCardListing always get the contacts from the cache */
  593. if (pbap->cache.valid) {
  594. obj = vobject_create(pbap, NULL);
  595. ret = generate_response(pbap);
  596. } else {
  597. request = phonebook_create_cache(name, cache_entry_notify,
  598. cache_ready_notify, pbap, &ret);
  599. if (ret == 0)
  600. obj = vobject_create(pbap, request);
  601. }
  602. if (ret < 0)
  603. goto fail;
  604. if (err)
  605. *err = 0;
  606. return obj;
  607. fail:
  608. if (obj)
  609. vobject_close(obj);
  610. if (err)
  611. *err = ret;
  612. return NULL;
  613. }
  614. static void *vobject_vcard_open(const char *name, int oflag, mode_t mode,
  615. void *context, size_t *size, int *err)
  616. {
  617. struct pbap_session *pbap = context;
  618. const char *id;
  619. uint32_t handle;
  620. int ret;
  621. void *request;
  622. DBG("name %s context %p valid %d", name, context, pbap->cache.valid);
  623. if (oflag != O_RDONLY) {
  624. ret = -EPERM;
  625. goto fail;
  626. }
  627. if (name == NULL || sscanf(name, "%u.vcf", &handle) != 1) {
  628. ret = -EBADR;
  629. goto fail;
  630. }
  631. if (pbap->cache.valid == FALSE) {
  632. pbap->find_handle = handle;
  633. request = phonebook_create_cache(pbap->folder,
  634. cache_entry_notify, cache_entry_done, pbap, &ret);
  635. goto done;
  636. }
  637. id = cache_find(&pbap->cache, handle);
  638. if (!id) {
  639. ret = -ENOENT;
  640. goto fail;
  641. }
  642. request = phonebook_get_entry(pbap->folder, id, pbap->params,
  643. query_result, pbap, &ret);
  644. done:
  645. if (ret < 0)
  646. goto fail;
  647. if (err)
  648. *err = 0;
  649. return vobject_create(pbap, request);
  650. fail:
  651. if (err)
  652. *err = ret;
  653. return NULL;
  654. }
  655. static ssize_t vobject_pull_get_next_header(void *object, void *buf, size_t mtu,
  656. uint8_t *hi)
  657. {
  658. struct pbap_object *obj = object;
  659. if (!obj->buffer && !obj->apparam)
  660. return -EAGAIN;
  661. *hi = G_OBEX_HDR_APPARAM;
  662. if (obj->firstpacket) {
  663. obj->firstpacket = FALSE;
  664. return g_obex_apparam_encode(obj->apparam, buf, mtu);
  665. }
  666. return 0;
  667. }
  668. static ssize_t vobject_pull_read(void *object, void *buf, size_t count)
  669. {
  670. struct pbap_object *obj = object;
  671. struct pbap_session *pbap = obj->session;
  672. int len, ret;
  673. DBG("buffer %p maxlistcount %d", obj->buffer,
  674. pbap->params->maxlistcount);
  675. if (!obj->buffer) {
  676. if (pbap->params->maxlistcount == 0)
  677. return -ENOSTR;
  678. return -EAGAIN;
  679. }
  680. len = string_read(obj->buffer, buf, count);
  681. if (len == 0 && !obj->lastpart) {
  682. /* in case when buffer is empty and we know that more
  683. * data is still available in backend, requesting new
  684. * data part via phonebook_pull_read and returning
  685. * -EAGAIN to suspend request for now */
  686. ret = phonebook_pull_read(obj->request);
  687. if (ret)
  688. return -EPERM;
  689. return -EAGAIN;
  690. }
  691. return len;
  692. }
  693. static ssize_t vobject_list_get_next_header(void *object, void *buf, size_t mtu,
  694. uint8_t *hi)
  695. {
  696. struct pbap_object *obj = object;
  697. struct pbap_session *pbap = obj->session;
  698. /* Backend still busy reading contacts */
  699. if (!pbap->cache.valid)
  700. return -EAGAIN;
  701. *hi = G_OBEX_HDR_APPARAM;
  702. if (obj->firstpacket) {
  703. obj->firstpacket = FALSE;
  704. return g_obex_apparam_encode(obj->apparam, buf, mtu);
  705. }
  706. return 0;
  707. }
  708. static ssize_t vobject_list_read(void *object, void *buf, size_t count)
  709. {
  710. struct pbap_object *obj = object;
  711. struct pbap_session *pbap = obj->session;
  712. DBG("valid %d maxlistcount %d", pbap->cache.valid,
  713. pbap->params->maxlistcount);
  714. if (pbap->params->maxlistcount == 0)
  715. return -ENOSTR;
  716. return string_read(obj->buffer, buf, count);
  717. }
  718. static ssize_t vobject_vcard_read(void *object, void *buf, size_t count)
  719. {
  720. struct pbap_object *obj = object;
  721. DBG("buffer %p", obj->buffer);
  722. if (!obj->buffer)
  723. return -EAGAIN;
  724. return string_read(obj->buffer, buf, count);
  725. }
  726. static struct obex_mime_type_driver mime_pull = {
  727. .target = PBAP_TARGET,
  728. .target_size = TARGET_SIZE,
  729. .mimetype = "x-bt/phonebook",
  730. .open = vobject_pull_open,
  731. .close = vobject_close,
  732. .read = vobject_pull_read,
  733. .get_next_header = vobject_pull_get_next_header,
  734. };
  735. static struct obex_mime_type_driver mime_list = {
  736. .target = PBAP_TARGET,
  737. .target_size = TARGET_SIZE,
  738. .mimetype = "x-bt/vcard-listing",
  739. .open = vobject_list_open,
  740. .close = vobject_close,
  741. .read = vobject_list_read,
  742. .get_next_header = vobject_list_get_next_header,
  743. };
  744. static struct obex_mime_type_driver mime_vcard = {
  745. .target = PBAP_TARGET,
  746. .target_size = TARGET_SIZE,
  747. .mimetype = "x-bt/vcard",
  748. .open = vobject_vcard_open,
  749. .close = vobject_close,
  750. .read = vobject_vcard_read,
  751. };
  752. static int pbap_init(void)
  753. {
  754. int err;
  755. err = phonebook_init();
  756. if (err < 0)
  757. return err;
  758. err = obex_mime_type_driver_register(&mime_pull);
  759. if (err < 0)
  760. goto fail_mime_pull;
  761. err = obex_mime_type_driver_register(&mime_list);
  762. if (err < 0)
  763. goto fail_mime_list;
  764. err = obex_mime_type_driver_register(&mime_vcard);
  765. if (err < 0)
  766. goto fail_mime_vcard;
  767. err = obex_service_driver_register(&pbap);
  768. if (err < 0)
  769. goto fail_pbap_reg;
  770. return 0;
  771. fail_pbap_reg:
  772. obex_mime_type_driver_unregister(&mime_vcard);
  773. fail_mime_vcard:
  774. obex_mime_type_driver_unregister(&mime_list);
  775. fail_mime_list:
  776. obex_mime_type_driver_unregister(&mime_pull);
  777. fail_mime_pull:
  778. phonebook_exit();
  779. return err;
  780. }
  781. static void pbap_exit(void)
  782. {
  783. obex_service_driver_unregister(&pbap);
  784. obex_mime_type_driver_unregister(&mime_pull);
  785. obex_mime_type_driver_unregister(&mime_list);
  786. obex_mime_type_driver_unregister(&mime_vcard);
  787. phonebook_exit();
  788. }
  789. OBEX_PLUGIN_DEFINE(pbap, pbap_init, pbap_exit)