Created
August 30, 2017 09:23
-
-
Save maddingue/174dc80eecc3483dc0e269b143cf2f4f to your computer and use it in GitHub Desktop.
skeleton program for procesing incoming messages, suitable for being used as a Gammu RunOnReceive handler
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use utf8; | |
use strict; | |
use warnings; | |
no warnings qw< void >; | |
use Getopt::Long; | |
$::PROGRAM = "incoming-sms-handler"; | |
$::VERSION = "0.1.5"; | |
my @raspis = qw< ... >; | |
my @zabbix = qw< ... >; | |
MAIN: { | |
main() unless caller(); | |
} | |
# | |
# main() | |
# ---- | |
sub main { | |
# default options | |
my %options = ( | |
debug => 0, | |
errfile => "/var/log/$::PROGRAM.err", | |
logfile => "/var/log/$::PROGRAM.log", | |
); | |
# parse options | |
Getopt::Long::Configure(qw< no_auto_abbrev no_ignore_case >); | |
GetOptions(\%options, qw{ | |
help|usage|h! man! version|V! | |
debug|d! errfile=s logfile=s | |
}) or pod2usage(0); | |
if (not $options{debug}) { | |
# redirect standard output & error | |
open STDOUT, ">>", $options{errfile}; | |
open STDERR, ">&", \*STDOUT; | |
STDOUT->autoflush(1); | |
STDERR->autoflush(1); | |
} | |
# create dispatcher object | |
my $dispatcher = SMS::Dispatcher->new(\%options); | |
# process each message | |
for my $n (1 .. $ENV{SMS_MESSAGES}) { | |
my $from = $ENV{"SMS_${n}_NUMBER"}; | |
my $text = $ENV{"SMS_${n}_TEXT"}; | |
$text =~ s/^\s+|\s+$//g; # trim spaces | |
$dispatcher->log("from=[$from] text=[$text]"); | |
# check sender number | |
$dispatcher->log("invalid sender number [$from]") and next | |
unless $from =~ /^\+?[0-9]+$/; | |
# extract the command from the text | |
my ($cmd, @args) = split /\s+/, $text; | |
$cmd = lc $cmd; | |
# find the corresponding method | |
my $method = SMS::Dispatcher::Handler->can($cmd); | |
$dispatcher->log("no handler for command [$cmd]") and next | |
unless $method; | |
# execute the handler | |
$dispatcher->$method({ | |
from => $from, | |
command => $cmd, | |
args => \@args, | |
}); | |
} | |
} | |
# ============================================================================== | |
package SMS::Dispatcher; | |
use File::Temp qw< tempfile >; | |
use POSIX qw< strftime >; | |
# This namespace contains utility methods for the handlers. | |
# | |
# new() | |
# --- | |
sub new { | |
return bless $_[1], $_[0] | |
} | |
# | |
# log() | |
# --- | |
sub log { | |
my $self = shift; | |
my $ts = strftime "%F %T", localtime; | |
my ($func) = map { s/^SMS::Dispatcher:://; $_ } (caller(1))[3]; | |
my $msg = "$ts [$func] @_\n"; | |
if ($self->{debug}) { | |
print STDERR $msg; | |
} | |
else { | |
if (open my $fh, ">>", $self->{logfile}) { | |
print {$fh} $msg; | |
close $fh; | |
} | |
} | |
return 1 | |
} | |
# | |
# furl() | |
# ---- | |
# Create and return a Furl object, configured for the particular uses | |
# within this program | |
# | |
sub furl { | |
require Furl; | |
require IO::Socket::SSL; | |
import IO::Socket::SSL qw< SSL_VERIFY_NONE >; | |
my $furl = Furl->new( | |
timeout => 1, | |
ssl_opts => { SSL_verify_mode => SSL_VERIFY_NONE() }, | |
); | |
return $furl | |
} | |
# | |
# send_sms() | |
# -------- | |
# Send a SMS; when in debug mode, write it to standard output | |
# Args: | |
# - recipient number | |
# - text message, either as a plain string or as an arrayref | |
# | |
sub send_sms { | |
my ($self, $to, $msg) = @_; | |
my $text; | |
if (ref $msg) { | |
if (ref $msg eq "ARRAY") { | |
$text = join "\n", @$msg; | |
} | |
} | |
else { | |
$text = $msg; | |
} | |
# write the text in a file | |
my ($fh, $path) = tempfile("sms-answer-XXXXXX", TMPDIR => 1, UNLINK => 1); | |
print {$fh} $text; | |
close $fh; | |
# execute the script to send the SMS | |
if ($self->{debug}) { | |
$self->log("exec: gammu-smsd-inject TEXT $to -unicode < $path"); | |
$self->log("$path:"); | |
system "/bin/cat $path"; | |
print STDERR "\n"; | |
} | |
else { | |
system "gammu-smsd-inject TEXT $to -unicode < $path"; | |
} | |
} | |
# ============================================================================== | |
package SMS::Dispatcher::Handler; | |
# Add in this namespace the command handlers, with the method name being the | |
# command name. If you want to create command aliases, you can do this with | |
# method aliases: | |
# | |
# *meep = \&ping; # "meep" now is an alias for "ping" | |
# | |
# ping() | |
# ---- | |
sub ping { | |
my ($self, $params) = @_; | |
$self->send_sms($params->{from}, "pong"); | |
} | |
# | |
# status() | |
# ------ | |
# Answer a text with the status of the RaspiSMS & the Zabbix servers | |
# | |
sub status { | |
my ($self, $params) = @_; | |
my $from = $params->{from}; | |
my $furl = $self->furl(); | |
my @status; | |
for my $rpi (@raspis) { | |
my $res = $furl->get("http://$rpi/status.txt"); | |
my ($signal) = $res->content =~ /([0-9]+)%/; | |
push @status, sprintf "%s $rpi 📶 %d%%", | |
$res->is_success ? "✔️" : "❌", $signal; | |
} | |
for my $zbx (@zabbix) { | |
my $res = $furl->get("https://$zbx/"); | |
push @status, sprintf "%s $zbx", | |
$res->is_success ? "✔️" : "❌"; | |
} | |
$self->send_sms($from, \@status); | |
} | |
__PACKAGE__ | |
__END__ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment