diff --git a/modules/smsops/examples/kamailio.cfg b/modules/smsops/examples/kamailio.cfg new file mode 100644 index 00000000000..5a9f1c2de01 --- /dev/null +++ b/modules/smsops/examples/kamailio.cfg @@ -0,0 +1,418 @@ +#!KAMAILIO +# +# This config file implements the basic P-CSCF functionality +# - web: http://www.kamailio.org +# - git: http://sip-router.org +# +# Refer to the Core CookBook at http://www.kamailio.org/dokuwiki/doku.php +# for an explanation of possible statements, functions and parameters. +# +# Direct your questions about this file to: . +# +# For more information about the various parameters, functions and statements +# try http://sip-router.org/wiki/ . +# + +include_file "smsc.cfg" + +####### Global Parameters ######### +debug=2 +log_stderror=no +sip_warning=no +children=4 + +user_agent_header="User-Agent: Kamailio SMSC" +server_header="Server: Kamailio SMSC" + +/* comment the next line to enable the auto discovery of local aliases + based on reverse DNS on IPs (default on) */ +auto_aliases=no + +check_via=no # (cmd. line: -v) +dns=no # (cmd. line: -r) +rev_dns=no # (cmd. line: -R) +tcp_accept_no_cl=yes + +#!define SMS_3GPP 1 +#!define SMS_TEXT 2 + +alias=SERVER + +# ------------------ module loading ---------------------------------- +mpath="/root/kamailio-devel/lib64/kamailio/modules" +# (we try both the lib64 and the lib directory) + +loadmodule "tm" +loadmodule "tmx" +loadmodule "smsops" +loadmodule "xlog" +loadmodule "maxfwd" +loadmodule "textops" +loadmodule "sl" +loadmodule "sanity" +loadmodule "siputils" +loadmodule "pv" +loadmodule "uac" +loadmodule "xhttp" +loadmodule "utils" +loadmodule "json" +loadmodule "enum" +loadmodule "db_mysql" +loadmodule "dialplan" +loadmodule "sqlops" +loadmodule "htable" +loadmodule "rtimer" +loadmodule "usrloc" +loadmodule "registrar" +loadmodule "pua" +loadmodule "pua_reginfo" + +modparam("sqlops","sqlcon","sms=>mysql://root@localhost/smsc") +modparam("dialplan|pua", "db_url", "mysql://root@localhost/kamailio") +modparam("uac","restore_mode","none") +modparam("enum", "domain_suffix", "DOMAIN.") + +modparam("htable", "htable", "publish_sent=>size=8;autoexpire=SUBSCRIBE_EXPIRE") + +# time interval set to 3 seconds +modparam("rtimer", "timer", "name=sms;interval=3;mode=1;") +modparam("rtimer", "exec", "timer=sms;route=SMS_WORKER") + +modparam("pua_reginfo", "server_address", "sip:reginfo@DOMAIN") +modparam("pua_reginfo", "publish_reginfo", 0) + +####### Routing Logic ######## +# Main SIP request routing logic +# - processing of any incoming SIP request starts with this route + +route { + xlog("L_DBG", "$rm ($fu ($si:$sp) to $tu, $ci)\n"); + + # per request initial checks + route(REQINIT); + + if (is_method("NOTIFY")) { + route(NOTIFY); + send_reply("202", "Accepted"); + exit; + } + + if (!is_method("MESSAGE")) { + append_to_reply("Allow: MESSAGE,NOTIFY\r\n"); + send_reply("405", "Method not allowed"); + exit; + } + + if ($cT == "application/vnd.3gpp.sms") { + route(SMS_FROM_3GPP); + } else if ($cT == "text/plain") { + route(SMS_FROM_SIP); + } else { + send_reply("488", "Content-Type not supported"); + exit; + } +} + +###################################################################### +# Helper routes (Basic-Checks, NAT-Handling/RTP-Control, XML-RPC) +###################################################################### +# Per SIP request initial checks +route[REQINIT] { + # Trace this message + + if (!mf_process_maxfwd_header("10")) { + sl_send_reply("483","Too Many Hops"); + exit; + } + + if(!sanity_check("1511", "7")) { + xlog("Malformed SIP message from $si:$sp\n"); + exit; + } + + # Reply to OPTIONS: + if (is_method("OPTIONS") && (uri==myself)) { + options_reply(); + exit; + } + + # Ignore Re-Transmits: + if (t_lookup_request()) { + exit; + } +} + +###################################################################### +# SMS from VoLTE Handsets +###################################################################### +route[SMS_FROM_3GPP] { +#!ifdef WITH_DEBUG + xlog("3GPP-SMS: $rm ($fu ($si:$sp) to $tu, $ci)\n"); + xlog("SMS for $tpdu(destination) \"$tpdu(payload)\" (Valid: $tpdu(validity) )\n"); +#!endif + send_reply("202", "Accepted"); + + if (isRPDATA()) { + $uac_req(method) = "MESSAGE"; + $uac_req(ruri) = $ai; + $uac_req(furi) = $ai; + $uac_req(turi) = $ai; + $uac_req(hdrs) = "Content-Type: application/vnd.3gpp.sms\r\nRequest-Disposition: fork, parallel\r\nAccept-Contact: *;+g.3gpp.smsip;require;explicit\r\n"; + $uac_req(body) = $smsack; + uac_req_send(); + + + $avp(from) = $(ai{uri.user}); + $avp(to) = $tpdu(destination); + # Translate "To": + dp_translate("1", "$avp(to)/$avp(to)"); + + $avp(text) = $tpdu(payload); +#!ifdef WITH_DEBUG + xlog("SMS from 3GPP/VoLTE\n"); + xlog("-------------------------------------\n"); + xlog("FROM $avp(from)\n"); + xlog("TO $avp(to)\n"); + xlog("TEXT $avp(text)\n"); +#!endif + route(SMS); + } + + exit; +} + +###################################################################### +# SMS from OTT Handsets +###################################################################### +route[SMS_FROM_SIP] { + send_reply("200", "OK"); + + $avp(from) = $(ai{uri.user}); + # Translate "To": + $avp(to) = $tU; + dp_translate("1", "$avp(to)/$avp(to)"); + $avp(text) = $rb; +#!ifdef WITH_DEBUG + xlog("SMS from SIP/OTT\n"); + xlog("-------------------------------------\n"); + xlog("FROM $avp(from)\n"); + xlog("TO $avp(to)\n"); + xlog("TEXT $avp(text)\n"); +#!endif + route(SMS); + + exit; +} + + +###################################################################### +# SMS from other networks +###################################################################### +event_route[xhttp:request] { + if ($(hu{url.querystring}{s.len}) > 0) { + $avp(from) = $(hu{url.querystring}{param.value,msisdn,&}); + $avp(to) = $(hu{url.querystring}{param.value,to,&}); + $avp(text) = $(hu{url.querystring}{param.value,text,&}{s.replace,+,%20}{s.unescape.user}); + $avp(from_outbound) = 1; +#!ifdef WITH_DEBUG + xlog("SMS from Outbound ($hu)\n"); + xlog("-------------------------------------\n"); + xlog("FROM $avp(from)\n"); + xlog("TO $avp(to)\n"); + xlog("TEXT $avp(text)\n"); +#!endif + if ($avp(to) == "491771782261") + $avp(to) = "494046895124"; + if ($avp(to) == "491771782319") + $avp(to) = "494034927220"; + + route(SMS); + } + + xhttp_reply("200", "OK", "text/html", "OK - [$si:$sp]"); +} + +###################################################################### +# SMS to VoLTE Handsets +###################################################################### +route[SMS_TO_3GPP] { +#!ifdef WITH_DEBUG + xlog("SMS to 3GPP/VoLTE\n"); + xlog("-------------------------------------\n"); + xlog("FROM $avp(from)\n"); + xlog("TO $avp(to)\n"); + xlog("TEXT $avp(text)\n"); +#!endif + + // Construct a new SMS-Body: + $rpdata(all) = $null; + $rpdata(type) = 1; // RP-DATA: Network to UE + $rpdata(reference) = $avp(id); + $rpdata(originator) = $avp(from); + $tpdu(type) = 4; // SMS-Deliver + $tpdu(origen) = $avp(from); // The Destination becomes the originator of the SMS + $tpdu(payload) = $avp(text); + + $uac_req(method) = "MESSAGE"; + $uac_req(ruri) = "sip:"+$avp(to)+"@"+DOMAIN; + $uac_req(furi) = "sip:"+$avp(to)+"@"+DOMAIN; + $uac_req(turi) = "sip:"+$avp(to)+"@"+DOMAIN; + $uac_req(hdrs) = "Content-Type: application/vnd.3gpp.sms\r\nRequest-Disposition: fork, parallel\r\nAccept-Contact: *;+g.3gpp.smsip;require;explicit\r\nX-MSG-ID: "+$avp(id)+"\r\n"; + $uac_req(body) = $smsbody; + $uac_req(evroute)=1; + uac_req_send(); + sql_query("sms", "delete from messages where id=$avp(id);"); +} + +###################################################################### +# SMS to OTT-Handsets +###################################################################### +route[SMS_TO_SIP] { +#!ifdef WITH_DEBUG + xlog("SMS to SIP/OTT\n"); + xlog("-------------------------------------\n"); + xlog("FROM $avp(from)\n"); + xlog("TO $avp(to)\n"); + xlog("TEXT $avp(text)\n"); +#!endif + + $uac_req(method) = "MESSAGE"; + $uac_req(ruri) = "sip:"+$avp(to)+"@"+DOMAIN; + $uac_req(furi) = "sip:+"+$avp(from)+"@"+DOMAIN; + $uac_req(turi) = "sip:"+$avp(to)+"@"+DOMAIN; + $uac_req(hdrs) = "Content-Type: text/plain\r\nX-MSG-ID: "+$avp(id)+"\r\n"; + $uac_req(evroute)=1; + $uac_req(body) = $avp(text); + + uac_req_send(); +} + +###################################################################### +# SMS to Outbound +###################################################################### +route[SMS_TO_OUTBOUND] { +#!ifdef WITH_DEBUG + xlog("SMS to Outbound\n"); + xlog("-------------------------------------\n"); + xlog("FROM $avp(from)\n"); + xlog("TO $avp(to)\n"); + xlog("TEXT $avp(text)\n"); +#!endif + if ($avp(from_outbound) == 1) { + xlog("Not sending: FROM and TO Outbound!\n"); + return 1; + exit; + } + if ($avp(from) == "494046895124") + $avp(from) = "491771782261"; + if ($avp(from) == "494034927220") + $avp(from) = "491771782319"; + + http_query("https://rest.nexmo.com/sms/json?api_key=NEXMO_APIKEY&api_secret=NEXMO_APISECRET&from=$avp(from)&to=$avp(to)&text=$(avp(text){s.escape.user})", "$var(result)"); + if ($retcode != 200) return -1; + json_get_field("$var(result)", "messages", "$var(messages)"); + json_get_field("$var(messages)", "status", "$var(status)"); + if ($var(status) != 0) return -1; + return 1; +} + +###################################################################### +# SMS Handling +###################################################################### +route[SMS] { +#!ifdef WITH_DEBUG + xlog("SMS-Task\n"); + xlog("-------------------------------------\n"); + xlog("FROM $avp(from)\n"); + xlog("TO $avp(to)\n"); + xlog("TEXT $avp(text)\n"); +#!endif + + # Query ENUM: Local number? + $var(enum) = "+"+$avp(to); + if (!enum_pv_query("$var(enum)")) { + route(SMS_TO_OUTBOUND); + return $retcode; + } + if (sql_query("sms", "insert into messages (caller, callee, text, valid) values ('$(avp(from){s.escape.common})', '$(avp(to){s.escape.common})', '$(avp(text){s.escape.common})', now());")) + return 1; + else + return -1; +} + +###################################################################### +# SMS Handling +###################################################################### +route[SMS_WORKER] { + sql_query("sms", "select id, caller, callee, text from messages;", "q"); + if ($dbr(q=>rows) > 0) { + $var(i) = 0; + while ($var(i) < $dbr(q=>rows)) { + $avp(id) = $dbr(q=>[$var(i),0]); + $avp(from) = $dbr(q=>[$var(i),1]); + $avp(to) = $dbr(q=>[$var(i),2]); + $avp(text) = $dbr(q=>[$var(i),3]); + + route(SEND_SMS); +#!ifdef WITH_DEBUG + xlog("ID $avp(id)\n"); + xlog("FROM $avp(from)\n"); + xlog("TO $avp(to)\n"); + xlog("TEXT $avp(text)\n"); +#!endif + $var(i) = $var(i) + 1; + } + } + sql_result_free("q"); +} + +route[NOTIFY] { + if (has_body("application/reginfo+xml")) { + if (reginfo_handle_notify("location")) + send_reply("202", "Accepted"); + } else { + send_reply("503", "Invalid Content-Type"); + } + exit; +} + +route[SEND_SMS] { + $var(uri) = "sip:"+$avp(to)+"@"+DOMAIN; + + if (reg_fetch_contacts("location", "$var(uri)", "caller")) { + $var(j) = 0; + $var(is3gpp) = 0; + while($var(j) < $(ulc(caller=>count))) { + $var(k) = 0; + while($var(k) < $(ulc(caller=>addr)[$var(j)]{param.count})) { + if ($(ulc(caller=>addr)[$var(j)]{param.name,$var(k)}) == "+g.3gpp.smsip") + $var(is3gpp) = 1; + $var(k) = $var(k) + 1; + } + if ($var(is3gpp) == 1) + route(SMS_TO_3GPP); + else + route(SMS_TO_SIP); + $var(j) = $var(j) + 1; + } + } else { + if ($sht(publish_sent=>$var(uri)) == $null) { + reginfo_subscribe("$var(uri)", "SUBSCRIBE_EXPIRE"); + $sht(publish_sent=>$var(uri)) = 1; + } + } +} + +event_route [tm:local-request] { + if (is_method("SUBSCRIBE")) { + append_hf("P-Asserted-Identity: $ru\r\n"); + } +} + +event_route[uac:reply] { + if (($uac_req(evtype) == 1) && ($uac_req(evcode) == 200)) { + $var(msgid) = $(uac_req(hdrs){line.sw,X-MSG-ID:}{s.substr,10,0}{s.int}); + sql_query("sms", "delete from messages where id=$var(msgid);"); + } +} + diff --git a/modules/smsops/examples/smsc.cfg b/modules/smsops/examples/smsc.cfg new file mode 100644 index 00000000000..bb575318237 --- /dev/null +++ b/modules/smsops/examples/smsc.cfg @@ -0,0 +1,8 @@ +listen=udp:127.0.0.1:5060 +listen=tcp:127.0.0.1:80 + +#!substdef "/DOMAIN/ims.mnc001.mcc001.3gppnetwork.org/" +#!substdef "/SERVER/smsc.ims.mnc001.mcc001.3gppnetwork.org/" +#!subst "/NEXMO_APIKEY/abcdef/" +#!subst "/NEXMO_APISECRET/xyz/" +#!subst "/SUBSCRIBE_EXPIRE/7200/"