1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
|
/*
* Copyright (C) 2010-2011 Mamadou Diop.
*
* Contact: Mamadou Diop <diopmamadou(at)doubango[dot]org>
*
* This file is part of Open Source Doubango Framework.
*
* DOUBANGO is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DOUBANGO is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DOUBANGO.
*
*/
/**@file tsk_params.c
* @brief SIP/MSRP/XCAP Parameters parser.
*
* @author Mamadou Diop <diopmamadou(at)doubango[dot]org>
*
*/
#include "tsk_params.h"
#include "tsk_memory.h"
#include "tsk_string.h"
#include "tsk_common.h"
#include "tsk_debug.h"
#include <string.h>
/**@defgroup tsk_params_group SIP/MSRP/XCAP Parameters parser.
*/
/* Predicate function used to find a parameter by name (case-insensitive).
*/
static int pred_find_param_by_name(const tsk_list_item_t *item, const void *name)
{
if(item && item->data){
tsk_param_t *param = (tsk_param_t*)item->data;
return tsk_stricmp(param->name, (const char*)name);
}
return -1;
}
/**@ingroup tsk_params_group
*/
tsk_param_t* tsk_param_create(const char* name, const char* value)
{
return (tsk_param_t*)tsk_object_new(TSK_PARAM_VA_ARGS(name, value));
}
/**@ingroup tsk_params_group
*/
tsk_param_t* tsk_param_create_null()
{
return tsk_param_create(tsk_null, tsk_null);
}
/**@ingroup tsk_params_group
* Converts a key-value-pair string (kvp) to @ref tsk_param_t object.
* @param line The kvp (e.g. 'branch=z9hG4bK652hsge') string to parse.
* @param size The size (length) of the kvp string.
* @retval @ref tsk_param_t object.
*/
tsk_param_t *tsk_params_parse_param(const char* line, tsk_size_t size)
{
if(line && size){
const char* start = line;
const char* end = (line + size);
const char* equal = strstr(line, "=");
tsk_param_t *param = tsk_param_create_null();
if (param && equal && equal<end) {
if ((param->name = (char*)tsk_calloc((tsk_size_t)((equal - start) + 1), sizeof(const char)))) {
memcpy(param->name, start, (equal - start));
}
if ((param->value = (char*)tsk_calloc((tsk_size_t)((end - equal - 1) + 1), sizeof(const char)))) {
memcpy(param->value, equal + 1, (end - equal - 1));
}
}
else if (param) {
if ((param->name = (char*)tsk_calloc((tsk_size_t)((end - start) + 1), sizeof(const char)))) {
memcpy(param->name, start, (end - start));
}
}
return param;
}
return tsk_null;
}
/**@ingroup tsk_params_group
* Checks if the supplied list of parameters contains a parameter named @a name (case-insensitive).
* @param self The list of parameters into which to search.
* @param name The name of the parameter to search.
* @retval @ref tsk_true if the parameter exist and @ref tsk_false otherwise.
*/
tsk_bool_t tsk_params_have_param(const tsk_params_L_t *self, const char* name)
{
if(self){
if(tsk_list_find_item_by_pred(self, pred_find_param_by_name, name)){
return tsk_true;
}
}
else{
TSK_DEBUG_ERROR("Invalid parameter");
}
return tsk_false;
}
/**@ingroup tsk_params_group
* Adds a parameter to the list of parameters. If the parameter already exist(case-insensitive), then it's value will be updated.
* @param self The destination list.
* @param name The name of the parameter to add.
* @param value The value of the parameter to add.
* @retval Zero if succeed and -1 otherwise.
*/
int tsk_params_add_param(tsk_params_L_t **self, const char* name, const char* value)
{
tsk_param_t *param;
if(!self || !name) {
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
if(!*self){
*self = tsk_list_create();
}
if((param = (tsk_param_t*)tsk_params_get_param_by_name(*self, name))){
tsk_strupdate(¶m->value, value); /* Already exist ==> update the value. */
}
else{
param = tsk_param_create(name, value);
tsk_list_push_back_data(*self, (void**)¶m);
}
return 0;
}
int tsk_params_add_param_2(tsk_params_L_t **self, const tsk_param_t* param)
{
if(!self || !param || !param){
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
return tsk_params_add_param(self, param->name, param->value);
}
int tsk_params_add_param_3(tsk_params_L_t **self, const char* name, int64_t value)
{
tsk_istr_t value_str;
tsk_itoa(value, &value_str);
return tsk_params_add_param(self, name, value_str);
}
/**@ingroup tsk_params_group
* Removes a parameter from the list of parameters.
* @param self The list from which to remove the parameter.
* @param name The name(case-insensitive) of the parameter to remove.
* @retval Zero if succeed and -1 otherwise.
*/
int tsk_params_remove_param(tsk_params_L_t *self, const char* name)
{
if(self){
tsk_list_remove_item_by_pred(self, pred_find_param_by_name, name);
return 0;
}
else{
TSK_DEBUG_ERROR("Invalid parameter");
return -1;
}
}
/**@ingroup tsk_params_group
* Gets a parameter from the list of parameters by name.
* @param self The source list.
* @param name The name(case-insensitive) of the parameter to retrieve.
* @retval @ref tsk_param_t if succeed and @ref tsk_null otherwise.
*/
const tsk_param_t *tsk_params_get_param_by_name(const tsk_params_L_t *self, const char* name)
{
if(self){
const tsk_list_item_t *item_const = tsk_list_find_item_by_pred(self, pred_find_param_by_name, name);
if(item_const){
return (const tsk_param_t*)item_const->data;
}
}
else{
TSK_DEBUG_ERROR("Invalid parameter");
}
return tsk_null;
}
/**@ingroup tsk_params_group
* Gets the value of a parameter.
* @param self The source list.
* @param name The name(case-insensitive) of the parameter to retrieve.
* @retval The value of the parameter if succeed and NULL otherwise.
*/
const char *tsk_params_get_param_value(const tsk_params_L_t *self, const char* name)
{
if(self && name){
const tsk_list_item_t *item_const = tsk_list_find_item_by_pred(self, pred_find_param_by_name, name);
if(item_const && item_const->data){
return ((const tsk_param_t *)item_const->data)->value;
}
}
else{
TSK_DEBUG_ERROR("Invalid parameter");
}
return tsk_null;
}
/**@ingroup tsk_params_group
* Gets the value of a parameter.
* @param self The source list.
* @param name The name(case-insensitive) of the parameter to retrieve.
* @retval The value of the parameter if succeed and -1 otherwise.
*/
int tsk_params_get_param_value_as_int(const tsk_params_L_t *self, const char* name)
{
const char *value = tsk_params_get_param_value(self, name);
return value ? atoi(value) : -1;
}
/**@ingroup tsk_params_group
* Serializes a @ref tsk_param_t object.
* @param param The parameter to serialize.
* @param output The output buffer.
* @retval Zero if succeed and -1 otherwise.
*/
int tsk_params_param_tostring(const tsk_param_t *param, tsk_buffer_t* output)
{
if(param){
return tsk_buffer_append_2(output, param->value?"%s=%s":"%s", param->name, param->value);
}
return -1;
}
/**@ingroup tsk_params_group
* Serializes a @ref tsk_params_L_t object.
* @param self The list of parameters to serialize.
* @param separator The character to use as separator between params.
* @param output The output buffer.
* @retval Zero if succeed and non-zero error code otherwise.
*/
int tsk_params_tostring(const tsk_params_L_t *self, const char separator, tsk_buffer_t* output)
{
int ret = -1;
if(self){
tsk_list_item_t *item;
ret = 0; // for empty lists
tsk_list_foreach(item, self){
tsk_param_t* param = (tsk_param_t*)item->data;
//tsk_params_param_tostring(param, output);
if(TSK_LIST_IS_FIRST(self, item)){
if((ret = tsk_buffer_append_2(output, param->value?"%s=%s":"%s", param->name, param->value))){
goto bail;
}
}
else{
if((ret = tsk_buffer_append_2(output, param->value?"%c%s=%s":"%c%s", separator, param->name, param->value))){
goto bail;
}
}
}
}
bail:
return ret;
}
/**@ingroup tsk_params_group
*/
tsk_params_L_t* tsk_params_fromstring(const char* string, const char* separator, tsk_bool_t trim)
{
tsk_params_L_t* params = tsk_null;
tsk_param_t* param;
int i = 0, index;
tsk_size_t size = tsk_strlen(string);
#define PUSH_PARAM() \
if(!params){ \
params = tsk_list_create(); \
} \
if(trim){ \
if(param->name){ \
tsk_strtrim(¶m->name); \
} \
if(param->value){ \
tsk_strtrim(¶m->value); \
} \
} \
tsk_list_push_back_data(params, (void**)¶m);
while((index = tsk_strindexOf((string + i), (size - i), separator)) != -1){
if((param = tsk_params_parse_param((string + i), index))){
PUSH_PARAM();
}
i += (index + 1);
}
// last one
if(i<(int)size){
if((param = tsk_params_parse_param((string + i), (size - i)))){
PUSH_PARAM();
}
}
return params;
}
//=================================================================================================
// param object definition
//
static tsk_object_t* tsk_param_ctor(tsk_object_t* self, va_list * app)
{
tsk_param_t *param = (tsk_param_t*)self;
if(param){
const char* name = va_arg(*app, const char *);
const char* value = va_arg(*app, const char *);
if(!tsk_strnullORempty(name)) {
param->name = tsk_strdup(name);
if(!tsk_strnullORempty(value)) {
param->value = tsk_strdup(value);
}
}
}
return self;
}
static tsk_object_t* tsk_param_dtor(tsk_object_t* self)
{
tsk_param_t *param = (tsk_param_t*)self;
if(param){
TSK_FREE(param->name);
TSK_FREE(param->value);
}
return self;
}
static const tsk_object_def_t tsk_param_def_s =
{
sizeof(tsk_param_t),
tsk_param_ctor,
tsk_param_dtor,
tsk_null,
};
const tsk_object_def_t *tsk_param_def_t = &tsk_param_def_s;
|