5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2002 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; version 2 of the License.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
21 #include "silcincludes.h"
22 #include "silccommand.h"
24 /******************************************************************************
28 ******************************************************************************/
30 /* Command Payload structure. Contents of this structure is parsed
32 struct SilcCommandPayloadStruct {
35 SilcArgumentPayload args;
38 /* Length of the command payload */
39 #define SILC_COMMAND_PAYLOAD_LEN 6
41 /* Parses command payload returning new command payload structure */
43 SilcCommandPayload silc_command_payload_parse(const unsigned char *payload,
44 SilcUInt32 payload_len)
46 SilcBufferStruct buffer;
47 SilcCommandPayload newp;
48 unsigned char args_num;
52 SILC_LOG_DEBUG(("Parsing command payload"));
54 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
55 newp = silc_calloc(1, sizeof(*newp));
59 /* Parse the Command Payload */
60 ret = silc_buffer_unformat(&buffer,
61 SILC_STR_UI_SHORT(&p_len),
62 SILC_STR_UI_CHAR(&newp->cmd),
63 SILC_STR_UI_CHAR(&args_num),
64 SILC_STR_UI_SHORT(&newp->ident),
67 SILC_LOG_ERROR(("Incorrect command payload in packet"));
72 if (p_len != buffer.len) {
73 SILC_LOG_ERROR(("Incorrect command payload in packet"));
79 SILC_LOG_ERROR(("Incorrect command type in command payload"));
84 silc_buffer_pull(&buffer, SILC_COMMAND_PAYLOAD_LEN);
86 newp->args = silc_argument_payload_parse(buffer.data, buffer.len,
93 silc_buffer_push(&buffer, SILC_COMMAND_PAYLOAD_LEN);
98 /* Encodes Command Payload returning it to SilcBuffer. */
100 SilcBuffer silc_command_payload_encode(SilcCommand cmd,
102 unsigned char **argv,
103 SilcUInt32 *argv_lens,
104 SilcUInt32 *argv_types,
108 SilcBuffer args = NULL;
111 SILC_LOG_DEBUG(("Encoding command payload"));
114 args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types);
120 len += SILC_COMMAND_PAYLOAD_LEN;
121 buffer = silc_buffer_alloc_size(len);
125 /* Create Command payload */
126 silc_buffer_format(buffer,
127 SILC_STR_UI_SHORT(len),
128 SILC_STR_UI_CHAR(cmd),
129 SILC_STR_UI_CHAR(argc),
130 SILC_STR_UI_SHORT(ident),
135 silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
136 silc_buffer_format(buffer,
137 SILC_STR_UI_XNSTRING(args->data, args->len),
139 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
140 silc_buffer_free(args);
146 /* Same as above but encode the buffer from SilcCommandPayload structure
147 instead of raw data. */
149 SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload)
152 SilcBuffer args = NULL;
156 SILC_LOG_DEBUG(("Encoding command payload"));
159 args = silc_argument_payload_encode_payload(payload->args);
162 argc = silc_argument_get_arg_num(payload->args);
165 len += SILC_COMMAND_PAYLOAD_LEN;
166 buffer = silc_buffer_alloc_size(len);
169 silc_buffer_free(args);
173 /* Create Command payload */
174 silc_buffer_format(buffer,
175 SILC_STR_UI_SHORT(len),
176 SILC_STR_UI_CHAR(payload->cmd),
177 SILC_STR_UI_CHAR(argc),
178 SILC_STR_UI_SHORT(payload->ident),
183 silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
184 silc_buffer_format(buffer,
185 SILC_STR_UI_XNSTRING(args->data, args->len),
187 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
188 silc_buffer_free(args);
194 /* Encodes Command payload with variable argument list. The arguments
195 must be: SilcUInt32, unsigned char *, unsigned int, ... One
196 {SilcUInt32, unsigned char * and unsigned int} forms one argument,
197 thus `argc' in case when sending one {SilcUInt32, unsigned char *
198 and SilcUInt32} equals one (1) and when sending two of those it
199 equals two (2), and so on. This has to be preserved or bad things
200 will happen. The variable arguments is: {type, data, data_len}. */
202 SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
204 SilcUInt32 argc, ...)
210 buffer = silc_command_payload_encode_vap(cmd, ident, argc, ap);
216 /* Same as above but with va_list. */
218 SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
220 SilcUInt32 argc, va_list ap)
222 unsigned char **argv = NULL;
223 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
227 SilcBuffer buffer = NULL;
231 argv = silc_calloc(argc, sizeof(unsigned char *));
234 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
237 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
241 for (i = 0, k = 0; i < argc; i++) {
242 x_type = va_arg(ap, SilcUInt32);
243 x = va_arg(ap, unsigned char *);
244 x_len = va_arg(ap, SilcUInt32);
246 if (!x_type || !x || !x_len)
249 argv[k] = silc_memdup(x, x_len);
252 argv_lens[k] = x_len;
253 argv_types[k] = x_type;
258 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
262 for (i = 0; i < k; i++)
265 silc_free(argv_lens);
266 silc_free(argv_types);
271 /* Same as above except that this is used to encode strictly command
272 reply packets. The command status message to be returned is sent as
273 extra argument to this function. The `argc' must not count `status'
277 silc_command_reply_payload_encode_va(SilcCommand cmd,
281 SilcUInt32 argc, ...)
287 buffer = silc_command_reply_payload_encode_vap(cmd, status, error,
295 silc_command_reply_payload_encode_vap(SilcCommand cmd,
298 SilcUInt16 ident, SilcUInt32 argc,
301 unsigned char **argv;
302 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
303 unsigned char status_data[2];
307 SilcBuffer buffer = NULL;
311 argv = silc_calloc(argc, sizeof(unsigned char *));
314 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
319 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
321 silc_free(argv_lens);
326 status_data[0] = status;
327 status_data[1] = error;
328 argv[0] = silc_memdup(status_data, sizeof(status_data));
330 silc_free(argv_types);
331 silc_free(argv_lens);
335 argv_lens[0] = sizeof(status_data);
338 for (i = 1, k = 1; i < argc; i++) {
339 x_type = va_arg(ap, SilcUInt32);
340 x = va_arg(ap, unsigned char *);
341 x_len = va_arg(ap, SilcUInt32);
343 if (!x_type || !x || !x_len)
346 argv[k] = silc_memdup(x, x_len);
349 argv_lens[k] = x_len;
350 argv_types[k] = x_type;
354 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
358 for (i = 0; i < k; i++)
361 silc_free(argv_lens);
362 silc_free(argv_types);
367 /* Frees Command Payload */
369 void silc_command_payload_free(SilcCommandPayload payload)
372 silc_argument_payload_free(payload->args);
377 /* Returns command */
379 SilcCommand silc_command_get(SilcCommandPayload payload)
384 /* Retuns arguments payload */
386 SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload)
388 return payload->args;
391 /* Returns identifier */
393 SilcUInt16 silc_command_get_ident(SilcCommandPayload payload)
395 return payload->ident;
398 /* Return command status */
400 bool silc_command_get_status(SilcCommandPayload payload,
409 tmp = silc_argument_get_arg_type(payload->args, 1, &tmp_len);
410 if (!tmp || tmp_len != 2)
413 /* Check for 1.0 protocol version which didn't have `error' */
414 if (tmp[0] == 0 && tmp[1] != 0) {
415 /* Protocol 1.0 version */
417 SILC_GET16_MSB(s, tmp);
422 if (s >= SILC_STATUS_ERR_NO_SUCH_NICK && error)
424 return (s < SILC_STATUS_ERR_NO_SUCH_NICK);
427 /* Take both status and possible error */
429 *status = (SilcStatus)tmp[0];
431 *error = (SilcStatus)tmp[1];
433 /* If single error occurred have the both `status' and `error' indicate
434 the error value for convenience. */
435 if (tmp[0] >= SILC_STATUS_ERR_NO_SUCH_NICK && error)
438 return (tmp[0] < SILC_STATUS_ERR_NO_SUCH_NICK && tmp[1] == SILC_STATUS_OK);
441 /* Function to set identifier to already allocated Command Payload. Command
442 payloads are frequentlly resent in SILC and thusly this makes it easy
443 to set the identifier. */
445 void silc_command_set_ident(SilcCommandPayload payload, SilcUInt16 ident)
447 payload->ident = ident;
450 /* Function to set the command to already allocated Command Payload. */
452 void silc_command_set_command(SilcCommandPayload payload, SilcCommand command)
454 payload->cmd = command;