#!/usr/bin/perl # # LJ::TextMessage class # See perldoc documentation at the end of this file. # # ------------------------------------------------------------------------- # # This package is released under the LGPL (GNU Library General Public License) # # A copy of the license has been included with the software as LGPL.txt. # If not, the license is available at: # http://www.gnu.org/copyleft/library.txt # # ------------------------------------------------------------------------- # package LJ::TextMessage; use URI::Escape; use LWP::UserAgent; use strict; use vars qw($VERSION $SENDMAIL %providers); $VERSION = '1.2'; # default path to sendmail, if none other specified. we should probably # use something more perl-ish and less unix-specific, but whateva' $SENDMAIL = "/usr/sbin/sendmail -t"; %providers = ( 'voicestream' => { 'name' => 'Voicestream', 'notes' => 'Enter your 10-digit phone number. Message is sent via the web gateway on Voicestream.com which is often a lot faster than the email gateway. Expect arrival within 5 or 6 seconds.', 'fromlimit' => 15, 'msglimit' => 140, 'totlimit' => 140, }, 'pacbell' => { 'name' => 'Pacific Bell Wireless (Cingular)', 'notes' => 'Enter your 10 digit phone number. Sent through web gateway at pacbellpcs.net, almost instant delivery.', 'fromlimit' => 25, 'msglimit' => 640, 'totlimit' => 665, }, 'att' => { 'name' => 'AT&T Wireless', 'notes' => '10-digit phone number. Goes to @mobile.att.net', 'fromlimit' => 50, 'msglimit' => 150, 'totlimit' => 150, }, 'nextel' => { 'name' => 'Nextel', 'notes' => '10-digit phone number. Goes to @messaging.nextel.com', 'fromlimit' => 50, 'msglimit' => 126, 'totlimit' => 126, }, 'qwest' => { 'name' => 'Qwest', 'notes' => '10-digit phone number. Goes to @uswestdatamail.com', 'fromlimit' => 14, 'msglimit' => 100, 'totlimit' => 100, }, 'skytelalpha' => { 'name' => 'Skytel - Alphanumeric', 'notes' => 'Enter your 7-digit pin number as your number and your message will be mailed to pin@skytel.com', 'fromlimit' => 15, 'msglimit' => 240, 'totlimit' => 240, }, 'email' => { 'name' => 'Other', 'notes' => 'If your provider isn\'t supported directly, enter the email address that sends you a text message in phone number field. To be safe, the entire message is sent in the body of the message, and the length limit is really short. We\'d prefer you give us information about your provider so we can support it directly.', 'fromlimit' => 15, 'msglimit' => 100, 'totlimit' => 100, }, 'bellsouthmobility' => { 'name' => 'BellSouth Mobility', 'notes' => 'Enter your 10-digit phone number. Goes to @blsdcs.net via email.', 'fromlimit' => 15, 'msglimit' => 160, 'totlimit' => 160, }, 'sprintpcs' => { 'name' => 'Sprint PCS', 'notes' => 'Enter your 10-digit phone number. Goes to @messaging.sprintpcs.com', 'fromlimit' => 15, 'msglimit' => 97, 'totlimit' => 97, }, 'arch' => { 'name' => 'Arch Wireless', 'notes' => 'Enter your 10-digit phone number. Sent via http://www.arch.com/message/ gateway. Assumes blank PIN.', 'fromlimit' => 15, 'msglimit' => 220, 'totlimit' => 220, }, # uBoot feature added by Tony Sutton (Tony@hypertony.co.uk) LJ: tsutton # Last Updated 24th Febuary 2001 'uboot' => { 'name' => 'uBoot', 'notes' => 'Enter your username as the phone number. See http://www.uboot.com for more details', 'fromlimit' => 15, 'msglimit' => 160, 'totlimit' => 160, }, ); sub providers { return sort { lc($providers{$a}->{'name'}) cmp lc($providers{$b}->{'name'}) } keys %providers; } sub provider_info { my $provider = shift; return { %{$providers{$provider}} }; } sub new { my ($class, $args) = @_; my $self = {}; bless $self, ref $class || $class; $self->init($args); return $self; } sub init { my $self = shift; my $args = shift; $self->{'sendmail'} = $args->{'mailcommand'} || $SENDMAIL; $self->{'provider'} = $args->{'provider'}; $self->{'number'} = $args->{'number'}; } sub send { my $self = shift; my $msg = shift; # hashref: 'from', 'message' my $errors = shift; # arrayref my $provider = $self->{'provider'}; unless ($provider) { push @$errors, "No provider specified in object constructor."; return; } my $prov = $providers{$provider}; ## ## truncate 'from' if it's too long for the given provider ## if (length($msg->{'from'}) > $prov->{'fromlimit'}) { $msg->{'from'} = substr($msg->{'from'}, 0, $prov->{'fromlimit'}); } ## ## now send the message, based on the provider ## if ($provider eq "voicestream" ) { post_webform("http://www.voicestream.com/messagecenter/rtsValidate.asp", $errors, { "txtNum0" => $self->{'number'}, "From" => $msg->{'from'}, "Message" => $msg->{'message'}, "totSubscriber" => 1, ## who knows what this is. }); # uBoot feature added by Tony Sutton (Tony@hypertony.co.uk) LJ: tsutton # Last Updated 24th Febuary 2001 } elsif ($provider eq "uboot") { post_webform("http://www.uboot.com/cgi-bin/nickpage.fcgi", $errors, { "page" => "Sms", "action" => "send_sms", "nickname" => $self->{'number'}, "text" => $msg->{'message'}, }); } elsif ($provider eq "pacbell") { post_webform("http://www.pacbellpcs.net/servlet/cmg.vasp.smlp.ShortMessageLaunchPad?FOO", $errors, { "LANGUAGE" => "en", "NETWORK" => "smsc1", "DELIVERY_TIME" => 0, "SENDER" => $msg->{'from'}, "RECIPIENT" => "1$self->{'number'}", # 11 digit phone number ("1"+number) "SHORT_MESSAGE" => $msg->{'message'}, }); } elsif ($provider eq "att") { send_mail($self, { 'to' => "$self->{'number'}\@mobile.att.net", 'from' => "$msg->{'from'}", 'body' => $msg->{'message'}, }); } elsif ($provider eq "nextel") { send_emailgate($self, $msg, "messaging.nextel.com"); } elsif ($provider eq "skytelalpha") { send_mail($self, { 'to' => "$self->{'number'}\@skytel.com", 'from' => $msg->{'from'}, 'body' => $msg->{'message'}, }); } elsif ($provider eq "qwest") { send_emailgate($self, $msg, "uswestdatamail.com"); } elsif ($provider eq "sprintpcs") { post_webform("http://www.messaging.sprintpcs.com/sms/check_message_syntax.html", { }, # no error checking { "mobilenum" => $self->{'number'}, "message" => "($msg->{'from'}) $msg->{'message'}", "java" => "yes", # they mean javascript. dumb asses. }); } elsif ($provider eq "arch") { post_webform("http://www.arch.com/cgi-bin/archepage.exe", $errors, { "ACCESS" => $self->{'number'}, "MSSG" => "($msg->{'from'}) $msg->{'message'}", "Q1" => "1", "PIN" => "", }); } elsif ($provider eq "bellsouthmobility") { send_emailgate($self, $msg, "blsdcs.net"); } elsif ($provider eq "email") { send_mail($self, { 'to' => $self->{'number'}, 'from' => "LiveJournal", 'body' => "(f:$msg->{'from'})$msg->{'message'}", }); } else { push @$errors, "Tried to send a message to an unknown or unsupported provider."; } } sub post_webform { my ($url, $errors, $postvars) = @_; ### we're going to POST to voicestream's page my $ua = new LWP::UserAgent; $ua->agent("Mozilla/4.0 (compatible; MSIE 5.5; Windows NT 5.0)"); $ua->timeout(5); my $req = new HTTP::Request POST => $url; $req->content_type('application/x-www-form-urlencoded'); $req->content(request_string($postvars)); # Pass request to the user agent and get a response back my $res = $ua->request($req); if ($res->is_success) { return; } else { push @$errors, "There was some error contacting the user's text messaging service via its web gateway. The message was most likely not sent."; return; } } sub send_emailgate { my ($self, $msg, $domain) = @_; send_mail($self, { 'to' => "$self->{'number'}\@$domain", 'from' => "webmaster\@livejournal.com ($msg->{'from'})", 'subject' => "LJ Msg", 'body' => $msg->{'message'}, }); } sub send_mail { my $self = shift; my $opt = shift; open (MAIL, "|" . $self->{'sendmail'}); print MAIL "To: $opt->{'to'}\n"; print MAIL "Bcc: $opt->{'bcc'}\n" if ($opt->{'bcc'}); print MAIL "From: $opt->{'from'}"; if ($opt->{'fromname'}) { print MAIL " ($opt->{'fromname'})"; } print MAIL "\nSubject: $opt->{'subject'}\n\n"; print MAIL $opt->{'body'}; close MAIL; } sub request_string { my ($vars) = shift; my $req = ""; foreach (sort keys %{$vars}) { my $val = uri_escape($vars->{$_},"\+\=\&"); $val =~ s/ /+/g; $req .= "&" if $req; $req .= "$_=$val"; } return $req; } 1; __END__ # Below is the stub of documentation for your module. You better edit it! =head1 NAME LJ::TextMessage - text message phones/pages using a variety of methods/services =head1 SYNOPSIS use LJ::TextMessage; @providers = LJ::TextMessage::providers(); foreach my $p (@providers) { my $info = LJ::TextMessage::provider_info($p); print "Name: $info->{'name'}\n"; print "Notes: $info->{'notes'}\n"; print "Limits: \n"; foreach my $limit (qw(from msg tot)) { print " $limit: ", $info->{"${limit}limit"}, "\n"; } } my $phone = new LJ::TextMessage { 'provider' => 'voicestream', 'number' => '2045551212', 'mailcommand' => '/usr/local/sbin/sendmail -t', }; my @errors; $phone->send({ 'from' => 'Bob', 'message' => "Hello! This is my message!" }, \@errors); if (@errors) { ... } else { print "Message sent!\n"; } =head1 DESCRIPTION The synopsis pretty much shows all the functionality that's available, but details would be nice here. =head1 BUGS This library is highly volatile, as cellphone and pager providers can change the details of their web or email gateways at any time. In practice I haven't had to update this library much, but providers have no responsibility to tell me when they change their form field names on their website, or change URLs. This documentation sucks. =head1 AUTHOR Brad Fitzpatrick, bradfitz@bradfitz.com Information about text messaging gateways from many. =cut