From 76064f46232b9dc64da861dccf320be855fdd22c Mon Sep 17 00:00:00 2001 From: Joshua Ferraro Date: Mon, 29 Oct 2007 21:13:49 -0500 Subject: [PATCH] adding SMS stuff so we don't forget about it Signed-off-by: Chris Cormack Signed-off-by: Joshua Ferraro --- C4/SMS.pm | 149 ++++++++ .../prog/en/modules/sms/sms-home.tmpl | 40 ++ misc/cronjobs/smsoverdues.pl | 351 ++++++++++++++++++ sms/sms.pl | 43 +++ sms/sms_listen.pl | 131 +++++++ sms/sms_listen_windows_start.pl | 16 + 6 files changed, 730 insertions(+) create mode 100644 C4/SMS.pm create mode 100644 koha-tmpl/intranet-tmpl/prog/en/modules/sms/sms-home.tmpl create mode 100755 misc/cronjobs/smsoverdues.pl create mode 100755 sms/sms.pl create mode 100755 sms/sms_listen.pl create mode 100755 sms/sms_listen_windows_start.pl diff --git a/C4/SMS.pm b/C4/SMS.pm new file mode 100644 index 0000000000..319ac33ff4 --- /dev/null +++ b/C4/SMS.pm @@ -0,0 +1,149 @@ +package C4::SMS; +#Written by tgarip@neu.edu.tr for SMS message sending and other SMS related services + +use strict; +require Exporter; +use LWP::UserAgent; +use C4::Context; +use vars qw($VERSION @ISA @EXPORT); +$VERSION = 0.01; +my $user=C4::Context->config('smsuser'); +my $pwd=C4::Context->config('smspass'); +my $uri ="https://spgw.kktcell.com/smshttpproxy/SmsHttpProxyServlet"; + + + +@ISA = qw(Exporter); + +@EXPORT = qw( +&get_sms_auth +&send_sms +&read_sms +&error_codes +&parse_phone +&parse_message +&write_sms +&mod_sms +&kill_sms +); + +sub get_sms_auth { + my $ua = LWP::UserAgent->new; +my $commands; + my $res=$ua->post($uri,[cmd=>'REGISTER',pUser=>$user,pPwd=>$pwd]); + if ($res->is_success){ + $commands=parse_content($res->content); + } +return($commands,$ua); +} + +sub send_sms{ +my $ua=shift; +my $phone=shift; +my $message=shift; +my $session=shift; + my $res=$ua->post($uri,[cmd=>'SENDSMS',pUser=>$user,pPwd=>$pwd,pSessionId=>$session,pService_Code=>4130,pMsisdn=>$phone, + pContent=>$message]); +return parse_content($res->content); +} +sub read_sms{ +my $ua=shift; +my $session=shift; + my $res=$ua->post($uri,[cmd=>'GETSMS',pUser=>$user,pPwd=>$pwd,pSessionId=>$session,pService_Code=>4130]); +return parse_content($res->content); +} +sub parse_content{ +my $content=shift; +my %commands; +my @attributes=split /&/,$content; + foreach my $params(@attributes){ + my (@param)=split /=/,$params; + $commands{$param[0]}=$param[1]; + } +return(\%commands); +} + +sub error_codes{ +my $error=shift; +if ($error==-1){ +return "Closed session - Retry "; +}elsif($error==-2){ +return "Invalid session - Retry "; +}elsif($error==-3){ +return "Invalid password" ; +}elsif($error==-103){ +return "Invalid user"; +}elsif($error==-422){ +return "Invalid Parameter"; +}elsif($error==-426){ +return "User doesn’t have permission to send message"; +}elsif($error==-700){ +return "No permission"; +}elsif($error==-801){ +return " Msdisn count differs-warn administartor"; +}elsif($error==-803){ +return "Content count differs from XSER count"; +}elsif($error==-1101){ +return " Insufficient Credit Do not retry" ; +}elsif($error==-1104){ +return "Invalid Phone number"; +}elsif($error==-10001){ +return " Internal system error- Tell Turkcell/Telsim"; +}elsif($error==-9005){ +return " No messages to read"; +}elsif ($error){ +return "Unknow error no $error occured - tell Turkcell/Telsim"; +} +} + +sub parse_phone{ +## checks acceptable phone numbers +## Fix to accept Telsim when available (542 numbers) +my $phone=shift; +$phone=~s/^0//g; +$phone=~s/ //g; +my $length=length($phone); +if ($length==10 || $length==12){ +my $code=substr($phone,0,3) if $length==10; + $code=substr($phone,0,5) if $length==12; + if ($code=~/533/){ + return $phone; + }else{ + return 0; + } +}else{ +return 0; +} +} + +sub parse_message{ +my $message=shift; +$message=~s/ / /g; +my @parsed=split / /,$message; +return (@parsed); +} + +sub write_sms{ +my ($userid,$message,$phone)=@_; +my $dbh=C4::Context->dbh; +my $sth=$dbh->prepare("INSERT into sms_messages(userid,message,user_phone,date_received) values(?,?,?,now())"); +$sth->execute($userid,$message,$phone); +$sth->finish; +return $dbh->{'mysql_insertid'}; +} + +sub mod_sms{ +my ($smsid,$message)=@_; +my $dbh=C4::Context->dbh; +my $sth=$dbh->prepare("UPDATE sms_messages set reply=? ,date_replied=now() where smsid=?"); +$sth->execute($message,$smsid); +$sth->finish; +} +sub kill_sms{ +#end a session +my $ua=shift; +my $session=shift; + my $res=$ua->post($uri,[cmd=>'KILLSESSION',pSessionId=>$session]); +} +1; +__END__ \ No newline at end of file diff --git a/koha-tmpl/intranet-tmpl/prog/en/modules/sms/sms-home.tmpl b/koha-tmpl/intranet-tmpl/prog/en/modules/sms/sms-home.tmpl new file mode 100644 index 0000000000..0c1d93d63d --- /dev/null +++ b/koha-tmpl/intranet-tmpl/prog/en/modules/sms/sms-home.tmpl @@ -0,0 +1,40 @@ + +SMS Administration + + + + + +
+ +
+
+
+

