File Coverage

blib/lib/SMS/Handler/Dispatcher.pm
Criterion Covered Total %
statement 15 49 30.6
branch 0 32 0.0
condition 0 2 0.0
subroutine 5 8 62.5
pod 3 3 100.0
total 23 94 24.4


line stmt bran cond sub pod time code
1             package SMS::Handler::Dispatcher;
2              
3             require 5.005_62;
4              
5 3     3   17 use Carp;
  3         6  
  3         198  
6 3     3   15 use strict;
  3         6  
  3         255  
7 3     3   20 use warnings;
  3         5  
  3         77  
8 3     3   14 use SMS::Handler;
  3         6  
  3         142  
9 3     3   20 use SMS::Handler::Utils;
  3         6  
  3         2832  
10              
11             our $Debug = 0;
12              
13             # $Id: Dispatcher.pm,v 1.4 2003/03/13 20:41:54 lem Exp $
14              
15             our $VERSION = q$Revision: 1.4 $;
16             $VERSION =~ s/Revision: //;
17              
18             =pod
19              
20             =head1 NAME
21              
22             SMS::Handler::Dispatcher - Helper class for dispatch - based SMS handlers
23              
24             =head1 SYNOPSIS
25              
26             use SMS::Handler::Dispatcher;
27             package MyHandler;
28             @ISA = qw(SMS::Handler::Dispatcher);
29              
30             ...
31              
32             =head1 DESCRIPTION
33              
34             This module provides a base class that implements a dispatch table
35             based on the commands contained in the given SMS. Commands consist of
36             words (sequences of characters matching C<\w>) or its abbreviations
37             preceded by a single dot.
38              
39             =pod
40              
41             The following methods are provided:
42              
43             =over 4
44              
45             =pod
46              
47             =item C<-Ehandle()>
48              
49             Dispatch the required command to the handlers set up by the invoking
50             class. The command to method mapping is assumed to be supplied by the
51             object when calling C<-Eabbrevs> (for the command abbreviations)
52             or C<-Ecmds> for the command mapping. C<-Eabbrevs> must return
53             a reference to a hash where each key is a possible command
54             abbreviation andd its value, is the actual command.
55              
56             C<-Ecmds> must return a reference to a hash, where each key is a
57             command and each value is a reference to the corresponding method to
58             call. This class includes dummy methods that simply return
59             C<-E{abbrevs}> or C<-E{cmds}> respectively.
60              
61             Each of the methods implementing a command, will be called with the
62             following arguments.
63              
64             =over 3
65              
66             =item *
67              
68             A reference to the object.
69              
70             =item *
71              
72             The hash reference passed to C<-Ehandle>.
73              
74             =item *
75              
76             A compact representation of the source address, made from
77             concatenating the NPI, TON and SOURCE with dots.
78              
79             =item *
80              
81             A reference to the command line of the SMS (or the whole SMS if no
82             separate lines).
83              
84             =item *
85              
86             A reference to the remainder of the SMS.
87              
88             =back
89              
90             A positive return value from said methods, tell C<-Ehandle> to
91             keep looking for commands. A false return value, stops the search for
92             further commands. In any case, C<-Ehandle> will return C
93             | SMS_DEQUEUE>.
94              
95             If no corresponding command can be found for a given SMS, the
96             C<-Edispatch_error> method will be invoked, using the same calling
97             protocol than command methods. Its return value will be returned by
98             C<-Ehandle>.
99              
100             The calling protocol depicted above is only attempted if the object
101             contains C<$self-E{number}>. In this case, the SMS destination
102             address is matched against C<$self-{dest_addr_ton}>,
103             C<$self-{dest_addr_npi}> and
104             C<$self-{dest_addr_destination_addr}>. Only if this match
105             succeeds, the message is accepted. This allows an object to restrict
106             the numbers it handles. C is returned in this case, to
107             allow other objects a chance to process this message.
108              
109             =cut
110              
111             sub handle
112             {
113 0     0 1   my $self = shift;
114 0           my $hsms = shift;
115              
116 0 0         if ($self->{number})
117             {
118 0 0         unless ($hsms->{dest_addr_ton} == $self->{ton})
119             {
120 0 0         warn "Email: Destination address did not match TON\n" if $Debug;
121 0           return SMS_CONTINUE;
122             }
123 0 0         unless ($hsms->{dest_addr_npi} == $self->{npi})
124             {
125 0 0         warn "Email: Destination address did not match NPI\n" if $Debug;
126 0           return SMS_CONTINUE;
127             }
128 0 0         unless ($hsms->{destination_addr} == $self->{number})
129             {
130 0 0         warn "Email: Destination address did not match NUMBER\n" if $Debug;
131 0           return SMS_CONTINUE;
132             }
133             }
134             # This is a convenient shortcut for the
135             # source address
136              
137 0           my $source = join('.', $hsms->{source_addr_ton},
138             $hsms->{source_addr_npi},
139             $hsms->{source_addr});
140              
141 0           my $msg = $hsms->{short_message};
142 0           my $body;
143              
144 0           ($msg, $body) = SMS::Handler::Utils::Split($msg);
145             # $msg contains the first line of the SMS,
146             # where we must look for commands.
147             # We will look for a command keyword and
148             # hand the whole thing to the corresponding
149             # handler method
150              
151 0           $msg =~ s/^[^\.]+//; # Remove any potential garbage before the
152             # first dot.
153              
154 0           $msg =~ s/\s+$//; # Remove trailing whitespace
155              
156 0           while ($msg =~ m/^\.(\w+)/)
157             {
158 0 0         warn "Dispatcher: Looking for command for '$1'\n" if $Debug;
159 0 0         if ($self->cmds->{uc $1})
160             {
161 0 0         warn "Dispatcher: command found\n" if $Debug;
162 0 0         last unless $self->cmds->{uc $1}->($self, $hsms,
163             $source, \$msg,
164             \$body);
165             }
166             else
167             {
168 0   0       my $name = $self->abbrevs->{uc $1} || undef;
169 0 0         last unless $name;
170              
171 0 0         warn "Dispatcher: match with $name\n" if $Debug;
172              
173 0 0         last unless $self->cmds->{$name}->($self, $hsms, $source,
174             \$msg, \$body);
175             }
176             }
177              
178 0           $msg =~ s/^\s+$//; # Discard void whitespace
179            
180 0 0         if ($msg)
181             {
182 0 0         warn "Dispatcher: no match\n" if $Debug;
183 0           return $self->dispatch_error($hsms, $source, \$msg, \$body);
184             }
185              
186 0           return SMS_STOP | SMS_DEQUEUE;
187             }
188              
189             =pod
190              
191             =item C<-Edispatch_error>
192              
193             sub dispatch_error
194             {
195             croak "Classes based on SMS::Handler::Dispatcher must implement their dispatch_method()\n";
196             }
197              
198             =cut
199              
200             =pod
201              
202             =item C<-Eabbrevs>
203              
204             Return C<$self->{abbrevs}>.
205              
206             =cut
207              
208 0     0 1   sub abbrevs { return $_[0]->{abbrevs}; }
209              
210             =item C<-Ecmds>
211              
212             Return C<$self->{cmds}>.
213              
214             =cut
215              
216 0     0 1   sub cmds { return $_[0]->{cmds}; }
217              
218             1;
219              
220             __END__