Browsing articles tagged with " phones" I’m in your IRC, SMSing your SMSes

This script is a proof-of-concept that I wanted to try more than anything else. Lightly modelled on bitlbee, it pretends to be an IRC server, and accepts/sends SMSes via a gateway (or a gateway app on your Android phone). It’s very much not a finished product and is known to have memory leaks. It also doesn’t clean up after it’s threads.

This script requires threads, threads::shared and IO::Socket.

Config-wise, it’s fairly straightforward – it’s all done in lines 6-21 of the script source. Set $IRCport and $IRCbind to the IP and TCP port you want the server to listen on. Set $IRCpassword to be the password that the IRC client must submit to connect.

The only part that gets tricky is interacting with the gateway. $SMScommand should be set to a script to pass the SMS off to the gateway for delivery. You can use the variables %TO% and %TEXT% in the script path as parameters – these will be replaced with the recipient and the text of the message respectively before the script is called. This could be a PHP script (“/usr/bin/php send-sms.php %TO% ‘%TEXT%’”), a URL using curl or wget (“/usr/bin/wget http://localhost/cgi-bin/sms.cgi?to=%TO%&text=%TEXT%”), an email address using sendmail or similar (“echo %TEXT% | /usr/sbin/sendmail”) or anything else you might want to use.

Likewise, receiving SMSes can be a bit tricky. $SMSreceiveKey needs to be set to a key that will be used to ensure that the SMSes are received from the real gateway. SMSes are accepted from the gateway by connecting to the IRC server socket and sending nothing more than:

DELIVER sms-receive-key 1234567890 :SMS text goes here.\r\n

The connection does not have be registered as an IRC client or authenticated to the server. It’s important to note that the IP and port you have set earlier in the configuration must be accessible by whatever is delivering the SMSes as well, or it will not be able to connect. In a lot of cases, SMS gateway services or gateway apps running on your phone will only support email forwarding or HTTP delivery of incoming texts. In either of these cases, I suggest creating a script to deliver the SMS for you. In the former case, a Perl script that gets called by a pipe from the mail server which connects to the server’s socket and deliver’s the SMS would be pretty straightforward. Likewise, a PHP script on a webserver could be configured to accept an SMS by GET/POST parameters and connect to the socket to deliver it.

Use-wise, it’s fairly straightforward. You can type ‘help’ in #sms after connecting for a short summary of this information. When you receive an SMS, the phone number it is received from will join #sms and address the text message to your attention:

* 1234567890 has joined #sms.
<1234567890> your-nickname: Hello there.

You can reply in kind:

<your-nickname> 1234567890: Hiya.

You can also send a text message to a number not presently in the channel the same way – just address the message at the number and SMSbot will ensure it’s delivered for you.

You can also message people by opening a private chat with them – either use ‘/query 123456790′ or double-click their name on the userlist of most IRC clients to open a private chat. Send your message, and replies will automatically be sent back to you in private message. To switch back to receiving their messages in #sms, just message them from the channel again and their replies will go there instead.

Finally, you can use the channel’s userlist as a sort of contact list by adding and removing users from it. When you receive an SMS from someone not already in the channel, they will join. You can also add them to the channel without sending them a message:

<your-nickname> add 1234567890
* 1234567890 has joined #sms.

Likewise, you can remove someone from the channel whether they joined because you added them or because they sent you a message:

<your-nickname> remove 1234567890
* 1234567890 has left #sms.

If you remove someone from the channel, they will join again the next time they send you a message.

Script Source

use IO::Socket;
use threads;
use threads::shared;

##### Config #####

# IRCd settings. At least change the password.
my $IRCport = "21337";
my $IRCbind = "";
my $IRCpassword = "irc4sms";

# Shell command to send SMSes via gateway.
# Consider using wget or sendmail!
# Variables! %TO% and %TEXT%
my $SMScommand = "/usr/bin/wget http://localhost/cgi-bin/send-sms.cgi?to=%TO%&text=%TEXT%";

# Key to receive inbound SMSes. Change this.
my $SMSreceiveKey = "1rc45m5!";

##### End Config ######

$version = "0.2";
$crlf = "\r\n";

my @msgQueue;
my %joined;


my $listen_socket = IO::Socket::INET->new(
	LocalPort => $IRCport,
	LocalAddr => $IRCbind,
	Listen => 10,
	Proto => 'tcp',
	Reuse => 1
die "Can't bind local socket: $!\n" unless $listen_socket;

while(my $connection = $listen_socket->accept){
	my $child = threads->create("read_data", $connection);

sub deliver_data {
	my($socket, $nickname) = @_;
		foreach my $message(@msgQueue) {
				my ($sender, $text) = $message =~ /^(.+?)\:(.+)$/;
				if($sender && $text){
						if($joined{$sender} < 1){
								$joined{$sender} = 1;
								print $socket ':'.$sender.' JOIN #sms'.$crlf;
						if($joined{$sender} == 1){ print $socket ':'.$sender.' PRIVMSG #sms :'.$nickname.': '.$text.$crlf; }
						if($joined{$sender} > 1){ print $socket ':'.$sender.' PRIVMSG '.$nickname.' :'.$text.$crlf; }
		@msgQueue = ();

sub read_data {
	my($socket) = @_;
	my $registered = 0;

	print $socket ':irc4sms.local NOTICE AUTH :irc4sms ready. Login or deliver an SMS.'.$crlf;
		$data = $_;
		print $data;
		$data =~ s/[\r\n]//ig;

		if($data =~ /^PING (.+)$/){
			print $socket ':irc4sms.local PONG irc4sms.local :'.$1.$crlf;

		if($registered < 3){
			if($data =~ /^DELIVER (.+?) (.+?) \:(.+)$/ && $1 eq $SMSreceiveKey){
				$sender = $2;
				$text = $3;
				$sender =~ s/^\+//;
				$msgQueue[++$#msgQueue] = $sender.":".$text;
				print $socket 'MESSAGE OK ('.$sender.'): '.$text.' - Queued for delivery.'.$crlf;
			}elsif($data =~ /^USER (.+?) .+ (?:\:|)(.+)$/){
				$username = $1;
				$realname = $3;
			}elsif($data =~ /^NICK (.+)$/){
				$nickname = $1;
				print $socket ':irc4sms.local 464 '.$nickname.' :P assword required.'.$crlf;
			}elsif($data =~ /^PASS (.+)$/){
				if($1 eq $IRCpassword){
					print $socket ':irc4sms.local 464 '.$nickname.' :Invalid password.'.$crlf;

			if($registered == 3){
				print $socket ':irc4sms.local 001 '.$nickname.' :Welcome'.$crlf;
				print $socket ':irc4sms.local 002 '.$nickname.' :Host irc4sms.local is running irc4sms '.$version.$crlf;
				print $socket ':irc4sms.local 003 '.$nickname.' :irc4sms ('.$crlf;
				print $socket ':irc4sms.local 004 '.$nickname.' irc4sms.local abiswRo ntC'.$crlf;
				print $socket ':irc4sms.local 005 '.$nickname.' PREFIX=(ohv)@%+ CHANTYPES=# CHANMODES=,,,ntC NICKLEN=25 CHANNELLEN=25 NETWORK=irc4sms SAFELIST CASEMAPPING=rfc1459 MAXTARGETS=1 WATCH=128 :are supported by this server'.$crlf;
				print $socket ':irc4sms.local 375 '.$nickname.' :- irc4sms.local MOTD:'.$crlf;
				print $socket ':irc4sms.local 372 '.$nickname.' :- Welcome to irc4sms '.$version.$crlf;
				print $socket ':irc4sms.local 376 '.$nickname.' :End of MOTD'.$crlf;
				print $socket ':'.$nickname.'!'.$username.'@irc4sms.local MODE cm :+sR'.$crlf;
				print $socket ':'.$nickname.'!'.$username.'@irc4sms.local JOIN :#sms'.$crlf;
				print $socket ':irc4sms.local MODE #sms +Ct'.$crlf;
				print $socket ':irc4sms.local 353 '.$nickname.' = #sms :@'.$nickname.' @SMSbot'.$crlf;
				print $socket ':irc4sms.local 366 '.$nickname.' #sms :End of /NAMES list'.$crlf;
				print $socket ':irc4sms.local 332 '.$nickname.' #sms :irc4sms '.$version.$crlf;
				print $socket ':irc4sms.local 333 '.$nickname.' #sms SMSbot!SMSbot@irc4sms.local '.(time - 60).$crlf;
				$joined{$nickname} = 1;
				$joined{'SMSbot'} = 1;
				my $delivery = threads->create("deliver_data", $socket, $nickname);
			if($data =~ /^MODE/){
				print $socket ':irc4sms.local 324 '.$nickname.' #sms +Ct'.$crlf;
			}elsif($data =~ /^WHO/){
				print $socket ':irc4sms.local 352 '.$nickname.' #sms '.$username.' irc4sms.local irc4sms.local '.$nickname.' H@ :0 '.$realname.$crlf;
				print $socket ':irc4sms.local 352 '.$nickname.' #sms irc4sms irc4sms.local irc4sms.local SMSbot H@ :0 irc4sms '.$version.$crlf;
			}elsif($data =~ /^PRIVMSG \#sms \:(.+?)(?:\:|\,) (.+)$/){
				if($joined{$1} > 0){
					$joined{$1} = 1;
				$to = $1;
				$text = $2;
				$cmd = $SMScommand;
				$cmd =~ s/\%TO\%/$to/g;
				$cmd =~ s/\%TEXT\%/$text/g;
			}elsif($data =~ /^PRIVMSG ([a-zA-Z0-9\+]+?) \:(.+?)$/){
				if($joined{$1} > 0){
					$joined{$1} = 2;
				$to = $1;
				$text = $2;
				$cmd = $SMScommand;
				$cmd =~ s/\%TO\%/$to/g;
				$cmd =~ s/\%TEXT\%/$text/g;
			}elsif($data =~ /^PRIVMSG \#sms :( .+?)$/){
				$command = $1;
				if($command =~ /^add (.+)/ && !$joined{$1} ){
					$joined{$1} = 1;
					print $socket ':'.$1.' JOIN #sms'.$crlf;
				}elsif($command =~ /^remove (.+?)$/ && ($joined{$1})){
					$joined{$1} = '';
					print $socket ':'.$1.' QUIT :Leaving...'.$crlf;
				}elsif($command =~ /^help/){
					print $socket ':SMSbot PRIVMSG #sms :Commands: add 442392123456, remove 442392123456'.$crlf;
					print $socket ':SMSbot PRIVMSG #sms :If you /msg a contact, responses will automatically come as a /msg'.$crlf;
					print $socket ':SMSbot PRIVMSG #sms :Otherwise, address the contact in this channel, and their replies will come here'.$crlf;
					print $socket ':SMSbot PRIVMSG #sms :I don\'t recognise that as a valid command. Sorry. Try "help".'.$crlf;

Palm Centro Bluetooth Enabler

Script Information
I recently owned a Palm Centro (although I no longer do and now I do yet again), which is a nice device except for the part where it lacks Wifi connectivity. To combat this problem, I put together a script that allows me to connect to the computer from the Centro using bluetooth, and have my computer act as a router for the unit, allowing it to get on the internet over the bluetooth connection.

It uses AppleScript and Perl, and has three parts. It can be easily modified to work on Linux.


set mypath to POSIX path of (path to me)
set interfaces to do shell script "/bin/bash '" & mypath & "Contents/Resources/Scripts/'"
set ttys to do shell script "/bin/bash '" & mypath & "Contents/Resources/Scripts/'"

set interfacedialog to display dialog "Which interface is connected to the internet?

(Interfaces on this system: " & interfaces & ")" default answer "en1"

set syncttydialog to display dialog "Which serial port is the Bluetooth PDA sync port?

(Ports on this system: " & ttys & ")" default answer "Bluetooth-PDA-Sync"

set sharettydialog to display dialog "Which serial port is the Bluetooth modem sharing port?

This should have been added by you before running this script. If you haven't done this, click cancel, open Bluetooth preferences, go to advanced, and add a new, non-secure port of type Modem, then re-run this enabler and put it's name in this dialog.

Ports on this system: " & ttys & ")" default answer "sharing-port"

set theinterface to the text returned of interfacedialog
set thesynctty to the text returned of syncttydialog
set thesharetty to the text returned of sharettydialog

display dialog "The enabler will now run, starting a PPP server on " & thesynctty & " and " & thesharetty & ", directing packets between them, using " & theinterface & " as a default gateway. It will enable kernel-level packet forwarding and NAT.

This needs to be run each time the system is booted before the Palm will be able to connect, and not more than once.

It will require your password to run, and it may take a short time to complete. Configuration instructions for your handheld will be displayed when it is complete."

do shell script "sudo /usr/sbin/pppd /dev/tty." & thesynctty & " 115200 noauth local
  passive proxyarp asyncmap 0 silent persist : &" with administrator privileges
do shell script "sudo /usr/sbin/sysctl -w net.inet.ip.forwarding=1" with administrator privileges
do shell script "sudo /usr/sbin/natd -same_ports -use_sockets -log -deny_incoming -interface " & theinterface with administrator privileges
do shell script "sudo /sbin/ipfw add divert natd ip from any to any via " & theinterface with administrator privileges
do shell script "sudo /usr/sbin/pppd /dev/tty." & thesharetty & " 115200 noauth local passive proxyarp asyncmap 0 silent persist : &" with administrator privileges

display dialog "The enabler has run. You can now try to connect from your Palm. Your Palm should be paired to this computer.

The Palm should be configured with a connection profile set to 'Connect to PC via Bluetooth', and the device should be set to your computer. Under details, you will need to set the spped to 115,200 bps, and the Flow Ctl to automatic.

You will also need to create a new network profile, set to use the connection you just created. No username or password is necessary. Under details, the idle timeout should be set to never, and under advanced, specify an IP address of You may use whatever DNS servers you like, reccomended are and

Once this is configured you should be able to connect."


ifconfig | perl -e 'while($line=<STDIN>){($int)=$line=~/^(\w+\d):/;if($int ne "" && $int ne "lo0" && $int ne "gif0" && $int ne "stf0"){$allints .= $int." ";}} $allints =~ s/\ $/\n/; print $allints'


ls -1 /dev/tty.* | perl -e 'while($line=<STDIN>){($int)=$line=~/\/dev\/tty\.(.+)$/; $ints.=$int." "}$ints=~s/\ $/\n/;print $ints;'