mirror of https://github.com/sipwise/kamailio.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1601 lines
39 KiB
1601 lines
39 KiB
/*
|
|
* MSILO module
|
|
*
|
|
* Copyright (C) 2001-2003 FhG Fokus
|
|
*
|
|
* This file is part of Kamailio, a free SIP server.
|
|
*
|
|
* Kamailio is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version
|
|
*
|
|
* Kamailio is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
*
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <sys/types.h>
|
|
#include <sys/ipc.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <time.h>
|
|
|
|
#include "../../sr_module.h"
|
|
#include "../../dprint.h"
|
|
#include "../../ut.h"
|
|
#include "../../timer.h"
|
|
#include "../../mem/shm_mem.h"
|
|
#include "../../lib/srdb1/db.h"
|
|
#include "../../parser/parse_from.h"
|
|
#include "../../parser/parse_content.h"
|
|
#include "../../parser/contact/parse_contact.h"
|
|
#include "../../parser/parse_allow.h"
|
|
#include "../../parser/parse_methods.h"
|
|
#include "../../resolve.h"
|
|
#include "../../usr_avp.h"
|
|
#include "../../mod_fix.h"
|
|
|
|
#include "../../modules/tm/tm_load.h"
|
|
|
|
#include "ms_msg_list.h"
|
|
#include "msfuncs.h"
|
|
#include "api.h"
|
|
|
|
#define MAX_DEL_KEYS 1
|
|
#define NR_KEYS 11
|
|
|
|
static str sc_mid = str_init("id"); /* 0 */
|
|
static str sc_from = str_init("src_addr"); /* 1 */
|
|
static str sc_to = str_init("dst_addr"); /* 2 */
|
|
static str sc_uri_user = str_init("username"); /* 3 */
|
|
static str sc_uri_host = str_init("domain"); /* 4 */
|
|
static str sc_body = str_init("body"); /* 5 */
|
|
static str sc_ctype = str_init("ctype"); /* 6 */
|
|
static str sc_exp_time = str_init("exp_time"); /* 7 */
|
|
static str sc_inc_time = str_init("inc_time"); /* 8 */
|
|
static str sc_snd_time = str_init("snd_time"); /* 9 */
|
|
static str sc_stored_hdrs = str_init("extra_hdrs"); /* 10 */
|
|
|
|
#define SET_STR_VAL(_str, _res, _r, _c) \
|
|
if (RES_ROWS(_res)[_r].values[_c].nul == 0) \
|
|
{ \
|
|
switch(RES_ROWS(_res)[_r].values[_c].type) \
|
|
{ \
|
|
case DB1_STRING: \
|
|
(_str).s=(char*)RES_ROWS(_res)[_r].values[_c].val.string_val; \
|
|
(_str).len=strlen((_str).s); \
|
|
break; \
|
|
case DB1_STR: \
|
|
(_str).len=RES_ROWS(_res)[_r].values[_c].val.str_val.len; \
|
|
(_str).s=(char*)RES_ROWS(_res)[_r].values[_c].val.str_val.s; \
|
|
break; \
|
|
case DB1_BLOB: \
|
|
(_str).len=RES_ROWS(_res)[_r].values[_c].val.blob_val.len; \
|
|
(_str).s=(char*)RES_ROWS(_res)[_r].values[_c].val.blob_val.s; \
|
|
break; \
|
|
default: \
|
|
(_str).len=0; \
|
|
(_str).s=NULL; \
|
|
} \
|
|
}
|
|
|
|
MODULE_VERSION
|
|
|
|
#define S_TABLE_VERSION 8
|
|
|
|
/** database connection */
|
|
static db1_con_t *db_con = NULL;
|
|
static db_func_t msilo_dbf;
|
|
|
|
/** precessed msg list - used for dumping the messages */
|
|
msg_list ml = NULL;
|
|
|
|
/** TM bind */
|
|
struct tm_binds tmb;
|
|
|
|
/** parameters */
|
|
|
|
static str ms_db_url = str_init(DEFAULT_DB_URL);
|
|
static str ms_db_table = str_init("silo");
|
|
str ms_reminder = {NULL, 0};
|
|
str ms_outbound_proxy = {NULL, 0};
|
|
|
|
char* ms_from = NULL; /*"sip:registrar@example.org";*/
|
|
char* ms_contact = NULL; /*"Contact: <sip:registrar@example.org>\r\n";*/
|
|
char* ms_extra_hdrs = NULL; /*"X-foo: bar\r\nX-bar: foo\r\n";*/
|
|
char* ms_content_type = NULL; /*"Content-Type: text/plain\r\n";*/
|
|
char* ms_offline_message = NULL; /*"<em>I'm offline.</em>"*/
|
|
void** ms_from_sp = NULL;
|
|
void** ms_contact_sp = NULL;
|
|
void** ms_extra_hdrs_sp = NULL;
|
|
void** ms_content_type_sp = NULL;
|
|
void** ms_offline_message_sp = NULL;
|
|
|
|
int ms_expire_time = 259200;
|
|
int ms_check_time = 60;
|
|
int ms_send_time = 0;
|
|
int ms_clean_period = 10;
|
|
int ms_use_contact = 1;
|
|
int ms_add_date = 1;
|
|
int ms_add_contact = 0;
|
|
int ms_max_messages = 0;
|
|
|
|
static str ms_snd_time_avp_param = {NULL, 0};
|
|
int_str ms_snd_time_avp_name;
|
|
unsigned short ms_snd_time_avp_type;
|
|
|
|
static str ms_extra_hdrs_avp_param = {NULL, 0};
|
|
int_str ms_extra_hdrs_avp_name;
|
|
unsigned short ms_extra_hdrs_avp_type;
|
|
|
|
str msg_type = str_init("MESSAGE");
|
|
static int ms_skip_notification_flag = -1;
|
|
|
|
/** module functions */
|
|
static int mod_init(void);
|
|
static int child_init(int);
|
|
|
|
static int m_store(struct sip_msg*, str*);
|
|
static int m_dump(struct sip_msg*, str*);
|
|
|
|
static int m_store_2(struct sip_msg*, char*, char*);
|
|
static int m_dump_2(struct sip_msg*, char*, char*);
|
|
|
|
static void destroy(void);
|
|
|
|
static int bind_msilo(msilo_api_t* api);
|
|
|
|
void m_clean_silo(unsigned int ticks, void *);
|
|
void m_send_ontimer(unsigned int ticks, void *);
|
|
|
|
int ms_reset_stime(int mid);
|
|
|
|
int check_message_support(struct sip_msg* msg);
|
|
|
|
|
|
/** TM callback function */
|
|
static void m_tm_callback( struct cell *t, int type, struct tmcb_params *ps);
|
|
|
|
static cmd_export_t cmds[]={
|
|
{"m_store", (cmd_function)m_store_2, 0, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE},
|
|
{"m_store", (cmd_function)m_store_2, 1, fixup_spve_null, 0,
|
|
REQUEST_ROUTE | FAILURE_ROUTE},
|
|
{"m_dump", (cmd_function)m_dump_2, 0, 0, 0, REQUEST_ROUTE},
|
|
{"m_dump", (cmd_function)m_dump_2, 1, fixup_spve_null, 0,
|
|
REQUEST_ROUTE},
|
|
{"bind_msilo",(cmd_function)bind_msilo, 1, 0, 0, ANY_ROUTE},
|
|
{0,0,0,0,0,0}
|
|
};
|
|
|
|
|
|
static param_export_t params[]={
|
|
{ "db_url", PARAM_STR, &ms_db_url },
|
|
{ "db_table", PARAM_STR, &ms_db_table },
|
|
{ "from_address", PARAM_STRING, &ms_from },
|
|
{ "contact_hdr", PARAM_STRING, &ms_contact },
|
|
{ "extra_hdrs", PARAM_STRING, &ms_extra_hdrs },
|
|
{ "content_type_hdr", PARAM_STRING, &ms_content_type },
|
|
{ "offline_message", PARAM_STRING, &ms_offline_message },
|
|
{ "reminder", PARAM_STR, &ms_reminder },
|
|
{ "outbound_proxy", PARAM_STR, &ms_outbound_proxy },
|
|
{ "expire_time", INT_PARAM, &ms_expire_time },
|
|
{ "check_time", INT_PARAM, &ms_check_time },
|
|
{ "send_time", INT_PARAM, &ms_send_time },
|
|
{ "clean_period", INT_PARAM, &ms_clean_period },
|
|
{ "use_contact", INT_PARAM, &ms_use_contact },
|
|
{ "sc_mid", PARAM_STR, &sc_mid },
|
|
{ "sc_from", PARAM_STR, &sc_from },
|
|
{ "sc_to", PARAM_STR, &sc_to },
|
|
{ "sc_uri_user", PARAM_STR, &sc_uri_user },
|
|
{ "sc_uri_host", PARAM_STR, &sc_uri_host },
|
|
{ "sc_body", PARAM_STR, &sc_body },
|
|
{ "sc_ctype", PARAM_STR, &sc_ctype },
|
|
{ "sc_exp_time", PARAM_STR, &sc_exp_time },
|
|
{ "sc_inc_time", PARAM_STR, &sc_inc_time },
|
|
{ "sc_snd_time", PARAM_STR, &sc_snd_time },
|
|
{ "sc_stored_hdrs", PARAM_STR, &sc_stored_hdrs },
|
|
{ "snd_time_avp", PARAM_STR, &ms_snd_time_avp_param },
|
|
{ "extra_hdrs_avp", PARAM_STR, &ms_extra_hdrs_avp_param },
|
|
{ "add_date", INT_PARAM, &ms_add_date },
|
|
{ "max_messages", INT_PARAM, &ms_max_messages },
|
|
{ "add_contact", INT_PARAM, &ms_add_contact },
|
|
{ "skip_notification_flag", PARAM_INT, &ms_skip_notification_flag },
|
|
{ 0,0,0 }
|
|
};
|
|
|
|
#ifdef STATISTICS
|
|
#include "../../lib/kcore/statistics.h"
|
|
|
|
stat_var* ms_stored_msgs;
|
|
stat_var* ms_dumped_msgs;
|
|
stat_var* ms_failed_msgs;
|
|
stat_var* ms_dumped_rmds;
|
|
stat_var* ms_failed_rmds;
|
|
|
|
stat_export_t msilo_stats[] = {
|
|
{"stored_messages" , 0, &ms_stored_msgs },
|
|
{"dumped_messages" , 0, &ms_dumped_msgs },
|
|
{"failed_messages" , 0, &ms_failed_msgs },
|
|
{"dumped_reminders" , 0, &ms_dumped_rmds },
|
|
{"failed_reminders" , 0, &ms_failed_rmds },
|
|
{0,0,0}
|
|
};
|
|
|
|
#endif
|
|
/** module exports */
|
|
struct module_exports exports= {
|
|
"msilo", /* module id */
|
|
DEFAULT_DLFLAGS, /* dlopen flags */
|
|
cmds, /* module's exported functions */
|
|
params, /* module's exported parameters */
|
|
#ifdef STATISTICS
|
|
msilo_stats,
|
|
#else
|
|
0, /* exported statistics */
|
|
#endif
|
|
0, /* exported MI functions */
|
|
0, /* exported pseudo-variables */
|
|
0, /* extra processes */
|
|
mod_init, /* module initialization function */
|
|
0, /* response handler */
|
|
(destroy_function) destroy, /* module destroy function */
|
|
child_init /* per-child init function */
|
|
};
|
|
|
|
static int bind_msilo(msilo_api_t* api)
|
|
{
|
|
if (!api) {
|
|
return -1;
|
|
}
|
|
api->m_store = m_store;
|
|
api->m_dump = m_dump;
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* init module function
|
|
*/
|
|
static int mod_init(void)
|
|
{
|
|
pv_spec_t avp_spec;
|
|
|
|
#ifdef STATISTICS
|
|
/* register statistics */
|
|
if (register_module_stats( exports.name, msilo_stats)!=0 ) {
|
|
LM_ERR("failed to register core statistics\n");
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
if(ms_skip_notification_flag!=-1) {
|
|
if(ms_skip_notification_flag<0 || ms_skip_notification_flag>31) {
|
|
LM_ERR("invalid skip notification flag value: %d\n",
|
|
ms_skip_notification_flag);
|
|
return -1;
|
|
}
|
|
ms_skip_notification_flag = 1 << ms_skip_notification_flag;
|
|
}
|
|
|
|
/* binding to mysql module */
|
|
if (db_bind_mod(&ms_db_url, &msilo_dbf))
|
|
{
|
|
LM_DBG("database module not found\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!DB_CAPABILITY(msilo_dbf, DB_CAP_ALL)) {
|
|
LM_ERR("database module does not implement "
|
|
"all functions needed by the module\n");
|
|
return -1;
|
|
}
|
|
|
|
if (ms_snd_time_avp_param.s && ms_snd_time_avp_param.len > 0) {
|
|
if (pv_parse_spec(&ms_snd_time_avp_param, &avp_spec)==0
|
|
|| avp_spec.type!=PVT_AVP) {
|
|
LM_ERR("malformed or non AVP %.*s AVP definition\n",
|
|
ms_snd_time_avp_param.len, ms_snd_time_avp_param.s);
|
|
return -1;
|
|
}
|
|
|
|
if(pv_get_avp_name(0, &(avp_spec.pvp), &ms_snd_time_avp_name,
|
|
&ms_snd_time_avp_type)!=0)
|
|
{
|
|
LM_ERR("[%.*s]- invalid AVP definition\n",
|
|
ms_snd_time_avp_param.len, ms_snd_time_avp_param.s);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (ms_extra_hdrs_avp_param.s && ms_extra_hdrs_avp_param.len > 0) {
|
|
if (pv_parse_spec(&ms_extra_hdrs_avp_param, &avp_spec)==0
|
|
|| avp_spec.type!=PVT_AVP) {
|
|
LM_ERR("malformed or non AVP %.*s AVP definition\n",
|
|
ms_extra_hdrs_avp_param.len, ms_extra_hdrs_avp_param.s);
|
|
return -1;
|
|
}
|
|
|
|
if (pv_get_avp_name(0, &(avp_spec.pvp), &ms_extra_hdrs_avp_name,
|
|
&ms_extra_hdrs_avp_type) != 0) {
|
|
LM_ERR("[%.*s]- invalid AVP definition\n",
|
|
ms_extra_hdrs_avp_param.len, ms_extra_hdrs_avp_param.s);
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
db_con = msilo_dbf.init(&ms_db_url);
|
|
if (!db_con)
|
|
{
|
|
LM_ERR("failed to connect to the database\n");
|
|
return -1;
|
|
}
|
|
|
|
if(db_check_table_version(&msilo_dbf, db_con, &ms_db_table, S_TABLE_VERSION) < 0) {
|
|
LM_ERR("error during table version check.\n");
|
|
return -1;
|
|
}
|
|
if(db_con)
|
|
msilo_dbf.close(db_con);
|
|
db_con = NULL;
|
|
|
|
/* load the TM API */
|
|
if (load_tm_api(&tmb)!=0) {
|
|
LM_ERR("can't load TM API\n");
|
|
return -1;
|
|
}
|
|
|
|
if(ms_from!=NULL)
|
|
{
|
|
ms_from_sp = (void**)pkg_malloc(sizeof(void*));
|
|
if(ms_from_sp==NULL)
|
|
{
|
|
LM_ERR("no more pkg\n");
|
|
return -1;
|
|
}
|
|
*ms_from_sp = (void*)ms_from;
|
|
if(fixup_spve_null(ms_from_sp, 1)!=0)
|
|
{
|
|
LM_ERR("bad contact parameter\n");
|
|
return -1;
|
|
}
|
|
}
|
|
if(ms_contact!=NULL)
|
|
{
|
|
ms_contact_sp = (void**)pkg_malloc(sizeof(void*));
|
|
if(ms_contact_sp==NULL)
|
|
{
|
|
LM_ERR("no more pkg\n");
|
|
return -1;
|
|
}
|
|
*ms_contact_sp = (void*)ms_contact;
|
|
if(fixup_spve_null(ms_contact_sp, 1)!=0)
|
|
{
|
|
LM_ERR("bad contact parameter\n");
|
|
return -1;
|
|
}
|
|
}
|
|
if(ms_extra_hdrs!=NULL)
|
|
{
|
|
ms_extra_hdrs_sp = (void**)pkg_malloc(sizeof(void*));
|
|
if(ms_extra_hdrs_sp==NULL)
|
|
{
|
|
LM_ERR("no more pkg\n");
|
|
return -1;
|
|
}
|
|
*ms_extra_hdrs_sp = (void*)ms_extra_hdrs;
|
|
if(fixup_spve_null(ms_extra_hdrs_sp, 1)!=0)
|
|
{
|
|
LM_ERR("bad extra_hdrs parameter\n");
|
|
return -1;
|
|
}
|
|
}
|
|
if(ms_content_type!=NULL)
|
|
{
|
|
ms_content_type_sp = (void**)pkg_malloc(sizeof(void*));
|
|
if(ms_content_type_sp==NULL)
|
|
{
|
|
LM_ERR("no more pkg\n");
|
|
return -1;
|
|
}
|
|
*ms_content_type_sp = (void*)ms_content_type;
|
|
if(fixup_spve_null(ms_content_type_sp, 1)!=0)
|
|
{
|
|
LM_ERR("bad content_type parameter\n");
|
|
return -1;
|
|
}
|
|
}
|
|
if(ms_offline_message!=NULL)
|
|
{
|
|
ms_offline_message_sp = (void**)pkg_malloc(sizeof(void*));
|
|
if(ms_offline_message_sp==NULL)
|
|
{
|
|
LM_ERR("no more pkg\n");
|
|
return -1;
|
|
}
|
|
*ms_offline_message_sp = (void*)ms_offline_message;
|
|
if(fixup_spve_null(ms_offline_message_sp, 1)!=0)
|
|
{
|
|
LM_ERR("bad offline_message parameter\n");
|
|
return -1;
|
|
}
|
|
}
|
|
if(ms_offline_message!=NULL && ms_content_type==NULL)
|
|
{
|
|
LM_ERR("content_type parameter must be set\n");
|
|
return -1;
|
|
}
|
|
|
|
ml = msg_list_init();
|
|
if(ml==NULL)
|
|
{
|
|
LM_ERR("can't initialize msg list\n");
|
|
return -1;
|
|
}
|
|
if(ms_check_time<0)
|
|
{
|
|
LM_ERR("bad check time value\n");
|
|
return -1;
|
|
}
|
|
register_timer(m_clean_silo, 0, ms_check_time);
|
|
if(ms_send_time>0 && ms_reminder.s!=NULL)
|
|
register_timer(m_send_ontimer, 0, ms_send_time);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Initialize children
|
|
*/
|
|
static int child_init(int rank)
|
|
{
|
|
if (rank==PROC_INIT || rank==PROC_MAIN || rank==PROC_TCP_MAIN)
|
|
return 0; /* do nothing for the main process */
|
|
|
|
LM_DBG("rank #%d / pid <%d>\n", rank, getpid());
|
|
if (msilo_dbf.init==0)
|
|
{
|
|
LM_CRIT("database not bound\n");
|
|
return -1;
|
|
}
|
|
db_con = msilo_dbf.init(&ms_db_url);
|
|
if (!db_con)
|
|
{
|
|
LM_ERR("child %d: failed to connect database\n", rank);
|
|
return -1;
|
|
}
|
|
else
|
|
{
|
|
if (msilo_dbf.use_table(db_con, &ms_db_table) < 0) {
|
|
LM_ERR("child %d: failed in use_table\n", rank);
|
|
return -1;
|
|
}
|
|
|
|
LM_DBG("#%d database connection opened successfully\n", rank);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* get_non_mandatory_headers
|
|
* Extracts additional headers into the given buffer for storing alongside the message
|
|
* returns the length of the created data
|
|
*
|
|
* It is assumed that all headers have been parsed at this point
|
|
*/
|
|
static int get_non_mandatory_headers(struct sip_msg *msg, char *buf, int buf_len)
|
|
{
|
|
struct hdr_field *hdrs;
|
|
int len = 0;
|
|
int_str avp_value;
|
|
struct usr_avp *avp;
|
|
|
|
if (ms_extra_hdrs_avp_name.n != 0) {
|
|
avp = NULL;
|
|
avp = search_first_avp(ms_extra_hdrs_avp_type,
|
|
ms_extra_hdrs_avp_name, &avp_value, 0);
|
|
if ((avp != NULL) && is_avp_str_val(avp)) {
|
|
if (buf_len <= avp_value.s.len) {
|
|
LM_ERR("insufficient space to store headers in silo\n");
|
|
return -1;
|
|
}
|
|
memcpy(buf, avp_value.s.s, avp_value.s.len);
|
|
return avp_value.s.len;
|
|
}
|
|
}
|
|
|
|
for (hdrs = msg->headers; hdrs != NULL; hdrs = hdrs->next)
|
|
{
|
|
switch (hdrs->type) {
|
|
case HDR_OTHER_T:
|
|
case HDR_PPI_T:
|
|
case HDR_PAI_T:
|
|
case HDR_PRIVACY_T:
|
|
if (buf_len <= hdrs->len)
|
|
{
|
|
LM_ERR("Insufficient space to store headers in silo\n");
|
|
return -1;
|
|
}
|
|
memcpy(buf, hdrs->name.s, hdrs->len);
|
|
len += hdrs->len;
|
|
buf += hdrs->len;
|
|
buf_len -= hdrs->len;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
return len;
|
|
}
|
|
|
|
/**
|
|
* store message
|
|
* mode = "0" -- look for outgoing URI starting with new_uri
|
|
* = "1" -- look for outgoing URI starting with r-uri
|
|
* = "2" -- look for outgoing URI only at to header
|
|
*/
|
|
|
|
static int m_store(struct sip_msg* msg, str *owner_s)
|
|
{
|
|
str body, str_hdr, ctaddr;
|
|
struct to_body *pto, *pfrom;
|
|
struct sip_uri puri;
|
|
str duri;
|
|
#define EXTRA_HDRS_BUF_LEN 1024
|
|
static char extra_hdrs_buf[EXTRA_HDRS_BUF_LEN];
|
|
str extra_hdrs;
|
|
db_key_t db_keys[NR_KEYS-1];
|
|
db_val_t db_vals[NR_KEYS-1];
|
|
db_key_t db_cols[1];
|
|
db1_res_t* res = NULL;
|
|
uac_req_t uac_r;
|
|
|
|
int nr_keys = 0, val, lexpire;
|
|
content_type_t ctype;
|
|
#define MS_BUF1_SIZE 1024
|
|
static char ms_buf1[MS_BUF1_SIZE];
|
|
int mime;
|
|
str notify_from;
|
|
str notify_body;
|
|
str notify_ctype;
|
|
str notify_contact;
|
|
|
|
int_str avp_value;
|
|
struct usr_avp *avp;
|
|
|
|
LM_DBG("------------ start ------------\n");
|
|
|
|
/* get message body - after that whole SIP MESSAGE is parsed */
|
|
body.s = get_body( msg );
|
|
if (body.s==0)
|
|
{
|
|
LM_ERR("cannot extract body from msg\n");
|
|
goto error;
|
|
}
|
|
|
|
/* content-length (if present) must be already parsed */
|
|
if (!msg->content_length)
|
|
{
|
|
LM_ERR("no Content-Length header found!\n");
|
|
goto error;
|
|
}
|
|
body.len = get_content_length( msg );
|
|
|
|
/* check if the body of message contains something */
|
|
if(body.len <= 0)
|
|
{
|
|
LM_ERR("body of the message is empty!\n");
|
|
goto error;
|
|
}
|
|
|
|
/* get TO URI */
|
|
if(parse_to_header(msg)<0)
|
|
{
|
|
LM_ERR("failed getting 'to' header!\n");
|
|
goto error;
|
|
}
|
|
|
|
pto = get_to(msg);
|
|
|
|
/* get the owner */
|
|
memset(&puri, 0, sizeof(struct sip_uri));
|
|
if(owner_s != NULL)
|
|
{
|
|
if(parse_uri(owner_s->s, owner_s->len, &puri)!=0)
|
|
{
|
|
LM_ERR("bad owner SIP address!\n");
|
|
goto error;
|
|
} else {
|
|
LM_DBG("using user id [%.*s]\n", owner_s->len, owner_s->s);
|
|
}
|
|
} else { /* get it from R-URI */
|
|
if(msg->new_uri.len <= 0)
|
|
{
|
|
if(msg->first_line.u.request.uri.len <= 0)
|
|
{
|
|
LM_ERR("bad dst URI!\n");
|
|
goto error;
|
|
}
|
|
duri = msg->first_line.u.request.uri;
|
|
} else {
|
|
duri = msg->new_uri;
|
|
}
|
|
LM_DBG("NEW R-URI found - check if is AoR!\n");
|
|
if(parse_uri(duri.s, duri.len, &puri)!=0)
|
|
{
|
|
LM_ERR("bad dst R-URI!!\n");
|
|
goto error;
|
|
}
|
|
}
|
|
if(puri.user.len<=0)
|
|
{
|
|
LM_ERR("no username for owner\n");
|
|
goto error;
|
|
}
|
|
|
|
db_keys[nr_keys] = &sc_uri_user;
|
|
|
|
db_vals[nr_keys].type = DB1_STR;
|
|
db_vals[nr_keys].nul = 0;
|
|
db_vals[nr_keys].val.str_val.s = puri.user.s;
|
|
db_vals[nr_keys].val.str_val.len = puri.user.len;
|
|
|
|
nr_keys++;
|
|
|
|
db_keys[nr_keys] = &sc_uri_host;
|
|
|
|
db_vals[nr_keys].type = DB1_STR;
|
|
db_vals[nr_keys].nul = 0;
|
|
db_vals[nr_keys].val.str_val.s = puri.host.s;
|
|
db_vals[nr_keys].val.str_val.len = puri.host.len;
|
|
|
|
nr_keys++;
|
|
|
|
if (msilo_dbf.use_table(db_con, &ms_db_table) < 0)
|
|
{
|
|
LM_ERR("failed to use_table\n");
|
|
goto error;
|
|
}
|
|
|
|
if (ms_max_messages > 0) {
|
|
db_cols[0] = &sc_inc_time;
|
|
if (msilo_dbf.query(db_con, db_keys, 0, db_vals, db_cols,
|
|
2, 1, 0, &res) < 0 ) {
|
|
LM_ERR("failed to query the database\n");
|
|
return -1;
|
|
}
|
|
if (RES_ROW_N(res) >= ms_max_messages) {
|
|
LM_ERR("too many messages for AoR '%.*s@%.*s'\n",
|
|
puri.user.len, puri.user.s, puri.host.len, puri.host.s);
|
|
msilo_dbf.free_result(db_con, res);
|
|
return -1;
|
|
}
|
|
msilo_dbf.free_result(db_con, res);
|
|
}
|
|
|
|
/* Set To key */
|
|
db_keys[nr_keys] = &sc_to;
|
|
|
|
db_vals[nr_keys].type = DB1_STR;
|
|
db_vals[nr_keys].nul = 0;
|
|
db_vals[nr_keys].val.str_val.s = pto->uri.s;
|
|
db_vals[nr_keys].val.str_val.len = pto->uri.len;
|
|
|
|
nr_keys++;
|
|
|
|
/* check FROM URI */
|
|
if ( parse_from_header( msg )<0 )
|
|
{
|
|
LM_ERR("cannot parse From header\n");
|
|
goto error;
|
|
}
|
|
pfrom = get_from(msg);
|
|
LM_DBG("'From' header: <%.*s>\n", pfrom->uri.len, pfrom->uri.s);
|
|
|
|
db_keys[nr_keys] = &sc_from;
|
|
|
|
db_vals[nr_keys].type = DB1_STR;
|
|
db_vals[nr_keys].nul = 0;
|
|
db_vals[nr_keys].val.str_val.s = pfrom->uri.s;
|
|
db_vals[nr_keys].val.str_val.len = pfrom->uri.len;
|
|
|
|
nr_keys++;
|
|
|
|
/* add the message's body in SQL query */
|
|
|
|
db_keys[nr_keys] = &sc_body;
|
|
|
|
db_vals[nr_keys].type = DB1_BLOB;
|
|
db_vals[nr_keys].nul = 0;
|
|
db_vals[nr_keys].val.blob_val.s = body.s;
|
|
db_vals[nr_keys].val.blob_val.len = body.len;
|
|
|
|
nr_keys++;
|
|
|
|
lexpire = ms_expire_time;
|
|
/* add 'content-type' -- parse the content-type header */
|
|
if ((mime=parse_content_type_hdr(msg))<1 )
|
|
{
|
|
LM_ERR("cannot parse Content-Type header\n");
|
|
goto error;
|
|
}
|
|
|
|
db_keys[nr_keys] = &sc_ctype;
|
|
db_vals[nr_keys].type = DB1_STR;
|
|
db_vals[nr_keys].nul = 0;
|
|
db_vals[nr_keys].val.str_val.s = "text/plain";
|
|
db_vals[nr_keys].val.str_val.len = 10;
|
|
|
|
/** check the content-type value */
|
|
if( mime!=(TYPE_TEXT<<16)+SUBTYPE_PLAIN
|
|
&& mime!=(TYPE_MESSAGE<<16)+SUBTYPE_CPIM )
|
|
{
|
|
if(m_extract_content_type(msg->content_type->body.s,
|
|
msg->content_type->body.len, &ctype, CT_TYPE) != -1)
|
|
{
|
|
LM_DBG("'content-type' found\n");
|
|
db_vals[nr_keys].val.str_val.s = ctype.type.s;
|
|
db_vals[nr_keys].val.str_val.len = ctype.type.len;
|
|
}
|
|
}
|
|
nr_keys++;
|
|
|
|
/* check 'expires' -- no more parsing - already done by get_body() */
|
|
if(msg->expires && msg->expires->body.len > 0)
|
|
{
|
|
LM_DBG("'expires' found\n");
|
|
val = atoi(msg->expires->body.s);
|
|
if(val > 0)
|
|
lexpire = (ms_expire_time<=val)?ms_expire_time:val;
|
|
}
|
|
|
|
/* current time */
|
|
val = (int)time(NULL);
|
|
|
|
/* add expiration time */
|
|
db_keys[nr_keys] = &sc_exp_time;
|
|
db_vals[nr_keys].type = DB1_INT;
|
|
db_vals[nr_keys].nul = 0;
|
|
db_vals[nr_keys].val.int_val = val+lexpire;
|
|
nr_keys++;
|
|
|
|
/* add incoming time */
|
|
db_keys[nr_keys] = &sc_inc_time;
|
|
db_vals[nr_keys].type = DB1_INT;
|
|
db_vals[nr_keys].nul = 0;
|
|
db_vals[nr_keys].val.int_val = val;
|
|
nr_keys++;
|
|
|
|
/* add sending time */
|
|
db_keys[nr_keys] = &sc_snd_time;
|
|
db_vals[nr_keys].type = DB1_INT;
|
|
db_vals[nr_keys].nul = 0;
|
|
db_vals[nr_keys].val.int_val = 0;
|
|
if(ms_snd_time_avp_name.n!=0)
|
|
{
|
|
avp = NULL;
|
|
avp=search_first_avp(ms_snd_time_avp_type, ms_snd_time_avp_name,
|
|
&avp_value, 0);
|
|
if(avp!=NULL && is_avp_str_val(avp))
|
|
{
|
|
if(ms_extract_time(&avp_value.s, &db_vals[nr_keys].val.int_val)!=0)
|
|
db_vals[nr_keys].val.int_val = 0;
|
|
}
|
|
}
|
|
nr_keys++;
|
|
|
|
/* add the extra headers in SQL query */
|
|
extra_hdrs.s = extra_hdrs_buf;
|
|
extra_hdrs.len = get_non_mandatory_headers(msg, extra_hdrs_buf, EXTRA_HDRS_BUF_LEN);
|
|
if (extra_hdrs.len < 0)
|
|
{
|
|
goto error;
|
|
}
|
|
|
|
db_keys[nr_keys] = &sc_stored_hdrs;
|
|
|
|
db_vals[nr_keys].type = DB1_BLOB;
|
|
db_vals[nr_keys].nul = 0;
|
|
db_vals[nr_keys].val.blob_val.s = extra_hdrs.s;
|
|
db_vals[nr_keys].val.blob_val.len = extra_hdrs.len;
|
|
|
|
nr_keys++;
|
|
|
|
if(msilo_dbf.insert(db_con, db_keys, db_vals, nr_keys) < 0)
|
|
{
|
|
LM_ERR("failed to store message\n");
|
|
goto error;
|
|
}
|
|
LM_DBG("message stored. T:<%.*s> F:<%.*s>\n",
|
|
pto->uri.len, pto->uri.s, pfrom->uri.len, pfrom->uri.s);
|
|
|
|
#ifdef STATISTICS
|
|
update_stat(ms_stored_msgs, 1);
|
|
#endif
|
|
|
|
if(ms_from==NULL || ms_offline_message == NULL
|
|
|| (ms_skip_notification_flag!=-1
|
|
&& (msg->flags & ms_skip_notification_flag)))
|
|
goto done;
|
|
|
|
LM_DBG("sending info message.\n");
|
|
if(fixup_get_svalue(msg, (gparam_p)*ms_from_sp, ¬ify_from)!=0
|
|
|| notify_from.len<=0)
|
|
{
|
|
LM_WARN("cannot get notification From address\n");
|
|
goto done;
|
|
}
|
|
if(fixup_get_svalue(msg, (gparam_p)*ms_offline_message_sp, ¬ify_body)!=0
|
|
|| notify_body.len<=0)
|
|
{
|
|
LM_WARN("cannot get notification body\n");
|
|
goto done;
|
|
}
|
|
if(fixup_get_svalue(msg, (gparam_p)*ms_content_type_sp, ¬ify_ctype)!=0
|
|
|| notify_ctype.len<=0)
|
|
{
|
|
LM_WARN("cannot get notification content type\n");
|
|
goto done;
|
|
}
|
|
|
|
if(ms_contact!=NULL && fixup_get_svalue(msg, (gparam_p)*ms_contact_sp,
|
|
¬ify_contact)==0 && notify_contact.len>0)
|
|
{
|
|
if(notify_contact.len+notify_ctype.len>=MS_BUF1_SIZE)
|
|
{
|
|
LM_WARN("insufficient buffer to build notification headers\n");
|
|
goto done;
|
|
}
|
|
memcpy(ms_buf1, notify_contact.s, notify_contact.len);
|
|
memcpy(ms_buf1+notify_contact.len, notify_ctype.s, notify_ctype.len);
|
|
str_hdr.s = ms_buf1;
|
|
str_hdr.len = notify_contact.len + notify_ctype.len;
|
|
} else {
|
|
str_hdr = notify_ctype;
|
|
}
|
|
|
|
/* look for Contact header -- must be parsed by now*/
|
|
ctaddr.s = NULL;
|
|
if(ms_use_contact && msg->contact!=NULL && msg->contact->body.s!=NULL
|
|
&& msg->contact->body.len > 0)
|
|
{
|
|
LM_DBG("contact header found\n");
|
|
if((msg->contact->parsed!=NULL
|
|
&& ((contact_body_t*)(msg->contact->parsed))->contacts!=NULL)
|
|
|| (parse_contact(msg->contact)==0
|
|
&& msg->contact->parsed!=NULL
|
|
&& ((contact_body_t*)(msg->contact->parsed))->contacts!=NULL))
|
|
{
|
|
LM_DBG("using contact header for info msg\n");
|
|
ctaddr.s =
|
|
((contact_body_t*)(msg->contact->parsed))->contacts->uri.s;
|
|
ctaddr.len =
|
|
((contact_body_t*)(msg->contact->parsed))->contacts->uri.len;
|
|
|
|
if(!ctaddr.s || ctaddr.len < 6 || strncmp(ctaddr.s, "sip:", 4)
|
|
|| ctaddr.s[4]==' ')
|
|
ctaddr.s = NULL;
|
|
else
|
|
LM_DBG("feedback contact [%.*s]\n", ctaddr.len,ctaddr.s);
|
|
}
|
|
}
|
|
|
|
memset(&uac_r,'\0', sizeof(uac_r));
|
|
uac_r.method = &msg_type;
|
|
uac_r.headers = &str_hdr;
|
|
uac_r.body = ¬ify_body;
|
|
tmb.t_request(&uac_r, /* UAC Req */
|
|
(ctaddr.s)?&ctaddr:&pfrom->uri, /* Request-URI */
|
|
&pfrom->uri, /* To */
|
|
¬ify_from, /* From */
|
|
(ms_outbound_proxy.s)?&ms_outbound_proxy:0 /* outbound uri */
|
|
);
|
|
|
|
done:
|
|
return 1;
|
|
error:
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* store message
|
|
*/
|
|
static int m_store_2(struct sip_msg* msg, char* owner, char* s2)
|
|
{
|
|
str owner_s;
|
|
if (owner != NULL)
|
|
{
|
|
if(fixup_get_svalue(msg, (gparam_p)owner, &owner_s)!=0)
|
|
{
|
|
LM_ERR("invalid owner uri parameter");
|
|
return -1;
|
|
}
|
|
return m_store(msg, &owner_s);
|
|
}
|
|
return m_store(msg, NULL);
|
|
}
|
|
|
|
/**
|
|
* dump message
|
|
*/
|
|
static int m_dump(struct sip_msg* msg, str* owner_s)
|
|
{
|
|
struct to_body *pto = NULL;
|
|
db_key_t db_keys[3];
|
|
db_key_t ob_key;
|
|
db_op_t db_ops[3];
|
|
db_val_t db_vals[3];
|
|
db_key_t db_cols[7];
|
|
db1_res_t* db_res = NULL;
|
|
int i, db_no_cols = 7, db_no_keys = 3, mid, n;
|
|
static char hdr_buf[1024];
|
|
static char body_buf[1024];
|
|
struct sip_uri puri;
|
|
uac_req_t uac_r;
|
|
str str_vals[5], hdr_str, body_str, extra_hdrs_str, tmp_extra_hdrs;
|
|
time_t rtime;
|
|
|
|
/* init */
|
|
ob_key = &sc_mid;
|
|
|
|
db_keys[0]=&sc_uri_user;
|
|
db_keys[1]=&sc_uri_host;
|
|
db_keys[2]=&sc_snd_time;
|
|
db_ops[0]=OP_EQ;
|
|
db_ops[1]=OP_EQ;
|
|
db_ops[2]=OP_EQ;
|
|
|
|
db_cols[0]=&sc_mid;
|
|
db_cols[1]=&sc_from;
|
|
db_cols[2]=&sc_to;
|
|
db_cols[3]=&sc_body;
|
|
db_cols[4]=&sc_ctype;
|
|
db_cols[5]=&sc_inc_time;
|
|
db_cols[6]=&sc_stored_hdrs;
|
|
|
|
|
|
LM_DBG("------------ start ------------\n");
|
|
hdr_str.s=hdr_buf;
|
|
hdr_str.len=1024;
|
|
body_str.s=body_buf;
|
|
body_str.len=1024;
|
|
|
|
/* check for TO header */
|
|
if(parse_to_header(msg)<0)
|
|
{
|
|
LM_ERR("failed parsing To header\n");
|
|
goto error;
|
|
}
|
|
|
|
pto = get_to(msg);
|
|
|
|
/**
|
|
* check if has expires=0 (REGISTER)
|
|
*/
|
|
if(msg->first_line.u.request.method_value==METHOD_REGISTER)
|
|
{
|
|
if (check_message_support(msg)!=0) {
|
|
LM_DBG("MESSAGE method not supported\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* get the owner */
|
|
memset(&puri, 0, sizeof(struct sip_uri));
|
|
if(owner_s)
|
|
{
|
|
if(parse_uri(owner_s->s, owner_s->len, &puri)!=0)
|
|
{
|
|
LM_ERR("bad owner SIP address!\n");
|
|
goto error;
|
|
} else {
|
|
LM_DBG("using user id [%.*s]\n", owner_s->len, owner_s->s);
|
|
}
|
|
} else { /* get it from To URI */
|
|
if(parse_uri(pto->uri.s, pto->uri.len, &puri)!=0)
|
|
{
|
|
LM_ERR("bad owner To URI!\n");
|
|
goto error;
|
|
}
|
|
}
|
|
if(puri.user.len<=0 || puri.user.s==NULL
|
|
|| puri.host.len<=0 || puri.host.s==NULL)
|
|
{
|
|
LM_ERR("bad owner URI!\n");
|
|
goto error;
|
|
}
|
|
|
|
db_vals[0].type = DB1_STR;
|
|
db_vals[0].nul = 0;
|
|
db_vals[0].val.str_val.s = puri.user.s;
|
|
db_vals[0].val.str_val.len = puri.user.len;
|
|
|
|
db_vals[1].type = DB1_STR;
|
|
db_vals[1].nul = 0;
|
|
db_vals[1].val.str_val.s = puri.host.s;
|
|
db_vals[1].val.str_val.len = puri.host.len;
|
|
|
|
db_vals[2].type = DB1_INT;
|
|
db_vals[2].nul = 0;
|
|
db_vals[2].val.int_val = 0;
|
|
|
|
if (db_con == NULL) {
|
|
LM_ERR("database connection has not been established\n");
|
|
goto error;
|
|
}
|
|
|
|
if (msilo_dbf.use_table(db_con, &ms_db_table) < 0)
|
|
{
|
|
LM_ERR("failed to use_table\n");
|
|
return -1;
|
|
}
|
|
|
|
if (msilo_dbf.query(db_con,db_keys,db_ops,db_vals,db_cols,db_no_keys,
|
|
db_no_cols, ob_key, &db_res) < 0) {
|
|
LM_ERR("failed to query database\n");
|
|
goto error;
|
|
}
|
|
|
|
if (RES_ROW_N(db_res) <= 0) {
|
|
LM_DBG("no stored message for <%.*s>!\n", pto->uri.len, pto->uri.s);
|
|
goto done;
|
|
}
|
|
|
|
LM_DBG("dumping [%d] messages for <%.*s>!!!\n",
|
|
RES_ROW_N(db_res), pto->uri.len, pto->uri.s);
|
|
|
|
for(i = 0; i < RES_ROW_N(db_res); i++)
|
|
{
|
|
mid = RES_ROWS(db_res)[i].values[0].val.int_val;
|
|
if(msg_list_check_msg(ml, mid))
|
|
{
|
|
LM_DBG("message[%d] mid=%d already sent.\n", i, mid);
|
|
continue;
|
|
}
|
|
|
|
memset(str_vals, 0, 5*sizeof(str));
|
|
SET_STR_VAL(str_vals[0], db_res, i, 1); /* from */
|
|
SET_STR_VAL(str_vals[1], db_res, i, 2); /* to */
|
|
SET_STR_VAL(str_vals[2], db_res, i, 3); /* body */
|
|
SET_STR_VAL(str_vals[3], db_res, i, 4); /* ctype */
|
|
SET_STR_VAL(str_vals[4], db_res, i, 6); /* stored hdrs */
|
|
rtime =
|
|
(time_t)RES_ROWS(db_res)[i].values[5/*inc time*/].val.int_val;
|
|
|
|
if (ms_extra_hdrs != NULL) {
|
|
if (fixup_get_svalue(msg, (gparam_p)*ms_extra_hdrs_sp,
|
|
&extra_hdrs_str) != 0) {
|
|
if (msilo_dbf.free_result(db_con, db_res) < 0)
|
|
LM_ERR("failed to free the query result\n");
|
|
LM_ERR("unable to get extra_hdrs value\n");
|
|
goto error;
|
|
}
|
|
} else {
|
|
extra_hdrs_str.len = 0;
|
|
}
|
|
|
|
tmp_extra_hdrs.len = extra_hdrs_str.len+str_vals[4].len;
|
|
if(tmp_extra_hdrs.len>0)
|
|
{
|
|
if ((tmp_extra_hdrs.s = pkg_malloc(tmp_extra_hdrs.len)) == NULL)
|
|
{
|
|
LM_ERR("Out of pkg memory");
|
|
if (msilo_dbf.free_result(db_con, db_res) < 0)
|
|
LM_ERR("failed to free the query result\n");
|
|
msg_list_set_flag(ml, mid, MS_MSG_ERRO);
|
|
goto error;
|
|
}
|
|
if(extra_hdrs_str.len>0)
|
|
memcpy(tmp_extra_hdrs.s, extra_hdrs_str.s, extra_hdrs_str.len);
|
|
memcpy(tmp_extra_hdrs.s+extra_hdrs_str.len, str_vals[4].s, str_vals[4].len);
|
|
} else {
|
|
tmp_extra_hdrs.len = 0;
|
|
tmp_extra_hdrs.s = "";
|
|
}
|
|
hdr_str.len = 1024;
|
|
if(m_build_headers(&hdr_str, str_vals[3] /*ctype*/,
|
|
str_vals[0]/*from*/, rtime /*Date*/,
|
|
tmp_extra_hdrs /*extra_hdrs*/) < 0)
|
|
{
|
|
LM_ERR("headers building failed [%d]\n", mid);
|
|
if(tmp_extra_hdrs.len>0)
|
|
pkg_free(tmp_extra_hdrs.s);
|
|
if (msilo_dbf.free_result(db_con, db_res) < 0)
|
|
LM_ERR("failed to free the query result\n");
|
|
msg_list_set_flag(ml, mid, MS_MSG_ERRO);
|
|
goto error;
|
|
}
|
|
if(tmp_extra_hdrs.len>0)
|
|
pkg_free(tmp_extra_hdrs.s);
|
|
|
|
LM_DBG("msg [%d-%d] for: %.*s\n", i+1, mid, pto->uri.len, pto->uri.s);
|
|
|
|
/** sending using TM function: t_uac */
|
|
body_str.len = 1024;
|
|
/* send composed body only if content type is text/plain */
|
|
if ((str_vals[3].len == 10) &&
|
|
(strncmp(str_vals[3].s, "text/plain", 10) == 0)) {
|
|
n = m_build_body(&body_str, rtime, str_vals[2/*body*/], 0);
|
|
} else {
|
|
n = -1;
|
|
}
|
|
if(n<0)
|
|
LM_DBG("sending simple body\n");
|
|
else
|
|
LM_DBG("sending composed body\n");
|
|
|
|
memset(&uac_r,'\0', sizeof(uac_r));
|
|
uac_r.method = &msg_type;
|
|
uac_r.headers = &hdr_str;
|
|
uac_r.body = (n<0)?&str_vals[2]:&body_str;
|
|
uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
|
|
uac_r.cb = m_tm_callback;
|
|
uac_r.cbp = (void*)(long)mid;
|
|
|
|
tmb.t_request(&uac_r, /* UAC Req */
|
|
&str_vals[1], /* Request-URI */
|
|
&str_vals[1], /* To */
|
|
&str_vals[0], /* From */
|
|
(ms_outbound_proxy.s)?&ms_outbound_proxy:0 /* ob uri */
|
|
);
|
|
}
|
|
|
|
done:
|
|
/**
|
|
* Free the result because we don't need it
|
|
* anymore
|
|
*/
|
|
if ((db_res !=NULL) && msilo_dbf.free_result(db_con, db_res) < 0)
|
|
LM_ERR("failed to free result of query\n");
|
|
|
|
return 1;
|
|
error:
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* dump message
|
|
*/
|
|
static int m_dump_2(struct sip_msg* msg, char* owner, char* s2)
|
|
{
|
|
str owner_s;
|
|
if (owner != NULL)
|
|
{
|
|
if(fixup_get_svalue(msg, (gparam_p)owner, &owner_s)!=0)
|
|
{
|
|
LM_ERR("invalid owner uri parameter");
|
|
return -1;
|
|
}
|
|
return m_dump(msg, &owner_s);
|
|
}
|
|
return m_dump(msg, NULL);
|
|
}
|
|
|
|
/**
|
|
* - cleaning up the messages that got reply
|
|
* - delete expired messages from database
|
|
*/
|
|
void m_clean_silo(unsigned int ticks, void *param)
|
|
{
|
|
msg_list_el mle = NULL, p;
|
|
db_key_t db_keys[MAX_DEL_KEYS];
|
|
db_val_t db_vals[MAX_DEL_KEYS];
|
|
db_op_t db_ops[1] = { OP_LEQ };
|
|
int n;
|
|
|
|
LM_DBG("cleaning stored messages - %d\n", ticks);
|
|
|
|
msg_list_check(ml);
|
|
mle = p = msg_list_reset(ml);
|
|
n = 0;
|
|
if (msilo_dbf.use_table(db_con, &ms_db_table) < 0)
|
|
{
|
|
LM_ERR("failed to use_table\n");
|
|
return;
|
|
}
|
|
while(p)
|
|
{
|
|
if(p->flag & MS_MSG_DONE)
|
|
{
|
|
#ifdef STATISTICS
|
|
if(p->flag & MS_MSG_TSND)
|
|
update_stat(ms_dumped_msgs, 1);
|
|
else
|
|
update_stat(ms_dumped_rmds, 1);
|
|
#endif
|
|
|
|
db_keys[n] = &sc_mid;
|
|
db_vals[n].type = DB1_INT;
|
|
db_vals[n].nul = 0;
|
|
db_vals[n].val.int_val = p->msgid;
|
|
LM_DBG("cleaning sent message [%d]\n", p->msgid);
|
|
n++;
|
|
if(n==MAX_DEL_KEYS)
|
|
{
|
|
if (msilo_dbf.delete(db_con, db_keys, NULL, db_vals, n) < 0)
|
|
LM_ERR("failed to clean %d messages.\n",n);
|
|
n = 0;
|
|
}
|
|
}
|
|
if((p->flag & MS_MSG_ERRO) && (p->flag & MS_MSG_TSND))
|
|
{ /* set snd time to 0 */
|
|
ms_reset_stime(p->msgid);
|
|
#ifdef STATISTICS
|
|
update_stat(ms_failed_rmds, 1);
|
|
#endif
|
|
|
|
}
|
|
#ifdef STATISTICS
|
|
if((p->flag & MS_MSG_ERRO) && !(p->flag & MS_MSG_TSND))
|
|
update_stat(ms_failed_msgs, 1);
|
|
#endif
|
|
p = p->next;
|
|
}
|
|
if(n>0)
|
|
{
|
|
if (msilo_dbf.delete(db_con, db_keys, NULL, db_vals, n) < 0)
|
|
LM_ERR("failed to clean %d messages\n", n);
|
|
n = 0;
|
|
}
|
|
|
|
msg_list_el_free_all(mle);
|
|
|
|
/* cleaning expired messages */
|
|
if(ticks%(ms_check_time*ms_clean_period)<ms_check_time)
|
|
{
|
|
LM_DBG("cleaning expired messages\n");
|
|
db_keys[0] = &sc_exp_time;
|
|
db_vals[0].type = DB1_INT;
|
|
db_vals[0].nul = 0;
|
|
db_vals[0].val.int_val = (int)time(NULL);
|
|
if (msilo_dbf.delete(db_con, db_keys, db_ops, db_vals, 1) < 0)
|
|
LM_DBG("ERROR cleaning expired messages\n");
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* destroy function
|
|
*/
|
|
static void destroy(void)
|
|
{
|
|
msg_list_free(ml);
|
|
|
|
if(db_con && msilo_dbf.close)
|
|
msilo_dbf.close(db_con);
|
|
}
|
|
|
|
/**
|
|
* TM callback function - delete message from database if was sent OK
|
|
*/
|
|
void m_tm_callback( struct cell *t, int type, struct tmcb_params *ps)
|
|
{
|
|
if(ps->param==NULL || *ps->param==0)
|
|
{
|
|
LM_DBG("message id not received\n");
|
|
goto done;
|
|
}
|
|
|
|
LM_DBG("completed with status %d [mid: %ld/%d]\n",
|
|
ps->code, (long)ps->param, *((int*)ps->param));
|
|
if(!db_con)
|
|
{
|
|
LM_ERR("db_con is NULL\n");
|
|
goto done;
|
|
}
|
|
if(ps->code >= 300)
|
|
{
|
|
LM_DBG("message <%d> was not sent successfully\n", *((int*)ps->param));
|
|
msg_list_set_flag(ml, *((int*)ps->param), MS_MSG_ERRO);
|
|
goto done;
|
|
}
|
|
|
|
LM_DBG("message <%d> was sent successfully\n", *((int*)ps->param));
|
|
msg_list_set_flag(ml, *((int*)ps->param), MS_MSG_DONE);
|
|
|
|
done:
|
|
return;
|
|
}
|
|
|
|
void m_send_ontimer(unsigned int ticks, void *param)
|
|
{
|
|
db_key_t db_keys[2];
|
|
db_op_t db_ops[2];
|
|
db_val_t db_vals[2];
|
|
db_key_t db_cols[6];
|
|
db1_res_t* db_res = NULL;
|
|
int i, db_no_cols = 6, db_no_keys = 2, mid, n;
|
|
static char hdr_buf[1024];
|
|
static char uri_buf[1024];
|
|
static char body_buf[1024];
|
|
str puri;
|
|
time_t ttime;
|
|
uac_req_t uac_r;
|
|
str str_vals[4], hdr_str, body_str;
|
|
str extra_hdrs_str = {0};
|
|
time_t stime;
|
|
|
|
if(ms_reminder.s==NULL)
|
|
{
|
|
LM_WARN("reminder address null\n");
|
|
return;
|
|
}
|
|
|
|
/* init */
|
|
db_keys[0]=&sc_snd_time;
|
|
db_keys[1]=&sc_snd_time;
|
|
db_ops[0]=OP_NEQ;
|
|
db_ops[1]=OP_LEQ;
|
|
|
|
db_cols[0]=&sc_mid;
|
|
db_cols[1]=&sc_uri_user;
|
|
db_cols[2]=&sc_uri_host;
|
|
db_cols[3]=&sc_body;
|
|
db_cols[4]=&sc_ctype;
|
|
db_cols[5]=&sc_snd_time;
|
|
|
|
|
|
LM_DBG("------------ start ------------\n");
|
|
hdr_str.s=hdr_buf;
|
|
hdr_str.len=1024;
|
|
body_str.s=body_buf;
|
|
body_str.len=1024;
|
|
|
|
db_vals[0].type = DB1_INT;
|
|
db_vals[0].nul = 0;
|
|
db_vals[0].val.int_val = 0;
|
|
|
|
db_vals[1].type = DB1_INT;
|
|
db_vals[1].nul = 0;
|
|
ttime = time(NULL);
|
|
db_vals[1].val.int_val = (int)ttime;
|
|
|
|
if (msilo_dbf.use_table(db_con, &ms_db_table) < 0)
|
|
{
|
|
LM_ERR("failed to use_table\n");
|
|
return;
|
|
}
|
|
|
|
if (msilo_dbf.query(db_con,db_keys,db_ops,db_vals,db_cols,db_no_keys,
|
|
db_no_cols, NULL,&db_res) < 0) {
|
|
LM_ERR("failed to query database\n");
|
|
goto done;
|
|
}
|
|
|
|
if (RES_ROW_N(db_res) <= 0)
|
|
{
|
|
LM_DBG("no message for <%.*s>!\n", 24, ctime((const time_t*)&ttime));
|
|
goto done;
|
|
}
|
|
|
|
LM_DBG("dumping [%d] messages for <%.*s>!!!\n", RES_ROW_N(db_res), 24,
|
|
ctime((const time_t*)&ttime));
|
|
|
|
for(i = 0; i < RES_ROW_N(db_res); i++)
|
|
{
|
|
mid = RES_ROWS(db_res)[i].values[0].val.int_val;
|
|
if(msg_list_check_msg(ml, mid))
|
|
{
|
|
LM_DBG("message[%d] mid=%d already sent.\n", i, mid);
|
|
continue;
|
|
}
|
|
|
|
memset(str_vals, 0, 4*sizeof(str));
|
|
SET_STR_VAL(str_vals[0], db_res, i, 1); /* user */
|
|
SET_STR_VAL(str_vals[1], db_res, i, 2); /* host */
|
|
SET_STR_VAL(str_vals[2], db_res, i, 3); /* body */
|
|
SET_STR_VAL(str_vals[3], db_res, i, 4); /* ctype */
|
|
|
|
extra_hdrs_str.len = 0;
|
|
hdr_str.len = 1024;
|
|
if(m_build_headers(&hdr_str, str_vals[3] /*ctype*/,
|
|
ms_reminder/*from*/,0/*Date*/,
|
|
extra_hdrs_str/*extra*/)
|
|
< 0)
|
|
{
|
|
LM_ERR("headers building failed [%d]\n", mid);
|
|
if (msilo_dbf.free_result(db_con, db_res) < 0)
|
|
LM_DBG("failed to free result of query\n");
|
|
msg_list_set_flag(ml, mid, MS_MSG_ERRO);
|
|
return;
|
|
}
|
|
|
|
puri.s = uri_buf;
|
|
puri.len = 4 + str_vals[0].len + 1 + str_vals[1].len;
|
|
memcpy(puri.s, "sip:", 4);
|
|
memcpy(puri.s+4, str_vals[0].s, str_vals[0].len);
|
|
puri.s[4+str_vals[0].len] = '@';
|
|
memcpy(puri.s+4+str_vals[0].len+1, str_vals[1].s, str_vals[1].len);
|
|
|
|
LM_DBG("msg [%d-%d] for: %.*s\n", i+1, mid, puri.len, puri.s);
|
|
|
|
/** sending using TM function: t_uac */
|
|
body_str.len = 1024;
|
|
stime =
|
|
(time_t)RES_ROWS(db_res)[i].values[5/*snd time*/].val.int_val;
|
|
n = m_build_body(&body_str, 0, str_vals[2/*body*/], stime);
|
|
if(n<0)
|
|
LM_DBG("sending simple body\n");
|
|
else
|
|
LM_DBG("sending composed body\n");
|
|
|
|
msg_list_set_flag(ml, mid, MS_MSG_TSND);
|
|
|
|
|
|
memset(&uac_r, '\0', sizeof(uac_r));
|
|
uac_r.method = &msg_type;
|
|
uac_r.headers = &hdr_str;
|
|
uac_r.body = (n<0)?&str_vals[2]:&body_str;
|
|
uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
|
|
uac_r.cb = m_tm_callback;
|
|
uac_r.cbp = (void*)(long)mid;
|
|
tmb.t_request(&uac_r, /* UAC Req */
|
|
&puri, /* Request-URI */
|
|
&puri, /* To */
|
|
&ms_reminder, /* From */
|
|
(ms_outbound_proxy.s)?&ms_outbound_proxy:0 /* ob uri */
|
|
);
|
|
}
|
|
|
|
done:
|
|
/**
|
|
* Free the result because we don't need it anymore
|
|
*/
|
|
if ((db_res != NULL) && msilo_dbf.free_result(db_con, db_res) < 0)
|
|
LM_DBG("failed to free result of query\n");
|
|
|
|
return;
|
|
}
|
|
|
|
int ms_reset_stime(int mid)
|
|
{
|
|
db_key_t db_keys[1];
|
|
db_op_t db_ops[1];
|
|
db_val_t db_vals[1];
|
|
db_key_t db_cols[1];
|
|
db_val_t db_cvals[1];
|
|
|
|
db_keys[0]=&sc_mid;
|
|
db_ops[0]=OP_EQ;
|
|
|
|
db_vals[0].type = DB1_INT;
|
|
db_vals[0].nul = 0;
|
|
db_vals[0].val.int_val = mid;
|
|
|
|
|
|
db_cols[0]=&sc_snd_time;
|
|
db_cvals[0].type = DB1_INT;
|
|
db_cvals[0].nul = 0;
|
|
db_cvals[0].val.int_val = 0;
|
|
|
|
LM_DBG("updating send time for [%d]!\n", mid);
|
|
|
|
if (msilo_dbf.use_table(db_con, &ms_db_table) < 0)
|
|
{
|
|
LM_ERR("failed to use_table\n");
|
|
return -1;
|
|
}
|
|
|
|
if(msilo_dbf.update(db_con,db_keys,db_ops,db_vals,db_cols,db_cvals,1,1)!=0)
|
|
{
|
|
LM_ERR("failed to make update for [%d]!\n", mid);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Check if REGISTER request has contacts that support MESSAGE method or
|
|
* if MESSAGE method is listed in Allow header and contact does not have
|
|
* methods parameter.
|
|
*/
|
|
int check_message_support(struct sip_msg* msg)
|
|
{
|
|
contact_t* c;
|
|
unsigned int allow_message = 0;
|
|
unsigned int allow_hdr = 0;
|
|
str *methods_body;
|
|
unsigned int methods;
|
|
int expires;
|
|
int posexp = 0;
|
|
|
|
/* Parse all headers in order to see all Allow headers */
|
|
if (parse_headers(msg, HDR_EOH_F, 0) == -1)
|
|
{
|
|
LM_ERR("failed to parse headers\n");
|
|
return -1;
|
|
}
|
|
|
|
if (parse_allow(msg) == 0)
|
|
{
|
|
allow_hdr = 1;
|
|
allow_message = get_allow_methods(msg) & METHOD_MESSAGE;
|
|
}
|
|
LM_DBG("Allow message: %u\n", allow_message);
|
|
|
|
if (!msg->contact)
|
|
{
|
|
LM_DBG("no Contact found\n");
|
|
return -1;
|
|
}
|
|
if (parse_contact(msg->contact) < 0)
|
|
{
|
|
LM_ERR("failed to parse Contact HF\n");
|
|
return -1;
|
|
}
|
|
if (((contact_body_t*)msg->contact->parsed)->star)
|
|
{
|
|
LM_DBG("* Contact found\n");
|
|
return -1;
|
|
}
|
|
|
|
if (contact_iterator(&c, msg, 0) < 0)
|
|
return -1;
|
|
|
|
/*
|
|
* Check contacts for MESSAGE method in methods parameter list
|
|
* If contact does not have methods parameter, use Allow header methods,
|
|
* if any. Stop if MESSAGE method is found.
|
|
*/
|
|
while(c)
|
|
{
|
|
/* calculate expires */
|
|
expires=1; /* 0 is explicitely set in hdr or param */
|
|
if(c->expires==NULL || c->expires->body.len<=0)
|
|
{
|
|
if(msg->expires!=NULL && msg->expires->body.len>0)
|
|
expires = atoi(msg->expires->body.s);
|
|
} else {
|
|
str2int(&c->expires->body, (unsigned int*)(&expires));
|
|
}
|
|
/* skip contacts with zero expires */
|
|
if (expires > 0)
|
|
{
|
|
posexp = 1;
|
|
if (c->methods)
|
|
{
|
|
methods_body = &(c->methods->body);
|
|
if (parse_methods(methods_body, &methods) < 0)
|
|
{
|
|
LM_ERR("failed to parse contact methods\n");
|
|
return -1;
|
|
}
|
|
if (methods & METHOD_MESSAGE)
|
|
{
|
|
LM_DBG("MESSAGE contact found\n");
|
|
return 0;
|
|
}
|
|
} else {
|
|
if (allow_message)
|
|
{
|
|
LM_DBG("MESSAGE found in Allow Header\n");
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
if (contact_iterator(&c, msg, c) < 0)
|
|
{
|
|
LM_DBG("MESSAGE contact not found\n");
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
/* no positivie expires header */
|
|
if(posexp==0)
|
|
return -1;
|
|
|
|
/* no Allow header and no methods in Contact => dump MESSAGEs */
|
|
if(allow_hdr==0)
|
|
return 0;
|
|
return -1;
|
|
}
|
|
|