updates.
[silc.git] / lib / silccore / silcargument.c
1 /*
2
3   silcargument.c 
4
5   Author: Pekka Riikonen <priikone@silcnet.org>
6
7   Copyright (C) 2001 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_LOG_DEBUG(("Parsing argument payload"));
54
55   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
56   newp = silc_calloc(1, sizeof(*newp));
57   if (!newp)
58     return NULL;
59   newp->argv = silc_calloc(argc, sizeof(unsigned char *));
60   if (!newp->argv)
61     goto err;
62   newp->argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
63   if (!newp->argv_lens)
64     goto err;
65   newp->argv_types = silc_calloc(argc, sizeof(SilcUInt32));
66   if (!newp->argv_types)
67     goto err;
68     
69   /* Get arguments */
70   arg_num = 1;
71   for (i = 0; i < argc; i++) {
72     ret = silc_buffer_unformat(&buffer,
73                                SILC_STR_UI_SHORT(&p_len),
74                                SILC_STR_UI_CHAR(&arg_type),
75                                SILC_STR_END);
76     if (ret == -1)
77       goto err;
78     
79     newp->argv_lens[i] = p_len;
80     newp->argv_types[i] = arg_type;
81
82     if (p_len > buffer.len - 3)
83       break;
84     
85     /* Get argument data */
86     silc_buffer_pull(&buffer, 3);
87     ret = silc_buffer_unformat(&buffer,
88                                SILC_STR_UI_XNSTRING_ALLOC(&newp->argv[i], 
89                                                           p_len),
90                                SILC_STR_END);
91     if (ret == -1)
92       goto err;
93
94     silc_buffer_pull(&buffer, p_len);
95     pull_len += 3 + p_len;
96   }
97
98   if (buffer.len != 0)
99     goto err;
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   if (i)
110     for (ret = 0; ret < i; ret++)
111       silc_free(newp->argv[ret]);
112
113   silc_free(newp->argv);
114   silc_free(newp->argv_lens);
115   silc_free(newp->argv_types);
116   silc_free(newp);
117
118   return NULL;
119 }
120
121 /* Encodes arguments in to Argument Paylods returning them to SilcBuffer. */
122
123 SilcBuffer silc_argument_payload_encode(SilcUInt32 argc,
124                                         unsigned char **argv,
125                                         SilcUInt32 *argv_lens,
126                                         SilcUInt32 *argv_types)
127 {
128   SilcBuffer buffer;
129   SilcUInt32 len;
130   int i;
131
132   SILC_LOG_DEBUG(("Encoding Argument payload"));
133
134   len = 0;
135   for (i = 0; i < argc; i++)
136     len += 3 + argv_lens[i];
137
138   buffer = silc_buffer_alloc_size(len);
139   if (!buffer)
140     return NULL;
141
142   /* Put arguments */
143   for (i = 0; i < argc; i++) {
144     silc_buffer_format(buffer,
145                        SILC_STR_UI_SHORT(argv_lens[i]),
146                        SILC_STR_UI_CHAR(argv_types[i]),
147                        SILC_STR_UI_XNSTRING(argv[i], argv_lens[i]),
148                        SILC_STR_END);
149     silc_buffer_pull(buffer, 3 + argv_lens[i]);
150   }
151
152   silc_buffer_push(buffer, len);
153
154   return buffer;
155 }
156
157 /* Same as above but encode the buffer from SilcArgumentPayload structure
158    instead of raw data. */
159
160 SilcBuffer silc_argument_payload_encode_payload(SilcArgumentPayload payload)
161 {
162   SilcBuffer buffer;
163   SilcUInt32 len;
164   int i;
165
166   SILC_LOG_DEBUG(("Encoding Argument payload"));
167
168   len = 0;
169   for (i = 0; i < payload->argc; i++)
170     len += 3 + payload->argv_lens[i];
171
172   buffer = silc_buffer_alloc_size(len);
173   if (!buffer)
174     return NULL;
175
176   /* Put arguments */
177   for (i = 0; i < payload->argc; i++) {
178     silc_buffer_format(buffer,
179                        SILC_STR_UI_SHORT(payload->argv_lens[i]),
180                        SILC_STR_UI_CHAR(payload->argv_types[i]),
181                        SILC_STR_UI_XNSTRING(payload->argv[i], 
182                                             payload->argv_lens[i]),
183                        SILC_STR_END);
184     silc_buffer_pull(buffer, 3 + payload->argv_lens[i]);
185   }
186
187   silc_buffer_push(buffer, len);
188
189   return buffer;
190 }
191
192 /* Frees Argument Payload */
193
194 void silc_argument_payload_free(SilcArgumentPayload payload)
195 {
196   int i;
197
198   if (payload) {
199     for (i = 0; i < payload->argc; i++)
200       silc_free(payload->argv[i]);
201
202     silc_free(payload->argv);
203     silc_free(payload->argv_lens);
204     silc_free(payload->argv_types);
205     silc_free(payload);
206   }
207 }
208
209 /* Returns number of arguments in payload */
210
211 SilcUInt32 silc_argument_get_arg_num(SilcArgumentPayload payload)
212 {
213   return payload ? payload->argc : 0;
214 }
215
216 /* Returns first argument from payload. */
217
218 unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload,
219                                            SilcUInt32 *ret_len)
220 {
221   if (!payload)
222     return NULL;
223
224   payload->pos = 0;
225
226   if (ret_len)
227     *ret_len = payload->argv_lens[payload->pos];
228
229   return payload->argv[payload->pos++];
230 }
231
232 /* Returns next argument from payload or NULL if no more arguments. */
233
234 unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload,
235                                           SilcUInt32 *ret_len)
236 {
237   if (!payload)
238     return NULL;
239
240   if (payload->pos >= payload->argc)
241     return NULL;
242
243   if (ret_len)
244     *ret_len = payload->argv_lens[payload->pos];
245
246   return payload->argv[payload->pos++];
247 }
248
249 /* Returns argument which type is `type'. */
250
251 unsigned char *silc_argument_get_arg_type(SilcArgumentPayload payload,
252                                           SilcUInt32 type,
253                                           SilcUInt32 *ret_len)
254 {
255   int i;
256
257   if (!payload)
258     return NULL;
259
260   for (i = 0; i < payload->argc; i++)
261     if (payload->argv_types[i] == type)
262       break;
263
264   if (i >= payload->argc)
265     return NULL;
266
267   if (ret_len)
268     *ret_len = payload->argv_lens[i];
269
270   return payload->argv[i];
271 }