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 delayed message delivery. When the recipient is offline, you receive a message about this when you try to send him a message, and an offer to try later.
    image

    Mess!

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

    So, we enable messages and specify the context for processing them, in the section Webmords Settings → Asterisk SIP Settings. At the very bottom, 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 the ODBC function, which saves the SMS message in the MySQL DBMS. 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 ;
    

    In the func_odbc.conf file, add the ODBC_ function itself:

    [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 circumvent glitches with the Cyrillic alphabet. By the way, text transmission in the context of messages must be enclosed in quotation marks, otherwise when a comma appears in the text, the dialpan considers this as a parameter separator :)

    So, the messages we save are stored in the database if there is no subscriber in the network. It remains to configure the mechanism for delivering this message to him. We will do it in php, I put the script in /etc/asterisk/send_delayes_messages.php:


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

    It remains to fasten the script via php -f /etc/asterisk/send_delayes_messages.php to the minute-by-minute crowns and once a minute it will check and attempt to deliver the message.

    What are the disadvantages of this implementation? The first one is that the registration of the status of the feast is held for some time after the break, and it is quite possible that the feast will be registered for a short time and fall off, and the system will “send” a message to it within a minute and consider it delivered. You can get out by using not Application in the call-file, but transferring data to the context with checking the status of the variable $ {MESSAGE_SEND_STATUS}. It will probably be possible to use the existing context by setting variables through Set in the call file.
    But so far I have settled on this: once.

    Good luck!

    Also popular now: