*** empty log message ***
[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 /* $Id$ */
21
22 #include "silcincludes.h"
23 #include "silccommand.h"
24
25 /******************************************************************************
26
27                               Command Payload
28
29 ******************************************************************************/
30
31 /* Command Payload structure. Contents of this structure is parsed
32    from SILC packets. */
33 struct SilcCommandPayloadStruct {
34   SilcCommand cmd;
35   unsigned short ident;
36   SilcArgumentPayload args;
37 };
38
39 /* Length of the command payload */
40 #define SILC_COMMAND_PAYLOAD_LEN 6
41
42 /* Parses command payload returning new command payload structure */
43
44 SilcCommandPayload silc_command_payload_parse(SilcBuffer buffer)
45 {
46   SilcCommandPayload new;
47   unsigned char args_num;
48   unsigned short payload_len;
49
50   SILC_LOG_DEBUG(("Parsing command payload"));
51
52   new = silc_calloc(1, sizeof(*new));
53
54   /* Parse the Command Payload */
55   silc_buffer_unformat(buffer, 
56                        SILC_STR_UI_SHORT(&payload_len),
57                        SILC_STR_UI_CHAR(&new->cmd),
58                        SILC_STR_UI_CHAR(&args_num),
59                        SILC_STR_UI_SHORT(&new->ident),
60                        SILC_STR_END);
61
62   if (payload_len != buffer->len) {
63     SILC_LOG_ERROR(("Incorrect command payload in packet, packet dropped"));
64     silc_free(new);
65     return NULL;
66   }
67
68   if (new->cmd == 0) {
69     silc_free(new);
70     return NULL;
71   }
72
73   silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
74   new->args = silc_argument_payload_parse(buffer, args_num);
75   if (!new->args) {
76     silc_free(new);
77     return NULL;
78   }
79   silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
80
81   return new;
82 }
83
84 /* Encodes Command Payload returning it to SilcBuffer. */
85
86 SilcBuffer silc_command_payload_encode(SilcCommand cmd,
87                                        unsigned int argc,
88                                        unsigned char **argv,
89                                        unsigned int *argv_lens,
90                                        unsigned int *argv_types,
91                                        unsigned short ident)
92 {
93   SilcBuffer buffer;
94   SilcBuffer args = NULL;
95   unsigned int len = 0;
96
97   SILC_LOG_DEBUG(("Encoding command payload"));
98
99   if (argc) {
100     args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types);
101     len = args->len;
102   }
103
104   len += SILC_COMMAND_PAYLOAD_LEN;
105   buffer = silc_buffer_alloc(len);
106   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
107
108   /* Create Command payload */
109   silc_buffer_format(buffer,
110                      SILC_STR_UI_SHORT(len),
111                      SILC_STR_UI_CHAR(cmd),
112                      SILC_STR_UI_CHAR(argc),
113                      SILC_STR_UI_SHORT(ident),
114                      SILC_STR_END);
115
116   /* Add arguments */
117   if (argc) {
118     silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
119     silc_buffer_format(buffer,
120                        SILC_STR_UI_XNSTRING(args->data, args->len),
121                        SILC_STR_END);
122     silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
123     silc_free(args);
124   }
125
126   return buffer;
127 }
128
129 /* Same as above but encode the buffer from SilcCommandPayload structure
130    instead of raw data. */
131
132 SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload)
133 {
134   SilcBuffer buffer;
135   SilcBuffer args = NULL;
136   unsigned int len = 0;
137   unsigned int argc = 0;
138
139   SILC_LOG_DEBUG(("Encoding command payload"));
140
141   if (payload->args) {
142     args = silc_argument_payload_encode_payload(payload->args);
143     len = args->len;
144     argc = silc_argument_get_arg_num(payload->args);
145   }
146
147   len += SILC_COMMAND_PAYLOAD_LEN;
148   buffer = silc_buffer_alloc(len);
149   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
150
151   /* Create Command payload */
152   silc_buffer_format(buffer,
153                      SILC_STR_UI_SHORT(len),
154                      SILC_STR_UI_CHAR(payload->cmd),
155                      SILC_STR_UI_CHAR(argc),
156                      SILC_STR_UI_SHORT(payload->ident),
157                      SILC_STR_END);
158
159   /* Add arguments */
160   if (args) {
161     silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
162     silc_buffer_format(buffer,
163                        SILC_STR_UI_XNSTRING(args->data, args->len),
164                        SILC_STR_END);
165     silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
166     silc_free(args);
167   }
168
169   return buffer;
170 }
171
172 /* Encodes Command payload with variable argument list. The arguments
173    must be: unsigned int, unsigned char *, unsigned int, ... One 
174    {unsigned int, unsigned char * and unsigned int} forms one argument, 
175    thus `argc' in case when sending one {unsigned int, unsigned char * 
176    and unsigned int} equals one (1) and when sending two of those it
177    equals two (2), and so on. This has to be preserved or bad things
178    will happen. The variable arguments is: {type, data, data_len}. */
179
180 SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, 
181                                           unsigned short ident, 
182                                           unsigned int argc, ...)
183 {
184   va_list ap;
185   unsigned char **argv;
186   unsigned int *argv_lens = NULL, *argv_types = NULL;
187   unsigned char *x;
188   unsigned int x_len;
189   unsigned int x_type;
190   SilcBuffer buffer;
191   int i;
192
193   va_start(ap, argc);
194
195   argv = silc_calloc(argc, sizeof(unsigned char *));
196   argv_lens = silc_calloc(argc, sizeof(unsigned int));
197   argv_types = silc_calloc(argc, sizeof(unsigned int));
198
199   for (i = 0; i < argc; i++) {
200     x_type = va_arg(ap, unsigned int);
201     x = va_arg(ap, unsigned char *);
202     x_len = va_arg(ap, unsigned int);
203
204     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
205     memcpy(argv[i], x, x_len);
206     argv_lens[i] = x_len;
207     argv_types[i] = x_type;
208   }
209
210   buffer = silc_command_payload_encode(cmd, argc, argv, 
211                                        argv_lens, argv_types, ident);
212
213   for (i = 0; i < argc; i++)
214     silc_free(argv[i]);
215   silc_free(argv);
216   silc_free(argv_lens);
217   silc_free(argv_types);
218
219   return buffer;
220 }
221
222 /* Same as above but with va_list. */
223
224 SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, 
225                                            unsigned short ident, 
226                                            unsigned int argc, va_list ap)
227 {
228   unsigned char **argv;
229   unsigned int *argv_lens = NULL, *argv_types = NULL;
230   unsigned char *x;
231   unsigned int x_len;
232   unsigned int x_type;
233   SilcBuffer buffer;
234   int i;
235
236   argv = silc_calloc(argc, sizeof(unsigned char *));
237   argv_lens = silc_calloc(argc, sizeof(unsigned int));
238   argv_types = silc_calloc(argc, sizeof(unsigned int));
239
240   for (i = 0; i < argc; i++) {
241     x_type = va_arg(ap, unsigned int);
242     x = va_arg(ap, unsigned char *);
243     x_len = va_arg(ap, unsigned int);
244
245     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
246     memcpy(argv[i], x, x_len);
247     argv_lens[i] = x_len;
248     argv_types[i] = x_type;
249   }
250
251   buffer = silc_command_payload_encode(cmd, argc, argv, 
252                                        argv_lens, argv_types, ident);
253
254   for (i = 0; i < argc; i++)
255     silc_free(argv[i]);
256   silc_free(argv);
257   silc_free(argv_lens);
258   silc_free(argv_types);
259
260   return buffer;
261 }
262
263 /* Same as above except that this is used to encode strictly command
264    reply packets. The command status message to be returned is sent as
265    extra argument to this function. The `argc' must not count `status'
266    as on argument. */
267
268 SilcBuffer 
269 silc_command_reply_payload_encode_va(SilcCommand cmd, 
270                                      SilcCommandStatus status,
271                                      unsigned short ident,
272                                      unsigned int argc, ...)
273 {
274   va_list ap;
275   unsigned char **argv;
276   unsigned int *argv_lens = NULL, *argv_types = NULL;
277   unsigned char status_data[2];
278   unsigned char *x;
279   unsigned int x_len;
280   unsigned int x_type;
281   SilcBuffer buffer;
282   int i;
283
284   va_start(ap, argc);
285
286   argc++;
287   argv = silc_calloc(argc, sizeof(unsigned char *));
288   argv_lens = silc_calloc(argc, sizeof(unsigned int));
289   argv_types = silc_calloc(argc, sizeof(unsigned int));
290
291   SILC_PUT16_MSB(status, status_data);
292   argv[0] = silc_calloc(sizeof(status_data) + 1, sizeof(unsigned char));
293   memcpy(argv[0], status_data, sizeof(status_data));
294   argv_lens[0] = sizeof(status_data);
295   argv_types[0] = 1;
296
297   for (i = 1; i < argc; i++) {
298     x_type = va_arg(ap, unsigned int);
299     x = va_arg(ap, unsigned char *);
300     x_len = va_arg(ap, unsigned int);
301
302     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
303     memcpy(argv[i], x, x_len);
304     argv_lens[i] = x_len;
305     argv_types[i] = x_type;
306   }
307
308   buffer = silc_command_payload_encode(cmd, argc, argv, 
309                                        argv_lens, argv_types, ident);
310
311   for (i = 0; i < argc; i++)
312     silc_free(argv[i]);
313   silc_free(argv);
314   silc_free(argv_lens);
315   silc_free(argv_types);
316
317   return buffer;
318 }
319
320 /* Free's Command Payload */
321
322 void silc_command_free_payload(SilcCommandPayload payload)
323 {
324   if (payload) {
325     silc_argument_payload_free(payload->args);
326     silc_free(payload);
327   }
328 }
329
330 /* Returns command */
331
332 SilcCommand silc_command_get(SilcCommandPayload payload)
333 {
334   return payload->cmd;
335 }
336
337 /* Retuns arguments payload */
338
339 SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload)
340 {
341   return payload->args;
342 }
343
344 /* Returns identifier */
345
346 unsigned short silc_command_get_ident(SilcCommandPayload payload)
347 {
348   return payload->ident;
349 }
350
351 /* Function to set identifier to already allocated Command Payload. Command
352    payloads are frequentlly resent in SILC and thusly this makes it easy
353    to set the identifier. */
354
355 void silc_command_set_ident(SilcCommandPayload payload, unsigned short ident)
356 {
357   payload->ident = ident;
358 }