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