#!/usr/local/bin/perl5 -w # send pages to people via paging company Web interfaces or SNPP # # released to mon list on 7/18/00 # alpha version - please send fixes, improvements, or suggestions to # Ed Ravin use strict; use Getopt::Long; use Socket; use Net::SNPP; my $myname="pageomat"; my %opt; GetOptions (\%opt, "debug", "pin=s", "company=s", "timeout=i", "message=s"); my %pageinfo= ( 'skytel'=> { 'url' => 'snpp://snpp.skytel.com:7777' }, 'skytel-http' => { 'url' => 'http://www.skytel.com/servlet/SendMessage', 'format' => 'recipients=%s&message=%s', 'match' => '(Your Message Status Number is: \d+)|(Skytel Messaging Center Has Received Your Message)' } , 'bellsouthips' => { 'url' => 'http://www.bellsouthips.com/scripts/rampage.dll?ProcessSendMail', 'format' => 'pin=%s&media=None&retaddr=&data=%s', 'match' => 'Your message has been sent to destination address' }, 'omnipoint' => { 'url' => 'http://www.omnipoint.com/cgi-bin/message.cgi', 'format' => 'load=%s&phone=%s&message=%s', 'match' => 'message_sent.html', 'referer' => 'Referer: http://www.omnipoint.com/common/center/main.html', 'arg1' => url_encode('http://www.omnipoint.com/common/center/message_sent.html') }, 'bam' => { 'url' => 'http://www3.bam.com/cgi-bin/sms/sms.cgi', 'format' => 'msg_type=messaging&area_code=%s&exchange=%s&extension=%s&message=%s&tCharacterCount=0', 'cut_pin_3' => 'true', 'match' => 'Your Message Has Been Accepted For Delivery' }, # att not tested yet 'att' => { 'url' => 'http://www.mobile.att.net/mc/pager_show.cgi', 'format' => 'category=personal&pin=%s&sizebox=%s' }, ); my $usage="Usage: $myname --pin=pagerid --company={" . join('|', keys %pageinfo) . "}\n"; my $debug= $opt{'debug'} || undef; my $pin= $opt{'pin'} || die "$usage"; my $company= $opt{'company'} || die "$usage"; my $timeout= $opt{'timeout'} || 30; my $message= $opt{'message'} || join (' ', ); $message =~ s/\n/ /g; # chop up url my ($protocol, $hostname, $path)= ($pageinfo{$company}{'url'} =~ m!([^:]+)://([^/]+)(.*)!); my $port; if ($hostname =~ m!([^:]+)(:\d+)!) { $hostname= $1; $port= $2; } $port=80 unless defined($port); $port=~ s/://; if ($debug) { print "Message to $pin at $company via $pageinfo{$company}{'url'}\n"; print "Protocol is $protocol, server is $hostname, port is $port, path is $path\n"; } if ($protocol eq "snpp") { send_snpp($hostname, $port, $pin, $message); exit 0; } if ($debug) { open COMMAND, ">&STDOUT" || die "$0: can't dup fd for debugging: $!"; } else { my $pro = getprotobyname ('tcp'); if (!defined $pro) { die "$myname: could not getprotobyname tcp: is there a network here?\n"; } if (!defined socket (COMMAND, PF_INET, SOCK_STREAM, $pro)) { die "$myname: could not create socket: $!\n"; } my $address = inet_aton ($hostname); if (!defined $address) { die "$myname: $hostname could not inet_aton"; } my $sin = sockaddr_in (80, $address); if (!defined $sin) { die "$0: $hostname/$address could not sockaddr_in"; } my $r; die "$0: cannot setsockopt: $!" unless setsockopt(COMMAND, SOL_SOCKET, SO_LINGER, pack "i i", 1, 10); eval { local $SIG{"ALRM"} = sub { die "alarm\n" }; alarm $timeout; $r = connect (COMMAND, $sin); alarm 0; }; if ($@) { if ($@ eq "alarm\n") { die "$0: $hostname/$address timeout"; } else { die "$0: $hostname/$address interrupted syscall: $!"; } } if (!defined $r) { die "$0: $hostname/$address could not connect: $!"; } } if ($company eq "skytel-http") { # Skytel's form chokes on or eats up these characters - so substitute them $message =~ s/[&]/{and}/g; $message =~ s/[+]/{plus}/g; $message =~ s/[%]/{percent}/g; } elsif ($company eq "bam") { # bam doesn't like carrots. Silly rabbit... $message =~ s//)/g; } $message= url_encode($message); # format for POST'ing my $data; if (defined($pageinfo{$company}{'arg1'})) { $data= sprintf $pageinfo{$company}{'format'}, $pageinfo{$company}{'arg1'}, $pin, $message; } elsif (defined($pageinfo{$company}{'cut_pin_3'})) { die "PIN must be 10-digit number for this company" unless $pin =~ /^\d{10}$/; my ($areacode, $exchange, $suffix)= (substr($pin,0,3), substr($pin,3,3), substr($pin,6,4)); $data= sprintf $pageinfo{$company}{'format'}, $areacode, $exchange, $suffix, $message; } else { $data= sprintf $pageinfo{$company}{'format'}, $pin, $message; } select COMMAND; $|=1; select STDOUT; print COMMAND "POST $path HTTP/1.0\r\n" . "Host: $hostname\r\n" . "Accept: text/html, text/plain\r\n" . "User-Agent: $myname\r\n" . ( defined($pageinfo{$company}{'referer'}) ? "$pageinfo{$company}{'referer'}\r\n" : "" ) . "Content-type: application/x-www-form-urlencoded\r\n" . "Content-length: " . length($data) . "\r\n\r\n" . $data; print COMMAND "\r\n" if $debug; $SIG{"PIPE"} = 'IGNORE'; shutdown COMMAND, 1; # SHUT_WR - disallow further writes my $response= ""; my @response; alarm $timeout; # just die if we get stuck somehow listening on the socket @response= ; $response= join('', @response); print length($response), " bytes received.\n"; if ( $response =~ $pageinfo{$company}{'match'} ) { print "Message delivery confirmed to $pin at $hostname:\n"; exit 0; } else { print "No match - cannot confirm message delivery.\n"; open TRACE, ">/tmp/pageomat.response.$$" || die "$0: cannot create tracefile /tmp/pageomat.$$: $!"; print TRACE $response; close TRACE; exit 1; } sub send_snpp { my ($host, $port, $pagerid, $text) = @_; my $rc; my $snpp = Net::SNPP->new ($host, Port => $port, Timeout => 60) or die "SNPP->new fails: $!"; $rc= $snpp->send ( Pager => [ $pagerid ], Message => "$text" ); die "SNPP send fails." unless $rc; $snpp->quit; } sub url_encode { my $text = shift; $text =~ s/([^a-zA-Z0-9_\-.])/uc sprintf("%%%02x",ord($1))/eg; return $text; }