Added SILC Server library.
[silc.git] / lib / silccore / silcargument.c
1 /*
2
3   silcargument.c
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2001 - 2005 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 /* Implementation of Argument Payload routines */
20 /* $Id$ */
21
22 #include "silc.h"
23 #include "silcargument.h"
24
25 /******************************************************************************
26
27                              Argument Payload
28
29 ******************************************************************************/
30
31 struct SilcArgumentPayloadStruct {
32   SilcUInt32 argc;
33   unsigned char **argv;
34   SilcUInt32 *argv_lens;
35   SilcUInt32 *argv_types;
36   SilcUInt32 pos;
37 };
38
39 /* Parses arguments and returns them into Argument Payload structure. */
40
41 SilcArgumentPayload silc_argument_payload_parse(const unsigned char *payload,
42                                                 SilcUInt32 payload_len,
43                                                 SilcUInt32 argc)
44 {
45   SilcBufferStruct buffer;
46   SilcArgumentPayload newp;
47   SilcUInt16 p_len = 0;
48   unsigned char arg_num = 0;
49   unsigned char arg_type = 0;
50   SilcUInt32 pull_len = 0;
51   int i = 0, ret;
52
53   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
54   newp = silc_calloc(1, sizeof(*newp));
55   if (!newp)
56     return NULL;
57   newp->argv = silc_calloc(argc, sizeof(unsigned char *));
58   if (!newp->argv)
59     goto err;
60   newp->argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
61   if (!newp->argv_lens)
62     goto err;
63   newp->argv_types = silc_calloc(argc, sizeof(SilcUInt32));
64   if (!newp->argv_types)
65     goto err;
66
67   /* Get arguments */
68   arg_num = 1;
69   for (i = 0; i < argc; i++) {
70     ret = silc_buffer_unformat(&buffer,
71                                SILC_STR_UI_SHORT(&p_len),
72                                SILC_STR_UI_CHAR(&arg_type),
73                                SILC_STR_END);
74     if (ret == -1 || p_len > silc_buffer_len(&buffer) - 3)
75       goto err;
76
77     newp->argv_lens[i] = p_len;
78     newp->argv_types[i] = arg_type;
79
80     /* Get argument data */
81     silc_buffer_pull(&buffer, 3);
82     ret = silc_buffer_unformat(&buffer,
83                                SILC_STR_UI_XNSTRING_ALLOC(&newp->argv[i],
84                                                           p_len),
85                                SILC_STR_END);
86     if (ret == -1)
87       goto err;
88
89     silc_buffer_pull(&buffer, p_len);
90     pull_len += 3 + p_len;
91   }
92
93   if (silc_buffer_len(&buffer) != 0) {
94     SILC_LOG_DEBUG(("Malformed argument payload"));
95     goto err;
96   }
97
98   newp->argc = argc;
99   newp->pos = 0;
100
101   silc_buffer_push(&buffer, pull_len);
102
103   return newp;
104
105  err:
106   SILC_LOG_DEBUG(("Error parsing argument payload"));
107   if (i)
108     for (ret = 0; ret < i; ret++)
109       silc_free(newp->argv[ret]);
110
111   silc_free(newp->argv);
112   silc_free(newp->argv_lens);
113   silc_free(newp->argv_types);
114   silc_free(newp);
115
116   return NULL;
117 }
118
119 /* Encodes arguments in to Argument Paylods returning them to SilcBuffer. */
120
121 SilcBuffer silc_argument_payload_encode(SilcUInt32 argc,
122                                         unsigned char **argv,
123                                         SilcUInt32 *argv_lens,
124                                         SilcUInt32 *argv_types)
125 {
126   SilcBuffer buffer;
127   SilcUInt32 len;
128   int i;
129
130   len = 0;
131   for (i = 0; i < argc; i++)
132     len += 3 + (SilcUInt16)argv_lens[i];
133
134   buffer = silc_buffer_alloc_size(len);
135   if (!buffer)
136     return NULL;
137
138   /* Put arguments */
139   for (i = 0; i < argc; i++) {
140     silc_buffer_format(buffer,
141                        SILC_STR_UI_SHORT(argv_lens[i]),
142                        SILC_STR_UI_CHAR(argv_types[i]),
143                        SILC_STR_UI_XNSTRING(argv[i], (SilcUInt16)argv_lens[i]),
144                        SILC_STR_END);
145     silc_buffer_pull(buffer, 3 + (SilcUInt16)argv_lens[i]);
146   }
147
148   silc_buffer_push(buffer, len);
149
150   return buffer;
151 }
152
153 /* Encode one argument to buffer */
154
155 SilcBuffer silc_argument_payload_encode_one(SilcBuffer args,
156                                             unsigned char *arg,
157                                             SilcUInt32 arg_len,
158                                             SilcUInt32 arg_type)
159 {
160   SilcBuffer buffer = args;
161   SilcUInt32 len;
162
163   len = 3 + (SilcUInt16)arg_len;
164   buffer = silc_buffer_realloc(buffer,
165                                (buffer ? silc_buffer_truelen(buffer) + len : len));
166   if (!buffer)
167     return NULL;
168   silc_buffer_pull(buffer, silc_buffer_len(buffer));
169   silc_buffer_pull_tail(buffer, len);
170   silc_buffer_format(buffer,
171                      SILC_STR_UI_SHORT(arg_len),
172                      SILC_STR_UI_CHAR(arg_type),
173                      SILC_STR_UI_XNSTRING(arg, (SilcUInt16)arg_len),
174                      SILC_STR_END);
175   silc_buffer_push(buffer, buffer->data - buffer->head);
176
177   return buffer;
178 }
179
180 /* Same as above but encode the buffer from SilcArgumentPayload structure
181    instead of raw data. */
182
183 SilcBuffer silc_argument_payload_encode_payload(SilcArgumentPayload payload)
184 {
185   SilcBuffer buffer;
186   SilcUInt32 len;
187   int i;
188
189   len = 0;
190   for (i = 0; i < payload->argc; i++)
191     len += 3 + payload->argv_lens[i];
192
193   buffer = silc_buffer_alloc_size(len);
194   if (!buffer)
195     return NULL;
196
197   /* Put arguments */
198   for (i = 0; i < payload->argc; i++) {
199     silc_buffer_format(buffer,
200                        SILC_STR_UI_SHORT(payload->argv_lens[i]),
201                        SILC_STR_UI_CHAR(payload->argv_types[i]),
202                        SILC_STR_UI_XNSTRING(payload->argv[i],
203                                             payload->argv_lens[i]),
204                        SILC_STR_END);
205     silc_buffer_pull(buffer, 3 + payload->argv_lens[i]);
206   }
207
208   silc_buffer_push(buffer, len);
209
210   return buffer;
211 }
212
213 /* Frees Argument Payload */
214
215 void silc_argument_payload_free(SilcArgumentPayload payload)
216 {
217   int i;
218
219   if (payload) {
220     for (i = 0; i < payload->argc; i++)
221       silc_free(payload->argv[i]);
222
223     silc_free(payload->argv);
224     silc_free(payload->argv_lens);
225     silc_free(payload->argv_types);
226     silc_free(payload);
227   }
228 }
229
230 /* Returns number of arguments in payload */
231
232 SilcUInt32 silc_argument_get_arg_num(SilcArgumentPayload payload)
233 {
234   return payload ? payload->argc : 0;
235 }
236
237 /* Returns first argument from payload. */
238
239 unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload,
240                                            SilcUInt32 *type,
241                                            SilcUInt32 *ret_len)
242 {
243   if (!payload)
244     return NULL;
245
246   payload->pos = 0;
247
248   if (type)
249     *type = payload->argv_types[payload->pos];
250   if (ret_len)
251     *ret_len = payload->argv_lens[payload->pos];
252
253   return payload->argv[payload->pos++];
254 }
255
256 /* Returns next argument from payload or NULL if no more arguments. */
257
258 unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload,
259                                           SilcUInt32 *type,
260                                           SilcUInt32 *ret_len)
261 {
262   if (!payload)
263     return NULL;
264
265   if (payload->pos >= payload->argc)
266     return NULL;
267
268   if (type)
269     *type = payload->argv_types[payload->pos];
270   if (ret_len)
271     *ret_len = payload->argv_lens[payload->pos];
272
273   return payload->argv[payload->pos++];
274 }
275
276 /* Returns argument which type is `type'. */
277
278 unsigned char *silc_argument_get_arg_type(SilcArgumentPayload payload,
279                                           SilcUInt32 type,
280                                           SilcUInt32 *ret_len)
281 {
282   int i;
283
284   if (!payload)
285     return NULL;
286
287   for (i = 0; i < payload->argc; i++)
288     if (payload->argv_types[i] == type)
289       break;
290
291   if (i >= payload->argc)
292     return NULL;
293
294   if (ret_len)
295     *ret_len = payload->argv_lens[i];
296
297   return payload->argv[i];
298 }