1 /*
2 
3   silcnotify.c
4 
5   Author: Pekka Riikonen <priikone@silcnet.org>
6 
7   Copyright (C) 2000 - 2007 Pekka Riikonen
8 
9   The contents of this file are subject to one of the Licenses specified
10   in the COPYING file;  You may not use this file except in compliance
11   with the License.
12 
13   The software distributed under the License is distributed on an "AS IS"
14   basis, in the hope that it will be useful, but WITHOUT WARRANTY OF ANY
15   KIND, either expressed or implied.  See the COPYING file for more
16   information.
17 
18 */
19 /* $Id$ */
20 
21 #include "silc.h"
22 #include "silcnotify.h"
23 
24 /******************************************************************************
25 
26                                Notify Payload
27 
28 ******************************************************************************/
29 
30 struct SilcNotifyPayloadStruct {
31   SilcNotifyType type;
32   unsigned char argc;
33   SilcArgumentPayload args;
34 };
35 
36 /* Parse notify payload buffer and return data into payload structure */
37 
silc_notify_payload_parse(const unsigned char * payload,SilcUInt32 payload_len)38 SilcNotifyPayload silc_notify_payload_parse(const unsigned char *payload,
39 					    SilcUInt32 payload_len)
40 {
41   SilcBufferStruct buffer;
42   SilcNotifyPayload newp;
43   SilcUInt16 len;
44   int ret;
45 
46   SILC_LOG_DEBUG(("Parsing Notify payload"));
47 
48   silc_buffer_set(&buffer, (unsigned char *)payload, payload_len);
49   newp = silc_calloc(1, sizeof(*newp));
50   if (!newp)
51     return NULL;
52 
53   ret = silc_buffer_unformat(&buffer,
54 			     SILC_STR_UI_SHORT(&newp->type),
55 			     SILC_STR_UI_SHORT(&len),
56 			     SILC_STR_UI_CHAR(&newp->argc),
57 			     SILC_STR_END);
58   if (ret == -1)
59     goto err;
60 
61   if (len > silc_buffer_len(&buffer))
62     goto err;
63 
64   if (newp->argc) {
65     silc_buffer_pull(&buffer, 5);
66     newp->args = silc_argument_payload_parse(buffer.data,
67 					     silc_buffer_len(&buffer),
68 					     newp->argc);
69     if (!newp->args)
70       goto err;
71     silc_buffer_push(&buffer, 5);
72   }
73 
74   return newp;
75 
76  err:
77   silc_free(newp);
78   return NULL;
79 }
80 
81 /* Encode notify payload with variable argument list. If `argc' is > 0
82    argument payloads will be associated to the notify payload. Variable
83    arguments must be {usigned char *, SilcUInt32 (len)}. */
84 
silc_notify_payload_encode(SilcNotifyType type,SilcUInt32 argc,va_list ap)85 SilcBuffer silc_notify_payload_encode(SilcNotifyType type, SilcUInt32 argc,
86 				      va_list ap)
87 {
88   SilcBuffer buffer;
89   SilcBuffer args = NULL;
90   unsigned char **argv;
91   SilcUInt32 *argv_lens = NULL, *argv_types = NULL;
92   unsigned char *x;
93   SilcUInt32 x_len, len = 0;
94   int i, k = 0;
95 
96   if (argc) {
97     argv = silc_calloc(argc, sizeof(unsigned char *));
98     if (!argv)
99       return NULL;
100     argv_lens = silc_calloc(argc, sizeof(SilcUInt32));
101     if (!argv_lens) {
102       silc_free(argv);
103       return NULL;
104     }
105     argv_types = silc_calloc(argc, sizeof(SilcUInt32));
106     if (!argv_types) {
107       silc_free(argv_lens);
108       silc_free(argv);
109       return NULL;
110     }
111 
112     for (i = 0, k = 0; i < argc; i++) {
113       x = va_arg(ap, unsigned char *);
114       x_len = va_arg(ap, SilcUInt32);
115 
116       if (!x || !x_len)
117 	continue;
118 
119       argv[k] = silc_memdup(x, x_len);
120       if (!argv[k])
121 	return NULL;
122       argv_lens[k] = x_len;
123       argv_types[k] = i + 1;
124       k++;
125     }
126 
127     args = silc_argument_payload_encode(k, argv, argv_lens, argv_types);
128     len = silc_buffer_len(args);
129 
130     for (i = 0; i < k; i++)
131       silc_free(argv[i]);
132     silc_free(argv);
133     silc_free(argv_lens);
134     silc_free(argv_types);
135   }
136 
137   len += 5;
138   buffer = silc_buffer_alloc_size(len);
139   if (!buffer)
140     return NULL;
141   silc_buffer_format(buffer,
142 		     SILC_STR_UI_SHORT(type),
143 		     SILC_STR_UI_SHORT(len),
144 		     SILC_STR_UI_CHAR(k),
145 		     SILC_STR_END);
146 
147   if (k) {
148     silc_buffer_format(buffer,
149 		       SILC_STR_OFFSET(5),
150 		       SILC_STR_DATA(args->data, silc_buffer_len(args)),
151 		       SILC_STR_END);
152     silc_buffer_free(args);
153   }
154 
155   return buffer;
156 }
157 
158 /* Same as above but takes argument from the `args' Argument Payload. */
159 
silc_notify_payload_encode_args(SilcNotifyType type,SilcUInt32 argc,SilcBuffer args)160 SilcBuffer silc_notify_payload_encode_args(SilcNotifyType type,
161 					   SilcUInt32 argc,
162 					   SilcBuffer args)
163 {
164   SilcBuffer buffer;
165   SilcUInt32 len;
166 
167   len = 5 + (args ? silc_buffer_len(args) : 0);
168   buffer = silc_buffer_alloc_size(len);
169   if (!buffer)
170     return NULL;
171   silc_buffer_format(buffer,
172 		     SILC_STR_UI_SHORT(type),
173 		     SILC_STR_UI_SHORT(len),
174 		     SILC_STR_UI_CHAR(argc),
175 		     SILC_STR_END);
176 
177   if (args)
178     silc_buffer_format(buffer,
179 		       SILC_STR_OFFSET(5),
180 		       SILC_STR_DATA(args->data, silc_buffer_len(args)),
181 		       SILC_STR_END);
182 
183   return buffer;
184 }
185 
186 /* Frees notify payload */
187 
silc_notify_payload_free(SilcNotifyPayload payload)188 void silc_notify_payload_free(SilcNotifyPayload payload)
189 {
190   if (payload) {
191     silc_argument_payload_free(payload->args);
192     silc_free(payload);
193   }
194 }
195 
196 /* Return notify type */
197 
silc_notify_get_type(SilcNotifyPayload payload)198 SilcNotifyType silc_notify_get_type(SilcNotifyPayload payload)
199 {
200   return payload->type;
201 }
202 
203 /* Return argument nums */
204 
silc_notify_get_arg_num(SilcNotifyPayload payload)205 SilcUInt32 silc_notify_get_arg_num(SilcNotifyPayload payload)
206 {
207   return payload->argc;
208 }
209 
210 /* Return argument payload */
211 
silc_notify_get_args(SilcNotifyPayload payload)212 SilcArgumentPayload silc_notify_get_args(SilcNotifyPayload payload)
213 {
214   return payload->args;
215 }
216