update
[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   unsigned short len;
36   unsigned char *id;
37 };
38
39 /* Parses buffer and return ID payload into payload structure */
40
41 SilcIDPayload silc_id_payload_parse(SilcBuffer buffer)
42 {
43   SilcIDPayload new;
44
45   SILC_LOG_DEBUG(("Parsing ID payload"));
46
47   new = silc_calloc(1, sizeof(*new));
48
49   silc_buffer_unformat(buffer,
50                        SILC_STR_UI_SHORT(&new->type),
51                        SILC_STR_UI_SHORT(&new->len),
52                        SILC_STR_END);
53
54   silc_buffer_pull(buffer, 4);
55
56   if (new->len > buffer->len)
57     goto err;
58
59   silc_buffer_unformat(buffer,
60                        SILC_STR_UI_XNSTRING_ALLOC(&new->id, new->len),
61                        SILC_STR_END);
62   silc_buffer_push(buffer, 4);
63
64   return new;
65
66  err:
67   silc_free(new);
68   return NULL;
69 }
70
71 /* Parses data and return ID payload into payload structure. */
72
73 SilcIDPayload silc_id_payload_parse_data(unsigned char *data, 
74                                          unsigned int len)
75 {
76   SilcIDPayload new;
77   SilcBuffer buffer;
78
79   SILC_LOG_DEBUG(("Parsing ID payload"));
80
81   buffer = silc_buffer_alloc(len);
82   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
83   silc_buffer_put(buffer, data, len);
84
85   new = silc_calloc(1, sizeof(*new));
86
87   silc_buffer_unformat(buffer,
88                        SILC_STR_UI_SHORT(&new->type),
89                        SILC_STR_UI_SHORT(&new->len),
90                        SILC_STR_END);
91
92   silc_buffer_pull(buffer, 4);
93
94   if (new->len > buffer->len)
95     goto err;
96
97   silc_buffer_unformat(buffer,
98                        SILC_STR_UI_XNSTRING_ALLOC(&new->id, new->len),
99                        SILC_STR_END);
100
101   silc_buffer_free(buffer);
102   return new;
103
104  err:
105   silc_buffer_free(buffer);
106   silc_free(new);
107   return NULL;
108 }
109
110 /* Return the ID directly from the raw payload data. */
111
112 void *silc_id_payload_parse_id(unsigned char *data, unsigned int len)
113 {
114   SilcBuffer buffer;
115   SilcIdType type;
116   unsigned short idlen;
117   unsigned char *id;
118
119   buffer = silc_buffer_alloc(len);
120   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
121   silc_buffer_put(buffer, data, len);
122
123   silc_buffer_unformat(buffer,
124                        SILC_STR_UI_SHORT(&type),
125                        SILC_STR_UI_SHORT(&idlen),
126                        SILC_STR_END);
127
128   silc_buffer_pull(buffer, 4);
129
130   if (idlen > buffer->len)
131     goto err;
132
133   silc_buffer_unformat(buffer,
134                        SILC_STR_UI_XNSTRING_ALLOC(&id, idlen),
135                        SILC_STR_END);
136
137   silc_buffer_free(buffer);
138
139   return silc_id_str2id(id, type);
140
141  err:
142   silc_buffer_free(buffer);
143   return NULL;
144 }
145
146 /* Encodes ID Payload */
147
148 SilcBuffer silc_id_payload_encode(void *id, SilcIdType type)
149 {
150   SilcBuffer buffer;
151   unsigned char *id_data;
152   unsigned int len;
153
154   SILC_LOG_DEBUG(("Parsing ID payload"));
155
156   id_data = silc_id_id2str(id, type);
157   len = silc_id_get_len(type);
158
159   buffer = silc_buffer_alloc(4 + len);
160   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
161   silc_buffer_format(buffer,
162                      SILC_STR_UI_SHORT(type),
163                      SILC_STR_UI_SHORT(len),
164                      SILC_STR_UI_XNSTRING(id_data, len),
165                      SILC_STR_END);
166   silc_free(id_data);
167
168   return buffer;
169 }
170
171 /* Free ID Payload */
172
173 void silc_id_payload_free(SilcIDPayload payload)
174 {
175   if (payload) {
176     silc_free(payload->id);
177   }
178 }
179
180 /* Get ID type */
181
182 SilcIdType silc_id_payload_get_type(SilcIDPayload payload)
183 {
184   return payload->type;
185 }
186
187 /* Get ID */
188
189 void *silc_id_payload_get_id(SilcIDPayload payload)
190 {
191   return silc_id_str2id(payload->id, payload->type);
192 }
193
194 /* Get raw ID data. Data is duplicated. */
195
196 unsigned char *silc_id_payload_get_data(SilcIDPayload payload)
197 {
198   unsigned char *ret = silc_calloc(payload->len, sizeof(*ret));
199   memcpy(ret, payload->id, payload->len);
200   return ret;
201 }
202
203 /* Get length of ID */
204
205 unsigned int silc_id_payload_get_len(SilcIDPayload payload)
206 {
207   return payload->len;
208 }
209
210 /******************************************************************************
211
212                              Argument Payload
213
214 ******************************************************************************/
215
216 struct SilcArgumentPayloadStruct {
217   unsigned int argc;
218   unsigned char **argv;
219   unsigned int *argv_lens;
220   unsigned int *argv_types;
221   unsigned int pos;
222 };
223
224 /* Parses arguments and returns them into Argument Payload structure. */
225
226 SilcArgumentPayload silc_argument_payload_parse(SilcBuffer buffer,
227                                                 unsigned int argc)
228 {
229   SilcArgumentPayload new;
230   unsigned short payload_len = 0;
231   unsigned char arg_num = 0;
232   unsigned char arg_type = 0;
233   unsigned int pull_len = 0;
234   int i = 0;
235
236   SILC_LOG_DEBUG(("Parsing argument payload"));
237
238   new = silc_calloc(1, sizeof(*new));
239   new->argv = silc_calloc(argc, sizeof(unsigned char *));
240   new->argv_lens = silc_calloc(argc, sizeof(unsigned int));
241   new->argv_types = silc_calloc(argc, sizeof(unsigned int));
242     
243   /* Get arguments */
244   arg_num = 1;
245   for (i = 0; i < argc; i++) {
246     silc_buffer_unformat(buffer,
247                          SILC_STR_UI_SHORT(&payload_len),
248                          SILC_STR_UI_CHAR(&arg_type),
249                          SILC_STR_END);
250     
251     new->argv_lens[i] = payload_len;
252     new->argv_types[i] = arg_type;
253
254     if (payload_len > buffer->len)
255       break;
256     
257     /* Get argument data */
258     silc_buffer_pull(buffer, 3);
259     silc_buffer_unformat(buffer,
260                          SILC_STR_UI_XNSTRING_ALLOC(&new->argv[i], 
261                                                     payload_len),
262                          SILC_STR_END);
263
264     silc_buffer_pull(buffer, payload_len);
265     pull_len += 3 + payload_len;
266   }
267
268   if (buffer->len != 0)
269     goto err;
270
271   new->argc = argc;
272   new->pos = 0;
273
274   silc_buffer_push(buffer, pull_len);
275
276   return new;
277
278  err:
279   if (i) {
280     int k;
281
282     for (k = 0; k < i; k++)
283       silc_free(new->argv[k]);
284   }
285
286   silc_free(new->argv);
287   silc_free(new->argv_lens);
288   silc_free(new->argv_types);
289
290   if (new)
291     silc_free(new);
292
293   return NULL;
294 }
295
296 /* Encodes arguments in to Argument Paylods returning them to SilcBuffer. */
297
298 SilcBuffer silc_argument_payload_encode(unsigned int argc,
299                                         unsigned char **argv,
300                                         unsigned int *argv_lens,
301                                         unsigned int *argv_types)
302 {
303   SilcBuffer buffer;
304   unsigned int len;
305   int i;
306
307   SILC_LOG_DEBUG(("Encoding Argument payload"));
308
309   len = 0;
310   for (i = 0; i < argc; i++)
311     len += 3 + argv_lens[i];
312
313   buffer = silc_buffer_alloc(len);
314   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
315
316   /* Put arguments */
317   for (i = 0; i < argc; i++) {
318     silc_buffer_format(buffer,
319                        SILC_STR_UI_SHORT(argv_lens[i]),
320                        SILC_STR_UI_CHAR(argv_types[i]),
321                        SILC_STR_UI_XNSTRING(argv[i], argv_lens[i]),
322                        SILC_STR_END);
323     silc_buffer_pull(buffer, 3 + argv_lens[i]);
324   }
325
326   silc_buffer_push(buffer, len);
327
328   return buffer;
329 }
330
331 /* Same as above but encode the buffer from SilcArgumentPayload structure
332    instead of raw data. */
333
334 SilcBuffer silc_argument_payload_encode_payload(SilcArgumentPayload payload)
335 {
336   SilcBuffer buffer;
337   unsigned int len;
338   int i;
339
340   SILC_LOG_DEBUG(("Encoding Argument payload"));
341
342   len = 0;
343   for (i = 0; i < payload->argc; i++)
344     len += 3 + payload->argv_lens[i];
345
346   buffer = silc_buffer_alloc(len);
347   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
348
349   /* Put arguments */
350   for (i = 0; i < payload->argc; i++) {
351     silc_buffer_format(buffer,
352                        SILC_STR_UI_SHORT(payload->argv_lens[i]),
353                        SILC_STR_UI_CHAR(payload->argv_types[i]),
354                        SILC_STR_UI_XNSTRING(payload->argv[i], 
355                                             payload->argv_lens[i]),
356                        SILC_STR_END);
357     silc_buffer_pull(buffer, 3 + payload->argv_lens[i]);
358   }
359
360   silc_buffer_push(buffer, len);
361
362   return buffer;
363 }
364
365 #if 0
366 /* Encodes Argument payload with variable argument list. The arguments
367    must be: unsigned int, unsigned char *, unsigned int, ... One 
368    {unsigned int, unsigned char * and unsigned int} forms one argument, 
369    thus `argc' in case when sending one {unsigned int, unsigned char * 
370    and unsigned int} equals one (1) and when sending two of those it
371    equals two (2), and so on. This has to be preserved or bad things
372    will happen. The variable arguments is: {type, data, data_len}. */
373
374 SilcBuffer silc_command_encode_payload_va(unsigned int argc, ...)
375 {
376   va_list ap;
377   unsigned char **argv;
378   unsigned int *argv_lens = NULL, *argv_types = NULL;
379   unsigned char *x;
380   unsigned int x_len;
381   unsigned int x_type;
382   SilcBuffer buffer;
383   int i;
384
385   va_start(ap, argc);
386
387   argv = silc_calloc(argc, sizeof(unsigned char *));
388   argv_lens = silc_calloc(argc, sizeof(unsigned int));
389   argv_types = silc_calloc(argc, sizeof(unsigned int));
390
391   for (i = 0; i < argc; i++) {
392     x_type = va_arg(ap, unsigned int);
393     x = va_arg(ap, unsigned char *);
394     x_len = va_arg(ap, unsigned int);
395
396     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
397     memcpy(argv[i], x, x_len);
398     argv_lens[i] = x_len;
399     argv_types[i] = x_type;
400   }
401
402   buffer = silc_argument_payload_encode(argc, argv, 
403                                         argv_lens, argv_types);
404
405   for (i = 0; i < argc; i++)
406     silc_free(argv[i]);
407   silc_free(argv);
408   silc_free(argv_lens);
409   silc_free(argv_types);
410
411   return buffer;
412 }
413 #endif
414
415 /* Free's Command Payload */
416
417 void silc_argument_payload_free(SilcArgumentPayload payload)
418 {
419   int i;
420
421   if (payload) {
422     for (i = 0; i < payload->argc; i++)
423       silc_free(payload->argv[i]);
424
425     silc_free(payload->argv);
426     silc_free(payload);
427   }
428 }
429
430 /* Returns number of arguments in payload */
431
432 unsigned int silc_argument_get_arg_num(SilcArgumentPayload payload)
433 {
434   return payload->argc;
435 }
436
437 /* Returns first argument from payload. */
438
439 unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload,
440                                            unsigned int *ret_len)
441 {
442   payload->pos = 0;
443
444   if (ret_len)
445     *ret_len = payload->argv_lens[payload->pos];
446
447   return payload->argv[payload->pos++];
448 }
449
450 /* Returns next argument from payload or NULL if no more arguments. */
451
452 unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload,
453                                           unsigned int *ret_len)
454 {
455   if (payload->pos >= payload->argc)
456     return NULL;
457
458   if (ret_len)
459     *ret_len = payload->argv_lens[payload->pos];
460
461   return payload->argv[payload->pos++];
462 }
463
464 /* Returns argument which type is `type'. */
465
466 unsigned char *silc_argument_get_arg_type(SilcArgumentPayload payload,
467                                           unsigned int type,
468                                           unsigned int *ret_len)
469 {
470   int i;
471
472   for (i = 0; i < payload->argc; i++)
473     if (payload->argv_types[i] == type)
474       break;
475
476   if (i >= payload->argc)
477     return NULL;
478
479   if (ret_len)
480     *ret_len = payload->argv_lens[i];
481
482   return payload->argv[i];
483 }