Added id_payload_parse_data function
[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 /* Encodes ID Payload */
111
112 SilcBuffer silc_id_payload_encode(void *id, unsigned short len,
113                                   SilcIdType type)
114 {
115   SilcBuffer buffer;
116   unsigned char *id_data;
117
118   SILC_LOG_DEBUG(("Parsing ID payload"));
119
120   id_data = silc_id_id2str(id, type);
121
122   buffer = silc_buffer_alloc(4 + len);
123   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
124   silc_buffer_format(buffer,
125                      SILC_STR_UI_SHORT(type),
126                      SILC_STR_UI_SHORT(len),
127                      SILC_STR_UI_XNSTRING(id_data, len),
128                      SILC_STR_END);
129   silc_free(id_data);
130
131   return buffer;
132 }
133
134 /* Free ID Payload */
135
136 void silc_id_payload_free(SilcIDPayload payload)
137 {
138   if (payload) {
139     silc_free(payload->id);
140   }
141 }
142
143 /* Get ID type */
144
145 SilcIdType silc_id_payload_get_type(SilcIDPayload payload)
146 {
147   return payload->type;
148 }
149
150 /* Get ID */
151
152 void *silc_id_payload_get_id(SilcIDPayload payload)
153 {
154   return silc_id_str2id(payload->id, payload->type);
155 }
156
157 /******************************************************************************
158
159                              Argument Payload
160
161 ******************************************************************************/
162
163 struct SilcArgumentPayloadStruct {
164   unsigned int argc;
165   unsigned char **argv;
166   unsigned int *argv_lens;
167   unsigned int *argv_types;
168   unsigned int pos;
169 };
170
171 /* Parses arguments and returns them into Argument Payload structure. */
172
173 SilcArgumentPayload silc_argument_payload_parse(SilcBuffer buffer,
174                                                 unsigned int argc)
175 {
176   SilcArgumentPayload new;
177   unsigned short payload_len = 0;
178   unsigned char arg_num = 0;
179   unsigned int arg_type = 0;
180   unsigned int pull_len = 0;
181   int i = 0;
182
183   SILC_LOG_DEBUG(("Parsing argument payload"));
184
185   new = silc_calloc(1, sizeof(*new));
186   new->argv = silc_calloc(argc, sizeof(unsigned char *));
187   new->argv_lens = silc_calloc(argc, sizeof(unsigned int));
188   new->argv_types = silc_calloc(argc, sizeof(unsigned int));
189     
190   /* Get arguments */
191   arg_num = 1;
192   for (i = 0; i < argc; i++) {
193     silc_buffer_unformat(buffer,
194                          SILC_STR_UI_SHORT(&payload_len),
195                          SILC_STR_UI_CHAR(&arg_type),
196                          SILC_STR_END);
197     
198     new->argv_lens[i] = payload_len;
199     new->argv_types[i] = arg_type;
200
201     if (payload_len > buffer->len)
202       break;
203     
204     /* Get argument data */
205     silc_buffer_pull(buffer, 3);
206     silc_buffer_unformat(buffer,
207                          SILC_STR_UI_XNSTRING_ALLOC(&new->argv[i], 
208                                                     payload_len),
209                          SILC_STR_END);
210
211     silc_buffer_pull(buffer, payload_len);
212     pull_len += 3 + payload_len;
213   }
214
215   if (buffer->len != 0)
216     goto err;
217
218   new->argc = argc;
219   new->pos = 0;
220
221   silc_buffer_push(buffer, pull_len);
222
223   return new;
224
225  err:
226   if (i) {
227     int k;
228
229     for (k = 0; k < i; k++)
230       silc_free(new->argv[k]);
231   }
232
233   silc_free(new->argv);
234   silc_free(new->argv_lens);
235   silc_free(new->argv_types);
236
237   if (new)
238     silc_free(new);
239
240   return NULL;
241 }
242
243 /* Encodes arguments in to Argument Paylods returning them to SilcBuffer. */
244
245 SilcBuffer silc_argument_payload_encode(unsigned int argc,
246                                         unsigned char **argv,
247                                         unsigned int *argv_lens,
248                                         unsigned int *argv_types)
249 {
250   SilcBuffer buffer;
251   unsigned int len;
252   int i;
253
254   SILC_LOG_DEBUG(("Encoding Argument payload"));
255
256   len = 0;
257   for (i = 0; i < argc; i++)
258     len += 3 + argv_lens[i];
259
260   buffer = silc_buffer_alloc(len);
261   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
262
263   /* Put arguments */
264   for (i = 0; i < argc; i++) {
265     silc_buffer_format(buffer,
266                        SILC_STR_UI_SHORT(argv_lens[i]),
267                        SILC_STR_UI_CHAR(argv_types[i]),
268                        SILC_STR_UI_XNSTRING(argv[i], argv_lens[i]),
269                        SILC_STR_END);
270     silc_buffer_pull(buffer, 3 + argv_lens[i]);
271   }
272
273   silc_buffer_push(buffer, len);
274
275   return buffer;
276 }
277
278 #if 0
279 /* Encodes Argument payload with variable argument list. The arguments
280    must be: unsigned int, unsigned char *, unsigned int, ... One 
281    {unsigned int, unsigned char * and unsigned int} forms one argument, 
282    thus `argc' in case when sending one {unsigned int, unsigned char * 
283    and unsigned int} equals one (1) and when sending two of those it
284    equals two (2), and so on. This has to be preserved or bad things
285    will happen. The variable arguments is: {type, data, data_len}. */
286
287 SilcBuffer silc_command_encode_payload_va(unsigned int argc, ...)
288 {
289   va_list ap;
290   unsigned char **argv;
291   unsigned int *argv_lens = NULL, *argv_types = NULL;
292   unsigned char *x;
293   unsigned int x_len;
294   unsigned int x_type;
295   SilcBuffer buffer;
296   int i;
297
298   va_start(ap, argc);
299
300   argv = silc_calloc(argc, sizeof(unsigned char *));
301   argv_lens = silc_calloc(argc, sizeof(unsigned int));
302   argv_types = silc_calloc(argc, sizeof(unsigned int));
303
304   for (i = 0; i < argc; i++) {
305     x_type = va_arg(ap, unsigned int);
306     x = va_arg(ap, unsigned char *);
307     x_len = va_arg(ap, unsigned int);
308
309     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
310     memcpy(argv[i], x, x_len);
311     argv_lens[i] = x_len;
312     argv_types[i] = x_type;
313   }
314
315   buffer = silc_argument_payload_encode(argc, argv, 
316                                         argv_lens, argv_types);
317
318   for (i = 0; i < argc; i++)
319     silc_free(argv[i]);
320   silc_free(argv);
321   silc_free(argv_lens);
322   silc_free(argv_types);
323
324   return buffer;
325 }
326 #endif
327
328 /* Free's Command Payload */
329
330 void silc_argument_payload_free(SilcArgumentPayload payload)
331 {
332   int i;
333
334   if (payload) {
335     for (i = 0; i < payload->argc; i++)
336       silc_free(payload->argv[i]);
337
338     silc_free(payload->argv);
339     silc_free(payload);
340   }
341 }
342
343 /* Returns number of arguments in payload */
344
345 unsigned int silc_argument_get_arg_num(SilcArgumentPayload payload)
346 {
347   return payload->argc;
348 }
349
350 /* Returns first argument from payload. */
351
352 unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload,
353                                            unsigned int *ret_len)
354 {
355   payload->pos = 0;
356
357   if (ret_len)
358     *ret_len = payload->argv_lens[payload->pos];
359
360   return payload->argv[payload->pos++];
361 }
362
363 /* Returns next argument from payload or NULL if no more arguments. */
364
365 unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload,
366                                           unsigned int *ret_len)
367 {
368   if (payload->pos >= payload->argc)
369     return NULL;
370
371   if (ret_len)
372     *ret_len = payload->argv_lens[payload->pos];
373
374   return payload->argv[payload->pos++];
375 }
376
377 /* Returns argument which type is `type'. */
378
379 unsigned char *silc_argument_get_arg_type(SilcArgumentPayload payload,
380                                           unsigned int type,
381                                           unsigned int *ret_len)
382 {
383   int i;
384
385   for (i = 0; i < payload->argc; i++)
386     if (payload->argv_types[i] == type)
387       break;
388
389   if (i >= payload->argc)
390     return NULL;
391
392   if (ret_len)
393     *ret_len = payload->argv_lens[i];
394
395   return payload->argv[i];
396 }