Cleanup.
[silc.git] / lib / silccore / silcattrs.c
1 /*
2
3   silcattrs.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2002 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; version 2 of the License.
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 */
19 /* Implementation of Attribute Payload routines */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23 #include "silcattrs.h"
24
25 /******************************************************************************
26
27                              Attribute Payload
28
29 ******************************************************************************/
30
31 struct SilcAttributePayloadStruct {
32   SilcAttribute attribute;
33   SilcAttributeFlags flags;
34   SilcUInt16 data_len;
35   unsigned char *data;
36 };
37
38 /* Parse one attribute payload */
39
40 SilcAttributePayload
41 silc_attribute_payload_parse(const unsigned char *payload,
42                              SilcUInt32 payload_len)
43 {
44   SilcBufferStruct buffer;
45   SilcAttributePayload newp;
46   int ret;
47
48   SILC_LOG_DEBUG(("Parsing attribute payload"));
49
50   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
51   newp = silc_calloc(1, sizeof(*newp));
52   if (!newp)
53     return NULL;
54
55   /* Parse the Attribute Payload. */
56   ret = silc_buffer_unformat(&buffer,
57                              SILC_STR_UI_CHAR(&newp->attribute),
58                              SILC_STR_UI_CHAR(&newp->flags),
59                              SILC_STR_UI16_NSTRING_ALLOC(&newp->data, 
60                                                          &newp->data_len),
61                              SILC_STR_END);
62   if (ret == -1)
63     goto err;
64
65   if (newp->data_len > buffer.len - 4) {
66     SILC_LOG_ERROR(("Incorrect attribute payload"));
67     goto err;
68   }
69
70   return newp;
71
72  err:
73   silc_attribute_payload_free(newp);
74   return NULL;
75 }
76
77 /* Encode one attribute payload to buffer */
78
79 SilcBuffer silc_attribute_payload_encode(SilcBuffer attrs,
80                                          SilcAttribute attribute,
81                                          SilcAttributeFlags flags,
82                                          void *object,
83                                          SilcUInt32 object_size)
84 {
85   SilcBuffer buffer, tmpbuf = NULL;
86   unsigned char tmp[4], *str = NULL;
87   int len;
88
89   SILC_LOG_DEBUG(("Encoding Attribute Payload"));
90
91   /* Encode according to attribute type */
92   if (flags & SILC_ATTRIBUTE_FLAG_VALID) {
93     if (!object || !object_size)
94       return NULL;
95
96     switch (attribute) {
97
98     case SILC_ATTRIBUTE_USER_INFO:
99       SILC_NOT_IMPLEMENTED("SILC_ATTRIBUTE_USER_INFO");
100       break;
101
102     case SILC_ATTRIBUTE_SERVICE:
103       {
104         SilcAttributeObjService *service = object;
105         if (object_size != sizeof(*service))
106           return NULL;
107         len = strlen(service->address);
108         str = silc_malloc(7 + len);
109         if (!str)
110           return NULL;
111         SILC_PUT32_MSB(service->port, str);
112         SILC_PUT16_MSB(len, str + 4);
113         memcpy(str + 6, service->address, len);
114         str[6 + len] = service->status;
115       }
116       break;
117
118     case SILC_ATTRIBUTE_STATUS_MOOD:
119     case SILC_ATTRIBUTE_PREFERRED_CONTACT:
120       {
121         SilcUInt32 mask = (SilcUInt32)object;
122         if (object_size != sizeof(SilcUInt32))
123           return NULL;
124         SILC_PUT32_MSB(mask, tmp);
125         object = tmp;
126         object_size = sizeof(SilcUInt32);
127       }
128       break;
129
130     case SILC_ATTRIBUTE_STATUS_FREETEXT:
131     case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
132     case SILC_ATTRIBUTE_TIMEZONE:
133       {
134         unsigned char *string = object;
135         str = silc_malloc(2 + object_size);
136         if (!str)
137           return NULL;
138         SILC_PUT16_MSB(object_size, str);
139         memcpy(str + 2, string, object_size);
140         object = str;
141         object_size += 2;
142       }
143       break;
144
145     case SILC_ATTRIBUTE_STATUS_MESSAGE:
146     case SILC_ATTRIBUTE_EXTENSION:
147       {
148         SilcAttributeObjMime *mime = object;
149         if (object_size != sizeof(*mime))
150           return NULL;
151         object = (void *)mime->mime;
152         object_size = mime->mime_len;
153       }
154       break;
155
156     case SILC_ATTRIBUTE_GEOLOCATION:
157       {
158         SilcAttributeObjGeo *geo = object;
159         if (object_size != sizeof(*geo))
160           return NULL;
161         len =
162           (geo->longitude ? strlen(geo->longitude) : 0) +
163           (geo->latitude  ? strlen(geo->latitude)  : 0) +
164           (geo->altitude  ? strlen(geo->altitude)  : 0) +
165           (geo->accuracy  ? strlen(geo->accuracy)  : 0);
166         if (!len)
167           return NULL;
168         tmpbuf = silc_buffer_alloc_size(8 + len);
169         if (!tmpbuf)
170           return NULL;
171         silc_buffer_format(tmpbuf,
172                            SILC_STR_UI16_STRING(geo->longitude),
173                            SILC_STR_UI16_STRING(geo->latitude),
174                            SILC_STR_UI16_STRING(geo->altitude),
175                            SILC_STR_UI16_STRING(geo->accuracy),
176                            SILC_STR_END);
177       }
178       break;
179
180     case SILC_ATTRIBUTE_DEVICE_INFO:
181       {
182         SilcAttributeObjDevice *dev = object;
183         if (object_size != sizeof(*dev))
184           return NULL;
185         len =
186           (dev->manufacturer ? strlen(dev->manufacturer) : 0) +
187           (dev->version      ? strlen(dev->version)      : 0) +
188           (dev->model        ? strlen(dev->model)        : 0) +
189           (dev->language     ? strlen(dev->language)     : 0);
190         tmpbuf = silc_buffer_alloc_size(4 + 8 + len);
191         if (!tmpbuf)
192           return NULL;
193         silc_buffer_format(tmpbuf,
194                            SILC_STR_UI_INT(dev->type),
195                            SILC_STR_UI16_STRING(dev->manufacturer),
196                            SILC_STR_UI16_STRING(dev->version),
197                            SILC_STR_UI16_STRING(dev->model),
198                            SILC_STR_UI16_STRING(dev->language),
199                            SILC_STR_END);
200       }
201       break;
202
203     case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
204     case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
205       {
206         SilcAttributeObjPk *pk = object;
207         if (object_size != sizeof(*pk))
208           return NULL;
209         len = (pk->type ? strlen(pk->type) : 0);
210         tmpbuf = silc_buffer_alloc_size(2 + len + pk->data_len);
211         if (!tmpbuf)
212           return NULL;
213         silc_buffer_format(tmpbuf,
214                            SILC_STR_UI_SHORT(len),
215                            SILC_STR_UI16_STRING(pk->type),
216                            SILC_STR_UI_XNSTRING(pk->data, pk->data_len),
217                            SILC_STR_END);
218       }
219       break;
220
221     case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
222     case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
223       {
224         SilcAttributeObjPk *pk = object;
225         if (object_size != sizeof(*pk))
226           return NULL;
227         object = pk->data;
228         object_size = pk->data_len;
229       }
230       break;
231
232     default:
233       return NULL;
234       break;
235     }
236   }
237
238   buffer = attrs;
239   len = 4 + object_size;
240
241   if (!buffer) {
242     buffer = silc_buffer_alloc_size(len);
243   } else {
244     buffer = silc_buffer_realloc(buffer,
245                                  (buffer ? buffer->truelen + len : len));
246     silc_buffer_pull_tail(buffer, (buffer->end - buffer->data));
247   }
248
249   silc_buffer_format(buffer, 
250                      SILC_STR_UI_CHAR(attribute),
251                      SILC_STR_UI_CHAR(flags),
252                      SILC_STR_UI_SHORT((SilcUInt16)object_size),
253                      SILC_STR_UI_XNSTRING(object, object_size),
254                      SILC_STR_END);
255
256   silc_buffer_pull(buffer, len);
257   if (buffer)
258     silc_buffer_push(buffer, buffer->data - buffer->head);
259
260   if (tmpbuf)
261     silc_buffer_free(tmpbuf);
262   silc_free(str);
263
264   return buffer;
265 }
266
267 /* Parse list of payloads */
268
269 SilcDList silc_attribute_payload_parse_list(const unsigned char *payload,
270                                             SilcUInt32 payload_len)
271 {
272   SilcBufferStruct buffer;
273   SilcDList list;
274   SilcAttributePayload newp;
275   int len, ret;
276
277   SILC_LOG_DEBUG(("Parsing Attribute Payload list"));
278
279   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
280   list = silc_dlist_init();
281
282   while (buffer.len) {
283     newp = silc_calloc(1, sizeof(*newp));
284     if (!newp)
285       goto err;
286     ret = silc_buffer_unformat(&buffer,
287                                SILC_STR_UI_CHAR(&newp->attribute),
288                                SILC_STR_UI_CHAR(&newp->flags),
289                                SILC_STR_UI16_NSTRING_ALLOC(&newp->data, 
290                                                            &newp->data_len),
291                                SILC_STR_END);
292     if (ret == -1)
293       goto err;
294
295     if (newp->data_len > buffer.len) {
296       SILC_LOG_ERROR(("Incorrect attribute payload in list"));
297       goto err;
298     }
299
300     len = 4 + newp->data_len;
301     if (buffer.len < len)
302       break;
303     silc_buffer_pull(&buffer, len);
304
305     silc_dlist_add(list, newp);
306   }
307   
308   return list;
309
310  err:
311   silc_attribute_payload_list_free(list);
312   return NULL;
313 }
314
315 /* Free Attribute Payload */
316
317 void silc_attribute_payload_free(SilcAttributePayload payload)
318 {
319   silc_free(payload->data);
320   silc_free(payload);
321 }
322
323 /* Free's list of Attribute Payloads */
324
325 void silc_attribute_payload_list_free(SilcDList list)
326 {
327   SilcAttributePayload entry;
328
329   silc_dlist_start(list);
330   while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
331     silc_attribute_payload_free(entry);
332     silc_dlist_del(list, entry);
333   }
334
335   silc_dlist_uninit(list);
336 }
337
338 /* Return attribute type */
339
340 SilcAttribute silc_attribute_get_attribute(SilcAttributePayload payload)
341 {
342   return payload->attribute;
343 }
344
345 /* Return attribute flags */
346
347 SilcAttributeFlags silc_attribute_get_flags(SilcAttributePayload payload)
348 {
349   return payload->flags;
350 }
351
352 /* Return attribute data from the payload */
353
354 const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
355                                              SilcUInt32 *data_len)
356 {
357   if (data_len)
358     *data_len = payload->data_len;
359   return (const unsigned char *)payload->data;
360 }
361
362 /* Return parsed attribute object */
363
364 bool silc_attribute_get_object(SilcAttributePayload payload,
365                                SilcAttribute attribute,
366                                void **object, SilcUInt32 object_size)
367 {
368   SilcUInt16 len;
369   bool ret = FALSE;
370
371   if (!attribute || payload->attribute != attribute || !object || !(*object) ||
372       payload->flags & SILC_ATTRIBUTE_FLAG_INVALID)
373     return FALSE;
374
375   switch (attribute) {
376   case SILC_ATTRIBUTE_USER_INFO:
377     SILC_NOT_IMPLEMENTED("SILC_ATTRIBUTE_USER_INFO");
378     break;
379
380   case SILC_ATTRIBUTE_SERVICE:
381     {
382       SilcAttributeObjService *service = *object;
383       if (object_size != sizeof(*service))
384         break;
385       if (payload->data_len < 7)
386         break;
387       SILC_GET32_MSB(service->port, payload->data);
388       SILC_GET16_MSB(len, payload->data + 4);
389       if (payload->data_len < 7 + len)
390         break;
391       memcpy(service->address, payload->data + 6,
392              (len < sizeof(service->address) - 1 ? len :
393               sizeof(service->address) - 1));
394       service->status = payload->data[6 + len] ? TRUE : FALSE;
395       ret = TRUE;
396     }
397     break;
398
399   case SILC_ATTRIBUTE_STATUS_MOOD:
400   case SILC_ATTRIBUTE_PREFERRED_CONTACT:
401     {
402       SilcUInt32 *mask = *object;
403       if (object_size != sizeof(SilcUInt32))
404         break;
405       if (payload->data_len < 4)
406         break;
407       SILC_GET32_MSB(*mask, payload->data);
408       ret = TRUE;
409     }
410     break;
411
412   case SILC_ATTRIBUTE_STATUS_FREETEXT:
413   case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
414   case SILC_ATTRIBUTE_TIMEZONE:
415     {
416       char *string = *object;
417       if (payload->data_len < 2)
418         break;
419       SILC_GET16_MSB(len, payload->data);
420       if (payload->data_len < 2 + len)
421         break;
422       if (object_size < len)
423         break;
424       memcpy(string, payload->data + 2, len);
425       ret = TRUE;
426     }
427     break;
428
429   case SILC_ATTRIBUTE_STATUS_MESSAGE:
430   case SILC_ATTRIBUTE_EXTENSION:
431     {
432       SilcAttributeObjMime *mime = *object;
433       if (object_size != sizeof(*mime))
434         break;
435       mime->mime = (const unsigned char *)payload->data;
436       mime->mime_len = payload->data_len;
437       ret = TRUE;
438     }
439     break;
440
441   case SILC_ATTRIBUTE_GEOLOCATION:
442     {
443       SilcAttributeObjGeo *geo = *object;
444       SilcBufferStruct buffer;
445       int res;
446       if (object_size != sizeof(*geo))
447         break;
448       silc_buffer_set(&buffer, (unsigned char *)payload->data,
449                       payload->data_len);
450       res = silc_buffer_unformat(&buffer,
451                                  SILC_STR_UI16_STRING_ALLOC(&geo->longitude),
452                                  SILC_STR_UI16_STRING_ALLOC(&geo->latitude),
453                                  SILC_STR_UI16_STRING_ALLOC(&geo->altitude),
454                                  SILC_STR_UI16_STRING_ALLOC(&geo->accuracy),
455                                  SILC_STR_END);
456       if (res == 1)
457         break;
458       ret = TRUE;
459     }
460     break;
461
462   case SILC_ATTRIBUTE_DEVICE_INFO:
463     {
464       SilcAttributeObjDevice *dev = *object;
465       SilcBufferStruct buffer;
466       SilcUInt32 type;
467       int res;
468       if (object_size != sizeof(*dev))
469         break;
470       silc_buffer_set(&buffer, (unsigned char *)payload->data,
471                       payload->data_len);
472       res =
473         silc_buffer_unformat(&buffer,
474                              SILC_STR_UI_INT(&type),
475                              SILC_STR_UI16_STRING_ALLOC(&dev->manufacturer),
476                              SILC_STR_UI16_STRING_ALLOC(&dev->version),
477                              SILC_STR_UI16_STRING_ALLOC(&dev->model),
478                              SILC_STR_UI16_STRING_ALLOC(&dev->language),
479                              SILC_STR_END);
480       if (res == 1)
481         break;
482       dev->type = type;
483       ret = TRUE;
484     }
485     break;
486
487   case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
488   case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
489     {
490       SilcAttributeObjPk *pk = *object;
491       SilcBufferStruct buffer;
492       int res;
493       if (object_size != sizeof(*pk))
494         break;
495       silc_buffer_set(&buffer, (unsigned char *)payload->data,
496                       payload->data_len);
497       res =
498         silc_buffer_unformat(&buffer,
499                              SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
500                              SILC_STR_END);
501       if (res == 1)
502         break;
503       pk->data = silc_memdup(payload->data + 2 + len,
504                              payload->data_len - 2 - len);
505       pk->data_len = payload->data_len - 2 - len;
506       ret = TRUE;
507     }
508     break;
509
510   case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
511   case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
512     {
513       SilcAttributeObjPk *pk = *object;
514       if (object_size != sizeof(*pk))
515         break;
516       pk->type = NULL;
517       pk->data = silc_memdup(payload->data, payload->data_len);
518       pk->data_len = payload->data_len;
519       ret = TRUE;
520     }
521     break;
522
523   default:
524     break;
525   }
526
527   return ret;
528 }