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),
71 if (p_len != buffer.len) {
72 SILC_LOG_ERROR(("Incorrect command payload in packet, packet dropped"));
78 SILC_LOG_ERROR(("Incorrect command type in command payload"));
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);
119 len += SILC_COMMAND_PAYLOAD_LEN;
120 buffer = silc_buffer_alloc_size(len);
124 /* Create Command payload */
125 silc_buffer_format(buffer,
126 SILC_STR_UI_SHORT(len),
127 SILC_STR_UI_CHAR(cmd),
128 SILC_STR_UI_CHAR(argc),
129 SILC_STR_UI_SHORT(ident),
134 silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
135 silc_buffer_format(buffer,
136 SILC_STR_UI_XNSTRING(args->data, args->len),
138 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
139 silc_buffer_free(args);
145 /* Same as above but encode the buffer from SilcCommandPayload structure
146 instead of raw data. */
148 SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload)
151 SilcBuffer args = NULL;
155 SILC_LOG_DEBUG(("Encoding command payload"));
158 args = silc_argument_payload_encode_payload(payload->args);
161 argc = silc_argument_get_arg_num(payload->args);
164 len += SILC_COMMAND_PAYLOAD_LEN;
165 buffer = silc_buffer_alloc_size(len);
168 silc_buffer_free(args);
172 /* Create Command payload */
173 silc_buffer_format(buffer,
174 SILC_STR_UI_SHORT(len),
175 SILC_STR_UI_CHAR(payload->cmd),
176 SILC_STR_UI_CHAR(argc),
177 SILC_STR_UI_SHORT(payload->ident),
182 silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
183 silc_buffer_format(buffer,
184 SILC_STR_UI_XNSTRING(args->data, args->len),
186 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
187 silc_buffer_free(args);
193 /* Encodes Command payload with variable argument list. The arguments
194 must be: SilcUInt32, unsigned char *, unsigned int, ... One
195 {SilcUInt32, unsigned char * and unsigned int} forms one argument,
196 thus `argc' in case when sending one {SilcUInt32, unsigned char *
197 and SilcUInt32} equals one (1) and when sending two of those it
198 equals two (2), and so on. This has to be preserved or bad things
199 will happen. The variable arguments is: {type, data, data_len}. */
201 SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
203 SilcUInt32 argc, ...)
209 buffer = silc_command_payload_encode_vap(cmd, ident, argc, ap);
215 /* Same as above but with va_list. */
217 SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
219 SilcUInt32 argc, va_list ap)
221 unsigned char **argv = NULL;
222 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
226 SilcBuffer buffer = NULL;
230 argv = silc_calloc(argc, sizeof(unsigned char *));
233 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
236 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
240 for (i = 0, k = 0; i < argc; i++) {
241 x_type = va_arg(ap, SilcUInt32);
242 x = va_arg(ap, unsigned char *);
243 x_len = va_arg(ap, SilcUInt32);
245 if (!x_type || !x || !x_len)
248 argv[k] = silc_memdup(x, x_len);
251 argv_lens[k] = x_len;
252 argv_types[k] = x_type;
257 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
261 for (i = 0; i < k; i++)
264 silc_free(argv_lens);
265 silc_free(argv_types);
270 /* Same as above except that this is used to encode strictly command
271 reply packets. The command status message to be returned is sent as
272 extra argument to this function. The `argc' must not count `status'
276 silc_command_reply_payload_encode_va(SilcCommand cmd,
280 SilcUInt32 argc, ...)
286 buffer = silc_command_reply_payload_encode_vap(cmd, status, error,
294 silc_command_reply_payload_encode_vap(SilcCommand cmd,
297 SilcUInt16 ident, SilcUInt32 argc,
300 unsigned char **argv;
301 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
302 unsigned char status_data[2];
306 SilcBuffer buffer = NULL;
310 argv = silc_calloc(argc, sizeof(unsigned char *));
313 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
318 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
320 silc_free(argv_lens);
325 status_data[0] = status;
326 status_data[1] = error;
327 argv[0] = silc_memdup(status_data, sizeof(status_data));
329 silc_free(argv_types);
330 silc_free(argv_lens);
334 argv_lens[0] = sizeof(status_data);
337 for (i = 1, k = 1; i < argc; i++) {
338 x_type = va_arg(ap, SilcUInt32);
339 x = va_arg(ap, unsigned char *);
340 x_len = va_arg(ap, SilcUInt32);
342 if (!x_type || !x || !x_len)
345 argv[k] = silc_memdup(x, x_len);
348 argv_lens[k] = x_len;
349 argv_types[k] = x_type;
353 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
357 for (i = 0; i < k; i++)
360 silc_free(argv_lens);
361 silc_free(argv_types);
366 /* Frees Command Payload */
368 void silc_command_payload_free(SilcCommandPayload payload)
371 silc_argument_payload_free(payload->args);
376 /* Returns command */
378 SilcCommand silc_command_get(SilcCommandPayload payload)
383 /* Retuns arguments payload */
385 SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload)
387 return payload->args;
390 /* Returns identifier */
392 SilcUInt16 silc_command_get_ident(SilcCommandPayload payload)
394 return payload->ident;
397 /* Return command status */
399 bool silc_command_get_status(SilcCommandPayload payload,
408 tmp = silc_argument_get_arg_type(payload->args, 1, &tmp_len);
409 if (!tmp || tmp_len != 2)
412 /* Check for 1.0 protocol version which didn't have `error' */
413 if (tmp[0] == 0 && tmp[1] != 0) {
414 /* Protocol 1.0 version */
416 SILC_GET16_MSB(s, tmp);
421 if (s >= SILC_STATUS_ERR_NO_SUCH_NICK && error)
423 return (s < SILC_STATUS_ERR_NO_SUCH_NICK);
426 /* Take both status and possible error */
428 *status = (SilcStatus)tmp[0];
430 *error = (SilcStatus)tmp[1];
432 /* If single error occurred have the both `status' and `error' indicate
433 the error value for convenience. */
434 if (tmp[0] >= SILC_STATUS_ERR_NO_SUCH_NICK && error)
437 return (tmp[0] < SILC_STATUS_ERR_NO_SUCH_NICK && tmp[1] == SILC_STATUS_OK);
440 /* Function to set identifier to already allocated Command Payload. Command
441 payloads are frequentlly resent in SILC and thusly this makes it easy
442 to set the identifier. */
444 void silc_command_set_ident(SilcCommandPayload payload, SilcUInt16 ident)
446 payload->ident = ident;
449 /* Function to set the command to already allocated Command Payload. */
451 void silc_command_set_command(SilcCommandPayload payload, SilcCommand command)
453 payload->cmd = command;