5 Author: Pekka Riikonen <priikone@silcnet.org>
7 Copyright (C) 1997 - 2006 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.
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 != silc_buffer_len(&buffer)) {
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,
87 silc_buffer_len(&buffer),
94 silc_buffer_push(&buffer, SILC_COMMAND_PAYLOAD_LEN);
99 /* Encodes Command Payload returning it to SilcBuffer. */
101 SilcBuffer silc_command_payload_encode(SilcCommand cmd,
103 unsigned char **argv,
104 SilcUInt32 *argv_lens,
105 SilcUInt32 *argv_types,
109 SilcBuffer args = NULL;
112 SILC_LOG_DEBUG(("Encoding command payload"));
115 args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types);
118 len = silc_buffer_len(args);
121 len += SILC_COMMAND_PAYLOAD_LEN;
122 buffer = silc_buffer_alloc_size(len);
126 /* Create Command payload */
127 silc_buffer_format(buffer,
128 SILC_STR_UI_SHORT(len),
129 SILC_STR_UI_CHAR(cmd),
130 SILC_STR_UI_CHAR(argc),
131 SILC_STR_UI_SHORT(ident),
136 silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
137 silc_buffer_format(buffer,
138 SILC_STR_UI_XNSTRING(args->data,
139 silc_buffer_len(args)),
141 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
142 silc_buffer_free(args);
148 /* Same as above but encode the buffer from SilcCommandPayload structure
149 instead of raw data. */
151 SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload)
154 SilcBuffer args = NULL;
158 SILC_LOG_DEBUG(("Encoding command payload"));
161 args = silc_argument_payload_encode_payload(payload->args);
163 len = silc_buffer_len(args);
164 argc = silc_argument_get_arg_num(payload->args);
167 len += SILC_COMMAND_PAYLOAD_LEN;
168 buffer = silc_buffer_alloc_size(len);
171 silc_buffer_free(args);
175 /* Create Command payload */
176 silc_buffer_format(buffer,
177 SILC_STR_UI_SHORT(len),
178 SILC_STR_UI_CHAR(payload->cmd),
179 SILC_STR_UI_CHAR(argc),
180 SILC_STR_UI_SHORT(payload->ident),
185 silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
186 silc_buffer_format(buffer,
187 SILC_STR_UI_XNSTRING(args->data,
188 silc_buffer_len(args)),
190 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
191 silc_buffer_free(args);
197 /* Encodes Command payload with variable argument list. The arguments
198 must be: SilcUInt32, unsigned char *, unsigned int, ... One
199 {SilcUInt32, unsigned char * and unsigned int} forms one argument,
200 thus `argc' in case when sending one {SilcUInt32, unsigned char *
201 and SilcUInt32} equals one (1) and when sending two of those it
202 equals two (2), and so on. This has to be preserved or bad things
203 will happen. The variable arguments is: {type, data, data_len}. */
205 SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
207 SilcUInt32 argc, ...)
213 buffer = silc_command_payload_encode_vap(cmd, ident, argc, ap);
219 /* Same as above but with va_list. */
221 SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
223 SilcUInt32 argc, va_list ap)
225 unsigned char **argv = NULL;
226 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
230 SilcBuffer buffer = NULL;
234 argv = silc_calloc(argc, sizeof(unsigned char *));
237 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
240 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
244 for (i = 0, k = 0; i < argc; i++) {
245 x_type = va_arg(ap, SilcUInt32);
246 x = va_arg(ap, unsigned char *);
247 x_len = va_arg(ap, SilcUInt32);
249 if (!x_type || !x || !x_len)
252 argv[k] = silc_memdup(x, x_len);
255 argv_lens[k] = x_len;
256 argv_types[k] = x_type;
261 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
265 for (i = 0; i < k; i++)
268 silc_free(argv_lens);
269 silc_free(argv_types);
274 /* Same as above except that this is used to encode strictly command
275 reply packets. The command status message to be returned is sent as
276 extra argument to this function. The `argc' must not count `status'
280 silc_command_reply_payload_encode_va(SilcCommand cmd,
284 SilcUInt32 argc, ...)
290 buffer = silc_command_reply_payload_encode_vap(cmd, status, error,
298 silc_command_reply_payload_encode_vap(SilcCommand cmd,
301 SilcUInt16 ident, SilcUInt32 argc,
304 unsigned char **argv;
305 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
306 unsigned char status_data[2];
310 SilcBuffer buffer = NULL;
314 argv = silc_calloc(argc, sizeof(unsigned char *));
317 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
322 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
324 silc_free(argv_lens);
329 status_data[0] = status;
330 status_data[1] = error;
331 argv[0] = silc_memdup(status_data, sizeof(status_data));
333 silc_free(argv_types);
334 silc_free(argv_lens);
338 argv_lens[0] = sizeof(status_data);
341 for (i = 1, k = 1; i < argc; i++) {
342 x_type = va_arg(ap, SilcUInt32);
343 x = va_arg(ap, unsigned char *);
344 x_len = va_arg(ap, SilcUInt32);
346 if (!x_type || !x || !x_len)
349 argv[k] = silc_memdup(x, x_len);
352 argv_lens[k] = x_len;
353 argv_types[k] = x_type;
357 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
361 for (i = 0; i < k; i++)
364 silc_free(argv_lens);
365 silc_free(argv_types);
370 /* Frees Command Payload */
372 void silc_command_payload_free(SilcCommandPayload payload)
375 silc_argument_payload_free(payload->args);
380 /* Returns command */
382 SilcCommand silc_command_get(SilcCommandPayload payload)
387 /* Retuns arguments payload */
389 SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload)
391 return payload->args;
394 /* Returns identifier */
396 SilcUInt16 silc_command_get_ident(SilcCommandPayload payload)
398 return payload->ident;
401 /* Return command status */
403 SilcBool silc_command_get_status(SilcCommandPayload payload,
412 tmp = silc_argument_get_arg_type(payload->args, 1, &tmp_len);
413 if (!tmp || tmp_len != 2)
416 /* Check for 1.0 protocol version which didn't have `error' */
417 if (tmp[0] == 0 && tmp[1] != 0) {
418 /* Protocol 1.0 version */
420 SILC_GET16_MSB(s, tmp);
425 if (s >= SILC_STATUS_ERR_NO_SUCH_NICK && error)
427 return (s < SILC_STATUS_ERR_NO_SUCH_NICK);
430 /* Take both status and possible error */
432 *status = (SilcStatus)tmp[0];
434 *error = (SilcStatus)tmp[1];
436 /* If single error occurred have the both `status' and `error' indicate
437 the error value for convenience. */
438 if (tmp[0] >= SILC_STATUS_ERR_NO_SUCH_NICK && error)
441 return (tmp[0] < SILC_STATUS_ERR_NO_SUCH_NICK && tmp[1] == SILC_STATUS_OK);
444 /* Function to set identifier to already allocated Command Payload. Command
445 payloads are frequentlly resent in SILC and thusly this makes it easy
446 to set the identifier. */
448 void silc_command_set_ident(SilcCommandPayload payload, SilcUInt16 ident)
450 payload->ident = ident;
453 /* Function to set the command to already allocated Command Payload. */
455 void silc_command_set_command(SilcCommandPayload payload, SilcCommand command)
457 payload->cmd = command;