A LOT updates. Cannot separate. :)
[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 /* Encodes Command payload with variable argument list. The arguments
130    must be: unsigned int, unsigned char *, unsigned int, ... One 
131    {unsigned int, unsigned char * and unsigned int} forms one argument, 
132    thus `argc' in case when sending one {unsigned int, unsigned char * 
133    and unsigned int} equals one (1) and when sending two of those it
134    equals two (2), and so on. This has to be preserved or bad things
135    will happen. The variable arguments is: {type, data, data_len}. */
136
137 SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, 
138                                           unsigned short ident, 
139                                           unsigned int argc, ...)
140 {
141   va_list ap;
142   unsigned char **argv;
143   unsigned int *argv_lens = NULL, *argv_types = NULL;
144   unsigned char *x;
145   unsigned int x_len;
146   unsigned int x_type;
147   SilcBuffer buffer;
148   int i;
149
150   va_start(ap, argc);
151
152   argv = silc_calloc(argc, sizeof(unsigned char *));
153   argv_lens = silc_calloc(argc, sizeof(unsigned int));
154   argv_types = silc_calloc(argc, sizeof(unsigned int));
155
156   for (i = 0; i < argc; i++) {
157     x_type = va_arg(ap, unsigned int);
158     x = va_arg(ap, unsigned char *);
159     x_len = va_arg(ap, unsigned int);
160
161     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
162     memcpy(argv[i], x, x_len);
163     argv_lens[i] = x_len;
164     argv_types[i] = x_type;
165   }
166
167   buffer = silc_command_payload_encode(cmd, argc, argv, 
168                                        argv_lens, argv_types, ident);
169
170   for (i = 0; i < argc; i++)
171     silc_free(argv[i]);
172   silc_free(argv);
173   silc_free(argv_lens);
174   silc_free(argv_types);
175
176   return buffer;
177 }
178
179 /* Same as above but with va_list. */
180
181 SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd, 
182                                            unsigned short ident, 
183                                            unsigned int argc, va_list ap)
184 {
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   argv = silc_calloc(argc, sizeof(unsigned char *));
194   argv_lens = silc_calloc(argc, sizeof(unsigned int));
195   argv_types = silc_calloc(argc, sizeof(unsigned int));
196
197   for (i = 0; i < argc; i++) {
198     x_type = va_arg(ap, unsigned int);
199     x = va_arg(ap, unsigned char *);
200     x_len = va_arg(ap, unsigned int);
201
202     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
203     memcpy(argv[i], x, x_len);
204     argv_lens[i] = x_len;
205     argv_types[i] = x_type;
206   }
207
208   buffer = silc_command_payload_encode(cmd, argc, argv, 
209                                        argv_lens, argv_types, ident);
210
211   for (i = 0; i < argc; i++)
212     silc_free(argv[i]);
213   silc_free(argv);
214   silc_free(argv_lens);
215   silc_free(argv_types);
216
217   return buffer;
218 }
219
220 /* Same as above except that this is used to encode strictly command
221    reply packets. The command status message to be returned is sent as
222    extra argument to this function. The `argc' must not count `status'
223    as on argument. */
224
225 SilcBuffer 
226 silc_command_reply_payload_encode_va(SilcCommand cmd, 
227                                      SilcCommandStatus status,
228                                      unsigned short ident,
229                                      unsigned int argc, ...)
230 {
231   va_list ap;
232   unsigned char **argv;
233   unsigned int *argv_lens = NULL, *argv_types = NULL;
234   unsigned char status_data[2];
235   unsigned char *x;
236   unsigned int x_len;
237   unsigned int x_type;
238   SilcBuffer buffer;
239   int i;
240
241   va_start(ap, argc);
242
243   argc++;
244   argv = silc_calloc(argc, sizeof(unsigned char *));
245   argv_lens = silc_calloc(argc, sizeof(unsigned int));
246   argv_types = silc_calloc(argc, sizeof(unsigned int));
247
248   SILC_PUT16_MSB(status, status_data);
249   argv[0] = silc_calloc(sizeof(status_data) + 1, sizeof(unsigned char));
250   memcpy(argv[0], status_data, sizeof(status_data));
251   argv_lens[0] = sizeof(status_data);
252   argv_types[0] = 1;
253
254   for (i = 1; i < argc; i++) {
255     x_type = va_arg(ap, unsigned int);
256     x = va_arg(ap, unsigned char *);
257     x_len = va_arg(ap, unsigned int);
258
259     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
260     memcpy(argv[i], x, x_len);
261     argv_lens[i] = x_len;
262     argv_types[i] = x_type;
263   }
264
265   buffer = silc_command_payload_encode(cmd, argc, argv, 
266                                        argv_lens, argv_types, ident);
267
268   for (i = 0; i < argc; i++)
269     silc_free(argv[i]);
270   silc_free(argv);
271   silc_free(argv_lens);
272   silc_free(argv_types);
273
274   return buffer;
275 }
276
277 /* Free's Command Payload */
278
279 void silc_command_free_payload(SilcCommandPayload payload)
280 {
281   if (payload) {
282     silc_argument_payload_free(payload->args);
283     silc_free(payload);
284   }
285 }
286
287 /* Returns command */
288
289 SilcCommand silc_command_get(SilcCommandPayload payload)
290 {
291   return payload->cmd;
292 }
293
294 /* Retuns arguments payload */
295
296 SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload)
297 {
298   return payload->args;
299 }
300
301 /* Returns identifier */
302
303 unsigned short silc_command_get_ident(SilcCommandPayload payload)
304 {
305   return payload->ident;
306 }