1 /*======================================================================
2  FILE: icalderivedparameters.{c,h}
3  CREATOR: eric 09 May 1999
4 
5  (C) COPYRIGHT 2000, Eric Busboom <eric@civicknowledge.com>
6 
7  This library is free software; you can redistribute it and/or modify
8  it under the terms of either:
9 
10     The LGPL as published by the Free Software Foundation, version
11     2.1, available at: https://www.gnu.org/licenses/lgpl-2.1.html
12 
13  Or:
14 
15     The Mozilla Public License Version 2.0. You may obtain a copy of
16     the License at https://www.mozilla.org/MPL/
17 
18   The original code is icalderivedparameters.{c,h}
19 
20  Contributions from:
21     Graham Davison <g.m.davison@computer.org>
22 ======================================================================*/
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 
27 #include "icalparameter.h"
28 #include "icalparameterimpl.h"
29 #include "icalerror.h"
30 #include "icalmemory.h"
31 
32 #include <errno.h>
33 #include <stdlib.h>
34 
icalparameter_new_impl(icalparameter_kind kind)35 LIBICAL_ICAL_EXPORT struct icalparameter_impl *icalparameter_new_impl(icalparameter_kind kind)
36 {
37     struct icalparameter_impl *v;
38 
39     if ((v = (struct icalparameter_impl *)malloc(sizeof(struct icalparameter_impl))) == 0) {
40         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
41         return 0;
42     }
43 
44     memset(v, 0, sizeof(struct icalparameter_impl));
45 
46     strcpy(v->id, "para");
47 
48     v->kind = kind;
49 
50     return v;
51 }
52 
icalparameter_new(icalparameter_kind kind)53 icalparameter *icalparameter_new(icalparameter_kind kind)
54 {
55     struct icalparameter_impl *v = icalparameter_new_impl(kind);
56 
57     return (icalparameter *) v;
58 }
59 
icalparameter_free(icalparameter * param)60 void icalparameter_free(icalparameter *param)
61 {
62 /*  Comment out the following as it always triggers, even when parameter is non-zero
63     icalerror_check_arg_rv((parameter==0),"parameter");*/
64 
65     if (param->parent != 0) {
66         return;
67     }
68 
69     if (param->string != 0) {
70         free((void *)param->string);
71     }
72 
73     if (param->x_name != 0) {
74         free((void *)param->x_name);
75     }
76 
77     memset(param, 0, sizeof(icalparameter));
78 
79     param->parent = 0;
80     param->id[0] = 'X';
81     free(param);
82 }
83 
icalparameter_new_clone(icalparameter * old)84 icalparameter *icalparameter_new_clone(icalparameter *old)
85 {
86     struct icalparameter_impl *new;
87 
88     icalerror_check_arg_rz((old != 0), "param");
89 
90     new = icalparameter_new_impl(old->kind);
91 
92     if (new == 0) {
93         return 0;
94     }
95 
96     memcpy(new, old, sizeof(struct icalparameter_impl));
97 
98     if (old->string != 0) {
99         new->string = icalmemory_strdup(old->string);
100         if (new->string == 0) {
101             new->parent = 0;
102             icalparameter_free(new);
103             return 0;
104         }
105     }
106 
107     if (old->x_name != 0) {
108         new->x_name = icalmemory_strdup(old->x_name);
109         if (new->x_name == 0) {
110             new->parent = 0;
111             icalparameter_free(new);
112             return 0;
113         }
114     }
115 
116     return new;
117 }
118 
icalparameter_new_from_string(const char * str)119 icalparameter *icalparameter_new_from_string(const char *str)
120 {
121     char *eq;
122     char *cpy;
123     icalparameter_kind kind;
124     icalparameter *param;
125 
126     icalerror_check_arg_rz(str != 0, "str");
127 
128     cpy = icalmemory_strdup(str);
129 
130     if (cpy == 0) {
131         icalerror_set_errno(ICAL_NEWFAILED_ERROR);
132         return 0;
133     }
134 
135     eq = strchr(cpy, '=');
136 
137     if (eq == 0) {
138         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
139         free(cpy);
140         return 0;
141     }
142 
143     *eq = '\0';
144 
145     eq++;
146 
147     kind = icalparameter_string_to_kind(cpy);
148 
149     if (kind == ICAL_NO_PARAMETER) {
150         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
151         free(cpy);
152         return 0;
153     }
154 
155     param = icalparameter_new_from_value_string(kind, eq);
156 
157     if (kind == ICAL_X_PARAMETER) {
158         icalparameter_set_xname(param, cpy);
159     } else if (kind == ICAL_IANA_PARAMETER) {
160         icalparameter_set_iana_name(param, cpy);
161     }
162 
163     free(cpy);
164 
165     return param;
166 }
167 
icalparameter_as_ical_string(icalparameter * param)168 char *icalparameter_as_ical_string(icalparameter *param)
169 {
170     char *buf;
171 
172     buf = icalparameter_as_ical_string_r(param);
173     icalmemory_add_tmp_buffer(buf);
174     return buf;
175 }
176 
177 /*
178  * checks whether this character is allowed in a (Q)SAFE-CHAR
179  *
180  * QSAFE-CHAR   = WSP / %x21 / %x23-7E / NON-US-ASCII
181  * ; any character except CTLs and DQUOTE
182  * SAFE-CHAR    = WSP / %x21 / %x23-2B / %x2D-39 / %x3C-7E / NON-US-ASCII
183  * ; any character except CTLs, DQUOTE. ";", ":", ","
184  * WSP      = SPACE / HTAB
185  * NON-US-ASCII       = %x80-F8
186  * ; Use restricted by charset parameter
187  * ; on outer MIME object (UTF-8 preferred)
188  */
icalparameter_is_safe_char(unsigned char character,int quoted)189 static int icalparameter_is_safe_char(unsigned char character, int quoted)
190 {
191     if (character == ' ' || character == '\t' || character == '!' ||
192         (character >= 0x80 && character <= 0xF8)) {
193         return 1;
194     }
195 
196     if (quoted && character >= 0x23 && character <= 0x7e) {
197         return 1;
198     }
199     else if (!quoted &&
200              ((character >= 0x23 && character <= 0x2b) ||
201               (character >= 0x2d && character <= 0x39) ||
202               (character >= 0x3c && character <= 0x7e))) {
203         return 1;
204     }
205 
206     return 0;
207 }
208 
209  /**
210  * Appends the parameter value to the buffer, encoding per RFC 6868
211  * and filtering out those characters not permitted by the specifications
212  *
213  * paramtext    = *SAFE-CHAR
214  * quoted-string= DQUOTE *QSAFE-CHAR DQUOTE
215  */
icalparameter_append_encoded_value(char ** buf,char ** buf_ptr,size_t * buf_size,const char * value)216 static void icalparameter_append_encoded_value(char **buf, char **buf_ptr,
217                                                size_t *buf_size, const char *value)
218 {
219     int qm = 0;
220     const char *p;
221 
222     /* Encapsulate the property in quotes if necessary */
223     if (strpbrk(value, ";:,") != 0) {
224         icalmemory_append_char(buf, buf_ptr, buf_size, '"');
225         qm = 1;
226     }
227 
228     /* Copy the parameter value */
229     for (p = value; *p; p++) {
230         if (icalparameter_is_safe_char((unsigned char)*p, qm)) {
231             icalmemory_append_char(buf, buf_ptr, buf_size, *p);
232         } else {
233             /* Encode unsafe characters per RFC6868, otherwise replace with SP */
234             switch (*p) {
235             case '\n':
236                 icalmemory_append_string(buf, buf_ptr, buf_size, "^n");
237                 break;
238 
239             case '^':
240                 icalmemory_append_string(buf, buf_ptr, buf_size, "^^");
241                 break;
242 
243             case '"':
244                 icalmemory_append_string(buf, buf_ptr, buf_size, "^'");
245                 break;
246 
247             default:
248                 icalmemory_append_char(buf, buf_ptr, buf_size, ' ');
249                 break;
250             }
251         }
252     }
253 
254     if (qm == 1) {
255         icalmemory_append_char(buf, buf_ptr, buf_size, '"');
256     }
257 }
258 
259 /**
260  * Return a string representation of the parameter according to RFC5445/RFC6868.
261  *
262  * param        = param-name "=" param-value
263  * param-name   = iana-token / x-token
264  * param-value  = paramtext /quoted-string
265  * paramtext    = *SAFE-CHAR
266  * quoted-string= DQUOTE *QSAFE-CHAR DQUOTE
267  * QSAFE-CHAR   = any character except CTLs and DQUOTE
268  * SAFE-CHAR    = any character except CTLs, DQUOTE. ";", ":", ","
269  */
icalparameter_as_ical_string_r(icalparameter * param)270 char *icalparameter_as_ical_string_r(icalparameter *param)
271 {
272     size_t buf_size = 1024;
273     char *buf;
274     char *buf_ptr;
275     const char *kind_string;
276 
277     icalerror_check_arg_rz((param != 0), "parameter");
278 
279     /* Create new buffer that we can append names, parameters and a
280      * value to, and reallocate as needed.
281      */
282 
283     buf = icalmemory_new_buffer(buf_size);
284     buf_ptr = buf;
285 
286     if (param->kind == ICAL_X_PARAMETER) {
287         icalmemory_append_string(&buf, &buf_ptr, &buf_size, icalparameter_get_xname(param));
288     } else if (param->kind == ICAL_IANA_PARAMETER) {
289         icalmemory_append_string(&buf, &buf_ptr, &buf_size, icalparameter_get_iana_name(param));
290     } else {
291 
292         kind_string = icalparameter_kind_to_string(param->kind);
293 
294         if (param->kind == ICAL_NO_PARAMETER ||
295             param->kind == ICAL_ANY_PARAMETER || kind_string == 0) {
296             icalerror_set_errno(ICAL_BADARG_ERROR);
297             free(buf);
298             return 0;
299         }
300 
301         /* Put the parameter name into the string */
302         icalmemory_append_string(&buf, &buf_ptr, &buf_size, kind_string);
303     }
304 
305     icalmemory_append_string(&buf, &buf_ptr, &buf_size, "=");
306 
307     if (param->string != 0) {
308         icalparameter_append_encoded_value(&buf, &buf_ptr, &buf_size, param->string);
309     } else if (param->data != 0) {
310         const char *str = icalparameter_enum_to_string(param->data);
311 
312         icalmemory_append_string(&buf, &buf_ptr, &buf_size, str);
313     } else {
314         icalerror_set_errno(ICAL_MALFORMEDDATA_ERROR);
315         free(buf);
316         return 0;
317     }
318 
319     return buf;
320 }
321 
icalparameter_isa(icalparameter * parameter)322 icalparameter_kind icalparameter_isa(icalparameter *parameter)
323 {
324     if (parameter == 0) {
325         return ICAL_NO_PARAMETER;
326     }
327 
328     return parameter->kind;
329 }
330 
icalparameter_isa_parameter(void * parameter)331 int icalparameter_isa_parameter(void *parameter)
332 {
333     struct icalparameter_impl *impl = (struct icalparameter_impl *)parameter;
334 
335     if (parameter == 0) {
336         return 0;
337     }
338 
339     if (strcmp(impl->id, "para") == 0) {
340         return 1;
341     } else {
342         return 0;
343     }
344 }
345 
icalparameter_set_xname(icalparameter * param,const char * v)346 void icalparameter_set_xname(icalparameter *param, const char *v)
347 {
348     icalerror_check_arg_rv((param != 0), "param");
349     icalerror_check_arg_rv((v != 0), "v");
350 
351     if (param->x_name != 0) {
352         free((void *)param->x_name);
353     }
354 
355     param->x_name = icalmemory_strdup(v);
356 
357     if (param->x_name == 0) {
358         errno = ENOMEM;
359     }
360 }
361 
icalparameter_get_xname(icalparameter * param)362 const char *icalparameter_get_xname(icalparameter *param)
363 {
364     icalerror_check_arg_rz((param != 0), "param");
365 
366     return param->x_name;
367 }
368 
icalparameter_set_xvalue(icalparameter * param,const char * v)369 void icalparameter_set_xvalue(icalparameter *param, const char *v)
370 {
371     icalerror_check_arg_rv((param != 0), "param");
372     icalerror_check_arg_rv((v != 0), "v");
373 
374     if (param->string != 0) {
375         free((void *)param->string);
376     }
377 
378     param->string = icalmemory_strdup(v);
379 
380     if (param->string == 0) {
381         errno = ENOMEM;
382     }
383 }
384 
icalparameter_get_xvalue(icalparameter * param)385 const char *icalparameter_get_xvalue(icalparameter *param)
386 {
387     icalerror_check_arg_rz((param != 0), "param");
388 
389     return param->string;
390 }
391 
icalparameter_set_iana_value(icalparameter * param,const char * v)392 void icalparameter_set_iana_value(icalparameter *param, const char *v)
393 {
394     icalparameter_set_xvalue(param, v);
395 }
396 
icalparameter_get_iana_value(icalparameter * param)397 const char *icalparameter_get_iana_value(icalparameter *param)
398 {
399     return icalparameter_get_xvalue(param);
400 }
401 
icalparameter_set_iana_name(icalparameter * param,const char * v)402 void icalparameter_set_iana_name(icalparameter *param, const char *v)
403 {
404     icalparameter_set_xname(param, v);
405 }
406 
icalparameter_get_iana_name(icalparameter * param)407 const char *icalparameter_get_iana_name(icalparameter *param)
408 {
409     return icalparameter_get_xname(param);
410 }
411 
icalparameter_set_parent(icalparameter * param,icalproperty * property)412 void icalparameter_set_parent(icalparameter *param, icalproperty *property)
413 {
414     icalerror_check_arg_rv((param != 0), "param");
415 
416     param->parent = property;
417 }
418 
icalparameter_get_parent(icalparameter * param)419 icalproperty *icalparameter_get_parent(icalparameter *param)
420 {
421     icalerror_check_arg_rz((param != 0), "param");
422 
423     return param->parent;
424 }
425 
426 /* returns 1 if parameters have same name in ICAL, otherwise 0 */
icalparameter_has_same_name(icalparameter * param1,icalparameter * param2)427 int icalparameter_has_same_name(icalparameter *param1, icalparameter *param2)
428 {
429     icalparameter_kind kind1;
430     icalparameter_kind kind2;
431     const char *name1;
432     const char *name2;
433 
434     icalerror_check_arg_rz((param1 != 0), "param1");
435     icalerror_check_arg_rz((param2 != 0), "param2");
436 
437     kind1 = icalparameter_isa(param1);
438     kind2 = icalparameter_isa(param2);
439 
440     if (kind1 != kind2)
441         return 0;
442 
443     if (kind1 == ICAL_X_PARAMETER) {
444         name1 = icalparameter_get_xname(param1);
445         name2 = icalparameter_get_xname(param2);
446         if (strcasecmp(name1, name2) != 0) {
447             return 0;
448         }
449     } else if (kind1 == ICAL_IANA_PARAMETER) {
450         name1 = icalparameter_get_iana_name(param1);
451         name2 = icalparameter_get_iana_name(param2);
452         if (strcasecmp(name1, name2) != 0) {
453             return 0;
454         }
455     }
456     return 1;
457 }
458 
459 /* Everything below this line is machine generated. Do not edit. */
460 /* ALTREP */
461