Archive for the ‘Kannel’ Category.

WAP: Part 4 - Send SMS from PHP

Finally, let's send SMS messages to mobile phones with links in them. This is the most simple and most reliable way to get a URL to a phone. Most modern phones are smart enough to be able to pick out a URL and give you an option to visit it. Granted, the "GOTO" option may be buried in a menu somewhere, but for now it's the best we can do to reach the broadest audience.

If you haven't set up Kannel yet, you'll want to do that. You can refer to my previous article WAP: Part 2 - Send SMS from Kannel. It includes information on a basic setup and also how to send a test SMS message on the command line so you know it works before we get into doing with PHP.

This process is also the easiest to construct using PHP. Since Kannel does all of it's calls using the HTTP protocol, we'll simply turn on allow_url_fopen in our PHP ini and then we can use file() to make the Kannel requests. You could also use curl or a socket connection if you'd like.

Since this example so simple, I'll let you download the example code to look at the actual call, but essentially we're doing:

<?php

$result = file(
    'http://localhost:13013/cgi-bin/sendsms' .
    '?user=sms_user' .
    '&pass=sms_pass' .
    '&to=7025551212' .
    '&text=Go+to+Yahoo%21+on+your+phone+by+visiting+http%3A%2F%2Fwap.yahoo.com'
);

?>

If you're using the example index to send, don't forget to change the message to include the URL in the message itself. Unlike sending a
WAP Push message, there is no URL directly associated with the message.

Download the example

Articles In This Series:


WAP: Part 1 - MultiTech USB GPRS Modem in Linux
WAP: Part 2 - Send SMS from Kannel
WAP: Part 3 - WAP Push with Kannel & PHP
WAP: Part 4 - Send SMS from PHP
WAP: Part 5 - Customizing content with WURFL
WAP: Part 6 - Microbrowser content in WML / XHTML MP

WAP: Part 3 - WAP Push with Kannel & PHP

This article will go through setting up Kannel to send "WAP Push" messages to mobile phones. It assumes you have a working Kannel
installation with a real modem -- see parts 1 & 2 of this series for more information.

Before we continue with this article, let me save you some time. I have found WAP Push messages to be very unreliable. Specifically I was only able to get a WAP Push message sent to a T-Mobile phone from my GSM modem with a T-Mobile SIM card. I tried a Cingular SIM card in the modem, but was unable to successfully send a WAP Push message to a Cingular or other network phone.

I searched for 3rd party companies that will send WAP Push messages, and contacting a few of them. It seems here in the U.S. this type of service is relatively unreliable and sometimes only the network providers themselves can send WAP Push messages that will get through. Case in point: I couldn't get a WAP Push message to a Cingular phone, but you can download ringtones from cingular.com, for which the URL is sent to the phone via WAP Push.

So, if you want to send WAP Push messages from a T-Mobile modem to only T-Mobile phones, read on! If not, you might save yourself the headache and time and skip the next article of my WAP series: Send SMS from PHP.

Sending WAP Push from the command line


To our working configuration file from WAP: Part 2 - Send SMS from Kannel, we'll add the ppg and wap-push-user groups. Also add wapbox to the startup file and restart Kannel.

/etc/kannel/kannel.conf
...
# PUSH PROXY GATEWAY CONFIG
group = ppg
ppg-url = /wappush
ppg-port = 8080
service-name = ppg
trusted-pi = true

# WAP USER
group = wap-push-user
wap-push-user = SellingSource
ppg-username = sellingsource
ppg-password = sellingsource


start_kannel.sh
#!/bin/sh

