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,
92 silc_buffer_push(&buffer, SILC_COMMAND_PAYLOAD_LEN);
97 /* Encodes Command Payload returning it to SilcBuffer. */
99 SilcBuffer silc_command_payload_encode(SilcCommand cmd,
101 unsigned char **argv,
102 SilcUInt32 *argv_lens,
103 SilcUInt32 *argv_types,
107 SilcBuffer args = NULL;
110 SILC_LOG_DEBUG(("Encoding command payload"));
113 args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types);
117 len += SILC_COMMAND_PAYLOAD_LEN;
118 buffer = silc_buffer_alloc_size(len);
122 /* Create Command payload */
123 silc_buffer_format(buffer,
124 SILC_STR_UI_SHORT(len),
125 SILC_STR_UI_CHAR(cmd),
126 SILC_STR_UI_CHAR(argc),
127 SILC_STR_UI_SHORT(ident),
132 silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
133 silc_buffer_format(buffer,
134 SILC_STR_UI_XNSTRING(args->data, args->len),
136 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
137 silc_buffer_free(args);
143 /* Same as above but encode the buffer from SilcCommandPayload structure
144 instead of raw data. */
146 SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload)
149 SilcBuffer args = NULL;
153 SILC_LOG_DEBUG(("Encoding command payload"));
156 args = silc_argument_payload_encode_payload(payload->args);
158 argc = silc_argument_get_arg_num(payload->args);
161 len += SILC_COMMAND_PAYLOAD_LEN;
162 buffer = silc_buffer_alloc_size(len);
165 silc_buffer_free(args);
169 /* Create Command payload */
170 silc_buffer_format(buffer,
171 SILC_STR_UI_SHORT(len),
172 SILC_STR_UI_CHAR(payload->cmd),
173 SILC_STR_UI_CHAR(argc),
174 SILC_STR_UI_SHORT(payload->ident),
179 silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
180 silc_buffer_format(buffer,
181 SILC_STR_UI_XNSTRING(args->data, args->len),
183 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
184 silc_buffer_free(args);
190 /* Encodes Command payload with variable argument list. The arguments
191 must be: SilcUInt32, unsigned char *, unsigned int, ... One
192 {SilcUInt32, unsigned char * and unsigned int} forms one argument,
193 thus `argc' in case when sending one {SilcUInt32, unsigned char *
194 and SilcUInt32} equals one (1) and when sending two of those it
195 equals two (2), and so on. This has to be preserved or bad things
196 will happen. The variable arguments is: {type, data, data_len}. */
198 SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
200 SilcUInt32 argc, ...)
206 buffer = silc_command_payload_encode_vap(cmd, ident, argc, ap);
212 /* Same as above but with va_list. */
214 SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
216 SilcUInt32 argc, va_list ap)
218 unsigned char **argv = NULL;
219 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
223 SilcBuffer buffer = NULL;
227 argv = silc_calloc(argc, sizeof(unsigned char *));
230 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
233 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
237 for (i = 0, k = 0; i < argc; i++) {
238 x_type = va_arg(ap, SilcUInt32);
239 x = va_arg(ap, unsigned char *);
240 x_len = va_arg(ap, SilcUInt32);
242 if (!x_type || !x || !x_len)
245 argv[k] = silc_memdup(x, x_len);
248 argv_lens[k] = x_len;
249 argv_types[k] = x_type;
254 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
258 for (i = 0; i < k; i++)
261 silc_free(argv_lens);
262 silc_free(argv_types);
267 /* Same as above except that this is used to encode strictly command
268 reply packets. The command status message to be returned is sent as
269 extra argument to this function. The `argc' must not count `status'
273 silc_command_reply_payload_encode_va(SilcCommand cmd,
274 SilcCommandStatus status,
275 SilcCommandStatus error,
277 SilcUInt32 argc, ...)
283 buffer = silc_command_reply_payload_encode_vap(cmd, status, error,
291 silc_command_reply_payload_encode_vap(SilcCommand cmd,
292 SilcCommandStatus status,
293 SilcCommandStatus error,
294 SilcUInt16 ident, SilcUInt32 argc,
297 unsigned char **argv;
298 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
299 unsigned char status_data[2];
303 SilcBuffer buffer = NULL;
307 argv = silc_calloc(argc, sizeof(unsigned char *));
310 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
315 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
317 silc_free(argv_lens);
322 status_data[0] = status;
323 status_data[1] = error;
324 argv[0] = silc_memdup(status_data, sizeof(status_data));
326 silc_free(argv_types);
327 silc_free(argv_lens);
331 argv_lens[0] = sizeof(status_data);
334 for (i = 1, k = 1; i < argc; i++) {
335 x_type = va_arg(ap, SilcUInt32);
336 x = va_arg(ap, unsigned char *);
337 x_len = va_arg(ap, SilcUInt32);
339 if (!x_type || !x || !x_len)
342 argv[k] = silc_memdup(x, x_len);
345 argv_lens[k] = x_len;
346 argv_types[k] = x_type;
350 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
354 for (i = 0; i < k; i++)
357 silc_free(argv_lens);
358 silc_free(argv_types);
363 /* Frees Command Payload */
365 void silc_command_payload_free(SilcCommandPayload payload)
368 silc_argument_payload_free(payload->args);
373 /* Returns command */
375 SilcCommand silc_command_get(SilcCommandPayload payload)
380 /* Retuns arguments payload */
382 SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload)
384 return payload->args;
387 /* Returns identifier */
389 SilcUInt16 silc_command_get_ident(SilcCommandPayload payload)
391 return payload->ident;
394 /* Return command status */
396 bool silc_command_get_status(SilcCommandPayload payload,
397 SilcCommandStatus *status,
398 SilcCommandStatus *error)
405 tmp = silc_argument_get_arg_type(payload->args, 1, &tmp_len);
406 if (!tmp || tmp_len != 2)
409 /* Check for 1.0 protocol version which didn't have `error' */
410 if (tmp[0] == 0 && tmp[1] != 0) {
411 /* Protocol 1.0 version */
413 SILC_GET16_MSB(s, tmp);
418 if (s >= SILC_STATUS_ERR_NO_SUCH_NICK && error)
420 return (s < SILC_STATUS_ERR_NO_SUCH_NICK);
423 /* Take both status and possible error */
425 *status = (SilcCommandStatus)tmp[0];
427 *error = (SilcCommandStatus)tmp[1];
429 /* If single error occurred have the both `status' and `error' indicate
430 the error value for convenience. */
431 if (tmp[0] >= SILC_STATUS_ERR_NO_SUCH_NICK && error)
434 return (tmp[0] < SILC_STATUS_ERR_NO_SUCH_NICK && tmp[1] == SILC_STATUS_OK);
437 /* Function to set identifier to already allocated Command Payload. Command
438 payloads are frequentlly resent in SILC and thusly this makes it easy
439 to set the identifier. */
441 void silc_command_set_ident(SilcCommandPayload payload, SilcUInt16 ident)
443 payload->ident = ident;
446 /* Function to set the command to already allocated Command Payload. */
448 void silc_command_set_command(SilcCommandPayload payload, SilcCommand command)
450 payload->cmd = command;