#!/usr/bin/env perl ############################################################################## # SMS sending script for Israeli cellular phones: Cellcom, Orange (Partner), # Pelephone, and Amigo (Mirs). # # English, and Hebrew (UTF-8 encoding) messages supported for # all providers (but not all phones in all providers support Hebrew SMSs). ############################################################################## # #Copyright (C) 1999-2005 Nadav Har'El (http://harel.org.il/nadav) #Portions by Dan Kenigsberg, Alon Altman, and others #License: GNU GPL *with the following exception* # GPL Exception: This script may not be used for the purpose of mass # unsolicited message distribution (spam). # # Version 3.14beta (unofficial!), [September 15, 2007] # For version history, see below. # The latest version of this script can be found in # http://harel.org.il/nadav/software/sendsms # ############################################################################## # #Installation instructions: (don't forget to read this part!) # #1. You'll have to install the following perl libraries first # Digest-MD5 MIME-Base64 libnet # HTML-Parser URI libwww-perl # Crypt-SSLeay Net::vICQ # # Some Linux distributions (such as Redhat) already include all these # useful libraries by default so you don't need to do anything. # # If you haven't installed these libraries in your system's official Perl # module directory, you'll need to tell sendsms where to find the libraries. # Either change the "BEGIN" line below to list the directory where you # installed these libraries. Or, if you don't want to modify the sendsms # script, you can set the PERLLIB environment variable to point to the # directory where you installed the libraries. For example, to run sendsms # without any modifications even if your Perl and Perl libraries are # installed in non-standard locations, you can run something like this: # PERLLIB=/directory/of/perl/libraries perl -w /where/you/put/sendsms # #2. To send SMSs to phones of each of the supported providers, you will need # to register online and get free SMS-sending acounts: # Amigo: # http://www.amigo.co.il/html/login/new_user.asp # - Hebrew site only # Cellcom, Pelephone or Orange: # http://web.icq.com/sms/login (or any ICQ client) # - Does not require a Cellcom or Pelephone phone; English site. # - If you already have an ICQ account, you can use it. # Orange: # http://www.orange.co.il/default.asp?page=/registration/main.asp # - Completing registration requires owning an Orange phone! # - Hebrew site only # - Might not work on any browser except Microsoft Internet Explorer # #3. Create a file ".sendsmsrc" in your home directory, to include at least # information about these provider accounts. Use the commands # account amigo USER PASSWORD # account icq NUMBER PASSWORD (or email instead of number) # account orange USER PASSWORD # using the accounts you acquired above. If you do not do that for a # particular company, you won't be able to send SMSs to numbers in that # company. You may have more than one account for each provider - in that # case one of the accounts is chosen at random on every invocation of # sendsms (the reason you might want to have more than one account is that # most providers limit each account to 20 messages per day). # The ~/.sendsmsrc file can also contain a proxy definition, aliases, and # including of other files. See the sendsms(1) manual for more information. # ############################################################################## # SendSMS Version History: # # 3.14beta (unofficial!): September 14, 2007 # * Supports the retouched Orange site. # * Expects UTF-8 Hebrew (Or English). # 3.13beta (unofficial!): not published # * Supports ICQ (for all cellphone providers) via vICQ.pm. By an # anonymous contributor. # 3.12beta (unofficial!): April 1, 2007 # * Supports the new (aprx. since Mar 20) Orange site. # * Kinda supports ICQ, via vICQ (http://gonzo.kiev.ua/projects/vicq/). # * Probably no longer supports Amigo. # 3.11: April 12, 2005 # * Support ICQ's changed site (for Orange, Cellcom and Pelephone). # This support now requires the Crypt-SSLeay Perl module (for SSL). # 3.10: March 31, 2005 # * An ICQ account, which previously enabled sending SMSs to Pelephone # and Cellcom phones, now also allows sending messages to Orange # phones. This method is used if an "orange" account is not set in # the .sendsmsrc. (thanks to Dan Kenigsberg) # * Sendsms should now work on Windows (ActiveState Perl). The sendsmsrc # file in Windows resides in $HOMEDRIVE$HOMEPATH\sendsmsrc (no initial # dot in the file name). (thanks to Nimrod Zimerman) # * Fixed 7-digit number support for Amigo (thanks to Amir Friedman) # * New -f option for choosing a different config file (thanks to Dan # Kenigsberg). # 3.9: October 11, 2004 (Nadav Har'El, Dan Kenigsberg) # * Accept new 7-digit phone numbers, as well as old 6-digits numbers. # (thanks to Dan Kenigsberg) # 3.8: December 24, 2003 (Netta Gavrieli, Elad Barkan, Dan Kenigsberg, # Gil Ratsabi) # * Fixed Hebrew support for Cellcom phones (thanks to Netta Gavrieli) # Note that arguments must be in iso8859-8, regardless of the locale. # * Fixed treatment of long ICQ passwords (thanks to Gil Ratsabi) # * Fixed Orange support after two site changes (Elad Barkan and # Dan Kenigsberg) # 3.7: September 7, 2003 (Nadav Har'El) # * Pelephone's old site no longer works (the new one requires owning # a pelephone phone, and apparently costs money). Instead, we started # using ICQ's site (previously used for Cellcom, needs a free account). # * Fixed 065 support. # * Sending Hebrew to Cellcom and Pelephone phones now works (only # tested from a shell running with a ISO-8859-8 locale). # 3.6: July 27, 2003 (Dan Kenigsberg) # * Fixed recognition of successful sending of an Orange message. # 3.5: June 20, 2003 (Nadav Har'El) # * Support for ICQ's modified site (for sending Cellcom messages). # No longer requires SSL or installing the SSLeay package. # * Added 066 area code for Orange and 065 for Cellcom. # 3.4: June 6, 2003 (Nadav Har'El and Eran Tromer) # * Support for Orange's modified site. # * Support for Cellcom's own interface (which now costs money) is # withdrawn; Sendsms can still send SMSs to Cellcom phones using # the ICQ interface. # 3.3: October 27, 2002 (Nadav Har'El, Dan Kenigsberg and Elad Barkan) # * Newlines in messages now work in Orange.co.il # * Can now send messages to Cellcom phones using ICQ's free web # interface (requires either an ICQ number or free registration, but # not a cellcom phone). Requires Crypt-SSLeay library for SSL. # * sms.gt.com.ua no longer works, so support for it has been withdrawn. # 3.2: September 17, 2002 (Nadav Har'El, Dan Kenigsberg, Alon Altman) # * Orangewalla service no longer works. Instead support the # http://sms.gt.com.ua/ and orange.co.il interfaces. # * Added 068 area code for Pelephone. # * Cellcom support trys to warn if Cellcom's service stops being free. # 3.1: July 6, 2002 (Nadav Har'El) # * Support for Cellcom's new site (old site taken down in June 26 2002). # Note that users must get a new iCellcom account. # 3.0: May 1, 2002 (Nadav Har'El) # * Read ~/.sendsmsrc file for accounts, proxy settings and aliases. # * Support for Amigo's new site (amigo.co.il) # * New manual page (sendsms.1) # 2.7: April 21, 2002 (Nadav Har'El) # * Fixed for changes in Cellcom's site done in April 21, 2002. # 2.6: December 11, 2001 (Nadav Har'El) # * Fixed for changes in Orange-Walla's site done Dec 11, 2001, 14:00 IST # * Truncate too-long messages that Orange-Walla's site will drop. # 2.5: December 10, 2001 (Nadav Har'El) # * Improve error reporting for Cellcom. # * Allow sending empty message to Cellcom (converted to a single space). # * Fixed for changes in Cellcom's site done around Dec 10, 2001. # 2.4: November 11, 2001 (Nadav Har'El and Dan Kenigsberg) # * Added 067 area code for Orange. # * Orange's SMS sending web interface stopped working. Use Orange-Walla # instead. # 2.3: May 22, 2001 (Nadav Har'El). # * Fixed for changes in Orange's site done in May 20-21, 2001. # 2.2: May 9, 2001 (Nadav Har'El) # * Added logical-Hebrew support for Pelephone (the previous version did # visual Hebrew. The "-l" option reverts back to visual Hebrew when # this is a Hebrew-supporting phone (latin1 is not supported). # * Added Mirs (Amigo) support. # 2.1: May 5, 2001 (Nadav Har'El) # * Added command line uptions: u (urgency, for cellcom), l, h (encoding) # * Added support for Hebrew SMS in Orange and Cellcom (the -l option is # used to specify Latin1, NOT Hebrew). Note that Hebrew SMS only works # on certain provider/phone combinations, and sendsms cannot always # know if the Hebrew send succeeded (in Cellcom, it can). # * As of April 2001, Cellcom has a fourth area code: 064. # 2.0: May 1, 2001 (Nadav Har'El) # Added Pelephone support, finally. It uses Pelephone's own web # form for sending SMSs (no "account" is necessary). An alternative, # email-gateway-based, approach appears commented out in the code. # A stub was added for the new Mirs Amigo, but no actual support for # it yet. # <2.0: (Nadav Har'El) # Versions released between 1999 and April 2001 were written in Perl # and supported Orange and Cellcom phones. Several times during this # period one of these companies' site has changed (sometimes a bit, # and sometimes a complete overhaul) and the interaction with it had # to be rewritten. A history of these versions was not kept (except # in this file's RCS history which is not public). # <1.0: (Nadav Har'El) # Versions released between June and August of 1999 supported only # Orange phones, using the now-defunct GoSMS web interface. They were # shell scripts, using wget for the actual HTTP interaction. ############################################################################## #TODO: convert this to object oriented, with different classes for different # companies with the same interface (use interitance). require 5.004; BEGIN {push @INC, ("/home/danken/lib/perl5/site_perl/5.8.6")}; # The following should be available on any modern Perl installation use strict; use Carp; use Getopt::Std; use IO::File; # for recursive configuration-file reading use Encode; # ICQ wants utf-8 encoding. # The following usually requires installation (see comment above about that) use LWP::UserAgent; use URI::Escape; use HTTP::Cookies; use Net::vICQ; ############################################################################# # process command line options: my %opts; getopts('lhu:f:', \%opts); # Read the user's configuration file (if any) # note: if for some reason you want to make this script self-contained (without # requiring an external ~/.sendsmsrc file), set the following variables here # and remove the readrc call below... my ($n_account_orange,$ORANGE_USER,$ORANGE_PASSWORD)=0; my ($n_account_amigo,$AMIGO_USER,$AMIGO_PASSWORD)=0; my ($n_account_icq,$ICQ_USER,$ICQ_PASSWORD)=0; my ($http_proxy,%aliases); my ($pay_orange)=0; sub readrc { my $filename = shift; my $RC = new IO::File; $RC->open($filename) or return 0; while(<$RC>){ chomp; if(/^\s*#|^\s*$/o){ # ignore comments and whitespace } elsif(/^\s*account\s+orange\s+(\S*)\s+(\S*)\s*$/o){ # a nice trick for picking a random account without # needing to remember the whole array! if(rand(1)*($n_account_orange++) < 1){ ($ORANGE_USER,$ORANGE_PASSWORD)=($1,$2); } } elsif(/^\s*account\s+amigo\s+(\S*)\s+(\S*)\s*$/o){ if(rand(1)*($n_account_amigo++) < 1){ ($AMIGO_USER,$AMIGO_PASSWORD)=($1,$2); } } elsif(/^\s*account\s+icq\s+(\S*)\s+(\S*)\s*$/o){ if(rand(1)*($n_account_icq++) < 1){ ($ICQ_USER,$ICQ_PASSWORD)=($1,$2); $ICQ_PASSWORD =~ s/^(........).*/$1/; } } elsif(/^\s*(http_)?proxy\s+(\S+)\s*$/o){ $http_proxy=$2; } elsif(/^\s*alias\s+(\S+)\s+(\S+)\s*$/o){ $aliases{$1}=$2; } elsif(/^\s*pay_orange\s+(true|false)\s*$/o){ $pay_orange = ($1 eq 'true'); } elsif(/^\s*include\s+(.*)\s*$/o){ readrc($1) or warn "Could not include file '$1'\n"; } else { warn "Syntax error in ~/.sendsmsrc: '".$_."'\n"; } } # note that close($RC) is automatic when the function ends. return 1; } # Config file to read: ~/.sendsmsrc on Unix-like systems, # $HOMEDRIVE$HOMEPATH\sendsmsrc on Windows, or user specified file if the # "-f" option was given: my $winhome = $ENV{"HOMEDRIVE"}.$ENV{"HOMEPATH"}; my $rcfile = ($winhome eq "") ? glob("~/.sendsmsrc") : $winhome."\\sendsmsrc"; $rcfile = $opts{f} if exists ($opts{f}); readrc($rcfile); ############################################################################# # some more checks on these command line options: #TODO: this piece of code is Cellcom-specific - move it to the cellcom section # after I decide what to do about addding an urgency option to Orange and # Pelephone. THIS CODE DOESN'T HAVE ANY EFFECT IN THIS VERSION! if(exists($opts{u})){ # Cellcom allows 1 ("Normal"), 2 ("Urgent") or 3 ("Emergency") # messages. Emergency messages, for example get listed on the phone # as "new emergency message", and so on. # TODO: Pelephone also allows urgency parameter - test it and use it. # check if orange also has one. Make the urgency parameter the same # for all providers. if($opts{u}!="1" && $opts{u}!="2" && $opts{u}!="3"){ print STDERR "Error: Urgency (-u) can be '1', '2' or '3'.\n"; exit 8; $opts{u}="1"; } } else { $opts{u}="1"; } # When we have non-ascii characters in the message, we need to know if they # are supposed to be Hebrew, or Latin1 characters. Not all provider/phone # combinations support Hebrew at all (and some support Hebrew do not support # Latin1), but some do support both - e.g., Nokia 5120 on Orange (it's non- # Hebrew encoding isn't exactly Latin1, but many important accented latin # characters are the same). # Note that the default "h" (Hebrew, ISO-8859-8) encoding, does not mean that # the message has to be Hebrew - it can be a completely ASCII message too. # Also, when the message does contain Hebrew, it should be "logical" hebrew/ # latin mix (e.g., the word "kelev" is written kaf, lamed, bet, in that order). # This version does not support other encodings. I don't think that Israeli # cellphone companies support SMSs in character-sets besides Hebrew and Latin1. # Using UTF8 encoding MAY work (I didn't check!), but only if the appropriate # "-l" or "-h" options is used (the choice isn't automatic). if(exists($opts{h}) && exists($opts{l})){ print STDERR "Error: Conflicting options -h (ISO-8859-8) and -l (ISO-8859-1) given.\n"; exit 8; } if(!exists($opts{h}) && !exists($opts{l})){ $opts{h}=1; } if($#ARGV+1 != 3){ print STDERR "Usage: $0 [-lh] [-f rcfile] [-u 1/2/3] phonenum sender message\n"; exit 1; } my $phonenum=$ARGV[0]; # check if it's an alias $phonenum = $aliases{$phonenum} if(exists($aliases{$phonenum})); # remove optional spaces, parantheses, or hyphens from phone number $phonenum =~ s/[ ()-]//go; my $sender=$ARGV[1]; my $message=$ARGV[2]; $phonenum = &sixtoseven($phonenum) if $phonenum =~ m/^05[0-9][0-9]{6}$/; my ($t_sec,$t_min,$t_hour,$t_mday,$t_mon,$t_year,$t_wday,$t_yday,$t_isdst) = localtime(time); print STDERR sprintf("[%02d/%02d/%02d %02d:%02d] ",$t_year%100,$t_mon+1,$t_mday, $t_hour,$t_min). "Sending to $phonenum: $message ($sender)\n"; ################################## my ($ua,$req); #$ua = new LWP::UserAgent(keep_alive => 1); $ua = new LWP::UserAgent; # Just some arbitrary (but real-looking, in case some site checks) user agent $ua->agent("Mozilla/4.73 [en] (Win95; I)"); # if no "proxy" (or "http_proxy") command is given in ~/.sendsmsrc, the # environment variables http_proxy and no_proxy are used to choose a proxy (if # any) - see env_proxy in LWP's UserAgent.pm. If a "proxy none" command is # given, a proxy is not used (regardless of the environment variables set). # Otherwise, a command like "proxy http://proxy.com:8080/" sets an http proxy. if(defined $http_proxy){ if($http_proxy ne "none"){ $ua->proxy('http', $http_proxy); } } else { $ua->env_proxy(); } ############################ ORANGE ######################################## # Written by Dan Kenigsberg and Nadav Har'El, with assistance of Elad Barkan sub sendsms_orange { my %args = @_; if($args{phonenum} !~ m/^0((5[45]|6[67])[0-9]{6}|54[0-9]{7})$/){ return 0; } # Orange.co.il does not support "sender". Let's just append it to # the message, in parantheses: if($args{sender} ne ""){ $args{message} = $args{message} . " (" . $args{sender} . ")" } # orange.co.il's form allows a maximum of 142 characters in an English # message, 49 in an Hebrew one. But this is just to make sure they can # stick their site name at the end. We can actually use more: 160 and # 70 respectively. # In the future, we might even want to put spaces at the end of the # message to make sure the "orange.co.il" advertisement doesn't fit :) # my $ishebrew=0; # if($opts{h} && ($args{message}=~ /[\200-\377]/)){ # $ishebrew=1; # if(length($args{message}) > 70){ # print STDERR "Warning: truncating Hebrew sender+". # "message at 70 characters...\n"; # $args{message}=substr($args{message},0,70); # } # $args{message}=encode("utf8", decode("iso-8859-8", $args{message})); # } else { # if(length($args{message}) > 160){ # print STDERR "Warning: truncating sender+message at ". # "160 characters...\n"; # $args{message}=substr($args{message},0,160); # } # } # Newlines in the message used to get ignored, and we needed to # change them into carriage-return-line-feed. This is no longer true. #$args{message} =~ s/\n/\r\n/g; my $res; my $base = "http://www.orange.co.il"; # check that we still have messages in our free quota. messages # beyond the first 20 per day cost money, and we wouldn't want that # to happen by accident! # Browse to the login page $req = new HTTP::Request GET => "$base/obox/Login.aspx?action=login"; $req->header('Accept' => 'text/html'); $ua->cookie_jar(HTTP::Cookies->new(hide_cookie2=>1)); $res = $ua->request($req); my ($viewstate, $eventvalidation, $session_details); # print $res->as_string. "\n"; if (($res->as_string) =~ m/__VIEWSTATE" value="([^"]*)"/) { $viewstate = URI::Escape::uri_escape($1); #print $viewstate,"\n"; } else { print STDERR "Error: unexpected response from Orange's site while logging in\n"; exit 11; } if (($res->as_string) =~ m/__EVENTVALIDATION" value="([^"]*)"/) { $eventvalidation = URI::Escape::uri_escape($1); } else { print STDERR "Error: unexpected response from Orange's site while logging in\n"; exit 11; } if (($res->as_string) =~ m/Session_Details" value="([^"]*)"/) { $session_details = URI::Escape::uri_escape($1); } else { print STDERR "Error: unexpected response from Orange's site while logging in\n"; exit 11; } # submit login form $req = new HTTP::Request POST => "$base/obox/Login.aspx?action=login"; $req->content_type('application/x-www-form-urlencoded'); $req->header('Accept' => '*/*'); $req->header('Referer' => 'http://www.orange.co.il/obox/Login.aspx?action=login'); $req->content("Session_Details=$session_details&__EVENTTARGET=ctl00%24ContentPlaceGlobal%24LoginBtn&__EVENTARGUMENT=&__VIEWSTATE=$viewstate&ctl00%24ContentPlaceGlobal%24txtUsername=".$args{user}."&ctl00%24ContentPlaceGlobal%24txtPassword=".$args{password}."&__EVENTVALIDATION=$eventvalidation"); $res = $ua->request($req); # print STDERR "-------- THE ERROR: --------\n". # $req->as_string. "\n". $res->as_string. "\n". # "----------------------------\n"; $req = new HTTP::Request GET => "$base/obox/sendsms.aspx"; $req->header('Accept' => 'text/html'); $res = $ua->request($req); if (($res->as_string) =~ m/__VIEWSTATE" value="([^"]*)"/) { $viewstate = URI::Escape::uri_escape($1); } else { print STDERR "Error: unexpected response from Orange's site on SMS form\n"; exit 11; } if (($res->as_string) =~ m/__EVENTVALIDATION" value="([^"]*)"/) { $eventvalidation = URI::Escape::uri_escape($1); } else { print STDERR "Error: unexpected response from Orange's site while logging in\n"; exit 11; } if (($res->as_string) =~ m/Session_Details" value="([^"]*)"/) { $session_details = URI::Escape::uri_escape($1); } else { print STDERR "Error: unexpected response from Orange's site while logging in\n"; exit 11; } if (($res->as_string) =~ m/lblBalance" class="MsgText"[^ ]* ([0-9]*)/) { my $freesmss=$1; #print "DDD $freesmss left\n"; if ($freesmss lt 1 && !$pay_orange) { print STDERR "Warning: depleted daily quota of free SMS. Sending may not be free.\n"; print STDERR "Not sending message, to avoid charge!\n"; print STDERR "\nYou can put 'pay_orange true' in ~/.sendsmsrc to avoid this test.\nUse at your own risk!\n"; exit 7; } } else { print STDERR "Error: unexpected response from Orange's site on SMS form\n"; exit 11; } # submit sms form $req = new HTTP::Request POST => "$base/obox/sendsms.aspx"; $req->content_type('application/x-www-form-urlencoded'); $req->header('Accept' => '*/*'); $req->content("Session_Details=$session_details&__EVENTTARGET=ctl00%24ContentPlaceGlobal%24SendBtn&". "__EVENTARGUMENT=&__VIEWSTATE=$viewstate&msisdn_list=". $args{phonenum}."&entity_list=&alias_list=orange&count_field=-1&". "TxtAreactl00_ContentPlaceGlobal_myInputText_InputText1=".uri_escape($args{message}, "^A-Za-z0-9"). "&__EVENTVALIDATION=$eventvalidation"); $res = $ua->request($req); # print STDERR "-------- THE ERROR: --------\n". # $req->as_string. "\n". $res->as_string. "\n". # "----------------------------\n"; ## Check if the sending succeeded if ($res->is_success) { if($res->content =~ m!הודעת SMS נשלחה בהצלחה למנוי orange!){ print STDERR "Sent successfully.\n"; } elsif($res->content =~ /location.href='.phone_book.'/){ print STDERR "Error: Could not send message, for ". " an unknown reason. Perhaps your acount was\n ". "not activated with an Orange phone number? Try ". "sending a message yourself\n using ". "http://orange.co.il\n"; exit 6; } else { # TODO: try to recover somehow maybe try to figure out # what went wrong by looking at $res->content. print STDERR "Error: unexpected response from Oranges's site\n"; print STDERR "-------- THE ERROR: --------\n". $req->as_string. "\n". $res->as_string. "\n". "----------------------------\n"; exit 6; } } else { # TODO: retry several times, sleeping between tries. print STDERR "Error sending message: " . $res->status_line . "\n"; #print STDERR "-------- THE ERROR: --------\n". # $res->content. "\n". # "----------------------------\n"; exit 5; } return 1; } my $keepalive=1; my $done = 0; my $offline_error = "You are offline. Connect first, please"; my $icq; if($n_account_icq>0){ $icq = Net::vICQ->new( $ICQ_USER, $ICQ_PASSWORD, "0"); } sub do_network { if($icq) { $icq->Execute_Once(); # $icq->{_Connected} or &disconnect; } } sub tick_handler { #print "tick_handler entry\n"; my $err; if($err = $icq->GetError()) { Error($err); return; } return unless $icq->{_LoggedIn}; alarm 1; unless($keepalive++ % 60) { $icq->Send_Keep_Alive(); } &do_network if $icq->{_Connected}; $done++; } sub sendsms_icq { my %args = @_; $SIG{INT} = \&disconnect; my $keepalive=1; my $tout=2; my $err; return 0 if($icq->{_Connected}); print "Trying to connect to ICQ network."; $icq->{_Auto_Login} = 1; $icq->Connect(); if(!($err = $icq->GetError())) { while(!$icq->{_LoggedIn} && !($err = $icq->GetError())) { $icq->Execute_Once(); } } if(!$err) { print "done!\n"; $SIG{ALRM} = \&tick_handler; alarm 1; } else { print "..failed!\n"; my $s=join("",$err); $s =~ s/\r\n/\n/g; print "\033M"; chomp($s); print "\n"; print "\033[2K"; print "$s\n"; return -1; } $icq->Add_Hook("Srv_Srv_Message", \&SrvMessage); my ($details); $details->{Status} = "Online"; $icq->Send_Command("Cmd_GSC_Set_Status", $details); $args{phonenum} =~ s/^0/+972/o; my $last_message_to = $args{phonenum}; my $text = $args{message}; $text .= "(".$args{sender}.")" if $args{sender} ne ""; my %details = ( SMS_Dest_Number => $args{phonenum}, MessageType => 'SMS', text => $text, delivery_receipt=>'Yes' ); return $offline_error unless $icq->{_Connected}; $icq->Send_Command("Cmd_Srv_Message", \%details); print "You sent SMS message to $args{phonenum}\n"; my $t = $keepalive; $icq->Execute_Once(); while($done<5&&$t+$tout > $keepalive){ # print "sleep\n"; sleep 3; } &disconnect; } sub SrvMessage { my($Object, $details) = @_; print "SrvMessage with MessageType: $details->{MessageType}\n"; if ($details->{MessageType} eq "sms_response") { &sms_response_handler($details); } if ($details->{MessageType} eq "sms_delivery_receipt") { &sms_delivery_receipt_handler($details); } } sub sms_response_handler { my $details = shift; my $data = ''; if($details->{deliverable} ne 'SMTP') { $data = "Response from SMS server:\n" . "Deliverable : $details->{deliverable}\n" . "Network : $details->{network}\n" . "MessageID : '$details->{message_id}'\n"; my $sender=$1 if $details->{message_id}=~/-(\d+)\s*$/; $sender ||="SMSC"; } else { $data = "Response from SMS server:\n" . "Deliverable : via SMTP\n" . "To : $details->{to}\n"; my $sender=$1 if $details->{message_id}=~/-(\d+)\s*$/; $sender ||="SMSC"; } print $data; } sub sms_delivery_receipt_handler { print "sms_delivery_receipt_handler\n"; my $details = shift; my $data = qq~ SMS delivery receipt Destination : $details->{destination} MessageId : $details->{message_id} Delivered : $details->{delivered} Submitted : $details->{submition_time} Delivered : $details->{delivery_time} ~; print $data; } sub disconnect { $icq->Disconnect(); print "Exiting..\n"; exit(0); } ############################################################################ if($phonenum =~ m/^0((5[238]|6[45])[0-9]{6}|52[0-9]{7})$/){ ############################ CELLCOM ####################################### if($n_account_icq>0){ sendsms_icq(sender => $sender, phonenum => $phonenum, message => $message, user => $ICQ_USER, password => $ICQ_PASSWORD); exit 0; } print STDERR "\nERROR: No ICQ SMS account defined in ". "your ~/.sendsmsrc!\nPlease see 'man sendsms' for ". "instructions.\n"; exit 1; ############################################################################ } elsif(defined $ORANGE_USER && defined $ORANGE_PASSWORD && sendsms_orange(sender => $sender, phonenum => $phonenum, message => $message, user => $ORANGE_USER, password => $ORANGE_PASSWORD)){ # ok ############################################################################ } elsif($phonenum =~ m/^0((5[45])[0-9]{6}|54[0-9]{7})$/){ ############################ ORANGE, Through ICQ ########################### if($n_account_icq>0){ sendsms_icq(sender => $sender, phonenum => $phonenum, message => $message, user => $ICQ_USER, password => $ICQ_PASSWORD); exit 0; } print STDERR "\nERROR: Can't send SMS to Orange because no Orange or ICQ account defined in ". "your ~/.sendsmsrc!\nPlease see 'man sendsms' for ". "instructions.\n"; exit 1; ############################################################################ } elsif($phonenum =~ m/^0((5[016]|68)[0-9]{6}|50[0-9]{7})$/){ ############################ PELEPHONE ##################################### if($n_account_icq>0){ sendsms_icq(sender => $sender, phonenum => $phonenum, message => $message, user => $ICQ_USER, password => $ICQ_PASSWORD); exit 0; } print STDERR "\nERROR: No ICQ SMS account defined in ". "your ~/.sendsmsrc!\nPlease see 'man sendsms' for ". "instructions.\n"; exit 1; ############################################################################ } elsif($phonenum =~ m/^057[0-9]{7}$/){ ############################## AMIGO ####################################### if($n_account_amigo==0){ print STDERR "\nERROR: No Amigo SMS account defined in ". "your ~/.sendsmsrc!\n\nPlease get a free account from:\n ". "http://www.amigo.co.il/html/login/new_user.asp\n". "and put in your ~/.sendsmsrc at least one line like:\n ". "account amigo EMAILADDRESS PASSWORD\n(filling in ". "EMAILADDRESS and PASSWORD, of course).\n"; exit 1; } my $res; my $cookie_jar = HTTP::Cookies->new; my $base = "http://www.amigo.co.il/html"; # If we get an HTTP error, we are going to retry 4 times with short # sleep intervals; since we expect the URLs to work, we'll retry # on any type of error - however strange. In the future, if the # retries don't help (e.g., in case of a longer-term problem), the # message should be queued for later delivery. my $ntries=0; while(1){ if($ntries>=4){ print STDERR "Failed $ntries login attempts - giving up.\n"; exit 3; last; # not reached }; # sleep a little until the next try sleep(30*$ntries*$ntries) if ($ntries>0); $ntries++; # Log in. We found the script we need to call, and the form parameters # we need to set, in the $base/login/login.asp page. $req = new HTTP::Request POST => "$base/login/check_login.asp"; $req->content_type('application/x-www-form-urlencoded'); $req->content("user_username=".uri_escape($AMIGO_USER, '^A-Za-z')."&". "user_psw=".uri_escape($AMIGO_PASSWORD, '^A-Za-z')); $req->header('Accept' => 'text/html'); $res = $ua->request($req); $cookie_jar->extract_cookies($res); # Successful login results in redirection to sending_frame.asp, and # with cookies (saved above) needed for the final, SMS sending form. if ($res->code==302 && $res->header('location') eq "../sending/sending_frame.asp") { if($ntries>1){ print STDERR "Success on attempt #$ntries\n"; } last; # stop retrying to log in } else { # If this is a known, permanent, error (e.g., wrong password), # then we exit. Otherwise we take this as a transient error # and try again. if($res->code==200){ if($res->as_string =~ /äæðú ðúåðéí ìà ðëåðéí ðñä ùåá/){ print STDERR "Failed login into Amigo: bad user/password.\n"; exit 1; } } print STDERR "Error: " . $res->status_line . "\n"; # go on to try again } } # now that we have session information (in cookie jar), send the # sms. my $mymessage=$message; # TODO: check if we need to change newlines, empty messages, or # fix other similar problems. # TODO: does Amigo support Hebrew? Do we need to do anything special # about it? $ntries=0; while(1){ if($ntries>=4){ print STDERR "Failed $ntries message sends - giving up.\n"; exit 5; last; # not reached }; # sleep a little until the next try sleep(30*$ntries*$ntries) if ($ntries>0); $ntries++; $req = new HTTP::Request POST => "$base/sending/sending.asp"; $req->content_type('application/x-www-form-urlencoded'); # NOTE: 1. we currently don't use Amigo's feature to send the same # message to up-to-6 phones. In the future, we can add such a # capability to sendsms, but it doesn't seem so important.. # 2. the phone_1...phone_6, redir and counter fields also present in # $base/sending/sending_form.asp are ignored. # TODO: what to do about sender num? Currently I send "123" :) $req->content("from=".uri_escape($sender, "^A-Za-z")."&". "sender_num=123&". "amigo1=57".uri_escape(substr($phonenum,3), "^0-9A-Za-z")."&". "amigo2=57&amigo3=57&amigo4=57&amigo5=57&amigo6=57&". "message=".uri_escape($mymessage, "^A-Za-z")); $req->header('Accept' => 'text/html'); $cookie_jar->add_cookie_header($req); $res = $ua->request($req); # just trying... # $req = new HTTP::Request GET => ("$base/sending/".$res->header('location')); # $cookie_jar->add_cookie_header($req); # $res = $ua->request($req); # print $res->as_string; if ($res->code==302 && $res->header('location') =~ /actions\.asp\?amigo1msg=1/) { print STDERR "Sent successfully.\n"; last; } else { # I don't know what this error means, or why it happens. # let's hope a retry will work... print STDERR "Sending the message failed with an unknown error... Retrying...\n"; next; } } ############################################################################ } else { print STDERR "Sorry, unrecognized cellphone number $phonenum.\n"; print STDERR "Currently, recognized numbers must begin with:\n"; print STDERR " Cellcom: 052, 053, 058, 064, or 065\n"; print STDERR " Orange: 054, 055, 066 or 067\n"; print STDERR " Pelephone: 050, 051, 056 or 068\n"; print STDERR " Amigo: 057\n"; print STDERR "followed by exactly 6 digits, or new-style numbers:\n"; print STDERR " 050, 052, 054 or 057 followed by 7 digits.\n"; print STDERR "Spaces and hyphens are ignored.\n"; exit 2; } sub sixtoseven { $_ = shift; s/-//g; s/^050/0505/; s/^051/0507/; s/^052/0522/; s/^053/0523/; s/^054/0544/; s/^055/0545/; s/^056/0506/; s/^057/0577/; s/^058/0528/; s/^059/0599/; s/^060/060/; s/^061/061/; s/^062/062/; s/^063/063/; s/^064/0524/; s/^065/0525/; s/^066/0546/; s/^067/0547/; s/^068/0508/; return $_ } 1;