obexd-test package is needed for testing
[profile/ivi/obexd.git] / src / map_ap.c
1 /*
2  *
3  *  OBEX Server
4  *
5  *  Copyright (C) 2010-2011  Nokia Corporation
6  *
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21  *
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #include <string.h>
29
30 #include "log.h"
31
32 #include "map_ap.h"
33
34 enum ap_type {
35         APT_UINT8,
36         APT_UINT16,
37         APT_UINT32,
38         APT_STR
39 };
40
41 /* NOTE: ap_defs array has to be kept in sync with map_ap_tag. */
42 static const struct ap_def {
43         const char *name;
44         enum ap_type type;
45 } ap_defs[] = {
46         { "MAXLISTCOUNT",               APT_UINT16 },
47         { "STARTOFFSET",                APT_UINT16 },
48         { "FILTERMESSAGETYPE",          APT_UINT8  },
49         { "FILTERPERIODBEGIN",          APT_STR    },
50         { "FILTERPERIODEND",            APT_STR    },
51         { "FILTERREADSTATUS",           APT_UINT8  },
52         { "FILTERRECIPIENT",            APT_STR    },
53         { "FILTERORIGINATOR",           APT_STR    },
54         { "FILTERPRIORITY",             APT_UINT8  },
55         { "ATTACHMENT",                 APT_UINT8  },
56         { "TRANSPARENT",                APT_UINT8  },
57         { "RETRY",                      APT_UINT8  },
58         { "NEWMESSAGE",                 APT_UINT8  },
59         { "NOTIFICATIONSTATUS",         APT_UINT8  },
60         { "MASINSTANCEID",              APT_UINT8  },
61         { "PARAMETERMASK",              APT_UINT32 },
62         { "FOLDERLISTINGSIZE",          APT_UINT16 },
63         { "MESSAGESLISTINGSIZE",        APT_UINT16 },
64         { "SUBJECTLENGTH",              APT_UINT8  },
65         { "CHARSET",                    APT_UINT8  },
66         { "FRACTIONREQUEST",            APT_UINT8  },
67         { "FRACTIONDELIVER",            APT_UINT8  },
68         { "STATUSINDICATOR",            APT_UINT8  },
69         { "STATUSVALUE",                APT_UINT8  },
70         { "MSETIME",                    APT_STR    },
71 };
72
73 struct ap_entry {
74         enum map_ap_tag tag;
75         union {
76                 uint32_t u32;
77                 uint16_t u16;
78                 uint8_t u8;
79                 char *str;
80         } val;
81 };
82
83 /* This comes from OBEX specs */
84 struct obex_ap_header {
85         uint8_t tag;
86         uint8_t len;
87         uint8_t val[0];
88 } __attribute__ ((packed));
89
90 static int find_ap_def_offset(uint8_t tag)
91 {
92         if (tag == 0 || tag > G_N_ELEMENTS(ap_defs))
93                 return -1;
94
95         return tag - 1;
96 }
97
98 static void ap_entry_dump(gpointer tag, gpointer val, gpointer user_data)
99 {
100         struct ap_entry *entry = val;
101         int offset;
102
103         offset = find_ap_def_offset(GPOINTER_TO_INT(tag));
104
105         switch (ap_defs[offset].type) {
106         case APT_UINT8:
107                 DBG("%-30s %08x", ap_defs[offset].name, entry->val.u8);
108                 break;
109         case APT_UINT16:
110                 DBG("%-30s %08x", ap_defs[offset].name, entry->val.u16);
111                 break;
112         case APT_UINT32:
113                 DBG("%-30s %08x", ap_defs[offset].name, entry->val.u32);
114                 break;
115         case APT_STR:
116                 DBG("%-30s %s", ap_defs[offset].name, entry->val.str);
117                 break;
118         }
119 }
120
121 static void ap_entry_free(gpointer val)
122 {
123         struct ap_entry *entry = val;
124         int offset;
125
126         offset = find_ap_def_offset(entry->tag);
127
128         if (offset >= 0 && ap_defs[offset].type == APT_STR)
129                 g_free(entry->val.str);
130
131         g_free(entry);
132 }
133
134 map_ap_t *map_ap_new(void)
135 {
136         return g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
137                                                                 ap_entry_free);
138 }
139
140 void map_ap_free(map_ap_t *ap)
141 {
142         if (!ap)
143                 return;
144
145         g_hash_table_destroy(ap);
146 }
147
148 static void ap_decode_u8(map_ap_t *ap, const struct obex_ap_header *hdr)
149 {
150         if (hdr->len != 1) {
151                 DBG("Value of tag %u is %u byte(s) long instead of expected "
152                                 "1 byte - skipped!", hdr->tag, hdr->len);
153                 return;
154         }
155
156         map_ap_set_u8(ap, hdr->tag, hdr->val[0]);
157 }
158
159 static void ap_decode_u16(map_ap_t *ap, const struct obex_ap_header *hdr)
160 {
161         uint16_t val;
162
163         if (hdr->len != 2) {
164                 DBG("Value of tag %u is %u byte(s) long instead of expected "
165                                 "2 bytes - skipped!", hdr->tag, hdr->len);
166                 return;
167         }
168
169         memcpy(&val, hdr->val, sizeof(val));
170         map_ap_set_u16(ap, hdr->tag, GUINT16_FROM_BE(val));
171 }
172
173 static void ap_decode_u32(map_ap_t *ap, const struct obex_ap_header *hdr)
174 {
175         uint32_t val;
176
177         if (hdr->len != 4) {
178                 DBG("Value of tag %u is %u byte(s) long instead of expected "
179                                 "4 bytes - skipped!", hdr->tag, hdr->len);
180                 return;
181         }
182
183         memcpy(&val, hdr->val, sizeof(val));
184         map_ap_set_u32(ap, hdr->tag, GUINT32_FROM_BE(val));
185 }
186
187 static void ap_decode_str(map_ap_t *ap, const struct obex_ap_header *hdr)
188 {
189         char *val = g_malloc0(hdr->len + 1);
190
191         memcpy(val, hdr->val, hdr->len);
192         map_ap_set_string(ap, hdr->tag, val);
193
194         g_free(val);
195 }
196
197 map_ap_t *map_ap_decode(const uint8_t *buffer, size_t length)
198 {
199         map_ap_t *ap;
200         struct obex_ap_header *hdr;
201         uint32_t done;
202         int offset;
203
204         ap = map_ap_new();
205         if (!ap)
206                 return NULL;
207
208         for (done = 0;  done < length; done += hdr->len + sizeof(*hdr)) {
209                 hdr = (struct obex_ap_header *)(buffer + done);
210
211                 offset = find_ap_def_offset(hdr->tag);
212
213                 if (offset < 0) {
214                         DBG("Unknown tag %u (length %u) - skipped.",
215                                                         hdr->tag, hdr->len);
216                         continue;
217                 }
218
219                 switch (ap_defs[offset].type) {
220                 case APT_UINT8:
221                         ap_decode_u8(ap, hdr);
222                         break;
223                 case APT_UINT16:
224                         ap_decode_u16(ap, hdr);
225                         break;
226                 case APT_UINT32:
227                         ap_decode_u32(ap, hdr);
228                         break;
229                 case APT_STR:
230                         ap_decode_str(ap, hdr);
231                         break;
232                 }
233         }
234
235         g_hash_table_foreach(ap, ap_entry_dump, NULL);
236
237         return ap;
238 }
239
240 static void ap_encode_u8(GByteArray *buf, struct ap_entry *entry)
241 {
242         struct obex_ap_header *hdr;
243
244         hdr = (struct obex_ap_header *) buf->data + buf->len;
245         g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + 1);
246
247         hdr->tag = entry->tag;
248         hdr->len = 1;
249         hdr->val[0] = entry->val.u8;
250 }
251
252 static void ap_encode_u16(GByteArray *buf, struct ap_entry *entry)
253 {
254         struct obex_ap_header *hdr;
255         uint16_t val;
256
257         hdr = (struct obex_ap_header *) buf->data + buf->len;
258
259         g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + 2);
260
261         hdr->tag = entry->tag;
262         hdr->len = 2;
263
264         val = GUINT16_TO_BE(entry->val.u16);
265         memcpy(hdr->val, &val, sizeof(val));
266 }
267
268 static void ap_encode_u32(GByteArray *buf, struct ap_entry *entry)
269 {
270         uint32_t val;
271         struct obex_ap_header *hdr;
272
273         hdr = (struct obex_ap_header *) buf->data + buf->len;
274         g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + 4);
275
276         hdr->tag = entry->tag;
277         hdr->len = 4;
278
279         val = GUINT32_TO_BE(entry->val.u16);
280         memcpy(hdr->val, &val, sizeof(val));
281 }
282
283 static void ap_encode_str(GByteArray *buf, struct ap_entry *entry)
284 {
285         size_t len;
286         struct obex_ap_header *hdr;
287
288         hdr = (struct obex_ap_header *) buf->data + buf->len;
289         len = strlen(entry->val.str);
290         g_byte_array_set_size(buf, buf->len + sizeof(*hdr) + len);
291
292         hdr->tag = entry->tag;
293         hdr->len = len;
294
295         memcpy(hdr->val, entry->val.str, len);
296 }
297
298 uint8_t *map_ap_encode(map_ap_t *ap, size_t *length)
299 {
300         GByteArray *buf;
301         GHashTableIter iter;
302         gpointer key, value;
303         struct ap_entry *entry;
304         int offset;
305
306         buf = g_byte_array_new();
307         g_hash_table_iter_init(&iter, ap);
308
309         while (g_hash_table_iter_next(&iter, &key, &value)) {
310                 entry = (struct ap_entry *) value;
311                 offset = find_ap_def_offset(entry->tag);
312
313                 switch (ap_defs[offset].type) {
314                 case APT_UINT8:
315                         ap_encode_u8(buf, entry);
316                         break;
317                 case APT_UINT16:
318                         ap_encode_u16(buf, entry);
319                         break;
320                 case APT_UINT32:
321                         ap_encode_u32(buf, entry);
322                         break;
323                 case APT_STR:
324                         ap_encode_str(buf, entry);
325                         break;
326                 }
327         }
328
329         *length = buf->len;
330
331         return g_byte_array_free(buf, FALSE);
332 }
333
334 gboolean map_ap_get_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t *val)
335 {
336         struct ap_entry *entry;
337         int offset = find_ap_def_offset(tag);
338
339         if (offset < 0 || ap_defs[offset].type != APT_UINT8)
340                 return FALSE;
341
342         entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
343         if (entry == NULL)
344                 return FALSE;
345
346         *val = entry->val.u8;
347
348         return TRUE;
349 }
350
351 gboolean map_ap_get_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t *val)
352 {
353         struct ap_entry *entry;
354         int offset = find_ap_def_offset(tag);
355
356         if (offset < 0 || ap_defs[offset].type != APT_UINT16)
357                 return FALSE;
358
359         entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
360         if (entry == NULL)
361                 return FALSE;
362
363         *val = entry->val.u16;
364
365         return TRUE;
366 }
367
368 gboolean map_ap_get_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t *val)
369 {
370         struct ap_entry *entry;
371         int offset = find_ap_def_offset(tag);
372
373         if (offset < 0 || ap_defs[offset].type != APT_UINT32)
374                 return FALSE;
375
376         entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
377         if (entry == NULL)
378                 return FALSE;
379
380         *val = entry->val.u32;
381
382         return TRUE;
383 }
384
385 const char *map_ap_get_string(map_ap_t *ap, enum map_ap_tag tag)
386 {
387         struct ap_entry *entry;
388         int offset = find_ap_def_offset(tag);
389
390         if (offset < 0 || ap_defs[offset].type != APT_STR)
391                 return NULL;
392
393         entry = g_hash_table_lookup(ap, GINT_TO_POINTER(tag));
394         if (entry == NULL)
395                 return NULL;
396
397         return entry->val.str;
398 }
399
400 gboolean map_ap_set_u8(map_ap_t *ap, enum map_ap_tag tag, uint8_t val)
401 {
402         struct ap_entry *entry;
403         int offset = find_ap_def_offset(tag);
404
405         if (offset < 0 || ap_defs[offset].type != APT_UINT8)
406                 return FALSE;
407
408         entry = g_new0(struct ap_entry, 1);
409         entry->tag = tag;
410         entry->val.u8 = val;
411
412         g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
413
414         return TRUE;
415 }
416
417 gboolean map_ap_set_u16(map_ap_t *ap, enum map_ap_tag tag, uint16_t val)
418 {
419         struct ap_entry *entry;
420         int offset = find_ap_def_offset(tag);
421
422         if (offset < 0 || ap_defs[offset].type != APT_UINT16)
423                 return FALSE;
424
425         entry = g_new0(struct ap_entry, 1);
426         entry->tag = tag;
427         entry->val.u16 = val;
428
429         g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
430
431         return TRUE;
432 }
433
434 gboolean map_ap_set_u32(map_ap_t *ap, enum map_ap_tag tag, uint32_t val)
435 {
436         struct ap_entry *entry;
437         int offset = find_ap_def_offset(tag);
438
439         if (offset < 0 || ap_defs[offset].type != APT_UINT32)
440                 return FALSE;
441
442         entry = g_new0(struct ap_entry, 1);
443         entry->tag = tag;
444         entry->val.u32 = val;
445
446         g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
447
448         return TRUE;
449 }
450
451 gboolean map_ap_set_string(map_ap_t *ap, enum map_ap_tag tag, const char *val)
452 {
453         struct ap_entry *entry;
454         int offset = find_ap_def_offset(tag);
455
456         if (offset < 0 || ap_defs[offset].type != APT_STR)
457                 return FALSE;
458
459         entry = g_new0(struct ap_entry, 1);
460         entry->tag = tag;
461         entry->val.str = g_strdup(val);
462
463         g_hash_table_insert(ap, GINT_TO_POINTER(tag), entry);
464
465         return TRUE;
466 }