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
31 #include <sys/types.h>
36 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
38 #include "asterisk/lock.h"
39 #include "asterisk/file.h"
40 #include "asterisk/logger.h"
41 #include "asterisk/options.h"
42 #include "asterisk/channel.h"
43 #include "asterisk/pbx.h"
44 #include "asterisk/module.h"
45 #include "asterisk/alaw.h"
46 #include "asterisk/callerid.h"
48 /* output using Alaw rather than linear */
52 /* Add full VP support */
53 /* Handle status report messages (generation and reception) */
54 /* Time zones on time stamps */
57 static volatile unsigned char message_ref; /* arbitary message ref */
58 static volatile unsigned int seq; /* arbitrary message sequence number for unqiue files */
60 static char log_file[255];
61 static char spool_dir[255];
63 static char *tdesc = "SMS/PSTN handler";
65 static char *app = "SMS";
67 static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
69 static char *descrip =
70 " SMS(name|[a][s]): SMS handles exchange of SMS data with a call to/from SMS capabale\n"
71 "phone or SMS PSTN service center. Can send and/or receive SMS messages.\n"
72 "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n"
73 "Typical usage is to use to handle called from the SMS service centre CLI,\n"
74 "or to set up a call using 'outgoing' or manager interface to connect\n"
75 "service centre to SMS()\n"
76 "name is the name of the queue used in /var/spool/asterisk/sms\n"
78 " a: answer, i.e. send initial FSK packet.\n"
79 " s: act as service centre talking to a phone.\n"
80 "Messages are processed as per text file message queues.\n"
81 "smsq (a separate software) is a command to generate message\n"
82 "queues and send messages.\n";
84 static signed short wave[] = {
85 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
86 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
88 -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
90 -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
94 static unsigned char wavea[80];
101 /* SMS 7 bit character mapping to UCS-2 */
102 static const unsigned short defaultalphabet[] = {
103 0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
104 0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
105 0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
106 0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
107 ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
108 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
109 161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
110 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
111 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
112 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
115 static const unsigned short escapes[] = {
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x000C, 0, 0, 0, 0, 0,
117 0, 0, 0, 0, 0x005E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118 0, 0, 0, 0, 0, 0, 0, 0, 0x007B, 0x007D, 0, 0, 0, 0, 0, 0x005C,
119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x005B, 0x007E, 0x005D, 0,
120 0x007C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
122 0, 0, 0, 0, 0, 0x20AC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
123 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126 #define SMSLEN 160 /* max SMS length */
130 unsigned char hangup; /* we are done... */
131 unsigned char err; /* set for any errors */
132 unsigned char smsc:1; /* we are SMSC */
133 unsigned char rx:1; /* this is a received message */
134 char queue[30]; /* queue name */
135 char oa[20]; /* originating address */
136 char da[20]; /* destination address */
137 time_t scts; /* time stamp, UTC */
138 unsigned char pid; /* protocol ID */
139 unsigned char dcs; /* data coding scheme */
140 short mr; /* message reference - actually a byte, but usde -1 for not set */
141 int udl; /* user data length */
142 int udhl; /* user data header length */
143 unsigned char srr:1; /* Status Report request */
144 unsigned char udhi:1; /* User Data Header required, even if length 0 */
145 unsigned char rp:1; /* Reply Path */
146 unsigned int vp; /* validity period in minutes, 0 for not set */
147 unsigned short ud[SMSLEN]; /* user data (message), UCS-2 coded */
148 unsigned char udh[SMSLEN]; /* user data header */
149 char cli[20]; /* caller ID */
150 unsigned char ophase; /* phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
151 unsigned char ophasep; /* phase (0-79) for 1200 bps */
152 unsigned char obyte; /* byte being sent */
153 unsigned int opause; /* silent pause before sending (in sample periods) */
154 unsigned char obitp; /* bit in byte */
155 unsigned char osync; /* sync bits to send */
156 unsigned char obytep; /* byte in data */
157 unsigned char obyten; /* bytes in data */
158 unsigned char omsg[256]; /* data buffer (out) */
159 unsigned char imsg[200]; /* data buffer (in) */
160 signed long long ims0,
163 imc1; /* magnitude averages sin/cos 0/1 */
165 unsigned short imag; /* signal level */
169 ipc1; /* phase sin/cos 0/1 */
170 unsigned char ibitl; /* last bit */
171 unsigned char ibitc; /* bit run length count */
172 unsigned char iphasep; /* bit phase (0-79) for 1200 bps */
173 unsigned char ibitn; /* bit number in byte being received */
174 unsigned char ibytev; /* byte value being received */
175 unsigned char ibytep; /* byte pointer in messafe */
176 unsigned char ibytec; /* byte checksum for message */
177 unsigned char ierr; /* error flag */
178 unsigned char ibith; /* history of last bits */
179 unsigned char ibitt; /* total of 1's in last 3 bites */
180 /* more to go here */
183 /* different types of encoding */
184 #define is7bit(dcs) (((dcs)&0xC0)?(!((dcs)&4)):(!((dcs)&12)))
185 #define is8bit(dcs) (((dcs)&0xC0)?(((dcs)&4)):(((dcs)&12)==4))
186 #define is16bit(dcs) (((dcs)&0xC0)?0:(((dcs)&12)==8))
188 static void *sms_alloc (struct ast_channel *chan, void *params)
193 static void sms_release (struct ast_channel *chan, void *data)
198 static void sms_messagetx (sms_t * h);
200 /*--- numcpy: copy number, skipping non digits apart from leading + */
201 static void numcpy (char *d, char *s)
213 /*--- isodate: static, return a date/time in ISO format */
214 static char * isodate (time_t t)
216 static char date[20];
217 strftime (date, sizeof (date), "%Y-%m-%dT%H:%M:%S", localtime (&t));
221 /*--- utf8decode: reads next UCS character from null terminated UTF-8 string and advanced pointer */
222 /* for non valid UTF-8 sequences, returns character as is */
223 /* Does not advance pointer for null termination */
224 static long utf8decode (unsigned char **pp)
226 unsigned char *p = *pp;
228 return 0; /* null termination of string */
231 return *p; /* ascii or continuation character */
233 if (*p < 0xC2 || (p[1] & 0xC0) != 0x80)
234 return *p; /* not valid UTF-8 */
236 return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
239 if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80)
240 return *p; /* not valid UTF-8 */
242 return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
245 if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80)
246 return *p; /* not valid UTF-8 */
248 return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
251 if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
252 || (p[4] & 0xC0) != 0x80)
253 return *p; /* not valid UTF-8 */
255 return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
258 if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
259 || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80)
260 return *p; /* not valid UTF-8 */
262 return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F);
264 return *p; /* not sensible */
267 /*--- 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 */
268 /* The return value is the number of septets packed in to o, which is internally limited to SMSLEN */
269 /* o can be null, in which case this is used to validate or count only */
270 /* if the input contains invalid characters then the return value is -1 */
271 static int packsms7 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
273 unsigned char p = 0, b = 0, n = 0;
275 if (udhl) { /* header */
295 }; /* filling to septet boundary */
304 for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
305 if (v == 128 && u && n + 1 < SMSLEN) {
306 for (v = 0; v < 128 && escapes[v] != u; v++);
307 if (v < 128) { /* escaped sequence */
315 o[p] = (27 >> (7 - b));
321 return -1; /* invalid character */
329 o[p] = (v >> (7 - b));
337 /*--- 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 */
338 /* The return value is the number of bytes packed in to o, which is internally limited to 140 */
339 /* o can be null, in which case this is used to validate or count only */
340 /* if the input contains invalid characters then the return value is -1 */
341 static int packsms8 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
345 /* header - no encoding */
359 if (u < 0 || u > 0xFF)
360 return -1; /* not valid */
369 /*--- packsms16: takes a binary header (udhl bytes at udh) and UCS-2
370 message (udl characters at ud) and packs in to o using 16 bit
371 UCS-2 character codes
372 The return value is the number of bytes packed in to o, which is
373 internally limited to 140
374 o can be null, in which case this is used to validate or count
375 only if the input contains invalid characters then
376 the return value is -1 */
377 static int packsms16 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
380 /* header - no encoding */
397 return p - 1; /* could not fit last character */
406 /*--- packsms: general pack, with length and data,
407 returns number of bytes of target used */
408 static int packsms (unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
410 unsigned char *p = base;
413 if (is7bit (dcs)) { /* 7 bit */
414 l = packsms7 (p + 1, udhl, udh, udl, ud);
418 p += (l * 7 + 7) / 8;
419 } else if (is8bit (dcs)) { /* 8 bit */
420 l = packsms8 (p + 1, udhl, udh, udl, ud);
426 l = packsms16 (p + 1, udhl, udh, udl, ud);
433 *p++ = 0; /* no user data */
438 /*--- packdate: pack a date and return */
439 static void packdate (unsigned char *o, time_t w)
441 struct tm *t = localtime (&w);
442 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
443 int z = -t->tm_gmtoff / 60 / 15;
445 int z = timezone / 60 / 15;
447 *o++ = ((t->tm_year % 10) << 4) + (t->tm_year % 100) / 10;
448 *o++ = (((t->tm_mon + 1) % 10) << 4) + (t->tm_mon + 1) / 10;
449 *o++ = ((t->tm_mday % 10) << 4) + t->tm_mday / 10;
450 *o++ = ((t->tm_hour % 10) << 4) + t->tm_hour / 10;
451 *o++ = ((t->tm_min % 10) << 4) + t->tm_min / 10;
452 *o++ = ((t->tm_sec % 10) << 4) + t->tm_sec / 10;
454 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
456 *o++ = ((z % 10) << 4) + z / 10;
459 /*--- unpackdate: unpack a date and return */
460 static time_t unpackdate (unsigned char *i)
463 t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
464 t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
465 t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
466 t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
467 t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
468 t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
471 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
473 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
477 /*--- unpacksms7: unpacks bytes (7 bit encoding) at i, len l septets,
478 and places in udh and ud setting udhl and udl. udh not used
480 static void unpacksms7 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
482 unsigned char b = 0, p = 0;
483 unsigned short *o = ud;
485 if (udhi && l) { /* header */
502 /* adjust for fill, septets */
512 v = ((i[p] >> b) & 0x7F);
514 v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
520 if (o > ud && o[-1] == 0x00A0 && escapes[v])
523 *o++ = defaultalphabet[v];
528 /*--- unpacksms8: unpacks bytes (8 bit encoding) at i, len l septets,
529 and places in udh and ud setting udhl and udl. udh not used
531 static void unpacksms8 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
533 unsigned short *o = ud;
549 *o++ = *i++; /* not to UTF-8 as explicitely 8 bit coding in DCS */
553 /*--- unpacksms16: unpacks bytes (16 bit encoding) at i, len l septets,
554 and places in udh and ud setting udhl and udl.
555 udh not used if udhi not set */
556 static void unpacksms16 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
558 unsigned short *o = ud;
582 /*--- unpacksms: general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
583 static int unpacksms (unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
587 unpacksms7 (i, l, udh, udhl, ud, udl, udhi);
588 l = (l * 7 + 7) / 8; /* adjust length to return */
589 } else if (is8bit (dcs))
590 unpacksms8 (i, l, udh, udhl, ud, udl, udhi);
592 unpacksms16 (i, l, udh, udhl, ud, udl, udhi);
596 /*--- unpackaddress: unpack an address from i, return byte length, unpack to o */
597 static unsigned char unpackaddress (char *o, unsigned char *i)
599 unsigned char l = i[0],
603 for (p = 0; p < l; p++) {
605 *o++ = (i[2 + p / 2] >> 4) + '0';
607 *o++ = (i[2 + p / 2] & 0xF) + '0';
613 /*--- packaddress: store an address at o, and return number of bytes used */
614 static unsigned char packaddress (unsigned char *o, char *i)
626 o[p++] |= ((*i & 0xF) << 4);
634 o[p++] |= 0xF0; /* pad */
638 /*--- sms_log: Log the output, and remove file */
639 static void sms_log (sms_t * h, char status)
641 if (*h->oa || *h->da) {
642 int o = open (log_file, O_CREAT | O_APPEND | O_WRONLY, 0666);
644 char line[1000], mrs[3] = "", *p;
648 snprintf (mrs, sizeof (mrs), "%02X", h->mr);
649 snprintf (line, sizeof (line), "%s %c%c%c%s %s %s %s ",
650 isodate (time (0)), status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue, *h->oa ? h->oa : "-",
651 *h->da ? h->da : "-");
652 p = line + strlen (line);
653 for (n = 0; n < h->udl; n++)
654 if (h->ud[n] == '\\') {
657 } else if (h->ud[n] == '\n') {
660 } else if (h->ud[n] == '\r') {
663 } else if (h->ud[n] < 32 || h->ud[n] == 127)
669 write (o, line, strlen (line));
672 *h->oa = *h->da = h->udl = 0;
676 /*--- sms_readfile: parse and delete a file */
677 static void sms_readfile (sms_t * h, char *fn)
681 char dcsset = 0; /* if DSC set */
682 ast_log (LOG_EVENT, "Sending %s\n", fn);
683 h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
685 h->dcs = 0xF1; /* normal messages class 1 */
691 { /* concurrent access, we lost */
695 while (fgets (line, sizeof (line), s))
696 { /* process line in file */
698 for (p = line; *p && *p != '\n' && *p != '\r'; p++);
699 *p = 0; /* strip eoln */
701 if (!*p || *p == ';')
702 continue; /* blank line or comment, ignore */
713 if (!strcmp (line, "ud"))
714 { /* parse message (UTF-8) */
716 while (*p && o < SMSLEN)
717 h->ud[o++] = utf8decode((unsigned char **)&p);
720 ast_log (LOG_WARNING, "UD too long in %s\n", fn);
725 if (!strcmp (line, "oa") && strlen (p) < sizeof (h->oa))
727 else if (!strcmp (line, "da") && strlen (p) < sizeof (h->oa))
729 else if (!strcmp (line, "pid"))
731 else if (!strcmp (line, "dcs"))
735 } else if (!strcmp (line, "mr"))
737 else if (!strcmp (line, "srr"))
738 h->srr = (atoi (p) ? 1 : 0);
739 else if (!strcmp (line, "vp"))
741 else if (!strcmp (line, "rp"))
742 h->rp = (atoi (p) ? 1 : 0);
743 else if (!strcmp (line, "scts"))
744 { /* get date/time */
751 if (sscanf (p, "%d-%d-%dT%d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6)
754 t.tm_year = Y - 1900;
761 h->scts = mktime (&t);
762 if (h->scts == (time_t) - 1)
763 ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
766 ast_log (LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
768 } else if (*p == '#')
769 { /* raw hex format */
774 if (!strcmp (line, "ud"))
777 while (*p && o < SMSLEN)
779 if (isxdigit (*p) && isxdigit (p[1]) && isxdigit (p[2]) && isxdigit (p[3]))
782 (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 12) +
783 (((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
784 (((isalpha (p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha (p[3]) ? 9 : 0) + (p[3] & 0xF));
791 ast_log (LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
793 ast_log (LOG_WARNING, "Only ud can use ## format, %s\n", fn);
794 } else if (!strcmp (line, "ud"))
797 while (*p && o < SMSLEN)
799 if (isxdigit (*p) && isxdigit (p[1]))
801 h->ud[o++] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
808 ast_log (LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
809 } else if (!strcmp (line, "udh"))
810 { /* user data header */
813 while (*p && o < SMSLEN)
815 if (isxdigit (*p) && isxdigit (p[1]))
817 h->udh[o] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
825 ast_log (LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
827 ast_log (LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
829 ast_log (LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
832 if (!dcsset && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
834 if (packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
836 if (packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
837 ast_log (LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
840 h->dcs = 0x08; /* default to 16 bit */
841 ast_log (LOG_WARNING, "Sending in 16 bit format (%s)\n", fn);
845 h->dcs = 0xF5; /* default to 8 bit */
846 ast_log (LOG_WARNING, "Sending in 8 bit format (%s)\n", fn);
849 if (is7bit (h->dcs) && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
850 ast_log (LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
851 if (is8bit (h->dcs) && packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
852 ast_log (LOG_WARNING, "Invalid 8 bit data %s\n", fn);
853 if (is16bit (h->dcs) && packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
854 ast_log (LOG_WARNING, "Invalid 16 bit data %s\n", fn);
858 /*--- sms_writefile: white a received text message to a file */
859 static void sms_writefile (sms_t * h)
861 char fn[200] = "", fn2[200] = "";
863 ast_copy_string (fn, spool_dir, sizeof (fn));
864 mkdir (fn, 0777); /* ensure it exists */
865 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
866 mkdir (fn, 0777); /* ensure it exists */
867 ast_copy_string (fn2, fn, sizeof (fn2));
868 snprintf (fn2 + strlen (fn2), sizeof (fn2) - strlen (fn2), "/%s.%s-%d", h->queue, isodate (h->scts), seq++);
869 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/.%s", fn2 + strlen (fn) + 1);
873 fprintf (o, "oa=%s\n", h->oa);
875 fprintf (o, "da=%s\n", h->da);
879 for (p = 0; p < h->udhl; p++)
880 fprintf (o, "%02X", h->udh[p]);
885 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
887 fputc (';', o); /* cannot use ud=, but include as a comment for human readable */
889 for (p = 0; p < h->udl; p++) {
890 unsigned short v = h->ud[p];
897 fputc (0xC0 + (v >> 6), o);
898 fputc (0x80 + (v & 0x3F), o);
901 fputc (0xE0 + (v >> 12), o);
902 fputc (0x80 + ((v >> 6) & 0x3F), o);
903 fputc (0x80 + (v & 0x3F), o);
907 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
909 for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
910 if (p == h->udl) { /* can write in ucs-1 hex */
912 for (p = 0; p < h->udl; p++)
913 fprintf (o, "%02X", h->ud[p]);
915 } else { /* write in UCS-2 */
917 for (p = 0; p < h->udl; p++)
918 fprintf (o, "%04X", h->ud[p]);
924 fprintf (o, "scts=%s\n", isodate (h->scts));
926 fprintf (o, "pid=%d\n", h->pid);
928 fprintf (o, "dcs=%d\n", h->dcs);
930 fprintf (o, "vp=%d\n", h->vp);
932 fprintf (o, "srr=1\n");
934 fprintf (o, "mr=%d\n", h->mr);
936 fprintf (o, "rp=1\n");
938 if (rename (fn, fn2))
941 ast_log (LOG_EVENT, "Received to %s\n", fn2);
945 /*--- readdirqueue: read dir skipping dot files... */
946 static struct dirent *readdirqueue (DIR * d, char *queue)
951 } while (f && (*f->d_name == '.' || strncmp (f->d_name, queue, strlen (queue)) || f->d_name[strlen (queue)] != '.'));
955 /*--- sms_handleincoming: handle the incoming message */
956 static unsigned char sms_handleincoming (sms_t * h)
959 if (h->smsc) { /* SMSC */
960 if ((h->imsg[2] & 3) == 1) { /* SMS-SUBMIT */
961 h->udhl = h->udl = 0;
963 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
964 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
965 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
966 ast_copy_string (h->oa, h->cli, sizeof (h->oa));
968 h->mr = h->imsg[p++];
969 p += unpackaddress (h->da, h->imsg + p);
970 h->pid = h->imsg[p++];
971 h->dcs = h->imsg[p++];
972 if ((h->imsg[2] & 0x18) == 0x10) { /* relative VP */
973 if (h->imsg[p] < 144)
974 h->vp = (h->imsg[p] + 1) * 5;
975 else if (h->imsg[p] < 168)
976 h->vp = 720 + (h->imsg[p] - 143) * 30;
977 else if (h->imsg[p] < 197)
978 h->vp = (h->imsg[p] - 166) * 1440;
980 h->vp = (h->imsg[p] - 192) * 10080;
982 } else if (h->imsg[2] & 0x18)
983 p += 7; /* ignore enhanced / absolute VP */
984 p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
985 h->rx = 1; /* received message */
986 sms_writefile (h); /* write the file */
987 if (p != h->imsg[1] + 2) {
988 ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
989 return 0xFF; /* duh! */
992 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
995 } else { /* client */
996 if (!(h->imsg[2] & 3)) { /* SMS-DELIVER */
997 *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
998 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
999 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
1000 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1002 p += unpackaddress (h->oa, h->imsg + p);
1003 h->pid = h->imsg[p++];
1004 h->dcs = h->imsg[p++];
1005 h->scts = unpackdate (h->imsg + p);
1007 p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1008 h->rx = 1; /* received message */
1009 sms_writefile (h); /* write the file */
1010 if (p != h->imsg[1] + 2) {
1011 ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1012 return 0xFF; /* duh! */
1015 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
1019 return 0; /* no error */
1023 #define NAME_MAX 1024
1026 /*--- sms_nextoutgoing: find and fill in next message,
1027 or send a REL if none waiting */
1028 static void sms_nextoutgoing (sms_t * h)
1030 char fn[100 + NAME_MAX] = "";
1033 ast_copy_string (fn, spool_dir, sizeof (fn));
1034 mkdir (fn, 0777); /* ensure it exists */
1035 h->rx = 0; /* outgoing message */
1036 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? "mttx" : "motx");
1037 mkdir (fn, 0777); /* ensure it exists */
1040 struct dirent *f = readdirqueue (d, h->queue);
1042 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", f->d_name);
1043 sms_readfile (h, fn);
1044 if (readdirqueue (d, h->queue))
1045 more = 1; /* more to send */
1049 if (*h->da || *h->oa) { /* message to send */
1050 unsigned char p = 2;
1051 h->omsg[0] = 0x91; /* SMS_DATA */
1052 if (h->smsc) { /* deliver */
1053 h->omsg[p++] = (more ? 4 : 0);
1054 p += packaddress (h->omsg + p, h->oa);
1055 h->omsg[p++] = h->pid;
1056 h->omsg[p++] = h->dcs;
1057 packdate (h->omsg + p, h->scts);
1059 p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1060 } else { /* submit */
1062 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
1064 h->mr = message_ref++;
1065 h->omsg[p++] = h->mr;
1066 p += packaddress (h->omsg + p, h->da);
1067 h->omsg[p++] = h->pid;
1068 h->omsg[p++] = h->dcs;
1069 if (h->vp) { /* relative VP */
1071 h->omsg[p++] = (h->vp + 4) / 5 - 1;
1072 else if (h->vp < 1440)
1073 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
1074 else if (h->vp < 43200)
1075 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
1076 else if (h->vp < 635040)
1077 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
1079 h->omsg[p++] = 255; /* max */
1081 p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1085 } else { /* no message */
1086 h->omsg[0] = 0x94; /* SMS_REL */
1092 static void sms_debug (char *dir, unsigned char *msg)
1094 char txt[259 * 3 + 1],
1095 *p = txt; /* always long enough */
1098 while (q < n && q < 30) {
1099 sprintf (p, " %02X", msg[q++]);
1104 if (option_verbose > 2)
1105 ast_verbose (VERBOSE_PREFIX_3 "SMS %s%s\n", dir, txt);
1108 static void sms_messagerx(sms_t * h)
1110 sms_debug ("RX", h->imsg);
1112 switch (h->imsg[0]) {
1113 case 0x91: /* SMS_DATA */
1115 unsigned char cause = sms_handleincoming (h);
1118 h->omsg[0] = 0x95; /* SMS_ACK */
1120 h->omsg[2] = 0x00; /* deliver report */
1121 h->omsg[3] = 0x00; /* no parameters */
1124 h->omsg[0] = 0x96; /* SMS_NACK */
1126 h->omsg[2] = 0; /* delivery report */
1127 h->omsg[3] = cause; /* cause */
1128 h->omsg[4] = 0; /* no parameters */
1133 case 0x92: /* SMS_ERROR */
1135 sms_messagetx (h); /* send whatever we sent again */
1137 case 0x93: /* SMS_EST */
1138 sms_nextoutgoing (h);
1140 case 0x94: /* SMS_REL */
1141 h->hangup = 1; /* hangup */
1143 case 0x95: /* SMS_ACK */
1145 sms_nextoutgoing (h);
1147 case 0x96: /* SMS_NACK */
1150 sms_nextoutgoing (h);
1152 default: /* Unknown */
1153 h->omsg[0] = 0x92; /* SMS_ERROR */
1155 h->omsg[2] = 3; /* unknown message type; */
1161 static void sms_messagetx(sms_t * h)
1163 unsigned char c = 0, p;
1164 for (p = 0; p < h->omsg[1] + 2; p++)
1166 h->omsg[h->omsg[1] + 2] = 0 - c;
1167 sms_debug ("TX", h->omsg);
1170 if (h->omsg[0] == 0x93)
1171 h->opause = 2400; /* initial message delay 300ms (for BT) */
1175 h->obyten = h->omsg[1] + 3;
1178 static int sms_generate (struct ast_channel *chan, void *data, int len, int samples)
1180 struct ast_frame f = { 0 };
1181 unsigned char waste[AST_FRIENDLY_OFFSET];
1183 unsigned char buf[800];
1185 signed short buf[800];
1190 if (len > sizeof (buf)) {
1191 ast_log (LOG_WARNING, "Only doing %d bytes (%d bytes requested)\n", (int)(sizeof (buf) / sizeof (signed short)), len);
1199 waste[0] = 0; /* make compiler happy */
1200 f.frametype = AST_FRAME_VOICE;
1202 f.subclass = AST_FORMAT_ALAW;
1203 f.datalen = samples;
1205 f.subclass = AST_FORMAT_SLINEAR;
1206 f.datalen = samples * 2;
1208 f.offset = AST_FRIENDLY_OFFSET;
1211 f.samples = samples;
1213 /* create a buffer containing the digital sms pattern */
1214 for (i = 0; i < samples; i++) {
1222 else if (h->obyten || h->osync) { /* sending data */
1224 buf[i] = wavea[h->ophase];
1226 buf[i] = wave[h->ophase];
1228 if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
1230 if ((h->ophasep += 12) >= 80) { /* next bit */
1233 h->osync--; /* sending sync bits */
1238 h->obyte = 0; /* start bit; */
1239 else if (h->obitp == 2)
1240 h->obyte = h->omsg[h->obytep];
1241 else if (h->obitp == 10) {
1242 h->obyte = 1; /* stop bit */
1245 if (h->obytep == h->obyten) {
1246 h->obytep = h->obyten = 0; /* sent */
1247 h->osync = 10; /* trailing marks */
1254 if (ast_write (chan, &f) < 0) {
1255 ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
1261 static void sms_process (sms_t * h, int samples, signed short *data)
1263 if (h->obyten || h->osync)
1264 return; /* sending */
1266 unsigned long long m0, m1;
1267 if (abs (*data) > h->imag)
1268 h->imag = abs (*data);
1270 h->imag = h->imag * 7 / 8;
1271 if (h->imag > 500) {
1273 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
1274 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
1275 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
1276 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
1277 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
1278 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
1279 if ((h->ips0 += 21) >= 80)
1281 if ((h->ipc0 += 21) >= 80)
1283 if ((h->ips1 += 13) >= 80)
1285 if ((h->ipc1 += 13) >= 80)
1296 bit = ((h->ibitt > 1) ? 1 : 0);
1297 if (bit != h->ibitl)
1302 if (!h->ibitn && h->ibitc == 4 && !bit) {
1306 if (bit && h->ibitc == 200) { /* sync, restart message */
1307 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1311 if (h->iphasep >= 80) { /* next bit */
1313 if (h->ibitn++ == 9) { /* end of byte */
1314 if (!bit) /* bad stop bit */
1315 h->ierr = 0xFF; /* unknown error */
1317 if (h->ibytep < sizeof (h->imsg)) {
1318 h->imsg[h->ibytep] = h->ibytev;
1319 h->ibytec += h->ibytev;
1321 } else if (h->ibytep == sizeof (h->imsg))
1322 h->ierr = 2; /* bad message length */
1323 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
1327 h->ierr = 1; /* bad checksum */
1332 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1336 } else { /* lost carrier */
1337 if (h->idle++ == 80000) { /* nothing happening */
1338 ast_log (LOG_EVENT, "No data, hanging up\n");
1342 if (h->ierr) { /* error */
1344 h->omsg[0] = 0x92; /* error */
1346 h->omsg[2] = h->ierr;
1347 sms_messagetx (h); /* send error */
1349 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1355 static struct ast_generator smsgen = {
1357 release:sms_release,
1358 generate:sms_generate,
1361 static int sms_exec (struct ast_channel *chan, void *data)
1364 struct localuser *u;
1365 struct ast_frame *f;
1370 h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1371 h.dcs = 0xF1; /* default */
1373 ast_log (LOG_ERROR, "Requires queue name at least\n");
1374 LOCAL_USER_REMOVE(u);
1378 if (chan->cid.cid_num)
1379 ast_copy_string (h.cli, chan->cid.cid_num, sizeof (h.cli));
1383 unsigned char *d = data,
1385 if (!*d || *d == '|') {
1386 ast_log (LOG_ERROR, "Requires queue name\n");
1387 LOCAL_USER_REMOVE(u);
1390 for (p = d; *p && *p != '|'; p++);
1391 if (p - d >= sizeof (h.queue)) {
1392 ast_log (LOG_ERROR, "Queue name too long\n");
1393 LOCAL_USER_REMOVE(u);
1396 strncpy (h.queue, (char *)d, p - d);
1400 for (p = (unsigned char *)h.queue; *p; p++)
1402 *p = '-'; /* make very safe for filenames */
1403 while (*d && *d != '|') {
1405 case 'a': /* we have to send the initial FSK sequence */
1408 case 's': /* we are acting as a service centre talking to a phone */
1411 /* the following apply if there is an arg3/4 and apply to the created message file */
1416 h.dcs |= 4; /* octets */
1424 case '7': /* set the pid for saved local message */
1425 h.pid = 0x40 + (*d & 0xF);
1431 /* submitting a message, not taking call. */
1432 /* deprecated, use smsq instead */
1435 for (p = d; *p && *p != '|'; p++);
1438 if (strlen ((char *)d) >= sizeof (h.oa)) {
1439 ast_log (LOG_ERROR, "Address too long %s\n", d);
1443 ast_copy_string (h.oa, (char *)d, sizeof (h.oa));
1445 ast_copy_string (h.da, (char *)d, sizeof (h.da));
1448 ast_copy_string (h.oa, h.cli, sizeof (h.oa));
1451 while (*p && h.udl < SMSLEN)
1452 h.ud[h.udl++] = utf8decode(&p);
1453 if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1454 ast_log (LOG_WARNING, "Invalid 7 bit GSM data\n");
1455 if (is8bit (h.dcs) && packsms8 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1456 ast_log (LOG_WARNING, "Invalid 8 bit data\n");
1457 if (is16bit (h.dcs) && packsms16 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1458 ast_log (LOG_WARNING, "Invalid 16 bit data\n");
1459 h.rx = 0; /* sent message */
1462 LOCAL_USER_REMOVE(u);
1467 /* set up SMS_EST initial message */
1474 if (chan->_state != AST_STATE_UP)
1478 res = ast_set_write_format (chan, AST_FORMAT_ALAW);
1480 res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
1483 res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
1485 ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
1486 LOCAL_USER_REMOVE (u);
1490 if (ast_activate_generator (chan, &smsgen, &h) < 0) {
1491 ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
1492 LOCAL_USER_REMOVE (u);
1496 /* Do our thing here */
1497 while (ast_waitfor (chan, -1) > -1 && !h.hangup)
1499 f = ast_read (chan);
1502 if (f->frametype == AST_FRAME_VOICE) {
1503 sms_process (&h, f->samples, f->data);
1509 sms_log (&h, '?'); /* log incomplete message */
1511 LOCAL_USER_REMOVE (u);
1515 int unload_module (void)
1519 res = ast_unregister_application (app);
1521 STANDARD_HANGUP_LOCALUSERS;
1526 int load_module (void)
1531 for (p = 0; p < 80; p++)
1532 wavea[p] = AST_LIN2A (wave[p]);
1535 snprintf (log_file, sizeof (log_file), "%s/sms", ast_config_AST_LOG_DIR);
1536 snprintf (spool_dir, sizeof (spool_dir), "%s/sms", ast_config_AST_SPOOL_DIR);
1537 return ast_register_application (app, sms_exec, synopsis, descrip);
1540 char *description (void)
1548 STANDARD_USECOUNT (res);
1554 return ASTERISK_GPL_KEY;