File Coverage

blib/lib/NetSDS/Message/SMS.pm
Criterion Covered Total %
statement 12 12 100.0
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 16 16 100.0


line stmt bran cond sub pod time code
1             #===============================================================================
2             #
3             # FILE: SMS.pm
4             #
5             # DESCRIPTION: SMS message representation
6             #
7             # NOTES: ---
8             # AUTHOR: Michael Bochkaryov (Rattler), <misha@rattler.kiev.ua>
9             # COMPANY: Net.Style
10             # CREATED: 14.08.2008 15:43:06 EEST
11             #===============================================================================
12              
13             =head1 NAME
14              
15             NetSDS::Message::SMS - short message according to ETSI GSM 03.40
16              
17             =head1 SYNOPSIS
18              
19             use NetSDS::Message::SMS;
20              
21             ...
22              
23             $msg = NetSDS::Message::SMS->new();
24             $msg->udh(conv_hex_str('050102030405');
25             $msg->ud('Hello there');
26              
27             $msg->coding(COD_7BIT);
28              
29             print "SM: " . $msg->message_body();
30              
31             =head1 DESCRIPTION
32              
33             This class provides API to SMS message data structure.
34              
35             =cut
36              
37             package NetSDS::Message::SMS;
38              
39 2     2   12816 use 5.8.0;
  2         49  
  2         110  
40 2     2   12 use strict;
  2         4  
  2         76  
41 2     2   12 use warnings;
  2         4  
  2         76  
42              
43 2     2   11 use base qw(NetSDS::Message Exporter);
  2         4  
  2         389  
44              
45             use version; our $VERSION = '0.021';
46              
47             use NetSDS::Util::Convert; # Data conversion routines
48             use NetSDS::Util::String; # String processing routines
49             use NetSDS::Util::SMS; # SMS related data processing
50             use NetSDS::Const::Message; # Messaging related constants
51              
52             our @EXPORT = qw(
53             create_long_sm
54             );
55              
56             #===============================================================================
57              
58             =head1 CLASS API
59              
60             =over
61              
62             =item B<new()> - class constructor
63              
64             Implements SMS constructor.
65              
66             my $object = NetSDS::Message::SMS->new();
67              
68             =cut
69              
70             #-----------------------------------------------------------------------
71             sub new {
72              
73             my ( $class, %params ) = @_;
74              
75             my $this = $class->SUPER::new(
76             media => 'sms', # Bearer for messages
77             headers => {
78             udhi => 0, # UDH Indicator
79             mclass => undef, # No message class by default
80             coding => COD_7BIT, # Default GSM charset (ETSI GSM 03.38)
81             mwi => undef, # Message Waiting Indicator (see DCS description)
82             priority => 0, # Non-priority messages
83             },
84             body => {
85             udh => undef, # User Data Headers
86             ud => undef, # User Data
87             },
88             format => 'sms', # Generic SMS data
89             %params,
90             );
91              
92             # Set SMS coding
93             if ( defined $params{coding} ) {
94             $this->coding( $params{coding} );
95             }
96              
97             return $this;
98              
99             } ## end sub new
100              
101             #***********************************************************************
102              
103             =item B<coding()> - set/get SMS coding
104              
105             Paramters: new coding to set
106              
107             Returns: message coding
108              
109             $msg->coding(COD_UCS2);
110              
111             =cut
112              
113             #-----------------------------------------------------------------------
114              
115             sub coding {
116              
117             my ( $this, $coding ) = @_;
118              
119             if ( defined $coding ) {
120              
121             # Check if coding is correct
122             $coding += 0;
123             if ( ( $coding < 0 ) or ( $coding > 2 ) ) {
124             return $this->error("Cant set unknown data coding for SMS");
125             }
126             $this->header( 'coding', $coding );
127             }
128              
129             return $this->header('coding');
130              
131             }
132              
133             #***********************************************************************
134              
135             =item B<mclass()> - set/get message class
136              
137             Paramters: new message class value
138              
139             $msg->mclass(0); # Send as Flash SMS
140              
141             =cut
142              
143             #-----------------------------------------------------------------------
144              
145             sub mclass {
146              
147             my ( $this, $mclass ) = @_;
148              
149             if ( defined $mclass ) {
150              
151             # Check if message class is correct
152             $mclass += 0;
153             if ( ( $mclass < 0 ) or ( $mclass > 3 ) ) {
154             return $this->error("Cant set unknown message class for SMS");
155             }
156             $this->header( 'mclass', $mclass );
157             }
158              
159             return $this->header('mclass');
160              
161             }
162              
163             #***********************************************************************
164              
165             =item B<udh()> - set/get UDH
166              
167             Paramters: UDH as binary string
168              
169             Returns: UDH
170              
171             $msg->udh(conv_hex_str('050.02130405');
172              
173             =cut
174              
175             #-----------------------------------------------------------------------
176              
177             sub udh {
178              
179             my ( $this, $udh ) = @_;
180              
181             if ($udh) {
182              
183             $this->header( 'udhi', 1 );
184              
185             # Retrieve UDH length in bytes (1st
186             my ($udhl) = unpack( "C*", bytes::substr( $udh, 0, 1 ) );
187              
188             # Check if UDH isn't more than maximum SMS size
189             if ( $udhl > 139 ) {
190             return $this->error("Cant set UDH more than 139 bytes");
191             }
192              
193             # Check if UDHL is correct
194             if ( ( $udhl + 1 ) != bytes::length($udh) ) {
195             return $this->error("Incorrect UDHL in UDH");
196             }
197              
198             $this->{body}->{udh} = str_decode($udh);
199             }
200              
201             return $this->{body}->{udh};
202              
203             } ## end sub udh
204              
205             #***********************************************************************
206              
207             =item B<ud()> - set/get user data
208              
209             Paramters: user data as binary string
210              
211             Returns: user data
212              
213             =cut
214              
215             #-----------------------------------------------------------------------
216              
217             sub ud {
218              
219             my ( $this, $ud ) = @_;
220              
221             if ( defined $ud ) {
222             $this->{body}->{ud} = str_decode($ud);
223             }
224              
225             return $this->{body}->{ud};
226              
227             }
228              
229             #***********************************************************************
230              
231             =item B<esm_class()> - get esm_class from message
232              
233             See 5.2.12 chapter of SMPP 3.4 specification for details.
234              
235             $esm_class = $msg->esm_class();
236              
237             =cut
238              
239             #-----------------------------------------------------------------------
240              
241             sub esm_class {
242              
243             my ($this) = @_;
244              
245             my $esm_class = 0b00000000;
246              
247             # Set UDHI to 1 if UDH exists
248             if ( $this->udh() ) {
249             $esm_class += 0b01000000; # Set UDHI indicator
250             }
251              
252             # Set DLR indicator if 'dlr' header presents
253             if ( $this->header('dlr') ) {
254             $esm_class += 0b00001000; # Set DLR indicator
255             }
256              
257             return $esm_class;
258             }
259              
260             #***********************************************************************
261              
262             =item B<dcs()> - get data coding scheme
263              
264             Returns data coding schmeme in accordance with ETSI GSM 03.38
265              
266             $dcs = $msg->dcs();
267              
268             =cut
269              
270             #-----------------------------------------------------------------------
271              
272             sub dcs {
273              
274             my ($this) = @_;
275              
276             my $dcs = 0b00000000;
277              
278             # If have message class, bit 4 of DCS must be 1
279             # Message class value set in 1 and 0 bits
280             my $mclass = $this->header('mclass');
281             if ( defined $mclass ) {
282             $dcs += 0b00010000; # Has message class
283             $dcs += $mclass + 0; # Message class value
284             }
285              
286             # Add message coding (bits 2 and 3)
287             $dcs += ( ( $this->header('coding') << 2 ) & 0b00001100 );
288              
289             return $dcs;
290             }
291              
292             #***********************************************************************
293              
294             =item B<message_body()> - return SMS message body
295              
296             Returns: SMS body as byte string (UDH + UD)
297              
298             $msg_hex = conv_str_hex($msg->message_body);
299              
300             =cut
301              
302             #-----------------------------------------------------------------------
303              
304             sub message_body {
305              
306             my ($this) = @_;
307              
308             return $this->udh ? $this->udh . $this->ud : $this->ud;
309             }
310              
311             #***********************************************************************
312              
313             =item B<text($string, $coding)> - set SM data from text string
314              
315             Paramters: string, SMS coding
316              
317             # Set SMS text
318             $msg->text('Just some string', COD_7BIT);
319              
320             This will set UDH to undef and UD to string in GSM 03.38.
321              
322             =cut
323              
324             #-----------------------------------------------------------------------
325              
326             sub text {
327              
328             my ( $self, $str, $coding ) = @_;
329             $str = str_decode($str);
330              
331             $self->coding($coding);
332             $self->{body}->{udh} = undef; # only short text SMS
333              
334             # Convert UTF-8 string to proper encoding
335             if ( $coding == COD_7BIT ) {
336             $self->ud( str_recode( $str, 'UTF-8', 'GSM0338' ) );
337             } elsif ( $coding == COD_UCS2 ) {
338             $self->ud( str_recode( $str, 'UTF-8', 'UCS-2BE' ) );
339             } else {
340             return $self->error('Unknown encoding for text SM');
341             }
342              
343             return $self->ud();
344              
345             } ## end sub text
346              
347              
348             #***********************************************************************
349              
350             =back
351              
352             =head1 EXPORTED FUNCTIONS
353              
354             =over
355              
356             =item B<create_long_sm($text, $coding)> - concatenated SMS sequence
357              
358             Paramters: text string (UTF-8), SMS coding
359              
360             Returns: array of NetSDS::Message::SMS objects
361              
362             # Create 300 character string
363             my $long_str = 'abc'x100;
364              
365             my @parts = create_long_sm($long_str, COD_7BIT);
366              
367             =cut
368              
369             #-----------------------------------------------------------------------
370              
371             sub create_long_sm {
372              
373             my ( $str, $coding ) = @_;
374              
375             # Parse string
376             my @parts = NetSDS::Util::SMS::split_text( $str, $coding );
377              
378             # Create array of SMS objects
379             my @res = ();
380             foreach my $part (@parts) {
381             my $msg = NetSDS::Message::SMS->new(
382             coding => $coding,
383             );
384             $msg->udh( $part->{udh} );
385             $msg->ud( $part->{ud} );
386             push @res, $msg;
387             }
388             return @res;
389             }
390              
391             1;
392              
393             __END__
394              
395             =back
396              
397             =head1 EXAMPLES
398              
399             See C<samples> directory for examples.
400              
401             =head1 BUGS
402              
403             Unknown yet
404              
405             =head1 SEE ALSO
406              
407             * ETSI GSM 03.38 - alphabets and language specific information
408              
409             * ETSI GSM 03.40 - SMS realization on GSM networks
410              
411             * SMPP Protocol Specification v3.4
412              
413             =head1 TODO
414              
415             * Implement RPI and message mode support in esm_class()
416              
417             * Implement MWI support in dcs() method
418              
419             =head1 AUTHOR
420              
421             Michael Bochkaryov <misha@rattler.kiev.ua>
422              
423             =head1 LICENSE
424              
425             Copyright (C) 2008 Michael Bochkaryov
426              
427             This program is free software; you can redistribute it and/or modify
428             it under the terms of the GNU General Public License as published by
429             the Free Software Foundation; either version 2 of the License, or
430             (at your option) any later version.
431              
432             This program is distributed in the hope that it will be useful,
433             but WITHOUT ANY WARRANTY; without even the implied warranty of
434             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
435             GNU General Public License for more details.
436              
437             You should have received a copy of the GNU General Public License
438             along with this program; if not, write to the Free Software
439             Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
440              
441             =cut
442              
443