avpops_parse.c

Go to the documentation of this file.
00001 /*
00002  * $Id: avpops_parse.c 5243 2008-11-21 13:15:31Z henningw $
00003  *
00004  * Copyright (C) 2004-2006 Voice Sistem SRL
00005  *
00006  * This file is part of Kamailio.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License
00010  * as published by the Free Software Foundation; either version 2
00011  * of the License, or (at your option) any later version.
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program; if not, write to the Free Software
00020  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00021  *
00022  * History:
00023  * ---------
00024  *  2004-10-04  first version (ramona)
00025  *  2004-11-11  DB scheme added (ramona)
00026  *  2004-11-17  aligned to new AVP core global aliases (ramona)
00027  */
00028 
00029 
00030 
00031 #include <stdlib.h>
00032 #include <ctype.h>
00033 
00034 #include "../../ut.h"
00035 #include "../../dprint.h"
00036 #include "../../usr_avp.h"
00037 #include "../../mem/mem.h"
00038 #include "avpops_parse.h"
00039 
00040 
00041 #define SCHEME_UUID_COL          "uuid_col"
00042 #define SCHEME_UUID_COL_LEN      (sizeof(SCHEME_UUID_COL)-1)
00043 #define SCHEME_USERNAME_COL      "username_col"
00044 #define SCHEME_USERNAME_COL_LEN  (sizeof(SCHEME_USERNAME_COL)-1)
00045 #define SCHEME_DOMAIN_COL        "domain_col"
00046 #define SCHEME_DOMAIN_COL_LEN    (sizeof(SCHEME_DOMAIN_COL)-1)
00047 #define SCHEME_VALUE_COL         "value_col"
00048 #define SCHEME_VALUE_COL_LEN     (sizeof(SCHEME_VALUE_COL)-1)
00049 #define SCHEME_TABLE             "table"
00050 #define SCHEME_TABLE_LEN         (sizeof(SCHEME_TABLE)-1)
00051 #define SCHEME_VAL_TYPE          "value_type"
00052 #define SCHEME_VAL_TYPE_LEN      (sizeof(SCHEME_VAL_TYPE)-1)
00053 #define SCHEME_INT_TYPE          "integer"
00054 #define SCHEME_INT_TYPE_LEN      (sizeof(SCHEME_INT_TYPE)-1)
00055 #define SCHEME_STR_TYPE          "string"
00056 #define SCHEME_STR_TYPE_LEN      (sizeof(SCHEME_STR_TYPE)-1)
00057 
00058 struct fis_param *avpops_parse_pvar(char *in)
00059 {
00060    struct fis_param *ap;
00061    str s;
00062 
00063    /* compose the param structure */
00064    ap = (struct fis_param*)pkg_malloc(sizeof(struct fis_param));
00065    if (ap==0)
00066    {
00067       LM_ERR("no more pkg mem\n");
00068       return NULL;
00069    }
00070    memset( ap, 0, sizeof(struct fis_param));
00071    s.s = in; s.len = strlen(s.s);
00072    if(pv_parse_spec(&s, &ap->u.sval)==0)
00073    {
00074       pkg_free(ap);
00075       return NULL;
00076    }
00077 
00078    ap->opd |= AVPOPS_VAL_PVAR;
00079    ap->type = AVPOPS_VAL_PVAR;
00080    return ap;
00081 }
00082 
00083 
00084 int parse_avp_db(char *s, struct db_param *dbp, int allow_scheme)
00085 {
00086    unsigned long ul;
00087    str   tmp;
00088    str   s0;
00089    char  have_scheme;
00090    char *p;
00091    char *p0;
00092    unsigned int flags;
00093 
00094    tmp.s = s;
00095    /* parse the attribute name - check first if it's not an alias */
00096    p0=strchr(tmp.s, '/');
00097    if(p0!=NULL)
00098       *p0=0;
00099    if ( *s!='$')
00100    {
00101       if(strlen(s)<1)
00102       {
00103          LM_ERR("bad param - expected : $avp(name), *, s or i value\n");
00104          return E_UNSPEC;
00105       }
00106       switch(*s) {
00107          case 's': case 'S':
00108             dbp->a.opd = AVPOPS_VAL_NONE|AVPOPS_VAL_STR;
00109          break;
00110          case 'i': case 'I':
00111             dbp->a.opd = AVPOPS_VAL_NONE|AVPOPS_VAL_INT;
00112          break;
00113          case '*': case 'a': case 'A':
00114             dbp->a.opd = AVPOPS_VAL_NONE;
00115          break;
00116          default:
00117             LM_ERR("bad param - expected : *, s or i AVP flag\n");
00118          return E_UNSPEC;
00119       }
00120       /* flags */
00121       flags = 0;
00122       if(*(s+1)!='\0')
00123       {
00124          s0.s = s+1;
00125          s0.len = strlen(s0.s);
00126          if(str2int(&s0, &flags)!=0)
00127          {
00128             LM_ERR("error - bad avp flags\n");
00129             goto error;
00130          }
00131       }
00132       dbp->a.u.sval.pvp.pvn.u.isname.type |= (flags<<8)&0xff00;
00133       dbp->a.type = AVPOPS_VAL_NONE;
00134    } else {
00135       s0.s = s; s0.len = strlen(s0.s);
00136       p = pv_parse_spec(&s0, &dbp->a.u.sval);
00137       if (p==0 || *p!='\0' || dbp->a.u.sval.type!=PVT_AVP)
00138       {
00139          LM_ERR("bad param - expected : $avp(name) or int/str value\n");
00140          return E_UNSPEC;
00141       }
00142       dbp->a.type = AVPOPS_VAL_PVAR;
00143    }
00144 
00145    /* optimize and keep the attribute name as str also to
00146     * speed up db querie builds */
00147    if (dbp->a.type == AVPOPS_VAL_PVAR)
00148    {
00149       dbp->a.opd = AVPOPS_VAL_PVAR;
00150       if(pv_has_sname(&dbp->a.u.sval))
00151       {
00152          dbp->sa.s=(char*)pkg_malloc(
00153                dbp->a.u.sval.pvp.pvn.u.isname.name.s.len+1);
00154          if (dbp->sa.s==0)
00155          {
00156             LM_ERR("no more pkg mem\n");
00157             goto error;
00158          }
00159          memcpy(dbp->sa.s, dbp->a.u.sval.pvp.pvn.u.isname.name.s.s,
00160                dbp->a.u.sval.pvp.pvn.u.isname.name.s.len);
00161          dbp->sa.len = dbp->a.u.sval.pvp.pvn.u.isname.name.s.len;
00162          dbp->sa.s[dbp->sa.len] = 0;
00163          dbp->a.opd = AVPOPS_VAL_PVAR|AVPOPS_VAL_STR;
00164       } else if(pv_has_iname(&dbp->a.u.sval)) {
00165          ul = (unsigned long)dbp->a.u.sval.pvp.pvn.u.isname.name.n;
00166          tmp.s = int2str( ul, &(tmp.len) );
00167          dbp->sa.s = (char*)pkg_malloc( tmp.len + 1 );
00168          if (dbp->sa.s==0)
00169          {
00170             LM_ERR("no more pkg mem\n");
00171             goto error;
00172          }
00173          memcpy( dbp->sa.s, tmp.s, tmp.len);
00174          dbp->sa.len = tmp.len;
00175          dbp->sa.s[dbp->sa.len] = 0;
00176          dbp->a.opd = AVPOPS_VAL_PVAR|AVPOPS_VAL_INT;
00177       }
00178    }
00179 
00180    /* restore '/' */
00181    if(p0)
00182       *p0 = '/';
00183    /* is there a table name ? */
00184    s = p0;
00185    if (s && *s)
00186    {
00187       s++;
00188       if (*s=='$')
00189       {
00190          if (allow_scheme==0)
00191          {
00192             LM_ERR("function doesn't support DB schemes\n");
00193             goto error;
00194          }
00195          if (dbp->a.opd&AVPOPS_VAL_NONE)
00196          {
00197             LM_ERR("inconsistent usage of "
00198                "DB scheme without complet specification of AVP name\n");
00199             goto error;
00200          }
00201          have_scheme = 1;
00202          s++;
00203       } else {
00204          have_scheme = 0;
00205       }
00206       tmp.s = s;
00207       tmp.len = 0;
00208       while ( *s ) s++;
00209       tmp.len = s - tmp.s;
00210       if (tmp.len==0)
00211       {
00212          LM_ERR("empty scheme/table name\n");
00213          goto error;
00214       }
00215       if (have_scheme)
00216       {
00217          dbp->scheme = avp_get_db_scheme( &tmp );
00218          if (dbp->scheme==0) 
00219          {
00220             LM_ERR("scheme <%s> not found\n", tmp.s);
00221             goto error;
00222          }
00223          /* update scheme flags with AVP name type*/
00224          dbp->scheme->db_flags|=dbp->a.opd&AVPOPS_VAL_STR?AVP_NAME_STR:0;
00225       } else {
00226          /* duplicate table as str */
00227          pkg_str_dup(&dbp->table, &tmp);
00228       }
00229    }
00230 
00231    return 0;
00232 error:
00233    return -1;
00234 }
00235 
00236 
00237 struct fis_param* parse_intstr_value(char *p, int len)
00238 {
00239    struct fis_param *vp;
00240    unsigned int uint;
00241    str val_str;
00242    int flags;
00243 
00244    if (p==0 || len==0)
00245          goto error;
00246 
00247    if (len>1 && *(p+1)==':')
00248    {
00249       if (*p=='i' || *p=='I')
00250          flags = AVPOPS_VAL_INT;
00251       else if (*p=='s' || *p=='S')
00252          flags = AVPOPS_VAL_STR;
00253       else
00254       {
00255          LM_ERR("unknown value type <%c>\n",*p);
00256          goto error;
00257       }
00258       p += 2;
00259       len -= 2;
00260       if (*p==0 || len<=0 )
00261       {
00262          LM_ERR("parse error arround <%.*s>\n",len,p);
00263             goto error;
00264       }
00265    } else {
00266       flags = AVPOPS_VAL_STR;
00267    }
00268    /* get the value */
00269    vp = (struct fis_param*)pkg_malloc(sizeof(struct fis_param));
00270    if (vp==0)
00271    {
00272       LM_ERR("no more pkg mem\n");
00273       goto error;;
00274    }
00275    memset( vp, 0, sizeof(struct fis_param));
00276    vp->opd = flags;
00277    val_str.s = p;
00278    val_str.len = len;
00279    if (flags&AVPOPS_VAL_INT) {
00280       /* convert the value to integer */
00281       if(val_str.len>2 && p[0]=='0' && (p[1]=='x' || p[1]=='X'))
00282       {
00283          if(hexstr2int(val_str.s+2, val_str.len-2, &uint))
00284          {
00285             LM_ERR("value is not hex int as type says <%.*s>\n", 
00286                   val_str.len, val_str.s);
00287             goto error;
00288          }
00289       } else {
00290          if(str2sint( &val_str, (int*)&uint)==-1)
00291          {
00292             LM_ERR("value is not int"
00293                " as type says <%.*s>\n", val_str.len, val_str.s);
00294             goto error;
00295          }
00296       }
00297       vp->u.n = (int)uint;
00298       vp->type = AVPOPS_VAL_INT;
00299    } else {
00300       /* duplicate the value as string */
00301       vp->u.s.s = (char*)pkg_malloc((val_str.len+1)*sizeof(char));
00302       if (vp->u.s.s==0)
00303       {
00304          LM_ERR("no more pkg mem\n");
00305          goto error;
00306       }
00307       vp->u.s.len = val_str.len;
00308       memcpy(vp->u.s.s, val_str.s, val_str.len);
00309       vp->u.s.s[vp->u.s.len] = 0;
00310       vp->type = AVPOPS_VAL_STR;
00311    }
00312 
00313    return vp;
00314 error:
00315    return 0;
00316 }
00317 
00318 
00319 #define  duplicate_str(_p, _str, _error) \
00320    do { \
00321       _p.s = (char*)pkg_malloc(_str.len+1); \
00322       if (_p.s==0) \
00323       { \
00324          LM_ERR("no more pkg memory\n");\
00325          goto _error; \
00326       } \
00327       _p.len = _str.len; \
00328       memcpy( _p.s, _str.s, _str.len); \
00329       _p.s[_str.len] = 0; \
00330    }while(0)
00331 
00332 int parse_avp_db_scheme( char *s, struct db_scheme *scheme)
00333 {
00334    str foo;
00335    str bar;
00336    char *p;
00337 
00338    if (s==0 || *s==0)
00339       goto error;
00340    p = s;
00341 
00342    /*parse the name */
00343    while (*p && isspace((int)*p)) p++;
00344    foo.s = p;
00345    while (*p && *p!=':' && !isspace((int)*p)) p++;
00346    if (foo.s==p || *p==0)
00347       /* missing name or empty scheme */
00348       goto parse_error;
00349    foo.len = p - foo.s;
00350    /* dulicate it */
00351    duplicate_str( scheme->name, foo, error);
00352 
00353    /* parse the ':' separator */
00354    while (*p && isspace((int)*p)) p++;
00355    if (*p!=':')
00356       goto parse_error;
00357    p++;
00358    while (*p && isspace((int)*p)) p++;
00359    if (*p==0)
00360       goto parse_error;
00361 
00362    /* set as default value type string */
00363    scheme->db_flags = AVP_VAL_STR;
00364 
00365    /* parse the attributes */
00366    while (*p)
00367    {
00368       /* get the attribute name */
00369       foo.s = p;
00370       while (*p && *p!='=' && !isspace((int)*p)) p++;
00371       if (p==foo.s || *p==0)
00372          /* missing attribute name */
00373          goto parse_error;
00374       foo.len = p - foo.s;
00375 
00376       /* parse the '=' separator */
00377       while (*p && isspace((int)*p)) p++;
00378       if (*p!='=')
00379          goto parse_error;
00380       p++;
00381       while (*p && isspace((int)*p)) p++;
00382       if (*p==0)
00383          goto parse_error;
00384 
00385       /* parse the attribute value */
00386       bar.s = p;
00387       while (*p && *p!=';' && !isspace((int)*p)) p++;
00388       if (p==bar.s)
00389          /* missing attribute value */
00390          goto parse_error;
00391       bar.len = p - bar.s;
00392 
00393       /* parse the ';' separator, if any */
00394       while (*p && isspace((int)*p)) p++;
00395       if (*p!=0 && *p!=';')
00396          goto parse_error;
00397       if (*p==';') p++;
00398       while (*p && isspace((int)*p)) p++;
00399 
00400       /* identify the attribute */
00401       if ( foo.len==SCHEME_UUID_COL_LEN && 
00402       !strncasecmp( foo.s, SCHEME_UUID_COL, foo.len) )
00403       {
00404          if (scheme->uuid_col.s) goto parse_error;
00405          duplicate_str( scheme->uuid_col, bar, error);
00406       } else
00407       if ( foo.len==SCHEME_USERNAME_COL_LEN && 
00408       !strncasecmp( foo.s, SCHEME_USERNAME_COL, foo.len) )
00409       {
00410          if (scheme->username_col.s) goto parse_error;
00411          duplicate_str( scheme->username_col, bar, error);
00412       } else
00413       if ( foo.len==SCHEME_DOMAIN_COL_LEN && 
00414       !strncasecmp( foo.s, SCHEME_DOMAIN_COL, foo.len) )
00415       {
00416          if (scheme->domain_col.s) goto parse_error;
00417          duplicate_str( scheme->domain_col, bar, error);
00418       } else
00419       if ( foo.len==SCHEME_VALUE_COL_LEN && 
00420       !strncasecmp( foo.s, SCHEME_VALUE_COL, foo.len) )
00421       {
00422          if (scheme->value_col.s) goto parse_error;
00423          duplicate_str( scheme->value_col, bar, error);
00424       } else
00425       if ( foo.len==SCHEME_TABLE_LEN && 
00426       !strncasecmp( foo.s, SCHEME_TABLE, foo.len) )
00427       {
00428          if (scheme->table.s) goto parse_error;
00429          duplicate_str( scheme->table, bar, error);
00430       } else
00431       if ( foo.len==SCHEME_VAL_TYPE_LEN && 
00432       !strncasecmp( foo.s, SCHEME_VAL_TYPE, foo.len) )
00433       {
00434          if ( bar.len==SCHEME_INT_TYPE_LEN &&
00435          !strncasecmp( bar.s, SCHEME_INT_TYPE, bar.len) )
00436             scheme->db_flags &= (~AVP_VAL_STR);
00437          else if ( bar.len==SCHEME_STR_TYPE_LEN &&
00438          !strncasecmp( bar.s, SCHEME_STR_TYPE, bar.len) )
00439             scheme->db_flags = AVP_VAL_STR;
00440          else
00441          {
00442             LM_ERR("unknown value type <%.*s>\n",bar.len,bar.s);
00443             goto error;
00444          }
00445       } else {
00446          LM_ERR("unknown attribute <%.*s>\n",foo.len,foo.s);
00447          goto error;
00448       }
00449    } /* end while */
00450 
00451    return 0;
00452 parse_error:
00453    LM_ERR("parse error in <%s> around %ld\n", s, (long)(p-s));
00454 error:
00455    return -1;
00456 }
00457 
00458 struct fis_param* parse_check_value(char *s)
00459 {
00460    struct fis_param *vp;
00461    int  ops;
00462    int  opd;
00463    char *p;
00464    char *t;
00465    int len;
00466 
00467    ops = 0;
00468    opd = 0;
00469    vp = 0;
00470 
00471    if ( (p=strchr(s,'/'))==0 || (p-s!=2&&p-s!=3) )
00472       goto parse_error;
00473    /* get the operation */
00474    if (strncasecmp(s,"eq",2)==0) {
00475       ops |= AVPOPS_OP_EQ;
00476    } else if (strncasecmp(s,"ne",2)==0) {
00477       ops |= AVPOPS_OP_NE;
00478    } else if (strncasecmp(s,"lt",2)==0) {
00479       ops |= AVPOPS_OP_LT;
00480    } else if (strncasecmp(s,"le",2)==0) {
00481       ops |= AVPOPS_OP_LE;
00482    } else if (strncasecmp(s,"gt",2)==0) {
00483       ops |= AVPOPS_OP_GT;
00484    } else if (strncasecmp(s,"ge",2)==0) {
00485       ops |= AVPOPS_OP_GE;
00486    } else if (strncasecmp(s,"re",2)==0) {
00487       ops |= AVPOPS_OP_RE;
00488    } else if (strncasecmp(s,"fm",2)==0) {
00489       ops |= AVPOPS_OP_FM;
00490    } else if (strncasecmp(s,"and",3)==0) {
00491       ops |= AVPOPS_OP_BAND;
00492    } else if (strncasecmp(s,"or",2)==0) {
00493       ops |= AVPOPS_OP_BOR;
00494    } else if (strncasecmp(s,"xor",3)==0) {
00495       ops |= AVPOPS_OP_BXOR;
00496    } else {
00497       LM_ERR("unknown operation <%.*s>\n",2,s);
00498       goto error;
00499    }
00500    /* get the value */
00501    if (*(++p)==0)
00502       goto parse_error;
00503    if ( (t=strchr(p,'/'))==0)
00504       len = strlen(p);
00505    else
00506       len = t-p;
00507 
00508    if (*p=='$')
00509    {
00510       /* is variable */
00511       vp = avpops_parse_pvar(p);
00512       if (vp==0)
00513       {
00514          LM_ERR("unable to get pseudo-variable\n");
00515          goto error;
00516       }
00517       if (vp->u.sval.type==PVT_NULL)
00518       {
00519          LM_ERR("bad param; expected : $pseudo-variable or int/str value\n");
00520          goto error;
00521       }
00522       opd |= AVPOPS_VAL_PVAR;
00523       LM_DBG("flag==%d/%d\n", opd, ops);
00524    } else {
00525       /* value is explicitly given */
00526       if ( (vp=parse_intstr_value(p,len))==0) {
00527          LM_ERR("unable to parse value\n");
00528          goto error;
00529       }
00530    }
00531 
00532    p = t;
00533    /* any flags */
00534    if (p!=NULL && *p!=0)
00535    {
00536       if (*p!='/' || *(++p)==0)
00537          goto parse_error;
00538       while (*p)
00539       {
00540          switch (*p)
00541          {
00542             case 'g':
00543             case 'G':
00544                ops|=AVPOPS_FLAG_ALL;
00545                break;
00546             case 'i':
00547             case 'I':
00548                ops|=AVPOPS_FLAG_CI;
00549                break;
00550             default:
00551                LM_ERR("unknown flag <%c>\n",*p);
00552                goto error;
00553          }
00554          p++;
00555       }
00556    }
00557 
00558    vp->ops |= ops;
00559    vp->opd |= opd;
00560    return vp;
00561 parse_error:
00562    LM_ERR("parse error in <%s> pos %ld\n", s,(long)(p-s));
00563 error:
00564    if (vp) pkg_free(vp);
00565    return 0;
00566 }
00567 
00568 struct fis_param* parse_op_value(char *s)
00569 {
00570    struct fis_param *vp;
00571    int  ops;
00572    int  opd;
00573    char *p;
00574    char *t;
00575    int len;
00576 
00577    ops = 0;
00578    opd = 0;
00579    vp = 0;
00580 
00581    if ( (p=strchr(s,'/'))==0 || (p-s!=2&&p-s!=3) )
00582       goto parse_error;
00583    /* get the operation */
00584    if (strncasecmp(s,"add",3)==0) {
00585       ops |= AVPOPS_OP_ADD;
00586    } else if (strncasecmp(s,"sub",3)==0) {
00587       ops |= AVPOPS_OP_SUB;
00588    } else if (strncasecmp(s,"mul",3)==0) {
00589       ops |= AVPOPS_OP_MUL;
00590    } else if (strncasecmp(s,"div",3)==0) {
00591       ops |= AVPOPS_OP_DIV;
00592    } else if (strncasecmp(s,"mod",3)==0) {
00593       ops |= AVPOPS_OP_MOD;
00594    } else if (strncasecmp(s,"and",3)==0) {
00595       ops |= AVPOPS_OP_BAND;
00596    } else if (strncasecmp(s,"or",2)==0) {
00597       ops |= AVPOPS_OP_BOR;
00598    } else if (strncasecmp(s,"xor",3)==0) {
00599       ops |= AVPOPS_OP_BXOR;
00600    } else if (strncasecmp(s,"not",3)==0) {
00601       ops |= AVPOPS_OP_BNOT;
00602    } else {
00603       LM_ERR("unknown operation <%.*s>\n",2,s);
00604       goto error;
00605    }
00606    /* get the value */
00607    if (*(++p)==0)
00608       goto parse_error;
00609    if ( (t=strchr(p,'/'))==0)
00610       len = strlen(p);
00611    else
00612       len = t-p;
00613 
00614    if (*p=='$')
00615    {
00616       /* is variable */
00617       vp = avpops_parse_pvar(p);
00618       if (vp==0)
00619       {
00620          LM_ERR("unable to get pseudo-variable\n");
00621          goto error;
00622       }
00623       if (vp->u.sval.type==PVT_NULL)
00624       {
00625          LM_ERR("bad param; expected : $pseudo-variable or int/str value\n");
00626          goto error;
00627       }
00628       opd |= AVPOPS_VAL_PVAR;
00629       LM_DBG("flag==%d/%d\n", opd, ops);
00630    } else {
00631       /* value is explicitly given */
00632       if ( (vp=parse_intstr_value(p,len))==0) {
00633          LM_ERR("unable to parse value\n");
00634          goto error;
00635       }
00636       if((vp->opd&AVPOPS_VAL_INT)==0) {
00637          LM_ERR("value must be int\n");
00638          goto error;
00639       }
00640    }
00641 
00642    /* any flags */
00643    p = t;
00644    if (p!=0 && *p!=0 )
00645    {
00646       if (*p!='/' || *(++p)==0)
00647          goto parse_error;
00648       while (*p)
00649       {
00650          switch (*p)
00651          {
00652             case 'g':
00653             case 'G':
00654                ops|=AVPOPS_FLAG_ALL;
00655                break;
00656             case 'd':
00657             case 'D':
00658                ops|=AVPOPS_FLAG_DELETE;
00659                break;
00660             default:
00661                LM_ERR("unknown flag <%c>\n",*p);
00662                goto error;
00663          }
00664          p++;
00665       }
00666    }
00667 
00668    vp->ops |= ops;
00669    vp->opd |= opd;
00670    return vp;
00671 parse_error:
00672    LM_ERR("parse error in <%s> pos %ld\n", s,(long)(p-s));
00673 error:
00674    if (vp) pkg_free(vp);
00675    return 0;
00676 }
00677 

Generated on Thu May 17 12:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6