1 /*
2
3 silccommand.c
4
5 Author: Pekka Riikonen <priikone@silcnet.org>
6
7 Copyright (C) 1997 - 2006 Pekka Riikonen
8
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.
12
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.
17
18 */
19 /* $Id: silccommand.c,v 1.34 2006/07/18 13:15:14 priikone Exp $ */
20
21 #include "silc.h"
22 #include "silccommand.h"
23
24 /******************************************************************************
25
26 Command Payload
27
28 ******************************************************************************/
29
30 /* Command Payload structure. Contents of this structure is parsed
31 from SILC packets. */
32 struct SilcCommandPayloadStruct {
33 SilcCommand cmd;
34 SilcUInt16 ident;
35 SilcArgumentPayload args;
36 };
37
38 /* Length of the command payload */
39 #define SILC_COMMAND_PAYLOAD_LEN 6
40
41 /* Parses command payload returning new command payload structure */
42
43 SilcCommandPayload silc_command_payload_parse(const unsigned char *payload,
44 SilcUInt32 payload_len)
45 {
46 SilcBufferStruct buffer;
47 SilcCommandPayload newp;
48 unsigned char args_num;
49 SilcUInt16 p_len;
50 int ret;
51
52 SILC_LOG_DEBUG(("Parsing command payload"));
53
54 silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
55 newp = silc_calloc(1, sizeof(*newp));
56 if (!newp)
57 return NULL;
58
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),
65 SILC_STR_END);
66 if (ret == -1) {
67 SILC_LOG_ERROR(("Incorrect command payload in packet"));
68 silc_free(newp);
69 return NULL;
70 }
71
72 if (p_len != silc_buffer_len(&buffer)) {
73 SILC_LOG_ERROR(("Incorrect command payload in packet"));
74 silc_free(newp);
75 return NULL;
76 }
77
78 if (newp->cmd == 0) {
79 SILC_LOG_ERROR(("Incorrect command type in command payload"));
80 silc_free(newp);
81 return NULL;
82 }
83
84 silc_buffer_pull(&buffer, SILC_COMMAND_PAYLOAD_LEN);
85 if (args_num) {
86 newp->args = silc_argument_payload_parse(buffer.data,
87 silc_buffer_len(&buffer),
88 args_num);
89 if (!newp->args) {
90 silc_free(newp);
91 return NULL;
92 }
93 }
94 silc_buffer_push(&buffer, SILC_COMMAND_PAYLOAD_LEN);
95
96 return newp;
97 }
98
99 /* Encodes Command Payload returning it to SilcBuffer. */
100
101 SilcBuffer silc_command_payload_encode(SilcCommand cmd,
102 SilcUInt32 argc,
103 unsigned char **argv,
104 SilcUInt32 *argv_lens,
105 SilcUInt32 *argv_types,
106 SilcUInt16 ident)
107 {
108 SilcBuffer buffer;
109 SilcBuffer args = NULL;
110 SilcUInt32 len = 0;
111
112 SILC_LOG_DEBUG(("Encoding command payload"));
113
114 if (argc) {
115 args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types);
116 if (!args)
117 return NULL;
118 len = silc_buffer_len(args);
119 }
120
121 len += SILC_COMMAND_PAYLOAD_LEN;
122 buffer = silc_buffer_alloc_size(len);
123 if (!buffer)
124 return NULL;
125
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),
132 SILC_STR_END);
133
134 /* Add arguments */
135 if (argc) {
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)),
140 SILC_STR_END);
141 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
142 silc_buffer_free(args);
143 }
144
145 return buffer;
146 }
147
148 /* Same as above but encode the buffer from SilcCommandPayload structure
149 instead of raw data. */
150
151 SilcBuffer silc_command_payload_encode_payload(SilcCommandPayload payload)
152 {
153 SilcBuffer buffer;
154 SilcBuffer args = NULL;
155 SilcUInt32 len = 0;
156 SilcUInt32 argc = 0;
157
158 SILC_LOG_DEBUG(("Encoding command payload"));
159
160 if (payload->args) {
161 args = silc_argument_payload_encode_payload(payload->args);
162 if (args)
163 len = silc_buffer_len(args);
164 argc = silc_argument_get_arg_num(payload->args);
165 }
166
167 len += SILC_COMMAND_PAYLOAD_LEN;
168 buffer = silc_buffer_alloc_size(len);
169 if (!buffer) {
170 if (args)
171 silc_buffer_free(args);
172 return NULL;
173 }
174
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),
181 SILC_STR_END);
182
183 /* Add arguments */
184 if (args) {
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)),
189 SILC_STR_END);
190 silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
191 silc_buffer_free(args);
192 }
193
194 return buffer;
195 }
196
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}. */
204
205 SilcBuffer silc_command_payload_encode_va(SilcCommand cmd,
206 SilcUInt16 ident,
207 SilcUInt32 argc, ...)
208 {
209 va_list ap;
210 SilcBuffer buffer;
211
212 va_start(ap, argc);
213 buffer = silc_command_payload_encode_vap(cmd, ident, argc, ap);
214 va_end(ap);
215
216 return buffer;
217 }
218
219 /* Same as above but with va_list. */
220
221 SilcBuffer silc_command_payload_encode_vap(SilcCommand cmd,
222 SilcUInt16 ident,
223 SilcUInt32 argc, va_list ap)
224 {
225 unsigned char **argv = NULL;
226 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
227 unsigned char *x;
228 SilcUInt32 x_len;
229 SilcUInt32 x_type;
230 SilcBuffer buffer = NULL;
231 int i, k = 0;
232
233 if (argc) {
234 argv = silc_calloc(argc, sizeof(unsigned char *));
235 if (!argv)
236 return NULL;
237 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
238 if (!argv_lens)
239 return NULL;
240 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
241 if (!argv_types)
242 return NULL;
243
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);
248
249 if (!x_type || !x || !x_len)
250 continue;
251
252 argv[k] = silc_memdup(x, x_len);
253 if (!argv[k])
254 goto out;
255 argv_lens[k] = x_len;
256 argv_types[k] = x_type;
257 k++;
258 }
259 }
260
261 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
262 argv_types, ident);
263
264 out:
265 for (i = 0; i < k; i++)
266 silc_free(argv[i]);
267 silc_free(argv);
268 silc_free(argv_lens);
269 silc_free(argv_types);
270
271 return buffer;
272 }
273
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'
277 as on argument. */
278
279 SilcBuffer
280 silc_command_reply_payload_encode_va(SilcCommand cmd,
281 SilcStatus status,
282 SilcStatus error,
283 SilcUInt16 ident,
284 SilcUInt32 argc, ...)
285 {
286 va_list ap;
287 SilcBuffer buffer;
288
289 va_start(ap, argc);
290 buffer = silc_command_reply_payload_encode_vap(cmd, status, error,
291 ident, argc, ap);
292 va_end(ap);
293
294 return buffer;
295 }
296
297 SilcBuffer
298 silc_command_reply_payload_encode_vap(SilcCommand cmd,
299 SilcStatus status,
300 SilcStatus error,
301 SilcUInt16 ident, SilcUInt32 argc,
302 va_list ap)
303 {
304 unsigned char **argv;
305 SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
306 unsigned char status_data[2];
307 unsigned char *x;
308 SilcUInt32 x_len;
309 SilcUInt32 x_type;
310 SilcBuffer buffer = NULL;
311 int i, k;
312
313 argc++;
314 argv = silc_calloc(argc, sizeof(unsigned char *));
315 if (!argv)
316 return NULL;
317 argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
318 if (!argv_lens) {
319 silc_free(argv);
320 return NULL;
321 }
322 argv_types = silc_calloc(argc, sizeof(SilcUInt32));
323 if (!argv_types) {
324 silc_free(argv_lens);
325 silc_free(argv);
326 return NULL;
327 }
328
329 status_data[0] = status;
330 status_data[1] = error;
331 argv[0] = silc_memdup(status_data, sizeof(status_data));
332 if (!argv[0]) {
333 silc_free(argv_types);
334 silc_free(argv_lens);
335 silc_free(argv);
336 return NULL;
337 }
338 argv_lens[0] = sizeof(status_data);
339 argv_types[0] = 1;
340
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);
345
346 if (!x_type || !x || !x_len)
347 continue;
348
349 argv[k] = silc_memdup(x, x_len);
350 if (!argv[k])
351 goto out;
352 argv_lens[k] = x_len;
353 argv_types[k] = x_type;
354 k++;
355 }
356
357 buffer = silc_command_payload_encode(cmd, k, argv, argv_lens,
358 argv_types, ident);
359
360 out:
361 for (i = 0; i < k; i++)
362 silc_free(argv[i]);
363 silc_free(argv);
364 silc_free(argv_lens);
365 silc_free(argv_types);
366
367 return buffer;
368 }
369
370 /* Frees Command Payload */
371
372 void silc_command_payload_free(SilcCommandPayload payload)
373 {
374 if (payload) {
375 silc_argument_payload_free(payload->args);
376 silc_free(payload);
377 }
378 }
379
380 /* Returns command */
381
382 SilcCommand silc_command_get(SilcCommandPayload payload)
383 {
384 return payload->cmd;
385 }
386
387 /* Retuns arguments payload */
388
389 SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload)
390 {
391 return payload->args;
392 }
393
394 /* Returns identifier */
395
396 SilcUInt16 silc_command_get_ident(SilcCommandPayload payload)
397 {
398 return payload->ident;
399 }
400
401 /* Return command status */
402
403 SilcBool silc_command_get_status(SilcCommandPayload payload,
404 SilcStatus *status,
405 SilcStatus *error)
406 {
407 unsigned char *tmp;
408 SilcUInt32 tmp_len;
409
410 if (!payload->args)
411 return 0;
412 tmp = silc_argument_get_arg_type(payload->args, 1, &tmp_len);
413 if (!tmp || tmp_len != 2)
414 return 0;
415
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 */
419 SilcStatus s;
420 SILC_GET16_MSB(s, tmp);
421 if (status)
422 *status = s;
423 if (error)
424 *error = 0;
425 if (s >= SILC_STATUS_ERR_NO_SUCH_NICK && error)
426 *error = s;
427 return (s < SILC_STATUS_ERR_NO_SUCH_NICK);
428 }
429
430 /* Take both status and possible error */
431 if (status)
432 *status = (SilcStatus)tmp[0];
433 if (error)
434 *error = (SilcStatus)tmp[1];
435
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)
439 *error = tmp[0];
440
441 return (tmp[0] < SILC_STATUS_ERR_NO_SUCH_NICK && tmp[1] == SILC_STATUS_OK);
442 }
443
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. */
447
448 void silc_command_set_ident(SilcCommandPayload payload, SilcUInt16 ident)
449 {
450 payload->ident = ident;
451 }
452
453 /* Function to set the command to already allocated Command Payload. */
454
455 void silc_command_set_command(SilcCommandPayload payload, SilcCommand command)
456 {
457 payload->cmd = command;
458 }
459
This page was automatically generated by the LXR engine.
Free-text search provided by Glimpse