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,
47 SilcBufferStruct buffer;
48 SilcCommandPayload new;
49 unsigned char args_num;
53 SILC_LOG_DEBUG(("Parsing command payload"));
55 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
56 new = silc_calloc(1, sizeof(*new));
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),
70 if (p_len != buffer.len) {
71 SILC_LOG_ERROR(("Incorrect command payload in packet, packet dropped"));
81 silc_buffer_pull(&buffer, SILC_COMMAND_PAYLOAD_LEN);
83 new->args = silc_argument_payload_parse(buffer.data, buffer.len, args_num);
89 silc_buffer_push(&buffer, SILC_COMMAND_PAYLOAD_LEN);
94 /* Encodes Command Payload returning it to SilcBuffer. */
96 SilcBuffer silc_command_payload_encode(SilcCommand cmd,
104 SilcBuffer args = NULL;
107 SILC_LOG_DEBUG(("Encoding command payload"));
110 args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types);
114 len += SILC_COMMAND_PAYLOAD_LEN;
115 buffer = silc_buffer_alloc(len);
116 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
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),
128 silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
129 silc_buffer_format(buffer,
130 SILC_STR_UI_XNSTRING(args->data, args->len),
132 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
139 /* Same as above but encode the buffer from SilcCommandPayload structure
140 instead of raw data. */
142 SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload)
145 SilcBuffer args = NULL;
149 SILC_LOG_DEBUG(("Encoding command payload"));
152 args = silc_argument_payload_encode_payload(payload->args);
154 argc = silc_argument_get_arg_num(payload->args);
157 len += SILC_COMMAND_PAYLOAD_LEN;
158 buffer = silc_buffer_alloc(len);
159 silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
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),
171 silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
172 silc_buffer_format(buffer,
173 SILC_STR_UI_XNSTRING(args->data, args->len),
175 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
182 /* Encodes Command payload with variable argument list. The arguments
183 must be: uint32, unsigned char *, unsigned int, ... One
184 {uint32, unsigned char * and unsigned int} forms one argument,
185 thus `argc' in case when sending one {uint32, unsigned char *
186 and uint32} 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}. */
190 SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
198 buffer = silc_command_payload_encode_vap(cmd, ident, argc, ap);
204 /* Same as above but with va_list. */
206 SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
208 uint32 argc, va_list ap)
210 unsigned char **argv;
211 uint32 *argv_lens = NULL, *argv_types = NULL;
218 argv = silc_calloc(argc, sizeof(unsigned char *));
219 argv_lens = silc_calloc(argc, sizeof(uint32));
220 argv_types = silc_calloc(argc, sizeof(uint32));
222 for (i = 0, k = 0; i < argc; i++) {
223 x_type = va_arg(ap, uint32);
224 x = va_arg(ap, unsigned char *);
225 x_len = va_arg(ap, uint32);
227 if (!x_type || !x || !x_len)
230 argv[k] = silc_calloc(x_len + 1, sizeof(unsigned char));
231 memcpy(argv[k], x, x_len);
232 argv_lens[k] = x_len;
233 argv_types[k] = x_type;
237 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
240 for (i = 0; i < k; i++)
243 silc_free(argv_lens);
244 silc_free(argv_types);
249 /* Same as above except that this is used to encode strictly command
250 reply packets. The command status message to be returned is sent as
251 extra argument to this function. The `argc' must not count `status'
255 silc_command_reply_payload_encode_va(SilcCommand cmd,
256 SilcCommandStatus status,
264 buffer = silc_command_reply_payload_encode_vap(cmd, status, ident, argc, ap);
271 silc_command_reply_payload_encode_vap(SilcCommand cmd,
272 SilcCommandStatus status,
273 uint16 ident, uint32 argc,
276 unsigned char **argv;
277 uint32 *argv_lens = NULL, *argv_types = NULL;
278 unsigned char status_data[2];
286 argv = silc_calloc(argc, sizeof(unsigned char *));
287 argv_lens = silc_calloc(argc, sizeof(uint32));
288 argv_types = silc_calloc(argc, sizeof(uint32));
290 SILC_PUT16_MSB(status, status_data);
291 argv[0] = silc_calloc(sizeof(status_data) + 1, sizeof(unsigned char));
292 memcpy(argv[0], status_data, sizeof(status_data));
293 argv_lens[0] = sizeof(status_data);
296 for (i = 1, k = 1; i < argc; i++) {
297 x_type = va_arg(ap, uint32);
298 x = va_arg(ap, unsigned char *);
299 x_len = va_arg(ap, uint32);
301 if (!x_type || !x || !x_len)
304 argv[k] = silc_calloc(x_len + 1, sizeof(unsigned char));
305 memcpy(argv[k], x, x_len);
306 argv_lens[k] = x_len;
307 argv_types[k] = x_type;
311 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
314 for (i = 0; i < k; i++)
317 silc_free(argv_lens);
318 silc_free(argv_types);
323 /* Frees Command Payload */
325 void silc_command_payload_free(SilcCommandPayload payload)
328 silc_argument_payload_free(payload->args);
333 /* Returns command */
335 SilcCommand silc_command_get(SilcCommandPayload payload)
340 /* Retuns arguments payload */
342 SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload)
344 return payload->args;
347 /* Returns identifier */
349 uint16 silc_command_get_ident(SilcCommandPayload payload)
351 return payload->ident;
354 /* Function to set identifier to already allocated Command Payload. Command
355 payloads are frequentlly resent in SILC and thusly this makes it easy
356 to set the identifier. */
358 void silc_command_set_ident(SilcCommandPayload payload, uint16 ident)
360 payload->ident = ident;
363 /* Function to set the command to already allocated Command Payload. */
365 void silc_command_set_command(SilcCommandPayload payload, SilcCommand command)
367 payload->cmd = command;