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
28 #include <sys/types.h>
35 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
37 #include "asterisk/lock.h"
38 #include "asterisk/file.h"
39 #include "asterisk/logger.h"
40 #include "asterisk/options.h"
41 #include "asterisk/channel.h"
42 #include "asterisk/pbx.h"
43 #include "asterisk/module.h"
44 #include "asterisk/alaw.h"
45 #include "asterisk/callerid.h"
47 /* output using Alaw rather than linear */
51 /* Add full VP support */
52 /* Handle status report messages (generation and reception) */
53 /* Time zones on time stamps */
56 static volatile unsigned char message_ref; /* arbitary message ref */
57 static volatile unsigned int seq; /* arbitrary message sequence number for unqiue files */
59 static char log_file[255];
60 static char spool_dir[255];
62 static char *tdesc = "SMS/PSTN handler";
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];
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 /*--- numcpy: copy number, skipping non digits apart from leading + */
200 static void numcpy (char *d, char *s)
212 /*--- isodate: 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 /*--- utf8decode: 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 /*--- packsms7: 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 /*--- packsms8: 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 /*--- packsms16: 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 /*--- packsms: 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 /*--- packdate: 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 /*--- unpackdate: 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 /*--- unpacksms7: 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 /*--- unpacksms8: 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 /*--- unpacksms16: 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 /*--- unpacksms: 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 /*--- unpackaddress: 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 /*--- packaddress: 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 /*--- sms_log: 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 /*--- sms_readfile: 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 /*--- sms_writefile: 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 /*--- readdirqueue: 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 /*--- sms_handleincoming: 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 /*--- sms_nextoutgoing: find and fill in next message,
1026 or send a REL if none waiting */
1027 static void sms_nextoutgoing (sms_t * h)
1029 char fn[100 + NAME_MAX] = "";
1032 ast_copy_string (fn, spool_dir, sizeof (fn));
1033 mkdir (fn, 0777); /* ensure it exists */
1034 h->rx = 0; /* outgoing message */
1035 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? "mttx" : "motx");
1036 mkdir (fn, 0777); /* ensure it exists */
1039 struct dirent *f = readdirqueue (d, h->queue);
1041 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", f->d_name);
1042 sms_readfile (h, fn);
1043 if (readdirqueue (d, h->queue))
1044 more = 1; /* more to send */
1048 if (*h->da || *h->oa) { /* message to send */
1049 unsigned char p = 2;
1050 h->omsg[0] = 0x91; /* SMS_DATA */
1051 if (h->smsc) { /* deliver */
1052 h->omsg[p++] = (more ? 4 : 0);
1053 p += packaddress (h->omsg + p, h->oa);
1054 h->omsg[p++] = h->pid;
1055 h->omsg[p++] = h->dcs;
1056 packdate (h->omsg + p, h->scts);
1058 p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1059 } else { /* submit */
1061 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
1063 h->mr = message_ref++;
1064 h->omsg[p++] = h->mr;
1065 p += packaddress (h->omsg + p, h->da);
1066 h->omsg[p++] = h->pid;
1067 h->omsg[p++] = h->dcs;
1068 if (h->vp) { /* relative VP */
1070 h->omsg[p++] = (h->vp + 4) / 5 - 1;
1071 else if (h->vp < 1440)
1072 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
1073 else if (h->vp < 43200)
1074 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
1075 else if (h->vp < 635040)
1076 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
1078 h->omsg[p++] = 255; /* max */
1080 p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1084 } else { /* no message */
1085 h->omsg[0] = 0x94; /* SMS_REL */
1091 static void sms_debug (char *dir, unsigned char *msg)
1093 char txt[259 * 3 + 1],
1094 *p = txt; /* always long enough */
1097 while (q < n && q < 30) {
1098 sprintf (p, " %02X", msg[q++]);
1103 if (option_verbose > 2)
1104 ast_verbose (VERBOSE_PREFIX_3 "SMS %s%s\n", dir, txt);
1107 static void sms_messagerx(sms_t * h)
1109 sms_debug ("RX", h->imsg);
1111 switch (h->imsg[0]) {
1112 case 0x91: /* SMS_DATA */
1114 unsigned char cause = sms_handleincoming (h);
1117 h->omsg[0] = 0x95; /* SMS_ACK */
1119 h->omsg[2] = 0x00; /* deliver report */
1120 h->omsg[3] = 0x00; /* no parameters */
1123 h->omsg[0] = 0x96; /* SMS_NACK */
1125 h->omsg[2] = 0; /* delivery report */
1126 h->omsg[3] = cause; /* cause */
1127 h->omsg[4] = 0; /* no parameters */
1132 case 0x92: /* SMS_ERROR */
1134 sms_messagetx (h); /* send whatever we sent again */
1136 case 0x93: /* SMS_EST */
1137 sms_nextoutgoing (h);
1139 case 0x94: /* SMS_REL */
1140 h->hangup = 1; /* hangup */
1142 case 0x95: /* SMS_ACK */
1144 sms_nextoutgoing (h);
1146 case 0x96: /* SMS_NACK */
1149 sms_nextoutgoing (h);
1151 default: /* Unknown */
1152 h->omsg[0] = 0x92; /* SMS_ERROR */
1154 h->omsg[2] = 3; /* unknown message type; */
1160 static void sms_messagetx(sms_t * h)
1162 unsigned char c = 0, p;
1163 for (p = 0; p < h->omsg[1] + 2; p++)
1165 h->omsg[h->omsg[1] + 2] = 0 - c;
1166 sms_debug ("TX", h->omsg);
1169 if (h->omsg[0] == 0x93)
1170 h->opause = 2400; /* initial message delay 300ms (for BT) */
1174 h->obyten = h->omsg[1] + 3;
1177 static int sms_generate (struct ast_channel *chan, void *data, int len, int samples)
1179 struct ast_frame f = { 0 };
1180 unsigned char waste[AST_FRIENDLY_OFFSET];
1182 unsigned char buf[800];
1184 signed short buf[800];
1189 if (len > sizeof (buf)) {
1190 ast_log (LOG_WARNING, "Only doing %d bytes (%d bytes requested)\n", (int)(sizeof (buf) / sizeof (signed short)), len);
1198 waste[0] = 0; /* make compiler happy */
1199 f.frametype = AST_FRAME_VOICE;
1201 f.subclass = AST_FORMAT_ALAW;
1202 f.datalen = samples;
1204 f.subclass = AST_FORMAT_SLINEAR;
1205 f.datalen = samples * 2;
1207 f.offset = AST_FRIENDLY_OFFSET;
1210 f.samples = samples;
1212 /* create a buffer containing the digital sms pattern */
1213 for (i = 0; i < samples; i++) {
1221 else if (h->obyten || h->osync) { /* sending data */
1223 buf[i] = wavea[h->ophase];
1225 buf[i] = wave[h->ophase];
1227 if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
1229 if ((h->ophasep += 12) >= 80) { /* next bit */
1232 h->osync--; /* sending sync bits */
1237 h->obyte = 0; /* start bit; */
1238 else if (h->obitp == 2)
1239 h->obyte = h->omsg[h->obytep];
1240 else if (h->obitp == 10) {
1241 h->obyte = 1; /* stop bit */
1244 if (h->obytep == h->obyten) {
1245 h->obytep = h->obyten = 0; /* sent */
1246 h->osync = 10; /* trailing marks */
1253 if (ast_write (chan, &f) < 0) {
1254 ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
1260 static void sms_process (sms_t * h, int samples, signed short *data)
1262 if (h->obyten || h->osync)
1263 return; /* sending */
1265 unsigned long long m0, m1;
1266 if (abs (*data) > h->imag)
1267 h->imag = abs (*data);
1269 h->imag = h->imag * 7 / 8;
1270 if (h->imag > 500) {
1272 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
1273 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
1274 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
1275 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
1276 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
1277 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
1278 if ((h->ips0 += 21) >= 80)
1280 if ((h->ipc0 += 21) >= 80)
1282 if ((h->ips1 += 13) >= 80)
1284 if ((h->ipc1 += 13) >= 80)
1295 bit = ((h->ibitt > 1) ? 1 : 0);
1296 if (bit != h->ibitl)
1301 if (!h->ibitn && h->ibitc == 4 && !bit) {
1305 if (bit && h->ibitc == 200) { /* sync, restart message */
1306 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1310 if (h->iphasep >= 80) { /* next bit */
1312 if (h->ibitn++ == 9) { /* end of byte */
1313 if (!bit) /* bad stop bit */
1314 h->ierr = 0xFF; /* unknown error */
1316 if (h->ibytep < sizeof (h->imsg)) {
1317 h->imsg[h->ibytep] = h->ibytev;
1318 h->ibytec += h->ibytev;
1320 } else if (h->ibytep == sizeof (h->imsg))
1321 h->ierr = 2; /* bad message length */
1322 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
1326 h->ierr = 1; /* bad checksum */
1331 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1335 } else { /* lost carrier */
1336 if (h->idle++ == 80000) { /* nothing happening */
1337 ast_log (LOG_EVENT, "No data, hanging up\n");
1341 if (h->ierr) { /* error */
1343 h->omsg[0] = 0x92; /* error */
1345 h->omsg[2] = h->ierr;
1346 sms_messagetx (h); /* send error */
1348 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1354 static struct ast_generator smsgen = {
1356 release:sms_release,
1357 generate:sms_generate,
1360 static int sms_exec (struct ast_channel *chan, void *data)
1363 struct localuser *u;
1364 struct ast_frame *f;
1369 h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1370 h.dcs = 0xF1; /* default */
1372 ast_log (LOG_ERROR, "Requires queue name at least\n");
1373 LOCAL_USER_REMOVE(u);
1377 if (chan->cid.cid_num)
1378 ast_copy_string (h.cli, chan->cid.cid_num, sizeof (h.cli));
1384 if (!*d || *d == '|') {
1385 ast_log (LOG_ERROR, "Requires queue name\n");
1386 LOCAL_USER_REMOVE(u);
1389 for (p = d; *p && *p != '|'; p++);
1390 if (p - d >= sizeof (h.queue)) {
1391 ast_log (LOG_ERROR, "Queue name too long\n");
1392 LOCAL_USER_REMOVE(u);
1395 strncpy (h.queue, d, p - d);
1399 for (p = h.queue; *p; p++)
1401 *p = '-'; /* make very safe for filenames */
1402 while (*d && *d != '|') {
1404 case 'a': /* we have to send the initial FSK sequence */
1407 case 's': /* we are acting as a service centre talking to a phone */
1410 /* the following apply if there is an arg3/4 and apply to the created message file */
1415 h.dcs |= 4; /* octets */
1423 case '7': /* set the pid for saved local message */
1424 h.pid = 0x40 + (*d & 0xF);
1430 /* submitting a message, not taking call. */
1431 /* depricated, use smsq instead */
1434 for (p = d; *p && *p != '|'; p++);
1437 if (strlen (d) >= sizeof (h.oa)) {
1438 ast_log (LOG_ERROR, "Address too long %s\n", d);
1442 ast_copy_string (h.oa, d, sizeof (h.oa));
1444 ast_copy_string (h.da, d, sizeof (h.da));
1447 ast_copy_string (h.oa, h.cli, sizeof (h.oa));
1450 while (*p && h.udl < SMSLEN)
1451 h.ud[h.udl++] = utf8decode((unsigned char **)&p);
1452 if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1453 ast_log (LOG_WARNING, "Invalid 7 bit GSM data\n");
1454 if (is8bit (h.dcs) && packsms8 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1455 ast_log (LOG_WARNING, "Invalid 8 bit data\n");
1456 if (is16bit (h.dcs) && packsms16 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1457 ast_log (LOG_WARNING, "Invalid 16 bit data\n");
1458 h.rx = 0; /* sent message */
1461 LOCAL_USER_REMOVE(u);
1466 /* set up SMS_EST initial message */
1473 if (chan->_state != AST_STATE_UP)
1477 res = ast_set_write_format (chan, AST_FORMAT_ALAW);
1479 res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
1482 res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
1484 ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
1485 LOCAL_USER_REMOVE (u);
1489 if (ast_activate_generator (chan, &smsgen, &h) < 0) {
1490 ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
1491 LOCAL_USER_REMOVE (u);
1495 /* Do our thing here */
1496 while (ast_waitfor (chan, -1) > -1 && !h.hangup)
1498 f = ast_read (chan);
1501 if (f->frametype == AST_FRAME_VOICE) {
1502 sms_process (&h, f->samples, f->data);
1508 sms_log (&h, '?'); /* log incomplete message */
1510 LOCAL_USER_REMOVE (u);
1514 int unload_module (void)
1518 res = ast_unregister_application (app);
1520 STANDARD_HANGUP_LOCALUSERS;
1525 int load_module (void)
1530 for (p = 0; p < 80; p++)
1531 wavea[p] = AST_LIN2A (wave[p]);
1534 snprintf (log_file, sizeof (log_file), "%s/sms", ast_config_AST_LOG_DIR);
1535 snprintf (spool_dir, sizeof (spool_dir), "%s/sms", ast_config_AST_SPOOL_DIR);
1536 return ast_register_application (app, sms_exec, synopsis, descrip);
1539 char *description (void)
1547 STANDARD_USECOUNT (res);
1553 return ASTERISK_GPL_KEY;