File Coverage

blib/lib/SMS/Send/TW/Socket2Air.pm
Criterion Covered Total %
statement 28 135 20.7
branch 0 42 0.0
condition 0 4 0.0
subroutine 10 16 62.5
pod 2 2 100.0
total 40 199 20.1


line stmt bran cond sub pod time code
1             package SMS::Send::TW::Socket2Air;
2              
3 1     1   28547 use strict;
  1         2  
  1         37  
4 1     1   6 use Carp;
  1         2  
  1         96  
5 1     1   983 use IO::Socket;
  1         32344  
  1         5  
6 1     1   2297 use LWP::UserAgent;
  1         82993  
  1         40  
7 1     1   2603 use Switch;
  1         39044  
  1         7  
8 1     1   121754 use Text::Iconv;
  1         3748  
  1         73  
9 1     1   10 use base 'SMS::Send::Driver';
  1         2  
  1         986  
10              
11 1     1   362 use vars qw{$VERSION};
  1         3  
  1         38  
12             BEGIN {
13 1     1   54 $VERSION = '0.01';
14             }
15              
16             use constant {
17 1         1817 SENDBUF_SIZE => 266,
18             RECVBUF_SIZE => 244,
19             TYPE_SERV_CHECK => 0,
20             TYPE_SERV_SEND => 1,
21             TYPE_SERV_QUERY => 2,
22             TYPE_SERV_GET => 3,
23             TYPE_SERV_WAP_SEND => 13,
24             TYPE_SERV_WAP_QUERY => 14,
25             TYPE_SERV_SEND_INTL => 15,
26             TYPE_SERV_CANCEL_SEND => 16,
27             # Send now
28             TRAN_SEND_NOW => '01',
29             # Send now and stop sending message at
30             TRAN_SEND_NOW_AND_STOP_SEND_AT => '02',
31             # Ordered send
32             TRAN_SEND_ORDER => '03',
33             # Ordered send and stop sending message at
34             TRAN_SEND_ORDER_AND_STOP_SEND_AT => '04',
35             # Uncodumented coding
36             CODING_ASCII => 0,
37             CODING_BIG5 => 1,
38             CODING_BINARY => 2,
39             CODING_UCS2 => 3,
40             CODING_UTF8 => 4,
41             SMS_SERVER_IP => '202.39.54.130',
42             SMS_SERVER_PORT => '8000',
43 1     1   6 };
  1         3  
