summaryrefslogtreecommitdiffstats
path: root/scripts/sms.pl
diff options
context:
space:
mode:
Diffstat (limited to 'scripts/sms.pl')
-rw-r--r--scripts/sms.pl439
1 files changed, 439 insertions, 0 deletions
diff --git a/scripts/sms.pl b/scripts/sms.pl
new file mode 100644
index 0000000..14a4125
--- /dev/null
+++ b/scripts/sms.pl
@@ -0,0 +1,439 @@
+use strict;
+use Irssi 20020300;
+use 5.6.0;
+use Socket;
+use POSIX;
+
+use vars qw($VERSION %IRSSI %HELP);
+$HELP{sms} = "
+SMS <handle or phone number> <text>
+
+Sends sms to handle from addressbook (see HELP addsms and listsms)
+or phone number.
+";
+$HELP{addsms} = "
+ADDSMS <handle> <phone number>
+
+Adds 'handle' with phone 'phone number' to addressbook,
+or change phone number of existing handle.
+";
+$HELP{delsms} = "
+DELSMS <handle or number from listsms>
+
+Deletes entry from addressbook.
+";
+$HELP{listsms} = "
+LISTSMS [handle match]
+
+Lists addressbook.
+";
+$VERSION = "1.5b";
+%IRSSI = (
+ authors => "Maciek \'fahren\' Freudenheim",
+ contact => "fahren\@bochnia.pl",
+ name => "SMS",
+ description => "/ADDSMS, /DELSMS, /LISTSMS and /SMS - phone address-book with smssender, for now supports only Polish operators",
+ license => "GNU GPLv2 or later",
+ changed => "Fri Jan 10 03:54:07 CET 2003"
+);
+
+Irssi::theme_register([
+ 'sms_sending', '>> Sending SMS to %_$0%_ /$1/',
+ 'sms_sent', '>> Message to %_$0%_ has been sent.',
+ 'sms_esent', '>> Message $1/$2 to %_$0%_ has been sent.',
+ 'sms_notsent', '>> Message to %_$0%_ has %_NOT%_ been sent.',
+ 'sms_enotsent', '>> Message $1/$2 to %_$0%_ has %_NOT%_ been sent.',
+ 'sms_stat', '>> Total of %_$0%_ entries: %_$1%_ from PLUS, %_$2%_ from ERA, %_$3%_ from IDEA.',
+ 'sms_listline', '[%W$[!-2]0%n]%| $[9]1%_:%_ $2 /$[-4]3/',
+]);
+
+# Chanelog:
+## version 1.5b
+# $ENV{HOME}/.irssi -> Irssi::get_irssi_dir
+## version 1.5
+# - added new prefixes
+## version 1.4
+# - sorting /smslist
+# - do not lowercasing handles
+## version 1.3
+# - fixed smsfork(), ifork()
+# - added help
+## version 1.2d
+# - ... more ERA() fixes
+## version 1.2c
+# - added parsing of 'request cannot be processed at this time' in IDEA()
+# - added [act/total] in ERA() split messages
+## version 1.2b
+# - more fixes in ERA() messages spliting
+## version 1.2
+# - fixed long message spliting in ERA()
+## version 1.1
+# - fixed IDEA()
+# - inf. ifork() loop fixed (found by Lam)
+# - fixed regex matching in /delsms, /listsms and /sms
+# - changed kill() to POSIX::_exit()
+## version 1.0
+# - forking before sending SMS
+
+my $smssender = getlogin || getpwuid($<) || "anonymous";
+my $smsfile = Irssi::get_irssi_dir . "/smslist";
+my (@smslist, $fh, %ftag);
+
+sub cmd_sms {
+ my ($target, $text) = split(/ +/, $_[0], 2);
+ my $window = Irssi::active_win();
+ my $phone;
+
+ if ($text eq "") {
+ Irssi::print("Usage: /SMS <handle or phone number> <text>");
+ return;
+ }
+
+ if (isnumber($target)) {
+ if ($phone = corrnum($target)) {
+ my $net = smsnet($phone);
+ $window->printformat(MSGLEVEL_CLIENTNOTICE, 'sms_sending', smsnum($phone), $net);
+ &$net($phone, $text) unless &smsfork;
+ } else {
+ Irssi::print("%R>>%n Wrong number.");
+ }
+ } else {
+ my $i = 0;
+ my $handle = lc($target);
+ my $all = $handle eq "*"? 1 : 0;
+ for my $sms (@smslist) {
+ next unless ($all || lc($sms->{handle}) eq $handle);
+ $i++;
+ my $net = smsnet($sms->{phone});
+ $window->printformat(MSGLEVEL_CLIENTNOTICE, 'sms_sending', $sms->{handle}, $net);
+ &$net($sms->{phone}, $text) unless &smsfork;
+ }
+ Irssi::print("%R>>%n Can't find %_$target%_ in address book.") unless $i;
+ }
+}
+
+sub cmd_addsms {
+ my ($handle, $num) = split(/ +/, $_[0], 2);
+ my $phone;
+
+ unless ($phone = corrnum($num)) {
+ Irssi::print("Usage: /ADDSMS <handle> <phone number>");
+ return;
+ }
+
+ for my $sms (@smslist) {
+ if (lc($sms->{handle}) eq lc($handle)) {
+ Irssi::print(">> Changing phone number for %_$handle%_ /to $phone/");
+ $sms->{phone} = $phone;
+ &savesms;
+ return;
+ }
+ }
+ my $sms = {};
+ $sms->{handle} = $handle;
+ $sms->{phone} = $phone;
+ Irssi::print(">> Adding %_$handle%_ with num %_$phone%_.");
+ push @smslist, $sms;
+ &savesms;
+}
+
+sub cmd_delsms {
+ my $handle = shift;
+
+ if ($handle eq "") {
+ Irssi::print("Usage: /DELSMS <handle or number from listsms>");
+ return;
+ }
+
+ my @num;
+ $handle = lc($handle);
+
+ if ($handle =~ /^[0-9]+$/) {
+ push @num, $handle - 1;
+ } else {
+ my $all = $handle eq "*"? 1 : 0;
+ @smslist = sort { lc($a->{handle}) cmp lc($b->{handle}) } @smslist;
+ for (my $i = 0; $i < @smslist; $i++) {
+ push @num, $i if ($all || lc($smslist[$i]->{handle}) eq $handle);
+ }
+ }
+ for my $n (reverse(@num)) {
+ if (my($sms) = splice(@smslist, $n, 1)) {
+ Irssi::print(">> Deleted %_$sms->{handle}%_.");
+ }
+ }
+
+ &savesms;
+}
+
+sub cmd_listsms {
+ my $match = shift || "*";
+ my $window = Irssi::active_win();
+
+ if (@smslist == 0) {
+ Irssi::print("%R>>%n Your SMSLIST is empty.");
+ return;
+ }
+ my $all = $match eq "*"? 1 : 0;
+ @smslist = sort { lc($a->{handle}) cmp lc($b->{handle}) } @smslist;
+ my $i = 1;
+ for my $sms (@smslist) {
+ next unless $all || $sms->{handle} =~ /\Q$match\E/i;
+ $window->printformat(MSGLEVEL_CLIENTNOTICE, 'sms_listline', $i++, $sms->{handle}, $sms->{phone}, smsnet($sms->{phone}));
+ }
+ &smsstat if $match eq "*";
+}
+
+sub smsstat {
+ my ($plus, $era, $idea) = (0, 0, 0);
+
+ for my $sms (@smslist) {
+ for ($sms->{phone}) {
+ /^6(0[1,3,5,7,9]|91)/ and $plus++;
+ /^6(0[0,2,4,6,8]|92)/ and $era++;
+ /^50/ and $idea++;
+ }
+ }
+ Irssi::active_win()->printformat(MSGLEVEL_CLIENTNOTICE, 'sms_stat', scalar(@smslist), $plus, $era, $idea);
+}
+
+sub savesms {
+ local *fp;
+ open (fp, ">", $smsfile) or die "Couldn't open $smsfile for writing";
+ for my $sms (@smslist) {
+ print(fp "$sms->{handle} $sms->{phone}\n");
+ }
+ close(fp);
+}
+
+sub loadsms {
+ @smslist = ();
+ return unless (-e $smsfile);
+ local *fp;
+ open(fp, "<", $smsfile);
+ local $/ = "\n";
+ while (<fp>) {
+ chop;
+ my $sms = {};
+ ($sms->{handle}, $sms->{phone}) = split(/ /);
+ push(@smslist, $sms);
+ }
+ close(fp);
+ Irssi::print("Loaded address book:");
+ &smsstat;
+}
+
+sub isnumber {
+ return ($_[0] =~ /^([+]|[0-9])[0-9]{6,}$/);
+}
+
+sub corrnum {
+ my $num = shift;
+
+ return 0 unless isnumber($num);
+
+ if ($num =~ /^\+/) {
+ return 0 unless $num =~ s/^(\+48)//g;
+ }
+ $num =~ s/^(48)//;
+
+ return $num;
+}
+
+sub smsnum {
+ my $num = shift;
+ for my $sms (@smslist) {
+ if ($sms->{phone} eq $num) {
+ return $sms->{handle}
+ }
+ }
+ return $num;
+}
+
+sub smsnet {
+ for (@_) {
+ /^6(0[13579]|9[135])/ and return "PLUS";
+ /^6(0[02468]|9[24])/ and return "ERA";
+ /^50/ and return "IDEA";
+ }
+ return "UNKNOWN";
+}
+
+sub urlencode {
+ my $ret = shift;
+ $ret =~ s/([^a-zA-Z0-9])/sprintf("%%%.2x", ord($1));/eg;
+ return $ret;
+}
+
+sub smsfork {
+ my ($rh, $wh);
+ pipe($rh, $wh);
+ my $pid = fork();
+ unless (defined $pid) {
+ Irssi::print("%R>>%n Failed to fork() :/ - $!");
+ close $rh; close $wh;
+ return 1;
+ } elsif ($pid) { # parent
+ close $wh;
+ $ftag{$rh} = Irssi::input_add(fileno($rh), INPUT_READ, \&ifork, $rh);
+ Irssi::pidwait_add($pid);
+ } else { # child
+ close $rh;
+ $fh = $wh;
+ }
+ return $pid;
+}
+
+sub smskill {
+ print($fh "finished\n");
+ close $fh;
+ POSIX::_exit(1);
+}
+
+sub ifork {
+ my $rh= shift;
+ my $ret = 0;
+ while (<$rh>) {
+ /^sent (.+)/ and Irssi::active_win()->printformat(MSGLEVEL_CLIENTNOTICE, 'sms_sent', smsnum($1)), last;
+ /^esent ([0-9]+)\s([0-9]+)\s([0-9]+)$/ and Irssi::active_win()->printformat(MSGLEVEL_CLIENTNOTICE, 'sms_esent', smsnum($1), $2, $3), last;
+ /^notsent (.+)/ and Irssi::active_win()->printformat(MSGLEVEL_CLIENTNOTICE, 'sms_notsent', smsnum($1)), last;
+ /^enotsent ([0-9]+)\s([0-9]+)\s([0-9]+)$/ and Irssi::active_win()->printformat(MSGLEVEL_CLIENTNOTICE, 'sms_enotsent', smsnum($1), $2, $3), last;
+ /^info (.+)/ and Irssi::print("$1"), last;
+ /^finished$/ and $ret = 1, last;
+ }
+ return unless $ret;
+ Irssi::input_remove($ftag{$rh});
+ delete $ftag{$rh};
+ close $rh;
+}
+
+sub sconnect {
+ my $target = shift;
+ my ($proto, $iaddr, $saddr);
+
+ $proto = getprotobyname('tcp');
+ $iaddr = inet_aton($target);
+ socket(SOCK, PF_INET, SOCK_STREAM, $proto) || return 0;
+ local $SIG{ALRM} = sub {
+ print($fh "info %R>>%n connect() to $target timeouted :/\n");
+ close SOCK;
+ return 0;
+ };
+ alarm 10;
+ unless (connect(SOCK, sockaddr_in(80, $iaddr))) {
+ print($fh "info %R>>%n Couldn't connect to $target: $!\n");
+ close SOCK;
+ return 0;
+ }
+ alarm 0;
+ my $old = select(SOCK); $| = 1; select($old);
+ return 1;
+}
+
+sub PLUS {
+ my ($phone, $text) = @_;
+ &smskill unless sconnect("sms.plusgsm.pl");
+ my $tosend = "tprefix=" . substr($phone, 0, 3) . "&numer=" . substr($phone, 3) . "&odkogo=$smssender&tekst=" . urlencode($text) . "&dzien=dzisiaj&godz=&min=";
+ print SOCK "POST /sms/sendsms.php HTTP/1.0\n";
+ print SOCK "Host: www.text.plusgsm.pl:80\n";
+ print SOCK "Accept: */*\n";
+ print SOCK "Content-type: application/x-www-form-urlencoded\n";
+ print SOCK "Content-length: " . length($tosend) . "\n\n";
+ print SOCK "$tosend\r\n";
+ while (<SOCK>) {
+ /wiadomość została wysłana/ and print($fh "sent $phone\n"), last;
+ /nie został wysłany/ and print($fh "notsent $phone\n"), last;
+ }
+ close SOCK;
+ &smskill;
+}
+
+sub ERA {
+ my ($phone, $cutme) = @_;
+ my $ml = 126 - length($smssender);
+ my $cl = length($cutme);
+ my $total = int($cl / $ml) + (($cl%$ml)? 1 : 0);
+ if ($total > 1) {
+ $ml -= (4 + length($total) * 2);
+ $total = int($cl / $ml) + (($cl%$ml)? 1 : 0);
+ printf($fh "info >> Spliting SMS to $total messages.\n");
+ }
+ my $act = 0;
+ while ($cutme =~ s/.{1,$ml}//) {
+ my ($cookie, $code, $tosend, $text);
+ &smskill unless sconnect("boa.eragsm.pl");
+ $act++;
+ $text = "<$act/$total> " if $total > 1;
+ $text .= $&;
+ print SOCK "POST /sms/sendsms.asp?sms=1 HTTP/1.0\n";
+ print SOCK "Host: boa.eragsm.com.pl:80\n";
+ print SOCK "Accept: */*\n\r\n";
+ while (<SOCK>) {
+ $cookie = $1 if /Set\-Cookie\:\ ([^\;]+?)\;/;
+ $code = $1 if /name\=\"Code\"\ value\=\"(.+?)\"/;
+ }
+ close SOCK;
+ $tosend = "numer=$phone&bookopen=&message=" . urlencode($text) . "&podpis=$smssender&kontakt=&Nadaj=Nadaj&code=$code&Kasuj=Kasuj&Telefony=Telefony";
+ &smskill unless sconnect("boa.eragsm.pl");
+ print SOCK "POST /sms/sendsms.asp HTTP/1.0\n";
+ print SOCK "Host: boa.eragsm.com.pl:80\n";
+ print SOCK "Accept: */*\n";
+ print SOCK "Cookie: $cookie\n";
+ print SOCK "Referer: http://boa.eragsm.com.pl/sms/sendsms.asp\n";
+ print SOCK "Content-type: application/x-www-form-urlencoded\n";
+ print SOCK "Content-length: " . length($tosend) . "\n\n";
+ print SOCK "$tosend\r\n";
+ if ($total > 1) {
+ while (<SOCK>) {
+ /nie została wysłana!/ and print($fh "enotsent $phone $act $total\n"), last;
+ /została wysłana/ and print($fh "esent $phone $act $total\n"), last;
+ }
+ } else {
+ while (<SOCK>) {
+ /nie została wysłana!/ and print($fh "notsent $phone\n"), last;
+ /została wysłana/ and print($fh "sent $phone\n"), last;
+ }
+ }
+ close SOCK;
+ }
+ &smskill;
+}
+
+sub IDEA {
+ my ($phone, $text) = @_;
+ my ($sec, $min, $hour, $day, $mon, $year) = (localtime)[0,1,2,3,4,5];
+ $year += 1900;
+ $mon += 1;
+ &smskill unless sconnect("sms.idea.pl");
+ my $tosend = "LANGUAGE=pl&NETWORK=smsc1&DELIVERY_TIME=0&SENDER=$smssender&RECIPIENT=$phone&VALIDITY_PERIOD=24&DELIVERY_DATE=$day&DELIVERY_MONTH=$mon&DELIVERY_YEAR=$year&DELIVERY_HOUR=$hour&DELIVERY_MIN=$min&NOTIFICATION_FLAG=false&NOTIFICATION_ADDRESS=&SHORT_MESSAGE=" . urlencode($text) . "&SUBMIT=Wyslij";
+ print SOCK "POST /sendsms.asp HTTP/1.0\n";
+ print SOCK "Host: sms.idea.pl:80\n";
+ print SOCK "Accept: */*\n";
+ print SOCK "Content-type: application/x-www-form-urlencoded\n";
+ print SOCK "Content-length: " . length($tosend) . "\n\n";
+ print SOCK "$tosend\r\n";
+ while (<SOCK>) {
+ /SMS nie zostanie/ and print($fh "notsent $phone\n"), last;
+ /doby został wyczerpany/ and print($fh "notsent $phone\n"), last;
+ /została wysłana/ and print($fh "sent $phone\n"), last;
+ /request cannot be processed/ and print($fh "notsent $phone\n"), last;
+ }
+ close SOCK;
+ &smskill;
+}
+
+sub UNKNOWN {
+ print($fh "info %R>>%n Sorry, sms.pl supports only polish operators :/\n");
+ &smskill;
+}
+
+&loadsms;
+
+Irssi::command_bind("sms", "cmd_sms");
+Irssi::command_bind("addsms", "cmd_addsms");
+Irssi::command_bind("smsadd", "cmd_addsms");
+Irssi::command_bind("smsdel", "cmd_delsms");
+Irssi::command_bind("delsms", "cmd_delsms");
+Irssi::command_bind("listsms", "cmd_listsms");
+Irssi::command_bind("smslist", "cmd_listsms");
+Irssi::command_bind("smsstat", "smsstat");