File Coverage

blib/lib/SMS/Send/TW/chtsns.pm
Criterion Covered Total %
statement 28 138 20.2
branch 0 44 0.0
condition 0 4 0.0
subroutine 10 16 62.5
pod 2 2 100.0
total 40 204 19.6


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