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