Tag Archive > sms

Extending SMS Capabilities

» 16 July 2012 » In C#, Life, Open-Source, Programming » 3 Comments

I live in a place where wireless access points are few, mobile internet is expensive, but SMS is unlimited. Of course, I use SMS for communicating with my friends, family, girlfriend, colleagues, and for business. Then, one day it came to my mind, why not communicate with my personal computer?

My father brought home a USB dongle (Huawei E220), I unlocked it, and tried a sim card, and it worked! Now this, is what my computer will be using as a receiver. At first, it’s very frustrating to install the drivers for this dongle. Modern ones are just smooth on PnP (Plug ‘n Play) features. It took me a while to find out that I need to reconfigure the driver Windows installed by default.

Setting Up

Now it’s connected. But I need a way to make it receive SMS, and save it somehow. Then I stumbled upon Gammu luckily, it supports E220(see all supported devices). The configuration file is given, and pretty elementary.

[gammu]
port = COM6
connection = at19200
model = at

You just need to replace COM6 with the COM port you have in your device manager.

Device Manager

COM Port used by the USB Dongle

And then, I intend to install gammu as a service. Luckily an SMS daemon is included, and using the previous gammu configuration:

[smsd]
logfile=C:\smsd\smsd.log
service=files
inboxpath=C:\SMSData\data\


[gammu]
port = COM6
connection = at19200
model = at

[include_numbers]
+000000000000

You can change the paths as you wish, but make sure your number is included in the [include_numbers] section. This is a nice feature that will block unwanted texts from other numbers.

Not that it’s all set, run the daemon and make it install itself as a service, then start the service.

gammu-smsd -i -c C:\smsd\gammu-smsdrc

It will now run automatically with windows. Your USB dongle must be connected all the time to your computer.

Processing Received Messages

Now here’s a tricky but fun part. How will you process the incoming messages? Notice that I used the Files mode instead of using DBMS to receive SMS message. This is because, I need to constantly check if there’s a new message, and checking the database tables every now and then for 24/7 is painful. So in files, we’re gonna use a Timer? No! Of course, we’re not using methods that will cause heavy CPU load.

Using the FileSystemWatcher class, we can check, in real-time, if there’s a new file created in a given directory. This is perfect, because gammu’s SMS daemon creates a new text file, with the message in it, in the specified directory we included in the configuration file.

if (!fpath.Equals(""))
    watcher.Path = fpath + @"\";

watcher.Filter = "*.txt";
watcher.NotifyFilter = NotifyFilters.LastWrite | NotifyFilters.FileName;
watcher.Created += new FileSystemEventHandler(OnChanged);
watcher.EnableRaisingEvents = listenToolStripMenuItem.Checked;

Whenever a file is created inside the specified directory, it will execute the code inside the OnChanged() method. From this, we can process the content of each file and read them.

But not so fast. Sadly(although this seems like a right way), gammu splits the messages by 67 characters. Meaning, if your message exceeds 67 characters, it will be split into several files. For instance:

IN20120716_121927_00_+000000000000_00.txt
IN20120716_121927_00_+000000000000_00.txt
IN20120716_121930_00_+000000000000_01.txt

These are files the dongle received at one point in time. But they really are just 2 separate messages. How? If you look into the last two digits on the filename, it will tell you the sequence of the messages. 00 means the beginning of the message, if followed by another 00, it’s a new message. But if it’s followed by 01, it’s to be appended, and must be read as part two of the first one.

It took me sometime to figure out how to combine them into one. I can only receive one at a time, but the parts came both together with a very tiny interval. By this, I came up with a solution that will use a Timer.

timer.Enabled = false;
timer.Interval = 1000;
timer.Tick += new EventHandler(timer_Tick);

I allotted two seconds to wait for upcoming possible parts, then process them and verify if they really are parts of a long message.

private void OnChanged(object sender, FileSystemEventArgs e)
{
    if (timer.Enabled)
    {
        tmp.Add(e.FullPath);
    }
    else
    {
        tmp = new List<string>();
        this.Invoke(new MethodInvoker(delegate
        {
            timer.Enabled = true;
            timer.Start();
        }));
        tmp.Add(e.FullPath);
    }            
}

private void timer_Tick(object sender, EventArgs e)
{
    secs++;
    if (secs >= 2)
    {
        timer.Enabled = false;
        secs = 0;
        procList(tmp);
    }
}

private void procList(List<string> lst)
{
    List<string> data = new List<string>();
    string xdata = "";
    bool app = true;
    int prev = -1;
    foreach (string fp in lst)
    {
        if (Regex.IsMatch(fp, @"_(d{2})\.txt$"))
        {
            Match m = Regex.Match(fp, @"_(d{2})\.txt$");
            int x = Int32.Parse(m.Groups[1].Value);
            if (x - prev != 1)
            {
                app = false;
                prev = -1;
            }
            else
            {
                prev = x;
            }
        }
        string datum = readContent(fp);
        if (app)
        {
            xdata += datum;
        }
        else
        {
            data.Add(xdata);
            xdata = datum;
        }
    }
    data.Add(xdata);
    foreach (string d in data)
    {
        processData(d);
    }
            
}

It’s a pretty long process, and it took me hours to figure out what to do. But after that, it’s time to add some modules to boost its functionality.

Making Things Functional

As for now, I only have the twitter module working.

private void processData(string data)
{
    Command cmd = parseString(data);

    switch (cmd.id)
    {
        case "tweet":
            tServ.SendTweet(cmd.arg);
            break;
        case "google":
            // Google processing here
            break;
    }
}

