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