📜 ⬆️ ⬇️

sip messages: delayed delivery

The topic of messages (ala SMS) in Asterisk is not the first on Habré , but all publications have one drawback - they do not have the functionality of deferred message delivery. When the recipient is not online, you receive a message about it when you try to send him a message, and the offer to try later.
image

Disorder!

We will work with asterisk 11, with FreePBX installed. Traditionally, “without configs” will not work this time.

So, we allow the work of messages and specify the context for processing them in the webmoney section Settings → Asterisk SIP Settings. At the very bottom we add custom fields for sip.conf and specify:

accept_outofcall_message = yes outofcall_message_context = messages auth_message_requests = no 

Create this context in extensions_custom.conf:
')
 [messages] exten => _.,1,Set(MSG_TO=${CUT(MESSAGE(to),@,1)}) exten => _.,n,MessageSend(${MSG_TO},${MESSAGE(from)}) exten => _.,n,GotoIf($["${MESSAGE_SEND_STATUS}" != "SUCCESS"]?sendfailedmsg) exten => _.,n,Hangup() exten => _.,n(sendfailedmsg),Set(MSG_TMP=${CUT(MESSAGE(from),<,2)}) exten => _.,n,Set(MSG_FROM=${CUT(MSG_TMP,@,1)}) exten => _.,n,Set(ODBC_SAVE_MESSAGE("${MESSAGE(from)}","${MSG_TO}","${MESSAGE(body)}")=1) exten => _.,n,Set(MESSAGE(body)="[${STRFTIME(${EPOCH},,%d%m%Y-%H:%M:%S)}]    ${EXTEN}  .   ,     .") exten => _.,n,MessageSend(${MSG_FROM}, SYSTEM) exten => _.,n,Hangup() 

In this context, there is a call to an ODBC function that stores the SMS text in MySQL. In order not to fool around with separate databases and DSNs, I created a table in the existing asteriskcdrdb database:

 CREATE TABLE IF NOT EXISTS `messages` ( `id` int(11) NOT NULL AUTO_INCREMENT, `dt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `mfrom` varchar(100) CHARACTER SET utf8 NOT NULL, `mto` varchar(100) CHARACTER SET utf8 NOT NULL, `mbody` text CHARACTER SET utf8 NOT NULL, `delivered` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', PRIMARY KEY (`id`) ) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ; 

Add the ODBC_function itself in the func_odbc.conf file:

 [SAVE_MESSAGE] writesql = INSERT INTO messages (mfrom,mto,mbody) VALUES ('${ARG1}','${ARG2}','${BASE64_ENCODE(${ARG3})}') dsn = asteriskcdrdb 

As you can see, the text of the message is encoded in base_64 before saving. In such a simple way, I bypass glitches with Cyrillic. By the way, the transmission of text in the context of messages must be enclosed in quotes, otherwise when a message appears, for example, a comma in the text, dialpan considers this as a parameter separator :)

So, our messages are saved to the database in the absence of a subscriber in the network. It remains to configure the mechanism for delivering this message to him. We will do on php, the script I put in /etc/asterisk/send_delayes_messages.php:

 <?php #asteriskcdrdb database #mysql settings $hostname = "localhost"; $username = "asteriskuser"; $password = "password"; $dbName = "asteriskcdrdb"; mysql_connect($hostname,$username,$password) or die("no connect to MySQL."); mysql_select_db($dbName) or die("ERROR: ".mysql_error()); mysql_query("set names 'utf8'"); $messages_query = mysql_query('SELECT `id`,`mfrom`,`mto`,`mbody` FROM `messages` WHERE `delivered` = "0000-00-00 00:00:00" ORDER BY `dt`') or die("ERROR: ".mysql_error()); while($message = mysql_fetch_array($messages_query, MYSQL_ASSOC)) { $peer_to = explode(":", $message['mto']); if (peer_online($peer_to[1])) { //print_r($message); file_put_contents('/tmp/delayed_message_'.$peer_to[1].'_'.time(), 'Channel: Local/s@default'."\r\n".'Application: MessageSend'."\r\n".'Set: MESSAGE(body)='.base64_decode($message['mbody'])."\r\n".'Data: '.$message['mto'].','.$message['mfrom']."\r\n"); exec("mv /tmp/delayed_message_* /var/spool/asterisk/outgoing/"); mysql_query('UPDATE `messages` SET `delivered` = "'.date("Ymd H:i:s").'" WHERE `id` = '.$message['id']." LIMIT 1") or die("ERROR: ".mysql_error()); } } function peer_online($peer) { $raw = shell_exec('asterisk -rx "sip show peer '.$peer.'" | grep "Status" | grep "OK"'); print $raw; if(!empty($raw)) return true; else return false; } ?> 

As a label for the fact of delivery, I use the delivered field of the timestamp type, if there are zeros there, then the message needs to be delivered. Thus, running through saved undelivered messages, we check for each registration of a peer through the cli command, and if it is online, we create an outgoing call file, which delivers this message. After this, the script marks the message in the database, setting the date of sending.

It will be necessary to fasten the script via php -f /etc/asterisk/send_delayes_messages.php to the minute-by-minute cron and once a minute, the message will be checked and attempted.

What are the disadvantages of this implementation? The first is that the registration of the status of a peer is kept for some time after the break, and it is quite possible that the feast will register briefly and fall off, and the system will “send” a message to it within a minute, and will consider it delivered. You can get out using not the Application in the call-file, but transferring the data to the context with checking the status of the $ {MESSAGE_SEND_STATUS} variable. Probably, it will be possible to use the existing context by setting variables via Set in a call-file.
But while I stopped at this: there is no time.

Good luck!

Source: https://habr.com/ru/post/322462/


All Articles