124
struct aparam_header {
128
128
} __attribute__ ((packed));
130
struct pbap_session {
131
struct obex_session *os;
132
struct apparam_field *params;
130
137
static const guint8 PBAP_TARGET[TARGET_SIZE] = {
131
138
0x79, 0x61, 0x35, 0xF0, 0xF0, 0xC5, 0x11, 0xD8,
132
139
0x09, 0x66, 0x08, 0x00, 0x20, 0x0C, 0x9A, 0x66 };
134
static int pbap_parse_apparam_header(obex_t *obex, obex_object_t *obj,
135
struct apparam_field *apparam)
137
obex_headerdata_t hd;
141
while (OBEX_ObjectGetNextHeader(obex, obj, &hi, &hd, &hlen)) {
142
void *ptr = (void *) hd.bs;
145
if (hi != OBEX_HDR_APPARAM)
148
if (hlen < APPARAM_HDR_SIZE) {
149
g_free(apparam->searchval);
150
error("PBAP pullphonebook app parameters header"
151
" is too short: %d", hlen);
155
while (len > APPARAM_HDR_SIZE) {
156
struct apparam_hdr *hdr = ptr;
158
if (hdr->len > len - APPARAM_HDR_SIZE) {
159
g_free(apparam->searchval);
160
error("Unexpected PBAP pullphonebook app"
161
" length, tag %d, len %d",
168
if (hdr->len == ORDER_LEN)
169
apparam->order = hdr->val[0];
171
case SEARCHATTRIB_TAG:
172
if (hdr->len == SEARCHATTRIB_LEN)
173
apparam->searchattrib = hdr->val[0];
175
case SEARCHVALUE_TAG:
176
apparam->searchval = g_try_malloc(hdr->len + 1);
177
if (apparam->searchval != NULL) {
178
memcpy(apparam->searchval, hdr->val,
180
apparam->searchval[hdr->len] = '\0';
184
if (hdr->len == FILTER_LEN) {
186
memcpy(&val, hdr->val, sizeof(val));
187
apparam->filter = get_be64(&val);
191
if (hdr->len == FORMAT_LEN)
192
apparam->format = hdr->val[0];
194
case MAXLISTCOUNT_TAG:
195
if (hdr->len == MAXLISTCOUNT_LEN) {
197
memcpy(&val, hdr->val, sizeof(val));
198
apparam->maxlistcount = get_be16(&val);
201
case LISTSTARTOFFSET_TAG:
202
if (hdr->len == LISTSTARTOFFSET_LEN) {
204
memcpy(&val, hdr->val, sizeof(val));
205
apparam->liststartoffset = get_be16(&val);
209
g_free(apparam->searchval);
210
error("Unexpected PBAP pullphonebook app"
211
" parameter, tag %d, len %d",
216
ptr += APPARAM_HDR_SIZE + hdr->len;
217
len -= APPARAM_HDR_SIZE + hdr->len;
220
/* Ignore multiple app param headers */
227
/* Add app parameter header, that is sent back to PBAP client */
228
static int pbap_add_result_apparam_header(obex_t *obex, obex_object_t *obj,
229
guint16 maxlistcount, gchar *path_name,
230
guint16 phonebooksize,
231
guint8 newmissedcalls, gboolean *addbody)
234
gboolean addmissedcalls = FALSE;
235
obex_headerdata_t hd;
237
if (maxlistcount == 0) {
238
rspsize += APPARAM_HDR_SIZE + PHONEBOOKSIZE_LEN;
242
if (g_str_equal(path_name, SIM1_MCH) == TRUE ||
243
g_str_equal(path_name, MCH) == TRUE) {
244
rspsize += APPARAM_HDR_SIZE + NEWMISSEDCALLS_LEN;
245
addmissedcalls = TRUE;
251
buf = g_try_malloc0(rspsize);
257
if (maxlistcount == 0) {
258
struct apparam_hdr *hdr = ptr;
259
guint16 val = GUINT16_TO_BE(phonebooksize);
261
hdr->tag = PHONEBOOKSIZE_TAG;
262
hdr->len = PHONEBOOKSIZE_LEN;
263
memcpy(hdr->val, &val, sizeof(val));
265
ptr += APPARAM_HDR_SIZE + PHONEBOOKSIZE_LEN;
268
if (addmissedcalls == TRUE) {
269
struct apparam_hdr *hdr = ptr;
271
hdr->tag = NEWMISSEDCALLS_TAG;
272
hdr->len = NEWMISSEDCALLS_LEN;
273
hdr->val[0] = newmissedcalls;
275
ptr += APPARAM_HDR_SIZE + NEWMISSEDCALLS_LEN;
279
OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_APPARAM,
287
static int pbap_pullphonebook(obex_t *obex, obex_object_t *obj,
290
struct obex_session *session = OBEX_GetUserData(obex);
291
struct apparam_field params;
292
guint8 newmissedcalls = 0;
293
guint16 phonebooksize = 0;
296
memset(¶ms, 0, sizeof(struct apparam_field));
298
err = pbap_parse_apparam_header(obex, obj, ¶ms);
302
if (params.maxlistcount == 0) {
303
phonebooksize = DEFAULT_COUNT;
307
err = phonebook_pullphonebook(obex, obj, params);
312
return pbap_add_result_apparam_header(obex, obj, params.maxlistcount,
313
session->name, phonebooksize,
314
newmissedcalls, addbody);
317
static int pbap_pullvcardlisting(obex_t *obex, obex_object_t *obj,
320
struct obex_session *session = OBEX_GetUserData(obex);
322
struct apparam_field params;
323
guint8 newmissedcalls = 0;
324
guint16 phonebooksize = 0;
327
memset(¶ms, 0, sizeof(struct apparam_field));
329
err = pbap_parse_apparam_header(obex, obj, ¶ms);
333
if (params.maxlistcount == 0) {
334
phonebooksize = DEFAULT_COUNT;
338
/* libebook does not support sound attribute */
339
if (params.searchattrib >= 2) {
340
DBG("libebook does not support sound attribute");
344
err = phonebook_pullvcardlisting(obex, obj, params);
350
fullname = g_build_filename(session->current_folder, session->name,
352
if (fullname != NULL)
353
fullname = g_strconcat(fullname, ".vcf", NULL);
355
err = pbap_add_result_apparam_header(obex, obj, params.maxlistcount,
356
fullname, phonebooksize,
357
newmissedcalls, addbody);
361
g_free(params.searchval);
365
static int pbap_pullvcardentry(obex_t *obex, obex_object_t *obj)
367
struct apparam_field params;
370
memset(¶ms, 0, sizeof(struct apparam_field));
371
err = pbap_parse_apparam_header(obex, obj, ¶ms);
375
err = phonebook_pullvcardentry(obex, obj, params);
377
g_free(params.searchval);
381
static void pbap_connect(obex_t *obex, obex_object_t *obj)
383
struct obex_session *os = OBEX_GetUserData(obex);
384
obex_headerdata_t hd;
386
register_session(os->cid, os);
387
emit_session_created(os->cid);
389
/* Append received UUID in WHO header */
391
OBEX_ObjectAddHeader(obex, obj,
392
OBEX_HDR_WHO, hd, sizeof(PBAP_TARGET),
393
OBEX_FL_FIT_ONE_PACKET);
395
OBEX_ObjectAddHeader(obex, obj,
396
OBEX_HDR_CONNECTION, hd, 4,
397
OBEX_FL_FIT_ONE_PACKET);
399
OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
402
static void pbap_get(obex_t *obex, obex_object_t *obj)
404
struct obex_session *session = OBEX_GetUserData(obex);
405
obex_headerdata_t hd;
406
gboolean addbody = TRUE;
412
if (session->type == NULL)
415
if (g_str_equal(session->type, VCARDLISTING_TYPE) == FALSE
416
&& session->name == NULL)
419
OBEX_ObjectReParseHeaders(obex, obj);
421
if (g_str_equal(session->type, PHONEBOOK_TYPE) == TRUE)
422
err = pbap_pullphonebook(obex, obj, &addbody);
423
else if (g_str_equal(session->type, VCARDLISTING_TYPE) == TRUE)
424
err = pbap_pullvcardlisting(obex, obj, &addbody);
425
else if (g_str_equal(session->type, VCARDENTRY_TYPE) == TRUE)
426
err = pbap_pullvcardentry(obex, obj);
141
static void set_folder(struct pbap_session *pbap, const char *new_folder)
143
g_free(pbap->folder);
145
pbap->folder = new_folder ? g_strdup(new_folder) : NULL;
148
static struct apparam_field *parse_aparam(const guint8 *buffer, guint32 hlen)
150
struct apparam_field *param;
151
struct aparam_header *hdr;
156
param = g_new0(struct apparam_field, 1);
159
hdr = (void *) buffer + len;
163
if (hdr->len != ORDER_LEN)
166
param->order = hdr->val[0];
169
case SEARCHATTRIB_TAG:
170
if (hdr->len != SEARCHATTRIB_LEN)
173
param->searchattrib = hdr->val[0];
175
case SEARCHVALUE_TAG:
176
param->searchval = g_try_malloc0(hdr->len + 1);
177
if (param->searchval)
178
memcpy(param->searchval, hdr->val, hdr->len);
181
if (hdr->len != FILTER_LEN)
184
memcpy(&val64, hdr->val, sizeof(val64));
185
param->filter = GUINT64_FROM_BE(val64);
189
if (hdr->len != FORMAT_LEN)
192
param->format = hdr->val[0];
194
case MAXLISTCOUNT_TAG:
195
if (hdr->len != MAXLISTCOUNT_LEN)
198
memcpy(&val16, hdr->val, sizeof(val16));
199
param->maxlistcount = GUINT16_FROM_BE(val16);
201
case LISTSTARTOFFSET_TAG:
202
if (hdr->len != LISTSTARTOFFSET_LEN)
205
memcpy(&val16, hdr->val, sizeof(val16));
206
param->liststartoffset = GUINT16_FROM_BE(val16);
212
len += hdr->len + sizeof(struct aparam_header);
223
static gpointer pbap_connect(struct obex_session *os, int *err)
225
struct pbap_session *pbap;
227
manager_register_session(os);
229
pbap = g_new0(struct pbap_session, 1);
230
pbap->folder = g_strdup("/");
239
static int pbap_get(struct obex_session *os, obex_object_t *obj,
242
struct pbap_session *pbap = user_data;
243
const gchar *type = obex_get_type(os);
244
const gchar *name = obex_get_name(os);
245
struct apparam_field *params;
246
const guint8 *buffer;
254
if (strcmp(type, PHONEBOOK_TYPE) == 0)
255
/* Always contains the absolute path */
256
path = g_strdup(name);
257
else if (strcmp(type, VCARDLISTING_TYPE) == 0)
258
/* Always relative */
259
if (!name || strlen(name) == 0)
261
path = g_strdup(pbap->folder);
263
/* Current folder + relative path */
264
path = g_build_filename(pbap->folder, name, NULL);
266
else if (strcmp(type, VCARDENTRY_TYPE) == 0)
267
/* Always relative */
268
path = g_build_filename(pbap->folder, name, NULL);
433
if (addbody == TRUE) {
434
OBEX_SuspendRequest(obex, obj);
437
/* Add body header */
439
OBEX_ObjectAddHeader(obex, obj, OBEX_HDR_BODY,
440
hd, 0, OBEX_FL_STREAM_START);
443
OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS);
448
OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
451
static gboolean pbap_is_valid_folder(struct obex_session *session)
453
if (session->current_folder == NULL) {
454
if (g_str_equal(session->name, "telecom") == TRUE ||
455
g_str_equal(session->name, "SIM1") == TRUE)
457
} else if (g_str_equal(session->current_folder, "SIM1") == TRUE) {
458
if (g_str_equal(session->name, "telecom") == TRUE)
460
} else if (g_str_equal(session->current_folder, "telecom") == TRUE ||
461
g_str_equal(session->current_folder, "SIM1/telecom") == TRUE) {
462
if (g_str_equal(session->name, "pb") == TRUE ||
463
g_str_equal(session->name, "ich") == TRUE ||
464
g_str_equal(session->name, "och") == TRUE ||
465
g_str_equal(session->name, "mch") == TRUE ||
466
g_str_equal(session->name, "cch") == TRUE)
473
static void pbap_setpath(obex_t *obex, obex_object_t *obj)
475
struct obex_session *session = OBEX_GetUserData(obex);
272
rsize = obex_aparam_read(os, obj, &buffer);
278
params = parse_aparam(buffer, rsize);
279
if (params == NULL) {
285
g_free(pbap->params->searchval);
286
g_free(pbap->params);
289
pbap->params = params;
290
ret = obex_stream_start(os, path, pbap);
299
static int pbap_setpath(struct obex_session *os, obex_object_t *obj,
302
struct pbap_session *pbap = user_data;
479
308
if (OBEX_ObjectGetNonHdrData(obj, &nonhdr) != 2) {
480
OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE,
481
OBEX_RSP_PRECONDITION_FAILED);
482
309
error("Set path failed: flag and constants not found!");
486
/* Check "Backup" flag */
487
if ((nonhdr[0] & 0x01) == 0x01) {
488
debug("Set to parent path");
490
if (session->current_folder == NULL) {
491
/* we are already in top level folder */
492
OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN,
497
fullname = g_path_get_dirname(session->current_folder);
498
g_free(session->current_folder);
500
if (strlen(fullname) == 1 && *fullname == '.')
501
session->current_folder = NULL;
503
session->current_folder = g_strdup(fullname);
507
debug("Set to parent path: %s", session->current_folder);
509
OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS);
513
if (!session->name) {
514
OBEX_ObjectSetRsp(obj, OBEX_RSP_CONTINUE, OBEX_RSP_BAD_REQUEST);
515
error("Set path failed: name missing!");
519
if (strlen(session->name) == 0) {
520
debug("Set to root");
522
g_free(session->current_folder);
523
session->current_folder = NULL;
525
OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS);
529
/* Check and set to name path */
530
if (strstr(session->name, "/")) {
531
OBEX_ObjectSetRsp(obj, OBEX_RSP_FORBIDDEN, OBEX_RSP_FORBIDDEN);
532
error("Set path failed: name incorrect!");
536
if (pbap_is_valid_folder(session) == FALSE) {
537
OBEX_ObjectSetRsp(obj, OBEX_RSP_NOT_FOUND, OBEX_RSP_NOT_FOUND);
541
if (session->current_folder == NULL)
542
fullname = g_build_filename("", session->name, NULL);
313
name = obex_get_name(os);
315
ret = phonebook_set_folder(pbap->folder, name, nonhdr[0]);
320
fullname = g_strdup(name);
544
fullname = g_build_filename(session->current_folder, session->name, NULL);
546
debug("Fullname: %s", fullname);
548
g_free(session->current_folder);
549
session->current_folder = fullname;
550
OBEX_ObjectSetRsp(obj, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS);
322
fullname = g_build_filename(pbap->folder, name, NULL);
324
set_folder(pbap, fullname);
553
static void pbap_disconnect(obex_t *obex)
331
static void pbap_disconnect(struct obex_session *os,
555
struct obex_session *os = OBEX_GetUserData(obex);
557
emit_session_removed(os->cid);
558
unregister_session(os->cid);
334
struct pbap_session *pbap = user_data;
336
manager_unregister_session(os);
339
g_free(pbap->params->searchval);
340
g_free(pbap->params);
343
g_free(pbap->folder);
561
static gint pbap_chkput(obex_t *obex, obex_object_t *obj)
347
static gint pbap_chkput(struct obex_session *os,
563
350
/* Rejects all PUTs */