Fixed topic annoucning, server signoff handling, added -D option,
[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_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 + 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], argv_lens[i]),
147                        SILC_STR_END);
148     silc_buffer_pull(buffer, 3 + argv_lens[i]);
149   }
150
151   silc_buffer_push(buffer, len);
152
153   return buffer;
154 }
155
156 /* Same as above but encode the buffer from SilcArgumentPayload structure
157    instead of raw data. */
158
159 SilcBuffer silc_argument_payload_encode_payload(SilcArgumentPayload payload)
160 {
161   SilcBuffer buffer;
162   SilcUInt32 len;
163   int i;
164
165   len = 0;
166   for (i = 0; i < payload->argc; i++)
167     len += 3 + payload->argv_lens[i];
168
169   buffer = silc_buffer_alloc_size(len);
170   if (!buffer)
171     return NULL;
172
173   /* Put arguments */
174   for (i = 0; i < payload->argc; i++) {
175     silc_buffer_format(buffer,
176                        SILC_STR_UI_SHORT(payload->argv_lens[i]),
177                        SILC_STR_UI_CHAR(payload->argv_types[i]),
178                        SILC_STR_UI_XNSTRING(payload->argv[i], 
179                                             payload->argv_lens[i]),
180                        SILC_STR_END);
181     silc_buffer_pull(buffer, 3 + payload->argv_lens[i]);
182   }
183
184   silc_buffer_push(buffer, len);
185
186   return buffer;
187 }
188
189 /* Frees Argument Payload */
190
191 void silc_argument_payload_free(SilcArgumentPayload payload)
192 {
193   int i;
194
195   if (payload) {
196     for (i = 0; i < payload->argc; i++)
197       silc_free(payload->argv[i]);
198
199     silc_free(payload->argv);
200     silc_free(payload->argv_lens);
201     silc_free(payload->argv_types);
202     silc_free(payload);
203   }
204 }
205
206 /* Returns number of arguments in payload */
207
208 SilcUInt32 silc_argument_get_arg_num(SilcArgumentPayload payload)
209 {
210   return payload ? payload->argc : 0;
211 }
212
213 /* Returns first argument from payload. */
214
215 unsigned char *silc_argument_get_first_arg(SilcArgumentPayload payload,
216                                            SilcUInt32 *ret_len)
217 {
218   if (!payload)
219     return NULL;
220
221   payload->pos = 0;
222
223   if (ret_len)
224     *ret_len = payload->argv_lens[payload->pos];
225
226   return payload->argv[payload->pos++];
227 }
228
229 /* Returns next argument from payload or NULL if no more arguments. */
230
231 unsigned char *silc_argument_get_next_arg(SilcArgumentPayload payload,
232                                           SilcUInt32 *ret_len)
233 {
234   if (!payload)
235     return NULL;
236
237   if (payload->pos >= payload->argc)
238     return NULL;
239
240   if (ret_len)
241     *ret_len = payload->argv_lens[payload->pos];
242
243   return payload->argv[payload->pos++];
244 }
245
246 /* Returns argument which type is `type'. */
247
248 unsigned char *silc_argument_get_arg_type(SilcArgumentPayload payload,
249                                           SilcUInt32 type,
250                                           SilcUInt32 *ret_len)
251 {
252   int i;
253
254   if (!payload)
255     return NULL;
256
257   for (i = 0; i < payload->argc; i++)
258     if (payload->argv_types[i] == type)
259       break;
260
261   if (i >= payload->argc)
262     return NULL;
263
264   if (ret_len)
265     *ret_len = payload->argv_lens[i];
266
267   return payload->argv[i];
268 }