######## 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", 0) 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 kazoo.presence_sync_amqp = 0 descr "sync subscriptions to amqp" #!ifdef FAST_PICKUP_ROLE #!include_file "fast-pickup-role.cfg" #!endif #!ifdef PRESENCE_QUERY_ROLE #!include_file "presence_query-role.cfg" #!endif #!ifdef PRESENCE_NOTIFY_SYNC_ROLE #!include_file "presence_notify_sync-role.cfg" #!endif ####### Presence Logic ######## #!ifdef NAT_TRAVERSAL_ROLE route[PRESENCE_NAT] { force_rport(); if (client_nat_test("3")) { if(is_first_hop()) set_contact_alias(); } nat_keepalive(); } #!endif route[HANDLE_SUBSCRIBE] { if (!is_method("SUBSCRIBE")) { return; } #!ifdef NAT_TRAVERSAL_ROLE route(PRESENCE_NAT); #!endif if(has_totag()) { loose_route(); } record_route(); if (!t_newtran()) { sl_reply_error(); exit; } if(has_totag()) { route(HANDLE_RESUBSCRIBE); } else { route(HANDLE_NEW_SUBSCRIBE); } t_release(); exit; } route[HANDLE_RESUBSCRIBE] { 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", 'KZQ_HANDLE_NEW_SUBSCRIBE_DELETE1'); 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", 'KZQ_HANDLE_NEW_SUBSCRIBE_DELETE2'); 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] { if(@cfg_get.kazoo.presence_sync_amqp == 1) { $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; } } route[COUNT_PRESENTITIES] { $var(Query) = $_s(KZQ_COUNT_PRESENTITIES); $var(p) = $_s(uri=$var(presentity)); if (sql_xquery("cb", "$var(Query)", "subs") == 1) { while($xavp(subs) != $null) { $var(p) = $var(p) + ";" + $xavp(subs=>event) + "=" + $xavp(subs=>count); pv_unset("$xavp(subs)"); } } xavp_params_explode($var(p), "watchers"); } route[COUNT_ALL_PRESENTITIES] { $var(Query) = $_s(select event, (select count(*) from presentity b where b.event = a.event) count from event_list a); $var(p) = "uri=none"; if (sql_xquery("cb", "$var(Query)", "subs") == 1) { while($xavp(subs) != $null) { $var(p) = $var(p) + ";" + $xavp(subs=>event) + "=" + $xavp(subs=>count); pv_unset("$xavp(subs)"); } } xavp_params_explode($var(p), "watchers"); } route[COUNT_ALL_SUBSCRIBERS] { $var(Query) = $_s(KZQ_COUNT_ALL_SUBSCRIBERS); if (sql_xquery("cb", "$var(Query)", "subs") == 1) { $var(sep) = ""; $var(Subscribers) = ""; $var(Subscriptions) = ""; while($xavp(subs) != $null) { $var(Subscribers) = $var(Subscribers) + $var(sep) + $_s("$xavp(subs=>event)" : $xavp(subs=>count_unique)); $var(Subscriptions) = $var(Subscriptions) + $var(sep) + $_s("$xavp(subs=>event)" : $xavp(subs=>count)); $var(sep) = " , "; pv_unset("$xavp(subs)"); } } } route[COUNT_SUBSCRIBERS] { $var(Query) = $_s(KZQ_COUNT_SUBSCRIBERS); $var(p) = $_s(uri=$var(presentity)); if (sql_xquery("cb", "$var(Query)", "subs") == 1) { while($xavp(subs) != $null) { $var(p) = $var(p) + ";" + $xavp(subs=>event) + "=" + $xavp(subs=>count); pv_unset("$xavp(subs)"); } } xavp_params_explode($var(p), "watchers"); } event_route[kazoo:consumer-event-presence-dialog-update] { $var(Now) = $TS; 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}) from $(kzE{kz.json,Switch-URI}) at $(kzE{kz.json,AMQP-Received})/$var(Now)\n"); $var(JObj) = $kzE; #!ifdef FAST_PICKUP_ROLE route(FAST_PICKUP_INIT); #!endif $var(presentity) = $(kzE{kz.json,From}); if($(kzE{kz.json,State}) == "terminated") { route(COUNT_PRESENTITIES); } else { route(COUNT_SUBSCRIBERS); } if($xavp(watchers=>dialog) > 0) { xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|publishing $(kzE{kz.json,From}) dialog update for $xavp(watchers=>dialog) watchers\n"); kazoo_pua_publish_dialoginfo($var(JObj)); 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($xavp(watchers=>presence) > 0) { xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|publishing $(kzE{kz.json,From}) presence update for $xavp(watchers=>presence) watchers\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"); } xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|finished processing $(kzE{kz.json,Event-Package}) update for $(kzE{kz.json,From}) state $(kzE{kz.json,State}) from $(kzE{kz.json,Switch-URI}) at $(kzE{kz.json,AMQP-Received})/$var(Now)/$TS\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"); $var(presentity) = $(kzE{kz.json,From}); route(COUNT_SUBSCRIBERS); if($xavp(watchers=>message-summary) > 0) { xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|publishing $(kzE{kz.json,From}) message-summary update for $xavp(watchers=>message-summary) watchers\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,Presence-ID}) : $kzE\n"); $var(presentity) = $_s(sip:$(kzE{kz.json,Presence-ID})); if($(kzE{kz.json,State}) == "terminated") { route(COUNT_PRESENTITIES); } else { route(COUNT_SUBSCRIBERS); } if($xavp(watchers=>dialog) > 0) { xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|publishing $var(presentity) dialog update for $xavp(watchers=>dialog) watchers\n"); kazoo_pua_publish_dialoginfo($kzE); pres_refresh_watchers("$var(presentity)", "dialog", 1); } else { xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|skip dialog update for $var(presentity)\n"); } if($xavp(watchers=>presence) > 0) { xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|publishing $var(presentity) presence update for $xavp(watchers=>presence) watchers\n"); kazoo_pua_publish_presence($kzE); pres_refresh_watchers("$var(presentity)", "presence", 1); } else { xlog("L_INFO", "$(kzE{kz.json,Call-ID})|log|skip presence update for $var(presentity)\n"); } } #!include_file "presence-reset.cfg" route[PRESENCE_BINDINGS] { #!import_file "presence-custom-bindings.cfg" #!ifndef PRESENCE_CUSTOM_BINDINGS $var(payload) = "{ 'exchange' : 'presence', 'type' : 'topic', 'queue' : 'presence-dialog-MY_HOSTNAME', 'routing' : 'dialog.*.*', 'exclusive' : 0, 'federate' : 1 }"; kazoo_subscribe("$var(payload)"); $var(payload) = "{ 'exchange' : 'presence', 'type' : 'topic', 'queue' : 'presence-presence-MY_HOSTNAME', 'routing' : 'update.*.*', 'exclusive' : 0, 'federate' : 1 }"; kazoo_subscribe("$var(payload)"); $var(payload) = "{ 'exchange' : 'presence', 'type' : 'topic', 'queue' : 'presence-mwi-MY_HOSTNAME', 'routing' : 'mwi_updates.*', 'exclusive' : 0 , 'federate' : 1 }"; kazoo_subscribe("$var(payload)"); #!endif route(PRESENCE_RESET_BINDINGS); #!ifdef PRESENCE_QUERY_ROLE route(PRESENCE_QUERY_BINDINGS); #!endif #!ifdef FAST_PICKUP_ROLE route(FAST_PICKUP_START); #!endif } # vim: tabstop=4 softtabstop=4 shiftwidth=4 expandtab