rm /var/log/kannel/*
bearerbox --verbosity 4 --logfile /var/log/kannel/bearerbox.log /etc/kannel/kannel.conf &
sleep 10
smsbox --verbosity 4 --logfile /var/log/kannel/smsbox.log /etc/kannel/kannel.conf &
wapbox --verbosity 4 --logfile /var/log/kannel/wapbox.log /etc/kannel/kannel.conf &


I initially tested WAP Push using the included test_ppg executable included with the Kannel source. If you don't want/need to test it from the command line you can skip to the PHP segment.

Unfortunately the test programs are not included with the Gentoo/portage installation of Kannel. So I downloaded the source and
compiled (but did not install) it to get the test programs. Then I copied the example xml files used by test_ppg to my home directory for modification.

~ # cd ~/src
src # wget http://kannel.org/download/1.4.1/gateway-1.4.1.tar.bz2
src # tar -jxvf gateway-1.4.1.tar.bz2
src # cd gateway-1.4.1
gateway-1.4.1 # ./configure && make
gateway-1.4.1 # cp test/si.txt ~/si.xml
gateway-1.4.1 # cp test/smstestppg.txt ~/pap.xml

In si.xml I removed the created and si-expires attributes so there's no delivery timing issues (deliver immediately). The indication href
is a URL that will be shown as the 'From:' in the message, and is where the message will take them. The si-id is a unique message
identifier and should be changed everytime the message is sent. I like to use number@domain and up the number once before sending.
Change the message to something suitable, hopefully describing where the href URL will take them.

si.xml
<?xml version="1.0"?>
<!DOCTYPE si PUBLIC "-//WAPFORUM//DTD SI 1.0//EN"
"http://www.wapforum.org/DTD/si.dtd">
<si>
    <indication href="http://wap.yahoo.com"
        si-id="01@sellingsource.com"
        action="signal-high">
            Visit Yahoo! on your phone
    </indication>
</si>

In pap.xml, I changed to the push-id to the same as the si-id, this value should change per message as well. I changed the WAPPUSH number to my own, this time with country code (leading "+1"). I also changed the "carrier" after the 'PLMN@' to be our domain.

pap.xml
<?xml version="1.0"?>
<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP//EN"
          "http://www.wapforum.org/DTD/pap_1.0.dtd">
<pap>
  <push-message push-id="01@sellingsource.com"
  deliver-after-timestamp="2001-02-28T06:45:00Z"
  progress-notes-requested="false">
    <address address-value="WAPPUSH=+17025551212/TYPE=PLMN@sellingsource.com">
    </address>
    <quality-of-service
    priority="low"
    delivery-method="unconfirmed"
    network-required="true"
    network="gsm"
    bearer-required="true"
    bearer="sms">
    </quality-of-service>
  </push-message>
</pap>


So let's test this from the command line:
gateway-1.4.1 # ./test/test_ppg "http://localhost:8080/wappush?username=wap_user&password=wap_pass" ~/si.xml ~/pap.xml

On my T-Mobile Motorola phone, I now have a message under "Browser Msgs." I can click the "GO TO" button and it will take me to the URL specified in the 'href' attribute of si.xml.

Sending WAP Push from PHP


Now let's do the same thing using PHP. But first let me explain how things are going to change. XML is pretty chatty, so we'll be using a binary format called WBXML. Since we'll be communicating directly to Kannel via HTTP with a URL, we'll represent the hexadecimal numbers with a prefix of '%' for URL encoding, rather than '0x'. Along with the Service Indication (SI) document in WBXML, we'll also have to pass a User Data Header (udh) for WAP Push. For an explanation of the udh and WBXML, please see the reference information links below, I've also documented them as best I know in the code:

<?php

require_once 'SMSBase.php';

class WAPPush extends SMSBase
{
        public function __construct(KannelInfo $kannel_info)
        {
                parent::__construct($kannel_info);
        }

        public function sendSMSLink(LinkSMS $sms)
        {
                $fields = array('to' =>; urlencode($sms->getTo()),
                                                'udh' => '',
                                                'text' => '');

                //Nokia User Data Header (UDH) for WAP Push
                $fields['udh'] .= '%06'; //length of UDH - 6 bytes
                $fields['udh'] .= '%05'; //information element (IE) identifier - 0x05 = 16-bit port addressing scheme
                $fields['udh'] .= '%04'; //IE data length - 4 bytes
                $fields['udh'] .= '%0B%84'; //IE data - destination port, 0x0B84 = port 2948 (WAP Push)
                $fields['udh'] .= '%23%F0'; //IE data - origination port, 0x23F0 = port 9200

                //WBXML version of Service Indication (si)
                //headers
                $fields['text'] .= '%1B'; //Transaction ID
                $fields['text'] .= '%06'; //PDU Type - Push
                $fields['text'] .= '%01'; //length of headers
                $fields['text'] .= '%AE'; //Content-type: application/vnd.wap.sic

                //xml body
                $fields['text'] .= '%02'; //WBXML Version 1.2
                $fields['text'] .= '%05'; //DTD Version SI 1.0 Public Identifier
                $fields['text'] .= '%6A'; //Charset UTF-8
                $fields['text'] .= '%00'; //String Table Length (0)
                $fields['text'] .= '%45'; //<si>
                $fields['text'] .= '%C6'; //<indication>
                $fields['text'] .= '%0C'; //href="http://
                $fields['text'] .= '%03'; //start of string value
                $fields['text'] .= $this->urlHexEncode($sms->getURL());
                $fields['text'] .= '%00'; //end of string value
                $fields['text'] .= '%01'; //si-id attribute
                $fields['text'] .= '%03'; //start of string value
                $fields['text'] .= $this->urlHexEncode($sms->getText());
                $fields['text'] .= '%00'; //end of string value
                $fields['text'] .= '%01'; //end element (</si>)
                $fields['text'] .= '%01'; //end element ()

                return $this->sendSMS($fields);
        }

        private function urlHexEncode($text)
        {
                $string = '';
                for ($i=0; $i < strlen($text); $i++)
                {
                        $letter = $text[$i];
                        //get the numeric ascii value of the letter
                        //convert it to hex and add a percent (%)
                        $string .= sprintf('%%%02X', ord($letter));
                }
                return $string;
        }
}

?>

sendSMS() in the parent, SMSBase, simply uses the file() function to send the URL via HTTP GET -- you'll have to make sure allow_url_fopen is set to On in your php.ini or with ini_set().

Also, now that we're doing all of the encoding ourselves and sending directly to the smsbox daemon, we can turn off wapbox. In the startup script, comment out the wapbox line. In kannel.conf you can comment out any wap related entries in the core group (wapbox-port, wdp-interface-name, etc.). You can also comment out the entire wapbox, ppg, and wap-push-user group blocks. You'll have to restart kannel for these changes to take effect.

Resources


Download the entire example.

(udh explanation)
http://discussion.forum.nokia.com/forum/archive/index.php/t-13518.html

(wbxml breakdown)
http://discussion.forum.nokia.com/forum/archive/index.php/t-16775.html
http://www.activexperts.com/activsms/sms/wappushsi/

(wappush using PHP)
http://www.mail-archive.com/users@kannel.org/msg07893.html

Articles In This Series:


WAP: Part 1 - MultiTech USB GPRS Modem in Linux
WAP: Part 2 - Send SMS from Kannel
WAP: Part 3 - WAP Push with Kannel & PHP
WAP: Part 4 - Send SMS from PHP
WAP: Part 5 - Customizing content with WURFL
WAP: Part 6 - Microbrowser content in WML / XHTML MP

WAP: Part 2 - Send SMS from Kannel

While there is Kannel documentation, I found it was unclear to me since I wanted to hone in on one thing: sending a URL to my phone. So in this article I'll cover setting up Kannel to send a standard SMS text message to a mobile phone.

Compilation and Installation


I use Gentoo on my box at work. Yes, it can be both powerful and cumbersome, but it also had the best amd64 support when the processors were first available. So I will be covering Kannel installation in Gentoo/AMD64, but other distributions and architectures will probably be similar. The latest version in portage for the amd64 platform (at time of writing) was Kannel 1.4.1:
~ # emerge -av kannel   

These are the packages that would be merged, in order:   

Calculating dependencies                  ... done!
[ebuild  R  ] app-mobilephone/kannel-1.4.1  USE="doc mysql pam pcre sqlite sqlite3 ssl -debug -postgres" 0 kB   

Total: 1 package (1 reinstall), Size of downloads: 0 kB

kannel.conf configuration file


Once the software is compiled and installed, we'll make a simple Kannel configuration file.

/etc/kannel/kannel.conf
# CORE BEARERBOX/KANNEL CONFIG
group = core
admin-port = 13000
admin-password = admin_pass
status-password = status_pass
log-file = "/var/log/kannel/kannel.log"
#  0 = 'debug', 1 = 'info', 2 = 'warning', 3 = 'error', 4 = 'panic'
log-level = 4
access-log = "/var/log/kannel/core_access.log"
# Wapbox related
wapbox-port = 13002
wdp-interface-name = "*"
# Smsbox related
#smsbox-port = 13001 

# BASE WAPBOX CONFIG
group = wapbox
bearerbox-host = localhost

A few notes on the configuration file... The configuration blocks always start with a "group" directive. Also, there should not be any blank lines within a group, but there must be a blank line before the next group. A comment is a non-blank line. Kannel is pretty picky about it's configuration file setup, so it probably won't start if you got it wrong. You can see what all of these configuration directives do by reading the Kannel user guide. You can also look at a good Kannel WAP article from IBM.

Basically, in this configuration Kannel's core daemon will run on port 13000. All of the administration is done via http requests through this port. You'll need to use the specified admin and status passwords for certain operations. Also, I added a wapbox-port and wdp-interface directives. We're not actually going to start the wapbox executable yet, but we need to have one additional group for Kannel to start... so this is just the minimum we need, and these are the two directives required for wapbox. Then we need the wapbox group, and it's required bearerbox-host directive.

There are additional directives for allowing/blocking access to Kannel based on IP etc. I am behind a firewall and I'm not concerned with these settings, but you may choose to use them to protect yourself. Please see the aforementioned guides for this information.

Starting Kannel


So now let's start Kannel. The init.d startup scripts for Gentoo are terribly broken. Rather than fixing them, I just created a simple script to start up Kannel, specifically the bearerbox executable. We'll revisit this file later to add the other components.

start_kannel.sh
#!/bin/sh   

rm /var/log/kannel/*
bearerbox --verbosity 4 --logfile /var/log/kannel/bearerbox.log /etc/kannel/kannel.conf &

Kannel Administration


Once it's up and running, you can check the status using your web browser or via the command-line using curl, etc.:

Check the status (requires status password)
~ # curl http://localhost:13000/status?password=status_pass

Shutdown Kannel (requires admin password)
~ # curl http://localhost:13000/shutdown?password=admin_pass

Sending SMS Messages


Now that bearerbox is confirmed to be working (and we shut it back down), let's add smsbox to the mix:

/etc/kannel/kannel.conf
# CORE BEARERBOX/KANNEL CONFIG
group = core
admin-port = 13000
admin-password = admin_pass
status-password = status_pass
log-file = "/var/log/kannel/kannel.log"
#  0 = 'debug', 1 = 'info', 2 = 'warning', 3 = 'error', 4 = 'panic'
log-level = 4
access-log = "/var/log/kannel/core_access.log"
# Wapbox related
wapbox-port = 13002
wdp-interface-name = "*"
# Smsbox related
smsbox-port = 13001   

# BASE WAPBOX CONFIG
group = wapbox
bearerbox-host = localhost   

# GSM DEVICE FILE INFO
group = smsc
smsc = at
smsc-id = gsm_modem
modemtype = wavecom
device = /dev/ttyUSB0
keepalive = 30
max-error-count = 5
sim-buffering = true   

# MODEM CONFIGURATION
group = modems
id = wavecom
name = Wavecom
detect-string = "WAVECOM"
speed = 115200
reset-string = "ATZ"
init-string = "AT+CNMI=1,2,0,1,0;+CMEE=1"
# trying this to see if it resolves errors when the
# modem erroneously returns ERROR to the AT+CPIN? command
no-pin = true   

# SMSBOX SETUP
group = smsbox
bearerbox-host = localhost
sendsms-port = 13013
global-sender = 8005551212
log-file = "/var/log/kannel/smsbox.log"
log-level = 4
access-log = "/var/log/kannel/smsbox_access.log"   

# SEND-SMS USERS
group = sendsms-user
username = sms_user
password = sms_pass
forced-smsc = gsm_modem   

# SMS SERVICES
# there should be default always
group = sms-service
keyword = default
text = "No service specified"
max-messages = 0
catch-all = true

The gsm_modem smsc-id and modems group are configurations that Kannel uses to communicate with my Mutitech USB GPRS modem that I covered in a previous article. The smsbox group specifies that it's running on localhost port 13013 and the "from" phone number we want to show up on all messages is in the global-sender directive. The sendsms-user group defines what username and password we'll need to supply when sending SMS messages. Lastly the sms-service group is used for SMS messages received by Kannel. In this case we're just going to ignore them. Let's add smsbox to the startup file:

start_kannel.sh
#!/bin/sh   

rm /var/log/kannel/*
bearerbox --verbosity 4 --logfile /var/log/kannel/bearerbox.log /etc/kannel/kannel.conf &
sleep 10
smsbox --verbosity 4 --logfile /var/log/kannel/smsbox.log /etc/kannel/kannel.conf &

The sleep is in there to give bearerbox sufficient time to start and open it's communication ports before the others start and try to connect.

To test the SMS service, we'll connect directly to the sendsms CGI using CURL. The username and password parameters should be the same as user/pass in the sendsms-user group. The number should be a standard US 10-digit mobile phone number, and the text should be URL encoded. I added double quotes to the call to avoid the shell from interpreting the ampersands as background commands.
~ # curl "http://localhost:13013/cgi-bin/sendsms?username=sms_user&password=sms_pass&to=7025551212&text=Hello+world"
0: Accepted for delivery

You should shortly have an SMS message on your mobile. If not, I suggest grepping the /var/log/kannel directory for your area code to see what issues you may have. Things I've run into include bad usernames / passwords and a deactivated SIM card that yielded a "CMS ERROR: 512" from the modem.

Articles In This Series:


WAP: Part 1 - MultiTech USB GPRS Modem in Linux
WAP: Part 2 - Send SMS from Kannel
WAP: Part 3 - WAP Push with Kannel & PHP
WAP: Part 4 - Send SMS from PHP
WAP: Part 5 - Customizing content with WURFL
WAP: Part 6 - Microbrowser content in WML / XHTML MP

WAP: Part 1 - MultiTech USB GPRS Modem in Linux

The first part of my WAP series is going to cover getting the MultiTech MTCBA-G-U-F2 USB GPRS Modem to work with Linux. This is
very specific information, but it may also apply to other USB modems using the TI 3410 and 5052 chipsets.

The later articles will assume that you have a modem already setup, because we're not going to use the "Fake SMSC" protocol in Kannel,
we're going to send actual messages to actual phones. This segment can probably be skipped if you've already got a working modem (Skip to WAP: Part 2 - Send SMS from Kannel).

It may also be worth noting that we've had difficulty with reliability of these USB modems when sending out large batches of messages. I
think the problem occurs when the modem does not reset itself to a working/known state. But it seems to work fine for testing purposes.
So for production, we use the RS232 Serial version of the same modem.

To get the USB modem working, I started with patches from Peter Berger's site: ti_usb_multitech-1.1.tgz (local mirror). There's a lot of other interesting code (related to 3410/5052 and otherwise) in his downloads directory: http://gate.brimson.com/downloads/

Patching the Kernel


The patch contained in Peter's tarball is for kernel 2.6.13. If your kernel is newer than that, you can try my updated patch for 2.6.22 to see if it applies cleaner.
/ # cd
~ # wget http://dev.sellingsource.com/wp-content/uploads/2007/09/ti_usb_multitech_2622.patch
~ # cd /usr/src/linux
linux # patch -p1 < ~/ti_usb_multitech_2622.patch

For the most part, the instructions in ti_usb_multitech_release_notes-1.1.txt still apply, however there were some differences that may be specific to Gentoo:

  • I had better success copying the ti_usb_3410_5052.hotplug script (not ti_usb_3410_5052) to /etc/hotplug/usb/ti_usb_3410_5052

  • The release notes say to put the firmware images in /usr/lib/hotplug/firmware, but my hotplug installation was looking for them in /lib64/firmware

Plugging it in


Once everything is recompiled you should be able to plug the device in and hopefully hotplug will load the module for you (based on the USB ID). In your kernel dmesg hopefully you'll see a device assigned, and a new (usable) device file.
~ # dmesg
...
ti_usb_3410_5052 3-3:2.0: TI USB 3410 1 port adapter converter detected
usb 3-3: TI USB 3410 1 port adapter converter now attached to ttyUSB0
...
~ # ls -l /dev/ttyUSB0
crw-rw---- 1 root uucp 188, 0 Sep 10 16:13 /dev/ttyUSB0

Articles In This Series:


WAP: Part 1 - MultiTech USB GPRS Modem in Linux
WAP: Part 2 - Send SMS from Kannel
WAP: Part 3 - WAP Push with Kannel & PHP
WAP: Part 4 - Send SMS from PHP
WAP: Part 5 - Customizing content with WURFL
WAP: Part 6 - Microbrowser content in WML / XHTML MP