diff --git a/modules/presence/hash.c b/modules/presence/hash.c index 49e5a919062..5c302911734 100644 --- a/modules/presence/hash.c +++ b/modules/presence/hash.c @@ -138,6 +138,7 @@ subs_t* mem_copy_subs(subs_t* s, int mem_type) + s->to_tag.len+ s->from_tag.len+s->sockinfo_str.len+s->event_id.len + s->local_contact.len+ s->contact.len+ s->record_route.len + s->reason.len+ s->watcher_user.len+ s->watcher_domain.len + + s->user_agent.len + 1)*sizeof(char); if(mem_type & PKG_MEM_TYPE) @@ -166,6 +167,7 @@ subs_t* mem_copy_subs(subs_t* s, int mem_type) CONT_COPY(dest, dest->local_contact, s->local_contact) CONT_COPY(dest, dest->contact, s->contact) CONT_COPY(dest, dest->record_route, s->record_route) + CONT_COPY(dest, dest->user_agent, s->user_agent) if(s->event_id.s) CONT_COPY(dest, dest->event_id, s->event_id) if(s->reason.s) @@ -179,6 +181,7 @@ subs_t* mem_copy_subs(subs_t* s, int mem_type) dest->send_on_cback= s->send_on_cback; dest->expires= s->expires; dest->db_flag= s->db_flag; + dest->flags= s->flags; return dest; @@ -204,6 +207,7 @@ subs_t* mem_copy_subs_noc(subs_t* s) + s->to_tag.len+ s->from_tag.len+s->sockinfo_str.len+s->event_id.len + s->local_contact.len + s->record_route.len+ + s->reason.len+ s->watcher_user.len+ s->watcher_domain.len + + s->user_agent.len + 1)*sizeof(char); dest= (subs_t*)shm_malloc(size); @@ -227,6 +231,7 @@ subs_t* mem_copy_subs_noc(subs_t* s) CONT_COPY(dest, dest->sockinfo_str, s->sockinfo_str) CONT_COPY(dest, dest->local_contact, s->local_contact) CONT_COPY(dest, dest->record_route, s->record_route) + CONT_COPY(dest, dest->user_agent, s->user_agent) if(s->event_id.s) CONT_COPY(dest, dest->event_id, s->event_id) if(s->reason.s) @@ -240,6 +245,7 @@ subs_t* mem_copy_subs_noc(subs_t* s) dest->send_on_cback= s->send_on_cback; dest->expires= s->expires; dest->db_flag= s->db_flag; + dest->flags= s->flags; dest->contact.s= (char*)shm_malloc(s->contact.len* sizeof(char)); if(dest->contact.s== NULL) diff --git a/modules/presence/notify.c b/modules/presence/notify.c index d92182b1ccc..7e7b0b25e2d 100644 --- a/modules/presence/notify.c +++ b/modules/presence/notify.c @@ -46,10 +46,13 @@ #include "presence.h" #include "notify.h" #include "utils_func.h" +#include "../../receive.h" #define ALLOC_SIZE 3000 #define MAX_FORWARD 70 +int goto_on_notify_reply=-1; + extern int pres_local_log_level; c_back_param* shm_dup_cbparam(subs_t*); @@ -95,6 +98,8 @@ str str_sender_col = str_init("sender"); str str_updated_col = str_init("updated"); str str_updated_winfo_col = str_init("updated_winfo"); str str_priority_col = str_init("priority"); +str str_flags_col = str_init("flags"); +str str_user_agent_col = str_init("user_agent"); int subset=0; @@ -984,7 +989,7 @@ int get_subs_db(str* pres_uri, pres_ev_t* event, str* sender, db_key_t query_cols[7]; db_op_t query_ops[7]; db_val_t query_vals[7]; - db_key_t result_cols[19]; + db_key_t result_cols[21]; int n_result_cols = 0, n_query_cols = 0; db_row_t *row ; db_val_t *row_vals ; @@ -995,6 +1000,7 @@ int get_subs_db(str* pres_uri, pres_ev_t* event, str* sender, int version_col= 0, record_route_col = 0, contact_col = 0; int sockinfo_col= 0, local_contact_col= 0, event_id_col = 0; int watcher_user_col= 0, watcher_domain_col= 0; + int flags_col= 0, user_agent_col= 0; subs_t s, *s_new; int inc= 0; @@ -1058,6 +1064,8 @@ int get_subs_db(str* pres_uri, pres_ev_t* event, str* sender, result_cols[sockinfo_col=n_result_cols++] = &str_socket_info_col; result_cols[local_contact_col=n_result_cols++]= &str_local_contact_col; result_cols[version_col=n_result_cols++] = &str_version_col; + result_cols[flags_col=n_result_cols++] = &str_flags_col; + result_cols[user_agent_col=n_result_cols++] = &str_user_agent_col; if (pa_dbf.query(pa_db, query_cols, query_ops, query_vals,result_cols, n_query_cols, n_result_cols, 0, &result) < 0) @@ -1148,6 +1156,9 @@ int get_subs_db(str* pres_uri, pres_ev_t* event, str* sender, else s.expires = row_vals[expires_col].val.int_val - (int)time(NULL); s.version = row_vals[version_col].val.int_val +1; + s.flags = row_vals[flags_col].val.int_val; + s.user_agent.s= (char*)row_vals[user_agent_col].val.string_val; + s.user_agent.len= (s.user_agent.s)?strlen(s.user_agent.s):0; s_new= mem_copy_subs(&s, PKG_MEM_TYPE); if(s_new== NULL) @@ -1467,7 +1478,7 @@ int send_notify_request(subs_t* subs, subs_t * watcher_subs, str str_hdr = {0, 0}; str* notify_body = NULL; int result= 0; - c_back_param *cb_param= NULL; + subs_t *cb_param= NULL; str* final_body= NULL; uac_req_t uac_r; str* aux_body = NULL; @@ -1589,16 +1600,7 @@ int send_notify_request(subs_t* subs, subs_t * watcher_subs, } LM_DBG("expires %d status %d\n", subs->expires, subs->status); - /* if status is TERMINATED_STATUS, the subscription will be deleted so no need to send a parameter */ - if(subs->status != TERMINATED_STATUS) - { - cb_param = shm_dup_cbparam(subs); - if(cb_param == NULL) - { - LM_ERR("while duplicating cb_param in share memory\n"); - goto error; - } - } + cb_param = mem_copy_subs(subs, SHM_MEM_TYPE); set_uac_req(&uac_r, &met, &str_hdr, notify_body, td, TMCB_LOCAL_COMPLETED, p_tm_callback, (void*)cb_param); @@ -1607,7 +1609,7 @@ int send_notify_request(subs_t* subs, subs_t * watcher_subs, { LM_ERR("in function tmb.t_request_within\n"); if(cb_param) - free_cbparam(cb_param); + shm_free(cb_param); goto error; } @@ -1700,30 +1702,120 @@ int notify(subs_t* subs, subs_t * watcher_subs,str* n_body,int force_null_body) return 0; } -void p_tm_callback( struct cell *t, int type, struct tmcb_params *ps) +extern subs_t* _pres_subs_last_sub; +sip_msg_t* _pres_subs_notify_reply_msg = NULL; +int _pres_subs_notify_reply_code = 0; + +int pv_parse_notify_reply_var_name(pv_spec_p sp, str *in) +{ + pv_spec_t *pv=NULL; + if(in->s==NULL || in->len<=0) + return -1; + pv = (pv_spec_t*)pkg_malloc(sizeof(pv_spec_t)); + if(pv==NULL) + return -1; + memset(pv, 0, sizeof(pv_spec_t)); + if(pv_parse_spec(in, pv)==NULL) + goto error; + sp->pvp.pvn.u.dname = (void*)pv; + sp->pvp.pvn.type = PV_NAME_PVAR; + return 0; + +error: + LM_ERR("invalid pv name [%.*s]\n", in->len, in->s); + if(pv!=NULL) + pkg_free(pv); + return -1; +} + +int pv_get_notify_reply(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { - c_back_param* cb; + pv_spec_t *pv=NULL; - if(ps->param==NULL || *ps->param==NULL || - ((c_back_param*)(*ps->param))->callid.s == NULL || - ((c_back_param*)(*ps->param))->to_tag.s== NULL || - ((c_back_param*)(*ps->param))->from_tag.s== NULL) - { - LM_DBG("message id not received, probably a timeout notify\n"); - if(ps->param != NULL && *ps->param !=NULL) - free_cbparam((c_back_param*)(*ps->param)); + if(msg==NULL) + return 1; + + pv = (pv_spec_t*)param->pvn.u.dname; + if(pv==NULL) + return pv_get_null(msg, param, res); + + return pv_get_spec_value(_pres_subs_notify_reply_msg, pv, res); +} + +#define FAKED_SIP_408_MSG_FORMAT "SIP/2.0 408 TIMEOUT\r\nVia: SIP/2.0/UDP 127.0.0.1\r\nFrom: invalid;\r\nTo: invalid\r\nCall-ID: invalid\r\nCSeq: 1 TIMEOUT\r\nContent-Length: 0\r\n\r\n" +static sip_msg_t* _faked_msg = NULL; + +sip_msg_t* faked_msg() { + if(_faked_msg == NULL) { + _faked_msg = pkg_malloc(sizeof(sip_msg_t)); + if(likely(build_sip_msg_from_buf(_faked_msg, FAKED_SIP_408_MSG_FORMAT, strlen(FAKED_SIP_408_MSG_FORMAT), inc_msg_no())<0)) { + LM_ERR("failed to parse msg buffer\n"); + return NULL; + } + } + return _faked_msg; +} + +void run_notify_reply_event(struct cell *t, struct tmcb_params *ps) +{ + int backup_route_type; + subs_t* backup_subs = NULL; + sip_msg_t msg; + + if (goto_on_notify_reply==-1) + return; + + if(likely(build_sip_msg_from_buf(&msg, t->uac->request.buffer, t->uac->request.buffer_len, inc_msg_no())<0)) { + LM_ERR("failed to parse msg buffer\n"); return; } - cb= (c_back_param*)(*ps->param); + _pres_subs_notify_reply_code = ps->code; + if( ps->code == 408 || ps->rpl == NULL) { + _pres_subs_notify_reply_msg = faked_msg(); + } else { + _pres_subs_notify_reply_msg = ps->rpl; + } + + backup_subs = _pres_subs_last_sub; + _pres_subs_last_sub = mem_copy_subs((subs_t*)(*ps->param), PKG_MEM_TYPE); + + backup_route_type = get_route_type(); + set_route_type(LOCAL_ROUTE); + run_top_route(event_rt.rlist[goto_on_notify_reply], &msg, 0); + set_route_type(backup_route_type); + + _pres_subs_notify_reply_msg = NULL; + _pres_subs_notify_reply_code = 0; + pkg_free(_pres_subs_last_sub); + _pres_subs_last_sub = backup_subs; + free_sip_msg(&msg); + +} + +void p_tm_callback( struct cell *t, int type, struct tmcb_params *ps) +{ + subs_t* subs; + + if(ps->param == NULL || *ps->param == NULL) { + LM_ERR("weird shit happening\n"); + if(ps->param != NULL && *ps->param !=NULL) + shm_free((subs_t*)(*ps->param)); + return; + } + + subs= (subs_t*)(*ps->param); LM_DBG("completed with status %d [to_tag:%.*s]\n", - ps->code, cb->to_tag.len, cb->to_tag.s); + ps->code, subs->to_tag.len, subs->to_tag.s); + + run_notify_reply_event(t, ps); - if(ps->code == 481 || (ps->code == 408 && timeout_rm_subs)) - delete_subs(&cb->pres_uri, &cb->ev_name, - &cb->to_tag, &cb->from_tag, &cb->callid); + if(ps->code == 404 || ps->code == 481 || (ps->code == 408 && timeout_rm_subs)) { + delete_subs(&subs->pres_uri, &subs->event->name, + &subs->to_tag, &subs->from_tag, &subs->callid); + } - free_cbparam(cb); + shm_free(subs); } void free_cbparam(c_back_param* cb_param) @@ -2667,7 +2759,7 @@ static int notifier_notify(subs_t *sub, int *updated, int *end_transaction) int process_dialogs(int round, int presence_winfo) { - db_key_t query_cols[3], result_cols[18], update_cols[4]; + db_key_t query_cols[3], result_cols[20], update_cols[4]; db_val_t query_vals[3], update_vals[4], *values, *dvalues; db_op_t query_ops[2]; db_row_t *rows, *drows; @@ -2678,6 +2770,7 @@ int process_dialogs(int round, int presence_winfo) int wuser_col, wdomain_col, sockinfo_col, lcontact_col, contact_col; int rroute_col, event_id_col, reason_col, event_col, lcseq_col; int rcseq_col, status_col, version_col, updated_winfo_col, expires_col; + int flags_col, user_agent_col; int i, notify_sent = 0, cached_updated_winfo, ret = -1; int end_transaction = 0; subs_t sub; @@ -2818,6 +2911,8 @@ int process_dialogs(int round, int presence_winfo) result_cols[version_col = n_result_cols++] = &str_version_col; result_cols[updated_winfo_col = n_result_cols++] = &str_updated_winfo_col; result_cols[expires_col = n_result_cols++] = &str_expires_col; + result_cols[flags_col = n_result_cols++] = &str_flags_col; + result_cols[user_agent_col = n_result_cols++] = &str_user_agent_col; /* Need to redo this here as we might have switched to the presentity table during a previous iteration. */ @@ -2885,6 +2980,7 @@ int process_dialogs(int round, int presence_winfo) EXTRACT_STRING(sub.record_route, VAL_STRING(&dvalues[rroute_col])); EXTRACT_STRING(sub.event_id, VAL_STRING(&dvalues[event_id_col])); EXTRACT_STRING(sub.reason, VAL_STRING(&dvalues[reason_col])); + EXTRACT_STRING(sub.user_agent, VAL_STRING(&dvalues[user_agent_col])); sub.local_cseq = VAL_INT(&dvalues[lcseq_col]) + 1; sub.remote_cseq = VAL_INT(&dvalues[rcseq_col]); @@ -2897,6 +2993,7 @@ int process_dialogs(int round, int presence_winfo) sub.expires = VAL_INT(&dvalues[expires_col]) - now; else sub.expires = 0; + sub.flags = VAL_INT(&dvalues[flags_col]); sub.updated = round; diff --git a/modules/presence/notify.h b/modules/presence/notify.h index 4f8276cc8a6..368ae71918d 100644 --- a/modules/presence/notify.h +++ b/modules/presence/notify.h @@ -97,6 +97,12 @@ extern str str_sender_col; extern str str_updated_col; extern str str_updated_winfo_col; extern str str_priority_col; +extern str str_flags_col; +extern str str_user_agent_col; + +extern int goto_on_notify_reply; +int pv_parse_notify_reply_var_name(pv_spec_p sp, str *in); +int pv_get_notify_reply(struct sip_msg *msg, pv_param_t *param, pv_value_t *res); void PRINT_DLG(FILE* out, dlg_t* _d); diff --git a/modules/presence/presence.c b/modules/presence/presence.c index 0668bd2cf20..1751e119c97 100644 --- a/modules/presence/presence.c +++ b/modules/presence/presence.c @@ -77,7 +77,7 @@ MODULE_VERSION #define S_TABLE_VERSION 3 #define P_TABLE_VERSION 4 -#define ACTWATCH_TABLE_VERSION 11 +#define ACTWATCH_TABLE_VERSION 12 char *log_buf = NULL; static int clean_period=100; @@ -230,6 +230,7 @@ static mi_export_t mi_cmds[] = { static pv_export_t pres_mod_pvs[] = { {{"subs", (sizeof("subs")-1)}, PVT_OTHER, pv_get_subscription, 0, pv_parse_subscription_name, 0, 0, 0}, + {{"notify_reply", (sizeof("notify_reply")-1)}, PVT_OTHER, pv_get_notify_reply, 0, pv_parse_notify_reply_var_name, 0, 0, 0}, { {0, 0}, 0, 0, 0, 0, 0, 0, 0 } }; @@ -440,6 +441,10 @@ static int mod_init(void) pa_dbf.close(pa_db); pa_db = NULL; + goto_on_notify_reply=route_lookup(&event_rt, "presence:notify-reply"); + if (goto_on_notify_reply>=0 && event_rt.rlist[goto_on_notify_reply]==0) + goto_on_notify_reply=-1; /* disable */ + return 0; } @@ -1220,7 +1225,7 @@ static int update_pw_dialogs_dbonlymode(subs_t* subs, subs_t** subs_array) { db_key_t query_cols[5], db_cols[3]; db_val_t query_vals[5], db_vals[3]; - db_key_t result_cols[24]; + db_key_t result_cols[26]; int n_query_cols=0, n_result_cols=0, n_update_cols=0; int event_col, pres_uri_col, watcher_user_col, watcher_domain_col; int r_pres_uri_col,r_to_user_col,r_to_domain_col; @@ -1231,6 +1236,7 @@ static int update_pw_dialogs_dbonlymode(subs_t* subs, subs_t** subs_array) int r_event_col, r_local_cseq_col, r_remote_cseq_col; int r_status_col, r_version_col; int r_expires_col, r_watcher_user_col, r_watcher_domain_col; + int r_flags_col, r_user_agent_col; db1_res_t *result= NULL; db_val_t *row_vals; db_row_t *rows; @@ -1301,6 +1307,9 @@ static int update_pw_dialogs_dbonlymode(subs_t* subs, subs_t** subs_array) result_cols[r_status_col=n_result_cols++] = &str_status_col; /*********************************************/ + result_cols[r_flags_col=n_result_cols++] = &str_flags_col; + result_cols[r_user_agent_col=n_result_cols++] = &str_user_agent_col; + if(pa_dbf.query(pa_db, query_cols, 0, query_vals, result_cols, n_query_cols, n_result_cols, 0, &result )< 0) { @@ -1399,6 +1408,11 @@ static int update_pw_dialogs_dbonlymode(subs_t* subs, subs_t** subs_array) s.version = row_vals[r_version_col].val.int_val; + s.flags = row_vals[r_flags_col].val.int_val; + s.user_agent.s= (char*)row_vals[r_user_agent_col].val.string_val; + s.user_agent.len= (s.user_agent.s)?strlen(s.user_agent.s):0; + + cs = mem_copy_subs(&s, PKG_MEM_TYPE); if (cs == NULL) { diff --git a/modules/presence/subscribe.c b/modules/presence/subscribe.c index 12682439cac..299d435d599 100644 --- a/modules/presence/subscribe.c +++ b/modules/presence/subscribe.c @@ -40,6 +40,7 @@ #include "notify.h" #include "../pua/hash.h" #include "../../mod_fix.h" +#include "../../dset.h" int get_stored_info(struct sip_msg* msg, subs_t* subs, int* error_ret, str* reply_str); @@ -181,14 +182,15 @@ int delete_db_subs(str* to_tag, str* from_tag, str* callid) int insert_subs_db(subs_t* s, int type) { - db_key_t query_cols[24]; - db_val_t query_vals[24]; + db_key_t query_cols[26]; + db_val_t query_vals[26]; int n_query_cols = 0; int pres_uri_col, to_user_col, to_domain_col, from_user_col, from_domain_col, callid_col, totag_col, fromtag_col, event_col,status_col, event_id_col, local_cseq_col, remote_cseq_col, expires_col, record_route_col, contact_col, local_contact_col, version_col,socket_info_col,reason_col, - watcher_user_col, watcher_domain_col, updated_col, updated_winfo_col; + watcher_user_col, watcher_domain_col, updated_col, updated_winfo_col, + user_agent_col, flags_col; if(pa_dbf.use_table(pa_db, &active_watchers_table)< 0) { @@ -316,6 +318,16 @@ int insert_subs_db(subs_t* s, int type) query_vals[updated_winfo_col].nul = 0; n_query_cols++; + query_cols[flags_col= n_query_cols]=&str_flags_col; + query_vals[flags_col].type = DB1_INT; + query_vals[flags_col].nul = 0; + n_query_cols++; + + query_cols[user_agent_col= n_query_cols]=&str_user_agent_col; + query_vals[user_agent_col].type = DB1_STR; + query_vals[user_agent_col].nul = 0; + n_query_cols++; + query_vals[pres_uri_col].val.str_val= s->pres_uri; query_vals[callid_col].val.str_val= s->callid; query_vals[totag_col].val.str_val= s->to_tag; @@ -340,6 +352,8 @@ int insert_subs_db(subs_t* s, int type) query_vals[socket_info_col].val.str_val= s->sockinfo_str; query_vals[updated_col].val.int_val = s->updated; query_vals[updated_winfo_col].val.int_val = s->updated_winfo; + query_vals[flags_col].val.int_val = s->flags; + query_vals[user_agent_col].val.str_val= s->user_agent; if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) { @@ -755,7 +769,37 @@ void msg_watchers_clean(unsigned int ticks,void *param) LM_ERR("cleaning pending subscriptions\n"); } -static char* _pres_subs_last_presentity = NULL; +subs_t* _pres_subs_last_sub = NULL; + +/* + * Map between $subs(idxname) and subs_t + * + * uri (pres_uri) 1 + * pres_uri 1 + * to_user 2 + * to_domain 3 + * from_user 4 + * from_domain 5 + * watcher_username 6 + * watcher_domain 7 + * event (event->name) 8 + * event_id 9 + * to_tag 10 + * from_tag 11 + * callid 12 + * remote_cseq 13 + * local_cseq 14 + * contact 15 + * local_contact 16 + * record_route 17 + * expires 18 + * status 19 + * reason 20 + * version 21 + * flags 22 + * user_agent 23 + * + */ int pv_parse_subscription_name(pv_spec_p sp, str *in) { @@ -771,6 +815,119 @@ int pv_parse_subscription_name(pv_spec_p sp, str *in) goto error; }; break; + + case 5: + if(strncmp(in->s, "event", 5)==0) { + sp->pvp.pvn.u.isname.name.n = 8; + } else if(strncmp(in->s, "flags", 5)==0) { + sp->pvp.pvn.u.isname.name.n = 22; + } else { + goto error; + }; + break; + + case 6: + if(strncmp(in->s, "to_tag", 6)==0) { + sp->pvp.pvn.u.isname.name.n = 10; + } else if(strncmp(in->s, "callid", 6)==0) { + sp->pvp.pvn.u.isname.name.n = 12; + } else if(strncmp(in->s, "status", 6)==0) { + sp->pvp.pvn.u.isname.name.n = 19; + } else if(strncmp(in->s, "reason", 6)==0) { + sp->pvp.pvn.u.isname.name.n = 20; + } else { + goto error; + }; + break; + + case 7: + if(strncmp(in->s, "to_user", 7)==0) { + sp->pvp.pvn.u.isname.name.n = 2; + } else if(strncmp(in->s, "contact", 7)==0) { + sp->pvp.pvn.u.isname.name.n = 15; + } else if(strncmp(in->s, "expires", 7)==0) { + sp->pvp.pvn.u.isname.name.n = 18; + } else if(strncmp(in->s, "version", 7)==0) { + sp->pvp.pvn.u.isname.name.n = 21; + } else { + goto error; + }; + break; + + case 8: + if(strncmp(in->s, "pres_uri", 8)==0) { + sp->pvp.pvn.u.isname.name.n = 1; + } else if(strncmp(in->s, "event_id", 8)==0) { + sp->pvp.pvn.u.isname.name.n = 9; + } else if(strncmp(in->s, "from_tag", 8)==0) { + sp->pvp.pvn.u.isname.name.n = 11; + } else { + goto error; + }; + break; + + case 9: + if(strncmp(in->s, "to_domain", 9)==0) { + sp->pvp.pvn.u.isname.name.n = 3; + } else if(strncmp(in->s, "from_user", 9)==0) { + sp->pvp.pvn.u.isname.name.n = 4; + } else { + goto error; + }; + break; + + case 10: + if(strncmp(in->s, "local_cseq", 10)==0) { + sp->pvp.pvn.u.isname.name.n = 14; + } else if(strncmp(in->s, "user_agent", 10)==0) { + sp->pvp.pvn.u.isname.name.n = 23; + } else { + goto error; + }; + break; + + case 11: + if(strncmp(in->s, "from_domain", 11)==0) { + sp->pvp.pvn.u.isname.name.n = 5; + } else if(strncmp(in->s, "remote_cseq", 11)==0) { + sp->pvp.pvn.u.isname.name.n = 13; + } else { + goto error; + }; + break; + + case 12: + if(strncmp(in->s, "record_route", 12)==0) { + sp->pvp.pvn.u.isname.name.n = 17; + } else { + goto error; + }; + break; + + case 13: + if(strncmp(in->s, "local_contact", 13)==0) { + sp->pvp.pvn.u.isname.name.n = 16; + } else { + goto error; + }; + break; + + case 14: + if(strncmp(in->s, "watcher_domain", 14)==0) { + sp->pvp.pvn.u.isname.name.n = 7; + } else { + goto error; + }; + break; + + case 16: + if(strncmp(in->s, "watcher_username", 16)==0) { + sp->pvp.pvn.u.isname.name.n = 6; + } else { + goto error; + }; + break; + default: goto error; } @@ -786,13 +943,60 @@ int pv_parse_subscription_name(pv_spec_p sp, str *in) int pv_get_subscription(struct sip_msg *msg, pv_param_t *param, pv_value_t *res) { - if(param->pvn.u.isname.name.n==1) /* presentity */ - return (_pres_subs_last_presentity == NULL) ? pv_get_null(msg, param, res) - : pv_get_strzval(msg, param, res, _pres_subs_last_presentity); + if(_pres_subs_last_sub == NULL) { + return pv_get_null(msg, param, res); + } + + if(param->pvn.u.isname.name.n==1) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->pres_uri); + } else if(param->pvn.u.isname.name.n==2) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->to_user); + } else if(param->pvn.u.isname.name.n==3) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->to_domain); + } else if(param->pvn.u.isname.name.n==4) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->from_user); + } else if(param->pvn.u.isname.name.n==5) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->from_domain); + } else if(param->pvn.u.isname.name.n==6) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->watcher_user); + } else if(param->pvn.u.isname.name.n==7) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->watcher_domain); + } else if(param->pvn.u.isname.name.n==8) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->event->name); + } else if(param->pvn.u.isname.name.n==9) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->event_id); + } else if(param->pvn.u.isname.name.n==10) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->to_tag); + } else if(param->pvn.u.isname.name.n==11) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->from_tag); + } else if(param->pvn.u.isname.name.n==12) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->callid); + } else if(param->pvn.u.isname.name.n==13) { + return pv_get_uintval(msg, param, res, _pres_subs_last_sub->remote_cseq); + } else if(param->pvn.u.isname.name.n==14) { + return pv_get_uintval(msg, param, res, _pres_subs_last_sub->local_cseq); + } else if(param->pvn.u.isname.name.n==15) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->contact); + } else if(param->pvn.u.isname.name.n==16) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->local_contact); + } else if(param->pvn.u.isname.name.n==17) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->record_route); + } else if(param->pvn.u.isname.name.n==18) { + return pv_get_uintval(msg, param, res, _pres_subs_last_sub->expires); + } else if(param->pvn.u.isname.name.n==19) { + return pv_get_uintval(msg, param, res, _pres_subs_last_sub->status); + } else if(param->pvn.u.isname.name.n==20) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->reason); + } else if(param->pvn.u.isname.name.n==21) { + return pv_get_sintval(msg, param, res, _pres_subs_last_sub->version); + } else if(param->pvn.u.isname.name.n==22) { + return pv_get_sintval(msg, param, res, _pres_subs_last_sub->flags); + } else if(param->pvn.u.isname.name.n==23) { + return pv_get_strval(msg, param, res, &_pres_subs_last_sub->user_agent); + } LM_ERR("unknown specifier\n"); return pv_get_null(msg, param, res); - } int handle_subscribe0(struct sip_msg* msg) @@ -849,9 +1053,9 @@ int handle_subscribe(struct sip_msg* msg, str watcher_user, str watcher_domain) str reply_str; int sent_reply= 0; - if(_pres_subs_last_presentity) { - pkg_free(_pres_subs_last_presentity); - _pres_subs_last_presentity = NULL; + if(_pres_subs_last_sub) { + pkg_free(_pres_subs_last_sub); + _pres_subs_last_sub = NULL; } /* ??? rename to avoid collisions with other symbols */ @@ -952,13 +1156,6 @@ int handle_subscribe(struct sip_msg* msg, str watcher_user, str watcher_domain) reason= subs.reason; } - if(subs.pres_uri.len > 0 && subs.pres_uri.s) { - _pres_subs_last_presentity = - (char*)pkg_malloc((subs.pres_uri.len+1) * sizeof(char)); - strncpy(_pres_subs_last_presentity, subs.pres_uri.s, subs.pres_uri.len); - _pres_subs_last_presentity[subs.pres_uri.len] = '\0'; - } - /* mark that the received event is a SUBSCRIBE message */ subs.recv_event = PRES_SUBSCRIBE_RECV; @@ -1033,6 +1230,8 @@ int handle_subscribe(struct sip_msg* msg, str watcher_user, str watcher_domain) } } + _pres_subs_last_sub = mem_copy_subs(&subs, PKG_MEM_TYPE); + /* check if correct status */ if(get_status_str(subs.status)== NULL) { @@ -1378,6 +1577,12 @@ int extract_sdialog_info_ex(subs_t* subs,struct sip_msg* msg, int miexp, else subs->local_contact= scontact; + if (parse_headers(msg, HDR_USERAGENT_F, 0) != -1 && msg->user_agent && + msg->user_agent->body.len>0 && msg->user_agent->body.lenuser_agent = msg->user_agent->body; + } + getbflagsval(0, &subs->flags); + free_to_params(&TO); return 0; @@ -1534,7 +1739,7 @@ int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* r { db_key_t query_cols[3]; db_val_t query_vals[3]; - db_key_t result_cols[9]; + db_key_t result_cols[10]; db1_res_t *result= NULL; db_row_t *row ; db_val_t *row_vals ; @@ -1543,6 +1748,7 @@ int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* r int remote_cseq_col= 0, local_cseq_col= 0, status_col, reason_col; int record_route_col, version_col, pres_uri_col; int updated_col, updated_winfo_col; + int flags_col; unsigned int remote_cseq; str pres_uri, record_route; str reason; @@ -1575,6 +1781,7 @@ int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* r result_cols[version_col=n_result_cols++] = &str_version_col; result_cols[updated_col=n_result_cols++] = &str_updated_col; result_cols[updated_winfo_col=n_result_cols++] = &str_updated_winfo_col; + result_cols[flags_col=n_result_cols++] = &str_flags_col; if (pa_dbf.use_table(pa_db, &active_watchers_table) < 0) { @@ -1626,13 +1833,14 @@ int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* r if(reason.s) { reason.len= strlen(reason.s); - subs->reason.s= (char*)pkg_malloc(reason.len* sizeof(char)); - if(subs->reason.s== NULL) - { - ERR_MEM(PKG_MEM_STR); + if(reason.len > 0) { + subs->reason.s= (char*)pkg_malloc(reason.len* sizeof(char)); + if(subs->reason.s == NULL) { + ERR_MEM(PKG_MEM_STR); + } + memcpy(subs->reason.s, reason.s, reason.len); + subs->reason.len= reason.len; } - memcpy(subs->reason.s, reason.s, reason.len); - subs->reason.len= reason.len; } subs->local_cseq= row_vals[local_cseq_col].val.int_val + 1; @@ -1642,32 +1850,34 @@ int get_database_info(struct sip_msg* msg, subs_t* subs, int* reply_code, str* r { pres_uri.s= (char*)row_vals[pres_uri_col].val.string_val; pres_uri.len= strlen(pres_uri.s); - subs->pres_uri.s= (char*)pkg_malloc(pres_uri.len* sizeof(char)); - if(subs->pres_uri.s== NULL) - { - if(subs->reason.s) - pkg_free(subs->reason.s); - ERR_MEM(PKG_MEM_STR); + if(pres_uri.len > 0) { + subs->pres_uri.s= (char*)pkg_malloc(pres_uri.len* sizeof(char)); + if(subs->pres_uri.s== NULL) { + if(subs->reason.s) + pkg_free(subs->reason.s); + ERR_MEM(PKG_MEM_STR); + } + memcpy(subs->pres_uri.s, pres_uri.s, pres_uri.len); + subs->pres_uri.len= pres_uri.len; } - memcpy(subs->pres_uri.s, pres_uri.s, pres_uri.len); - subs->pres_uri.len= pres_uri.len; } record_route.s= (char*)row_vals[record_route_col].val.string_val; - if(record_route.s) - { + if(record_route.s) { record_route.len= strlen(record_route.s); - subs->record_route.s= (char*)pkg_malloc(record_route.len*sizeof(char)); - if(subs->record_route.s== NULL) - { - ERR_MEM(PKG_MEM_STR); + if( record_route.len > 0) { + subs->record_route.s= (char*)pkg_malloc(record_route.len*sizeof(char)); + if(subs->record_route.s== NULL) { + ERR_MEM(PKG_MEM_STR); + } + memcpy(subs->record_route.s, record_route.s, record_route.len); + subs->record_route.len= record_route.len; } - memcpy(subs->record_route.s, record_route.s, record_route.len); - subs->record_route.len= record_route.len; } subs->updated= row_vals[updated_col].val.int_val; subs->updated_winfo= row_vals[updated_winfo_col].val.int_val; + subs->flags = row_vals[flags_col].val.int_val; pa_dbf.free_result(pa_db, result); result= NULL; diff --git a/modules/presence/subscribe.h b/modules/presence/subscribe.h index 955e46a03af..6c13987168a 100644 --- a/modules/presence/subscribe.h +++ b/modules/presence/subscribe.h @@ -83,6 +83,8 @@ struct subscription int internal_update_flag; int updated; int updated_winfo; + flag_t flags; + str user_agent; struct subscription* next; };