modules_k/diversion/diversion.c

00001 /* 
00002  * $Id$
00003  *
00004  * Diversion Header Field Support
00005  *
00006  * Copyright (C) 2004 FhG Fokus
00007  *
00008  * This file is part of Kamailio, a free SIP server.
00009  *
00010  * Kamailio is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version
00014  *
00015  * Kamailio is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License 
00021  * along with this program; if not, write to the Free Software 
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  */
00025 
00026 #include <stdio.h>
00027 #include <string.h>
00028 #include "../../sr_module.h"
00029 #include "../../error.h"
00030 #include "../../dprint.h"
00031 #include "../../mem/mem.h"
00032 #include "../../data_lump.h"
00033 #include "../../mod_fix.h"
00034 
00035 
00036 MODULE_VERSION
00037 
00038 #define DIVERSION_HF "Diversion"
00039 #define DIVERSION_HF_LEN (sizeof(DIVERSION_HF) - 1)
00040 
00041 #define DIVERSION_PREFIX     DIVERSION_HF ": <"
00042 #define DIVERSION_PREFIX_LEN (sizeof(DIVERSION_PREFIX) - 1)
00043 
00044 #define DIVERSION_SUFFIX     ">;reason="
00045 #define DIVERSION_SUFFIX_LEN (sizeof(DIVERSION_SUFFIX) - 1)
00046 
00047 
00048 
00049 str suffix = {"", 0};
00050 
00051 int add_diversion(struct sip_msg* msg, char* r, char* u);
00052 
00053 /*
00054  * Module initialization function prototype
00055  */
00056 static int mod_init(void);
00057 
00058 
00059 /*
00060  * Exported functions
00061  */
00062 static cmd_export_t cmds[] = {
00063         {"add_diversion",    (cmd_function)add_diversion,    1, fixup_spve_null,
00064                 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
00065         {"add_diversion",    (cmd_function)add_diversion,    2, fixup_spve_spve,
00066                 0, REQUEST_ROUTE|FAILURE_ROUTE|BRANCH_ROUTE},
00067         {0, 0, 0, 0, 0, 0}
00068 };
00069 
00070 
00071 /*
00072  * Exported parameters
00073  */
00074 static param_export_t params[] = {
00075         {"suffix", STR_PARAM, &suffix.s},
00076         {0, 0, 0}
00077 };
00078 
00079 
00080 /*
00081  * Module interface
00082  */
00083 struct module_exports exports = {
00084         "diversion", 
00085         DEFAULT_DLFLAGS, /* dlopen flags */
00086         cmds,       /* Exported functions */
00087         params,     /* Exported parameters */
00088         0,          /* exported statistics */
00089         0,          /* exported MI functions */
00090         0,          /* exported pseudo-variables */
00091         0,          /* extra processes */
00092         mod_init,   /* module initialization function */
00093         0,          /* response function */
00094         0,          /* destroy function */
00095         0           /* child initialization function */
00096 };
00097 
00098 
00099 static int mod_init(void)
00100 {
00101         suffix.len = strlen(suffix.s);
00102         return 0;
00103 }
00104 
00105 
00106 static inline int add_diversion_helper(struct sip_msg* msg, str* s)
00107 {
00108         char *ptr;
00109         int is_ref;
00110 
00111         struct lump* anchor = 0;
00112 
00113         if (!msg->diversion && parse_headers(msg, HDR_DIVERSION_F, 0) == -1) {
00114                 LM_ERR("header parsing failed\n");
00115                 return -1;
00116         }
00117         
00118         if (msg->diversion) {
00119                      /* Insert just before the topmost Diversion header */
00120                 ptr = msg->diversion->name.s;
00121         } else {
00122                      /* Insert at the end */
00123                 ptr = msg->unparsed;
00124         }
00125 
00126         anchor = anchor_lump2(msg, ptr - msg->buf, 0, 0, &is_ref);
00127         if (!anchor) {
00128                 LM_ERR("can't get anchor\n");
00129                 return -2;
00130         }
00131         
00132         if (!insert_new_lump_before(anchor, s->s, s->len, 0)) {
00133                 LM_ERR("can't insert lump\n");
00134                 return -3;
00135         }
00136 
00137         return 0;
00138 }
00139 
00140 
00141 int add_diversion(struct sip_msg* msg, char* r, char* u)
00142 {
00143         str div_hf;
00144         char *at;
00145         str uri;
00146         str reason;
00147 
00148         if(fixup_get_svalue(msg, (gparam_t*)r, &reason)<0)
00149         {
00150                 LM_ERR("cannot get the script\n");
00151                 return -1;
00152         }
00153 
00154 
00155         if(u==NULL) {
00156                 uri = msg->first_line.u.request.uri;
00157         } else {
00158                 if(fixup_get_svalue(msg, (gparam_t*)u, &uri)<0)
00159                 {
00160                         LM_ERR("cannot get the uri parameter\n");
00161                         return -1;
00162                 }
00163         }
00164 
00165         div_hf.len = DIVERSION_PREFIX_LEN + uri.len + DIVERSION_SUFFIX_LEN + reason.len + CRLF_LEN;
00166         div_hf.s = pkg_malloc(div_hf.len);
00167         if (!div_hf.s) {
00168                 LM_ERR("no pkg memory left\n");
00169                 return -1;
00170         }
00171 
00172         at = div_hf.s;
00173         memcpy(at, DIVERSION_PREFIX, DIVERSION_PREFIX_LEN);
00174         at += DIVERSION_PREFIX_LEN;
00175 
00176         memcpy(at, uri.s, uri.len);
00177         at += uri.len;
00178 
00179         memcpy(at, DIVERSION_SUFFIX, DIVERSION_SUFFIX_LEN);
00180         at += DIVERSION_SUFFIX_LEN;
00181 
00182         memcpy(at, reason.s, reason.len);
00183         at += reason.len;
00184 
00185         memcpy(at, CRLF, CRLF_LEN);
00186 
00187         if (add_diversion_helper(msg, &div_hf) < 0) {
00188                 pkg_free(div_hf.s);
00189                 return -1;
00190         }
00191 
00192         return 1;
00193 }