attrs.h

00001 /*
00002  * Accounting module
00003  *
00004  * $Id$
00005  *
00006  * Copyright (C) 2001-2003 FhG FOKUS
00007  * Copyright (C) 2005 iptelorg GmbH
00008  *
00009  * This file is part of ser, a free SIP server.
00010  *
00011  * ser is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * For a license to use the ser software under conditions
00017  * other than those described here, or to purchase support for this
00018  * software, please contact iptel.org by e-mail at the following addresses:
00019  *    info@iptel.org
00020  *
00021  * ser is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00024  * GNU General Public License for more details.
00025  *
00026  * You should have received a copy of the GNU General Public License
00027  * along with this program; if not, write to the Free Software
00028  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00029  *
00030  */
00031 
00032 #ifndef _ATTRS_H
00033 #define _ATTRS_H
00034 
00035 #include <string.h>
00036 #include "../../mem/mem.h"
00037 #include "../../dprint.h"
00038 #include "../../usr_avp.h"
00039 #include "../../trim.h"
00040 #include "../../str.h"
00041 #include "../../ut.h"
00042 
00043 
00044 /*
00045  * Parse the value of attrs parameter 
00046  */
00047 static int parse_attrs(avp_ident_t** avps, int* avps_n, char* attrs)
00048 {
00049         str token;
00050 
00051         token.s = strtok(attrs, ",");
00052 
00053         *avps = 0;
00054         *avps_n = 0;
00055         while(token.s) {
00056                 token.len = strlen(token.s);
00057                 trim(&token);
00058                 
00059                 if (token.len && token.s[0] == '$') {
00060                         token.s++;
00061                         token.len--;
00062                 } else goto skip;
00063 
00064                 *avps = pkg_realloc(*avps, sizeof(avp_ident_t) * (*avps_n + 1));
00065                 if (!*avps) {
00066                         ERR("No memory left\n");
00067                         goto err;
00068                 }
00069 
00070                 if (parse_avp_ident(&token, &(*avps)[*avps_n]) < 0) {
00071                         ERR("Error while parsing AVP id '%.*s'\n", token.len, ZSW(token.s));
00072                         goto err;
00073                 }
00074                 DBG("Found attribute $%.*s\n", (*avps)[*avps_n].name.s.len, (*avps)[*avps_n].name.s.s);
00075 
00076                 (*avps_n)++;
00077         skip:
00078                 token.s = strtok(0, ",");
00079         }
00080         return 0;
00081  err:
00082         if (*avps) pkg_free(*avps);
00083         return -1;
00084 }
00085 
00086 
00087 
00088 #define attrs_append(dst, src)           \
00089 do {                                     \
00090     if ((dst).len < (src).len) {         \
00091         ERR("Buffer too small\n");       \
00092         goto error;                      \
00093     }                                    \
00094     memcpy((dst).s, (src).s, (src).len); \
00095     (dst).s += (src).len;                \
00096     (dst).len -= (src).len;              \
00097 } while(0)
00098 
00099 
00100 /*
00101  * Escape delimiter characters
00102  */
00103 #define attrs_append_esc(dst, src, esc_quote)               \
00104 do {                                                        \
00105         int i;                                              \
00106         char* w;                                            \
00107                                                             \
00108         if ((dst).len < ((src).len * 2)) {                  \
00109                 ERR("Buffer too small\n");                  \
00110                 goto error;                                 \
00111         }                                                   \
00112                                                             \
00113         w = (dst).s;                                        \
00114         for(i = 0; i < (src).len; i++) {                    \
00115                 switch((src).s[i]) {                        \
00116                 case '\n': *w++ = '\\'; *w++ = 'n';  break; \
00117                 case '\r': *w++ = '\\'; *w++ = 'r';  break; \
00118                 case '\t': *w++ = '\\'; *w++ = 't';  break; \
00119                 case '\\': *w++ = '\\'; *w++ = '\\'; break; \
00120                 case '\0': *w++ = '\\'; *w++ = '0';  break; \
00121                 case '"':                                   \
00122                     if (esc_quote) {                        \
00123                         *w++ = '\\'; *w++ = 'q';            \
00124                     } else {                                \
00125                         *w++ = (src).s[i];                  \
00126                     }                                       \
00127                     break;                                  \
00128                 case ':':  *w++ = '\\'; *w++ = 'o';  break; \
00129                 case ',':  *w++ = '\\'; *w++ = 'c';  break; \
00130                 default:   *w++ = (src).s[i];        break; \
00131                 }                                           \
00132         }                                                   \
00133         (dst).len -= w - (dst).s;                           \
00134         (dst).s = w;                                        \
00135 } while(0)
00136 
00137 
00138 #define attrs_append_printf(dst, fmt, args...)              \
00139 do {                                                        \
00140         int len = snprintf((dst).s, (dst).len, (fmt), ## args); \
00141         if (len < 0 || len >= (dst).len) {                      \
00142                 ERR("Buffer too small\n");                          \
00143                 goto error;                                         \
00144         }                                                       \
00145         (dst).s += len;                                         \
00146         (dst).len -= len;                                       \
00147 } while(0)
00148 
00149 
00150 
00151 #define ATTRS_BUF_LEN 4096
00152 static str* print_attrs(avp_ident_t* avps, int avps_n, int quote)
00153 {
00154         static str quote_s = STR_STATIC_INIT("\"");
00155         static str attrs_name_delim = STR_STATIC_INIT(":");
00156         static str attrs_delim = STR_STATIC_INIT(",");
00157         static char buf[ATTRS_BUF_LEN];
00158         static str res;
00159         int i;
00160         struct search_state st;
00161         avp_value_t val;
00162         str p;
00163 
00164         p.s = buf;
00165         p.len = ATTRS_BUF_LEN - 1;
00166 
00167         if (quote && avps_n) {
00168                 attrs_append(p, quote_s);
00169         }
00170 
00171         for(i = 0; i < avps_n; i++) {
00172                 avp_t *this_avp = search_first_avp(avps[i].flags, avps[i].name, &val, &st);
00173                 if (!this_avp) continue;
00174                 attrs_append(p, avps[i].name.s);
00175                 attrs_append(p, attrs_name_delim);
00176                 if (this_avp->flags & AVP_VAL_STR)
00177                         attrs_append_esc(p, val.s, quote);
00178                 else
00179                         attrs_append_printf(p, "%d", val.n);
00180 
00181                 while(search_next_avp(&st, &val)) {
00182                         attrs_append(p, attrs_delim);
00183                         attrs_append(p, avps[i].name.s);
00184                         attrs_append(p, attrs_name_delim);
00185                         attrs_append_esc(p, val.s, quote);
00186                 }
00187                 if (i < (avps_n - 1)) attrs_append(p, attrs_delim); 
00188         }
00189 
00190         if (quote && avps_n) {
00191                 attrs_append(p, quote_s);
00192         }
00193 
00194         *p.s = '\0';
00195         res.s = buf;
00196         res.len = p.s - buf;
00197         return &res;
00198 
00199  error:
00200         return 0;
00201 }
00202 
00203 #endif /* _ATTRS_H */