5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2001 Pekka Riikonen
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.
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.
22 #include "silcincludes.h"
23 #include "silccommand.h"
25 /******************************************************************************
29 ******************************************************************************/
31 /* Command Payload structure. Contents of this structure is parsed
33 struct SilcCommandPayloadStruct {
36 SilcArgumentPayload args;
39 /* Length of the command payload */
40 #define SILC_COMMAND_PAYLOAD_LEN 6
42 /* Parses command payload returning new command payload structure */
44 SilcCommandPayload silc_command_payload_parse(const unsigned char *payload,
45 SilcUInt32 payload_len)
47 SilcBufferStruct buffer;
48 SilcCommandPayload newp;
49 unsigned char args_num;
53 SILC_LOG_DEBUG(("Parsing command payload"));
55 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
56 newp = silc_calloc(1, sizeof(*newp));
60 /* Parse the Command Payload */
61 ret = silc_buffer_unformat(&buffer,
62 SILC_STR_UI_SHORT(&p_len),
63 SILC_STR_UI_CHAR(&newp->cmd),
64 SILC_STR_UI_CHAR(&args_num),
65 SILC_STR_UI_SHORT(&newp->ident),
72 if (p_len != buffer.len) {
73 SILC_LOG_ERROR(("Incorrect command payload in packet, packet dropped"));
83 silc_buffer_pull(&buffer, SILC_COMMAND_PAYLOAD_LEN);
85 newp->args = silc_argument_payload_parse(buffer.data, buffer.len, args_num);
91 silc_buffer_push(&buffer, SILC_COMMAND_PAYLOAD_LEN);
96 /* Encodes Command Payload returning it to SilcBuffer. */
98 SilcBuffer silc_command_payload_encode(SilcCommand cmd,
100 unsigned char **argv,
101 SilcUInt32 *argv_lens,
102 SilcUInt32 *argv_types,
106 SilcBuffer args = NULL;
109 SILC_LOG_DEBUG(("Encoding command payload"));
112 args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types);
116 len += SILC_COMMAND_PAYLOAD_LEN;
117 buffer = silc_buffer_alloc_size(len);
121 /* Create Command payload */
122 silc_buffer_format(buffer,
123 SILC_STR_UI_SHORT(len),
124 SILC_STR_UI_CHAR(cmd),
125 SILC_STR_UI_CHAR(argc),
126 SILC_STR_UI_SHORT(ident),
131 silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
132 silc_buffer_format(buffer,
133 SILC_STR_UI_XNSTRING(args->data, args->len),
135 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
136 silc_buffer_free(args);
142 /* Same as above but encode the buffer from SilcCommandPayload structure
143 instead of raw data. */
145 SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload)
148 SilcBuffer args = NULL;
152 SILC_LOG_DEBUG(("Encoding command payload"));
155 args = silc_argument_payload_encode_payload(payload->args);
157 argc = silc_argument_get_arg_num(payload->args);
160 len += SILC_COMMAND_PAYLOAD_LEN;
161 buffer = silc_buffer_alloc_size(len);
164 silc_buffer_free(args);
168 /* Create Command payload */
169 silc_buffer_format(buffer,
170 SILC_STR_UI_SHORT(len),
171 SILC_STR_UI_CHAR(payload->cmd),
172 SILC_STR_UI_CHAR(argc),
173 SILC_STR_UI_SHORT(payload->ident),
178 silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
179 silc_buffer_format(buffer,
180 SILC_STR_UI_XNSTRING(args->data, args->len),
182 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
183 silc_buffer_free(args);
189 /* Encodes Command payload with variable argument list. The arguments
190 must be: SilcUInt32, unsigned char *, unsigned int, ... One
191 {SilcUInt32, unsigned char * and unsigned int} forms one argument,
192 thus `argc' in case when sending one {SilcUInt32, unsigned char *
193 and SilcUInt32} equals one (1) and when sending two of those it
194 equals two (2), and so on. This has to be preserved or bad things
195 will happen. The variable arguments is: {type, data, data_len}. */
197 SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
199 SilcUInt32 argc, ...)
205 buffer = silc_command_payload_encode_vap(cmd, ident, argc, ap);
211 /* Same as above but with va_list. */
213 SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
215 SilcUInt32 argc, va_list ap)
217 unsigned char **argv = NULL;
218 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
222 SilcBuffer buffer = NULL;
226 argv = silc_calloc(argc, sizeof(unsigned char *));
229 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
232 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
236 for (i = 0, k = 0; i < argc; i++) {
237 x_type = va_arg(ap, SilcUInt32);
238 x = va_arg(ap, unsigned char *);
239 x_len = va_arg(ap, SilcUInt32);
241 if (!x_type || !x || !x_len)
244 argv[k] = silc_memdup(x, x_len);
247 argv_lens[k] = x_len;
248 argv_types[k] = x_type;
253 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
257 for (i = 0; i < k; i++)
260 silc_free(argv_lens);
261 silc_free(argv_types);
266 /* Same as above except that this is used to encode strictly command
267 reply packets. The command status message to be returned is sent as
268 extra argument to this function. The `argc' must not count `status'
272 silc_command_reply_payload_encode_va(SilcCommand cmd,
273 SilcCommandStatus status,
275 SilcUInt32 argc, ...)
281 buffer = silc_command_reply_payload_encode_vap(cmd, status, ident, argc, ap);
288 silc_command_reply_payload_encode_vap(SilcCommand cmd,
289 SilcCommandStatus status,
290 SilcUInt16 ident, SilcUInt32 argc,
293 unsigned char **argv;
294 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
295 unsigned char status_data[2];
299 SilcBuffer buffer = NULL;
303 argv = silc_calloc(argc, sizeof(unsigned char *));
306 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
311 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
313 silc_free(argv_lens);
318 SILC_PUT16_MSB(status, status_data);
319 argv[0] = silc_memdup(status_data, sizeof(status_data));
321 silc_free(argv_types);
322 silc_free(argv_lens);
326 argv_lens[0] = sizeof(status_data);
329 for (i = 1, k = 1; i < argc; i++) {
330 x_type = va_arg(ap, SilcUInt32);
331 x = va_arg(ap, unsigned char *);
332 x_len = va_arg(ap, SilcUInt32);
334 if (!x_type || !x || !x_len)
337 argv[k] = silc_memdup(x, x_len);
340 argv_lens[k] = x_len;
341 argv_types[k] = x_type;
345 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
349 for (i = 0; i < k; i++)
352 silc_free(argv_lens);
353 silc_free(argv_types);
358 /* Frees Command Payload */
360 void silc_command_payload_free(SilcCommandPayload payload)
363 silc_argument_payload_free(payload->args);
368 /* Returns command */
370 SilcCommand silc_command_get(SilcCommandPayload payload)
375 /* Retuns arguments payload */
377 SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload)
379 return payload->args;
382 /* Returns identifier */
384 SilcUInt16 silc_command_get_ident(SilcCommandPayload payload)
386 return payload->ident;
389 /* Function to set identifier to already allocated Command Payload. Command
390 payloads are frequentlly resent in SILC and thusly this makes it easy
391 to set the identifier. */
393 void silc_command_set_ident(SilcCommandPayload payload, SilcUInt16 ident)
395 payload->ident = ident;
398 /* Function to set the command to already allocated Command Payload. */
400 void silc_command_set_command(SilcCommandPayload payload, SilcCommand command)
402 payload->cmd = command;