|
|
######## Presence server module ########
|
|
|
#!trydef PRESENCE_MIN_EXPIRES 300
|
|
|
#!trydef PRESENCE_MIN_EXPIRES_ACTION 1
|
|
|
#!trydef PRESENCE_MAX_EXPIRES 3600
|
|
|
|
|
|
modparam("htable", "htable", "p=>size=32;autoexpire=3600;")
|
|
|
modparam("htable", "htable", "first=>size=32;autoexpire=3600;initval =0;updateexpire=1")
|
|
|
|
|
|
loadmodule "presence.so"
|
|
|
loadmodule "presence_dialoginfo.so"
|
|
|
loadmodule "presence_mwi.so"
|
|
|
loadmodule "presence_xml.so"
|
|
|
|
|
|
modparam("presence_dialoginfo", "force_dummy_dialog", 1)
|
|
|
modparam("presence_dialoginfo", "force_single_dialog", BLF_USE_SINGLE_DIALOG)
|
|
|
|
|
|
modparam("presence_xml", "force_dummy_presence", 1)
|
|
|
modparam("presence_xml", "force_active", 1)
|
|
|
modparam("presence_xml", "disable_winfo", 1)
|
|
|
modparam("presence_xml", "disable_bla", 1)
|
|
|
|
|
|
modparam("presence", "subs_db_mode", 3)
|
|
|
modparam("presence", "expires_offset", 0)
|
|
|
modparam("presence", "send_fast_notify", 1)
|
|
|
modparam("presence", "clean_period", 30)
|
|
|
modparam("presence", "db_update_period", 10)
|
|
|
modparam("presence", "publ_cache", 0)
|
|
|
modparam("presence", "min_expires_action", PRESENCE_MIN_EXPIRES_ACTION)
|
|
|
modparam("presence", "min_expires", PRESENCE_MIN_EXPIRES)
|
|
|
modparam("presence", "max_expires", PRESENCE_MAX_EXPIRES)
|
|
|
modparam("presence", "sip_uri_match", 1)
|
|
|
modparam("presence", "waitn_time", 1)
|
|
|
modparam("presence", "notifier_processes", 10)
|
|
|
modparam("presence", "db_url", "KAZOO_DB_URL")
|
|
|
modparam("presence", "xavp_cfg", "pres")
|
|
|
modparam("presence", "local_log_level", 6)
|
|
|
modparam("presence", "startup_mode", 0)
|
|
|
modparam("presence", "force_delete", 1)
|
|
|
modparam("presence", "timeout_rm_subs", 0)
|
|
|
modparam("presence", "cseq_offset", 1)
|
|
|
|
|
|
modparam("kazoo", "db_url", "KAZOO_DB_URL")
|
|
|
modparam("kazoo", "pua_mode", 1)
|
|
|
|
|
|
#!ifdef NAT_TRAVERSAL_ROLE
|
|
|
#!ifndef NAT_TRAVERSAL_LOADED
|
|
|
#!trydef NAT_TRAVERSAL_LOADED
|
|
|
loadmodule "nat_traversal.so"
|
|
|
#!endif
|
|
|
modparam("nat_traversal", "keepalive_method", "OPTIONS")
|
|
|
modparam("nat_traversal", "keepalive_from", "sip:sipcheck@MY_HOSTNAME")
|
|
|
modparam("nat_traversal", "keepalive_state_file", "KAZOO_DATA_DIR/keep_alive_state")
|
|
|
modparam("nat_traversal", "keepalive_interval", 45)
|
|
|
#!endif
|
|
|
|
|
|
|
|
|
####### SQL OPS module ##########
|
|
|
#!ifndef SQLOPS_LOADED
|
|
|
loadmodule "sqlops.so"
|
|
|
#!trydef SQLOPS_LOADED
|
|
|
#!endif
|
|
|
modparam("sqlops","sqlcon", "exec=>KAZOO_DB_URL")
|
|
|
|
|
|
route[PRESENCE_NAT]
|
|
|
{
|
|
|
if (client_nat_test("3")) {
|
|
|
fix_contact();
|
|
|
}
|
|
|
|
|
|
nat_keepalive();
|
|
|
force_rport();
|
|
|
|
|
|
}
|
|
|
|
|
|
####### Presence Logic ########
|
|
|
route[HANDLE_SUBSCRIBE]
|
|
|
{
|
|
|
if (!is_method("SUBSCRIBE")) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
#!ifdef NAT_TRAVERSAL_ROLE
|
|
|
route(PRESENCE_NAT);
|
|
|
#!endif
|
|
|
|
|
|
if(has_totag()) {
|
|
|
route(HANDLE_RESUBSCRIBE);
|
|
|
} else {
|
|
|
route(HANDLE_NEW_SUBSCRIBE);
|
|
|
}
|
|
|
|
|
|
exit;
|
|
|
}
|
|
|
|
|
|
route[HANDLE_RESUBSCRIBE]
|
|
|
{
|
|
|
loose_route();
|
|
|
if(handle_subscribe()) {
|
|
|
if($subs(remote_cseq) < 5) {
|
|
|
$sht(first=>$subs(callid)) = $null;
|
|
|
$sht(first=>$subs(from_user)::$subs(pres_uri)::$subs(from_domain)::$subs(event)) = $null;
|
|
|
}
|
|
|
route(SUBSCRIBE_AMQP);
|
|
|
};
|
|
|
}
|
|
|
|
|
|
|
|
|
route[HANDLE_NEW_SUBSCRIBE]
|
|
|
{
|
|
|
if ($hdr(Event) == "dialog"
|
|
|
|| $hdr(Event) == "presence"
|
|
|
|| $hdr(Event) == "message-summary") {
|
|
|
|
|
|
|
|
|
if ($tU == $null) {
|
|
|
xlog("L_INFO", "$ci|stop|ignoring subscribe with empty TO username from a $ua\n");
|
|
|
send_reply(400, "Missing TO username");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if ($fU == $null) {
|
|
|
xlog("L_INFO", "$ci|stop|ignoring subscribe with empty FROM username from a $ua\n");
|
|
|
send_reply(400, "Missing FROM username");
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
if($shtinc(first=>$ci) > 1) {
|
|
|
sql_query("exec", 'delete from active_watchers where callid = "$ci"');
|
|
|
xlog("L_INFO", "$ci|subscribe|resetting $hdr(Event) subscription from $fU to $tU in realm $fd : $sqlrows(exec)\n");
|
|
|
} else {
|
|
|
$var(presentity_uri) = $ru;
|
|
|
if($(var(presentity_uri){uri.user}) == "") {
|
|
|
$var(presentity_uri) = $tu;
|
|
|
}
|
|
|
if($shtinc(first=>$fU::$var(presentity_uri)::$fd::$hdr(Event)) > 1) {
|
|
|
sql_query("exec", 'delete from active_watchers where watcher_username="$fU" and presentity_uri="$var(presentity_uri)" and to_user="$tU" and watcher_domain="$fd" and event="$hdr(Event)"');
|
|
|
xlog("L_INFO", "$ci|subscribe|resetting $hdr(Event) subscription from $fU to $var(presentity_uri) in realm $fd : $sqlrows(exec)\n");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (handle_subscribe()) {
|
|
|
route(SUBSCRIBE_AMQP);
|
|
|
xlog("L_INFO","$ci|end|new $hdr(Event) subscription from $fU to $tU in realm $fd : $sht(first=>$ci) : $sht(first=>$fU::$tU::$fd::$hdr(Event))\n");
|
|
|
} else {
|
|
|
xlog("L_INFO", "$ci|stop|error $T_reply_code for new $hdr(Event) subscription from $fU to $tU in realm $fd\n");
|
|
|
}
|
|
|
} else {
|
|
|
xlog("L_INFO", "$ci|stop|unsupported subscription package $hdr(Event) from $fU to $tU in realm $fd\n");
|
|
|
send_reply(489, "Bad Event");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
route[SUBSCRIBE_AMQP]
|
|
|
{
|
|
|
$var(rk) = "subscribe." + $(subs(to_domain){kz.encode}) + "." + $(subs(to_user){kz.encode});
|
|
|
$var(amqp_payload_request) = $_s({"Event-Category" : "presence", "Event-Name" : "subscription", "Event-Package" : "$hdr(event)", "Expires" : $subs(expires), "Queue" : "BLF-MY_HOSTNAME", "Server-ID" : "BLF-MY_HOSTNAME" , "Contact" : "$(ct{s.escape.common}{s.replace,\','}{s.replace,$$,})", "Call-ID" : "$ci", "From" : "$fu", "User" : "$subs(uri)", "User-Agent" : "$(ua{s.escape.common}{s.replace,\','}{s.replace,$$,})" });
|
|
|
kazoo_publish("omnipresence", "$var(rk)", $var(amqp_payload_request));
|
|
|
}
|
|
|
|
|
|
route[HANDLE_PUBLISH]
|
|
|
{
|
|
|
if (is_method("PUBLISH")) {
|
|
|
if (!t_newtran()) {
|
|
|
sl_reply_error();
|
|
|
exit;
|
|
|
}
|
|
|
if($hdr(Sender)!= $null)
|
|
|
handle_publish("$hdr(Sender)");
|
|
|
else
|
|
|
handle_publish();
|
|
|
t_release();
|
|
|
exit;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
event_route[kazoo:consumer-event-presence-dialog-update]
|
|
|
{
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|received $(kzE{kz.json,Event-Package}) update for $(kzE{kz.json,From}) state $(kzE{kz.json,State})\n");
|
|
|
if(pres_has_subscribers("$(kzE{kz.json,From})", "dialog")) {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|publishing dialog update for $(kzE{kz.json,From})\n");
|
|
|
kazoo_pua_publish_dialoginfo($kzE);
|
|
|
pres_refresh_watchers("$(kzE{kz.json,From})", "dialog", 1);
|
|
|
} else {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|skip dialog update for $(kzE{kz.json,From})\n");
|
|
|
}
|
|
|
|
|
|
|
|
|
if(pres_has_subscribers("$(kzE{kz.json,From})", "presence")) {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|publishing presence update for $(kzE{kz.json,From})\n");
|
|
|
kazoo_pua_publish_presence($kzE);
|
|
|
pres_refresh_watchers("$(kzE{kz.json,From})", "presence", 1);
|
|
|
} else {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|skip presence update for $(kzE{kz.json,From})\n");
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
event_route[kazoo:consumer-event-presence-mwi-update]
|
|
|
{
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|received message-summary update for $(kzE{kz.json,From})\n");
|
|
|
if(pres_has_subscribers("$(kzE{kz.json,From})", "message-summary")) {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|publishing message-summary update for $(kzE{kz.json,From})\n");
|
|
|
kazoo_pua_publish_mwi($kzE);
|
|
|
pres_refresh_watchers("$(kzE{kz.json,From})", "message-summary", 1);
|
|
|
} else {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|skip message-summary update for $(kzE{kz.json,From})\n");
|
|
|
}
|
|
|
}
|
|
|
|
|
|
event_route[kazoo:consumer-event-presence-update]
|
|
|
{
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|received presence update for $(kzE{kz.json,From})\n");
|
|
|
if(pres_has_subscribers("$(kzE{kz.json,From})", "presence")) {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|publishing presence update for $(kzE{kz.json,From})\n");
|
|
|
kazoo_pua_publish_presence($kzE);
|
|
|
pres_refresh_watchers("$(kzE{kz.json,From})", "presence", 1);
|
|
|
} else {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|skip presence update for $(kzE{kz.json,From})\n");
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
route[RESET_ZONE]
|
|
|
{
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|received presence reset for this zone\n");
|
|
|
sql_query("exec", "delete from presentity");
|
|
|
$var(presentities) = $sqlrows(exec);
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|removed $var(presentities) presentities\n");
|
|
|
}
|
|
|
|
|
|
route[RESET_ACCOUNT]
|
|
|
{
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|received presence reset for realm $(kzE{kz.json,Realm})\n");
|
|
|
sql_query("exec", 'delete from presentity where domain="$(kzE{kz.json,Realm})" ');
|
|
|
$var(presentities) = $sqlrows(exec);
|
|
|
sql_query("exec", 'update active_watchers set expires = $TS where watcher_domain="$(kzE{kz.json,Realm})" ');
|
|
|
$var(watchers) = $sqlrows(exec);
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|removed $var(presentities) presentities and expired $var(watchers) subscribers for realm $(kzE{kz.json,Realm})\n");
|
|
|
}
|
|
|
|
|
|
route[RESET_WILDCARD]
|
|
|
{
|
|
|
if($(kzE{kz.json,Realm}) == "*") {
|
|
|
if($(kzE{kz.json,Username}) == "MY_AMQP_ZONE") {
|
|
|
route(RESET_ZONE);
|
|
|
} else {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|received presence reset for zone $(kzE{kz.json,Username}). 'MY_AMQP_ZONE' doesn't care\n");
|
|
|
}
|
|
|
exit();
|
|
|
} else {
|
|
|
route(RESET_ACCOUNT);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
event_route[kazoo:consumer-event-presence-reset]
|
|
|
{
|
|
|
if($(kzE{kz.json,Username}) == "*" || $(kzE{kz.json,Realm}) == "*") {
|
|
|
route(RESET_WILDCARD);
|
|
|
exit();
|
|
|
}
|
|
|
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|received presence reset for $(kzE{kz.json,Username})@$(kzE{kz.json,Realm})\n");
|
|
|
$var(presentity) = "sip:" + $(kzE{kz.json,Username}) + "@" + $(kzE{kz.json,Realm});
|
|
|
sql_query("exec", 'delete from presentity where domain="$(kzE{kz.json,Realm})" and username = "$(kzE{kz.json,Username})"');
|
|
|
if(pres_has_subscribers("$var(presentity)", "message-summary")) {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|notifying message-summary subscribers of $var(presentity)\n");
|
|
|
pres_refresh_watchers("$var(presentity)", "message-summary", 1);
|
|
|
} else {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|skip message-summary subscriber notification for $var(presentity))\n");
|
|
|
}
|
|
|
|
|
|
if(pres_has_subscribers("$var(presentity)", "presence")) {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|notifying presence subscribers of $var(presentity)\n");
|
|
|
pres_refresh_watchers("$var(presentity)", "presence", 1);
|
|
|
} else {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|skip presence subscriber notification for $var(presentity))\n");
|
|
|
}
|
|
|
|
|
|
if(pres_has_subscribers("$var(presentity)", "dialog")) {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|notifying dialog subscribers of $var(presentity)\n");
|
|
|
pres_refresh_watchers("$var(presentity)", "dialog", 1);
|
|
|
} else {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Msg-ID})|reset|skip dialog subscriber notification for $var(presentity))\n");
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
route[HANDLE_PRESENCE_UPDATE]
|
|
|
{
|
|
|
$var(call-id) = $(kzE{kz.json,Call-ID});
|
|
|
if( $(kzE{kz.json,Event-Package}) == "dialog") {
|
|
|
if($sht(p=>$var(call-id)) != $(kzE{kz.json,State}) || $(kzE{kz.json,Flush-Level}) != $null) {
|
|
|
xlog("L_INFO", "$(kzE{kz.json,Target-Call-ID})|log|received $(kzE{kz.json,Event-Package}) update for $(kzE{kz.json,From}) state $(kzE{kz.json,State}) $kzE\n");
|
|
|
$sht(p=>$(kzE{kz.json,Call-ID})) = $(kzE{kz.json,State});
|
|
|
#!ifdef FAST_PICKUP_ROLE
|
|
|
route(FAST_PICKUP_INIT);
|
|
|
#!endif
|
|
|
kazoo_pua_publish($kzE);
|
|
|
pres_refresh_watchers("$(kzE{kz.json,From})", "$(kzE{kz.json,Event-Package})", 1);
|
|
|
$var(Presence) = $(kzE{re.subst,/"Event-Package": "dialog"/"Event-Package": "presence"/g});
|
|
|
xlog("L_INFO", "PRESENCE $var(Presence)");
|
|
|
kazoo_pua_publish($var(Presence));
|
|
|
pres_refresh_watchers("$(var(Presence){kz.json,From})", "$(var(Presence){kz.json,Event-Package})", 1);
|
|
|
} else {
|
|
|
xlog("L_INFO", "$var(call-id)|log|received duplicate $(kzE{kz.json,Event-Package}) update for $(kzE{kz.json,From}) state $(kzE{kz.json,State}) $kzE\n");
|
|
|
xlog("L_INFO", "$var(call-id)|log|payload $kzE\n");
|
|
|
}
|
|
|
} else {
|
|
|
xlog("L_INFO", "$var(call-id)|log|received $(kzE{kz.json,Event-Package}) update for $(kzE{kz.json,From}) $kzE\n");
|
|
|
kazoo_pua_publish($kzE);
|
|
|
pres_refresh_watchers("$(kzE{kz.json,From})", "$(kzE{kz.json,Event-Package})", 1);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
#!ifndef PRESENCE_CUSTOM_BINDINGS
|
|
|
route[PRESENCE_BINDINGS]
|
|
|
{
|
|
|
$var(payload) = "{ 'exchange' : 'presence' , 'queue' : 'presence-dialog-MY_HOSTNAME', 'exclusive' : 0 ,'type' : 'topic', 'routing' : 'dialog.*.*', 'federate' : 1 }";
|
|
|
kazoo_subscribe("$var(payload)");
|
|
|
|
|
|
$var(payload) = "{ 'exchange' : 'presence' , 'queue' : 'presence-presence-MY_HOSTNAME', 'exclusive' : 0 ,'type' : 'topic', 'routing' : 'update.*.*', 'federate' : 1 }";
|
|
|
kazoo_subscribe("$var(payload)");
|
|
|
|
|
|
$var(payload) = "{ 'exchange' : 'presence' , 'queue' : 'presence-mwi-MY_HOSTNAME', 'exclusive' : 0 ,'type' : 'topic', 'routing' : 'mwi_updates.*', 'federate' : 1 }";
|
|
|
kazoo_subscribe("$var(payload)");
|
|
|
|
|
|
$var(payload) = "{ 'exchange' : 'presence' , 'queue' : 'presence-reset-MY_HOSTNAME', 'exclusive' : 0 ,'type' : 'topic', 'routing' : 'presence.reset.*.*', 'federate' : 1 }";
|
|
|
kazoo_subscribe("$var(payload)");
|
|
|
|
|
|
}
|
|
|
#!endif
|
|
|
|
|
|
# vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab
|