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 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,
99 SilcUInt32 *argv_lens,
100 SilcUInt32 *argv_types,
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);
133 silc_buffer_free(args);
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);
176 silc_buffer_free(args);
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}. */
190 SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
192 SilcUInt32 argc, ...)
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 SilcUInt32 argc, va_list ap)
210 unsigned char **argv = NULL;
211 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
219 argv = silc_calloc(argc, sizeof(unsigned char *));
220 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
221 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
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);
228 if (!x_type || !x || !x_len)
231 argv[k] = silc_memdup(x, x_len);
232 argv_lens[k] = x_len;
233 argv_types[k] = x_type;
238 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
241 for (i = 0; i < k; i++)
244 silc_free(argv_lens);
245 silc_free(argv_types);
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'
256 silc_command_reply_payload_encode_va(SilcCommand cmd,
257 SilcCommandStatus status,
259 SilcUInt32 argc, ...)
265 buffer = silc_command_reply_payload_encode_vap(cmd, status, ident, argc, ap);
272 silc_command_reply_payload_encode_vap(SilcCommand cmd,
273 SilcCommandStatus status,
274 SilcUInt16 ident, SilcUInt32 argc,
277 unsigned char **argv;
278 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
279 unsigned char status_data[2];
287 argv = silc_calloc(argc, sizeof(unsigned char *));
288 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
289 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
291 SILC_PUT16_MSB(status, status_data);
292 argv[0] = silc_memdup(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, SilcUInt32);
298 x = va_arg(ap, unsigned char *);
299 x_len = va_arg(ap, SilcUInt32);
301 if (!x_type || !x || !x_len)
304 argv[k] = silc_memdup(x, x_len);
305 argv_lens[k] = x_len;
306 argv_types[k] = x_type;
310 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
313 for (i = 0; i < k; i++)
316 silc_free(argv_lens);
317 silc_free(argv_types);
322 /* Frees Command Payload */
324 void silc_command_payload_free(SilcCommandPayload payload)
327 silc_argument_payload_free(payload->args);
332 /* Returns command */
334 SilcCommand silc_command_get(SilcCommandPayload payload)
339 /* Retuns arguments payload */
341 SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload)
343 return payload->args;
346 /* Returns identifier */
348 SilcUInt16 silc_command_get_ident(SilcCommandPayload payload)
350 return payload->ident;
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. */
357 void silc_command_set_ident(SilcCommandPayload payload, SilcUInt16 ident)
359 payload->ident = ident;
362 /* Function to set the command to already allocated Command Payload. */
364 void silc_command_set_command(SilcCommandPayload payload, SilcCommand command)
366 payload->cmd = command;