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 *tdesc = "SMS/PSTN handler";
66 static char *app = "SMS";
68 static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
70 static char *descrip =
71 " SMS(name|[a][s]): SMS handles exchange of SMS data with a call to/from SMS capabale\n"
72 "phone or SMS PSTN service center. Can send and/or receive SMS messages.\n"
73 "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n"
74 "Typical usage is to use to handle called from the SMS service centre CLI,\n"
75 "or to set up a call using 'outgoing' or manager interface to connect\n"
76 "service centre to SMS()\n"
77 "name is the name of the queue used in /var/spool/asterisk/sms\n"
79 " a: answer, i.e. send initial FSK packet.\n"
80 " s: act as service centre talking to a phone.\n"
81 "Messages are processed as per text file message queues.\n"
82 "smsq (a separate software) is a command to generate message\n"
83 "queues and send messages.\n";
85 static signed short wave[] = {
86 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
87 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
89 -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
91 -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
95 static unsigned char wavea[80];
100 /* SMS 7 bit character mapping to UCS-2 */
101 static const unsigned short defaultalphabet[] = {
102 0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
103 0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
104 0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
105 0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
106 ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
107 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
108 161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
109 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
110 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
111 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
114 static const unsigned short escapes[] = {
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x000C, 0, 0, 0, 0, 0,
116 0, 0, 0, 0, 0x005E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117 0, 0, 0, 0, 0, 0, 0, 0, 0x007B, 0x007D, 0, 0, 0, 0, 0, 0x005C,
118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x005B, 0x007E, 0x005D, 0,
119 0x007C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121 0, 0, 0, 0, 0, 0x20AC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
125 #define SMSLEN 160 /* max SMS length */
129 unsigned char hangup; /* we are done... */
130 unsigned char err; /* set for any errors */
131 unsigned char smsc:1; /* we are SMSC */
132 unsigned char rx:1; /* this is a received message */
133 char queue[30]; /* queue name */
134 char oa[20]; /* originating address */
135 char da[20]; /* destination address */
136 time_t scts; /* time stamp, UTC */
137 unsigned char pid; /* protocol ID */
138 unsigned char dcs; /* data coding scheme */
139 short mr; /* message reference - actually a byte, but usde -1 for not set */
140 int udl; /* user data length */
141 int udhl; /* user data header length */
142 unsigned char srr:1; /* Status Report request */
143 unsigned char udhi:1; /* User Data Header required, even if length 0 */
144 unsigned char rp:1; /* Reply Path */
145 unsigned int vp; /* validity period in minutes, 0 for not set */
146 unsigned short ud[SMSLEN]; /* user data (message), UCS-2 coded */
147 unsigned char udh[SMSLEN]; /* user data header */
148 char cli[20]; /* caller ID */
149 unsigned char ophase; /* phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
150 unsigned char ophasep; /* phase (0-79) for 1200 bps */
151 unsigned char obyte; /* byte being sent */
152 unsigned int opause; /* silent pause before sending (in sample periods) */
153 unsigned char obitp; /* bit in byte */
154 unsigned char osync; /* sync bits to send */
155 unsigned char obytep; /* byte in data */
156 unsigned char obyten; /* bytes in data */
157 unsigned char omsg[256]; /* data buffer (out) */
158 unsigned char imsg[200]; /* data buffer (in) */
159 signed long long ims0,
162 imc1; /* magnitude averages sin/cos 0/1 */
164 unsigned short imag; /* signal level */
168 ipc1; /* phase sin/cos 0/1 */
169 unsigned char ibitl; /* last bit */
170 unsigned char ibitc; /* bit run length count */
171 unsigned char iphasep; /* bit phase (0-79) for 1200 bps */
172 unsigned char ibitn; /* bit number in byte being received */
173 unsigned char ibytev; /* byte value being received */
174 unsigned char ibytep; /* byte pointer in messafe */
175 unsigned char ibytec; /* byte checksum for message */
176 unsigned char ierr; /* error flag */
177 unsigned char ibith; /* history of last bits */
178 unsigned char ibitt; /* total of 1's in last 3 bites */
179 /* more to go here */
182 /* different types of encoding */
183 #define is7bit(dcs) (((dcs)&0xC0)?(!((dcs)&4)):(!((dcs)&12)))
184 #define is8bit(dcs) (((dcs)&0xC0)?(((dcs)&4)):(((dcs)&12)==4))
185 #define is16bit(dcs) (((dcs)&0xC0)?0:(((dcs)&12)==8))
187 static void *sms_alloc (struct ast_channel *chan, void *params)
192 static void sms_release (struct ast_channel *chan, void *data)
197 static void sms_messagetx (sms_t * h);
199 /*! \brief copy number, skipping non digits apart from leading + */
200 static void numcpy (char *d, char *s)
212 /*! \brief static, return a date/time in ISO format */
213 static char * isodate (time_t t)
215 static char date[20];
216 strftime (date, sizeof (date), "%Y-%m-%dT%H:%M:%S", localtime (&t));
220 /*! \brief reads next UCS character from null terminated UTF-8 string and advanced pointer */
221 /* for non valid UTF-8 sequences, returns character as is */
222 /* Does not advance pointer for null termination */
223 static long utf8decode (unsigned char **pp)
225 unsigned char *p = *pp;
227 return 0; /* null termination of string */
230 return *p; /* ascii or continuation character */
232 if (*p < 0xC2 || (p[1] & 0xC0) != 0x80)
233 return *p; /* not valid UTF-8 */
235 return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
238 if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80)
239 return *p; /* not valid UTF-8 */
241 return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
244 if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80)
245 return *p; /* not valid UTF-8 */
247 return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
250 if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
251 || (p[4] & 0xC0) != 0x80)
252 return *p; /* not valid UTF-8 */
254 return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
257 if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
258 || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80)
259 return *p; /* not valid UTF-8 */
261 return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F);
263 return *p; /* not sensible */
266 /*! \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 */
267 /* The return value is the number of septets packed in to o, which is internally limited to SMSLEN */
268 /* o can be null, in which case this is used to validate or count only */
269 /* if the input contains invalid characters then the return value is -1 */
270 static int packsms7 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
272 unsigned char p = 0, b = 0, n = 0;
274 if (udhl) { /* header */
294 }; /* filling to septet boundary */
303 for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
304 if (v == 128 && u && n + 1 < SMSLEN) {
305 for (v = 0; v < 128 && escapes[v] != u; v++);
306 if (v < 128) { /* escaped sequence */
314 o[p] = (27 >> (7 - b));
320 return -1; /* invalid character */
328 o[p] = (v >> (7 - b));
336 /*! \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 */
337 /* The return value is the number of bytes packed in to o, which is internally limited to 140 */
338 /* o can be null, in which case this is used to validate or count only */
339 /* if the input contains invalid characters then the return value is -1 */
340 static int packsms8 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
344 /* header - no encoding */
358 if (u < 0 || u > 0xFF)
359 return -1; /* not valid */
368 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2
369 message (udl characters at ud) and packs in to o using 16 bit
370 UCS-2 character codes
371 The return value is the number of bytes packed in to o, which is
372 internally limited to 140
373 o can be null, in which case this is used to validate or count
374 only if the input contains invalid characters then
375 the return value is -1 */
376 static int packsms16 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
379 /* header - no encoding */
396 return p - 1; /* could not fit last character */
405 /*! \brief general pack, with length and data,
406 returns number of bytes of target used */
407 static int packsms (unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
409 unsigned char *p = base;
412 if (is7bit (dcs)) { /* 7 bit */
413 l = packsms7 (p + 1, udhl, udh, udl, ud);
417 p += (l * 7 + 7) / 8;
418 } else if (is8bit (dcs)) { /* 8 bit */
419 l = packsms8 (p + 1, udhl, udh, udl, ud);
425 l = packsms16 (p + 1, udhl, udh, udl, ud);
432 *p++ = 0; /* no user data */
437 /*! \brief pack a date and return */
438 static void packdate (unsigned char *o, time_t w)
440 struct tm *t = localtime (&w);
441 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
442 int z = -t->tm_gmtoff / 60 / 15;
444 int z = timezone / 60 / 15;
446 *o++ = ((t->tm_year % 10) << 4) + (t->tm_year % 100) / 10;
447 *o++ = (((t->tm_mon + 1) % 10) << 4) + (t->tm_mon + 1) / 10;
448 *o++ = ((t->tm_mday % 10) << 4) + t->tm_mday / 10;
449 *o++ = ((t->tm_hour % 10) << 4) + t->tm_hour / 10;
450 *o++ = ((t->tm_min % 10) << 4) + t->tm_min / 10;
451 *o++ = ((t->tm_sec % 10) << 4) + t->tm_sec / 10;
453 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
455 *o++ = ((z % 10) << 4) + z / 10;
458 /*! \brief unpack a date and return */
459 static time_t unpackdate (unsigned char *i)
462 t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
463 t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
464 t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
465 t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
466 t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
467 t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
470 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
472 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
476 /*! \brief unpacks bytes (7 bit encoding) at i, len l septets,
477 and places in udh and ud setting udhl and udl. udh not used
479 static void unpacksms7 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
481 unsigned char b = 0, p = 0;
482 unsigned short *o = ud;
484 if (udhi && l) { /* header */
501 /* adjust for fill, septets */
511 v = ((i[p] >> b) & 0x7F);
513 v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
519 if (o > ud && o[-1] == 0x00A0 && escapes[v])
522 *o++ = defaultalphabet[v];
527 /*! \brief unpacks bytes (8 bit encoding) at i, len l septets,
528 and places in udh and ud setting udhl and udl. udh not used
530 static void unpacksms8 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
532 unsigned short *o = ud;
548 *o++ = *i++; /* not to UTF-8 as explicitely 8 bit coding in DCS */
552 /*! \brief unpacks bytes (16 bit encoding) at i, len l septets,
553 and places in udh and ud setting udhl and udl.
554 udh not used if udhi not set */
555 static void unpacksms16 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
557 unsigned short *o = ud;
581 /*! \brief general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
582 static int unpacksms (unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
586 unpacksms7 (i, l, udh, udhl, ud, udl, udhi);
587 l = (l * 7 + 7) / 8; /* adjust length to return */
588 } else if (is8bit (dcs))
589 unpacksms8 (i, l, udh, udhl, ud, udl, udhi);
591 unpacksms16 (i, l, udh, udhl, ud, udl, udhi);
595 /*! \brief unpack an address from i, return byte length, unpack to o */
596 static unsigned char unpackaddress (char *o, unsigned char *i)
598 unsigned char l = i[0],
602 for (p = 0; p < l; p++) {
604 *o++ = (i[2 + p / 2] >> 4) + '0';
606 *o++ = (i[2 + p / 2] & 0xF) + '0';
612 /*! \brief store an address at o, and return number of bytes used */
613 static unsigned char packaddress (unsigned char *o, char *i)
625 o[p++] |= ((*i & 0xF) << 4);
633 o[p++] |= 0xF0; /* pad */
637 /*! \brief Log the output, and remove file */
638 static void sms_log (sms_t * h, char status)
640 if (*h->oa || *h->da) {
641 int o = open (log_file, O_CREAT | O_APPEND | O_WRONLY, 0666);
643 char line[1000], mrs[3] = "", *p;
647 snprintf (mrs, sizeof (mrs), "%02X", h->mr);
648 snprintf (line, sizeof (line), "%s %c%c%c%s %s %s %s ",
649 isodate (time (0)), status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue, *h->oa ? h->oa : "-",
650 *h->da ? h->da : "-");
651 p = line + strlen (line);
652 for (n = 0; n < h->udl; n++)
653 if (h->ud[n] == '\\') {
656 } else if (h->ud[n] == '\n') {
659 } else if (h->ud[n] == '\r') {
662 } else if (h->ud[n] < 32 || h->ud[n] == 127)
668 write (o, line, strlen (line));
671 *h->oa = *h->da = h->udl = 0;
675 /*! \brief parse and delete a file */
676 static void sms_readfile (sms_t * h, char *fn)
680 char dcsset = 0; /* if DSC set */
681 ast_log (LOG_EVENT, "Sending %s\n", fn);
682 h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
684 h->dcs = 0xF1; /* normal messages class 1 */
690 { /* concurrent access, we lost */
694 while (fgets (line, sizeof (line), s))
695 { /* process line in file */
697 for (p = line; *p && *p != '\n' && *p != '\r'; p++);
698 *p = 0; /* strip eoln */
700 if (!*p || *p == ';')
701 continue; /* blank line or comment, ignore */
712 if (!strcmp (line, "ud"))
713 { /* parse message (UTF-8) */
715 while (*p && o < SMSLEN)
716 h->ud[o++] = utf8decode((unsigned char **) &p);
719 ast_log (LOG_WARNING, "UD too long in %s\n", fn);
724 if (!strcmp (line, "oa") && strlen (p) < sizeof (h->oa))
726 else if (!strcmp (line, "da") && strlen (p) < sizeof (h->oa))
728 else if (!strcmp (line, "pid"))
730 else if (!strcmp (line, "dcs"))
734 } else if (!strcmp (line, "mr"))
736 else if (!strcmp (line, "srr"))
737 h->srr = (atoi (p) ? 1 : 0);
738 else if (!strcmp (line, "vp"))
740 else if (!strcmp (line, "rp"))
741 h->rp = (atoi (p) ? 1 : 0);
742 else if (!strcmp (line, "scts"))
743 { /* get date/time */
750 if (sscanf (p, "%d-%d-%dT%d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6)
753 t.tm_year = Y - 1900;
760 h->scts = mktime (&t);
761 if (h->scts == (time_t) - 1)
762 ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
765 ast_log (LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
767 } else if (*p == '#')
768 { /* raw hex format */
773 if (!strcmp (line, "ud"))
776 while (*p && o < SMSLEN)
778 if (isxdigit (*p) && isxdigit (p[1]) && isxdigit (p[2]) && isxdigit (p[3]))
781 (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 12) +
782 (((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
783 (((isalpha (p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha (p[3]) ? 9 : 0) + (p[3] & 0xF));
790 ast_log (LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
792 ast_log (LOG_WARNING, "Only ud can use ## format, %s\n", fn);
793 } else if (!strcmp (line, "ud"))
796 while (*p && o < SMSLEN)
798 if (isxdigit (*p) && isxdigit (p[1]))
800 h->ud[o++] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
807 ast_log (LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
808 } else if (!strcmp (line, "udh"))
809 { /* user data header */
812 while (*p && o < SMSLEN)
814 if (isxdigit (*p) && isxdigit (p[1]))
816 h->udh[o] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
824 ast_log (LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
826 ast_log (LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
828 ast_log (LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
831 if (!dcsset && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
833 if (packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
835 if (packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
836 ast_log (LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
839 h->dcs = 0x08; /* default to 16 bit */
840 ast_log (LOG_WARNING, "Sending in 16 bit format (%s)\n", fn);
844 h->dcs = 0xF5; /* default to 8 bit */
845 ast_log (LOG_WARNING, "Sending in 8 bit format (%s)\n", fn);
848 if (is7bit (h->dcs) && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
849 ast_log (LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
850 if (is8bit (h->dcs) && packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
851 ast_log (LOG_WARNING, "Invalid 8 bit data %s\n", fn);
852 if (is16bit (h->dcs) && packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
853 ast_log (LOG_WARNING, "Invalid 16 bit data %s\n", fn);
857 /*! \brief white a received text message to a file */
858 static void sms_writefile (sms_t * h)
860 char fn[200] = "", fn2[200] = "";
862 ast_copy_string (fn, spool_dir, sizeof (fn));
863 mkdir (fn, 0777); /* ensure it exists */
864 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
865 mkdir (fn, 0777); /* ensure it exists */
866 ast_copy_string (fn2, fn, sizeof (fn2));
867 snprintf (fn2 + strlen (fn2), sizeof (fn2) - strlen (fn2), "/%s.%s-%d", h->queue, isodate (h->scts), seq++);
868 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/.%s", fn2 + strlen (fn) + 1);
872 fprintf (o, "oa=%s\n", h->oa);
874 fprintf (o, "da=%s\n", h->da);
878 for (p = 0; p < h->udhl; p++)
879 fprintf (o, "%02X", h->udh[p]);
884 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
886 fputc (';', o); /* cannot use ud=, but include as a comment for human readable */
888 for (p = 0; p < h->udl; p++) {
889 unsigned short v = h->ud[p];
896 fputc (0xC0 + (v >> 6), o);
897 fputc (0x80 + (v & 0x3F), o);
900 fputc (0xE0 + (v >> 12), o);
901 fputc (0x80 + ((v >> 6) & 0x3F), o);
902 fputc (0x80 + (v & 0x3F), o);
906 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
908 for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
909 if (p == h->udl) { /* can write in ucs-1 hex */
911 for (p = 0; p < h->udl; p++)
912 fprintf (o, "%02X", h->ud[p]);
914 } else { /* write in UCS-2 */
916 for (p = 0; p < h->udl; p++)
917 fprintf (o, "%04X", h->ud[p]);
923 fprintf (o, "scts=%s\n", isodate (h->scts));
925 fprintf (o, "pid=%d\n", h->pid);
927 fprintf (o, "dcs=%d\n", h->dcs);
929 fprintf (o, "vp=%d\n", h->vp);
931 fprintf (o, "srr=1\n");
933 fprintf (o, "mr=%d\n", h->mr);
935 fprintf (o, "rp=1\n");
937 if (rename (fn, fn2))
940 ast_log (LOG_EVENT, "Received to %s\n", fn2);
944 /*! \brief read dir skipping dot files... */
945 static struct dirent *readdirqueue (DIR * d, char *queue)
950 } while (f && (*f->d_name == '.' || strncmp (f->d_name, queue, strlen (queue)) || f->d_name[strlen (queue)] != '.'));
954 /*! \brief handle the incoming message */
955 static unsigned char sms_handleincoming (sms_t * h)
958 if (h->smsc) { /* SMSC */
959 if ((h->imsg[2] & 3) == 1) { /* SMS-SUBMIT */
960 h->udhl = h->udl = 0;
962 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
963 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
964 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
965 ast_copy_string (h->oa, h->cli, sizeof (h->oa));
967 h->mr = h->imsg[p++];
968 p += unpackaddress (h->da, h->imsg + p);
969 h->pid = h->imsg[p++];
970 h->dcs = h->imsg[p++];
971 if ((h->imsg[2] & 0x18) == 0x10) { /* relative VP */
972 if (h->imsg[p] < 144)
973 h->vp = (h->imsg[p] + 1) * 5;
974 else if (h->imsg[p] < 168)
975 h->vp = 720 + (h->imsg[p] - 143) * 30;
976 else if (h->imsg[p] < 197)
977 h->vp = (h->imsg[p] - 166) * 1440;
979 h->vp = (h->imsg[p] - 192) * 10080;
981 } else if (h->imsg[2] & 0x18)
982 p += 7; /* ignore enhanced / absolute VP */
983 p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
984 h->rx = 1; /* received message */
985 sms_writefile (h); /* write the file */
986 if (p != h->imsg[1] + 2) {
987 ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
988 return 0xFF; /* duh! */
991 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
994 } else { /* client */
995 if (!(h->imsg[2] & 3)) { /* SMS-DELIVER */
996 *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
997 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
998 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
999 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1001 p += unpackaddress (h->oa, h->imsg + p);
1002 h->pid = h->imsg[p++];
1003 h->dcs = h->imsg[p++];
1004 h->scts = unpackdate (h->imsg + p);
1006 p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1007 h->rx = 1; /* received message */
1008 sms_writefile (h); /* write the file */
1009 if (p != h->imsg[1] + 2) {
1010 ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1011 return 0xFF; /* duh! */
1014 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
1018 return 0; /* no error */
1022 #define NAME_MAX 1024
1025 /*! \brief find and fill in next message, or send a REL if none waiting */
1026 static void sms_nextoutgoing (sms_t * h)
1028 char fn[100 + NAME_MAX] = "";
1031 ast_copy_string (fn, spool_dir, sizeof (fn));
1032 mkdir (fn, 0777); /* ensure it exists */
1033 h->rx = 0; /* outgoing message */
1034 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? "mttx" : "motx");
1035 mkdir (fn, 0777); /* ensure it exists */
1038 struct dirent *f = readdirqueue (d, h->queue);
1040 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", f->d_name);
1041 sms_readfile (h, fn);
1042 if (readdirqueue (d, h->queue))
1043 more = 1; /* more to send */
1047 if (*h->da || *h->oa) { /* message to send */
1048 unsigned char p = 2;
1049 h->omsg[0] = 0x91; /* SMS_DATA */
1050 if (h->smsc) { /* deliver */
1051 h->omsg[p++] = (more ? 4 : 0);
1052 p += packaddress (h->omsg + p, h->oa);
1053 h->omsg[p++] = h->pid;
1054 h->omsg[p++] = h->dcs;
1055 packdate (h->omsg + p, h->scts);
1057 p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1058 } else { /* submit */
1060 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
1062 h->mr = message_ref++;
1063 h->omsg[p++] = h->mr;
1064 p += packaddress (h->omsg + p, h->da);
1065 h->omsg[p++] = h->pid;
1066 h->omsg[p++] = h->dcs;
1067 if (h->vp) { /* relative VP */
1069 h->omsg[p++] = (h->vp + 4) / 5 - 1;
1070 else if (h->vp < 1440)
1071 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
1072 else if (h->vp < 43200)
1073 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
1074 else if (h->vp < 635040)
1075 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
1077 h->omsg[p++] = 255; /* max */
1079 p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1083 } else { /* no message */
1084 h->omsg[0] = 0x94; /* SMS_REL */
1090 static void sms_debug (char *dir, unsigned char *msg)
1092 char txt[259 * 3 + 1],
1093 *p = txt; /* always long enough */
1096 while (q < n && q < 30) {
1097 sprintf (p, " %02X", msg[q++]);
1102 if (option_verbose > 2)
1103 ast_verbose (VERBOSE_PREFIX_3 "SMS %s%s\n", dir, txt);
1106 static void sms_messagerx(sms_t * h)
1108 sms_debug ("RX", h->imsg);
1110 switch (h->imsg[0]) {
1111 case 0x91: /* SMS_DATA */
1113 unsigned char cause = sms_handleincoming (h);
1116 h->omsg[0] = 0x95; /* SMS_ACK */
1118 h->omsg[2] = 0x00; /* deliver report */
1119 h->omsg[3] = 0x00; /* no parameters */
1122 h->omsg[0] = 0x96; /* SMS_NACK */
1124 h->omsg[2] = 0; /* delivery report */
1125 h->omsg[3] = cause; /* cause */
1126 h->omsg[4] = 0; /* no parameters */
1131 case 0x92: /* SMS_ERROR */
1133 sms_messagetx (h); /* send whatever we sent again */
1135 case 0x93: /* SMS_EST */
1136 sms_nextoutgoing (h);
1138 case 0x94: /* SMS_REL */
1139 h->hangup = 1; /* hangup */
1141 case 0x95: /* SMS_ACK */
1143 sms_nextoutgoing (h);
1145 case 0x96: /* SMS_NACK */
1148 sms_nextoutgoing (h);
1150 default: /* Unknown */
1151 h->omsg[0] = 0x92; /* SMS_ERROR */
1153 h->omsg[2] = 3; /* unknown message type; */
1159 static void sms_messagetx(sms_t * h)
1161 unsigned char c = 0, p;
1162 for (p = 0; p < h->omsg[1] + 2; p++)
1164 h->omsg[h->omsg[1] + 2] = 0 - c;
1165 sms_debug ("TX", h->omsg);
1168 if (h->omsg[0] == 0x93)
1169 h->opause = 2400; /* initial message delay 300ms (for BT) */
1173 h->obyten = h->omsg[1] + 3;
1176 static int sms_generate (struct ast_channel *chan, void *data, int len, int samples)
1178 struct ast_frame f = { 0 };
1179 #define MAXSAMPLES (800)
1185 #define SAMPLE2LEN sizeof(*buf)
1189 if (samples > MAXSAMPLES) {
1190 ast_log (LOG_WARNING, "Only doing %d samples (%d requested)\n",
1191 MAXSAMPLES, samples);
1192 samples = MAXSAMPLES;
1194 len = samples * SAMPLE2LEN + AST_FRIENDLY_OFFSET;
1197 f.frametype = AST_FRAME_VOICE;
1199 f.subclass = AST_FORMAT_ALAW;
1201 f.subclass = AST_FORMAT_SLINEAR;
1204 f.offset = AST_FRIENDLY_OFFSET;
1206 f.data = buf + AST_FRIENDLY_OFFSET;
1207 f.samples = samples;
1209 /* create a buffer containing the digital sms pattern */
1210 for (i = 0; i < samples; i++) {
1218 else if (h->obyten || h->osync) { /* sending data */
1220 buf[i] = wavea[h->ophase];
1222 buf[i] = wave[h->ophase];
1224 if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
1226 if ((h->ophasep += 12) >= 80) { /* next bit */
1229 h->osync--; /* sending sync bits */
1234 h->obyte = 0; /* start bit; */
1235 else if (h->obitp == 2)
1236 h->obyte = h->omsg[h->obytep];
1237 else if (h->obitp == 10) {
1238 h->obyte = 1; /* stop bit */
1241 if (h->obytep == h->obyten) {
1242 h->obytep = h->obyten = 0; /* sent */
1243 h->osync = 10; /* trailing marks */
1250 if (ast_write (chan, &f) < 0) {
1251 ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
1259 static void sms_process (sms_t * h, int samples, signed short *data)
1261 if (h->obyten || h->osync)
1262 return; /* sending */
1264 unsigned long long m0, m1;
1265 if (abs (*data) > h->imag)
1266 h->imag = abs (*data);
1268 h->imag = h->imag * 7 / 8;
1269 if (h->imag > 500) {
1271 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
1272 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
1273 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
1274 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
1275 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
1276 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
1277 if ((h->ips0 += 21) >= 80)
1279 if ((h->ipc0 += 21) >= 80)
1281 if ((h->ips1 += 13) >= 80)
1283 if ((h->ipc1 += 13) >= 80)
1294 bit = ((h->ibitt > 1) ? 1 : 0);
1295 if (bit != h->ibitl)
1300 if (!h->ibitn && h->ibitc == 4 && !bit) {
1304 if (bit && h->ibitc == 200) { /* sync, restart message */
1305 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1309 if (h->iphasep >= 80) { /* next bit */
1311 if (h->ibitn++ == 9) { /* end of byte */
1312 if (!bit) /* bad stop bit */
1313 h->ierr = 0xFF; /* unknown error */
1315 if (h->ibytep < sizeof (h->imsg)) {
1316 h->imsg[h->ibytep] = h->ibytev;
1317 h->ibytec += h->ibytev;
1319 } else if (h->ibytep == sizeof (h->imsg))
1320 h->ierr = 2; /* bad message length */
1321 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
1325 h->ierr = 1; /* bad checksum */
1330 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1334 } else { /* lost carrier */
1335 if (h->idle++ == 80000) { /* nothing happening */
1336 ast_log (LOG_EVENT, "No data, hanging up\n");
1340 if (h->ierr) { /* error */
1342 h->omsg[0] = 0x92; /* error */
1344 h->omsg[2] = h->ierr;
1345 sms_messagetx (h); /* send error */
1347 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1353 static struct ast_generator smsgen = {
1355 release:sms_release,
1356 generate:sms_generate,
1359 static int sms_exec (struct ast_channel *chan, void *data)
1362 struct localuser *u;
1363 struct ast_frame *f;
1368 h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1369 h.dcs = 0xF1; /* default */
1371 ast_log (LOG_ERROR, "Requires queue name at least\n");
1372 LOCAL_USER_REMOVE(u);
1376 if (chan->cid.cid_num)
1377 ast_copy_string (h.cli, chan->cid.cid_num, sizeof (h.cli));
1381 unsigned char *d = data,
1383 if (!*d || *d == '|') {
1384 ast_log (LOG_ERROR, "Requires queue name\n");
1385 LOCAL_USER_REMOVE(u);
1388 for (p = d; *p && *p != '|'; p++);
1389 if (p - d >= sizeof (h.queue)) {
1390 ast_log (LOG_ERROR, "Queue name too long\n");
1391 LOCAL_USER_REMOVE(u);
1394 strncpy (h.queue, (char *)d, p - d);
1398 for (p = (unsigned char *)h.queue; *p; p++)
1400 *p = '-'; /* make very safe for filenames */
1401 while (*d && *d != '|') {
1403 case 'a': /* we have to send the initial FSK sequence */
1406 case 's': /* we are acting as a service centre talking to a phone */
1409 /* the following apply if there is an arg3/4 and apply to the created message file */
1414 h.dcs |= 4; /* octets */
1422 case '7': /* set the pid for saved local message */
1423 h.pid = 0x40 + (*d & 0xF);
1429 /* submitting a message, not taking call. */
1430 /* deprecated, use smsq instead */
1433 for (p = d; *p && *p != '|'; p++);
1436 if (strlen ((char *)d) >= sizeof (h.oa)) {
1437 ast_log (LOG_ERROR, "Address too long %s\n", d);
1441 ast_copy_string (h.oa, (char *)d, sizeof (h.oa));
1443 ast_copy_string (h.da, (char *)d, sizeof (h.da));
1446 ast_copy_string (h.oa, h.cli, sizeof (h.oa));
1449 while (*p && h.udl < SMSLEN)
1450 h.ud[h.udl++] = utf8decode(&p);
1451 if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1452 ast_log (LOG_WARNING, "Invalid 7 bit GSM data\n");
1453 if (is8bit (h.dcs) && packsms8 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1454 ast_log (LOG_WARNING, "Invalid 8 bit data\n");
1455 if (is16bit (h.dcs) && packsms16 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1456 ast_log (LOG_WARNING, "Invalid 16 bit data\n");
1457 h.rx = 0; /* sent message */
1460 LOCAL_USER_REMOVE(u);
1465 /* set up SMS_EST initial message */
1472 if (chan->_state != AST_STATE_UP)
1476 res = ast_set_write_format (chan, AST_FORMAT_ALAW);
1478 res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
1481 res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
1483 ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
1484 LOCAL_USER_REMOVE (u);
1488 if (ast_activate_generator (chan, &smsgen, &h) < 0) {
1489 ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
1490 LOCAL_USER_REMOVE (u);
1494 /* Do our thing here */
1495 while (ast_waitfor (chan, -1) > -1 && !h.hangup)
1497 f = ast_read (chan);
1500 if (f->frametype == AST_FRAME_VOICE) {
1501 sms_process (&h, f->samples, f->data);
1507 sms_log (&h, '?'); /* log incomplete message */
1509 LOCAL_USER_REMOVE (u);
1513 static int unload_module(void *mod)
1517 res = ast_unregister_application (app);
1519 STANDARD_HANGUP_LOCALUSERS;
1524 static int load_module(void *mod)
1529 for (p = 0; p < 80; p++)
1530 wavea[p] = AST_LIN2A (wave[p]);
1533 snprintf (log_file, sizeof (log_file), "%s/sms", ast_config_AST_LOG_DIR);
1534 snprintf (spool_dir, sizeof (spool_dir), "%s/sms", ast_config_AST_SPOOL_DIR);
1535 return ast_register_application (app, sms_exec, synopsis, descrip);
1538 static const char *description(void)
1543 static const char *key(void)
1545 return ASTERISK_GPL_KEY;