private Command parseString(string str)
{
    Command cmd = new Command();
    if (str.Contains(' '))
    {
        cmd.id = str.Split(' ').FirstOrDefault();
        cmd.arg = str.Remove(0, cmd.id.Length + 1);
    }
    return cmd;
}
// ... 
class Command
{
    public string id;
    public string arg;
}

I have plenty of ideas in mind. I am currently working on a google module, then a file-search module for my computer, and many more. In the mean time, you can watch the development process and add your own modules as well. Fork it in GitHub.

I will update if I have something new. Cheers!

I named this project after Parker, my favorite Leverage character.

Continue reading...

Tags: , , , , , ,

Using GAE Cron to get SMS Alerts from Gmail

» 06 February 2011 » In Guides, Internet, Programming, Python » 13 Comments

Who doesn’t love the free email service Gmail? I am currently using Google Apps Mail for this domain, and I got it installed in my computer, so I just have to switch windows to check messages. Most of the emails I am receiving is crucial, especially from Scriptlance. And when I am offline (either I am sleeping or I am not home), I don’t know if an email arrives, or if I should be online to respond to that email. So the solution for this? SMS alert.

I’m pretty sure there are lots of services that offer email alerts to your phone, but chances are, they are not free, and we are not sure if the login information is kept or used in something we do not like.

For this to work, there are some requirements:

  • SMS Gateway
  • Google App Engine Account
  • Google App Engine SDK (and Python 2.5 of course)
  • Your Gmail or Google Apps Mail credentials

The SMS gateway is not free in most cases, but you can use if a friend has one, just make sure it works with your carrier.

The first thing you need to do is create a GAE Application. Name it whatever you like, and on the app.yaml, add these lines:

- url: /check/mail
  script: check.py
  login: admin

Of course you can changes the url and script, but I just like to use that in this guide. Next is to create cron.yaml, and put the following lines:

cron:
- description: Check Mail
  url: /check/mail
  schedule: every 1 minutes

You can change the schedule on how frequent you like your mail to be checked. For me, I chose to check every one minute (There’s a grammatical error on the yaml file, but ignore it, it’s correct according to the syntax). That means, every minute, the script will check for unread messages and sends me a SMS message if there is one.

Next is to create a script called check.py:

#!/usr/bin/env python
'''
	Copyright (c) Ruel Pagayon <http://ruel.me>
'''

from xml.dom.minidom import parseString
from google.appengine.ext import db
import urllib2
import urllib
import base64
import sys

'''
	Change the values below.
'''
gFeed = 'https://mail.google.com/mail/feed/atom'
#gFeed = 'https://mail.google.com/a/domian.tld/feed/atom'	#For Google Apps for Mail users.

gEmail = 'user@domain.tld'
gPass = 'pass'

class Uid(db.Model):
	cont = db.StringProperty()

def sendSMS(message):
	'''
		Insert appropriate code for your SMS gateway here.
		Obviously the one below doesn't work.
		It's there to give you an insight on how it will work.
	'''
	urllib2.urlopen('http://somegateway.com:1578/?user=smsuser&password=smspass&PhoneNumber=18005669874&Text=%s' % urllib.quote(message))
	
def getNewMail(feed):
	'''
		Check for new unread mails. Use basic auth.
	'''
	request = urllib2.Request(feed)
	base64string = base64.encodestring('&s:%s' % (gEmail, gPass)).replace('\n', '')
	request.add_header("Authorization", "Basic %s" % base64string)
	'''
		Parse XML using DOM
	'''
	xdata = urllib2.urlopen(request).read()
	dom = parseString(xdata)
	count = dom.getElementsByTagName('fullcount')[0].firstChild.data
	
	'''
		Retrieve last message ID from datastore
	'''
	ouid = Uid.all()
	
	if ouid.count() != 0:
		lastId = ouid[0].cont
		
	if int(count) > 0:
		'''
			Check if there are feed entries.
			Get the ID of the latest message.
		'''
		eid = dom.getElementsByTagName('entry')[0].getElementsByTagName('id')[0].firstChild.data
		'''
			Generate report.
		'''
		message = "You got " + count + " new email(s)\n\n"
		for entry in dom.getElementsByTagName('entry'):
			'''
				Loop through each email entry
			'''
			message += "Sender: %s (%s)\n" % (entry.getElementsByTagName('name')[0].firstChild.data, entry.getElementsByTagName('email')[0].firstChild.data)
			message += "Subject: %s\n\n" % entry.getElementsByTagName('title')[0].firstChild.data
			
		if eid != lastId:
			'''
				If the last ID from the data store, 
				is different from the latest message ID,
				update the data store and
				send the SMS
			'''
			if ouid.count() != 0:
				nuid = Uid.get(ouid[0].key())
			else:
				nuid = Uid()
			nuid.cont = eid
			nuid.put()
			sendSMS(message)
		'''
			You got 1 new email(s)
			
			Sender: Someone (someone@domain.tld)
			Subject: Example Message
		'''

def main():
	getNewMail(gFeed)

if __name__ == '__main__':
	main()

Change the values that suites your needs. And the docstrings on the script pretty much explains everything, so I don’t have to repeat it here.

Now, we all know that a free GAE app has quota, and on the script, we will be using the Data Store API and the UrlFetch API, let’s do some math. The quota will reset every 24 hours. So, if you decided to check the mail every 1 minute, we got 1440 calls. And it’s not even a quarter of the limit.

Now obviously we can use the script on our webservers, the only thing that we need to change is the data store calls (GAE doesn’t allow writing to disk, so Datastore is used). But the problem here is the credentials are in plain text, and there’s a huge risk for this information to be seen by other parties. So why not just use GAE? Where only you and Google can have access. :)

Continue reading...

Tags: , , , , , ,