File Coverage

blib/lib/Net/SMS/160By2.pm
Criterion Covered Total %
statement 21 108 19.4
branch 0 74 0.0
condition 0 42 0.0
subroutine 7 15 46.6
pod 6 6 100.0
total 34 245 13.8


line stmt bran cond sub pod time code
1             package Net::SMS::160By2;
2              
3 1     1   16246 no warnings;
  1         1  
  1         32  
4 1     1   4 use strict;
  1         1  
  1         27  
5              
6             # Load this to handle exceptions nicely
7 1     1   4 use Carp;
  1         5  
  1         85  
8 1     1   635 use Data::Dumper;
  1         7368  
  1         64  
9              
10             # Load this to make HTTP Requests
11 1     1   820 use WWW::Mechanize;
  1         118991  
  1         39  
12 1     1   8 use HTML::Form;
  1         1  
  1         19  
13 1     1   605 use POSIX qw/strftime/;
  1         4845  
  1         5  
14              
15             =head1 NAME
16              
17             Net::SMS::160By2 - Send SMS using your 160By2 account!
18              
19             =head1 VERSION
20              
21             Version 0.04
22              
23             =cut
24              
25             our $VERSION = '0.04';
26              
27             our $BASE_URL = 'http://www.160by2.com';
28             our $LOGIN_URL = $BASE_URL . '/re-login';
29             our $SENDSMS_URL = $BASE_URL . '/SendSMS';
30             our $SENDSMS_SUBMIT_URL = $BASE_URL . '/SendSMSDec19';
31             my $mech;
32              
33             =head1 SYNOPSIS
34              
35             This module provides a wrapper around 160By2.com to send an SMS to any mobile number in
36              
37             India, Kuwait, UAE, Saudi, Singapore, Philippines & Malaysia at present.
38              
39             you can use this as follows.
40              
41             use Net::SMS::160By2;
42              
43             my $obj = Net::SMS::160By2->new(); # or Net::SMS::160By2->new({debug => 1, verbose => 1});
44             $obj->login($username, $password);
45            
46             # Send SMS to one mobile number
47             # country code is optional in mobile number
48             my ($msg1, $to1) = ('Test Msg', 1111111111);
49             $obj->send_sms($msg1, $to1);
50              
51             # Send SMSes to Many mobile numbers
52             my ($msg1, $to1, $msg2, $to2) = ('Test Msg 1', 2222222222, 'Test Msg 2', 3333333333);
53             my @array = (
54             [ $msg2, $to2 ],
55             [ $msg3, $to3 ],
56             # include as many as your want
57             );
58              
59             $obj->send_sms_multiple(\@array);
60              
61             # logout from 160by2.com
62             $obj->logout();
63              
64             # send additional params will print WWW::Mechanize detailed request and
65             # responses
66              
67             Thats it!
68            
69             =head1 SUBROUTINES/METHODS
70              
71             =head2 new
72              
73             This is constructor method.
74              
75             input: username, password
76              
77             A new object will be created with username, password attributes.
78              
79             You can send additional params in a hash ref as 3rd parameter.
80              
81             at present only debug option is handled in additional params.
82              
83             output: Net::SMS::160By2 object
84              
85             =cut
86              
87             sub new {
88 0     0 1   my $class = shift;
89              
90             # read username and password
91 0           my $options = shift;
92 0 0         $options = {} unless ref($options) eq 'HASH';
93              
94             # debug mean both debug and verbose
95             # verbose means only verbose
96 0 0         $options->{verbose} = $options->{debug} if $options->{debug};
97              
98             # return blessed object
99 0           my $self = bless {
100             'username' => undef,
101             'password' => undef,
102             'session_id' => undef,
103 0           %{$options}
104             }, $class;
105 0           return $self;
106             }
107              
108             =head2 login
109              
110             Login to www.160By2.com
111              
112             =cut
113              
114             sub login {
115 0     0 1   my ( $self, $username, $password ) = @_;
116              
117             # Throw error in case of no username or password
118 0 0         confess("No username provided") unless ($username);
119 0 0         confess("No password provided") unless ($password);
120              
121 0           $self->{username} = $username;
122 0           $self->{password} = $password;
123              
124             # create mechanize object
125 0           $mech = WWW::Mechanize->new( autocheck => 1 );
126 0 0         $self->logger( 'DEBUG', 'Created WWW::Mechanize successfully.' )
127             if $self->{debug};
128              
129             #if ( $self->{debug} ) {
130             # $mech->add_handler( "request_send", sub { shift->dump; return } );
131             # $mech->add_handler( "response_done", sub { shift->dump; return } );
132             #}
133 0           $mech->agent_alias('Windows Mozilla');
134              
135             # Login with given credentials
136 0 0         $self->logger( 'INFO',
137             "Logging into $BASE_URL using $self->{username}, $self->{password}" )
138             if $self->{verbose};
139 0           $mech->post( $LOGIN_URL,
140             { username => $self->{username}, password => $self->{password} } );
141              
142             # Verify login success/failed
143 0           my $content = $mech->content();
144 0 0         $self->logger( 'DEBUG', "Response received for Login request: \n$content" )
145             if $self->{debug};
146 0           my ($prefix) = ( $content =~
147             m/window\.location=['"](?:Main(?:\.action)?)\?(.*?)['"]/gi );
148 0           my ($session_id) = ( $prefix =~ /id=(.*)$/gi );
149 0 0 0       $self->logger( 'ERROR',
150             "No session details found in received Response for Login request. So treating this as Login failure."
151             ) if ( $self->{verbose} && !$session_id );
152 0 0         confess "Login to 160by2.com failed." unless $session_id;
153              
154 0           $self->{session_id} = $session_id;
155             }
156              
157             =head2 logout
158              
159             Logout from 160By2.com
160              
161             =cut
162              
163             sub logout {
164 0     0 1   my ($self) = @_;
165 0 0 0       $self->logger( 'ERROR', "No Session found to logout" )
166             if ( $self->{verbose} && !$self->{session_id} );
167 0 0         confess "No Session found to logout" unless ( $self->{session_id} );
168 0           my $logout_url = $BASE_URL . '/Logout';
169 0           $mech->get($logout_url);
170             }
171              
172             =head2 send_sms
173              
174             This method is used to send an SMS to any mobile number.
175             input : message, to
176              
177             where message contains the information you want to send.
178             to is the recipient mobile number
179            
180             =cut
181              
182             sub send_sms {
183 0     0 1   my ( $self, $msg, $to ) = @_;
184 0 0 0       confess 'Please send Message, mobile number as arguements to send_sms'
185             unless ( $msg || $to );
186              
187             # Check user session exists
188 0 0         confess "No Session details found. Please login first to send SMS"
189             unless ( $self->{session_id} );
190              
191             # format inputs
192 0 0         $self->logger( 'INFO', "Formatting message, mobile number" )
193             if $self->{verbose};
194 0           ( $msg, $to ) = $self->_format_input( $msg, $to );
195              
196             # sendsms from 160by2
197 0 0         $self->logger( 'INFO', "Sending Message '$msg' to Mobile '$to'" )
198             if $self->{verbose};
199 0           $self->_send_one( $msg, $to );
200              
201             }
202              
203             =head2 send_sms_multiple
204              
205             This method is used to send an SMS to many mobile numbers.
206             input : $ARRAY_REF [ [$msg1, $to1], [$msg2, $to2], [$msg3, $to3], etc.. ]
207              
208             where message contains the information you want to send.
209             to is the recipient mobile number
210            
211             =cut
212              
213             sub send_sms_multiple {
214 0     0 1   my ( $self, $persons ) = @_;
215              
216 0 0         confess
217             'Please send an array reference, ex. [ [$msg1, $mob1], [$msg2, $mob2], [$msg3, $mob3], and soon.. ] as an arguement to send_sms_multiple'
218             unless ref($persons) eq 'ARRAY';
219              
220             # Check user session exists
221 0 0         confess "No Session details found. Please login to send SMS"
222             unless ( $self->{session_id} );
223              
224 0           foreach my $person (@$persons) {
225              
226             # format inputs
227 0           my ( $msg, $to ) = @$person;
228 0 0 0       confess("Message or mobile number are missing") unless ( $msg || $to );
229              
230 0 0         $self->logger( 'INFO', "Formatting message, mobile number" )
231             if $self->{verbose};
232 0           ( $msg, $to ) = $self->_format_input(@$person);
233              
234             # sendsms from 160by2
235 0 0         $self->logger( 'INFO', "Sending Message '$msg' to Mobile '$to'" )
236             if $self->{verbose};
237 0           $self->_send_one( $msg, $to );
238             }
239              
240             }
241              
242             =head2 _format_input
243              
244             This will format message and mobile number
245              
246             =cut
247              
248             sub _format_input {
249 0     0     my ( $self, $msg, $to ) = @_;
250              
251             # trim spaces
252 0           $msg =~ s/^\s+|\s+$//;
253 0           $to =~ s/^\s+|\s+$//;
254              
255             # cleanup mobile number
256             # remove non digits
257 0           $to =~ s/\D//g;
258              
259             # prepend country code if not present
260 0 0         unless ( length($to) == 10 ) {
261 0           $to .= '91' . $to;
262             }
263 0           return ( $msg, $to );
264             }
265              
266             sub _send_one {
267 0     0     my ( $self, $message, $mobile ) = @_;
268              
269             # Try to go to Home Page
270 0           my $sendsms_url = $SENDSMS_URL . '?id=' . $self->{session_id};
271 0 0         $self->logger( 'INFO', "Getting SMS Form using URL $sendsms_url" )
272             if $self->{verbose};
273 0           $mech->get($sendsms_url);
274              
275 0           my $response = $mech->response();
276 0 0         $self->logger( 'INFO',
277             "Checking SMS Form really exists in received Response" )
278             if $self->{verbose};
279 0           my @forms = HTML::Form->parse($response);
280              
281 0 0 0       my ($sendsms_form) = grep {
282 0           ( $_->attr('name') =~ /frm_sendsms/i )
283             or ( $_->attr('id') =~ /frm_sendsms/i )
284             or ( $_->attr('id') =~ /send\-sms\-form/i )
285             } @forms;
286 0 0         die "Unable to find Send SMS Form\n" unless $sendsms_form;
287 0 0         $self->logger( 'INFO', "Found Send SMS form in response." )
288             if $self->{verbose};
289              
290 0           my @names = $sendsms_form->param;
291 0           my %params;
292             my $action;
293              
294 0           foreach my $name (@names) {
295 0           my $input = $sendsms_form->find_input($name);
296 0 0 0       if (
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
      0        
      0        
297             $input
298             && $input->type eq 'text'
299             && ( $input->name =~ /mobile/i
300             || $input->id =~ /mobile/i
301             || $input->{placeholder} =~ /Mobile (Number)?/i )
302             )
303             {
304 0           $params{$name} = $mobile;
305             }
306              
307             # Find message textarea element
308             elsif (
309             $input
310             && $input->type eq 'textarea'
311             && ( $input->name =~ /sendSMSMsg/i
312             || $input->id =~ /sendSMSMsg/i
313             || $input->{placeholder} =~ /(Enter your)?\s*message/i )
314             )
315             {
316 0           $params{$name} = $message;
317             }
318              
319             # Find form action attribute
320             elsif ($input
321             && $input->type eq 'hidden'
322             && ( $input->name =~ /fkapps/i || $input->id =~ /fkapps/i ) )
323             {
324 0           $action = $BASE_URL . '/' . $input->value;
325 0           $params{$name} = $input->value;
326             }
327             elsif ( $name eq 'hid_exists' ) {
328 0           $params{$name} = 'no';
329             }
330             elsif ( $name eq 'maxwellapps' ) {
331 0           $params{$name} = $self->{session_id};
332             }
333             elsif ( $name eq 'ulCategories' ) {
334 0           $params{$name} = 32;
335             }
336             elsif ( $name eq 'reminderDate' ) {
337 0           $params{$name} = strftime( "%m-%d-%Y", localtime );
338             }
339             else {
340 0           $params{$name} = $input->value;
341             }
342             }
343 0 0         $action = $SENDSMS_SUBMIT_URL unless $action;
344 0 0         $self->logger( 'DEBUG',
345             "Posting Data " . Dumper( \%params ) . " to URL $action" )
346             if $self->{debug};
347 0           $mech->post( $action, \%params );
348 0           my $content = $mech->content();
349 0 0         $self->logger( 'DEBUG', "Response for Send SMS Form Post : " . $content )
350             if $self->{debug};
351 0 0         if ( $content =~ /You have reached 160by2 Usage/gsmi ) {
352 0           $self->logger( 'ERROR',
353             '160By2 Usage Limit for your account reached today. Please use a different Account to send more or wait till tomorrow!'
354             );
355             }
356             }
357              
358             =head2 logger
359              
360             Log info for debugging purpose
361              
362             =cut
363              
364             sub logger {
365 0     0 1   my ( $self, $state, $msg ) = @_;
366 0           print STDOUT "$state: $msg\n";
367             }
368              
369             =head1 AUTHOR
370              
371             Mohan Prasad Gutta, C<< >>
372              
373             =head1 BUGS
374              
375             Please report any bugs or feature requests to C, or through
376             the web interface at L. I will be notified, and then you'll
377             automatically be notified of progress on your bug as I make changes.
378              
379              
380              
381              
382             =head1 SUPPORT
383              
384             You can find documentation for this module with the perldoc command.
385              
386             perldoc Net::SMS::160By2
387              
388              
389             You can also look for information at:
390              
391             =over 4
392              
393             =item * RT: CPAN's request tracker
394              
395             L
396              
397             =item * AnnoCPAN: Annotated CPAN documentation
398              
399             L
400              
401             =item * CPAN Ratings
402              
403             L
404              
405             =item * Search CPAN
406              
407             L
408              
409             =back
410              
411              
412             =head1 ACKNOWLEDGEMENTS
413              
414              
415             =head1 LICENSE AND COPYRIGHT
416              
417             Copyright 2014 Mohan Prasad Gutta.
418              
419             This program is free software; you can redistribute it and/or modify it
420             under the terms of either: the GNU General Public License as published
421             by the Free Software Foundation; or the Artistic License.
422              
423             See http://dev.perl.org/licenses/ for more information.
424              
425              
426             =cut
427              
428             1; # End of Net::SMS::160By2