44              
45             # Preloaded methods go here.
46              
47             sub new {
48 0     0 1   my ($class, %params) = @_;
49 0           my $agent;
50             my $conn;
51              
52 0           foreach(qw/username password/) {
53 0 0         Carp::croak("No $_ specified") unless(defined $params{"_$_"});
54             }
55 0   0       $params{'host_ip'} = $params{'_host_ip'} || SMS_SERVER_IP;
56 0   0       $params{'host_port'} = $params{'_host_port'} || SMS_SERVER_PORT;
57 0 0         $params{'proxy_host'} = $params{'_proxy_host'} if (defined($params{'_proxy_host'}));
58 0 0         $params{'proxy_port'} = $params{'_proxy_port'} if (defined($params{'_proxy_port'}));
59 0 0         $params{'proxy_type'} = $params{'_proxy_type'} if (defined($params{'_proxy_type'}));
60              
61 0 0         if (defined($params{'proxy_type'})) {
62 0           foreach(qw/proxy_host proxy_port/) {
63 0 0         Carp::croak("No $_ specified") unless(defined $params{"$_"});
64             }
65 0           switch($params{'proxy_type'}) {
  0            
  0            
  0            
66 0 0         case 'http' {
  0            
67 0           $agent = LWP::UserAgent->new(keep_alive => 1);
68 0           $agent->proxy(
69             http => "http://" . $params{'proxy_host'}. ':' . $params{'proxy_port'} . "/");
70 0           my $req = HTTP::Request->new(
71             CONNECT => "http://" . $params{'host_ip'} . ':' . $params{'host_port'}. "/");
72 0           my $res = $agent->request($req);
73              
74 0 0         Carp::croak($res->status_line()) unless $res->is_success();
75 0           $conn = $res->{client_socket};
76 0           }
  0            
  0            
  0            
77             }
78             } else {
79 0           $conn = IO::Socket::INET->new($params{'host_ip'} . ':' . $params{'host_port'});
80              
81 0 0         Carp::croak('Not able to connect to CHT Socket2Air Server') unless $conn->connected;
82             }
83              
84 0           $params{'conn'} = $conn;
85 0 0         $params{'agent'} = $agent if (defined($agent));
86 0           $params{'auth'} = 0;
87              
88 0           my $self = bless { %params }, $class;
89              
90 0           return $self;
91             }
92              
93             sub _send_packet {
94 0     0     my $self = shift;
95 0           my %params = @_;
96              
97 0           my $send_buf = '';
98 0           my $tmp;
99 0           my $zero_buf = "\0"x266;
100              
101 0           my $conn = $self->{'conn'};
102              
103 0           foreach (qw/msg_type/) {
104 0 0         Carp::croak("No $_ specified") unless(defined $params{"$_"});
105             }
106              
107 0           foreach (qw/msg_coding msg_priority msg_country_code msg_set_len msg_content_len/) {
108 0 0         $params{"_$_"} = 0 unless (defined $params{"$_"});
109             }
110              
111 0           foreach (qw/msg_set msg_content/) {
112 0 0         $params{"_$_"} = '' unless (defined $params{"$_"});
113             }
114              
115 0           $send_buf = pack("CCCCCCa100a160",
116             $params{'msg_type'},
117             $params{'msg_coding'},
118             $params{'msg_priority'},
119             $params{'msg_country_code'},
120             $params{'msg_set_len'},
121             $params{'msg_content_len'},
122             $params{'msg_set'},
123             $params{'msg_content'}
124             );
125              
126             # Fill 0...
127 0           $send_buf = pack("a" . SENDBUF_SIZE, $send_buf);
128              
129             # Send to server
130 0           $conn->syswrite($send_buf, SENDBUF_SIZE);
131             }
132              
133             sub _recv_packet {
134 0     0     my $self = shift;
135              
136 0           my $recv_buf = '';
137 0           my $tmp;
138             my %ret;
139              
140 0           my $conn = $self->{'conn'};
141              
142 0           $conn->sysread($recv_buf, RECVBUF_SIZE);
143              
144             # unpack
145 0           ($ret{'ret_code'}, $ret{'ret_coding'},
146             $ret{'ret_set_len'}, $ret{'ret_content_len'},
147             $ret{'ret_set'}, $ret{'ret_content'}) = unpack("cccca80a160", $recv_buf);
148              
149             # Convert Message to UTF-8
150 0           my $from_code;
151 0           switch($ret{'ret_coding'}) {
  0            
  0            
  0            
152 0 0         case CODING_BIG5 { $from_code = 'big5'; }
  0            
  0            
  0            
  0            
  0            
  0            
153 0 0         case CODING_UCS2 { $from_code = 'ucs-2'; }
  0            
  0            
  0            
  0            
  0            
  0            
154             # UTF8 or ASCII
155 0           else { $ret{'msg'} = $ret{'ret_content'}; }
156             }
157 0 0         if (defined($from_code)) {
158 0           my $converter = Text::Iconv->new($from_code, "utf-8");
159 0           $ret{'msg'} = $converter->convert($ret{'ret_content'});
160             }
161            
162 0           return %ret;
163             }
164              
165             sub send_sms {
166 0     0 1   my $self = shift;
167 0           my %params = @_;
168              
169 0           my %ret;
170              
171             # Get the message and destination
172 0           my $message = $self->_MESSAGE( $params{text} );
173 0           my $recipient = $self->_TO( delete $params{to} );
174 0           my $conn = $self->{'conn'};
175 0           my $msg_set;
176              
177             # Login
178 0 0         if (not $self->{'auth'}) {
179 0           $msg_set = $self->{'_username'} . "\0" . $self->{'_password'} . "\0";
180 0           $self->_send_packet(
181             'msg_type' => TYPE_SERV_CHECK,
182             'msg_set' => $msg_set,
183             'msg_set_len' => length($msg_set)
184             );
185 0           %ret = $self->_recv_packet();
186 0 0         Carp::croak($ret{'ret_content'}) unless(0 == $ret{'ret_code'});
187 0           $self->{'auth'} = 1;
188             }
189              
190 0           $msg_set = $recipient . "\0" . TRAN_SEND_NOW . "\0";
191 0           $self->_send_packet(
192             'msg_type' => TYPE_SERV_SEND,
193             'msg_coding' => CODING_UCS2,
194             'msg_set' => $msg_set,
195             'msg_set_len' => length($msg_set),
196             'msg_content' => $message,
197             'msg_content_len' => length($message)
198             );
199 0           %ret = $self->_recv_packet();
200              
201 0           return %ret;
202             }
203              
204             sub _MESSAGE {
205              
206 0 0   0     my $class = ref $_[0] ? ref shift : shift;
207 0           my $message = shift;
208 0           my $converter = Text::Iconv->new("utf-8", "ucs-2");
209 0 0         unless ( length($message) <= 160 ) {
210 0           Carp::croak("Message length limit is 160 characters");
211             }
212            
213 0           return $converter->convert($message);
214             }
215              
216             sub _TO {
217 0 0   0     my $class = ref $_[0] ? ref shift : shift;
218 0           my $to = shift;
219              
220             # International numbers need their + removed
221 0           $to =~ y/0123456789//cd;
222              
223 0           return $to;
224             }
225             1;
226             =head1 NAME
227              
228             SMS::Send::TW::Socket2Air - SMS::Send driver for HiNet Socket2Air
229              
230             =head1 SYNOPSIS
231              
232             use SMS::send;
233              
234             my $sender = SMS::Send->new('TW::Socket2Air',
235             _username => 'UserName',
236             _password => 'Password',
237             _proxy_host => 'proxy.to.specified',
238             _proxy_port => 3128,
239             _proxy_type => 'http',
240             );
241              
242             my $sent = $sender->send_sms(
243             text => 'My very urgent message',
244             to => '0912345678',
245             );
246              
247             =head1 DESCRIPTION
248              
249             SMS::Send::TW::Socket2Air is a SMS::Send driver which allows you to send messages through L.
250              
251             =head1 METHODS
252              
253             =head2 new
254              
255             The C method takes a few parameters. C<_username> and C<_password> >
256             are mandatory.
257              
258             =head2 send_sms
259              
260             Takes C as recipient phonenumber, and C as the utf-8 encoded text
261             that's supposed to be delivered.
262              
263             =head1 SEE ALSO
264              
265             =over 5
266              
267             =item * L
268              
269             =item * L
270              
271             =item * L
272              
273             =head1 AUTHOR
274              
275             Jui-Nan Lin, Ejnlin@csie.nctu.edu.twE
276              
277             =head1 COPYRIGHT AND LICENSE
278              
279             Copyright (C) 2010 by Jui-Nan Lin
280              
281             This library is free software; you can redistribute it and/or modify
282             it under the same terms as Perl itself, either Perl version 5.8.8 or,
283             at your option, any later version of Perl 5 you may have available.
284              
285              
286             =cut