NEULIS SMS Administration

+ + + + +
+ + + + + + + + + + + + + + +
SMS Messaging
Your Message
Phone:"/>5338644143 + +
Şu anda sadece KTcell abonelerine mesaj gönderilebilir. Rezervasyonu gelenler için kullanın!
+
+
+
+ + diff --git a/misc/cronjobs/smsoverdues.pl b/misc/cronjobs/smsoverdues.pl new file mode 100755 index 0000000000..5f930625bd --- /dev/null +++ b/misc/cronjobs/smsoverdues.pl @@ -0,0 +1,351 @@ +#!/usr/bin/perl + +# This script loops through each overdue item, determines the fine, +# and updates the total amount of fines due by each user. It relies on +# the existence of /tmp/fines, which is created by ??? +# Doesnt really rely on it, it relys on being able to write to /tmp/ +# It creates the fines file +# +# This script is meant to be run nightly out of cron. + +# Copyright 2000-2002 Katipo Communications +# +# This file is part of Koha. +# +# Koha is free software; you can redistribute it and/or modify it under the +# terms of the GNU General Public License as published by the Free Software +# Foundation; either version 2 of the License, or (at your option) any later +# version. +# +# Koha is distributed in the hope that it will be useful, but WITHOUT ANY +# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR +# A PARTICULAR PURPOSE. See the GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along with +# Koha; if not, write to the Free Software Foundation, Inc., 59 Temple Place, +# Suite 330, Boston, MA 02111-1307 USA + +# $Id: sendoverdues.pl,v 1.1.2.1 2007/03/26 22:38:09 tgarip1957 Exp $ + +use C4::Context; +use C4::Search; +use C4::Circulation; +use C4::Circulation::Fines; +use C4::Members; +use C4::Date; +use HTML::Template::Pro; +use Mail::Sendmail; +use Mail::RFC822::Address; +use C4::SMS; +use utf8; +my ($res,$ua);##variables for SMS + +my $date=get_today(); + my $dbh = C4::Context->dbh; + + + +notifyOverdues(); + +sub notifyOverdues { + # Look up the overdues for today. + # Capture overdues which fall on our dates of interest. + +#################################################################################################### +# Creating a big hash of available templates +my %email; +%email->{'template'}='email-2.txt'; +my %sms; +%sms->{'template'}='sms-2.txt'; + + +my %firstReminder->{'email'} = \%email; +%firstReminder->{'sms'} = \%sms; + +my %email2; +%email2->{'template'}='email-7.txt'; +my %secondReminder->{'email'} = \%email2; +my %sms2; +%sms2->{'template'}='sms-7.txt'; +%secondReminder->{'sms'} = \%sms2; +my %letter2; +%letter2->{'template'}='letter-7.html'; +%secondReminder->{'letter'} = \%letter2; + + +my %email3; +%email3->{'template'}='email-29.txt'; +my %sms3; +%sms3->{'template'}='sms-29.txt'; +my %letter3; +%letter3->{'template'}='letter-29.html'; + +my %finalReminder->{'email'} = \%email3; +%finalReminder->{'letter'} = \%letter3; +%finalReminder->{'sms'} = \%sms3; + +my %actions; +%actions->{'1'}=\%firstReminder; +%actions->{'3'}=\%secondReminder;###This was 7 days changed to 3 days +%actions->{'20'}=\%finalReminder;###This was 29 days changed to 20 days + +################################################################################################################## +my @overdues2;#an array for each actiondate +my @overdues7; +my @overdues29; +my $filename; + + + + # Retrieve an array of overdues. + my ($count, $overduesReference) = Getoverdues(); + my @overdues=@$overduesReference; + + + # We're going to build a hash of arrays, containing the items requiring action. + # ->borrowernumber, date, @overdues + my %actionItems; + + + foreach my $overdue (@overdues) { + my $due_day=$overdue->{'date_due'}; + + my $difference=DATE_subtract($date,$due_day); + # If does this item fall on a day of interest? + $overdue->{'difference'}=$difference; + foreach my $actiondate (keys(%actions)) { + if ($actiondate == $difference) { + $filename='overdues'.$actiondate; + push @$$filename,$overdue; +#print "$actiondate,-,$overdue->{borrowernumber}\n"; + } + $actionItems{$actiondate} = \@$$filename; + } + } + + # We now have a hash containing overdues which need actioning, we can step through each set. + # Work from earilest to latest. We only wish to send the most urgent message. + my %messages; + my %borritem; + + foreach my $actiondate (keys %actions) { +# print "\n\nThe following items are $actiondate days overdue.\n"; + my $items = $actionItems{$actiondate}; + $filename='overdues'.$actiondate; + foreach my $overdue (@$$filename) { + # Detemine which borrower is responsible for this overdue; + # if the offender is a child, then the guarantor is the person to notify + my $borrowernumber=$overdue->{borrowernumber}; + + my $borrower=responsibleBorrower($borrowernumber); + my ($method, $address) = preferedContactMethod($borrower); + if ($method && $address) { + + # Do we have to send something, using this method on this day? + if (%actions->{$actiondate}->{$method}->{'template'}) { + my $intranetdir=C4::Context->config('intranetdir'); + # Template the message + my $template = HTML::Template::Pro->new(filename => $intranetdir.'/scripts/misc/notifys/templates/'.%actions->{$actiondate}->{$method}->{'template'}, die_on_bad_params => 0); + my @bookdetails; + my %row_data; + my $item = getiteminformation("", $overdue->{'itemnumber'}); + $row_data{'BARCODE'}=$item->{'barcode'}; + + my $title=substr($item->{'title'},0,25)."..."; + + $title=changecharacter($title); + $row_data{'TITLE'}=$title; + $row_data{'DATE_DUE'}=format_date($overdue->{'date_due'}); + $row_data{'cardnumber'}=$borrower->{'cardnumber'}; + push(@bookdetails, \%row_data); + $template->param(BOOKDETAILS => \@bookdetails); + my $name= "$borrower->{'firstname'} $borrower->{'surname'}"; + $template->param(NAME=> $name); + %messages->{$borrower->{'borrowernumber'}} = $template->output(); + if ($method eq 'email') { + $result = sendEmail($address, 'library@library.neu.edu.tr', 'Overdue Library Items', %messages->{$borrowernumber}); + logContact($borrowernumber, $method, $address, $result, %messages->{$borrowernumber}); + } + elsif ($method eq 'sms') { + $result = sendSMS($address, %messages->{$borrowernumber}); + logContact($borrowernumber, $method, $address, $result, %messages->{$borrowernumber}); + } + elsif ($method eq 'letter') { + $result = printLetter($address, %messages->{$borrowernumber}); + } + }##template exists + }else{ + print "$borrowernumber has an overdue item, but no means of contact\n"; + }##$method + + + } #end of 'foreach overdue' + + } # end of foreach actiondate +} + +sub responsibleBorrower { + # Given an overdue item, return the details of the borrower responible as a hash of database columns. + my $borrowernumber=shift; + + if ($borrowernumber) { + my $borrower=BorType($borrowernumber); + # Overdue books assigned to children have notices sent to the guarantor. + if ($borrower->{'categorycode'} eq 'C') { + my $guarantor=BorType($borrower->{'guarantor'}); + $borrower = $guarantor; + } + + return $borrower; + } + +} + + + + + + + + + +sub preferedContactMethod { + # Given a reference to borrower details, in the format + # returned by BorType(), determine the prefered contact method, and address to use. + my $borrower=$_[0]; + my $borrcat = getborrowercategoryinfo($borrower->{'categorycode'}); +if( !$borrcat->{'overduenoticerequired'}){ +return (undef,undef); +} + my $method=''; + my $address=''; +## if borrower has a phone set that as our preferrred contact + if ($borrower->{'phoneday'}) { + if (parse_phone($borrower->{phoneday})){ + $address = parse_phone($borrower->{phoneday}); + $method="sms"; + return ($method, $address); + } + } + + if (($borrower->{'emailaddress'}) and (Mail::RFC822::Address::valid($borrower->{'emailaddress'}))) { + $address = $borrower->{'emailaddress'}; + $method="email"; + return ($method, $address); + } + + if ($borrower->{'streetaddress'}) { + $address = mailingAddress($borrower); + $method = 'letter'; + } +#print "$method, $address\n"; + return ($method, $address); +} + + + + + + + + +sub logContact { + # Given the details of an attempt to contact a borrower, + # log them in the attempted_contacts table of the koha database. + my ($borrowernumber, $method, $address, $result, $message) = @_; + + my $querystring = " insert into attempted_contacts + (borrowernumber, method, address, result, message, date) + values (?, ?, ?, ?, ?, now())"; + my $sth= $dbh->prepare($querystring); + $sth->execute($borrowernumber, $method, $address, $result, $message); + $sth->finish(); +} + + + + + + + + +sub mailingAddress { + # Given a hash of borrower information, such as that returned by BorType, + # return a mailing address. + my $borrower=$_[0]; + + my $address = $borrower->{'firstname'}."\n". + $borrower->{'streetaddress'}."\n". + $borrower->{'streetcity'}; + + return $address; +} + + + +sub sendEmail { + # Given an email address, and a subject and message, attempt to send email. + + my $to=$_[0]; + my $from=$_[1]; + my $subject=$_[2]; + my $message=$_[3]; +# print "in email area"; + +# print "\nSending Email To: $to\n$message\n"; + + my %mail = ( To => $to, + CC => 'library@library.neu.edu.tr', + From => $from, + Subject => $subject, + Message => $message); + + + if (not(sendmail %mail)) { +warn $Mail::Sendmail::error; + warn "sendEmail to $to failed."; + return 0; + } + + return 1; +} + + +sub sendSMS { +my ($phone, $message)=@_; +($res,$ua)=get_sms_auth() unless $res; + # Given a cell number and a message, attempt to send an SMS message. +my $sendresult=send_sms($ua,$phone,$message,$res->{pSessionId}); + my $error=error_codes($sendresult->{pErrCode}); + return 1 unless $error; + return $error; +} + + +sub printLetter { +print "letter\n"; + # Print a letter + # FIXME - decide where to print + return 1; +} +sub changecharacter { +my ($string)=@_; +$_=$string; + +s/ş/s/g; +s/Ş/S/g; +s/ü/u/g; +s/Ü/U/g; +s/ç/c/g; +s/Ç/C/g; +s/ö/o/g; +s/Ö/O/g; +s/ı/i/g; +s/İ/I/g; +s/ğ/g/g; +s/Ğ/G/g; +$string=$_; +return $string; +} +$dbh->disconnect(); + diff --git a/sms/sms.pl b/sms/sms.pl new file mode 100755 index 0000000000..72edda0a15 --- /dev/null +++ b/sms/sms.pl @@ -0,0 +1,43 @@ +#!/usr/bin/perl + +use strict; +use CGI; +use C4::SMS; +use C4::Output; +use C4::Auth; +my ($res,$ua); +my %commands; +my $query = new CGI; +my $message=$query->param('message'); +my $phone=$query->param('phone'); +my $operation=$query->param('operation'); +my $result; +my $errorcode; +my ($template, $loggedinuser, $cookie) + = get_template_and_user({template_name => "sms/sms-home.tmpl", + query => $query, + type => "intranet", + authnotrequired => 0, + flagsrequired => {circulate => 1}, + debug => 1, + }); +if ($operation eq"sendsms"){ + $phone=parse_phone($phone); + if ($phone>0){ +##write to a queue and exit +my $me=C4::Context->userenv; +my $card=$me->{cardnumber}; + $result=write_sms($card,$message,$phone); + + }else{ + $errorcode=-1104; + } +} +my $error=error_codes($errorcode); +$template->param(error=>$error); +output_html_with_http_headers $query, $cookie, $template->output; + + + + + diff --git a/sms/sms_listen.pl b/sms/sms_listen.pl new file mode 100755 index 0000000000..08c28c85fb --- /dev/null +++ b/sms/sms_listen.pl @@ -0,0 +1,131 @@ +#!/usr/bin/perl + +use strict; +use C4::SMS; +use C4::Auth; +use C4::Context; +use C4::Members; +use C4::Circulation; +my ($res,$ua); +my %commands; +my $message; +my $phone; +my $result; +my $errorcode; +my $smsid; +my $wait=600;## 10 mn. wait between sms checking +my $dbh=C4::Context->dbh; + +STARTAGAIN: +($res,$ua)=get_sms_auth(); +AGAIN: +$errorcode=0; + if ($res->{pRetCode}==200){ + $result=read_sms($ua,$res->{pSessionId}); + $errorcode=$result->{pErrCode}; +print "connected\n"; + }else{ + kill_sms($ua,$res->{pSessionId}); + warn (error_codes($res->{pErrCode}),$res->{pErrcode}) ; +# sleep $wait; + goto FINISH; + + } +if ($errorcode && $errorcode !=-9005){ +kill_sms($ua,$res->{pSessionId}); +warn error_codes($errorcode) ; +# sleep $wait; +goto FINISH; + +}elsif ($errorcode ==-9005){ +print "no more messages to read\n"; +goto WAITING; +} +#Parse the message to a useful hash +my @action=parse_message( $result->{pContent}); +## Log the request in our database; + $smsid=write_sms($action[1], $result->{pContent},$result->{pMsisdn}); +print "message logged\n"; +##Now do the service required +if (uc($action[0]) eq "RN"){ +print "dealing request\n"; +my ($ok,$cardnumber)=C4::Auth::checkpw($dbh,$action[1],$action[2]); + if($ok){ + my $item=getiteminformation(undef,0,$action[3]); + if ($item){ + my $borrower=getmember($cardnumber); + my $status=renewstatus(undef,$borrower->{borrowernumber},$item->{itemnumber}); + if ($status==1){ + my $date=renewbook(undef,$borrower->{borrowernumber},$item->{itemnumber}); + $message="Uzatildi :Renewed ".$item->{barcode}." : ".$date; + my $send=send_message($result,$message,$smsid); + }elsif($status==2){ + $message="Cok erken- yenilenmedi! :Too early-not renewed:".$item->{barcode}; + my $send=send_message($result,$message,$smsid); + }elsif($status==3){ + $message="Uzatamazsiniz GERI getiriniz! :No more renewals RETURN the item:".$item->{barcode}; + my $send=send_message($result,$message,$smsid); + }elsif($status==4){ + $message="Ayirtildi GERI getiriniz! :Reserved RETURN the item:".$item->{barcode}; + my $send=send_message($result,$message,$smsid); + }elsif($status==0){ + $message="Uzatilamaz! :Can not renew:".$item->{barcode}; + my $send=send_message($result,$message,$smsid); + } + }else{ + $message="Yanlis barkot! :Wrong barcode!"; + my $send=send_message($result,$message,$smsid); + }#wrong barcode + }else{ + $message="Yanlis kullanici/sifre! :Wrong username/password!"; + my $send=send_message($result,$message,$smsid); + }##wrong user/pass +}else{ +## reply about error +$message="Yanlis mesaj formati! :Wrong message! : + RN usercardno password barcode"; +my $send=send_message($result,$message,$smsid); +}### wrong service + +goto AGAIN; + + + + +WAITING: +##Now send the messages waiting in queue +my $smssth=$dbh->prepare("SELECT smsid,user_phone,message from sms_messages where date_replied like '0000-00-00%' "); +$smssth->execute(); +my @phones; +while (my $data=$smssth->fetchrow_hashref){ +push @phones,$data; +} +$smssth->finish; + +foreach my $user(@phones){ +print "replying $user->{user_phone}"; +my $send=send_sms($ua,$user->{user_phone},$user->{message},$res->{pSessionId}); +my $reply="--failed\n"; + if ($send->{pRetCode}==200){ +$reply= "--replied\n"; + mod_sms($user->{smsid},"Sent"); + } +print $reply; +} +$dbh->disconnect; + + +sub send_message{ +my ($mes,$message,$smsid)=@_; +my $send=send_sms($ua,$mes->{pMsisdn},$message,$res->{pSessionId}); + if ($send->{pRetCode}==200){ + mod_sms($smsid,$message); + }else{ + my $error=error_codes($send->{pErrCode}); + mod_sms($smsid,"Not replied error:".$error); + } +return $send; +} +FINISH: +1; +__END__ diff --git a/sms/sms_listen_windows_start.pl b/sms/sms_listen_windows_start.pl new file mode 100755 index 0000000000..a6d42fcc4b --- /dev/null +++ b/sms/sms_listen_windows_start.pl @@ -0,0 +1,16 @@ +#!/usr/bin/perl +# script that starts the zebraquee +# Written by TG on 01/08/2006 +use strict; + +use Win32::Process; +use Win32; +use C4::Context; +use CGI; +my $input=new CGI; +my $fileplace=C4::Context->config('intranetdir'); +my $fullpath=$fileplace."/cgi-bin/sms"; +my $ZebraObj; + my $pid=Win32::Process::Create($ZebraObj, "C:/perl/bin/perl.exe",'perl sms_listen.pl', 0, DETACHED_PROCESS,$fullpath) ; + +print $input->redirect("/cgi-bin/koha/mainpage.pl?pid=$pid"); -- 2.39.5