breaking up is hard to do
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@4819 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
bd1d59a008
commit
41d9cf2989
|
@ -12,6 +12,7 @@ LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/sdp -I$(SOFIAUA_DIR)/sip
|
|||
LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/soa -I$(SOFIAUA_DIR)/sresolv
|
||||
LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/stun -I$(SOFIAUA_DIR)/su
|
||||
LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/tport -I$(SOFIAUA_DIR)/url
|
||||
LOCAL_OBJS=sofia.o sofia_glue.o sofia_presence.o sofia_reg.o
|
||||
|
||||
SOFIALA=$(SOFIAUA_DIR)/libsofia-sip-ua.la
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,406 @@
|
|||
/*
|
||||
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
|
||||
*
|
||||
* Version: MPL 1.1
|
||||
*
|
||||
* The contents of this file are subject to the Mozilla Public License Version
|
||||
* 1.1 (the "License"); you may not use this file except in compliance with
|
||||
* the License. You may obtain a copy of the License at
|
||||
* http://www.mozilla.org/MPL/
|
||||
*
|
||||
* Software distributed under the License is distributed on an "AS IS" basis,
|
||||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
||||
* for the specific language governing rights and limitations under the
|
||||
* License.
|
||||
*
|
||||
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Anthony Minessale II <anthmct@yahoo.com>
|
||||
* Portions created by the Initial Developer are Copyright (C)
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
*
|
||||
* Anthony Minessale II <anthmct@yahoo.com>
|
||||
* Ken Rice, Asteria Solutions Group, Inc <ken@asteriasgi.com>
|
||||
* Paul D. Tinsley <pdt at jackhammer.org>
|
||||
* Bret McDanel <trixter AT 0xdecafbad.com>
|
||||
*
|
||||
*
|
||||
* mod_sofia.h -- SOFIA SIP Endpoint
|
||||
*
|
||||
*/
|
||||
|
||||
/*Defines etc..*/
|
||||
/*************************************************************************************************************************************************************/
|
||||
#define IREG_SECONDS 30
|
||||
#define GATEWAY_SECONDS 1
|
||||
|
||||
#define HAVE_APR
|
||||
#include <switch.h>
|
||||
|
||||
static const char modname[] = "mod_sofia";
|
||||
static const switch_state_handler_table_t noop_state_handler = { 0 };
|
||||
struct outbound_reg;
|
||||
typedef struct outbound_reg outbound_reg_t;
|
||||
|
||||
struct sofia_profile;
|
||||
typedef struct sofia_profile sofia_profile_t;
|
||||
#define NUA_MAGIC_T sofia_profile_t
|
||||
|
||||
struct sofia_private {
|
||||
char uuid[SWITCH_UUID_FORMATTED_LENGTH + 1];
|
||||
outbound_reg_t *gateway;
|
||||
};
|
||||
|
||||
typedef struct sofia_private sofia_private_t;
|
||||
|
||||
struct private_object;
|
||||
typedef struct private_object private_object_t;
|
||||
#define NUA_HMAGIC_T sofia_private_t
|
||||
|
||||
#define MY_EVENT_REGISTER "sofia::register"
|
||||
#define MY_EVENT_EXPIRE "sofia::expire"
|
||||
#define MULTICAST_EVENT "multicast::event"
|
||||
#define SOFIA_REPLACES_HEADER "_sofia_replaces_"
|
||||
#define SOFIA_USER_AGENT "FreeSWITCH(mod_sofia)"
|
||||
#define SOFIA_CHAT_PROTO "sip"
|
||||
#define SOFIA_SIP_HEADER_PREFIX "sip_h_"
|
||||
#define SOFIA_SIP_HEADER_PREFIX_T "~sip_h_"
|
||||
#define SOFIA_DEFAULT_PORT "5060"
|
||||
|
||||
#include <sofia-sip/nua.h>
|
||||
#include <sofia-sip/sip_status.h>
|
||||
#include <sofia-sip/sdp.h>
|
||||
#include <sofia-sip/sip_protos.h>
|
||||
#include <sofia-sip/auth_module.h>
|
||||
#include <sofia-sip/su_md5.h>
|
||||
#include <sofia-sip/su_log.h>
|
||||
#include <sofia-sip/nea.h>
|
||||
#include <sofia-sip/msg_addr.h>
|
||||
|
||||
|
||||
#define set_param(ptr,val) if (ptr) {free(ptr) ; ptr = NULL;} if (val) {ptr = strdup(val);}
|
||||
#define set_anchor(t,m) if (t->Anchor) {delete t->Anchor;} t->Anchor = new SipMessage(m);
|
||||
|
||||
/* Local Structures */
|
||||
/*************************************************************************************************************************************************************/
|
||||
struct sip_alias_node {
|
||||
char *url;
|
||||
nua_t *nua;
|
||||
struct sip_alias_node *next;
|
||||
};
|
||||
|
||||
typedef struct sip_alias_node sip_alias_node_t;
|
||||
|
||||
typedef enum {
|
||||
PFLAG_AUTH_CALLS = (1 << 0),
|
||||
PFLAG_BLIND_REG = (1 << 1),
|
||||
PFLAG_AUTH_ALL = (1 << 2),
|
||||
PFLAG_FULL_ID = (1 << 3),
|
||||
PFLAG_PRESENCE = (1 << 4),
|
||||
PFLAG_PASS_RFC2833 = (1 << 5),
|
||||
PFLAG_DISABLE_TRANSCODING = (1 << 6)
|
||||
} PFLAGS;
|
||||
|
||||
typedef enum {
|
||||
TFLAG_IO = (1 << 0),
|
||||
TFLAG_CHANGE_MEDIA = (1 << 1),
|
||||
TFLAG_OUTBOUND = (1 << 2),
|
||||
TFLAG_READING = (1 << 3),
|
||||
TFLAG_WRITING = (1 << 4),
|
||||
TFLAG_HUP = (1 << 5),
|
||||
TFLAG_RTP = (1 << 6),
|
||||
TFLAG_BYE = (1 << 7),
|
||||
TFLAG_ANS = (1 << 8),
|
||||
TFLAG_EARLY_MEDIA = (1 << 9),
|
||||
TFLAG_SECURE = (1 << 10),
|
||||
TFLAG_VAD_IN = (1 << 11),
|
||||
TFLAG_VAD_OUT = (1 << 12),
|
||||
TFLAG_VAD = (1 << 13),
|
||||
TFLAG_TIMER = (1 << 14),
|
||||
TFLAG_READY = (1 << 15),
|
||||
TFLAG_REINVITE = (1 << 16),
|
||||
TFLAG_REFER = (1 << 17),
|
||||
TFLAG_NOHUP = (1 << 18),
|
||||
TFLAG_XFER = (1 << 19),
|
||||
TFLAG_NOMEDIA = (1 << 20),
|
||||
TFLAG_BUGGY_2833 = (1 << 21),
|
||||
TFLAG_SIP_HOLD = (1 << 22),
|
||||
TFLAG_INB_NOMEDIA = (1 << 23),
|
||||
TFLAG_LATE_NEGOTIATION = (1 << 24)
|
||||
} TFLAGS;
|
||||
|
||||
struct sofia_globals {
|
||||
switch_hash_t *profile_hash;
|
||||
switch_hash_t *gateway_hash;
|
||||
switch_mutex_t *hash_mutex;
|
||||
uint32_t callid;
|
||||
int32_t running;
|
||||
switch_mutex_t *mutex;
|
||||
char guess_ip[80];
|
||||
};
|
||||
extern struct sofia_globals globals;
|
||||
|
||||
|
||||
typedef enum {
|
||||
REG_FLAG_AUTHED = (1 << 0),
|
||||
} reg_flags_t;
|
||||
|
||||
typedef enum {
|
||||
REG_STATE_UNREGED,
|
||||
REG_STATE_TRYING,
|
||||
REG_STATE_REGISTER,
|
||||
REG_STATE_REGED,
|
||||
REG_STATE_FAILED,
|
||||
REG_STATE_EXPIRED
|
||||
} reg_state_t;
|
||||
|
||||
struct outbound_reg {
|
||||
sofia_private_t *sofia_private;
|
||||
nua_handle_t *nh;
|
||||
sofia_profile_t *profile;
|
||||
char *name;
|
||||
char *register_scheme;
|
||||
char *register_realm;
|
||||
char *register_username;
|
||||
char *register_password;
|
||||
char *register_from;
|
||||
char *register_contact;
|
||||
char *register_to;
|
||||
char *register_proxy;
|
||||
char *register_context;
|
||||
char *expires_str;
|
||||
uint32_t freq;
|
||||
time_t expires;
|
||||
time_t retry;
|
||||
uint32_t flags;
|
||||
reg_state_t state;
|
||||
switch_memory_pool_t *pool;
|
||||
struct outbound_reg *next;
|
||||
};
|
||||
|
||||
|
||||
struct sofia_profile {
|
||||
int debug;
|
||||
char *name;
|
||||
char *dbname;
|
||||
char *dialplan;
|
||||
char *context;
|
||||
char *extrtpip;
|
||||
char *rtpip;
|
||||
char *sipip;
|
||||
char *extsipip;
|
||||
char *username;
|
||||
char *url;
|
||||
char *bindurl;
|
||||
char *sipdomain;
|
||||
char *timer_name;
|
||||
char *hold_music;
|
||||
int sip_port;
|
||||
char *codec_string;
|
||||
int running;
|
||||
int codec_ms;
|
||||
int dtmf_duration;
|
||||
unsigned int flags;
|
||||
unsigned int pflags;
|
||||
uint32_t max_calls;
|
||||
uint32_t nonce_ttl;
|
||||
nua_t *nua;
|
||||
switch_memory_pool_t *pool;
|
||||
su_root_t *s_root;
|
||||
sip_alias_node_t *aliases;
|
||||
switch_payload_t te;
|
||||
switch_payload_t cng_pt;
|
||||
uint32_t codec_flags;
|
||||
switch_mutex_t *ireg_mutex;
|
||||
switch_mutex_t *gateway_mutex;
|
||||
outbound_reg_t *gateways;
|
||||
su_home_t *home;
|
||||
switch_hash_t *profile_hash;
|
||||
switch_hash_t *chat_hash;
|
||||
};
|
||||
|
||||
|
||||
struct private_object {
|
||||
sofia_private_t *sofia_private;
|
||||
uint32_t flags;
|
||||
switch_payload_t agreed_pt;
|
||||
switch_core_session_t *session;
|
||||
switch_frame_t read_frame;
|
||||
char *codec_order[SWITCH_MAX_CODECS];
|
||||
int codec_order_last;
|
||||
const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];
|
||||
int num_codecs;
|
||||
switch_codec_t read_codec;
|
||||
switch_codec_t write_codec;
|
||||
uint32_t codec_ms;
|
||||
switch_caller_profile_t *caller_profile;
|
||||
uint32_t timestamp_send;
|
||||
//int32_t timestamp_recv;
|
||||
switch_rtp_t *rtp_session;
|
||||
int ssrc;
|
||||
//switch_time_t last_read;
|
||||
sofia_profile_t *profile;
|
||||
char *local_sdp_audio_ip;
|
||||
switch_port_t local_sdp_audio_port;
|
||||
char *remote_sdp_audio_ip;
|
||||
switch_port_t remote_sdp_audio_port;
|
||||
char *adv_sdp_audio_ip;
|
||||
switch_port_t adv_sdp_audio_port;
|
||||
char *proxy_sdp_audio_ip;
|
||||
switch_port_t proxy_sdp_audio_port;
|
||||
char *from_uri;
|
||||
char *to_uri;
|
||||
char *from_address;
|
||||
char *to_address;
|
||||
char *callid;
|
||||
char *far_end_contact;
|
||||
char *contact_url;
|
||||
char *from_str;
|
||||
char *rm_encoding;
|
||||
char *rm_fmtp;
|
||||
char *fmtp_out;
|
||||
char *remote_sdp_str;
|
||||
char *local_sdp_str;
|
||||
char *dest;
|
||||
char *dest_to;
|
||||
char *key;
|
||||
char *xferto;
|
||||
char *kick;
|
||||
char *origin;
|
||||
char *hash_key;
|
||||
char *chat_from;
|
||||
char *chat_to;
|
||||
char *e_dest;
|
||||
char *call_id;
|
||||
unsigned long rm_rate;
|
||||
switch_payload_t pt;
|
||||
switch_mutex_t *flag_mutex;
|
||||
switch_payload_t te;
|
||||
switch_payload_t bte;
|
||||
switch_payload_t cng_pt;
|
||||
switch_payload_t bcng_pt;
|
||||
nua_handle_t *nh;
|
||||
nua_handle_t *nh2;
|
||||
su_home_t *home;
|
||||
sip_contact_t *contact;
|
||||
};
|
||||
|
||||
struct callback_t {
|
||||
char *val;
|
||||
switch_size_t len;
|
||||
int matches;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
REG_REGISTER,
|
||||
REG_INVITE
|
||||
} sofia_regtype_t;
|
||||
|
||||
typedef enum {
|
||||
AUTH_OK,
|
||||
AUTH_FORBIDDEN,
|
||||
AUTH_STALE,
|
||||
} auth_res_t;
|
||||
|
||||
/* Function Prototypes */
|
||||
/*************************************************************************************************************************************************************/
|
||||
|
||||
|
||||
switch_status_t sofia_glue_activate_rtp(private_object_t * tech_pvt);
|
||||
|
||||
void sofia_glue_deactivate_rtp(private_object_t * tech_pvt);
|
||||
|
||||
void sofia_glue_set_local_sdp(private_object_t * tech_pvt, char *ip, uint32_t port, char *sr, int force);
|
||||
|
||||
void sofia_glue_sofia_glue_tech_set_codecs(private_object_t * tech_pvt);
|
||||
|
||||
void sofia_glue_attach_private(switch_core_session_t *session, sofia_profile_t * profile, private_object_t * tech_pvt, const char *channame);
|
||||
|
||||
void sofia_glue_terminate_session(switch_core_session_t **session, switch_call_cause_t cause, int line);
|
||||
|
||||
switch_status_t sofia_glue_tech_choose_port(private_object_t * tech_pvt);
|
||||
|
||||
switch_status_t sofia_glue_do_invite(switch_core_session_t *session);
|
||||
|
||||
uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t * sdp);
|
||||
|
||||
char *sofia_reg_get_auth_data(char *dbname, char *nonce, char *npassword, size_t len, switch_mutex_t * mutex);
|
||||
|
||||
void sofia_presence_establish_presence(sofia_profile_t * profile);
|
||||
|
||||
void sofia_handle_sip_i_state(int status,
|
||||
char const *phrase,
|
||||
nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
|
||||
|
||||
|
||||
void sofia_handle_sip_i_refer(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]);
|
||||
|
||||
void sofia_handle_sip_i_info(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]);
|
||||
|
||||
void sofia_handle_sip_i_invite(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
|
||||
|
||||
void sofia_reg_handle_sip_i_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
|
||||
|
||||
void sofia_event_callback(nua_event_t event,
|
||||
int status,
|
||||
char const *phrase,
|
||||
nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
|
||||
|
||||
|
||||
void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t * thread, void *obj);
|
||||
|
||||
void launch_sofia_profile_thread(sofia_profile_t * profile);
|
||||
|
||||
switch_status_t sofia_presence_chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint);
|
||||
void sofia_glue_tech_absorb_sdp(private_object_t * tech_pvt);
|
||||
switch_status_t sofia_glue_tech_media(private_object_t * tech_pvt, char *r_sdp);
|
||||
char *sofia_reg_find_reg_url(sofia_profile_t * profile, const char *user, const char *host, char *val, switch_size_t len);
|
||||
void event_handler(switch_event_t *event);
|
||||
void sofia_presence_event_handler(switch_event_t *event);
|
||||
void sofia_presence_cancel(void);
|
||||
switch_status_t config_sofia(int reload);
|
||||
auth_res_t parse_auth(sofia_profile_t * profile, sip_authorization_t const *authorization, const char *regstr, char *np, size_t nplen);
|
||||
void sofia_reg_handle_sip_r_challenge(int status,
|
||||
char const *phrase,
|
||||
nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]);
|
||||
void sofia_reg_handle_sip_r_register(int status,
|
||||
char const *phrase,
|
||||
nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
|
||||
void sofia_handle_sip_i_options(int status,
|
||||
char const *phrase,
|
||||
nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
|
||||
void sofia_presence_handle_sip_i_publish(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
|
||||
void sofia_presence_handle_sip_i_message(int status,
|
||||
char const *phrase,
|
||||
nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
|
||||
void sofia_presence_handle_sip_r_subscribe(int status,
|
||||
char const *phrase,
|
||||
nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
|
||||
void sofia_presence_handle_sip_i_subscribe(int status,
|
||||
char const *phrase,
|
||||
nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
|
||||
|
||||
sofia_profile_t *sofia_glue_find_profile(char *key);
|
||||
void sofia_glue_add_profile(char *key, sofia_profile_t * profile);
|
||||
void sofia_glue_execute_sql(char *dbname, char *sql, switch_mutex_t * mutex);
|
||||
void sofia_reg_check_expire(switch_core_db_t *db, sofia_profile_t * profile, time_t now);
|
||||
void sofia_reg_check_gateway(sofia_profile_t * profile, time_t now);
|
||||
void sofia_reg_unregister(sofia_profile_t * profile);
|
||||
switch_status_t sofia_glue_ext_address_lookup(char **ip, switch_port_t *port, char *sourceip, switch_memory_pool_t *pool);
|
||||
outbound_reg_t *sofia_reg_find_gateway(char *key);
|
||||
void sofia_reg_add_gateway(char *key, outbound_reg_t * gateway);
|
||||
void sofia_glue_pass_sdp(private_object_t * tech_pvt, char *sdp);
|
||||
switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status);
|
||||
void sofia_glue_do_xfer_invite(switch_core_session_t *session);
|
||||
uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sip_t const *sip, sofia_regtype_t regtype, char *key, uint32_t keylen);
|
||||
const switch_endpoint_interface_t sofia_endpoint_interface;
|
||||
void sofia_presence_set_chat_hash(private_object_t * tech_pvt, sip_t const *sip);
|
||||
switch_status_t sofia_on_hangup(switch_core_session_t *session);
|
||||
char *sofia_glue_get_url_from_contact(char *buf, uint8_t to_dup);
|
||||
int sofia_presence_resub_callback(void *pArg, int argc, char **argv, char **columnNames);
|
||||
int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char **columnNames);
|
||||
void sofia_presence_set_hash_key(char *hash_key, int32_t len, sip_t const *sip);
|
|
@ -194,16 +194,19 @@
|
|||
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
|
||||
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
|
||||
>
|
||||
<File
|
||||
RelativePath=".\mod_sofia.c"
|
||||
>
|
||||
</File>
|
||||
<File RelativePath=".\mod_sofia.c"></File>
|
||||
<File RelativePath=".\sofia_reg.c"></File>
|
||||
<File RelativePath=".\sofia_glue.c"></File>
|
||||
<File RelativePath=".\sofia_presence.c"></File>
|
||||
<File RelativePath=".\sofia.c"></File>
|
||||
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Header Files"
|
||||
Filter="h;hpp;hxx;hm;inl;inc;xsd"
|
||||
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
|
||||
>
|
||||
<File RelativePath=".\mod_sofia.h"></File>
|
||||
</Filter>
|
||||
<Filter
|
||||
Name="Resource Files"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,909 @@
|
|||
#include "mod_sofia.h"
|
||||
|
||||
|
||||
switch_status_t sofia_presence_chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint)
|
||||
{
|
||||
char buf[256];
|
||||
char *user, *host;
|
||||
sofia_profile_t *profile;
|
||||
char *ffrom = NULL;
|
||||
nua_handle_t *msg_nh;
|
||||
char *contact;
|
||||
|
||||
if (to && (user = strdup(to))) {
|
||||
if ((host = strchr(user, '@'))) {
|
||||
*host++ = '\0';
|
||||
}
|
||||
|
||||
if (!host || !(profile = sofia_glue_find_profile(host))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
|
||||
"Chat proto [%s]\nfrom [%s]\nto [%s]\n%s\nInvalid Profile %s\n", proto, from, to,
|
||||
body ? body : "[no body]", host ? host : "NULL");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (!sofia_reg_find_reg_url(profile, user, host, buf, sizeof(buf))) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (!strcmp(proto, SOFIA_CHAT_PROTO)) {
|
||||
from = hint;
|
||||
} else {
|
||||
char *fp, *p, *fu = NULL;
|
||||
|
||||
if (!(fp = strdup(from))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if ((p = strchr(fp, '@'))) {
|
||||
*p = '\0';
|
||||
fu = strdup(fp);
|
||||
*p = '+';
|
||||
}
|
||||
|
||||
ffrom = switch_mprintf("\"%s\" <sip:%s+%s@%s>", fu, proto, fp, profile->name);
|
||||
from = ffrom;
|
||||
switch_safe_free(fu);
|
||||
switch_safe_free(fp);
|
||||
}
|
||||
|
||||
contact = sofia_glue_get_url_from_contact(buf, 1);
|
||||
msg_nh = nua_handle(profile->nua, NULL, SIPTAG_FROM_STR(from), NUTAG_URL(contact), SIPTAG_TO_STR(buf), // if this cries, add contact here too, change the 1 to 0 and omit the safe_free
|
||||
SIPTAG_CONTACT_STR(profile->url), TAG_END());
|
||||
|
||||
switch_safe_free(contact);
|
||||
|
||||
|
||||
nua_message(msg_nh, SIPTAG_CONTENT_TYPE_STR("text/html"), SIPTAG_PAYLOAD_STR(body), TAG_END());
|
||||
|
||||
|
||||
switch_safe_free(ffrom);
|
||||
free(user);
|
||||
}
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
void sofia_presence_cancel(void)
|
||||
{
|
||||
char *sql, *errmsg = NULL;
|
||||
switch_core_db_t *db;
|
||||
sofia_profile_t *profile;
|
||||
switch_hash_index_t *hi;
|
||||
void *val;
|
||||
|
||||
if ((sql = switch_mprintf("select 0,'unavailable','unavailable',* from sip_subscriptions where event='presence'"))) {
|
||||
switch_mutex_lock(globals.hash_mutex);
|
||||
for (hi = switch_hash_first(switch_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, NULL, NULL, &val);
|
||||
profile = (sofia_profile_t *) val;
|
||||
if (!(profile->pflags & PFLAG_PRESENCE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(db = switch_core_db_open_file(profile->dbname))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
|
||||
continue;
|
||||
}
|
||||
switch_mutex_lock(profile->ireg_mutex);
|
||||
switch_core_db_exec(db, sql, sofia_presence_sub_callback, profile, &errmsg);
|
||||
switch_mutex_unlock(profile->ireg_mutex);
|
||||
switch_core_db_close(db);
|
||||
}
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
switch_mutex_unlock(globals.hash_mutex);
|
||||
}
|
||||
|
||||
void sofia_presence_establish_presence(sofia_profile_t * profile)
|
||||
{
|
||||
char *sql, *errmsg = NULL;
|
||||
switch_core_db_t *db;
|
||||
|
||||
if (!(db = switch_core_db_open_file(profile->dbname))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
|
||||
return;
|
||||
}
|
||||
|
||||
if ((sql = switch_mprintf("select user,host,'Registered','unknown','' from sofia_handle_sip_registrations"))) {
|
||||
switch_mutex_lock(profile->ireg_mutex);
|
||||
switch_core_db_exec(db, sql, sofia_presence_resub_callback, profile, &errmsg);
|
||||
switch_mutex_unlock(profile->ireg_mutex);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
|
||||
if ((sql = switch_mprintf("select sub_to_user,sub_to_host,'Online','unknown',proto from sip_subscriptions "
|
||||
"where proto='ext' or proto='user' or proto='conf'"))) {
|
||||
switch_mutex_lock(profile->ireg_mutex);
|
||||
switch_core_db_exec(db, sql, sofia_presence_resub_callback, profile, &errmsg);
|
||||
switch_mutex_unlock(profile->ireg_mutex);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
|
||||
switch_core_db_close(db);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
char *sofia_presence_translate_rpid(char *in, char *ext)
|
||||
{
|
||||
char *r = NULL;
|
||||
|
||||
if (in && (strstr(in, "null") || strstr(in, "NULL"))) {
|
||||
in = NULL;
|
||||
}
|
||||
|
||||
if (!in) {
|
||||
in = ext;
|
||||
}
|
||||
|
||||
if (!in) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!strcasecmp(in, "dnd")) {
|
||||
r = "busy";
|
||||
}
|
||||
|
||||
if (ext && !strcasecmp(ext, "away")) {
|
||||
r = "idle";
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void sofia_presence_event_handler(switch_event_t *event)
|
||||
{
|
||||
sofia_profile_t *profile;
|
||||
switch_hash_index_t *hi;
|
||||
void *val;
|
||||
char *from = switch_event_get_header(event, "from");
|
||||
char *proto = switch_event_get_header(event, "proto");
|
||||
char *rpid = switch_event_get_header(event, "rpid");
|
||||
char *status = switch_event_get_header(event, "status");
|
||||
char *event_type = switch_event_get_header(event, "event_type");
|
||||
//char *event_subtype = switch_event_get_header(event, "event_subtype");
|
||||
char *sql = NULL;
|
||||
char *euser = NULL, *user = NULL, *host = NULL;
|
||||
char *errmsg;
|
||||
switch_core_db_t *db;
|
||||
|
||||
|
||||
if (rpid && !strcasecmp(rpid, "n/a")) {
|
||||
rpid = NULL;
|
||||
}
|
||||
|
||||
if (status && !strcasecmp(status, "n/a")) {
|
||||
status = NULL;
|
||||
}
|
||||
|
||||
if (rpid) {
|
||||
rpid = sofia_presence_translate_rpid(rpid, status);
|
||||
}
|
||||
|
||||
if (!status) {
|
||||
status = "Available";
|
||||
|
||||
if (rpid) {
|
||||
if (!strcasecmp(rpid, "busy")) {
|
||||
status = "Busy";
|
||||
} else if (!strcasecmp(rpid, "unavailable")) {
|
||||
status = "Idle";
|
||||
} else if (!strcasecmp(rpid, "away")) {
|
||||
status = "Idle";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!rpid) {
|
||||
rpid = "unknown";
|
||||
}
|
||||
|
||||
if (event->event_id == SWITCH_EVENT_ROSTER) {
|
||||
|
||||
if (from) {
|
||||
sql = switch_mprintf("select 1,'%q','%q',* from sip_subscriptions where event='presence' and full_from like '%%%q%%'", status, rpid, from);
|
||||
} else {
|
||||
sql = switch_mprintf("select 1,'%q','%q',* from sip_subscriptions where event='presence'", status, rpid);
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.hash_mutex);
|
||||
for (hi = switch_hash_first(switch_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, NULL, NULL, &val);
|
||||
profile = (sofia_profile_t *) val;
|
||||
if (!(profile->pflags & PFLAG_PRESENCE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sql) {
|
||||
if (!(db = switch_core_db_open_file(profile->dbname))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
|
||||
continue;
|
||||
}
|
||||
switch_mutex_lock(profile->ireg_mutex);
|
||||
switch_core_db_exec(db, sql, sofia_presence_sub_callback, profile, &errmsg);
|
||||
switch_mutex_unlock(profile->ireg_mutex);
|
||||
switch_core_db_close(db);
|
||||
}
|
||||
|
||||
}
|
||||
switch_mutex_unlock(globals.hash_mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (switch_strlen_zero(event_type)) {
|
||||
event_type = "presence";
|
||||
}
|
||||
|
||||
if ((user = strdup(from))) {
|
||||
if ((host = strchr(user, '@'))) {
|
||||
char *p;
|
||||
*host++ = '\0';
|
||||
if ((p = strchr(host, '/'))) {
|
||||
*p = '\0';
|
||||
}
|
||||
} else {
|
||||
switch_safe_free(user);
|
||||
return;
|
||||
}
|
||||
if ((euser = strchr(user, '+'))) {
|
||||
euser++;
|
||||
} else {
|
||||
euser = user;
|
||||
}
|
||||
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch (event->event_id) {
|
||||
case SWITCH_EVENT_PRESENCE_PROBE:
|
||||
if (proto) {
|
||||
switch_core_db_t *db = NULL;
|
||||
char *to = switch_event_get_header(event, "to");
|
||||
char *user, *euser, *host, *p;
|
||||
|
||||
if (!to || !(user = strdup(to))) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((host = strchr(user, '@'))) {
|
||||
*host++ = '\0';
|
||||
}
|
||||
euser = user;
|
||||
if ((p = strchr(euser, '+'))) {
|
||||
euser = (p + 1);
|
||||
}
|
||||
|
||||
if (euser && host &&
|
||||
(sql =
|
||||
switch_mprintf("select user,host,status,rpid,'' from sofia_handle_sip_registrations where user='%q' and host='%q'",
|
||||
euser, host)) && (profile = sofia_glue_find_profile(host))) {
|
||||
if (!(db = switch_core_db_open_file(profile->dbname))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
|
||||
switch_safe_free(user);
|
||||
switch_safe_free(sql);
|
||||
return;
|
||||
}
|
||||
|
||||
switch_mutex_lock(profile->ireg_mutex);
|
||||
switch_core_db_exec(db, sql, sofia_presence_resub_callback, profile, &errmsg);
|
||||
switch_mutex_unlock(profile->ireg_mutex);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
switch_safe_free(user);
|
||||
switch_core_db_close(db);
|
||||
}
|
||||
return;
|
||||
case SWITCH_EVENT_PRESENCE_IN:
|
||||
sql =
|
||||
switch_mprintf
|
||||
("select 1,'%q','%q',* from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'",
|
||||
status, rpid, proto, event_type, euser, host);
|
||||
break;
|
||||
case SWITCH_EVENT_PRESENCE_OUT:
|
||||
sql =
|
||||
switch_mprintf
|
||||
("select 0,'%q','%q',* from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'",
|
||||
status, rpid, proto, event_type, euser, host);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch_mutex_lock(globals.hash_mutex);
|
||||
for (hi = switch_hash_first(switch_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) {
|
||||
switch_hash_this(hi, NULL, NULL, &val);
|
||||
profile = (sofia_profile_t *) val;
|
||||
if (!(profile->pflags & PFLAG_PRESENCE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (sql) {
|
||||
if (!(db = switch_core_db_open_file(profile->dbname))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
|
||||
continue;
|
||||
}
|
||||
switch_mutex_lock(profile->ireg_mutex);
|
||||
switch_core_db_exec(db, sql, sofia_presence_sub_callback, profile, &errmsg);
|
||||
switch_mutex_unlock(profile->ireg_mutex);
|
||||
|
||||
switch_core_db_close(db);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(globals.hash_mutex);
|
||||
|
||||
switch_safe_free(sql);
|
||||
switch_safe_free(user);
|
||||
}
|
||||
|
||||
int sofia_presence_sub_reg_callback(void *pArg, int argc, char **argv, char **columnNames)
|
||||
{
|
||||
sofia_profile_t *profile = (sofia_profile_t *) pArg;
|
||||
//char *proto = argv[0];
|
||||
char *user = argv[1];
|
||||
char *host = argv[2];
|
||||
switch_event_t *event;
|
||||
char *status = NULL;
|
||||
if (switch_strlen_zero(status)) {
|
||||
status = "Available";
|
||||
}
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", status);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_subtype", "probe");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sofia_presence_resub_callback(void *pArg, int argc, char **argv, char **columnNames)
|
||||
{
|
||||
sofia_profile_t *profile = (sofia_profile_t *) pArg;
|
||||
char *user = argv[0];
|
||||
char *host = argv[1];
|
||||
char *status = argv[2];
|
||||
char *rpid = argv[3];
|
||||
char *proto = argv[4];
|
||||
switch_event_t *event;
|
||||
|
||||
if (switch_strlen_zero(proto)) {
|
||||
proto = NULL;
|
||||
}
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "%s", proto ? proto : SOFIA_CHAT_PROTO);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", status);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char **columnNames)
|
||||
{
|
||||
sofia_profile_t *profile = (sofia_profile_t *) pArg;
|
||||
char *pl;
|
||||
char *id, *note;
|
||||
uint32_t in = atoi(argv[0]);
|
||||
char *status = argv[1];
|
||||
char *rpid = argv[2];
|
||||
char *proto = argv[3];
|
||||
char *user = argv[4];
|
||||
char *host = argv[5];
|
||||
char *sub_to_user = argv[6];
|
||||
char *sub_to_host = argv[7];
|
||||
char *event = argv[8];
|
||||
char *contact = argv[9];
|
||||
char *callid = argv[10];
|
||||
char *full_from = argv[11];
|
||||
char *full_via = argv[12];
|
||||
nua_handle_t *nh;
|
||||
char *to;
|
||||
char *open;
|
||||
char *tmp;
|
||||
|
||||
if (!rpid) {
|
||||
rpid = "unknown";
|
||||
}
|
||||
|
||||
if (in) {
|
||||
note = switch_mprintf("<dm:note>%s</dm:note>", status);
|
||||
open = "open";
|
||||
} else {
|
||||
note = NULL;
|
||||
open = "closed";
|
||||
}
|
||||
|
||||
if (!strcasecmp(sub_to_host, host)) {
|
||||
/* same host */
|
||||
id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host);
|
||||
} else if (strcasecmp(proto, SOFIA_CHAT_PROTO)) {
|
||||
/*encapsulate */
|
||||
id = switch_mprintf("sip:%s+%s+%s@%s", proto, sub_to_user, sub_to_host, host);
|
||||
} else {
|
||||
id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
|
||||
}
|
||||
|
||||
to = switch_mprintf("sip:%s@%s", user, host);
|
||||
pl = switch_mprintf("<?xml version='1.0' encoding='UTF-8'?>\r\n"
|
||||
"<presence xmlns='urn:ietf:params:xml:ns:pidf'\r\n"
|
||||
"xmlns:dm='urn:ietf:params:xml:ns:pidf:data-model'\r\n"
|
||||
"xmlns:rpid='urn:ietf:params:xml:ns:pidf:rpid'\r\n"
|
||||
"xmlns:c='urn:ietf:params:xml:ns:pidf:cipid'\r\n"
|
||||
"entity='pres:%s'>\r\n"
|
||||
"<tuple id='t6a5ed77e'>\r\n"
|
||||
"<status>\r\n"
|
||||
"<basic>%s</basic>\r\n"
|
||||
"</status>\r\n"
|
||||
"</tuple>\r\n"
|
||||
"<dm:person id='p06360c4a'>\r\n"
|
||||
"<rpid:activities>\r\n" "<rpid:%s/>\r\n" "</rpid:activities>%s</dm:person>\r\n" "</presence>", id, open, rpid, note);
|
||||
|
||||
|
||||
|
||||
nh = nua_handle(profile->nua, NULL, TAG_END());
|
||||
tmp = contact;
|
||||
contact = sofia_glue_get_url_from_contact(tmp, 0);
|
||||
|
||||
nua_notify(nh,
|
||||
NUTAG_URL(contact),
|
||||
SIPTAG_TO_STR(full_from),
|
||||
SIPTAG_FROM_STR(id),
|
||||
SIPTAG_CONTACT_STR(profile->url),
|
||||
SIPTAG_CALL_ID_STR(callid),
|
||||
SIPTAG_VIA_STR(full_via),
|
||||
SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=3600"),
|
||||
SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"), SIPTAG_PAYLOAD_STR(pl), TAG_END());
|
||||
|
||||
switch_safe_free(id);
|
||||
switch_safe_free(note);
|
||||
switch_safe_free(pl);
|
||||
switch_safe_free(to);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sofia_presence_handle_sip_i_subscribe(int status,
|
||||
char const *phrase,
|
||||
nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
|
||||
{
|
||||
if (sip) {
|
||||
long exp, exp_raw;
|
||||
sip_to_t const *to = sip->sip_to;
|
||||
sip_from_t const *from = sip->sip_from;
|
||||
sip_contact_t const *contact = sip->sip_contact;
|
||||
char *from_user = NULL;
|
||||
char *from_host = NULL;
|
||||
char *to_user = NULL;
|
||||
char *to_host = NULL;
|
||||
char *sql, *event = NULL;
|
||||
char *proto = "sip";
|
||||
char *d_user = NULL;
|
||||
char *contact_str = "";
|
||||
char *call_id = NULL;
|
||||
char *to_str = NULL;
|
||||
char *full_from = NULL;
|
||||
char *full_via = NULL;
|
||||
switch_core_db_t *db;
|
||||
char *errmsg;
|
||||
char *sstr;
|
||||
const char *display = "\"user\"";
|
||||
switch_event_t *sevent;
|
||||
|
||||
if (contact) {
|
||||
char *port = (char *) contact->m_url->url_port;
|
||||
|
||||
display = contact->m_display;
|
||||
|
||||
if (switch_strlen_zero(display)) {
|
||||
if (from) {
|
||||
display = from->a_display;
|
||||
if (switch_strlen_zero(display)) {
|
||||
display = "\"user\"";
|
||||
}
|
||||
}
|
||||
} else {
|
||||
display = "\"user\"";
|
||||
}
|
||||
|
||||
if (!port) {
|
||||
port = SOFIA_DEFAULT_PORT;
|
||||
}
|
||||
|
||||
if (contact->m_url->url_params) {
|
||||
contact_str = switch_mprintf("%s <sip:%s@%s:%s;%s>",
|
||||
display, contact->m_url->url_user, contact->m_url->url_host, port, contact->m_url->url_params);
|
||||
} else {
|
||||
contact_str = switch_mprintf("%s <sip:%s@%s:%s>", display, contact->m_url->url_user, contact->m_url->url_host, port);
|
||||
}
|
||||
}
|
||||
|
||||
if (to) {
|
||||
to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host); //, to->a_url->url_port);
|
||||
}
|
||||
|
||||
if (to) {
|
||||
to_user = (char *) to->a_url->url_user;
|
||||
to_host = (char *) to->a_url->url_host;
|
||||
}
|
||||
|
||||
|
||||
if (strstr(to_user, "ext+") || strstr(to_user, "user+") || strstr(to_user, "conf+")) {
|
||||
char proto[80];
|
||||
char *p;
|
||||
|
||||
switch_copy_string(proto, to_user, sizeof(proto));
|
||||
if ((p = strchr(proto, '+'))) {
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
|
||||
switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "login", "%s", profile->name);
|
||||
switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, to_host);
|
||||
switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "rpid", "unknown");
|
||||
switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "status", "Click To Call");
|
||||
switch_event_fire(&sevent);
|
||||
}
|
||||
}
|
||||
|
||||
if (strchr(to_user, '+')) {
|
||||
char *h;
|
||||
if ((proto = (d_user = strdup(to_user)))) {
|
||||
if ((to_user = strchr(d_user, '+'))) {
|
||||
*to_user++ = '\0';
|
||||
if ((h = strchr(to_user, '+')) || (h = strchr(to_user, '@'))) {
|
||||
*h++ = '\0';
|
||||
to_host = h;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(proto && to_user && to_host)) {
|
||||
nua_respond(nh, SIP_404_NOT_FOUND, NUTAG_WITH_THIS(nua), TAG_END());
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
call_id = sip_header_as_string(profile->home, (void *) sip->sip_call_id);
|
||||
event = sip_header_as_string(profile->home, (void *) sip->sip_event);
|
||||
full_from = sip_header_as_string(profile->home, (void *) sip->sip_from);
|
||||
full_via = sip_header_as_string(profile->home, (void *) sip->sip_via);
|
||||
|
||||
exp_raw = (sip->sip_expires ? sip->sip_expires->ex_delta : 3600);
|
||||
exp = (long) time(NULL) + exp_raw;
|
||||
|
||||
if (sip && sip->sip_from) {
|
||||
from_user = (char *) sip->sip_from->a_url->url_user;
|
||||
from_host = (char *) sip->sip_from->a_url->url_host;
|
||||
} else {
|
||||
from_user = "n/a";
|
||||
from_host = "n/a";
|
||||
}
|
||||
|
||||
if ((sql = switch_mprintf("delete from sip_subscriptions where "
|
||||
"proto='%q' and user='%q' and host='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q';\n"
|
||||
"insert into sip_subscriptions values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld)",
|
||||
proto,
|
||||
from_user,
|
||||
from_host,
|
||||
to_user,
|
||||
to_host, event, proto, from_user, from_host, to_user, to_host, event, contact_str, call_id, full_from, full_via, exp))) {
|
||||
sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
|
||||
sstr = switch_mprintf("active;expires=%ld", exp_raw);
|
||||
|
||||
nua_respond(nh, SIP_202_ACCEPTED,
|
||||
NUTAG_WITH_THIS(nua),
|
||||
SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_FROM(sip->sip_to), SIPTAG_TO(sip->sip_from), SIPTAG_CONTACT_STR(to_str), TAG_END());
|
||||
|
||||
|
||||
|
||||
switch_safe_free(sstr);
|
||||
|
||||
if (!(db = switch_core_db_open_file(profile->dbname))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
|
||||
goto end;
|
||||
}
|
||||
if ((sql = switch_mprintf("select * from sip_subscriptions where user='%q' and host='%q'", to_user, to_host, to_user, to_host))) {
|
||||
switch_mutex_lock(profile->ireg_mutex);
|
||||
switch_core_db_exec(db, sql, sofia_presence_sub_reg_callback, profile, &errmsg);
|
||||
switch_mutex_unlock(profile->ireg_mutex);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
switch_core_db_close(db);
|
||||
end:
|
||||
|
||||
if (event) {
|
||||
su_free(profile->home, event);
|
||||
}
|
||||
if (call_id) {
|
||||
su_free(profile->home, call_id);
|
||||
}
|
||||
if (full_from) {
|
||||
su_free(profile->home, full_from);
|
||||
}
|
||||
if (full_via) {
|
||||
su_free(profile->home, full_via);
|
||||
}
|
||||
|
||||
switch_safe_free(d_user);
|
||||
switch_safe_free(to_str);
|
||||
switch_safe_free(contact_str);
|
||||
}
|
||||
}
|
||||
|
||||
void sofia_presence_handle_sip_r_subscribe(int status,
|
||||
char const *phrase,
|
||||
nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void sofia_presence_handle_sip_i_publish(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
|
||||
{
|
||||
if (sip) {
|
||||
sip_from_t const *from = sip->sip_from;
|
||||
char *from_user = NULL;
|
||||
char *from_host = NULL;
|
||||
char *rpid = "unknown";
|
||||
sip_payload_t *payload = sip->sip_payload;
|
||||
char *event_type;
|
||||
|
||||
if (from) {
|
||||
from_user = (char *) from->a_url->url_user;
|
||||
from_host = (char *) from->a_url->url_host;
|
||||
}
|
||||
|
||||
if (payload) {
|
||||
switch_xml_t xml, note, person, tuple, status, basic, act;
|
||||
switch_event_t *event;
|
||||
uint8_t in = 0;
|
||||
char *sql;
|
||||
|
||||
if ((xml = switch_xml_parse_str(payload->pl_data, strlen(payload->pl_data)))) {
|
||||
char *status_txt = "", *note_txt = "";
|
||||
|
||||
if ((tuple = switch_xml_child(xml, "tuple")) && (status = switch_xml_child(tuple, "status"))
|
||||
&& (basic = switch_xml_child(status, "basic"))) {
|
||||
status_txt = basic->txt;
|
||||
}
|
||||
|
||||
if ((person = switch_xml_child(xml, "dm:person")) && (note = switch_xml_child(person, "dm:note"))) {
|
||||
note_txt = note->txt;
|
||||
}
|
||||
|
||||
if (person && (act = switch_xml_child(person, "rpid:activities"))) {
|
||||
if ((rpid = strchr(act->child->name, ':'))) {
|
||||
rpid++;
|
||||
} else {
|
||||
rpid = act->child->name;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strcasecmp(status_txt, "open")) {
|
||||
if (switch_strlen_zero(note_txt)) {
|
||||
note_txt = "Available";
|
||||
}
|
||||
in = 1;
|
||||
} else if (!strcasecmp(status_txt, "closed")) {
|
||||
if (switch_strlen_zero(note_txt)) {
|
||||
note_txt = "Unavailable";
|
||||
}
|
||||
}
|
||||
|
||||
if ((sql =
|
||||
switch_mprintf("update sofia_handle_sip_registrations set status='%q',rpid='%q' where user='%q' and host='%q'",
|
||||
note_txt, rpid, from_user, from_host))) {
|
||||
sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex);
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
|
||||
event_type = sip_header_as_string(profile->home, (void *) sip->sip_event);
|
||||
|
||||
if (in) {
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
|
||||
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", note_txt);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "%s", event_type);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
} else {
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
|
||||
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "%s", event_type);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
|
||||
if (event_type) {
|
||||
su_free(profile->home, event_type);
|
||||
}
|
||||
|
||||
switch_xml_free(xml);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
|
||||
|
||||
}
|
||||
|
||||
void sofia_presence_set_hash_key(char *hash_key, int32_t len, sip_t const *sip)
|
||||
{
|
||||
|
||||
snprintf(hash_key, len, "%s%s%s", (char *) sip->sip_from->a_url->url_user, (char *) sip->sip_from->a_url->url_host,
|
||||
(char *) sip->sip_to->a_url->url_user);
|
||||
|
||||
|
||||
#if 0
|
||||
/* nicer one we cant use in both directions >=0 */
|
||||
snprintf(hash_key, len, "%s%s%s%s%s%s",
|
||||
(char *) sip->sip_to->a_url->url_user,
|
||||
(char *) sip->sip_to->a_url->url_host,
|
||||
(char *) sip->sip_to->a_url->url_params,
|
||||
(char *) sip->sip_from->a_url->url_user, (char *) sip->sip_from->a_url->url_host, (char *) sip->sip_from->a_url->url_params);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
void sofia_presence_handle_sip_i_message(int status,
|
||||
char const *phrase,
|
||||
nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
|
||||
{
|
||||
if (sip) {
|
||||
sip_from_t const *from = sip->sip_from;
|
||||
char *from_user = NULL;
|
||||
char *from_host = NULL;
|
||||
sip_to_t const *to = sip->sip_to;
|
||||
char *to_user = NULL;
|
||||
char *to_host = NULL;
|
||||
sip_subject_t const *sip_subject = sip->sip_subject;
|
||||
sip_payload_t *payload = sip->sip_payload;
|
||||
const char *subject = "n/a";
|
||||
char *msg = NULL;
|
||||
|
||||
if (sip->sip_content_type) {
|
||||
if (strstr((char *) sip->sip_content_type->c_subtype, "composing")) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (from) {
|
||||
from_user = (char *) from->a_url->url_user;
|
||||
from_host = (char *) from->a_url->url_host;
|
||||
}
|
||||
|
||||
if (to) {
|
||||
to_user = (char *) to->a_url->url_user;
|
||||
to_host = (char *) to->a_url->url_host;
|
||||
}
|
||||
|
||||
|
||||
if (!to_user) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (payload) {
|
||||
msg = payload->pl_data;
|
||||
}
|
||||
|
||||
if (sip_subject) {
|
||||
subject = sip_subject->g_value;
|
||||
}
|
||||
|
||||
if (nh) {
|
||||
char hash_key[512];
|
||||
private_object_t *tech_pvt;
|
||||
switch_channel_t *channel;
|
||||
switch_event_t *event;
|
||||
char *to_addr;
|
||||
char *from_addr;
|
||||
char *p;
|
||||
char *full_from;
|
||||
char proto[512] = SOFIA_CHAT_PROTO;
|
||||
|
||||
full_from = sip_header_as_string(profile->home, (void *) sip->sip_from);
|
||||
|
||||
if ((p = strchr(to_user, '+'))) {
|
||||
switch_copy_string(proto, to_user, sizeof(proto));
|
||||
p = strchr(proto, '+');
|
||||
*p++ = '\0';
|
||||
|
||||
if ((to_addr = strdup(p))) {
|
||||
if ((p = strchr(to_addr, '+'))) {
|
||||
*p = '@';
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
to_addr = switch_mprintf("%s@%s", to_user, to_host);
|
||||
}
|
||||
|
||||
from_addr = switch_mprintf("%s@%s", from_user, from_host);
|
||||
|
||||
|
||||
sofia_presence_set_hash_key(hash_key, sizeof(hash_key), sip);
|
||||
if ((tech_pvt = (private_object_t *) switch_core_hash_find(profile->chat_hash, hash_key))) {
|
||||
channel = switch_core_session_get_channel(tech_pvt->session);
|
||||
if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s", tech_pvt->hash_key);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "to", "%s", to_addr);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "subject", "SIMPLE MESSAGE");
|
||||
if (msg) {
|
||||
switch_event_add_body(event, "%s", msg);
|
||||
}
|
||||
if (switch_core_session_queue_event(tech_pvt->session, &event) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch_chat_interface_t *ci;
|
||||
|
||||
if ((ci = switch_loadable_module_get_chat_interface(proto))) {
|
||||
ci->chat_send(SOFIA_CHAT_PROTO, from_addr, to_addr, "", msg, full_from);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Chat Interface [%s]!\n", proto ? proto : "(none)");
|
||||
}
|
||||
|
||||
}
|
||||
switch_safe_free(to_addr);
|
||||
switch_safe_free(from_addr);
|
||||
if (full_from) {
|
||||
su_free(profile->home, full_from);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void sofia_presence_set_chat_hash(private_object_t * tech_pvt, sip_t const *sip)
|
||||
{
|
||||
char hash_key[256] = "";
|
||||
char buf[512];
|
||||
|
||||
if (tech_pvt->hash_key || !sip || !sip->sip_from || !sip->sip_from->a_url || !sip->sip_from->a_url->url_user || !sip->sip_from->a_url->url_host) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (sofia_reg_find_reg_url(tech_pvt->profile, sip->sip_from->a_url->url_user, sip->sip_from->a_url->url_host, buf, sizeof(buf))) {
|
||||
tech_pvt->chat_from = sip_header_as_string(tech_pvt->home, (const sip_header_t *) sip->sip_to);
|
||||
tech_pvt->chat_to = switch_core_session_strdup(tech_pvt->session, buf);
|
||||
sofia_presence_set_hash_key(hash_key, sizeof(hash_key), sip);
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
tech_pvt->hash_key = switch_core_session_strdup(tech_pvt->session, hash_key);
|
||||
switch_core_hash_insert(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt);
|
||||
|
||||
}
|
|
@ -0,0 +1,790 @@
|
|||
#include "mod_sofia.h"
|
||||
|
||||
|
||||
void sofia_reg_unregister(sofia_profile_t * profile)
|
||||
{
|
||||
outbound_reg_t *gateway_ptr;
|
||||
for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
|
||||
if (gateway_ptr->sofia_private) {
|
||||
free(gateway_ptr->sofia_private);
|
||||
nua_handle_bind(gateway_ptr->nh, NULL);
|
||||
gateway_ptr->sofia_private = NULL;
|
||||
}
|
||||
nua_handle_destroy(gateway_ptr->nh);
|
||||
}
|
||||
}
|
||||
|
||||
void sofia_reg_check_gateway(sofia_profile_t * profile, time_t now)
|
||||
{
|
||||
outbound_reg_t *gateway_ptr;
|
||||
for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
|
||||
int ss_state = nua_callstate_authenticating;
|
||||
reg_state_t ostate = gateway_ptr->state;
|
||||
|
||||
switch (ostate) {
|
||||
case REG_STATE_REGISTER:
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "registered %s\n", gateway_ptr->name);
|
||||
gateway_ptr->expires = now + gateway_ptr->freq;
|
||||
gateway_ptr->state = REG_STATE_REGED;
|
||||
break;
|
||||
case REG_STATE_UNREGED:
|
||||
if ((gateway_ptr->nh = nua_handle(gateway_ptr->profile->nua, NULL,
|
||||
NUTAG_URL(gateway_ptr->register_proxy),
|
||||
SIPTAG_TO_STR(gateway_ptr->register_to),
|
||||
NUTAG_CALLSTATE_REF(ss_state), SIPTAG_FROM_STR(gateway_ptr->register_from), TAG_END()))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "registering %s\n", gateway_ptr->name);
|
||||
|
||||
if (!(gateway_ptr->sofia_private = malloc(sizeof(*gateway_ptr->sofia_private)))) {
|
||||
abort();
|
||||
}
|
||||
memset(gateway_ptr->sofia_private, 0, sizeof(*gateway_ptr->sofia_private));
|
||||
|
||||
gateway_ptr->sofia_private->gateway = gateway_ptr;
|
||||
nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private);
|
||||
|
||||
nua_register(gateway_ptr->nh,
|
||||
SIPTAG_FROM_STR(gateway_ptr->register_from),
|
||||
SIPTAG_CONTACT_STR(gateway_ptr->register_contact),
|
||||
SIPTAG_EXPIRES_STR(gateway_ptr->expires_str),
|
||||
NUTAG_REGISTRAR(gateway_ptr->register_proxy),
|
||||
NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL());
|
||||
gateway_ptr->retry = now + 10;
|
||||
gateway_ptr->state = REG_STATE_TRYING;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error registering %s\n", gateway_ptr->name);
|
||||
gateway_ptr->state = REG_STATE_FAILED;
|
||||
}
|
||||
break;
|
||||
|
||||
case REG_STATE_TRYING:
|
||||
if (gateway_ptr->retry && now >= gateway_ptr->retry) {
|
||||
gateway_ptr->state = REG_STATE_UNREGED;
|
||||
gateway_ptr->retry = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
if (now >= gateway_ptr->expires) {
|
||||
gateway_ptr->state = REG_STATE_UNREGED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int sofia_reg_find_callback(void *pArg, int argc, char **argv, char **columnNames)
|
||||
{
|
||||
struct callback_t *cbt = (struct callback_t *) pArg;
|
||||
|
||||
switch_copy_string(cbt->val, argv[0], cbt->len);
|
||||
cbt->matches++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sofia_reg_del_callback(void *pArg, int argc, char **argv, char **columnNames)
|
||||
{
|
||||
switch_event_t *s_event;
|
||||
|
||||
if (argc >= 3) {
|
||||
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_EXPIRE) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile-name", "%s", argv[0]);
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "user", "%s", argv[1]);
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "host", "%s", argv[2]);
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s", argv[3]);
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%s", argv[4]);
|
||||
switch_event_fire(&s_event);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sofia_reg_check_expire(switch_core_db_t *db, sofia_profile_t * profile, time_t now)
|
||||
{
|
||||
char sql[1024];
|
||||
char *errmsg;
|
||||
|
||||
if (!db) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
|
||||
return;
|
||||
}
|
||||
|
||||
switch_mutex_lock(profile->ireg_mutex);
|
||||
snprintf(sql, sizeof(sql), "select '%s',* from sip_registrations where expires > 0 and expires < %ld", profile->name, (long) now);
|
||||
switch_core_db_exec(db, sql, sofia_reg_del_callback, NULL, &errmsg);
|
||||
|
||||
if (errmsg) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s][%s]\n", sql, errmsg);
|
||||
switch_safe_free(errmsg);
|
||||
errmsg = NULL;
|
||||
}
|
||||
|
||||
snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0 and expires < %ld", (long) now);
|
||||
switch_core_db_persistant_execute(db, sql, 1000);
|
||||
snprintf(sql, sizeof(sql), "delete from sip_authentication where expires > 0 and expires < %ld", (long) now);
|
||||
switch_core_db_persistant_execute(db, sql, 1000);
|
||||
snprintf(sql, sizeof(sql), "delete from sip_subscriptions where expires > 0 and expires < %ld", (long) now);
|
||||
switch_core_db_persistant_execute(db, sql, 1000);
|
||||
|
||||
switch_mutex_unlock(profile->ireg_mutex);
|
||||
|
||||
}
|
||||
|
||||
char *sofia_reg_find_reg_url(sofia_profile_t * profile, const char *user, const char *host, char *val, switch_size_t len)
|
||||
{
|
||||
char *errmsg;
|
||||
struct callback_t cbt = { 0 };
|
||||
switch_core_db_t *db;
|
||||
|
||||
if (!user) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Called with null user!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!(db = switch_core_db_open_file(profile->dbname))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cbt.val = val;
|
||||
cbt.len = len;
|
||||
switch_mutex_lock(profile->ireg_mutex);
|
||||
if (host) {
|
||||
snprintf(val, len, "select contact from sip_registrations where user='%s' and host='%s'", user, host);
|
||||
} else {
|
||||
snprintf(val, len, "select contact from sip_registrations where user='%s'", user);
|
||||
}
|
||||
|
||||
switch_core_db_exec(db, val, sofia_reg_find_callback, &cbt, &errmsg);
|
||||
|
||||
if (errmsg) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s][%s]\n", val, errmsg);
|
||||
switch_safe_free(errmsg);
|
||||
errmsg = NULL;
|
||||
}
|
||||
|
||||
switch_mutex_unlock(profile->ireg_mutex);
|
||||
|
||||
switch_core_db_close(db);
|
||||
if (cbt.matches) {
|
||||
return val;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char *sofia_reg_get_auth_data(char *dbname, char *nonce, char *npassword, size_t len, switch_mutex_t * mutex)
|
||||
{
|
||||
switch_core_db_t *db;
|
||||
switch_core_db_stmt_t *stmt;
|
||||
char *sql = NULL, *ret = NULL;
|
||||
|
||||
if (mutex) {
|
||||
switch_mutex_lock(mutex);
|
||||
}
|
||||
|
||||
if (!dbname) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (!(db = switch_core_db_open_file(dbname))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", dbname);
|
||||
goto end;
|
||||
}
|
||||
|
||||
sql = switch_mprintf("select passwd from sip_authentication where nonce='%q'", nonce);
|
||||
if (switch_core_db_prepare(db, sql, -1, &stmt, 0)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Statement Error!\n");
|
||||
goto fail;
|
||||
} else {
|
||||
int running = 1;
|
||||
int colcount;
|
||||
|
||||
while (running < 5000) {
|
||||
int result = switch_core_db_step(stmt);
|
||||
|
||||
if (result == SWITCH_CORE_DB_ROW) {
|
||||
if ((colcount = switch_core_db_column_count(stmt))) {
|
||||
switch_copy_string(npassword, (char *) switch_core_db_column_text(stmt, 0), len);
|
||||
ret = npassword;
|
||||
}
|
||||
break;
|
||||
} else if (result == SWITCH_CORE_DB_BUSY) {
|
||||
running++;
|
||||
switch_yield(1000);
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch_core_db_finalize(stmt);
|
||||
}
|
||||
|
||||
|
||||
fail:
|
||||
|
||||
switch_core_db_close(db);
|
||||
|
||||
end:
|
||||
if (mutex) {
|
||||
switch_mutex_unlock(mutex);
|
||||
}
|
||||
|
||||
if (sql) {
|
||||
switch_safe_free(sql);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sip_t const *sip, sofia_regtype_t regtype, char *key,
|
||||
uint32_t keylen)
|
||||
{
|
||||
sip_from_t const *from = NULL;
|
||||
sip_expires_t const *expires = NULL;
|
||||
sip_authorization_t const *authorization = NULL;
|
||||
sip_contact_t const *contact = NULL;
|
||||
switch_xml_t domain, xml, user, param, xparams;
|
||||
char params[1024] = "";
|
||||
char *sql;
|
||||
switch_event_t *s_event;
|
||||
const char *from_user = NULL;
|
||||
const char *from_host = NULL;
|
||||
char contact_str[1024] = "";
|
||||
char buf[512];
|
||||
const char *passwd = NULL;
|
||||
const char *a1_hash = NULL;
|
||||
uint8_t stale = 0, ret = 0, forbidden = 0;
|
||||
auth_res_t auth_res;
|
||||
long exptime = 60;
|
||||
switch_event_t *event;
|
||||
const char *rpid = "unknown";
|
||||
const char *display = "\"user\"";
|
||||
|
||||
/* all callers must confirm that sip, sip->sip_request and sip->sip_contact are not NULL */
|
||||
assert(sip != NULL && sip->sip_contact != NULL && sip->sip_request != NULL);
|
||||
|
||||
expires = sip->sip_expires;
|
||||
authorization = sip->sip_authorization;
|
||||
contact = sip->sip_contact;
|
||||
from = sip->sip_from;
|
||||
|
||||
if (from) {
|
||||
from_user = from->a_url->url_user;
|
||||
from_host = from->a_url->url_host;
|
||||
}
|
||||
|
||||
if (!from_user || !from_host) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can not do authorization without a complete from header\n");
|
||||
nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (contact->m_url) {
|
||||
const char *port = contact->m_url->url_port;
|
||||
display = contact->m_display;
|
||||
|
||||
if (switch_strlen_zero(display)) {
|
||||
if (from) {
|
||||
display = from->a_display;
|
||||
if (switch_strlen_zero(display)) {
|
||||
display = "\"user\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!port) {
|
||||
port = SOFIA_DEFAULT_PORT;
|
||||
}
|
||||
|
||||
if (contact->m_url->url_params) {
|
||||
snprintf(contact_str, sizeof(contact_str), "%s <sip:%s@%s:%s;%s>",
|
||||
display, contact->m_url->url_user, contact->m_url->url_host, port, contact->m_url->url_params);
|
||||
} else {
|
||||
snprintf(contact_str, sizeof(contact_str), "%s <sip:%s@%s:%s>", display, contact->m_url->url_user, contact->m_url->url_host, port);
|
||||
}
|
||||
}
|
||||
|
||||
if (expires) {
|
||||
exptime = expires->ex_delta;
|
||||
} else if (contact->m_expires) {
|
||||
exptime = atol(contact->m_expires);
|
||||
}
|
||||
|
||||
if (regtype == REG_REGISTER) {
|
||||
authorization = sip->sip_authorization;
|
||||
} else if (regtype == REG_INVITE) {
|
||||
authorization = sip->sip_proxy_authorization;
|
||||
}
|
||||
|
||||
if ((profile->pflags & PFLAG_BLIND_REG)) {
|
||||
goto reg;
|
||||
}
|
||||
|
||||
if (authorization) {
|
||||
if ((auth_res = parse_auth(profile, authorization, sip->sip_request->rq_method_name, key, keylen)) == AUTH_STALE) {
|
||||
stale = 1;
|
||||
}
|
||||
|
||||
if (auth_res != AUTH_OK && !stale) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "send %s for [%s@%s]\n", forbidden ? "forbidden" : "challange", from_user, from_host);
|
||||
if (auth_res == AUTH_FORBIDDEN) {
|
||||
nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
|
||||
} else {
|
||||
nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), TAG_END());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!authorization || stale) {
|
||||
snprintf(params, sizeof(params), "from_user=%s&from_host=%s&contact=%s", from_user, from_host, contact_str);
|
||||
|
||||
|
||||
if (switch_xml_locate("directory", "domain", "name", from_host, &xml, &domain, params) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "can't find domain for [%s@%s]\n", from_user, from_host);
|
||||
nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END());
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(user = switch_xml_find_child(domain, "user", "id", from_user))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find user [%s@%s]\n", from_user, from_host);
|
||||
nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END());
|
||||
switch_xml_free(xml);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!(xparams = switch_xml_child(user, "params"))) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find params for user [%s@%s]\n", from_user, from_host);
|
||||
nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END());
|
||||
switch_xml_free(xml);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
for (param = switch_xml_child(xparams, "param"); param; param = param->next) {
|
||||
const char *var = switch_xml_attr_soft(param, "name");
|
||||
const char *val = switch_xml_attr_soft(param, "value");
|
||||
|
||||
if (!strcasecmp(var, "password")) {
|
||||
passwd = val;
|
||||
}
|
||||
|
||||
if (!strcasecmp(var, "a1-hash")) {
|
||||
a1_hash = val;
|
||||
}
|
||||
}
|
||||
|
||||
if (passwd || a1_hash) {
|
||||
switch_uuid_t uuid;
|
||||
char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
|
||||
char *sql, *auth_str;
|
||||
|
||||
su_md5_t ctx;
|
||||
char hexdigest[2 * SU_MD5_DIGEST_SIZE + 1];
|
||||
char *input;
|
||||
|
||||
if (!a1_hash) {
|
||||
input = switch_mprintf("%s:%s:%s", from_user, from_host, passwd);
|
||||
su_md5_init(&ctx);
|
||||
su_md5_strupdate(&ctx, input);
|
||||
su_md5_hexdigest(&ctx, hexdigest);
|
||||
su_md5_deinit(&ctx);
|
||||
switch_safe_free(input);
|
||||
|
||||
switch_uuid_get(&uuid);
|
||||
switch_uuid_format(uuid_str, &uuid);
|
||||
a1_hash = hexdigest;
|
||||
}
|
||||
|
||||
sql = switch_mprintf("delete from sip_authentication where user='%q' and host='%q';\n"
|
||||
"insert into sip_authentication values('%q','%q','%q','%q', %ld)",
|
||||
from_user, from_host, from_user, from_host, a1_hash, uuid_str, time(NULL) + profile->nonce_ttl);
|
||||
auth_str =
|
||||
switch_mprintf("Digest realm=\"%q\", nonce=\"%q\",%s algorithm=MD5, qop=\"auth\"", from_host, uuid_str, stale ? " stale=\"true\"," : "");
|
||||
|
||||
|
||||
if (regtype == REG_REGISTER) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Requesting Registration from: [%s@%s]\n", from_user, from_host);
|
||||
nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_WWW_AUTHENTICATE_STR(auth_str), TAG_END());
|
||||
} else if (regtype == REG_INVITE) {
|
||||
nua_respond(nh, SIP_407_PROXY_AUTH_REQUIRED, NUTAG_WITH_THIS(nua), SIPTAG_PROXY_AUTHENTICATE_STR(auth_str), TAG_END());
|
||||
|
||||
}
|
||||
|
||||
sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex);
|
||||
switch_safe_free(sql);
|
||||
switch_safe_free(auth_str);
|
||||
ret = 1;
|
||||
} else {
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
switch_xml_free(xml);
|
||||
|
||||
if (ret) {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
reg:
|
||||
|
||||
if (exptime) {
|
||||
if (!sofia_reg_find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) {
|
||||
sql = switch_mprintf("insert into sip_registrations values ('%q','%q','%q','Registered', '%q', %ld)",
|
||||
from_user, from_host, contact_str, rpid, (long) time(NULL) + (long) exptime * 2);
|
||||
|
||||
} else {
|
||||
sql =
|
||||
switch_mprintf
|
||||
("update sip_registrations set contact='%q', expires=%ld, rpid='%q' where user='%q' and host='%q'",
|
||||
contact_str, (long) time(NULL) + (long) exptime * 2, rpid, from_user, from_host);
|
||||
|
||||
}
|
||||
|
||||
if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_REGISTER) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile-name", "%s", profile->name);
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-user", "%s", from_user);
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-host", "%s", from_host);
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s", contact_str);
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
|
||||
switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long) exptime);
|
||||
switch_event_fire(&s_event);
|
||||
}
|
||||
|
||||
if (sql) {
|
||||
sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex);
|
||||
switch_safe_free(sql);
|
||||
sql = NULL;
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
|
||||
"Register:\nFrom: [%s@%s]\nContact: [%s]\nExpires: [%ld]\n", from_user, from_host, contact_str, (long) exptime);
|
||||
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
|
||||
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "Registered");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
} else {
|
||||
if ((sql = switch_mprintf("delete from sip_subscriptions where user='%q' and host='%q'", from_user, from_host))) {
|
||||
sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex);
|
||||
switch_safe_free(sql);
|
||||
sql = NULL;
|
||||
}
|
||||
if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s+%s@%s", SOFIA_CHAT_PROTO, from_user, from_host);
|
||||
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "unavailable");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (switch_event_create(&event, SWITCH_EVENT_ROSTER) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip");
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
|
||||
switch_event_fire(&event);
|
||||
}
|
||||
|
||||
if (regtype == REG_REGISTER) {
|
||||
nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(contact), NUTAG_WITH_THIS(nua), TAG_END());
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void sofia_reg_handle_sip_i_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
|
||||
{
|
||||
char key[128] = "";
|
||||
|
||||
if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n");
|
||||
nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(sip->sip_contact && sip->sip_contact->m_url)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n");
|
||||
nua_respond(nh, 400, "Missing Contact Header", TAG_END());
|
||||
return;
|
||||
}
|
||||
|
||||
sofia_reg_handle_register(nua, profile, nh, sip, REG_REGISTER, key, sizeof(key));
|
||||
}
|
||||
|
||||
|
||||
void sofia_reg_handle_sip_r_register(int status,
|
||||
char const *phrase,
|
||||
nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
|
||||
{
|
||||
if (sofia_private && sofia_private->gateway) {
|
||||
switch (status) {
|
||||
case 200:
|
||||
if (sip && sip->sip_contact && sip->sip_contact->m_expires) {
|
||||
char *new_expires = (char *) sip->sip_contact->m_expires;
|
||||
uint32_t expi = (uint32_t) atoi(new_expires);
|
||||
|
||||
if (expi != sofia_private->gateway->freq) {
|
||||
sofia_private->gateway->freq = expi;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
|
||||
"Changing expire time to %d by request of proxy %s\n", expi, sofia_private->gateway->register_proxy);
|
||||
}
|
||||
|
||||
}
|
||||
sofia_private->gateway->state = REG_STATE_REGISTER;
|
||||
break;
|
||||
case 100:
|
||||
break;
|
||||
default:
|
||||
sofia_private->gateway->state = REG_STATE_FAILED;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Registration Failed with status %d\n", status);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sofia_reg_handle_sip_r_challenge(int status,
|
||||
char const *phrase,
|
||||
nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[])
|
||||
{
|
||||
outbound_reg_t *gateway = NULL;
|
||||
sip_www_authenticate_t const *authenticate = NULL;
|
||||
char const *realm = NULL;
|
||||
char *p = NULL, *duprealm = NULL, *qrealm = NULL;
|
||||
char const *scheme = NULL;
|
||||
int indexnum;
|
||||
char *cur;
|
||||
char authentication[256] = "";
|
||||
int ss_state;
|
||||
|
||||
if (session) {
|
||||
private_object_t *tech_pvt;
|
||||
if ((tech_pvt = switch_core_session_get_private(session)) && switch_test_flag(tech_pvt, TFLAG_REFER)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "received reply from refer\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (sip->sip_www_authenticate) {
|
||||
authenticate = sip->sip_www_authenticate;
|
||||
} else if (sip->sip_proxy_authenticate) {
|
||||
authenticate = sip->sip_proxy_authenticate;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Missing Authenticate Header!\n");
|
||||
return;
|
||||
}
|
||||
scheme = (char const *) authenticate->au_scheme;
|
||||
if (authenticate->au_params) {
|
||||
for (indexnum = 0; (cur = (char *) authenticate->au_params[indexnum]); indexnum++) {
|
||||
if ((realm = strstr(cur, "realm="))) {
|
||||
realm += 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!(scheme && realm)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No scheme and realm!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (profile) {
|
||||
outbound_reg_t *gateway_ptr;
|
||||
|
||||
if ((duprealm = strdup(realm))) {
|
||||
qrealm = duprealm;
|
||||
|
||||
while (*qrealm && *qrealm == '"') {
|
||||
qrealm++;
|
||||
}
|
||||
|
||||
if ((p = strchr(qrealm, '"'))) {
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
if (sip->sip_from) {
|
||||
char *from_key = switch_mprintf("sip:%s@%s",
|
||||
(char *) sip->sip_from->a_url->url_user,
|
||||
(char *) sip->sip_from->a_url->url_host);
|
||||
|
||||
if (!(gateway = sofia_reg_find_gateway(from_key))) {
|
||||
gateway = sofia_reg_find_gateway(qrealm);
|
||||
}
|
||||
|
||||
switch_safe_free(from_key);
|
||||
}
|
||||
|
||||
if (!gateway) {
|
||||
for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
|
||||
if (scheme && qrealm && !strcasecmp(gateway_ptr->register_scheme, scheme)
|
||||
&& !strcasecmp(gateway_ptr->register_realm, qrealm)) {
|
||||
gateway = gateway_ptr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!gateway) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Match for Scheme [%s] Realm [%s]\n", scheme, qrealm);
|
||||
return;
|
||||
}
|
||||
switch_safe_free(duprealm);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
snprintf(authentication, sizeof(authentication), "%s:%s:%s:%s", scheme, realm, gateway->register_username, gateway->register_password);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Authenticating '%s' with '%s'.\n", profile->username, authentication);
|
||||
|
||||
|
||||
ss_state = nua_callstate_authenticating;
|
||||
|
||||
tl_gets(tags, NUTAG_CALLSTATE_REF(ss_state), SIPTAG_WWW_AUTHENTICATE_REF(authenticate), TAG_END());
|
||||
|
||||
nua_authenticate(nh, SIPTAG_EXPIRES_STR(gateway->expires_str), NUTAG_AUTH(authentication), TAG_END());
|
||||
|
||||
}
|
||||
|
||||
auth_res_t parse_auth(sofia_profile_t * profile, sip_authorization_t const *authorization, const char *regstr, char *np, size_t nplen)
|
||||
{
|
||||
int indexnum;
|
||||
const char *cur;
|
||||
su_md5_t ctx;
|
||||
char uridigest[2 * SU_MD5_DIGEST_SIZE + 1];
|
||||
char bigdigest[2 * SU_MD5_DIGEST_SIZE + 1];
|
||||
char *nonce, *uri, *qop, *cnonce, *nc, *response, *input = NULL, *input2 = NULL;
|
||||
auth_res_t ret = AUTH_FORBIDDEN;
|
||||
char *npassword = NULL;
|
||||
int cnt = 0;
|
||||
nonce = uri = qop = cnonce = nc = response = NULL;
|
||||
|
||||
if (authorization->au_params) {
|
||||
for (indexnum = 0; (cur = authorization->au_params[indexnum]); indexnum++) {
|
||||
char *var, *val, *p, *work;
|
||||
var = val = work = NULL;
|
||||
if ((work = strdup(cur))) {
|
||||
var = work;
|
||||
if ((val = strchr(var, '='))) {
|
||||
*val++ = '\0';
|
||||
while (*val == '"') {
|
||||
*val++ = '\0';
|
||||
}
|
||||
if ((p = strchr(val, '"'))) {
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
if (!strcasecmp(var, "nonce")) {
|
||||
nonce = strdup(val);
|
||||
cnt++;
|
||||
} else if (!strcasecmp(var, "uri")) {
|
||||
uri = strdup(val);
|
||||
cnt++;
|
||||
} else if (!strcasecmp(var, "qop")) {
|
||||
qop = strdup(val);
|
||||
cnt++;
|
||||
} else if (!strcasecmp(var, "cnonce")) {
|
||||
cnonce = strdup(val);
|
||||
cnt++;
|
||||
} else if (!strcasecmp(var, "response")) {
|
||||
response = strdup(val);
|
||||
cnt++;
|
||||
} else if (!strcasecmp(var, "nc")) {
|
||||
nc = strdup(val);
|
||||
cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
free(work);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (cnt != 6) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Authorization header!\n");
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (switch_strlen_zero(np)) {
|
||||
if (!sofia_reg_get_auth_data(profile->dbname, nonce, np, nplen, profile->ireg_mutex)) {
|
||||
ret = AUTH_STALE;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
|
||||
npassword = np;
|
||||
|
||||
if ((input = switch_mprintf("%s:%q", regstr, uri))) {
|
||||
su_md5_init(&ctx);
|
||||
su_md5_strupdate(&ctx, input);
|
||||
su_md5_hexdigest(&ctx, uridigest);
|
||||
su_md5_deinit(&ctx);
|
||||
}
|
||||
|
||||
if ((input2 = switch_mprintf("%q:%q:%q:%q:%q:%q", npassword, nonce, nc, cnonce, qop, uridigest))) {
|
||||
memset(&ctx, 0, sizeof(ctx));
|
||||
su_md5_init(&ctx);
|
||||
su_md5_strupdate(&ctx, input2);
|
||||
su_md5_hexdigest(&ctx, bigdigest);
|
||||
su_md5_deinit(&ctx);
|
||||
|
||||
if (!strcasecmp(bigdigest, response)) {
|
||||
ret = AUTH_OK;
|
||||
} else {
|
||||
ret = AUTH_FORBIDDEN;
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
switch_safe_free(input);
|
||||
switch_safe_free(input2);
|
||||
switch_safe_free(nonce);
|
||||
switch_safe_free(uri);
|
||||
switch_safe_free(qop);
|
||||
switch_safe_free(cnonce);
|
||||
switch_safe_free(nc);
|
||||
switch_safe_free(response);
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
|
||||
outbound_reg_t *sofia_reg_find_gateway(char *key)
|
||||
{
|
||||
outbound_reg_t *gateway;
|
||||
|
||||
switch_mutex_lock(globals.hash_mutex);
|
||||
gateway = (outbound_reg_t *) switch_core_hash_find(globals.gateway_hash, key);
|
||||
switch_mutex_unlock(globals.hash_mutex);
|
||||
|
||||
return gateway;
|
||||
}
|
||||
|
||||
void sofia_reg_add_gateway(char *key, outbound_reg_t * gateway)
|
||||
{
|
||||
switch_mutex_lock(globals.hash_mutex);
|
||||
switch_core_hash_insert(globals.gateway_hash, key, gateway);
|
||||
switch_mutex_unlock(globals.hash_mutex);
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue