2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2004 - 2005, Adrian Kennard, rights assigned to Digium
6 * See http://www.asterisk.org for more information about
7 * the Asterisk project. Please do not directly contact
8 * any of the maintainers of this project for assistance;
9 * the project provides a web site, mailing lists and IRC
10 * channels for your use.
12 * This program is free software, distributed under the terms of
13 * the GNU General Public License Version 2. See the LICENSE file
14 * at the top of the source tree.
19 * \brief SMS application - ETSI ES 201 912 protocol 1 implimentation
20 * \ingroup applications
22 * \author Adrian Kennard
27 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
36 #include <sys/types.h>
39 #include "asterisk/lock.h"
40 #include "asterisk/file.h"
41 #include "asterisk/logger.h"
42 #include "asterisk/options.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/pbx.h"
45 #include "asterisk/module.h"
46 #include "asterisk/alaw.h"
47 #include "asterisk/callerid.h"
49 /* output using Alaw rather than linear */
53 /* Add full VP support */
54 /* Handle status report messages (generation and reception) */
55 /* Time zones on time stamps */
58 static volatile unsigned char message_ref
; /* arbitary message ref */
59 static volatile unsigned int seq
; /* arbitrary message sequence number for unqiue files */
61 static char log_file
[255];
62 static char spool_dir
[255];
64 static char *app
= "SMS";
66 static char *synopsis
= "Communicates with SMS service centres and SMS capable analogue phones";
68 static char *descrip
=
69 " SMS(name|[a][s]): SMS handles exchange of SMS data with a call to/from SMS capabale\n"
70 "phone or SMS PSTN service center. Can send and/or receive SMS messages.\n"
71 "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n"
72 "Typical usage is to use to handle called from the SMS service centre CLI,\n"
73 "or to set up a call using 'outgoing' or manager interface to connect\n"
74 "service centre to SMS()\n"
75 "name is the name of the queue used in /var/spool/asterisk/sms\n"
77 " a: answer, i.e. send initial FSK packet.\n"
78 " s: act as service centre talking to a phone.\n"
79 "Messages are processed as per text file message queues.\n"
80 "smsq (a separate software) is a command to generate message\n"
81 "queues and send messages.\n";
83 static signed short wave
[] = {
84 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
85 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
87 -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
89 -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
93 static unsigned char wavea
[80];
97 /* SMS 7 bit character mapping to UCS-2 */
98 static const unsigned short defaultalphabet
[] = {
99 0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
100 0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
101 0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
102 0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
103 ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
104 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
105 161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
106 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
107 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
108 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
111 static const unsigned short escapes
[] = {
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x000C, 0, 0, 0, 0, 0,
113 0, 0, 0, 0, 0x005E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
114 0, 0, 0, 0, 0, 0, 0, 0, 0x007B, 0x007D, 0, 0, 0, 0, 0, 0x005C,
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x005B, 0x007E, 0x005D, 0,
116 0x007C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118 0, 0, 0, 0, 0, 0x20AC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122 #define SMSLEN 160 /* max SMS length */
126 unsigned char hangup
; /* we are done... */
127 unsigned char err
; /* set for any errors */
128 unsigned char smsc
:1; /* we are SMSC */
129 unsigned char rx
:1; /* this is a received message */
130 char queue
[30]; /* queue name */
131 char oa
[20]; /* originating address */
132 char da
[20]; /* destination address */
133 time_t scts
; /* time stamp, UTC */
134 unsigned char pid
; /* protocol ID */
135 unsigned char dcs
; /* data coding scheme */
136 short mr
; /* message reference - actually a byte, but usde -1 for not set */
137 int udl
; /* user data length */
138 int udhl
; /* user data header length */
139 unsigned char srr
:1; /* Status Report request */
140 unsigned char udhi
:1; /* User Data Header required, even if length 0 */
141 unsigned char rp
:1; /* Reply Path */
142 unsigned int vp
; /* validity period in minutes, 0 for not set */
143 unsigned short ud
[SMSLEN
]; /* user data (message), UCS-2 coded */
144 unsigned char udh
[SMSLEN
]; /* user data header */
145 char cli
[20]; /* caller ID */
146 unsigned char ophase
; /* phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
147 unsigned char ophasep
; /* phase (0-79) for 1200 bps */
148 unsigned char obyte
; /* byte being sent */
149 unsigned int opause
; /* silent pause before sending (in sample periods) */
150 unsigned char obitp
; /* bit in byte */
151 unsigned char osync
; /* sync bits to send */
152 unsigned char obytep
; /* byte in data */
153 unsigned char obyten
; /* bytes in data */
154 unsigned char omsg
[256]; /* data buffer (out) */
155 unsigned char imsg
[200]; /* data buffer (in) */
156 signed long long ims0
,
159 imc1
; /* magnitude averages sin/cos 0/1 */
161 unsigned short imag
; /* signal level */
165 ipc1
; /* phase sin/cos 0/1 */
166 unsigned char ibitl
; /* last bit */
167 unsigned char ibitc
; /* bit run length count */
168 unsigned char iphasep
; /* bit phase (0-79) for 1200 bps */
169 unsigned char ibitn
; /* bit number in byte being received */
170 unsigned char ibytev
; /* byte value being received */
171 unsigned char ibytep
; /* byte pointer in messafe */
172 unsigned char ibytec
; /* byte checksum for message */
173 unsigned char ierr
; /* error flag */
174 unsigned char ibith
; /* history of last bits */
175 unsigned char ibitt
; /* total of 1's in last 3 bites */
176 /* more to go here */
179 /* different types of encoding */
180 #define is7bit(dcs) (((dcs)&0xC0)?(!((dcs)&4)):(!((dcs)&12)))
181 #define is8bit(dcs) (((dcs)&0xC0)?(((dcs)&4)):(((dcs)&12)==4))
182 #define is16bit(dcs) (((dcs)&0xC0)?0:(((dcs)&12)==8))
184 static void *sms_alloc (struct ast_channel
*chan
, void *params
)
189 static void sms_release (struct ast_channel
*chan
, void *data
)
194 static void sms_messagetx (sms_t
* h
);
196 /*! \brief copy number, skipping non digits apart from leading + */
197 static void numcpy (char *d
, char *s
)
209 /*! \brief static, return a date/time in ISO format */
210 static char * isodate (time_t t
)
212 static char date
[20];
213 strftime (date
, sizeof (date
), "%Y-%m-%dT%H:%M:%S", localtime (&t
));
217 /*! \brief reads next UCS character from null terminated UTF-8 string and advanced pointer */
218 /* for non valid UTF-8 sequences, returns character as is */
219 /* Does not advance pointer for null termination */
220 static long utf8decode (unsigned char **pp
)
222 unsigned char *p
= *pp
;
224 return 0; /* null termination of string */
227 return *p
; /* ascii or continuation character */
229 if (*p
< 0xC2 || (p
[1] & 0xC0) != 0x80)
230 return *p
; /* not valid UTF-8 */
232 return ((*p
& 0x1F) << 6) + (p
[1] & 0x3F);
235 if ((*p
== 0xE0 && p
[1] < 0xA0) || (p
[1] & 0xC0) != 0x80 || (p
[2] & 0xC0) != 0x80)
236 return *p
; /* not valid UTF-8 */
238 return ((*p
& 0x0F) << 12) + ((p
[1] & 0x3F) << 6) + (p
[2] & 0x3F);
241 if ((*p
== 0xF0 && p
[1] < 0x90) || (p
[1] & 0xC0) != 0x80 || (p
[2] & 0xC0) != 0x80 || (p
[3] & 0xC0) != 0x80)
242 return *p
; /* not valid UTF-8 */
244 return ((*p
& 0x07) << 18) + ((p
[1] & 0x3F) << 12) + ((p
[2] & 0x3F) << 6) + (p
[3] & 0x3F);
247 if ((*p
== 0xF8 && p
[1] < 0x88) || (p
[1] & 0xC0) != 0x80 || (p
[2] & 0xC0) != 0x80 || (p
[3] & 0xC0) != 0x80
248 || (p
[4] & 0xC0) != 0x80)
249 return *p
; /* not valid UTF-8 */
251 return ((*p
& 0x03) << 24) + ((p
[1] & 0x3F) << 18) + ((p
[2] & 0x3F) << 12) + ((p
[3] & 0x3F) << 6) + (p
[4] & 0x3F);
254 if ((*p
== 0xFC && p
[1] < 0x84) || (p
[1] & 0xC0) != 0x80 || (p
[2] & 0xC0) != 0x80 || (p
[3] & 0xC0) != 0x80
255 || (p
[4] & 0xC0) != 0x80 || (p
[5] & 0xC0) != 0x80)
256 return *p
; /* not valid UTF-8 */
258 return ((*p
& 0x01) << 30) + ((p
[1] & 0x3F) << 24) + ((p
[2] & 0x3F) << 18) + ((p
[3] & 0x3F) << 12) + ((p
[4] & 0x3F) << 6) + (p
[5] & 0x3F);
260 return *p
; /* not sensible */
263 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using SMS 7 bit character codes */
264 /* The return value is the number of septets packed in to o, which is internally limited to SMSLEN */
265 /* o can be null, in which case this is used to validate or count only */
266 /* if the input contains invalid characters then the return value is -1 */
267 static int packsms7 (unsigned char *o
, int udhl
, unsigned char *udh
, int udl
, unsigned short *ud
)
269 unsigned char p
= 0, b
= 0, n
= 0;
271 if (udhl
) { /* header */
291 }; /* filling to septet boundary */
300 for (v
= 0; v
< 128 && defaultalphabet
[v
] != u
; v
++);
301 if (v
== 128 && u
&& n
+ 1 < SMSLEN
) {
302 for (v
= 0; v
< 128 && escapes
[v
] != u
; v
++);
303 if (v
< 128) { /* escaped sequence */
311 o
[p
] = (27 >> (7 - b
));
317 return -1; /* invalid character */
325 o
[p
] = (v
>> (7 - b
));
333 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 8 bit character codes */
334 /* The return value is the number of bytes packed in to o, which is internally limited to 140 */
335 /* o can be null, in which case this is used to validate or count only */
336 /* if the input contains invalid characters then the return value is -1 */
337 static int packsms8 (unsigned char *o
, int udhl
, unsigned char *udh
, int udl
, unsigned short *ud
)
341 /* header - no encoding */
355 if (u
< 0 || u
> 0xFF)
356 return -1; /* not valid */
365 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2
366 message (udl characters at ud) and packs in to o using 16 bit
367 UCS-2 character codes
368 The return value is the number of bytes packed in to o, which is
369 internally limited to 140
370 o can be null, in which case this is used to validate or count
371 only if the input contains invalid characters then
372 the return value is -1 */
373 static int packsms16 (unsigned char *o
, int udhl
, unsigned char *udh
, int udl
, unsigned short *ud
)
376 /* header - no encoding */
393 return p
- 1; /* could not fit last character */
402 /*! \brief general pack, with length and data,
403 returns number of bytes of target used */
404 static int packsms (unsigned char dcs
, unsigned char *base
, unsigned int udhl
, unsigned char *udh
, int udl
, unsigned short *ud
)
406 unsigned char *p
= base
;
409 if (is7bit (dcs
)) { /* 7 bit */
410 l
= packsms7 (p
+ 1, udhl
, udh
, udl
, ud
);
414 p
+= (l
* 7 + 7) / 8;
415 } else if (is8bit (dcs
)) { /* 8 bit */
416 l
= packsms8 (p
+ 1, udhl
, udh
, udl
, ud
);
422 l
= packsms16 (p
+ 1, udhl
, udh
, udl
, ud
);
429 *p
++ = 0; /* no user data */
434 /*! \brief pack a date and return */
435 static void packdate (unsigned char *o
, time_t w
)
437 struct tm
*t
= localtime (&w
);
438 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
439 int z
= -t
->tm_gmtoff
/ 60 / 15;
441 int z
= timezone
/ 60 / 15;
443 *o
++ = ((t
->tm_year
% 10) << 4) + (t
->tm_year
% 100) / 10;
444 *o
++ = (((t
->tm_mon
+ 1) % 10) << 4) + (t
->tm_mon
+ 1) / 10;
445 *o
++ = ((t
->tm_mday
% 10) << 4) + t
->tm_mday
/ 10;
446 *o
++ = ((t
->tm_hour
% 10) << 4) + t
->tm_hour
/ 10;
447 *o
++ = ((t
->tm_min
% 10) << 4) + t
->tm_min
/ 10;
448 *o
++ = ((t
->tm_sec
% 10) << 4) + t
->tm_sec
/ 10;
450 *o
++ = (((-z
) % 10) << 4) + (-z
) / 10 + 0x08;
452 *o
++ = ((z
% 10) << 4) + z
/ 10;
455 /*! \brief unpack a date and return */
456 static time_t unpackdate (unsigned char *i
)
459 t
.tm_year
= 100 + (i
[0] & 0xF) * 10 + (i
[0] >> 4);
460 t
.tm_mon
= (i
[1] & 0xF) * 10 + (i
[1] >> 4) - 1;
461 t
.tm_mday
= (i
[2] & 0xF) * 10 + (i
[2] >> 4);
462 t
.tm_hour
= (i
[3] & 0xF) * 10 + (i
[3] >> 4);
463 t
.tm_min
= (i
[4] & 0xF) * 10 + (i
[4] >> 4);
464 t
.tm_sec
= (i
[5] & 0xF) * 10 + (i
[5] >> 4);
467 t
.tm_min
+= 15 * ((i
[6] & 0x7) * 10 + (i
[6] >> 4));
469 t
.tm_min
-= 15 * ((i
[6] & 0x7) * 10 + (i
[6] >> 4));
473 /*! \brief unpacks bytes (7 bit encoding) at i, len l septets,
474 and places in udh and ud setting udhl and udl. udh not used
476 static void unpacksms7 (unsigned char *i
, unsigned char l
, unsigned char *udh
, int *udhl
, unsigned short *ud
, int *udl
, char udhi
)
478 unsigned char b
= 0, p
= 0;
479 unsigned short *o
= ud
;
481 if (udhi
&& l
) { /* header */
498 /* adjust for fill, septets */
508 v
= ((i
[p
] >> b
) & 0x7F);
510 v
= ((((i
[p
] >> b
) + (i
[p
+ 1] << (8 - b
)))) & 0x7F);
516 if (o
> ud
&& o
[-1] == 0x00A0 && escapes
[v
])
519 *o
++ = defaultalphabet
[v
];
524 /*! \brief unpacks bytes (8 bit encoding) at i, len l septets,
525 and places in udh and ud setting udhl and udl. udh not used
527 static void unpacksms8 (unsigned char *i
, unsigned char l
, unsigned char *udh
, int *udhl
, unsigned short *ud
, int *udl
, char udhi
)
529 unsigned short *o
= ud
;
545 *o
++ = *i
++; /* not to UTF-8 as explicitely 8 bit coding in DCS */
549 /*! \brief unpacks bytes (16 bit encoding) at i, len l septets,
550 and places in udh and ud setting udhl and udl.
551 udh not used if udhi not set */
552 static void unpacksms16 (unsigned char *i
, unsigned char l
, unsigned char *udh
, int *udhl
, unsigned short *ud
, int *udl
, char udhi
)
554 unsigned short *o
= ud
;
578 /*! \brief general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
579 static int unpacksms (unsigned char dcs
, unsigned char *i
, unsigned char *udh
, int *udhl
, unsigned short *ud
, int *udl
, char udhi
)
583 unpacksms7 (i
, l
, udh
, udhl
, ud
, udl
, udhi
);
584 l
= (l
* 7 + 7) / 8; /* adjust length to return */
585 } else if (is8bit (dcs
))
586 unpacksms8 (i
, l
, udh
, udhl
, ud
, udl
, udhi
);
588 unpacksms16 (i
, l
, udh
, udhl
, ud
, udl
, udhi
);
592 /*! \brief unpack an address from i, return byte length, unpack to o */
593 static unsigned char unpackaddress (char *o
, unsigned char *i
)
595 unsigned char l
= i
[0],
599 for (p
= 0; p
< l
; p
++) {
601 *o
++ = (i
[2 + p
/ 2] >> 4) + '0';
603 *o
++ = (i
[2 + p
/ 2] & 0xF) + '0';
609 /*! \brief store an address at o, and return number of bytes used */
610 static unsigned char packaddress (unsigned char *o
, char *i
)
622 o
[p
++] |= ((*i
& 0xF) << 4);
630 o
[p
++] |= 0xF0; /* pad */
634 /*! \brief Log the output, and remove file */
635 static void sms_log (sms_t
* h
, char status
)
637 if (*h
->oa
|| *h
->da
) {
638 int o
= open (log_file
, O_CREAT
| O_APPEND
| O_WRONLY
, 0666);
640 char line
[1000], mrs
[3] = "", *p
;
644 snprintf (mrs
, sizeof (mrs
), "%02X", h
->mr
);
645 snprintf (line
, sizeof (line
), "%s %c%c%c%s %s %s %s ",
646 isodate (time (0)), status
, h
->rx
? 'I' : 'O', h
->smsc
? 'S' : 'M', mrs
, h
->queue
, *h
->oa
? h
->oa
: "-",
647 *h
->da
? h
->da
: "-");
648 p
= line
+ strlen (line
);
649 for (n
= 0; n
< h
->udl
; n
++)
650 if (h
->ud
[n
] == '\\') {
653 } else if (h
->ud
[n
] == '\n') {
656 } else if (h
->ud
[n
] == '\r') {
659 } else if (h
->ud
[n
] < 32 || h
->ud
[n
] == 127)
665 write (o
, line
, strlen (line
));
668 *h
->oa
= *h
->da
= h
->udl
= 0;
672 /*! \brief parse and delete a file */
673 static void sms_readfile (sms_t
* h
, char *fn
)
677 char dcsset
= 0; /* if DSC set */
678 ast_log (LOG_EVENT
, "Sending %s\n", fn
);
679 h
->rx
= h
->udl
= *h
->oa
= *h
->da
= h
->pid
= h
->srr
= h
->udhi
= h
->rp
= h
->vp
= h
->udhl
= 0;
681 h
->dcs
= 0xF1; /* normal messages class 1 */
687 { /* concurrent access, we lost */
691 while (fgets (line
, sizeof (line
), s
))
692 { /* process line in file */
695 for (p
= line
; *p
&& *p
!= '\n' && *p
!= '\r'; p
++);
696 *p
= 0; /* strip eoln */
698 if (!*p
|| *p
== ';')
699 continue; /* blank line or comment, ignore */
710 if (!strcmp (line
, "ud"))
711 { /* parse message (UTF-8) */
713 while (*p
&& o
< SMSLEN
)
714 h
->ud
[o
++] = utf8decode(pp
);
717 ast_log (LOG_WARNING
, "UD too long in %s\n", fn
);
722 if (!strcmp (line
, "oa") && strlen (p
) < sizeof (h
->oa
))
724 else if (!strcmp (line
, "da") && strlen (p
) < sizeof (h
->oa
))
726 else if (!strcmp (line
, "pid"))
728 else if (!strcmp (line
, "dcs"))
732 } else if (!strcmp (line
, "mr"))
734 else if (!strcmp (line
, "srr"))
735 h
->srr
= (atoi (p
) ? 1 : 0);
736 else if (!strcmp (line
, "vp"))
738 else if (!strcmp (line
, "rp"))
739 h
->rp
= (atoi (p
) ? 1 : 0);
740 else if (!strcmp (line
, "scts"))
741 { /* get date/time */
748 if (sscanf (p
, "%d-%d-%dT%d:%d:%d", &Y
, &m
, &d
, &H
, &M
, &S
) == 6)
751 t
.tm_year
= Y
- 1900;
758 h
->scts
= mktime (&t
);
759 if (h
->scts
== (time_t) - 1)
760 ast_log (LOG_WARNING
, "Bad date/timein %s: %s", fn
, p
);
763 ast_log (LOG_WARNING
, "Cannot parse in %s: %s=%si\n", fn
, line
, p
);
765 } else if (*p
== '#')
766 { /* raw hex format */
771 if (!strcmp (line
, "ud"))
774 while (*p
&& o
< SMSLEN
)
776 if (isxdigit (*p
) && isxdigit (p
[1]) && isxdigit (p
[2]) && isxdigit (p
[3]))
779 (((isalpha (*p
) ? 9 : 0) + (*p
& 0xF)) << 12) +
780 (((isalpha (p
[1]) ? 9 : 0) + (p
[1] & 0xF)) << 8) +
781 (((isalpha (p
[2]) ? 9 : 0) + (p
[2] & 0xF)) << 4) + ((isalpha (p
[3]) ? 9 : 0) + (p
[3] & 0xF));
788 ast_log (LOG_WARNING
, "UD too long / invalid UCS-2 hex in %s\n", fn
);
790 ast_log (LOG_WARNING
, "Only ud can use ## format, %s\n", fn
);
791 } else if (!strcmp (line
, "ud"))
794 while (*p
&& o
< SMSLEN
)
796 if (isxdigit (*p
) && isxdigit (p
[1]))
798 h
->ud
[o
++] = (((isalpha (*p
) ? 9 : 0) + (*p
& 0xF)) << 4) + ((isalpha (p
[1]) ? 9 : 0) + (p
[1] & 0xF));
805 ast_log (LOG_WARNING
, "UD too long / invalid UCS-1 hex in %s\n", fn
);
806 } else if (!strcmp (line
, "udh"))
807 { /* user data header */
810 while (*p
&& o
< SMSLEN
)
812 if (isxdigit (*p
) && isxdigit (p
[1]))
814 h
->udh
[o
] = (((isalpha (*p
) ? 9 : 0) + (*p
& 0xF)) << 4) + ((isalpha (p
[1]) ? 9 : 0) + (p
[1] & 0xF));
822 ast_log (LOG_WARNING
, "UDH too long / invalid hex in %s\n", fn
);
824 ast_log (LOG_WARNING
, "Only ud and udh can use # format, %s\n", fn
);
826 ast_log (LOG_WARNING
, "Cannot parse in %s: %s\n", fn
, line
);
829 if (!dcsset
&& packsms7 (0, h
->udhl
, h
->udh
, h
->udl
, h
->ud
) < 0)
831 if (packsms8 (0, h
->udhl
, h
->udh
, h
->udl
, h
->ud
) < 0)
833 if (packsms16 (0, h
->udhl
, h
->udh
, h
->udl
, h
->ud
) < 0)
834 ast_log (LOG_WARNING
, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn
);
837 h
->dcs
= 0x08; /* default to 16 bit */
838 ast_log (LOG_WARNING
, "Sending in 16 bit format (%s)\n", fn
);
842 h
->dcs
= 0xF5; /* default to 8 bit */
843 ast_log (LOG_WARNING
, "Sending in 8 bit format (%s)\n", fn
);
846 if (is7bit (h
->dcs
) && packsms7 (0, h
->udhl
, h
->udh
, h
->udl
, h
->ud
) < 0)
847 ast_log (LOG_WARNING
, "Invalid 7 bit GSM data %s\n", fn
);
848 if (is8bit (h
->dcs
) && packsms8 (0, h
->udhl
, h
->udh
, h
->udl
, h
->ud
) < 0)
849 ast_log (LOG_WARNING
, "Invalid 8 bit data %s\n", fn
);
850 if (is16bit (h
->dcs
) && packsms16 (0, h
->udhl
, h
->udh
, h
->udl
, h
->ud
) < 0)
851 ast_log (LOG_WARNING
, "Invalid 16 bit data %s\n", fn
);
855 /*! \brief white a received text message to a file */
856 static void sms_writefile (sms_t
* h
)
858 char fn
[200] = "", fn2
[200] = "";
860 ast_copy_string (fn
, spool_dir
, sizeof (fn
));
861 mkdir (fn
, 0777); /* ensure it exists */
862 snprintf (fn
+ strlen (fn
), sizeof (fn
) - strlen (fn
), "/%s", h
->smsc
? h
->rx
? "morx" : "mttx" : h
->rx
? "mtrx" : "motx");
863 mkdir (fn
, 0777); /* ensure it exists */
864 ast_copy_string (fn2
, fn
, sizeof (fn2
));
865 snprintf (fn2
+ strlen (fn2
), sizeof (fn2
) - strlen (fn2
), "/%s.%s-%d", h
->queue
, isodate (h
->scts
), seq
++);
866 snprintf (fn
+ strlen (fn
), sizeof (fn
) - strlen (fn
), "/.%s", fn2
+ strlen (fn
) + 1);
870 fprintf (o
, "oa=%s\n", h
->oa
);
872 fprintf (o
, "da=%s\n", h
->da
);
876 for (p
= 0; p
< h
->udhl
; p
++)
877 fprintf (o
, "%02X", h
->udh
[p
]);
882 for (p
= 0; p
< h
->udl
&& h
->ud
[p
] >= ' '; p
++);
884 fputc (';', o
); /* cannot use ud=, but include as a comment for human readable */
886 for (p
= 0; p
< h
->udl
; p
++) {
887 unsigned short v
= h
->ud
[p
];
894 fputc (0xC0 + (v
>> 6), o
);
895 fputc (0x80 + (v
& 0x3F), o
);
898 fputc (0xE0 + (v
>> 12), o
);
899 fputc (0x80 + ((v
>> 6) & 0x3F), o
);
900 fputc (0x80 + (v
& 0x3F), o
);
904 for (p
= 0; p
< h
->udl
&& h
->ud
[p
] >= ' '; p
++);
906 for (p
= 0; p
< h
->udl
&& h
->ud
[p
] < 0x100; p
++);
907 if (p
== h
->udl
) { /* can write in ucs-1 hex */
909 for (p
= 0; p
< h
->udl
; p
++)
910 fprintf (o
, "%02X", h
->ud
[p
]);
912 } else { /* write in UCS-2 */
914 for (p
= 0; p
< h
->udl
; p
++)
915 fprintf (o
, "%04X", h
->ud
[p
]);
921 fprintf (o
, "scts=%s\n", isodate (h
->scts
));
923 fprintf (o
, "pid=%d\n", h
->pid
);
925 fprintf (o
, "dcs=%d\n", h
->dcs
);
927 fprintf (o
, "vp=%d\n", h
->vp
);
929 fprintf (o
, "srr=1\n");
931 fprintf (o
, "mr=%d\n", h
->mr
);
933 fprintf (o
, "rp=1\n");
935 if (rename (fn
, fn2
))
938 ast_log (LOG_EVENT
, "Received to %s\n", fn2
);
942 /*! \brief read dir skipping dot files... */
943 static struct dirent
*readdirqueue (DIR * d
, char *queue
)
948 } while (f
&& (*f
->d_name
== '.' || strncmp (f
->d_name
, queue
, strlen (queue
)) || f
->d_name
[strlen (queue
)] != '.'));
952 /*! \brief handle the incoming message */
953 static unsigned char sms_handleincoming (sms_t
* h
)
956 if (h
->smsc
) { /* SMSC */
957 if ((h
->imsg
[2] & 3) == 1) { /* SMS-SUBMIT */
958 h
->udhl
= h
->udl
= 0;
960 h
->srr
= ((h
->imsg
[2] & 0x20) ? 1 : 0);
961 h
->udhi
= ((h
->imsg
[2] & 0x40) ? 1 : 0);
962 h
->rp
= ((h
->imsg
[2] & 0x80) ? 1 : 0);
963 ast_copy_string (h
->oa
, h
->cli
, sizeof (h
->oa
));
965 h
->mr
= h
->imsg
[p
++];
966 p
+= unpackaddress (h
->da
, h
->imsg
+ p
);
967 h
->pid
= h
->imsg
[p
++];
968 h
->dcs
= h
->imsg
[p
++];
969 if ((h
->imsg
[2] & 0x18) == 0x10) { /* relative VP */
970 if (h
->imsg
[p
] < 144)
971 h
->vp
= (h
->imsg
[p
] + 1) * 5;
972 else if (h
->imsg
[p
] < 168)
973 h
->vp
= 720 + (h
->imsg
[p
] - 143) * 30;
974 else if (h
->imsg
[p
] < 197)
975 h
->vp
= (h
->imsg
[p
] - 166) * 1440;
977 h
->vp
= (h
->imsg
[p
] - 192) * 10080;
979 } else if (h
->imsg
[2] & 0x18)
980 p
+= 7; /* ignore enhanced / absolute VP */
981 p
+= unpacksms (h
->dcs
, h
->imsg
+ p
, h
->udh
, &h
->udhl
, h
->ud
, &h
->udl
, h
->udhi
);
982 h
->rx
= 1; /* received message */
983 sms_writefile (h
); /* write the file */
984 if (p
!= h
->imsg
[1] + 2) {
985 ast_log (LOG_WARNING
, "Mismatch receive unpacking %d/%d\n", p
, h
->imsg
[1] + 2);
986 return 0xFF; /* duh! */
989 ast_log (LOG_WARNING
, "Unknown message type %02X\n", h
->imsg
[2]);
992 } else { /* client */
993 if (!(h
->imsg
[2] & 3)) { /* SMS-DELIVER */
994 *h
->da
= h
->srr
= h
->rp
= h
->vp
= h
->udhi
= h
->udhl
= h
->udl
= 0;
995 h
->srr
= ((h
->imsg
[2] & 0x20) ? 1 : 0);
996 h
->udhi
= ((h
->imsg
[2] & 0x40) ? 1 : 0);
997 h
->rp
= ((h
->imsg
[2] & 0x80) ? 1 : 0);
999 p
+= unpackaddress (h
->oa
, h
->imsg
+ p
);
1000 h
->pid
= h
->imsg
[p
++];
1001 h
->dcs
= h
->imsg
[p
++];
1002 h
->scts
= unpackdate (h
->imsg
+ p
);
1004 p
+= unpacksms (h
->dcs
, h
->imsg
+ p
, h
->udh
, &h
->udhl
, h
->ud
, &h
->udl
, h
->udhi
);
1005 h
->rx
= 1; /* received message */
1006 sms_writefile (h
); /* write the file */
1007 if (p
!= h
->imsg
[1] + 2) {
1008 ast_log (LOG_WARNING
, "Mismatch receive unpacking %d/%d\n", p
, h
->imsg
[1] + 2);
1009 return 0xFF; /* duh! */
1012 ast_log (LOG_WARNING
, "Unknown message type %02X\n", h
->imsg
[2]);
1016 return 0; /* no error */
1020 #define NAME_MAX 1024
1023 /*! \brief find and fill in next message, or send a REL if none waiting */
1024 static void sms_nextoutgoing (sms_t
* h
)
1026 char fn
[100 + NAME_MAX
] = "";
1029 ast_copy_string (fn
, spool_dir
, sizeof (fn
));
1030 mkdir (fn
, 0777); /* ensure it exists */
1031 h
->rx
= 0; /* outgoing message */
1032 snprintf (fn
+ strlen (fn
), sizeof (fn
) - strlen (fn
), "/%s", h
->smsc
? "mttx" : "motx");
1033 mkdir (fn
, 0777); /* ensure it exists */
1036 struct dirent
*f
= readdirqueue (d
, h
->queue
);
1038 snprintf (fn
+ strlen (fn
), sizeof (fn
) - strlen (fn
), "/%s", f
->d_name
);
1039 sms_readfile (h
, fn
);
1040 if (readdirqueue (d
, h
->queue
))
1041 more
= 1; /* more to send */
1045 if (*h
->da
|| *h
->oa
) { /* message to send */
1046 unsigned char p
= 2;
1047 h
->omsg
[0] = 0x91; /* SMS_DATA */
1048 if (h
->smsc
) { /* deliver */
1049 h
->omsg
[p
++] = (more
? 4 : 0);
1050 p
+= packaddress (h
->omsg
+ p
, h
->oa
);
1051 h
->omsg
[p
++] = h
->pid
;
1052 h
->omsg
[p
++] = h
->dcs
;
1053 packdate (h
->omsg
+ p
, h
->scts
);
1055 p
+= packsms (h
->dcs
, h
->omsg
+ p
, h
->udhl
, h
->udh
, h
->udl
, h
->ud
);
1056 } else { /* submit */
1058 0x01 + (more
? 4 : 0) + (h
->srr
? 0x20 : 0) + (h
->rp
? 0x80 : 0) + (h
->vp
? 0x10 : 0) + (h
->udhi
? 0x40 : 0);
1060 h
->mr
= message_ref
++;
1061 h
->omsg
[p
++] = h
->mr
;
1062 p
+= packaddress (h
->omsg
+ p
, h
->da
);
1063 h
->omsg
[p
++] = h
->pid
;
1064 h
->omsg
[p
++] = h
->dcs
;
1065 if (h
->vp
) { /* relative VP */
1067 h
->omsg
[p
++] = (h
->vp
+ 4) / 5 - 1;
1068 else if (h
->vp
< 1440)
1069 h
->omsg
[p
++] = (h
->vp
- 720 + 29) / 30 + 143;
1070 else if (h
->vp
< 43200)
1071 h
->omsg
[p
++] = (h
->vp
+ 1439) / 1440 + 166;
1072 else if (h
->vp
< 635040)
1073 h
->omsg
[p
++] = (h
->vp
+ 10079) / 10080 + 192;
1075 h
->omsg
[p
++] = 255; /* max */
1077 p
+= packsms (h
->dcs
, h
->omsg
+ p
, h
->udhl
, h
->udh
, h
->udl
, h
->ud
);
1081 } else { /* no message */
1082 h
->omsg
[0] = 0x94; /* SMS_REL */
1088 static void sms_debug (char *dir
, unsigned char *msg
)
1090 char txt
[259 * 3 + 1],
1091 *p
= txt
; /* always long enough */
1094 while (q
< n
&& q
< 30) {
1095 sprintf (p
, " %02X", msg
[q
++]);
1100 if (option_verbose
> 2)
1101 ast_verbose (VERBOSE_PREFIX_3
"SMS %s%s\n", dir
, txt
);
1104 static void sms_messagerx(sms_t
* h
)
1106 sms_debug ("RX", h
->imsg
);
1108 switch (h
->imsg
[0]) {
1109 case 0x91: /* SMS_DATA */
1111 unsigned char cause
= sms_handleincoming (h
);
1114 h
->omsg
[0] = 0x95; /* SMS_ACK */
1116 h
->omsg
[2] = 0x00; /* deliver report */
1117 h
->omsg
[3] = 0x00; /* no parameters */
1120 h
->omsg
[0] = 0x96; /* SMS_NACK */
1122 h
->omsg
[2] = 0; /* delivery report */
1123 h
->omsg
[3] = cause
; /* cause */
1124 h
->omsg
[4] = 0; /* no parameters */
1129 case 0x92: /* SMS_ERROR */
1131 sms_messagetx (h
); /* send whatever we sent again */
1133 case 0x93: /* SMS_EST */
1134 sms_nextoutgoing (h
);
1136 case 0x94: /* SMS_REL */
1137 h
->hangup
= 1; /* hangup */
1139 case 0x95: /* SMS_ACK */
1141 sms_nextoutgoing (h
);
1143 case 0x96: /* SMS_NACK */
1146 sms_nextoutgoing (h
);
1148 default: /* Unknown */
1149 h
->omsg
[0] = 0x92; /* SMS_ERROR */
1151 h
->omsg
[2] = 3; /* unknown message type; */
1157 static void sms_messagetx(sms_t
* h
)
1159 unsigned char c
= 0, p
;
1160 for (p
= 0; p
< h
->omsg
[1] + 2; p
++)
1162 h
->omsg
[h
->omsg
[1] + 2] = 0 - c
;
1163 sms_debug ("TX", h
->omsg
);
1166 if (h
->omsg
[0] == 0x93)
1167 h
->opause
= 2400; /* initial message delay 300ms (for BT) */
1171 h
->obyten
= h
->omsg
[1] + 3;
1174 static int sms_generate (struct ast_channel
*chan
, void *data
, int len
, int samples
)
1176 struct ast_frame f
= { 0 };
1177 #define MAXSAMPLES (800)
1183 #define SAMPLE2LEN sizeof(*buf)
1187 if (samples
> MAXSAMPLES
) {
1188 ast_log (LOG_WARNING
, "Only doing %d samples (%d requested)\n",
1189 MAXSAMPLES
, samples
);
1190 samples
= MAXSAMPLES
;
1192 len
= samples
* SAMPLE2LEN
+ AST_FRIENDLY_OFFSET
;
1195 f
.frametype
= AST_FRAME_VOICE
;
1197 f
.subclass
= AST_FORMAT_ALAW
;
1199 f
.subclass
= AST_FORMAT_SLINEAR
;
1202 f
.offset
= AST_FRIENDLY_OFFSET
;
1205 f
.samples
= samples
;
1207 /* create a buffer containing the digital sms pattern */
1208 for (i
= 0; i
< samples
; i
++) {
1216 else if (h
->obyten
|| h
->osync
) { /* sending data */
1218 buf
[i
] = wavea
[h
->ophase
];
1220 buf
[i
] = wave
[h
->ophase
];
1222 if ((h
->ophase
+= ((h
->obyte
& 1) ? 13 : 21)) >= 80)
1224 if ((h
->ophasep
+= 12) >= 80) { /* next bit */
1227 h
->osync
--; /* sending sync bits */
1232 h
->obyte
= 0; /* start bit; */
1233 else if (h
->obitp
== 2)
1234 h
->obyte
= h
->omsg
[h
->obytep
];
1235 else if (h
->obitp
== 10) {
1236 h
->obyte
= 1; /* stop bit */
1239 if (h
->obytep
== h
->obyten
) {
1240 h
->obytep
= h
->obyten
= 0; /* sent */
1241 h
->osync
= 10; /* trailing marks */
1248 if (ast_write (chan
, &f
) < 0) {
1249 ast_log (LOG_WARNING
, "Failed to write frame to '%s': %s\n", chan
->name
, strerror (errno
));
1257 static void sms_process (sms_t
* h
, int samples
, signed short *data
)
1259 if (h
->obyten
|| h
->osync
)
1260 return; /* sending */
1262 unsigned long long m0
, m1
;
1263 if (abs (*data
) > h
->imag
)
1264 h
->imag
= abs (*data
);
1266 h
->imag
= h
->imag
* 7 / 8;
1267 if (h
->imag
> 500) {
1269 h
->ims0
= (h
->ims0
* 6 + *data
* wave
[h
->ips0
]) / 7;
1270 h
->imc0
= (h
->imc0
* 6 + *data
* wave
[h
->ipc0
]) / 7;
1271 h
->ims1
= (h
->ims1
* 6 + *data
* wave
[h
->ips1
]) / 7;
1272 h
->imc1
= (h
->imc1
* 6 + *data
* wave
[h
->ipc1
]) / 7;
1273 m0
= h
->ims0
* h
->ims0
+ h
->imc0
* h
->imc0
;
1274 m1
= h
->ims1
* h
->ims1
+ h
->imc1
* h
->imc1
;
1275 if ((h
->ips0
+= 21) >= 80)
1277 if ((h
->ipc0
+= 21) >= 80)
1279 if ((h
->ips1
+= 13) >= 80)
1281 if ((h
->ipc1
+= 13) >= 80)
1292 bit
= ((h
->ibitt
> 1) ? 1 : 0);
1293 if (bit
!= h
->ibitl
)
1298 if (!h
->ibitn
&& h
->ibitc
== 4 && !bit
) {
1302 if (bit
&& h
->ibitc
== 200) { /* sync, restart message */
1303 h
->ierr
= h
->ibitn
= h
->ibytep
= h
->ibytec
= 0;
1307 if (h
->iphasep
>= 80) { /* next bit */
1309 if (h
->ibitn
++ == 9) { /* end of byte */
1310 if (!bit
) /* bad stop bit */
1311 h
->ierr
= 0xFF; /* unknown error */
1313 if (h
->ibytep
< sizeof (h
->imsg
)) {
1314 h
->imsg
[h
->ibytep
] = h
->ibytev
;
1315 h
->ibytec
+= h
->ibytev
;
1317 } else if (h
->ibytep
== sizeof (h
->imsg
))
1318 h
->ierr
= 2; /* bad message length */
1319 if (h
->ibytep
> 1 && h
->ibytep
== 3 + h
->imsg
[1] && !h
->ierr
) {
1323 h
->ierr
= 1; /* bad checksum */
1328 h
->ibytev
= (h
->ibytev
>> 1) + (bit
? 0x80 : 0);
1332 } else { /* lost carrier */
1333 if (h
->idle
++ == 80000) { /* nothing happening */
1334 ast_log (LOG_EVENT
, "No data, hanging up\n");
1338 if (h
->ierr
) { /* error */
1340 h
->omsg
[0] = 0x92; /* error */
1342 h
->omsg
[2] = h
->ierr
;
1343 sms_messagetx (h
); /* send error */
1345 h
->ierr
= h
->ibitn
= h
->ibytep
= h
->ibytec
= 0;
1351 static struct ast_generator smsgen
= {
1353 release
:sms_release
,
1354 generate
:sms_generate
,
1357 static int sms_exec (struct ast_channel
*chan
, void *data
)
1360 struct ast_module_user
*u
;
1361 struct ast_frame
*f
;
1364 u
= ast_module_user_add(chan
);
1366 h
.ipc0
= h
.ipc1
= 20; /* phase for cosine */
1367 h
.dcs
= 0xF1; /* default */
1369 ast_log (LOG_ERROR
, "Requires queue name at least\n");
1370 ast_module_user_remove(u
);
1374 if (chan
->cid
.cid_num
)
1375 ast_copy_string (h
.cli
, chan
->cid
.cid_num
, sizeof (h
.cli
));
1379 unsigned char *d
= data
,
1381 if (!*d
|| *d
== '|') {
1382 ast_log (LOG_ERROR
, "Requires queue name\n");
1383 ast_module_user_remove(u
);
1386 for (p
= d
; *p
&& *p
!= '|'; p
++);
1387 if (p
- d
>= sizeof (h
.queue
)) {
1388 ast_log (LOG_ERROR
, "Queue name too long\n");
1389 ast_module_user_remove(u
);
1392 strncpy (h
.queue
, (char *)d
, p
- d
);
1396 for (p
= (unsigned char *)h
.queue
; *p
; p
++)
1398 *p
= '-'; /* make very safe for filenames */
1399 while (*d
&& *d
!= '|') {
1401 case 'a': /* we have to send the initial FSK sequence */
1404 case 's': /* we are acting as a service centre talking to a phone */
1407 /* the following apply if there is an arg3/4 and apply to the created message file */
1412 h
.dcs
|= 4; /* octets */
1420 case '7': /* set the pid for saved local message */
1421 h
.pid
= 0x40 + (*d
& 0xF);
1427 /* submitting a message, not taking call. */
1428 /* deprecated, use smsq instead */
1431 for (p
= d
; *p
&& *p
!= '|'; p
++);
1434 if (strlen ((char *)d
) >= sizeof (h
.oa
)) {
1435 ast_log (LOG_ERROR
, "Address too long %s\n", d
);
1439 ast_copy_string (h
.oa
, (char *)d
, sizeof (h
.oa
));
1441 ast_copy_string (h
.da
, (char *)d
, sizeof (h
.da
));
1444 ast_copy_string (h
.oa
, h
.cli
, sizeof (h
.oa
));
1447 while (*p
&& h
.udl
< SMSLEN
)
1448 h
.ud
[h
.udl
++] = utf8decode(&p
);
1449 if (is7bit (h
.dcs
) && packsms7 (0, h
.udhl
, h
.udh
, h
.udl
, h
.ud
) < 0)
1450 ast_log (LOG_WARNING
, "Invalid 7 bit GSM data\n");
1451 if (is8bit (h
.dcs
) && packsms8 (0, h
.udhl
, h
.udh
, h
.udl
, h
.ud
) < 0)
1452 ast_log (LOG_WARNING
, "Invalid 8 bit data\n");
1453 if (is16bit (h
.dcs
) && packsms16 (0, h
.udhl
, h
.udh
, h
.udl
, h
.ud
) < 0)
1454 ast_log (LOG_WARNING
, "Invalid 16 bit data\n");
1455 h
.rx
= 0; /* sent message */
1458 ast_module_user_remove(u
);
1463 /* set up SMS_EST initial message */
1470 if (chan
->_state
!= AST_STATE_UP
)
1474 res
= ast_set_write_format (chan
, AST_FORMAT_ALAW
);
1476 res
= ast_set_write_format (chan
, AST_FORMAT_SLINEAR
);
1479 res
= ast_set_read_format (chan
, AST_FORMAT_SLINEAR
);
1481 ast_log (LOG_ERROR
, "Unable to set to linear mode, giving up\n");
1482 ast_module_user_remove(u
);
1486 if (ast_activate_generator (chan
, &smsgen
, &h
) < 0) {
1487 ast_log (LOG_ERROR
, "Failed to activate generator on '%s'\n", chan
->name
);
1488 ast_module_user_remove(u
);
1492 /* Do our thing here */
1493 while (ast_waitfor (chan
, -1) > -1 && !h
.hangup
)
1495 f
= ast_read (chan
);
1498 if (f
->frametype
== AST_FRAME_VOICE
) {
1499 sms_process (&h
, f
->samples
, f
->data
);
1505 sms_log (&h
, '?'); /* log incomplete message */
1507 ast_module_user_remove(u
);
1511 static int unload_module(void)
1515 res
= ast_unregister_application (app
);
1517 ast_module_user_hangup_all();
1522 static int load_module(void)
1527 for (p
= 0; p
< 80; p
++)
1528 wavea
[p
] = AST_LIN2A (wave
[p
]);
1531 snprintf (log_file
, sizeof (log_file
), "%s/sms", ast_config_AST_LOG_DIR
);
1532 snprintf (spool_dir
, sizeof (spool_dir
), "%s/sms", ast_config_AST_SPOOL_DIR
);
1533 return ast_register_application (app
, sms_exec
, synopsis
, descrip
);
1536 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY
, "SMS/PSTN handler");