Created silcpayload.[ch] for generic payloads.
[silc.git] / lib / silccore / silccommand.c
1 /*
2
3   silccommand.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 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; either version 2 of the License, or
12   (at your option) any later version.
13   
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.
18
19 */
20 /* $Id$ */
21
22 #include "silcincludes.h"
23 #include "silccommand.h"
24
25 /******************************************************************************
26
27                               Command Payload
28
29 ******************************************************************************/
30
31 /* Command Payload structure. Contents of this structure is parsed
32    from SILC packets. */
33 struct SilcCommandPayloadStruct {
34   SilcCommand cmd;
35   unsigned short ident;
36   SilcArgumentPayload args;
37 };
38
39 /* Length of the command payload */
40 #define SILC_COMMAND_PAYLOAD_LEN 6
41
42 /* Parses command payload returning new command payload structure */
43
44 SilcCommandPayload silc_command_payload_parse(SilcBuffer buffer)
45 {
46   SilcCommandPayload new;
47   unsigned char args_num;
48   unsigned short payload_len;
49
50   SILC_LOG_DEBUG(("Parsing command payload"));
51
52   new = silc_calloc(1, sizeof(*new));
53
54   /* Parse the Command Payload */
55   silc_buffer_unformat(buffer, 
56                        SILC_STR_UI_SHORT(&payload_len),
57                        SILC_STR_UI_CHAR(&new->cmd),
58                        SILC_STR_UI_CHAR(&args_num),
59                        SILC_STR_UI_SHORT(&new->ident),
60                        SILC_STR_END);
61
62   if (payload_len != buffer->len) {
63     SILC_LOG_ERROR(("Incorrect command payload in packet, packet dropped"));
64     silc_free(new);
65     return NULL;
66   }
67
68   if (new->cmd == 0) {
69     silc_free(new);
70     return NULL;
71   }
72
73   silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
74   new->args = silc_argument_payload_parse(buffer, args_num);
75   if (!new->args) {
76     silc_free(new);
77     return NULL;
78   }
79   silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
80
81   return new;
82 }
83
84 /* Encodes Command Payload returning it to SilcBuffer. */
85
86 SilcBuffer silc_command_payload_encode(SilcCommand cmd,
87                                        unsigned int argc,
88                                        unsigned char **argv,
89                                        unsigned int *argv_lens,
90                                        unsigned int *argv_types,
91                                        unsigned short ident)
92 {
93   SilcBuffer buffer;
94   SilcBuffer args = NULL;
95   unsigned int len = 0;
96
97   SILC_LOG_DEBUG(("Encoding command payload"));
98
99   if (argc) {
100     args = silc_argument_payload_encode(argc, argv, argv_lens, argv_types);
101     len = args->len;
102   }
103
104   len += SILC_COMMAND_PAYLOAD_LEN;
105   buffer = silc_buffer_alloc(len);
106   silc_buffer_pull_tail(buffer, SILC_BUFFER_END(buffer));
107
108   /* Create Command payload */
109   silc_buffer_format(buffer,
110                      SILC_STR_UI_SHORT(len),
111                      SILC_STR_UI_CHAR(cmd),
112                      SILC_STR_UI_CHAR(argc),
113                      SILC_STR_UI_SHORT(ident),
114                      SILC_STR_END);
115
116   /* Add arguments */
117   if (argc) {
118     silc_buffer_pull(buffer, SILC_COMMAND_PAYLOAD_LEN);
119     silc_buffer_format(buffer,
120                        SILC_STR_UI_XNSTRING(args->data, args->len),
121                        SILC_STR_END);
122     silc_buffer_push(buffer, SILC_COMMAND_PAYLOAD_LEN);
123     silc_free(args);
124   }
125
126   return buffer;
127 }
128
129 /* Encodes Command payload with variable argument list. The arguments
130    must be: unsigned int, unsigned char *, unsigned int, ... One 
131    {unsigned int, unsigned char * and unsigned int} forms one argument, 
132    thus `argc' in case when sending one {unsigned int, unsigned char * 
133    and unsigned int} equals one (1) and when sending two of those it
134    equals two (2), and so on. This has to be preserved or bad things
135    will happen. The variable arguments is: {type, data, data_len}. */
136
137 SilcBuffer silc_command_payload_encode_va(SilcCommand cmd, 
138                                           unsigned short ident, 
139                                           unsigned int argc, ...)
140 {
141   va_list ap;
142   unsigned char **argv;
143   unsigned int *argv_lens = NULL, *argv_types = NULL;
144   unsigned char *x;
145   unsigned int x_len;
146   unsigned int x_type;
147   SilcBuffer buffer;
148   int i;
149
150   va_start(ap, argc);
151
152   argv = silc_calloc(argc, sizeof(unsigned char *));
153   argv_lens = silc_calloc(argc, sizeof(unsigned int));
154   argv_types = silc_calloc(argc, sizeof(unsigned int));
155
156   for (i = 0; i < argc; i++) {
157     x_type = va_arg(ap, unsigned int);
158     x = va_arg(ap, unsigned char *);
159     x_len = va_arg(ap, unsigned int);
160
161     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
162     memcpy(argv[i], x, x_len);
163     argv_lens[i] = x_len;
164     argv_types[i] = x_type;
165   }
166
167   buffer = silc_command_payload_encode(cmd, argc, argv, 
168                                        argv_lens, argv_types, ident);
169
170   for (i = 0; i < argc; i++)
171     silc_free(argv[i]);
172   silc_free(argv);
173   silc_free(argv_lens);
174   silc_free(argv_types);
175
176   return buffer;
177 }
178
179 /* Same as above except that this is used to encode strictly command
180    reply packets. The command status message to be returned is sent as
181    extra argument to this function. The `argc' must not count `status'
182    as on argument. */
183
184 SilcBuffer 
185 silc_command_reply_payload_encode_va(SilcCommand cmd, 
186                                      SilcCommandStatus status,
187                                      unsigned short ident,
188                                      unsigned int argc, ...)
189 {
190   va_list ap;
191   unsigned char **argv;
192   unsigned int *argv_lens = NULL, *argv_types = NULL;
193   unsigned char status_data[2];
194   unsigned char *x;
195   unsigned int x_len;
196   unsigned int x_type;
197   SilcBuffer buffer;
198   int i;
199
200   va_start(ap, argc);
201
202   argc++;
203   argv = silc_calloc(argc, sizeof(unsigned char *));
204   argv_lens = silc_calloc(argc, sizeof(unsigned int));
205   argv_types = silc_calloc(argc, sizeof(unsigned int));
206
207   SILC_PUT16_MSB(status, status_data);
208   argv[0] = silc_calloc(sizeof(status_data) + 1, sizeof(unsigned char));
209   memcpy(argv[0], status_data, sizeof(status_data));
210   argv_lens[0] = sizeof(status_data);
211   argv_types[0] = 1;
212
213   for (i = 1; i < argc; i++) {
214     x_type = va_arg(ap, unsigned int);
215     x = va_arg(ap, unsigned char *);
216     x_len = va_arg(ap, unsigned int);
217
218     argv[i] = silc_calloc(x_len + 1, sizeof(unsigned char));
219     memcpy(argv[i], x, x_len);
220     argv_lens[i] = x_len;
221     argv_types[i] = x_type;
222   }
223
224   buffer = silc_command_payload_encode(cmd, argc, argv, 
225                                        argv_lens, argv_types, ident);
226
227   for (i = 0; i < argc; i++)
228     silc_free(argv[i]);
229   silc_free(argv);
230   silc_free(argv_lens);
231   silc_free(argv_types);
232
233   return buffer;
234 }
235
236 /* Free's Command Payload */
237
238 void silc_command_free_payload(SilcCommandPayload payload)
239 {
240   if (payload) {
241     silc_argument_payload_free(payload->args);
242     silc_free(payload);
243   }
244 }
245
246 /* Returns command */
247
248 SilcCommand silc_command_get(SilcCommandPayload payload)
249 {
250   return payload->cmd;
251 }
252
253 /* Retuns arguments payload */
254
255 SilcArgumentPayload silc_command_get_args(SilcCommandPayload payload)
256 {
257   return payload->args;
258 }
259
260 /* Returns identifier */
261
262 unsigned short silc_command_get_ident(SilcCommandPayload payload)
263 {
264   return payload->ident;
265 }