#!/usr/bin/perl # # Srijith K. Nair (http://srijith.net) # # Perl script to send expense to Clearcheckbook's GMail/XMPP Bot # Now with offline support! # # Note that this does not support transactions like 'bal' which requires # a reply from the Bot since the Net::XMPP::Client->MessageSend doesn't # seem to handle responses! # # Copyright: Perl Artistic License 2.0 # http://www.opensource.org/licenses/artistic-license-2.0.php # # Version : 1.0 # Release : 06-Nov-2007 use strict; use Net::XMPP; use Getopt::Std; ############## Configuration #################### my $username = ""; # don't add 'gmail.com' my $password = ""; my $offlineFile = '/home/username/.offline-b4b'; my $componentname = 'gmail.com'; my $to = "clearcheckbot"; my $resource = "Bot4Bot"; my $DEBUG = 0; my $XMPP_DEBUG = 0; ############ End of configuration ################# my %options=(); getopts("osh",\%options); my $msg = $ARGV[0]; if($options{'h'}) { &usage(); exit(0); }elsif (($msg eq "") and !($options{'s'})) { print "Wrong input\n\n"; &usage(); exit(0); } if ($options{'o'} and $options{'s'}) { print "You cannot set both 'offline' and 'sync' mode at the same time. Exiting!\n"; exit(0); } my $datetime = localtime(); if ($options{'o'}) { print "DEBUG: offline mode set\n" if $DEBUG; print "Adding to offline file ..."; &addEntry($msg); print "Done!\n"; exit(1); } my $Connection = new Net::XMPP::Client(debuglevel=>$XMPP_DEBUG,debugfile=>"stdout"); my $status = &connAuth(); if (!($options{'s'})) { # Send message my @result= $Connection->MessageSend( to => "$to\@$componentname", body => $msg, resource => $resource); if($result[0] == 0) { print "Successful sent transaction!\n"; } else { print "There was some error. Try again!\n"; exit(0); } } else { print "DEBUG: sync mode set\n" if $DEBUG; } &sendOfflineContent(); #-------------------------- subroutines -----------------------------# sub addEntry { my $newTran = shift; open(FILE,">>$offlineFile") || die("Cannot open offline file $offlineFile"); print FILE "$newTran on $datetime\n"; #Bot does not support time field so we need to add it to description close (FILE); print "DEBUG: '$newTran' added to offline file\n" if $DEBUG; } sub promptUser { # two possible input arguments - $promptString, and $defaultValue my ($promptString,$defaultValue) = @_; if ($defaultValue) { print $promptString, "[", $defaultValue, "]: "; } else { print $promptString, ": "; } $| = 1; # force a flush after our print $_ = ; # get the input from STDIN (presumably the keyboard) chomp; #-----------------------------------------------------------------# # if we had a $default value, and the user gave us input, then # # return the input; if we had a default, and they gave us no # # no input, return the $defaultValue. # # # # if we did not have a default value, then just return whatever # # the user gave us. if they just hit the key, # # the calling routine will have to deal with that. # #-----------------------------------------------------------------# if ("$defaultValue") { return $_ ? $_ : $defaultValue; # return $_ if it has a value } else { return $_; } } sub sendOfflineContent { open(FILE, "<$offlineFile"); my @rawData=; close(FILE); my $index=0; my @result; if($rawData[0]) { print "You have old offline data. Let me send it. Hold on *"; while($rawData[0]) { @result= $Connection->MessageSend( to => "$to\@$componentname", body => $rawData[0], resource => $resource); if($result[0] != 0) { print "There was some error. Saving unsent data!\n"; open(FILE, ">$offlineFile"); print FILE @rawData; close FILE; exit(0); } print "DEBUG: Sent $rawData[0]" if $DEBUG; print "*";sleep 1; splice(@rawData, 0, 1); } print " Done\n"; open(FILE, ">$offlineFile"); print FILE @rawData; close FILE; } else { print "No offline data to send!\n"; } } sub connAuth{ # Google Talk parameters my $hostname = 'talk.google.com'; my $port = 5222; my $connectiontype = 'tcpip'; my $tls = 1; my $timeout = 10; # Connect my $status = $Connection->Connect( hostname => $hostname, port => $port, componentname => $componentname, connectiontype => $connectiontype, tls => $tls, timeout => $timeout); if (!(defined($status)) and !($options{'s'})) { print "ERROR: Connection failed.\n"; print "DEBUG: ($!)\n" if $DEBUG; my $useOffline = &promptUser("Resort to Offline mode? (y/n) ","y"); if($useOffline eq 'y') { addEntry($msg); print ("Appened transaction to offline file. Will send it over the next you call me, if we are back online.\n"); exit(1); } elsif ($useOffline eq 'n') { exit(0); } } elsif(!(defined($status))) { print "Connection Error. Sync Failed\n"; exit(0); } # Change hostname my $sid = $Connection->{SESSION}->{id}; $Connection->{STREAM}->{SIDS}->{$sid}->{hostname} = $componentname; # Authenticate my @result = $Connection->AuthSend( username => $username, password => $password, resource => $resource); if ($result[0] ne "ok") { print "ERROR: Authorization failed: $result[0] - $result[1]\n"; exit(0); } } sub usage() { print "Usage:\n"; print "$0 [-o -s] [transaction]\n\n"; print "Invoked without -o or -s, the script sends specified transaction to Clearcheckbook.com\n"; print "and also uploads older locally stored transactions. Note that the transaction string should\n"; print "be enclosed in a single quote. For example: $0 'w 5.61 ck f subway sandwich' \n\n"; print "-o\tOffline mode. New transaction is added into local file for synchronisation later.\n"; print "-s\tSend transactions stored in offline file. Does not expect new transaction.\n"; }