Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
meta_data.c
Go to the documentation of this file.
1 /* ====================================================================
2  * The Kannel Software License, Version 1.0
3  *
4  * Copyright (c) 2001-2016 Kannel Group
5  * Copyright (c) 1998-2001 WapIT Ltd.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Kannel Group (http://www.kannel.org/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Kannel" and "Kannel Group" must not be used to
28  * endorse or promote products derived from this software without
29  * prior written permission. For written permission, please
30  * contact org@kannel.org.
31  *
32  * 5. Products derived from this software may not be called "Kannel",
33  * nor may "Kannel" appear in their name, without prior written
34  * permission of the Kannel Group.
35  *
36  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
37  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
38  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
39  * DISCLAIMED. IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS
40  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
41  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
42  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
43  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
44  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
45  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
46  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Kannel Group. For more information on
51  * the Kannel Group, please see <http://www.kannel.org/>.
52  *
53  * Portions of this software are based upon software originally written at
54  * WapIT Ltd., Helsinki, Finland for the Kannel project.
55  */
56 
57 /*
58  * meta_data.c
59  *
60  * Meta Data manipulation.
61  *
62  * Alexander Malysh <amalysh kannel.org>, 2007-2009
63  */
64 
65 #include "gwlib/gwlib.h"
66 #include "meta_data.h"
67 
68 
69 struct meta_data {
72  struct meta_data *next;
73 };
74 
75 
76 static struct meta_data *meta_data_create(void)
77 {
78  struct meta_data *ret;
79 
80  ret = gw_malloc(sizeof(*ret));
81  ret->group = NULL;
82  ret->values = NULL;
83  ret->next = NULL;
84 
85  return ret;
86 }
87 
88 
89 static void meta_data_destroy(struct meta_data *meta)
90 {
91  struct meta_data *next;
92 
93  if (meta == NULL)
94  return;
95 
96  do {
97  next = meta->next;
98  octstr_destroy(meta->group);
99  dict_destroy(meta->values);
100  gw_free(meta);
101  meta = next;
102  } while(meta != NULL);
103 }
104 
105 
106 /* format: ?group-name?key=value&key=value?group?... group, key, value are urlencoded */
107 static struct meta_data *meta_data_unpack(const Octstr *data)
108 {
109  struct meta_data *ret = NULL, *curr = NULL;
110  const char *str;
111  long pos;
112  Octstr *key = NULL;
113  int type, next_type;
114  long start, end;
115 
116  start = end = -1;
117  type = next_type = -1;
118  for (pos = 0, str = octstr_get_cstr(data); pos <= octstr_len(data); str++, pos++) {
119  switch(*str) {
120  case '?':
121  if (start == -1) { /* start of str */
122  start = pos;
123  type = 0;
124  } else if (type == 0) { /* end of group */
125  end = pos;
126  next_type = 1;
127  } else if (type == 2 && key != NULL) { /* end of value */
128  end = pos;
129  next_type = 0;
130  } else if (key == NULL) { /* start of next group without key and value */
131  start = pos;
132  type = 0;
133  } else {
134  /* FAILED */
135  error(0, "MDATA: Found '?' but not expected it end=%ld start=%ld type=%d.", end, start, type);
136  meta_data_destroy(ret);
137  octstr_destroy(key);
138  return NULL;
139  }
140  break;
141  case '=':
142  if (type == 1 && curr != NULL && key == NULL) { /* end of key */
143  end = pos;
144  next_type = 2;
145  } else {
146  /* FAILED */
147  error(0, "MDATA: Found '=' but not expected it end=%ld start=%ld type=%d.", end, start, type);
148  meta_data_destroy(ret);
149  octstr_destroy(key);
150  return NULL;
151  }
152  break;
153  case '&':
154  if (type == 2 && curr != NULL && key != NULL) { /* end of value */
155  end = pos;
156  next_type = 1;
157  } else if (type == 1 && key == NULL) { /* just & skip it */
158  start = pos;
159  } else {
160  /* FAILED */
161  error(0, "MDATA: Found '&' but not expected it end=%ld start=%ld type=%d.", end, start, type);
162  meta_data_destroy(ret);
163  octstr_destroy(key);
164  return NULL;
165  }
166  break;
167  case '\0':
168  if (type == 2) /* end of value */
169  end = pos;
170  break;
171  }
172  if (start >= 0 && end >= 0) {
173  Octstr *tmp;
174 
175  if (end - start - 1 == 0)
176  tmp = octstr_create("");
177  else
178  tmp = octstr_create_from_data(str - end + start + 1, end - start - 1);
179 
180  octstr_url_decode(tmp);
181 
182  switch(type) {
183  case 0: /* group */
184  if (curr == NULL) {
185  curr = gw_malloc(sizeof(*curr));
186  } else {
187  curr->next = gw_malloc(sizeof(*curr));
188  curr = curr->next;
189  }
190  curr->group = tmp;
191  tmp = NULL;
192  curr->values = dict_create(1024, octstr_destroy_item);
193  curr->next = NULL;
194  if (ret == NULL)
195  ret = curr;
196  debug("meta_data", 0, "new group created `%s'", octstr_get_cstr(curr->group));
197  break;
198  case 1: /* key */
199  key = tmp;
200  tmp = NULL;
201  break;
202  case 2: /* value */
203  debug("meta_data", 0, "group=`%s' key=`%s' value=`%s'", octstr_get_cstr(curr->group),
204  octstr_get_cstr(key), octstr_get_cstr(tmp));
205  dict_put(curr->values, key, tmp);
206  tmp = NULL;
207  octstr_destroy(key);
208  key = NULL;
209  break;
210  }
211  octstr_destroy(tmp);
212  type = next_type;
213  next_type = -1;
214  start = end;
215  end = -1;
216  }
217  }
218  octstr_destroy(key);
219 
220  return ret;
221 }
222 
223 
224 static int meta_data_pack(struct meta_data *mdata, Octstr *data)
225 {
226  List *l;
227  Octstr *tmp;
228 
229  if (mdata == NULL || data == NULL)
230  return -1;
231  /* clear data */
232  octstr_delete(data, 0, octstr_len(data));
233  do {
234  octstr_format_append(data, "?%E?", mdata->group);
235  l = dict_keys(mdata->values);
236  while(l != NULL && (tmp = gwlist_extract_first(l)) != NULL) {
237  octstr_format_append(data, "%E=%E&", tmp, dict_get(mdata->values, tmp));
238  octstr_destroy(tmp);
239  }
241  mdata = mdata->next;
242  } while(mdata != NULL);
243 
244  return 0;
245 }
246 
247 
248 Dict *meta_data_get_values(const Octstr *data, const char *group)
249 {
250  struct meta_data *mdata, *curr;
251  Dict *ret = NULL;
252 
253  if (data == NULL || group == NULL)
254  return NULL;
255 
256  mdata = meta_data_unpack(data);
257  if (mdata == NULL)
258  return NULL;
259  for (curr = mdata; curr != NULL; curr = curr->next) {
260  if (octstr_str_case_compare(curr->group, group) == 0) {
261  ret = curr->values;
262  curr->values = NULL;
263  break;
264  }
265  }
266 
267  meta_data_destroy(mdata);
268 
269  return ret;
270 }
271 
272 
273 int meta_data_set_values(Octstr *data, const Dict *dict, const char *group, int replace)
274 {
275  struct meta_data *mdata, *curr;
276  int i;
277  List *keys;
278  Octstr *key;
279 
280  if (data == NULL || group == NULL)
281  return -1;
282 
283  mdata = meta_data_unpack(data);
284  for (curr = mdata; curr != NULL; curr = curr->next) {
285  if (octstr_str_case_compare(curr->group, group) == 0) {
286  /*
287  * If we don't replace the values, copy the old Dict values to the new Dict
288  */
289  if (replace == 0) {
290  keys = dict_keys(curr->values);
291  while((key = gwlist_extract_first(keys)) != NULL) {
292  dict_put_once((Dict*)dict, key, octstr_duplicate(dict_get(curr->values, key)));
293  octstr_destroy(key);
294  }
296  }
297  dict_destroy(curr->values);
298  curr->values = (Dict*)dict;
299  break;
300  }
301  }
302 
303  if (curr == NULL) {
304  curr = meta_data_create();
305  curr->group = octstr_create(group);
306  curr->values = (Dict*)dict;
307  curr->next = NULL;
308  if (mdata == NULL) {
309  mdata = curr;
310  } else {
311  curr->next = mdata->next;
312  mdata->next = curr;
313  }
314  }
315  i = meta_data_pack(mdata, data);
316  curr->values = NULL;
317 
318  meta_data_destroy(mdata);
319 
320  return i;
321 }
322 
323 
324 int meta_data_set_value(Octstr *data, const char *group, const Octstr *key, const Octstr *value, int replace)
325 {
326  struct meta_data *mdata, *curr;
327  int ret = 0;
328 
329  if (data == NULL || group == NULL || value == NULL)
330  return -1;
331 
332  mdata = meta_data_unpack(data);
333  for (curr = mdata; curr != NULL; curr = curr->next) {
334  if (octstr_str_case_compare(curr->group, group) == 0)
335  break;
336  }
337  if (curr == NULL) {
338  /* group doesn't exists */
339  curr = meta_data_create();
340  curr->group = octstr_create(group);
342  if (mdata != NULL) {
343  curr->next = mdata->next;
344  mdata->next = curr;
345  } else {
346  mdata = curr;
347  }
348  }
349  if (replace) {
350  /* delete old value if any */
351  dict_put(curr->values, (Octstr *) key, NULL);
352  /* put new value */
353  dict_put(curr->values, (Octstr *) key, octstr_duplicate(value));
354  } else if (dict_get(curr->values, (Octstr *) key) == NULL) {
355  /* put new value */
356  dict_put(curr->values, (Octstr *) key, octstr_duplicate(value));
357  }
358 
359  /* pack it */
360  ret = meta_data_pack(mdata, data);
361 
362  meta_data_destroy(mdata);
363 
364  return ret;
365 }
366 
367 
368 Octstr *meta_data_get_value(Octstr *data, const char *group, const Octstr *key)
369 {
370  struct meta_data *mdata, *curr;
371  Octstr *ret = NULL;
372 
373  if (data == NULL || group == NULL || key == NULL)
374  return NULL;
375 
376  mdata = meta_data_unpack(data);
377  if (mdata == NULL)
378  return NULL;
379  for (curr = mdata; curr != NULL; curr = curr->next) {
380  if (octstr_str_case_compare(curr->group, group) == 0) {
381  ret = dict_remove(curr->values, (Octstr *) key);
382  break;
383  }
384  }
385 
386  meta_data_destroy(mdata);
387 
388  return ret;
389 }
390 
391 
392 Octstr *meta_data_merge(const Octstr *data, const Octstr *new_data, int replace)
393 {
394  Octstr *ret = NULL;
395  struct meta_data *mdata, *new_mdata, *new_curr, *curr;
396 
397  if (octstr_len(data) < 1)
398  return octstr_duplicate(new_data);
399  if (octstr_len(new_data) < 1)
400  return octstr_duplicate(data);
401 
402  mdata = meta_data_unpack(data);
403  if (mdata == NULL) {
404  error(0, "meta_data_merge: Unable to parse data `%s'", octstr_get_cstr(data));
405  return octstr_duplicate(new_data);
406  }
407  new_mdata = meta_data_unpack(new_data);
408  if (new_mdata == NULL) {
409  meta_data_destroy(mdata);
410  error(0, "meta_data_merge: Unable to parse data `%s'", octstr_get_cstr(new_data));
411  return octstr_duplicate(data);
412  }
413  for (new_curr = new_mdata; new_curr != NULL; new_curr = new_curr->next) {
414  for (curr = mdata; curr != NULL; curr = curr->next) {
415  /* check group name */
416  if (octstr_compare(curr->group, new_curr->group) == 0) {
417  /* match */
418  List *keys;
419  Octstr *key;
420 
421  keys = dict_keys(new_curr->values);
422  while((key = gwlist_consume(keys)) != NULL) {
423  if (replace == 0) {
424  dict_put_once(curr->values, key, octstr_duplicate(dict_get(new_curr->values, key)));
425  } else {
426  /* remove if any */
427  dict_put(curr->values, key, NULL);
428  dict_put(curr->values, key, octstr_duplicate(dict_get(new_curr->values, key)));
429  }
430  octstr_destroy(key);
431  }
433  break; /* we found mdata group */
434  } else if (curr->next == NULL) {
435  /* do not match and this is last value -> add group */
436  curr->next = meta_data_create();
437  curr->next->group = octstr_duplicate(new_curr->group);
439  }
440  }
441  }
442  ret = octstr_create("");
443  if (meta_data_pack(mdata, ret) == -1) {
444  octstr_destroy(ret);
445  ret = NULL;
446  }
447  meta_data_destroy(new_mdata);
448  meta_data_destroy(mdata);
449 
450  return ret;
451 }
Dict * dict_create(long size_hint, void(*destroy_value)(void *))
Definition: dict.c:192
void error(int err, const char *fmt,...)
Definition: log.c:612
Dict * meta_data_get_values(const Octstr *data, const char *group)
Definition: meta_data.c:248
Octstr * group
Definition: meta_data.c:70
int octstr_str_case_compare(const Octstr *ostr, const char *str)
Definition: octstr.c:984
void dict_put(Dict *dict, Octstr *key, void *value)
Definition: dict.c:240
int meta_data_set_value(Octstr *data, const char *group, const Octstr *key, const Octstr *value, int replace)
Definition: meta_data.c:324
int octstr_url_decode(Octstr *ostr)
Definition: octstr.c:1744
int type
Definition: smsc_cimd2.c:215
Octstr * meta_data_get_value(Octstr *data, const char *group, const Octstr *key)
Definition: meta_data.c:368
Dict * values
Definition: meta_data.c:71
struct meta_data * next
Definition: meta_data.c:72
#define octstr_get_cstr(ostr)
Definition: octstr.h:233
void * dict_remove(Dict *dict, Octstr *key)
Definition: dict.c:307
void * gwlist_extract_first(List *list)
Definition: list.c:305
void * dict_get(Dict *dict, Octstr *key)
Definition: dict.c:286
void octstr_delete(Octstr *ostr1, long pos, long len)
Definition: octstr.c:1525
Octstr * meta_data_merge(const Octstr *data, const Octstr *new_data, int replace)
Definition: meta_data.c:392
Definition: dict.c:116
#define octstr_duplicate(ostr)
Definition: octstr.h:187
static void meta_data_destroy(struct meta_data *meta)
Definition: meta_data.c:89
static struct meta_data * meta_data_create(void)
Definition: meta_data.c:76
void octstr_destroy(Octstr *ostr)
Definition: octstr.c:322
#define octstr_create(cstr)
Definition: octstr.h:125
void octstr_destroy_item(void *os)
Definition: octstr.c:334
long octstr_len(const Octstr *ostr)
Definition: octstr.c:340
void dict_destroy(Dict *dict)
Definition: dict.c:215
Definition: octstr.c:118
static int meta_data_pack(struct meta_data *mdata, Octstr *data)
Definition: meta_data.c:224
void * gwlist_consume(List *list)
Definition: list.c:427
void debug(const char *place, int err, const char *fmt,...)
Definition: log.c:690
void octstr_format_append(Octstr *os, const char *fmt,...)
Definition: octstr.c:2505
List * dict_keys(Dict *dict)
Definition: dict.c:347
int dict_put_once(Dict *dict, Octstr *key, void *value)
Definition: dict.c:271
static struct meta_data * meta_data_unpack(const Octstr *data)
Definition: meta_data.c:107
#define octstr_create_from_data(data, len)
Definition: octstr.h:134
Definition: list.c:102
static int start
int meta_data_set_values(Octstr *data, const Dict *dict, const char *group, int replace)
Definition: meta_data.c:273
int octstr_compare(const Octstr *ostr1, const Octstr *ostr2)
Definition: octstr.c:869
void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
Definition: list.c:145
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.