Clickatell with Qt

Tags: Programming, Qt, SMS

Over the past couple of weeks I've been working extensively on the Linux kernel, specifically working on drivers and board support for the the new Genesi hardware based on the Freescale i.mx53 ARM SOC. I needed a little 15 minute break from the Linux code and decided to play with Qt again. Specifically, I wanted to send SMS messages from a Qt application, just for fun.

Qt Logo

Clickatell provides a service to allow SMS messages to be sent over the internet. It is one of the largest Online SMS mobile messaging gateway providers. They provides an easy to use API to send, e.g., text messages from a website using e.g., PHP. 

You can build some pretty neat applications with this. In the past, I build a microcontroller with SMS capability using the service. The microcontroller was a Renesas M32C with a port of LwIP. It was used at the time to send sensor data to a mobile phone at daily intervals.

Using the service from a Qt application is pretty straight forward when using the http API, the same one used in e.g., PHP code. There are more extensive API's available, but this one is the easiest to use and suits my purpose just fine. The code below is very minimalistic and can (and should) definitely be improved upon if this is to be used in a real application.

The class description (in clickatell.h) looks like this:

#ifndef CLICKATELL_H
#define CLICKATELL_H

#include <QString>
#include <QStringList>
#include <QUrl>
#include <QNetworkAccessManager>
#include <QNetworkReply>
#include <QDebug>

typedef struct{
    QString user;
    QString password;
    QString api_id;
    QString baseurl;
    QString text;
    QString to;
}ClickatellMessage;

class Clickatell : public QObject
{
Q_OBJECT

public:
    Clickatell();
    void printParams(void);
    void setParams(QString user, QString password, QString api_id);
    void setText(QString txt);
    void setRecipient(QString to):
    void send(void);

private:
    ClickatellMessage message;
    QNetworkAccessManager* manager;

public slots:
    void replyFinished(QNetworkReply* reply);
};

#endif // CLICKATELL_H

Pretty simple. We have a struct which will hold our message parameters: 'user' and 'password' from Clickatell, same as the api ID, which is a unique identifier you get from Clickatell when you open an account. The 'baseurl' is the main URL through which we will send our message using the http protocol. This will become clear later. Finally, we have 'text' and 'to' parameters which will hold the actual text message and the destination phone number.

The public methods are there to simplify setting the parameters just described, a debug method (printParams()) which just prints the elements from the struct and the send() method which will do the actual sending of the SMS. Private attributes are the 'message' and a QNetworkAccessManager object 'message' which we will instantiate in the constructor later. One slot will also be used, replyFinished(), which will be responsible for dealing with data coming back from the API.

Let's have a look at the actual implementaion of this class:

Clickatell::Clickatell()
{
    manager = new QNetworkAccessManager(this);
    message.baseurl="http://api.clickatell.com";
    connect(manager, SIGNAL(finished(QNetworkReply*)),
                                this, SLOT(replyFinished(QNetworkReply*)));

}

In the constructor, we instantiate the QNetworkAccessManager and the base url is set to the Clickatell API. We connect the signal emitted by the QNetworkAccessManager when it is done loading a URL (finished) to the slot we defined earlier (replyFinished()).

I'll assume the methods for setting the recipient phone number, password, username and text message are trivial. The only special need for setting the text message is to make sure the string gets encoded in a way suitable for sending through a URL. We can do that as follows:

void Clickatell::setText(QString txt){
    message.text = QUrl::toPercentEncoding(txt);
}

We implement the send() method as follows. This method is responsible to do the authentication with the Clickatell server, and we get a session ID back when it succeeds:

void Clickatell::send(void){
    QString auth = QString("/http/auth?user=%1&password=%2&api_id=%3");
    auth = auth.arg(message.user).arg(message.password).arg(message.api_id);

    QUrl connect(message.baseurl+auth);
    manager->get(QNetworkRequest(connect));

}

Where do we get the response from? From our slot we connected earlier. We enter this method as soon as the QNetworkAccessManager is done sending the request. 

void Clickatell::replyFinished(QNetworkReply* reply){
    QString sess_id;
    QString partTwo;

    QString sendmsg = QString("/http/sendmsg?session_id=%1&to=%2&text=%3");

    QByteArray data = reply->readAll();
    QString str(data);
    QStringList list = str.split(':');

    if(list.at(0) == "OK"){
        // list.at(1) contains the session ID
        // Remove possible whitespaces
        sess_id = list.at(1).trimmed();

        partTwo = message.baseurl + sendmsg.arg(sess_id).arg(message.to).arg(message.text);

        manager->get(QNetworkRequest(QUrl(partTwo)));

    }else{
        if(list.at(0).contains("ID"))
            qDebug() << "Message on the way";
        else
            qDebug() << str;
    }
}

This method just splits the reply, checks if we got an OK back. If so, authentication went fine and we can go ahead sending the message with the correct session ID embedded in the URL.

As said, these are only the bare essentials, but they should provide a start for some interesting and fun applications.

 

Comments

а вот это забавно: Using the

а вот это забавно: Using the service from a Qt application is pretty straight forward when using the http API, the same one used in e.g., PHP code. There are more extensive APIs available, but this one is the easiest to use and suits my purpose just fine. The code below...

Hi rupnivespi1989, Why do you

Hi rupnivespi1989,

Why do you think it is funny?

 

Johan.