cpl.c

Go to the documentation of this file.
00001 /*
00002  * $Id: cpl.c 5600 2009-02-12 19:25:22Z miconda $
00003  *
00004  * Copyright (C) 2001-2003 FhG Fokus
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (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  * 2003-03-11: New module interface (janakj)
00025  * 2003-03-16: flags export parameter added (janakj)
00026  * 2003-11-11: build_lump_rpl() removed, add_lump_rpl() has flags (bogdan)
00027  * 2004-06-06  updated to the new DB api (andrei)
00028  * 2004-06-14: all global variables merged into cpl_env and cpl_fct;
00029  *             case_sensitive and realm_prefix added for building AORs - see
00030  *             build_userhost (bogdan)
00031  * 2004-10-09: added process_register_norpl to allow register processing 
00032  *             without sending the reply(bogdan) - based on a patch sent by
00033  *             Christopher Crawford
00034  */
00035 
00036 
00037 #include <stdio.h>
00038 #include <string.h>
00039 #include <sys/types.h>
00040 #include <sys/stat.h>
00041 #include <unistd.h>
00042 #include <fcntl.h>
00043 #include <signal.h>
00044 
00045 #include "../../mem/shm_mem.h"
00046 #include "../../mem/mem.h"
00047 #include "../../sr_module.h"
00048 #include "../../str.h"
00049 #include "../../ut.h"
00050 #include "../../dprint.h"
00051 #include "../../data_lump_rpl.h"
00052 #include "../../pvar.h"
00053 #include "../../parser/parse_uri.h"
00054 #include "../../parser/parse_from.h"
00055 #include "../../parser/parse_content.h"
00056 #include "../../parser/parse_disposition.h"
00057 #include "../../db/db.h"
00058 #include "../../mi/mi.h"
00059 #include "../sl/sl_api.h"
00060 #include "cpl_run.h"
00061 #include "cpl_env.h"
00062 #include "cpl_db.h"
00063 #include "cpl_loader.h"
00064 #include "cpl_parser.h"
00065 #include "cpl_nonsig.h"
00066 #include "loc_set.h"
00067 
00068 
00069 #define MAX_PROXY_RECURSE  10
00070 #define MAX_USERHOST_LEN    256
00071 
00072 
00073 /* modules param variables */
00074 static str db_url           = str_init(DEFAULT_DB_URL); /* database url */
00075 static str db_table        = str_init("cpl");  /* database table */
00076 static char *dtd_file      = 0;  /* name of the DTD file for CPL parser */
00077 static char *lookup_domain = 0;
00078 static str  timer_avp      = {NULL, 0};  /* name of variable timer AVP */
00079 
00080 
00081 struct cpl_enviroment    cpl_env = {
00082       0, /* no cpl logging */
00083       0, /* recurse proxy level is 0 */
00084       0, /* no script route to be run before proxy */
00085       0, /* user part is not case sensitive */
00086       {0,0},   /* no domain prefix to be ignored */
00087       {-1,-1}, /* communication pipe to aux_process */
00088       {0,0},   /* original TZ \0 terminated "TZ=value" format */
00089       0,   /* udomain */
00090       0,   /* no branches on lookup */
00091       0,   /* timer avp type */
00092       {0}, /* timer avp name/ID */
00093       0    /* use_domain */
00094 };
00095 
00096 struct cpl_functions  cpl_fct;
00097 static str cpl_ok_rpl = str_init("OK");
00098 
00099 
00100 MODULE_VERSION
00101 
00102 
00103 static int cpl_invoke_script (struct sip_msg* msg, char* str, char* str2);
00104 static int w_process_register(struct sip_msg* msg, char* str, char* str2);
00105 static int w_process_register_norpl(struct sip_msg* msg, char* str,char* str2);
00106 static int cpl_process_register(struct sip_msg* msg, int no_rpl);
00107 static int fixup_cpl_run_script(void** param, int param_no);
00108 static int cpl_init(void);
00109 static int mi_child_init(void);
00110 static int cpl_child_init(int rank);
00111 static int cpl_exit(void);
00112 static void cpl_process(int rank);
00113 
00114 
00115 /*
00116  * Exported processes
00117  */
00118 static proc_export_t cpl_procs[] = {
00119    {"CPL Aux",  0,  0,  cpl_process, 1 },
00120    {0,0,0,0,0}
00121 };
00122 
00123 
00124 /*
00125  * Exported functions
00126  */
00127 static cmd_export_t cmds[] = {
00128    {"cpl_run_script",            (cmd_function)cpl_invoke_script,        2,
00129          fixup_cpl_run_script, 0, REQUEST_ROUTE},
00130    {"cpl_process_register",      (cmd_function)w_process_register,       0,
00131          0, 0,                    REQUEST_ROUTE},
00132    {"cpl_process_register_norpl",(cmd_function)w_process_register_norpl, 0,
00133          0, 0,                    REQUEST_ROUTE},
00134    {0, 0, 0, 0, 0, 0}
00135 };
00136 
00137 
00138 /*
00139  * Exported parameters
00140  */
00141 static param_export_t params[] = {
00142    {"db_url",         STR_PARAM, &db_url.s                          },
00143    {"db_table",       STR_PARAM, &db_table.s                        },
00144    {"cpl_dtd_file",   STR_PARAM, &dtd_file                          },
00145    {"proxy_recurse",  INT_PARAM, &cpl_env.proxy_recurse             },
00146    {"proxy_route",    INT_PARAM, &cpl_env.proxy_route               },
00147    {"log_dir",        STR_PARAM, &cpl_env.log_dir                   },
00148    {"case_sensitive", INT_PARAM, &cpl_env.case_sensitive            },
00149    {"realm_prefix",   STR_PARAM, &cpl_env.realm_prefix.s            },
00150    {"lookup_domain",  STR_PARAM, &lookup_domain                     },
00151    {"lookup_append_branches", INT_PARAM, &cpl_env.lu_append_branches},
00152    {"timer_avp",      STR_PARAM, &timer_avp.s                       },
00153    {"username_column",STR_PARAM, &cpl_username_col                  },
00154    {"domain_column",  STR_PARAM, &cpl_domain_col                    },
00155    {"cpl_xml_column", STR_PARAM, &cpl_xml_col                       },
00156    {"cpl_bin_column", STR_PARAM, &cpl_bin_col                       },
00157    {"use_domain",     INT_PARAM, &cpl_env.use_domain                },
00158    {0, 0, 0}
00159 };
00160 
00161 
00162 /*
00163  * Exported MI functions
00164  */
00165 static mi_export_t mi_cmds[] = {
00166    { "LOAD_CPL",   mi_cpl_load,     0,  0,  mi_child_init },
00167    { "REMOVE_CPL", mi_cpl_remove,   0,  0,  0             },
00168    { "GET_CPL",    mi_cpl_get,      0,  0,  0             },
00169    { 0, 0, 0, 0, 0}
00170 };
00171 
00172 
00173 
00174 
00175 struct module_exports exports = {
00176    "cpl-c",
00177    DEFAULT_DLFLAGS, /* dlopen flags */
00178    cmds,     /* Exported functions */
00179    params,   /* Exported parameters */
00180    0,        /* exported statistics */
00181    mi_cmds,  /* exported MI functions */
00182    0,        /* exported pseudo-variables */
00183    cpl_procs,/* extra processes */
00184    cpl_init, /* Module initialization function */
00185    0,
00186    (destroy_function) cpl_exit,
00187    (child_init_function) cpl_child_init /* per-child init function */
00188 };
00189 
00190 
00191 
00192 static int fixup_cpl_run_script(void** param, int param_no)
00193 {
00194    long flag;
00195 
00196    if (param_no==1) {
00197       if (!strcasecmp( "incoming", *param))
00198          flag = CPL_RUN_INCOMING;
00199       else if (!strcasecmp( "outgoing", *param))
00200          flag = CPL_RUN_OUTGOING;
00201       else {
00202          LM_ERR("script directive \"%s\" unknown!\n",(char*)*param);
00203          return E_UNSPEC;
00204       }
00205       pkg_free(*param);
00206       *param=(void*)flag;
00207       return 0;
00208    } else if (param_no==2) {
00209       if ( !strcasecmp("is_stateless", *param) ) {
00210          flag = 0;
00211       } else if ( !strcasecmp("is_stateful", *param) ) {
00212          flag = CPL_IS_STATEFUL;
00213       } else if ( !strcasecmp("force_stateful", *param) ) {
00214          flag = CPL_FORCE_STATEFUL;
00215       } else {
00216          LM_ERR("flag \"%s\" (second param) unknown!\n",(char*)*param);
00217          return E_UNSPEC;
00218       }
00219       pkg_free(*param);
00220       *param=(void*)flag;
00221    }
00222    return 0;
00223 }
00224 
00225 
00226 
00227 static int cpl_init(void)
00228 {
00229    bind_usrloc_t bind_usrloc;
00230    struct stat   stat_t;
00231    char *ptr;
00232    int val;
00233    pv_spec_t avp_spec;
00234    unsigned short avp_type;
00235 
00236    db_url.len = strlen(db_url.s);
00237    db_table.len = strlen(db_table.s);
00238    if (timer_avp.s) timer_avp.len = strlen(timer_avp.s);
00239 
00240    if (cpl_env.proxy_recurse>MAX_PROXY_RECURSE) {
00241       LM_CRIT("value of proxy_recurse param (%d) exceeds "
00242          "the maximum safety value (%d)\n",
00243          cpl_env.proxy_recurse,MAX_PROXY_RECURSE);
00244       goto error;
00245    }
00246 
00247    /* fix the timer_avp name */
00248    if (timer_avp.s && timer_avp.len > 0) {
00249       if (pv_parse_spec(&timer_avp, &avp_spec)==0
00250             || avp_spec.type!=PVT_AVP) {
00251          LM_ERR("malformed or non AVP %.*s AVP definition\n", timer_avp.len, timer_avp.s);
00252          return -1;
00253       }
00254 
00255       if(pv_get_avp_name(0, &(avp_spec.pvp), &cpl_env.timer_avp,
00256                      &avp_type)!=0)
00257       {
00258          LM_ERR("[%.*s]- invalid AVP definition\n", timer_avp.len, timer_avp.s);
00259          return -1;
00260       }
00261       cpl_env.timer_avp_type = avp_type;
00262    }
00263 
00264    if (dtd_file==0) {
00265       LM_CRIT("mandatory parameter \"cpl_dtd_file\" found empty\n");
00266       goto error;
00267    } else {
00268       /* check if the dtd file exists */
00269       if (stat( dtd_file, &stat_t)==-1) {
00270          LM_ERR("checking file \"%s\" status failed; stat returned %s\n",
00271                dtd_file,strerror(errno));
00272          goto error;
00273       }
00274       if ( !S_ISREG( stat_t.st_mode ) ) {
00275          LM_ERR("dir \"%s\" is not a regular file!\n", dtd_file);
00276          goto error;
00277       }
00278       if (access( dtd_file, R_OK )==-1) {
00279          LM_ERR("checking file \"%s\" for permissions "
00280             "failed; access returned %s\n",dtd_file,strerror(errno));
00281          goto error;
00282       }
00283    }
00284 
00285    if (cpl_env.log_dir==0) {
00286       LM_INFO("log_dir param found empty -> logging disabled!\n");
00287    } else {
00288       if ( strlen(cpl_env.log_dir)>MAX_LOG_DIR_SIZE ) {
00289          LM_ERR("dir \"%s\" has a too long name :-(!\n", cpl_env.log_dir);
00290          goto error;
00291       }
00292       /* check if the dir exists */
00293       if (stat( cpl_env.log_dir, &stat_t)==-1) {
00294          LM_ERR("checking dir \"%s\" status failed;"
00295             " stat returned %s\n",cpl_env.log_dir,strerror(errno));
00296          goto error;
00297       }
00298       if ( !S_ISDIR( stat_t.st_mode ) ) {
00299          LM_ERR("dir \"%s\" is not a directory!\n", cpl_env.log_dir);
00300          goto error;
00301       }
00302       if (access( cpl_env.log_dir, R_OK|W_OK )==-1) {
00303          LM_ERR("checking dir \"%s\" for permissions failed; access "
00304                "returned %s\n", cpl_env.log_dir, strerror(errno));
00305          goto error;
00306       }
00307    }
00308 
00309    /* bind to the mysql module */
00310    if (cpl_db_bind(&db_url, &db_table)<0) goto error;
00311 
00312    /* load TM API */
00313    if (load_tm_api(&cpl_fct.tmb)!=0) {
00314       LM_ERR("can't load TM API\n");
00315       goto error;
00316    }
00317    /* load SL API */
00318    if (load_sl_api(&cpl_fct.slb)!=0) {
00319       LM_ERR("can't load SL API\n");
00320       goto error;
00321    }
00322 
00323    /* bind to usrloc module if requested */
00324    if (lookup_domain) {
00325       /* import all usrloc functions */
00326       bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0);
00327       if (!bind_usrloc) {
00328          LM_ERR("can't bind usrloc\n");
00329          goto error;
00330       }
00331       if (bind_usrloc( &(cpl_fct.ulb) ) < 0) {
00332          LM_ERR("importing usrloc failed\n");
00333          goto error;
00334       }
00335       /* convert lookup_domain from char* to udomain_t* pointer */
00336       if (cpl_fct.ulb.register_udomain( lookup_domain, &cpl_env.lu_domain)
00337       < 0) {
00338          LM_ERR("failed to register domain <%s>\n",lookup_domain);
00339          goto error;
00340       }
00341    } else {
00342       LM_NOTICE("no lookup_domain given -> disable lookup node\n");
00343    }
00344 
00345    /* build a pipe for sending commands to aux process */
00346    if ( pipe( cpl_env.cmd_pipe )==-1 ) {
00347       LM_CRIT("cannot create command pipe: %s!\n", strerror(errno) );
00348       goto error;
00349    }
00350    /* set the writing non blocking */
00351    if ( (val=fcntl(cpl_env.cmd_pipe[1], F_GETFL, 0))<0 ) {
00352       LM_ERR("getting flags from pipe[1] failed: fcntl said %s!\n",
00353             strerror(errno));
00354       goto error;
00355    }
00356    if ( fcntl(cpl_env.cmd_pipe[1], F_SETFL, val|O_NONBLOCK) ) {
00357       LM_ERR("setting flags to pipe[1] failed: fcntl said %s!\n",
00358             strerror(errno));
00359       goto error;
00360    }
00361 
00362    /* init the CPL parser */
00363    if (init_CPL_parser( dtd_file )!=1 ) {
00364       LM_ERR("init_CPL_parser failed!\n");
00365       goto error;
00366    }
00367 
00368    /* make a copy of the original TZ env. variable */
00369    ptr = getenv("TZ");
00370    cpl_env.orig_tz.len = 3/*"TZ="*/ + (ptr?(strlen(ptr)+1):0);
00371    if ( (cpl_env.orig_tz.s=shm_malloc( cpl_env.orig_tz.len ))==0 ) {
00372       LM_ERR("no more shm mem. for saving TZ!\n");
00373       goto error;
00374    }
00375    memcpy(cpl_env.orig_tz.s,"TZ=",3);
00376    if (ptr)
00377       strcpy(cpl_env.orig_tz.s+3,ptr);
00378 
00379    /* convert realm_prefix from string null terminated to str */
00380    if (cpl_env.realm_prefix.s) {
00381       cpl_env.realm_prefix.len = strlen(cpl_env.realm_prefix.s);
00382       /* convert the realm_prefix to lower cases */
00383       strlower( &cpl_env.realm_prefix );
00384    }
00385 
00386    return 0;
00387 error:
00388    return -1;
00389 }
00390 
00391 
00392 
00393 static int cpl_child_init(int rank)
00394 {
00395    return cpl_db_init(&db_url, &db_table);
00396 }
00397 
00398 
00399 static int mi_child_init(void)
00400 {
00401    return cpl_db_init(&db_url, &db_table);
00402 }
00403 
00404 
00405 static void cpl_process(int rank)
00406 {
00407    cpl_aux_process( cpl_env.cmd_pipe[0], cpl_env.log_dir);
00408    exit(-1);
00409 }
00410 
00411 
00412 static int cpl_exit(void)
00413 {
00414    /* free the TZ orig */
00415    if (cpl_env.orig_tz.s)
00416       shm_free(cpl_env.orig_tz.s);
00417 
00418    return 0;
00419 }
00420 
00421 
00422 
00423 static inline int build_user_AOR(str *username, str *domain, str *uh, int sip)
00424 {
00425    unsigned char do_strip;
00426    char *p;
00427    int i;
00428 
00429    /* calculate the len (without terminating \0) */
00430    uh->len = 4*(sip!=0) + username->len;
00431    do_strip = 0;
00432 
00433    if (sip || cpl_env.use_domain) {
00434       /* do we need to strip realm prefix? */
00435       if (cpl_env.realm_prefix.len && cpl_env.realm_prefix.len<domain->len){
00436          for( i=cpl_env.realm_prefix.len-1 ; i>=0 ; i-- )
00437             if ( cpl_env.realm_prefix.s[i]!=tolower(domain->s[i]) )
00438                break;
00439          if (i==-1)
00440             do_strip = 1;
00441       }
00442       uh->len += 1 + domain->len - do_strip*cpl_env.realm_prefix.len;
00443    }
00444 
00445    uh->s = (char*)shm_malloc( uh->len + 1 );
00446    if (!uh->s) {
00447       LM_ERR("no more shm memory.\n");
00448       return -1;
00449    }
00450 
00451    /* build user@host */
00452    p = uh->s;
00453    if (sip) {
00454       memcpy( uh->s, "sip:", 4);
00455       p += 4;
00456    }
00457    /* user part */
00458    if (cpl_env.case_sensitive) {
00459       memcpy( p, username->s, username->len);
00460       p += username->len;
00461    } else {
00462       for(i=0;i<username->len;i++)
00463          *(p++) = tolower(username->s[i]);
00464    }
00465    if (sip || cpl_env.use_domain) {
00466       *(p++) = '@';
00467       /* host part in lower cases */
00468       for( i=do_strip*cpl_env.realm_prefix.len ; i< domain->len ; i++ )
00469          *(p++) = tolower(domain->s[i]);
00470    }
00471    *(p++) = 0;
00472 
00473    /* sanity check */
00474    if (p-uh->s!=uh->len+1) {
00475       LM_CRIT("buffer overflow l=%d,w=%ld\n", uh->len,(long)(p-uh->s));
00476       return -1;
00477    }
00478    return 0;
00479 }
00480 
00481 
00482 
00483 static inline int get_dest_user(struct sip_msg *msg, str *username, str *domain)
00484 {
00485    struct sip_uri uri;
00486 
00487    /*  get the user_name from new_uri/RURI/To */
00488    LM_DBG("trying to get user from new_uri\n");
00489    if ( !msg->new_uri.s || parse_uri( msg->new_uri.s,msg->new_uri.len,&uri)<0
00490    || !uri.user.len )
00491    {
00492       LM_DBG("trying to get user from R_uri\n");
00493       if ( parse_uri( msg->first_line.u.request.uri.s,
00494       msg->first_line.u.request.uri.len ,&uri)==-1 || !uri.user.len )
00495       {
00496          LM_DBG("trying to get user from To\n");
00497          if ( (!msg->to&&((parse_headers(msg,HDR_TO_F,0)==-1)||!msg->to))||
00498          parse_uri( get_to(msg)->uri.s, get_to(msg)->uri.len, &uri)<0
00499          || !uri.user.len)
00500          {
00501             LM_ERR("unable to extract user name from RURI or To header!\n");
00502             return -1;
00503          }
00504       }
00505    }
00506    *username = uri.user;
00507    *domain = uri.host;
00508    return 0;
00509 }
00510 
00511 
00512 
00513 static inline int get_orig_user(struct sip_msg *msg, str *username, str *domain)
00514 {
00515    struct to_body *from;
00516    struct sip_uri uri;
00517    
00518    /* if it's outgoing -> get the user_name from From */
00519    /* parsing from header */
00520    LM_DBG("trying to get user from From\n");
00521    if ( parse_from_header( msg )==-1 ) {
00522       LM_ERR("unable to extract URI from FROM header\n");
00523       return -1;
00524    }
00525    from = (struct to_body*)msg->from->parsed;
00526    /* parse the extracted uri from From */
00527    if (parse_uri( from->uri.s, from->uri.len, &uri)||!uri.user.len) {
00528       LM_ERR("unable to extract user name from URI (From header)\n");
00529       return -1;
00530    }
00531    *username = uri.user;
00532    *domain = uri.host;
00533    return 0;
00534 }
00535 
00536 
00537 
00538 /* Params: 
00539  *   str1 - as unsigned int - can be CPL_RUN_INCOMING or CPL_RUN_OUTGOING 
00540  *   str2 - as unsigned int - flags regarding state(less)|(ful) 
00541  */
00542 static int cpl_invoke_script(struct sip_msg* msg, char* str1, char* str2)
00543 {
00544    struct cpl_interpreter  *cpl_intr;
00545    str  username = {0,0};
00546    str  domain = {0,0};
00547    str  loc;
00548    str  script;
00549 
00550    /* get the user_name */
00551    if ( ((unsigned long)str1)&CPL_RUN_INCOMING ) {
00552       /* if it's incoming -> get the destination user name */
00553       if (get_dest_user( msg, &username, &domain)==-1)
00554          goto error0;
00555    } else {
00556       /* if it's outgoing -> get the origin user name */
00557       if (get_orig_user( msg, &username, &domain)==-1)
00558          goto error0;
00559    }
00560 
00561    /* get the script for this user */
00562    if (get_user_script(&username, cpl_env.use_domain?&domain:0,
00563    &script, &cpl_bin_col)==-1)
00564       goto error0;
00565 
00566    /* has the user a non-empty script? if not, return normally, allowing the
00567     * script execution to continue */
00568    if ( !script.s || !script.len )
00569       return 1;
00570 
00571    /* build a new script interpreter */
00572    if ( (cpl_intr=new_cpl_interpreter(msg,&script))==0 )
00573       goto error1;
00574    /* set the flags */
00575    cpl_intr->flags =(unsigned int)((unsigned long)str1)|((unsigned long)str2);
00576    /* build user AOR */
00577    if (build_user_AOR( &username, &domain, &(cpl_intr->user), 0)!=0 )
00578       goto error2;
00579    /* for OUTGOING we need also the destination user for init. with him
00580     * the location set */
00581    if ( ((unsigned long)str1)&CPL_RUN_OUTGOING ) {
00582       /* build user initial location -> get the destination user name */
00583       if (get_dest_user( msg, &username, &domain)==-1)
00584          goto error2;
00585       if (build_user_AOR( &username, &domain, &loc, 1)!=0 )
00586          goto error2;
00587       if (add_location( &(cpl_intr->loc_set), &loc, 0, 10, 0/*no dup*/)==-1)
00588          goto error2;
00589    }
00590 
00591    /* run the script */
00592    switch (cpl_run_script( cpl_intr )) {
00593       case SCRIPT_DEFAULT:
00594          free_cpl_interpreter( cpl_intr );
00595          return 1; /* execution of ser's script will continue */
00596       case SCRIPT_END:
00597          free_cpl_interpreter( cpl_intr );
00598       case SCRIPT_TO_BE_CONTINUED:
00599          return 0; /* break the SER script */
00600       case SCRIPT_RUN_ERROR:
00601       case SCRIPT_FORMAT_ERROR:
00602          goto error2;
00603    }
00604 
00605    return 1;
00606 error2:
00607    free_cpl_interpreter( cpl_intr );
00608    return -1;
00609 error1:
00610    shm_free(script.s);
00611 error0:
00612    return -1;
00613 }
00614 
00615 
00616 
00617 #define CPL_SCRIPT          "script"
00618 #define CPL_SCRIPT_LEN      (sizeof(CPL_SCRIPT)-1)
00619 #define ACTION_PARAM        "action"
00620 #define ACTION_PARAM_LEN    (sizeof(ACTION_PARAM)-1)
00621 #define STORE_ACTION        "store"
00622 #define STORE_ACTION_LEN    (sizeof(STORE_ACTION)-1)
00623 #define REMOVE_ACTION       "remove"
00624 #define REMOVE_ACTION_LEN   (sizeof(REMOVE_ACTION)-1)
00625 
00626 #define REMOVE_SCRIPT       0xcaca
00627 #define STORE_SCRIPT        0xbebe
00628 
00629 #define CONTENT_TYPE_HDR      ("Content-Type: application/cpl-xml"CRLF)
00630 #define CONTENT_TYPE_HDR_LEN  (sizeof(CONTENT_TYPE_HDR)-1)
00631 
00632 struct cpl_error {
00633    int   err_code;
00634    str   err_msg;
00635 };
00636 
00637 static struct cpl_error bad_req = {400,str_init("Bad request")};
00638 static struct cpl_error intern_err = {500,str_init("Internal server error")};
00639 static struct cpl_error bad_cpl = {400,str_init("Bad CPL script")};
00640 
00641 static struct cpl_error *cpl_err = &bad_req;
00642 
00643 
00644 static inline int do_script_action(struct sip_msg *msg, int action)
00645 {
00646    str  body = {0,0};
00647    str  bin  = {0,0};
00648    str  log  = {0,0};
00649    str  username = {0,0};
00650    str  domain   = {0,0};
00651 
00652    /* content-length (if present) */
00653    if ( !msg->content_length &&
00654    ((parse_headers(msg,HDR_CONTENTLENGTH_F,0)==-1)||!msg->content_length)) {
00655       LM_ERR("no Content-Length hdr found!\n");
00656       goto error;
00657    }
00658    body.len = get_content_length( msg );
00659 
00660    /* get the user name */
00661    if (get_dest_user( msg, &username, &domain)==-1)
00662       goto error;
00663 
00664    /* we have the script and the user */
00665    switch (action) {
00666       case STORE_SCRIPT :
00667          /* check the len -> it must not be 0 */
00668          if (body.len==0) {
00669             LM_ERR("0 content-len found for store\n");
00670             goto error_1;
00671          }
00672          /* get the message's body */
00673          body.s = get_body( msg );
00674          if (body.s==0) {
00675             LM_ERR("cannot extract body from msg!\n");
00676             goto error_1;
00677          }
00678          /* now compile the script and place it into database */
00679          /* get the binary coding for the XML file */
00680          if ( encodeCPL( &body, &bin, &log)!=1) {
00681             cpl_err = &bad_cpl;
00682             goto error_1;
00683          }
00684 
00685          /* write both the XML and binary formats into database */
00686          if (write_to_db( &username, cpl_env.use_domain?&domain:0,
00687          &body,&bin)!=1) {
00688             cpl_err = &intern_err;
00689             goto error_1;
00690          }
00691          break;
00692       case REMOVE_SCRIPT:
00693          /* check the len -> it must be 0 */
00694          if (body.len!=0) {
00695             LM_ERR("non-0 content-len found for remove\n");
00696             goto error_1;
00697          }
00698          /* remove the script for the user */
00699          if (rmv_from_db( &username, cpl_env.use_domain?&domain:0)!=1) {
00700             cpl_err = &intern_err;
00701             goto error_1;
00702          }
00703          break;
00704    }
00705 
00706    if (log.s) pkg_free( log.s );
00707    return 0;
00708 error_1:
00709    if (log.s) pkg_free( log.s );
00710 error:
00711    return -1;
00712 }
00713 
00714 
00715 
00716 static inline int do_script_download(struct sip_msg *msg)
00717 {
00718    str username  = {0,0};
00719    str domain = {0,0};
00720    str script = {0,0};
00721 
00722    /* get the destination user name */
00723    if (get_dest_user( msg, &username, &domain)!=0)
00724       goto error;
00725 
00726    /* get the user's xml script from the database */
00727    if (get_user_script( &username, cpl_env.use_domain?&domain:0,
00728    &script, &cpl_xml_col)==-1)
00729       goto error;
00730 
00731    /* add a lump with content-type hdr */
00732    if (add_lump_rpl( msg, CONTENT_TYPE_HDR, CONTENT_TYPE_HDR_LEN,
00733    LUMP_RPL_HDR)==0) {
00734       LM_ERR("cannot build hdr lump\n");
00735       cpl_err = &intern_err;
00736       goto error;
00737    }
00738 
00739    if (script.s!=0) {
00740       /* user has a script -> add a body lump */
00741       if ( add_lump_rpl( msg, script.s, script.len, LUMP_RPL_BODY)==0) {
00742          LM_ERR("cannot build body lump\n");
00743          cpl_err = &intern_err;
00744          goto error;
00745       }
00746       /* build_lump_rpl duplicates the added text, so free the original */
00747       shm_free( script.s );
00748    }
00749 
00750    return 0;
00751 error:
00752    if (script.s)
00753       shm_free(script.s);
00754    return -1;
00755 }
00756 
00757 
00758 
00759 static int w_process_register(struct sip_msg* msg, char* str, char* str2)
00760 {
00761    return cpl_process_register( msg, 0);
00762 }
00763 
00764 
00765 
00766 static int w_process_register_norpl(struct sip_msg* msg, char* str,char* str2)
00767 {
00768    return cpl_process_register( msg, 1);
00769 }
00770 
00771 
00772 
00773 static int cpl_process_register(struct sip_msg* msg, int no_rpl)
00774 {
00775    struct disposition *disp;
00776    struct disposition_param *param;
00777    int  ret;
00778    int  mime;
00779    int  *mimes;
00780 
00781    /* make sure that is a REGISTER ??? */
00782 
00783    /* here should be the CONTACT- hack */
00784 
00785    /* is there a CONTENT-TYPE hdr ? */
00786    mime = parse_content_type_hdr( msg );
00787    if (mime==-1)
00788       goto error;
00789 
00790    /* check the mime type */
00791    LM_DBG("Content-Type mime found %u, %u\n",
00792       mime>>16,mime&0x00ff);
00793    if ( mime && mime==(TYPE_APPLICATION<<16)+SUBTYPE_CPLXML ) {
00794       /* can be an upload or remove -> check for the content-purpose and
00795        * content-action headers */
00796       LM_DBG("carrying CPL -> look at Content-Disposition\n");
00797       if (parse_content_disposition( msg )!=0) {
00798          LM_ERR("Content-Disposition missing or corrupted\n");
00799          goto error;
00800       }
00801       disp = get_content_disposition(msg);
00802       print_disposition( disp ); /* just for DEBUG */
00803       /* check if the type of disposition is SCRIPT */
00804       if (disp->type.len!=CPL_SCRIPT_LEN ||
00805       strncasecmp(disp->type.s,CPL_SCRIPT,CPL_SCRIPT_LEN) ) {
00806          LM_ERR("bogus message - Content-Type"
00807             "says CPL_SCRIPT, but Content-Disposition something else\n");
00808          goto error;
00809       }
00810       /* disposition type is OK -> look for action parameter */
00811       for(param=disp->params;param;param=param->next) {
00812          if (param->name.len==ACTION_PARAM_LEN &&
00813          !strncasecmp(param->name.s,ACTION_PARAM,ACTION_PARAM_LEN))
00814             break;
00815       }
00816       if (param==0) {
00817          LM_ERR("bogus message - "
00818             "Content-Disposition has no action param\n");
00819          goto error;
00820       }
00821       /* action param found -> check its value: store or remove */
00822       if (param->body.len==STORE_ACTION_LEN &&
00823       !strncasecmp( param->body.s, STORE_ACTION, STORE_ACTION_LEN)) {
00824          /* it's a store action -> get the script from body message and store
00825           * it into database (CPL and BINARY format) */
00826          if (do_script_action( msg, STORE_SCRIPT)==-1)
00827             goto error;
00828       } else
00829       if (param->body.len==REMOVE_ACTION_LEN &&
00830       !strncasecmp( param->body.s, REMOVE_ACTION, REMOVE_ACTION_LEN)) {
00831          /* it's a remove action -> remove the script from database */
00832          if (do_script_action( msg, REMOVE_SCRIPT)==-1)
00833             goto error;
00834       } else {
00835          LM_ERR("unknown action <%.*s>\n",
00836             param->body.len,param->body.s);
00837          goto error;
00838       }
00839 
00840       /* do I have to send to reply? */
00841       if (no_rpl)
00842          goto resume_script;
00843 
00844       /* send a 200 OK reply back */
00845       cpl_fct.slb.send_reply( msg, 200, &cpl_ok_rpl);
00846       /* I send the reply and I don't want to return to script execution, so
00847        * I return 0 to do break */
00848       goto stop_script;
00849    }
00850 
00851    /* is there an ACCEPT hdr ? */
00852    if ( (ret=parse_accept_hdr(msg))<0)
00853       goto error;
00854    if (ret==0 || (mimes=get_accept(msg))==0 )
00855       /* accept header not present or no mimes found */
00856       goto resume_script;
00857 
00858    /* looks if the REGISTER accepts cpl-xml or * */
00859    while (*mimes) {
00860       LM_DBG("accept mime found %u, %u\n",
00861          (*mimes)>>16,(*mimes)&0x00ff);
00862       if (*mimes==(TYPE_ALL<<16)+SUBTYPE_ALL ||
00863       *mimes==(TYPE_APPLICATION<<16)+SUBTYPE_CPLXML )
00864          break;
00865       mimes++;
00866    }
00867    if (*mimes==0)
00868       /* no accept mime that matched cpl */
00869       goto resume_script;
00870 
00871    /* get the user name from msg, retrieve the script from db
00872     * and appended to reply */
00873    if (do_script_download( msg )==-1)
00874       goto error;
00875 
00876    /* do I have to send to reply? */
00877    if (no_rpl)
00878       goto resume_script;
00879 
00880    /* send a 200 OK reply back */
00881    cpl_fct.slb.send_reply( msg, 200, &cpl_ok_rpl);
00882 
00883 stop_script:
00884    return 0;
00885 resume_script:
00886    return 1;
00887 error:
00888    /* send a error reply back */
00889    cpl_fct.slb.send_reply( msg, cpl_err->err_code, &cpl_err->err_msg);
00890    /* I don't want to return to script execution, so I return 0 to do break */
00891    return 0;
00892 }

Generated on Mon May 21 18:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6