Implemented the draft-riikonen-presence-attrs and Attribute
[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 */
78
79 SilcBuffer silc_attribute_payload_encode(SilcAttribute attribute,
80                                          SilcAttributeFlags flags,
81                                          const unsigned char *data,
82                                          SilcUInt32 data_len)
83 {
84   SilcBuffer buffer;
85
86   SILC_LOG_DEBUG(("Encoding Attribute Payload"));
87
88   buffer = silc_buffer_alloc_size(4 + data_len);
89   if (!buffer)
90     return NULL;
91
92   /* Encode the Attribute Payload */
93   silc_buffer_format(buffer, 
94                      SILC_STR_UI_CHAR(attribute),
95                      SILC_STR_UI_CHAR(flags),
96                      SILC_STR_UI_SHORT((SilcUInt16)data_len),
97                      SILC_STR_UI_XNSTRING(data, data_len),
98                      SILC_STR_END);
99
100   return buffer;
101 }
102
103 /* Parse list of payloads */
104
105 SilcDList silc_attribute_payload_parse_list(const unsigned char *payload,
106                                             SilcUInt32 payload_len)
107 {
108   SilcBufferStruct buffer;
109   SilcDList list;
110   SilcAttributePayload newp;
111   int len, ret;
112
113   SILC_LOG_DEBUG(("Parsing Attribute Payload list"));
114
115   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
116   list = silc_dlist_init();
117
118   while (buffer.len) {
119     newp = silc_calloc(1, sizeof(*newp));
120     if (!newp)
121       goto err;
122     ret = silc_buffer_unformat(&buffer,
123                                SILC_STR_UI_CHAR(&newp->attribute),
124                                SILC_STR_UI_CHAR(&newp->flags),
125                                SILC_STR_UI16_NSTRING_ALLOC(&newp->data, 
126                                                            &newp->data_len),
127                                SILC_STR_END);
128     if (ret == -1)
129       goto err;
130
131     if (newp->data_len > buffer.len) {
132       SILC_LOG_ERROR(("Incorrect attribute payload in list"));
133       goto err;
134     }
135
136     len = 4 + newp->data_len;
137     if (buffer.len < len)
138       break;
139     silc_buffer_pull(&buffer, len);
140
141     silc_dlist_add(list, newp);
142   }
143   
144   return list;
145
146  err:
147   silc_attribute_payload_list_free(list);
148   return NULL;
149 }
150
151 /* Encode list of payloads */
152
153 SilcBuffer silc_attribute_payload_encode_list(SilcUInt32 num_attrs, ...)
154 {
155   SilcBuffer buffer = NULL;
156   va_list ap;
157   int i, len = 0;
158   SilcAttribute attribute;
159   SilcAttributeFlags flags;
160   unsigned char *data;
161   SilcUInt32 data_len;
162
163   if (!num_attrs)
164     return NULL;
165
166   va_start(ap, num_attrs);
167   for (i = 0; i < num_attrs; i++) {
168     attribute = va_arg(ap, SilcUInt32);
169     flags = va_arg(ap, SilcUInt32);
170     data = va_arg(ap, unsigned char *);
171     data_len = va_arg(ap, SilcUInt32);
172
173     if (data || !data_len)
174       continue;
175
176     len = 4 + data_len;
177     buffer = silc_buffer_realloc(buffer,
178                                  (buffer ? buffer->truelen + len : len));
179     silc_buffer_pull_tail(buffer, (buffer->end - buffer->data));
180     silc_buffer_format(buffer, 
181                        SILC_STR_UI_CHAR(attribute),
182                        SILC_STR_UI_CHAR(flags),
183                        SILC_STR_UI_SHORT((SilcUInt16)data_len),
184                        SILC_STR_UI_XNSTRING(data, data_len),
185                        SILC_STR_END);
186     silc_buffer_pull(buffer, len);
187   }
188   va_end(ap);
189
190   if (buffer)
191     silc_buffer_push(buffer, buffer->data - buffer->head);
192
193   return buffer;
194 }
195
196 /* Free Attribute Payload */
197
198 void silc_attribute_payload_free(SilcAttributePayload payload)
199 {
200   silc_free(payload->data);
201   silc_free(payload);
202 }
203
204 /* Free's list of Attribute Payloads */
205
206 void silc_attribute_payload_list_free(SilcDList list)
207 {
208   SilcAttributePayload entry;
209
210   silc_dlist_start(list);
211   while ((entry = silc_dlist_get(list)) != SILC_LIST_END) {
212     silc_attribute_payload_free(entry);
213     silc_dlist_del(list, entry);
214   }
215
216   silc_dlist_uninit(list);
217 }
218
219 /* Return attribute type */
220
221 SilcAttribute silc_attribute_get_attribute(SilcAttributePayload payload)
222 {
223   return payload->attribute;
224 }
225
226 /* Return attribute flags */
227
228 SilcAttributeFlags silc_attribute_get_flags(SilcAttributePayload payload)
229 {
230   return payload->flags;
231 }
232
233 /* Return attribute data from the payload */
234
235 const unsigned char *silc_attribute_get_data(SilcAttributePayload payload,
236                                              SilcUInt32 *data_len)
237 {
238   if (data_len)
239     *data_len = payload->data_len;
240   return (const unsigned char *)payload->data;
241 }
242
243 /* Return parsed attribute object */
244
245 bool silc_attribute_get_object(SilcAttributePayload payload,
246                                SilcAttribute attribute,
247                                void **object, SilcUInt32 object_size)
248 {
249   SilcUInt16 len;
250   bool ret = FALSE;
251
252   if (!attribute || !object || !(*object))
253     return FALSE;
254
255   switch (attribute) {
256   case SILC_ATTRIBUTE_USER_INFO:
257     SILC_NOT_IMPLEMENTED("SILC_ATTRIBUTE_USER_INFO");
258     break;
259
260   case SILC_ATTRIBUTE_SERVICE:
261     {
262       SilcAttributeObjService *service = *object;
263       if (object_size != sizeof(*service))
264         break;
265       if (payload->data_len < 7)
266         break;
267       SILC_GET32_MSB(service->port, payload->data);
268       SILC_GET16_MSB(len, payload->data + 4);
269       if (payload->data_len < 7 + len)
270         break;
271       memcpy(service->address, payload->data + 6,
272              (len < sizeof(service->address) - 1 ? len :
273               sizeof(service->address) - 1));
274       service->status = payload->data[6 + len] ? TRUE : FALSE;
275       ret = TRUE;
276     }
277     break;
278
279   case SILC_ATTRIBUTE_STATUS_MOOD:
280   case SILC_ATTRIBUTE_PREFERRED_CONTACT:
281     {
282       SilcUInt32 *mask = *object;
283       if (object_size != sizeof(SilcUInt32))
284         break;
285       if (payload->data_len < 4)
286         break;
287       SILC_GET32_MSB(*mask, payload->data);
288       ret = TRUE;
289     }
290     break;
291
292   case SILC_ATTRIBUTE_STATUS_FREETEXT:
293   case SILC_ATTRIBUTE_PREFERRED_LANGUAGE:
294   case SILC_ATTRIBUTE_TIMEZONE:
295     {
296       char *string = *object;
297       if (payload->data_len < 2)
298         break;
299       SILC_GET16_MSB(len, payload->data);
300       if (payload->data_len < 2 + len)
301         break;
302       if (object_size < len)
303         break;
304       memcpy(string, payload->data + 2, len);
305       ret = TRUE;
306     }
307     break;
308
309   case SILC_ATTRIBUTE_STATUS_MESSAGE:
310   case SILC_ATTRIBUTE_EXTENSION:
311     {
312       SilcAttributeObjMime *mime = *object;
313       if (object_size != sizeof(*mime))
314         break;
315       mime->mime = silc_memdup(payload->data, payload->data_len);
316       mime->mime_len = payload->data_len;
317       ret = TRUE;
318     }
319     break;
320
321   case SILC_ATTRIBUTE_GEOLOCATION:
322     {
323       SilcAttributeObjGeo *geo = *object;
324       SilcBufferStruct buffer;
325       int res;
326       if (object_size != sizeof(*geo))
327         break;
328       silc_buffer_set(&buffer, (unsigned char *)payload->data,
329                       payload->data_len);
330       res = silc_buffer_unformat(&buffer,
331                                  SILC_STR_UI16_STRING_ALLOC(&geo->longitude),
332                                  SILC_STR_UI16_STRING_ALLOC(&geo->latitude),
333                                  SILC_STR_UI16_STRING_ALLOC(&geo->altitude),
334                                  SILC_STR_UI16_STRING_ALLOC(&geo->accuracy),
335                                  SILC_STR_END);
336       if (res == 1)
337         break;
338       ret = TRUE;
339     }
340     break;
341
342   case SILC_ATTRIBUTE_DEVICE_INFO:
343     {
344       SilcAttributeObjDevice *dev = *object;
345       SilcBufferStruct buffer;
346       SilcUInt32 type;
347       int res;
348       if (object_size != sizeof(*dev))
349         break;
350       silc_buffer_set(&buffer, (unsigned char *)payload->data,
351                       payload->data_len);
352       res =
353         silc_buffer_unformat(&buffer,
354                              SILC_STR_UI_INT(&type),
355                              SILC_STR_UI16_STRING_ALLOC(&dev->manufacturer),
356                              SILC_STR_UI16_STRING_ALLOC(&dev->version),
357                              SILC_STR_UI16_STRING_ALLOC(&dev->model),
358                              SILC_STR_UI16_STRING_ALLOC(&dev->language),
359                              SILC_STR_END);
360       if (res == 1)
361         break;
362       dev->type = type;
363       ret = TRUE;
364     }
365     break;
366
367   case SILC_ATTRIBUTE_USER_PUBLIC_KEY:
368   case SILC_ATTRIBUTE_SERVER_PUBLIC_KEY:
369     {
370       SilcAttributeObjPk *pk = *object;
371       SilcBufferStruct buffer;
372       int res;
373       if (object_size != sizeof(*pk))
374         break;
375       silc_buffer_set(&buffer, (unsigned char *)payload->data,
376                       payload->data_len);
377       res =
378         silc_buffer_unformat(&buffer,
379                              SILC_STR_UI16_NSTRING_ALLOC(&pk->type, &len),
380                              SILC_STR_END);
381       if (res == 1)
382         break;
383       pk->data = silc_memdup(payload->data + 2 + len,
384                              payload->data_len - 2 - len);
385       pk->data_len = payload->data_len - 2 - len;
386       ret = TRUE;
387     }
388     break;
389
390   case SILC_ATTRIBUTE_USER_DIGITAL_SIGNATURE:
391   case SILC_ATTRIBUTE_SERVER_DIGITAL_SIGNATURE:
392     {
393       SilcAttributeObjPk *pk = *object;
394       if (object_size != sizeof(*pk))
395         break;
396       pk->type = NULL;
397       pk->data = silc_memdup(payload->data, payload->data_len);
398       pk->data_len = payload->data_len;
399       ret = TRUE;
400     }
401     break;
402
403   default:
404     break;
405   }
406
407   return ret;
408 }