updates.
[silc.git] / lib / silccore / silcpayload.c
1 /*
2
3   silcpayload.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 2000 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; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /* Implementation of generic payloads described in the protocol 
21    specification drafts. */
22 /* $Id$ */
23
24 #include "silcincludes.h"
25 #include "silcpayload.h"
26
27 /******************************************************************************
28
29                                 ID Payload
30
31 ******************************************************************************/
32
33 struct SilcIDPayloadStruct {
34   SilcIdType type;
35   uint16 len;
36   unsigned char *id;
37 };
38
39 /* Parses buffer and return ID payload into payload structure */
40
41 SilcIDPayload silc_id_payload_parse(const unsigned char *payload,
42                                     uint32 payload_len)
43 {
44   SilcBufferStruct buffer;
45   SilcIDPayload new;
46   int ret;
47
48   SILC_LOG_DEBUG(("Parsing ID payload"));
49
50   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
51   new = silc_calloc(1, sizeof(*new));
52
53   ret = silc_buffer_unformat(&buffer,
54                              SILC_STR_UI_SHORT(&new->type),
55                              SILC_STR_UI_SHORT(&new->len),
56                              SILC_STR_END);
57   if (ret == -1)
58     goto err;
59
60   silc_buffer_pull(&buffer, 4);
61
62   if (new->len > buffer.len)
63     goto err;
64
65   ret = silc_buffer_unformat(&buffer,
66                              SILC_STR_UI_XNSTRING_ALLOC(&new->id, new->len),
67                              SILC_STR_END);
68   if (ret == -1)
69     goto err;
70
71   silc_buffer_push(&buffer, 4);
72
73   return new;
74
75  err:
76   silc_free(new);
77   return NULL;
78 }
79
80 /* Return the ID directly from the raw payload data. */
81
82 void *silc_id_payload_parse_id(const unsigned char *data, uint32 len)
83 {
84   SilcBufferStruct buffer;
85   SilcIdType type;
86   uint16 idlen;
87   unsigned char *id_data = NULL;
88   int ret;
89   void *id;
90
91   silc_buffer_set(&buffer, (unsigned char *)data, len);
92   ret = silc_buffer_unformat(&buffer,
93                              SILC_STR_UI_SHORT(&type),
94                              SILC_STR_UI_SHORT(&idlen),
95                              SILC_STR_END);
96   if (ret == -1)
97     goto err;
98
99   silc_buffer_pull(&buffer, 4);
100
101   if (idlen > buffer.len)
102     goto err;
103
104   ret = silc_buffer_unformat(&buffer,
105                              SILC_STR_UI_XNSTRING_ALLOC(&id_data, idlen),
106                              SILC_STR_END);
107   if (ret == -1)
108     goto err;
109
110   id = silc_id_str2id(id_data, idlen, type);
111   silc_free(id_data);
112   return id;
113
114  err:
115   return NULL;
116 }
117
118 /* Encodes ID Payload */
119
120 SilcBuffer silc_id_payload_encode(const void *id, SilcIdType type)
121 {
122   SilcBuffer buffer;
123   unsigned char *id_data;
124   uint32 len;
125
126   id_data = silc_id_id2str(id, type);
127   len = silc_id_get_len(id, type);
128   buffer = silc_id_payload_encode_data((const unsigned char *)id_data,
129                                        len, type);
130   silc_free(id_data);
131   return buffer;
132 }
133
134 SilcBuffer silc_id_payload_encode_data(const unsigned char *id,
135                                        uint32 id_len, SilcIdType type)
136 {
137   SilcBuffer buffer;
138
139   SILC_LOG_DEBUG(("Encoding %s ID payload",
140                   type == SILC_ID_CLIENT ? "Client" :
141                   type == SILC_ID_SERVER ? "Server" : "Channel"));
142
143   buffer = silc_buffer_alloc(4 + id_len);
144   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
145   silc_buffer_format(buffer,
146                      SILC_STR_UI_SHORT(type),
147                      SILC_STR_UI_SHORT(id_len),
148                      SILC_STR_UI_XNSTRING(id, id_len),
149                      SILC_STR_END);
150   return buffer;
151 }
152
153 /* Free ID Payload */
154
155 void silc_id_payload_free(SilcIDPayload payload)
156 {
157   if (payload) {
158     silc_free(payload->id);
159     silc_free(payload);
160   }
161 }
162
163 /* Get ID type */
164
165 SilcIdType silc_id_payload_get_type(SilcIDPayload payload)
166 {
167   return payload ? payload->type : 0;
168 }
169
170 /* Get ID */
171
172 void *silc_id_payload_get_id(SilcIDPayload payload)
173 {
174   return payload ? silc_id_str2id(payload->id, payload->len,
175                                   payload->type) : NULL;
176 }
177
178 /* Get raw ID data. Data is duplicated. */
179
180 unsigned char *silc_id_payload_get_data(SilcIDPayload payload)
181 {
182   unsigned char *ret;
183
184   if (!payload)
185     return NULL;
186
187   ret = silc_calloc(payload->len, sizeof(*ret));
188   memcpy(ret, payload->id, payload->len);
189   return ret;
190 }
191
192 /* Get length of ID */
193
194 uint32 silc_id_payload_get_len(SilcIDPayload payload)
195 {
196   return payload ? payload->len : 0;
197 }
198
199 /******************************************************************************
200
201                              Argument Payload
202
203 ******************************************************************************/
204
205 struct SilcArgumentPayloadStruct {
206   uint32 argc;
207   unsigned char **argv;
208   uint32 *argv_lens;
209   uint32 *argv_types;
210   uint32 pos;
211 };
212
213 /* Parses arguments and returns them into Argument Payload structure. */
214
215 SilcArgumentPayload silc_argument_payload_parse(const unsigned char *payload,
216                                                 uint32 payload_len,
217                                                 uint32 argc)
218 {
219   SilcBufferStruct buffer;
220   SilcArgumentPayload new;
221   uint16 p_len = 0;
222   unsigned char arg_num = 0;
223   unsigned char arg_type = 0;
224   uint32 pull_len = 0;
225   int i = 0, ret;
226
227   SILC_LOG_DEBUG(("Parsing argument payload"));
228
229   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
230   new = silc_calloc(1, sizeof(*new));
231   new->argv = silc_calloc(argc, sizeof(unsigned char *));
232   new->argv_lens = silc_calloc(argc, sizeof(uint32));
233   new->argv_types = silc_calloc(argc, sizeof(uint32));
234     
235   /* Get arguments */
236   arg_num = 1;
237   for (i = 0; i < argc; i++) {
238     ret = silc_buffer_unformat(&buffer,
239                                SILC_STR_UI_SHORT(&p_len),
240                                SILC_STR_UI_CHAR(&arg_type),
241                                SILC_STR_END);
242     if (ret == -1)
243       goto err;
244     
245     new->argv_lens[i] = p_len;
246     new->argv_types[i] = arg_type;
247
248     if (p_len > buffer.len - 3)
249       break;
250     
251     /* Get argument data */
252     silc_buffer_pull(&buffer, 3);
253     ret = silc_buffer_unformat(&buffer,
254                                SILC_STR_UI_XNSTRING_ALLOC(&new->argv[i], 
255                                                           p_len),
256                                SILC_STR_END);
257     if (ret == -1)
258       goto err;
259
260     silc_buffer_pull(&buffer, p_len);
261     pull_len += 3 + p_len;
262   }
263
264   if (buffer.len != 0)
265     goto err;
266
267   new->argc = argc;
268   new->pos = 0;
269
270   silc_buffer_push(&buffer, pull_len);
271
272   return new;
273
274  err:
275   if (i) {
276     int k;
277
278     for (k = 0; k < i; k++)
279       silc_free(new->argv[k]);
280   }
281
282   silc_free(new->argv);
283   silc_free(new->argv_lens);
284   silc_free(new->argv_types);
285
286   if (new)
287     silc_free(new);
288
289   return NULL;
290 }
291
292 /* Encodes arguments in to Argument Paylods returning them to SilcBuffer. */
293
294 SilcBuffer silc_argument_payload_encode(uint32 argc,
295                                         unsigned char **argv,
296                                         uint32 *argv_lens,
297                                         uint32 *argv_types)
298 {
299   SilcBuffer buffer;
300   uint32 len;
301   int i;
302
303   SILC_LOG_DEBUG(("Encoding Argument payload"));
304
305   len = 0;
306   for (i = 0; i < argc; i++)
307     len += 3 + argv_lens[i];
308
309   buffer = silc_buffer_alloc(len);
310   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
311
312   /* Put arguments */
313   for (i = 0; i < argc; i++) {
314     silc_buffer_format(buffer,
315                        SILC_STR_UI_SHORT(argv_lens[i]),
316                        SILC_STR_UI_CHAR(argv_types[i]),
317                        SILC_STR_UI_XNSTRING(argv[i], argv_lens[i]),
318                        SILC_STR_END);
319     silc_buffer_pull(buffer, 3 + argv_lens[i]);
320   }
321
322   silc_buffer_push(buffer, len);
323
324   return buffer;
325 }
326
327 /* Same as above but encode the buffer from SilcArgumentPayload structure
328    instead of raw data. */
329
330 SilcBuffer silc_argument_payload_encode_payload(SilcArgumentPayload payload)
331 {
332   SilcBuffer buffer;
333   uint32 len;
334   int i;
335
336   SILC_LOG_DEBUG(("Encoding Argument payload"));
337
338   len = 0;
339   for (i = 0; i < payload->argc; i++)
340     len += 3 + payload->argv_lens[i];
341
342   buffer = silc_buffer_alloc(len);
343   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
344
345   /* Put arguments */
346   for (i = 0; i < payload->argc; i++) {
347     silc_buffer_format(buffer,
348                        SILC_STR_UI_SHORT(payload->argv_lens[i]),
349                        SILC_STR_UI_CHAR(payload->argv_types[i]),
350                        SILC_STR_UI_XNSTRING(payload->argv[i], 
351                                             payload->argv_lens[i]),
352                        SILC_STR_END);
353     silc_buffer_pull(buffer, 3 + payload->argv_lens[i]);
354   }
355
356   silc_buffer_push(buffer, len);
357
358   return buffer;
359 }
360
361 /* Frees Argument Payload */
362
363 void silc_argument_payload_free(SilcArgumentPayload payload)
364 {
365   int i;
366
367   if (payload) {
368     for (i = 0; i < payload->argc; i++)
369       silc_free(payload->argv[i]);
370
371     silc_free(payload->argv);
372     silc_free(payload->argv_lens);
373     silc_free(payload->argv_types);
374     silc_free(payload);
375   }
376 }
377
378 /* Returns number of arguments in payload */
379
380 uint32 silc_argument_get_arg_num(SilcArgumentPayload payload)
381 {
382   return payload ? payload->argc : 0;
383 }
384
385 /* Returns first argument from payload. */
386
387 unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload,
388                                            uint32 *ret_len)
389 {
390   if (!payload)
391     return NULL;
392
393   payload->pos = 0;
394
395   if (ret_len)
396     *ret_len = payload->argv_lens[payload->pos];
397
398   return payload->argv[payload->pos++];
399 }
400
401 /* Returns next argument from payload or NULL if no more arguments. */
402
403 unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload,
404                                           uint32 *ret_len)
405 {
406   if (!payload)
407     return NULL;
408
409   if (payload->pos >= payload->argc)
410     return NULL;
411
412   if (ret_len)
413     *ret_len = payload->argv_lens[payload->pos];
414
415   return payload->argv[payload->pos++];
416 }
417
418 /* Returns argument which type is `type'. */
419
420 unsigned char *silc_argument_get_arg_type(SilcArgumentPayload payload,
421                                           uint32 type,
422                                           uint32 *ret_len)
423 {
424   int i;
425
426   if (!payload)
427     return NULL;
428
429   for (i = 0; i < payload->argc; i++)
430     if (payload->argv_types[i] == type)
431       break;
432
433   if (i >= payload->argc)
434     return NULL;
435
436   if (ret_len)
437     *ret_len = payload->argv_lens[i];
438
439   return payload->argv[i];
440 }