@ -4,6 +4,7 @@
#!trydef PRESENCE_MAX_EXPIRES 3600
#!trydef PRESENCE_MAX_EXPIRES 3600
modparam("htable", "htable", "p = >size=32;autoexpire=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.so"
loadmodule "presence_dialoginfo.so"
loadmodule "presence_dialoginfo.so"
@ -26,58 +27,134 @@ modparam("presence", "min_expires", PRESENCE_MIN_EXPIRES)
modparam("presence", "max_expires", PRESENCE_MAX_EXPIRES)
modparam("presence", "max_expires", PRESENCE_MAX_EXPIRES)
modparam("presence", "sip_uri_match", 1)
modparam("presence", "sip_uri_match", 1)
modparam("presence", "waitn_time", 1)
modparam("presence", "waitn_time", 1)
modparam("presence", "notifier_processes", 5 )
modparam("presence", "notifier_processes", 10 )
modparam("presence", "db_url", "KAZOO_DB_URL")
modparam("presence", "db_url", "KAZOO_DB_URL")
modparam("presence", "xavp_cfg", "pres")
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", "db_url", "KAZOO_DB_URL")
modparam("kazoo", "pua_mode", 1)
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 ########
####### Presence Logic ########
route[HANDLE_SUBSCRIBE]
route[HANDLE_SUBSCRIBE]
{
{
if (is_method("SUBSCRIBE")) {
#!ifdef NAT_TRAVERSAL_ROLE
route(NAT_TEST_AND_CORRECT);
#!endif
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(to_user)::$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) {
if ($tU = = $null) {
xlog("L_INFO", "$ci|stop|ignoring subscribe with empty TO username from a $ua\n");
xlog("L_INFO", "$ci|stop|ignoring subscribe with empty TO username from a $ua\n");
sl_send_reply(400, "Missing TO username");
exit;
send_reply(400, "Missing TO username");
r eturn ;
}
}
if ($fU = = $null) {
if ($fU = = $null) {
xlog("L_INFO", "$ci|stop|ignoring subscribe with empty FROM username from a $ua\n");
xlog("L_INFO", "$ci|stop|ignoring subscribe with empty FROM username from a $ua\n");
sl_send_reply(400, "Missing FROM username");
exit;
send_reply(400, "Missing FROM username");
r eturn ;
}
}
if (!handle_subscribe()) {
xlog("L_INFO", "$ci|stop|unsupported subsribe\n");
exit;
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 {
if($shtinc(first = >$fU::$tU::$fd::$hdr(Event)) > 1) {
sql_query("exec", 'delete from active_watchers where watcher_username = "$fU" and to_user="$tU" and watcher_domain="$fd" and event="$hdr(Event)"');
xlog("L_INFO", "$ci|subscribe|resetting $hdr(Event) subscription from $fU to $tU in realm $fd : $sqlrows(exec)\n");
}
}
}
$var(Expires) = $hdr(Expires);
if($var(Expires) < PRESENCE_MIN_EXPIRES) {
$var(Expires) = PRESENCE_MIN_EXPIRES;
} else if($var(Expires) > PRESENCE_MAX_EXPIRES) {
$var(Expires) = PRESENCE_MAX_EXPIRES;
}
##RabbitMQ
$var(fs_path) = "%3C" + $rz + "%3A" + $Ri + "%3A" + $Rp + "%3Btransport=" + $proto + "%3Blr%3Breceived=" + $si+":"+$sp+"%3E";
$var(fs_contact) = "<" + $(ct{tobody.uri}) + ";fs_path=" + $var(fs_path) + ">";
if($(ct{tobody.params}) ! = $null) {
$var(fs_contact) = $var(fs_contact) + ";" + $(ct{tobody.params});
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");
}
}
$var(amqp_payload_request) = '{"Event-Category" : "presence", "Event-Name" : "subscription", "Event-Package" : "$hdr(event)", "Expires" : "$var(Expires)", "Queue" : "BLF-MY_HOSTNAME", "Server-ID" : "BLF-MY_HOSTNAME" , "Contact" : "$(ct{s.escape.common})", "Call-ID" : "$ci", "From" : "$fu", "User" : "$subs(uri)", "User-Agent" : "$(ua{s.escape.common})" }';
route[SUBSCRIBE_AMQP]
{
$var(Expires) = $hdr(Expires);
if($var(Expires) < PRESENCE_MIN_EXPIRES) {
$var(Expires) = PRESENCE_MIN_EXPIRES;
} else if($var(Expires) > PRESENCE_MAX_EXPIRES) {
$var(Expires) = PRESENCE_MAX_EXPIRES;
}
kazoo_publish("dialoginfo_subs", "dialoginfo_subs", $var(amqp_payload_request));
$var(amqp_payload_request) = $_s({"Event-Category" : "presence", "Event-Name" : "subscription", "Event-Package" : "$hdr(event)", "Expires" : "$var(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("dialoginfo_subs", "dialoginfo_subs", $var(amqp_payload_request));
exit;
}
}
}
route[HANDLE_PUBLISH]
route[HANDLE_PUBLISH]
@ -96,10 +173,57 @@ route[HANDLE_PUBLISH]
}
}
}
}
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]
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[HANDLE_PRESENCE_UPDATE]
{
{
$var(call-id) = $(kzE{kz.json,Call-ID});
$var(call-id) = $(kzE{kz.json,Call-ID});
if( $(kzE{kz.json,Event-Package}) = = "dialog") {
if( $(kzE{kz.json,Event-Package}) = = "dialog") {
if($sht(p = >$var(call-id)) != $(kzE{kz.json,State}) || $(kzE{kz.json,Flush-Level}) != $null) {
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");
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});
$sht(p = >$(kzE{kz.json,Call-ID})) = $(kzE{kz.json,State});
@ -108,10 +232,14 @@ event_route[kazoo:consumer-event-presence-update]
#!endif
#!endif
kazoo_pua_publish($kzE);
kazoo_pua_publish($kzE);
pres_refresh_watchers("$(kzE{kz.json,From})", "$(kzE{kz.json,Event-Package})", 1);
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 {
} 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|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");
xlog("L_INFO", "$var(call-id)|log|payload $kzE\n");
}
}
} else {
} else {
xlog("L_INFO", "$var(call-id)|log|received $(kzE{kz.json,Event-Package}) update for $(kzE{kz.json,From}) $kzE\n");
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);
kazoo_pua_publish($kzE);