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