Removed status paylaod encoding functions -> not needed anymore.
[silc.git] / lib / silccore / silccommand.c
1 /*
2
3   silccommand.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 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 /*
21  * $Id$
22  * $Log$
23  * Revision 1.3  2000/07/06 07:11:06  priikone
24  *      Removed status paylaod encoding functions -> not needed anymore.
25  *      Added encode_reply_payload_va to encode reply packets only.
26  *      Normal encode_payload_va accepts now argument type as variable
27  *      argument as well.
28  *
29  * Revision 1.2  2000/07/05 06:06:35  priikone
30  *      Global cosmetic change.
31  *
32  * Revision 1.1.1.1  2000/06/27 11:36:55  priikone
33  *      Imported from internal CVS/Added Log headers.
34  *
35  *
36  */
37
38 #include "silcincludes.h"
39 #include "silccommand.h"
40
41 /* Command Payload structure. Contents of this structure is parsed
42    from SILC packets. */
43 struct SilcCommandPayloadStruct {
44   SilcCommand cmd;
45   unsigned int argc;
46   unsigned char **argv;
47   unsigned int *argv_lens;
48   unsigned int *argv_types;
49   unsigned int pos;
50 };
51
52 /* Length of the command payload */
53 #define SILC_COMMAND_PAYLOAD_LEN 4
54
55 /* Parses command payload returning new command payload structure */
56
57 SilcCommandPayload silc_command_parse_payload(SilcBuffer buffer)
58 {
59   SilcCommandPayload new;
60   unsigned short payload_len = 0;
61   unsigned char args_num = 0;
62   unsigned char arg_num = 0;
63   unsigned int arg_type = 0;
64   unsigned int pull_len = 0;
65   int i = 0;
66
67   SILC_LOG_DEBUG(("Parsing command payload"));
68
69   new = silc_calloc(1, sizeof(*new));
70
71   /* Parse the Command Payload */
72   silc_buffer_unformat(buffer, 
73                        SILC_STR_UI_CHAR(&new->cmd),
74                        SILC_STR_UI_CHAR(&args_num),
75                        SILC_STR_UI_SHORT(&payload_len),
76                        SILC_STR_END);
77
78   if (payload_len != buffer->len) {
79     SILC_LOG_ERROR(("Incorrect command payload in packet, packet dropped"));
80     return NULL;
81   }
82
83   if (new->cmd == 0)
84     return NULL;
85
86   if (args_num && payload_len) {
87
88     new->argv = silc_calloc(args_num, sizeof(unsigned char *));
89     new->argv_lens = silc_calloc(args_num, sizeof(unsigned int));
90     new->argv_types = silc_calloc(args_num, sizeof(unsigned int));
91
92     silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
93     pull_len += SILC_COMMAND_PAYLOAD_LEN;
94
95     /* Parse Command Argument Payloads */
96     arg_num = 1;
97     while(arg_num) {
98       silc_buffer_unformat(buffer,
99                            SILC_STR_UI_CHAR(&arg_num),
100                            SILC_STR_UI_CHAR(&arg_type),
101                            SILC_STR_UI_SHORT(&payload_len),
102                            SILC_STR_END);
103
104       /* Check that argument number is correct */
105       if (arg_num != i + 1)
106         goto err;
107
108       new->argv_lens[i] = payload_len;
109       new->argv_types[i] = arg_type;
110
111       /* Get argument data */
112       silc_buffer_pull(buffer, 4);
113       silc_buffer_unformat(buffer,
114                            SILC_STR_UI_XNSTRING_ALLOC(&new->argv[i], 
115                                                       payload_len),
116                            SILC_STR_END);
117       silc_buffer_pull(buffer, payload_len);
118       pull_len += 4 + payload_len;
119
120       i++;
121
122       if (i == args_num)
123         break;
124     }
125
126     /* Check the number of arguments */
127     if (arg_num != args_num)
128       goto err;
129   }
130
131   new->argc = i;
132   new->pos = 0;
133
134   silc_buffer_push(buffer, pull_len);
135
136   return new;
137
138  err:
139   if (i) {
140     int k;
141
142     for (k = 0; k < i; k++)
143       silc_free(new->argv[k]);
144   }
145
146   silc_free(new->argv);
147   silc_free(new->argv_lens);
148   silc_free(new->argv_types);
149
150   if (new)
151     silc_free(new);
152
153   return NULL;
154 }
155
156 /* Encodes Command Payload returning it to SilcBuffer. */
157
158 SilcBuffer silc_command_encode_payload(SilcCommand cmd,
159                                        unsigned int argc,
160                                        unsigned char **argv,
161                                        unsigned int *argv_lens,
162                                        unsigned int *argv_types)
163 {
164   SilcBuffer buffer;
165   unsigned int len;
166   int i;
167
168   SILC_LOG_DEBUG(("Encoding command payload"));
169
170   len = 1 + 1 + 2;
171   for (i = 0; i < argc; i++)
172     len += 1 + 1 + 2 + argv_lens[i];
173
174   buffer = silc_buffer_alloc(len);
175   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
176
177   /* Create Command payload */
178   silc_buffer_format(buffer,
179                      SILC_STR_UI_CHAR(cmd),
180                      SILC_STR_UI_CHAR(argc),
181                      SILC_STR_UI_SHORT(len),
182                      SILC_STR_END);
183
184   /* Put arguments */
185   if (argc) {
186     silc_buffer_pull(buffer, 4);
187    
188     for (i = 0; i < argc; i++) {
189       silc_buffer_format(buffer,
190                          SILC_STR_UI_CHAR(i + 1),
191                          SILC_STR_UI_CHAR(argv_types[i]),
192                          SILC_STR_UI_SHORT(argv_lens[i]),
193                          SILC_STR_UI_XNSTRING(argv[i], argv_lens[i]),
194                          SILC_STR_END);
195       silc_buffer_pull(buffer, 4 + argv_lens[i]);
196     }
197
198     silc_buffer_push(buffer, len);
199   }
200
201   return buffer;
202 }
203
204 /* Encodes Command payload with variable argument list. The arguments
205    must be: unsigned int, unsigned char *, unsigned int, ... One 
206    {unsigned int, unsigned char * and unsigned int} forms one argument, 
207    thus `argc' in case when sending one {unsigned int, unsigned char * 
208    and unsigned int} equals one (1) and when sending two of those it
209    equals two (2), and so on. This has to be preserved or bad things
210    will happen. The variable arguments is: {type, data, data_len}. */
211
212 SilcBuffer silc_command_encode_payload_va(SilcCommand cmd, 
213                                           unsigned int argc, ...)
214 {
215   va_list ap;
216   unsigned char **argv;
217   unsigned int *argv_lens = NULL, *argv_types = NULL;
218   unsigned char *x;
219   unsigned int x_len;
220   unsigned int x_type;
221   SilcBuffer buffer;
222   int i;
223
224   va_start(ap, argc);
225
226   argv = silc_calloc(argc, sizeof(unsigned char *));
227   argv_lens = silc_calloc(argc, sizeof(unsigned int));
228   argv_types = silc_calloc(argc, sizeof(unsigned int));
229
230   for (i = 0; i < argc; i++) {
231     x_type = va_arg(ap, unsigned int);
232     x = va_arg(ap, unsigned char *);
233     x_len = va_arg(ap, unsigned int);
234
235     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
236     memcpy(argv[i], x, x_len);
237     argv_lens[i] = x_len;
238     argv_types[i] = x_type;
239   }
240
241   buffer = silc_command_encode_payload(cmd, argc, argv, 
242                                        argv_lens, argv_types);
243
244   for (i = 0; i < argc; i++)
245     silc_free(argv[i]);
246   silc_free(argv);
247   silc_free(argv_lens);
248   silc_free(argv_types);
249
250   return buffer;
251 }
252
253 /* Same as above except that this is used to encode strictly command
254    reply packets. The command status message to be returned is sent as
255    extra argument to this function. The `argc' must not count `status'
256    as on argument. */
257
258 SilcBuffer 
259 silc_command_encode_reply_payload_va(SilcCommand cmd, 
260                                      SilcCommandStatus status,
261                                      unsigned int argc, ...)
262 {
263   va_list ap;
264   unsigned char **argv;
265   unsigned int *argv_lens = NULL, *argv_types = NULL;
266   unsigned char status_data[2];
267   unsigned char *x;
268   unsigned int x_len;
269   unsigned int x_type;
270   SilcBuffer buffer;
271   int i;
272
273   va_start(ap, argc);
274
275   argc++;
276   argv = silc_calloc(argc, sizeof(unsigned char *));
277   argv_lens = silc_calloc(argc, sizeof(unsigned int));
278   argv_types = silc_calloc(argc, sizeof(unsigned int));
279
280   SILC_PUT16_MSB(status, status_data);
281   argv[0] = silc_calloc(sizeof(status_data) + 1, sizeof(unsigned char));
282   memcpy(argv[0], status_data, sizeof(status_data));
283   argv_lens[0] = sizeof(status_data);
284   argv_types[0] = 1;
285
286   for (i = 1; i < argc; i++) {
287     x_type = va_arg(ap, unsigned int);
288     x = va_arg(ap, unsigned char *);
289     x_len = va_arg(ap, unsigned int);
290
291     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
292     memcpy(argv[i], x, x_len);
293     argv_lens[i] = x_len;
294     argv_types[i] = x_type;
295   }
296
297   buffer = silc_command_encode_payload(cmd, argc, argv, 
298                                        argv_lens, argv_types);
299
300   for (i = 0; i < argc; i++)
301     silc_free(argv[i]);
302   silc_free(argv);
303   silc_free(argv_lens);
304   silc_free(argv_types);
305
306   return buffer;
307 }
308
309 /* Free's Command Payload */
310
311 void silc_command_free_payload(SilcCommandPayload payload)
312 {
313   int i;
314
315   if (payload) {
316     for (i = 0; i < payload->argc; i++)
317       silc_free(payload->argv[i]);
318
319     silc_free(payload->argv);
320     silc_free(payload);
321   }
322 }
323
324 /* Returns the command type in payload */
325
326 SilcCommand silc_command_get(SilcCommandPayload payload)
327 {
328   return payload->cmd;
329 }
330
331 /* Returns number of arguments in payload */
332
333 unsigned int silc_command_get_arg_num(SilcCommandPayload payload)
334 {
335   return payload->argc;
336 }
337
338 /* Returns first argument from payload. */
339
340 unsigned char *silc_command_get_first_arg(SilcCommandPayload payload,
341                                           unsigned int *ret_len)
342 {
343   payload->pos = 0;
344
345   if (ret_len)
346     *ret_len = payload->argv_lens[payload->pos];
347
348   return payload->argv[payload->pos++];
349 }
350
351 /* Returns next argument from payload or NULL if no more arguments. */
352
353 unsigned char *silc_command_get_next_arg(SilcCommandPayload payload,
354                                          unsigned int *ret_len)
355 {
356   if (payload->pos >= payload->argc)
357     return NULL;
358
359   if (ret_len)
360     *ret_len = payload->argv_lens[payload->pos];
361
362   return payload->argv[payload->pos++];
363 }
364
365 /* Returns argument which type is `type'. */
366
367 unsigned char *silc_command_get_arg_type(SilcCommandPayload payload,
368                                          unsigned int type,
369                                          unsigned int *ret_len)
370 {
371   int i;
372
373   for (i = 0; i < payload->argc; i++)
374     if (payload->argv_types[i] == type)
375       break;
376
377   if (i >= payload->argc)
378     return NULL;
379
380   if (ret_len)
381     *ret_len = payload->argv_lens[i];
382
383   return payload->argv[i];
384 }