2 * Asterisk -- A telephony toolkit for Linux.
4 * SMS application - ETSI ES 201 912 protocol 1 implimentation
6 * Copyright (C) 2004 - 2005, Adrian Kennard, rights assigned to Digium
8 * This program is free software, distributed under the terms of
9 * the GNU General Public License
12 #include "asterisk/lock.h"
13 #include "asterisk/file.h"
14 #include "asterisk/logger.h"
15 #include "asterisk/options.h"
16 #include "asterisk/channel.h"
17 #include "asterisk/pbx.h"
18 #include "asterisk/module.h"
19 #include "asterisk/alaw.h"
20 #include "asterisk/callerid.h"
26 #include <sys/types.h>
32 /* output using Alaw rather than linear */
36 /* Add full VP support */
37 /* Handle status report messages (generation and reception) */
38 /* Time zones on time stamps */
41 static volatile unsigned char message_ref; /* arbitary message ref */
42 static volatile unsigned int seq; /* arbitrary message sequence number for unqiue files */
44 static char log_file[255];
45 static char spool_dir[255];
47 static char *tdesc = "SMS/PSTN handler";
49 static char *app = "SMS";
51 static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
53 static char *descrip =
54 " SMS(name|[a][s]): SMS handles exchange of SMS data with a call to/from SMS capabale\n"
55 "phone or SMS PSTN service centre. Can send and/or receive SMS messages.\n"
56 "Returns 0 if call handled correctly, or -1 if there were any problems.\n"
57 "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n"
58 "Typical usage is to use to handle called from the SMS service centre CLI,\n"
59 "or to set up a call using 'outgoing' or manager interface to connect service centre to SMS()\n"
60 "name is the name of the queue used in /var/spool/asterisk/sms\n"
61 "Argument 'a' means answer, i.e. send initial FSK packet.\n"
62 "Argument 's' means act as service centre talking to a phone.\n"
63 "Messages are processed as per text file message queues.\n" "smsq is a command to generate message queues and send messages.\n";
65 static signed short wave[] =
66 { 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
67 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
69 -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
71 -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
75 static unsigned char wavea[80];
82 /* SMS 7 bit character mapping to UCS-2 */
83 static const unsigned short defaultalphabet[] = {
84 0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
85 0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
86 0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
87 0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
88 ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
89 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
90 161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
91 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
92 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
93 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
96 static const unsigned short escapes[] = {
97 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x000C, 0, 0, 0, 0, 0,
98 0, 0, 0, 0, 0x005E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99 0, 0, 0, 0, 0, 0, 0, 0, 0x007B, 0x007D, 0, 0, 0, 0, 0, 0x005C,
100 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x005B, 0x007E, 0x005D, 0,
101 0x007C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103 0, 0, 0, 0, 0, 0x20AC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107 #define SMSLEN 160 /* max SMS length */
111 unsigned char hangup; /* we are done... */
112 unsigned char err; /* set for any errors */
113 unsigned char smsc:1; /* we are SMSC */
114 unsigned char rx:1; /* this is a received message */
115 char queue[30]; /* queue name */
116 char oa[20]; /* originating address */
117 char da[20]; /* destination address */
118 time_t scts; /* time stamp, UTC */
119 unsigned char pid; /* protocol ID */
120 unsigned char dcs; /* data coding scheme */
121 short mr; /* message reference - actually a byte, but usde -1 for not set */
122 int udl; /* user data length */
123 int udhl; /* user data header length */
124 unsigned char srr:1; /* Status Report request */
125 unsigned char udhi:1; /* User Data Header required, even if length 0 */
126 unsigned char rp:1; /* Reply Path */
127 unsigned int vp; /* validity period in minutes, 0 for not set */
128 unsigned short ud[SMSLEN]; /* user data (message), UCS-2 coded */
129 unsigned char udh[SMSLEN]; /* user data header */
130 unsigned char cli[20]; /* caller ID */
131 unsigned char ophase; /* phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
132 unsigned char ophasep; /* phase (0-79) for 1200 bps */
133 unsigned char obyte; /* byte being sent */
134 unsigned int opause; /* silent pause before sending (in sample periods) */
135 unsigned char obitp; /* bit in byte */
136 unsigned char osync; /* sync bits to send */
137 unsigned char obytep; /* byte in data */
138 unsigned char obyten; /* bytes in data */
139 unsigned char omsg[256]; /* data buffer (out) */
140 unsigned char imsg[200]; /* data buffer (in) */
141 signed long long ims0,
144 imc1; /* magnitude averages sin/cos 0/1 */
146 unsigned short imag; /* signal level */
150 ipc1; /* phase sin/cos 0/1 */
151 unsigned char ibitl; /* last bit */
152 unsigned char ibitc; /* bit run length count */
153 unsigned char iphasep; /* bit phase (0-79) for 1200 bps */
154 unsigned char ibitn; /* bit number in byte being received */
155 unsigned char ibytev; /* byte value being received */
156 unsigned char ibytep; /* byte pointer in messafe */
157 unsigned char ibytec; /* byte checksum for message */
158 unsigned char ierr; /* error flag */
159 unsigned char ibith; /* history of last bits */
160 unsigned char ibitt; /* total of 1's in last 3 bites */
161 /* more to go here */
164 /* different types of encoding */
165 #define is7bit(dcs) (((dcs)&0xC0)?(!((dcs)&4)):(!((dcs)&12)))
166 #define is8bit(dcs) (((dcs)&0xC0)?(((dcs)&4)):(((dcs)&12)==4))
167 #define is16bit(dcs) (((dcs)&0xC0)?0:(((dcs)&12)==8))
170 sms_alloc (struct ast_channel *chan, void *params)
176 sms_release (struct ast_channel *chan, void *data)
181 static void sms_messagetx (sms_t * h);
183 /* copy number, skipping non digits apart from leading + */
185 numcpy (char *d, char *s)
200 { /* static, return a date/time in ISO format */
201 static char date[20];
202 strftime (date, sizeof (date), "%Y-%m-%dT%H:%M:%S", localtime (&t));
206 /* reads next UCS character from null terminated UTF-8 string and advanced pointer */
207 /* for non valid UTF-8 sequences, returns character as is */
208 /* Does not advance pointer for null termination */
210 utf8decode (unsigned char **pp)
212 unsigned char *p = *pp;
214 return 0; /* null termination of string */
217 return *p; /* ascii or continuation character */
220 if (*p < 0xC2 || (p[1] & 0xC0) != 0x80)
221 return *p; /* not valid UTF-8 */
223 return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
227 if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80)
228 return *p; /* not valid UTF-8 */
230 return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
234 if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80)
235 return *p; /* not valid UTF-8 */
237 return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
241 if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
242 || (p[4] & 0xC0) != 0x80)
243 return *p; /* not valid UTF-8 */
245 return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
249 if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
250 || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80)
251 return *p; /* not valid UTF-8 */
253 return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) +
256 return *p; /* not sensible */
259 /* This 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 */
260 /* The return value is the number of septets packed in to o, which is internally limited to SMSLEN */
261 /* o can be null, in which case this is used to validate or count only */
262 /* if the input contains invalid characters then the return value is -1 */
264 packsms7 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
293 }; /* filling to septet boundary */
303 for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
304 if (v == 128 && u && n + 1 < SMSLEN)
306 for (v = 0; v < 128 && escapes[v] != u; v++);
308 { /* escaped sequence */
317 o[p] = (27 >> (7 - b));
323 return -1; /* invalid character */
332 o[p] = (v >> (7 - b));
340 /* This 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 */
341 /* The return value is the number of bytes packed in to o, which is internally limited to 140 */
342 /* o can be null, in which case this is used to validate or count only */
343 /* if the input contains invalid characters then the return value is -1 */
345 packsms8 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
348 /* header - no encoding */
365 if (u < 0 || u > 0xFF)
366 return -1; /* not valid */
375 /* This takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 16 bit UCS-2 character codes */
376 /* The return value is the number of bytes packed in to o, which is internally limited to 140 */
377 /* o can be null, in which case this is used to validate or count only */
378 /* if the input contains invalid characters then the return value is -1 */
380 packsms16 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
383 /* header - no encoding */
403 return p - 1; /* could not fit last character */
412 /* general pack, with length and data, returns number of bytes of target used */
414 packsms (unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
416 unsigned char *p = base;
422 l = packsms7 (p + 1, udhl, udh, udl, ud);
426 p += (l * 7 + 7) / 8;
427 } else if (is8bit (dcs))
429 l = packsms8 (p + 1, udhl, udh, udl, ud);
436 l = packsms16 (p + 1, udhl, udh, udl, ud);
443 *p++ = 0; /* no user data */
448 /* pack a date and return */
450 packdate (unsigned char *o, time_t w)
452 struct tm *t = localtime (&w);
453 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
454 int z = -t->tm_gmtoff / 60 / 15;
456 int z = timezone / 60 / 15;
458 *o++ = ((t->tm_year % 10) << 4) + (t->tm_year % 100) / 10;
459 *o++ = (((t->tm_mon + 1) % 10) << 4) + (t->tm_mon + 1) / 10;
460 *o++ = ((t->tm_mday % 10) << 4) + t->tm_mday / 10;
461 *o++ = ((t->tm_hour % 10) << 4) + t->tm_hour / 10;
462 *o++ = ((t->tm_min % 10) << 4) + t->tm_min / 10;
463 *o++ = ((t->tm_sec % 10) << 4) + t->tm_sec / 10;
465 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
467 *o++ = ((z % 10) << 4) + z / 10;
470 /* unpack a date and return */
472 unpackdate (unsigned char *i)
475 t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
476 t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
477 t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
478 t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
479 t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
480 t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
483 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
485 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
489 /* unpacks bytes (7 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set */
491 unpacksms7 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
495 unsigned short *o = ud;
518 /* adjust for fill, septets */
530 v = ((i[p] >> b) & 0x7F);
532 v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
539 if (o > ud && o[-1] == 0x00A0 && escapes[v])
542 *o++ = defaultalphabet[v];
547 /* unpacks bytes (8 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set */
549 unpacksms8 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
551 unsigned short *o = ud;
570 *o++ = *i++; /* not to UTF-8 as explicitely 8 bit coding in DCS */
574 /* unpacks bytes (16 bit encoding) at i, len l septets, and places in udh and ud setting udhl and udl. udh not used if udhi not set */
576 unpacksms16 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
578 unsigned short *o = ud;
606 /* general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
608 unpacksms (unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
613 unpacksms7 (i, l, udh, udhl, ud, udl, udhi);
614 l = (l * 7 + 7) / 8; /* adjust length to return */
615 } else if (is8bit (dcs))
616 unpacksms8 (i, l, udh, udhl, ud, udl, udhi);
618 unpacksms16 (i, l, udh, udhl, ud, udl, udhi);
622 /* unpack an address from i, return byte length, unpack to o */
624 unpackaddress (char *o, unsigned char *i)
626 unsigned char l = i[0],
630 for (p = 0; p < l; p++)
633 *o++ = (i[2 + p / 2] >> 4) + '0';
635 *o++ = (i[2 + p / 2] & 0xF) + '0';
641 /* store an address at o, and return number of bytes used */
643 packaddress (unsigned char *o, char *i)
657 o[p++] |= ((*i & 0xF) << 4);
665 o[p++] |= 0xF0; /* pad */
670 sms_log (sms_t * h, char status)
671 { /* log the output, and remove file */
672 if (*h->oa || *h->da)
674 int o = open (log_file, O_CREAT | O_APPEND | O_WRONLY, 0666);
682 snprintf (mrs, sizeof (mrs), "%02X", h->mr);
683 snprintf (line, sizeof (line), "%s %c%c%c%s %s %s %s ",
684 isodate (time (0)), status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue, *h->oa ? h->oa : "-",
685 *h->da ? h->da : "-");
686 p = line + strlen (line);
687 for (n = 0; n < h->udl; n++)
688 if (h->ud[n] == '\\')
692 } else if (h->ud[n] == '\n')
696 } else if (h->ud[n] == '\r')
700 } else if (h->ud[n] < 32 || h->ud[n] == 127)
706 write (o, line, strlen (line));
709 *h->oa = *h->da = h->udl = 0;
713 /* parse and delete a file */
715 sms_readfile (sms_t * h, char *fn)
719 char dcsset = 0; /* if DSC set */
720 ast_log (LOG_EVENT, "Sending %s\n", fn);
721 h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
723 h->dcs = 0xF1; /* normal messages class 1 */
729 { /* concurrent access, we lost */
733 while (fgets (line, sizeof (line), s))
734 { /* process line in file */
736 for (p = line; *p && *p != '\n' && *p != '\r'; p++);
737 *p = 0; /* strip eoln */
739 if (!*p || *p == ';')
740 continue; /* blank line or comment, ignore */
751 if (!strcmp (line, "ud"))
752 { /* parse message (UTF-8) */
754 while (*p && o < SMSLEN)
755 h->ud[o++] = utf8decode (&p);
758 ast_log (LOG_WARNING, "UD too long in %s\n", fn);
763 if (!strcmp (line, "oa") && strlen (p) < sizeof (h->oa))
765 else if (!strcmp (line, "da") && strlen (p) < sizeof (h->oa))
767 else if (!strcmp (line, "pid"))
769 else if (!strcmp (line, "dcs"))
773 } else if (!strcmp (line, "mr"))
775 else if (!strcmp (line, "srr"))
776 h->srr = (atoi (p) ? 1 : 0);
777 else if (!strcmp (line, "vp"))
779 else if (!strcmp (line, "rp"))
780 h->rp = (atoi (p) ? 1 : 0);
781 else if (!strcmp (line, "scts"))
782 { /* get date/time */
789 if (sscanf (p, "%d-%d-%dT%d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6)
792 t.tm_year = Y - 1900;
799 h->scts = mktime (&t);
800 if (h->scts == (time_t) - 1)
801 ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
804 ast_log (LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
806 } else if (*p == '#')
807 { /* raw hex format */
812 if (!strcmp (line, "ud"))
815 while (*p && o < SMSLEN)
817 if (isxdigit (*p) && isxdigit (p[1]) && isxdigit (p[2]) && isxdigit (p[3]))
820 (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 12) +
821 (((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
822 (((isalpha (p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha (p[3]) ? 9 : 0) + (p[3] & 0xF));
829 ast_log (LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
831 ast_log (LOG_WARNING, "Only ud can use ## format, %s\n", fn);
832 } else if (!strcmp (line, "ud"))
835 while (*p && o < SMSLEN)
837 if (isxdigit (*p) && isxdigit (p[1]))
839 h->ud[o++] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
846 ast_log (LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
847 } else if (!strcmp (line, "udh"))
848 { /* user data header */
851 while (*p && o < SMSLEN)
853 if (isxdigit (*p) && isxdigit (p[1]))
855 h->udh[o] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
863 ast_log (LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
865 ast_log (LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
867 ast_log (LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
870 if (!dcsset && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
872 if (packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
874 if (packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
875 ast_log (LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
878 h->dcs = 0x08; /* default to 16 bit */
879 ast_log (LOG_WARNING, "Sending in 16 bit format (%s)\n", fn);
883 h->dcs = 0xF5; /* default to 8 bit */
884 ast_log (LOG_WARNING, "Sending in 8 bit format (%s)\n", fn);
887 if (is7bit (h->dcs) && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
888 ast_log (LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
889 if (is8bit (h->dcs) && packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
890 ast_log (LOG_WARNING, "Invalid 8 bit data %s\n", fn);
891 if (is16bit (h->dcs) && packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
892 ast_log (LOG_WARNING, "Invalid 16 bit data %s\n", fn);
896 /* white a received text message to a file */
898 sms_writefile (sms_t * h)
903 strncpy (fn, spool_dir, sizeof (fn) - 1);
904 mkdir (fn, 0777); /* ensure it exists */
905 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
906 mkdir (fn, 0777); /* ensure it exists */
907 strncpy (fn2, fn, sizeof (fn2) - 1);
908 snprintf (fn2 + strlen (fn2), sizeof (fn2) - strlen (fn2), "/%s.%s-%d", h->queue, isodate (h->scts), seq++);
909 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/.%s", fn2 + strlen (fn) + 1);
914 fprintf (o, "oa=%s\n", h->oa);
916 fprintf (o, "da=%s\n", h->da);
921 for (p = 0; p < h->udhl; p++)
922 fprintf (o, "%02X", h->udh[p]);
928 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
930 fputc (';', o); /* cannot use ud=, but include as a comment for human readable */
932 for (p = 0; p < h->udl; p++)
934 unsigned short v = h->ud[p];
941 fputc (0xC0 + (v >> 6), o);
942 fputc (0x80 + (v & 0x3F), o);
945 fputc (0xE0 + (v >> 12), o);
946 fputc (0x80 + ((v >> 6) & 0x3F), o);
947 fputc (0x80 + (v & 0x3F), o);
951 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
954 for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
956 { /* can write in ucs-1 hex */
958 for (p = 0; p < h->udl; p++)
959 fprintf (o, "%02X", h->ud[p]);
962 { /* write in UCS-2 */
964 for (p = 0; p < h->udl; p++)
965 fprintf (o, "%04X", h->ud[p]);
971 fprintf (o, "scts=%s\n", isodate (h->scts));
973 fprintf (o, "pid=%d\n", h->pid);
975 fprintf (o, "dcs=%d\n", h->dcs);
977 fprintf (o, "vp=%d\n", h->vp);
979 fprintf (o, "srr=1\n");
981 fprintf (o, "mr=%d\n", h->mr);
983 fprintf (o, "rp=1\n");
985 if (rename (fn, fn2))
988 ast_log (LOG_EVENT, "Received to %s\n", fn2);
992 /* read dir skipping dot files... */
993 static struct dirent *
994 readdirqueue (DIR * d, char *queue)
1001 while (f && (*f->d_name == '.' || strncmp (f->d_name, queue, strlen (queue)) || f->d_name[strlen (queue)] != '.'));
1005 /* handle the incoming message */
1006 static unsigned char
1007 sms_handleincoming (sms_t * h)
1009 unsigned char p = 3;
1012 if ((h->imsg[2] & 3) == 1)
1014 h->udhl = h->udl = 0;
1016 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
1017 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
1018 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1019 strncpy (h->oa, h->cli, sizeof (h->oa) - 1);
1021 h->mr = h->imsg[p++];
1022 p += unpackaddress (h->da, h->imsg + p);
1023 h->pid = h->imsg[p++];
1024 h->dcs = h->imsg[p++];
1025 if ((h->imsg[2] & 0x18) == 0x10)
1027 if (h->imsg[p] < 144)
1028 h->vp = (h->imsg[p] + 1) * 5;
1029 else if (h->imsg[p] < 168)
1030 h->vp = 720 + (h->imsg[p] - 143) * 30;
1031 else if (h->imsg[p] < 197)
1032 h->vp = (h->imsg[p] - 166) * 1440;
1034 h->vp = (h->imsg[p] - 192) * 10080;
1036 } else if (h->imsg[2] & 0x18)
1037 p += 7; /* ignore enhanced / absolute VP */
1038 p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1039 h->rx = 1; /* received message */
1040 sms_writefile (h); /* write the file */
1041 if (p != h->imsg[1] + 2)
1043 ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1044 return 0xFF; /* duh! */
1048 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
1053 if (!(h->imsg[2] & 3))
1055 *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
1056 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
1057 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
1058 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1060 p += unpackaddress (h->oa, h->imsg + p);
1061 h->pid = h->imsg[p++];
1062 h->dcs = h->imsg[p++];
1063 h->scts = unpackdate (h->imsg + p);
1065 p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1066 h->rx = 1; /* received message */
1067 sms_writefile (h); /* write the file */
1068 if (p != h->imsg[1] + 2)
1070 ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1071 return 0xFF; /* duh! */
1075 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
1079 return 0; /* no error */
1083 #define NAME_MAX 1024
1087 sms_nextoutgoing (sms_t * h)
1088 { /* find and fill in next message, or send a REL if none waiting */
1089 char fn[100 + NAME_MAX] = "";
1092 strncpy (fn, spool_dir, sizeof (fn) - 1);
1093 mkdir (fn, 0777); /* ensure it exists */
1094 h->rx = 0; /* outgoing message */
1095 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? "mttx" : "motx");
1096 mkdir (fn, 0777); /* ensure it exists */
1100 struct dirent *f = readdirqueue (d, h->queue);
1103 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", f->d_name);
1104 sms_readfile (h, fn);
1105 if (readdirqueue (d, h->queue))
1106 more = 1; /* more to send */
1110 if (*h->da || *h->oa)
1111 { /* message to send */
1112 unsigned char p = 2;
1113 h->omsg[0] = 0x91; /* SMS_DATA */
1116 h->omsg[p++] = (more ? 4 : 0);
1117 p += packaddress (h->omsg + p, h->oa);
1118 h->omsg[p++] = h->pid;
1119 h->omsg[p++] = h->dcs;
1120 packdate (h->omsg + p, h->scts);
1122 p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1126 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
1128 h->mr = message_ref++;
1129 h->omsg[p++] = h->mr;
1130 p += packaddress (h->omsg + p, h->da);
1131 h->omsg[p++] = h->pid;
1132 h->omsg[p++] = h->dcs;
1136 h->omsg[p++] = (h->vp + 4) / 5 - 1;
1137 else if (h->vp < 1440)
1138 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
1139 else if (h->vp < 43200)
1140 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
1141 else if (h->vp < 635040)
1142 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
1144 h->omsg[p++] = 255; /* max */
1146 p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1152 h->omsg[0] = 0x94; /* SMS_REL */
1159 sms_debug (char *dir, unsigned char *msg)
1161 char txt[259 * 3 + 1],
1162 *p = txt; /* always long enough */
1165 while (q < n && q < 30)
1167 sprintf (p, " %02X", msg[q++]);
1172 ast_verbose (VERBOSE_PREFIX_3 "SMS %s%s\n", dir, txt);
1176 sms_messagerx (sms_t * h)
1178 sms_debug ("RX", h->imsg);
1182 case 0x91: /* SMS_DATA */
1184 unsigned char cause = sms_handleincoming (h);
1188 h->omsg[0] = 0x95; /* SMS_ACK */
1190 h->omsg[2] = 0x00; /* deliver report */
1191 h->omsg[3] = 0x00; /* no parameters */
1195 h->omsg[0] = 0x96; /* SMS_NACK */
1197 h->omsg[2] = 0; /* delivery report */
1198 h->omsg[3] = cause; /* cause */
1199 h->omsg[4] = 0; /* no parameters */
1204 case 0x92: /* SMS_ERROR */
1206 sms_messagetx (h); /* send whatever we sent again */
1208 case 0x93: /* SMS_EST */
1209 sms_nextoutgoing (h);
1211 case 0x94: /* SMS_REL */
1212 h->hangup = 1; /* hangup */
1214 case 0x95: /* SMS_ACK */
1216 sms_nextoutgoing (h);
1218 case 0x96: /* SMS_NACK */
1221 sms_nextoutgoing (h);
1223 default: /* Unknown */
1224 h->omsg[0] = 0x92; /* SMS_ERROR */
1226 h->omsg[2] = 3; /* unknown message type; */
1233 sms_messagetx (sms_t * h)
1235 unsigned char c = 0,
1237 for (p = 0; p < h->omsg[1] + 2; p++)
1239 h->omsg[h->omsg[1] + 2] = 0 - c;
1240 sms_debug ("TX", h->omsg);
1243 if (h->omsg[0] == 0x93)
1244 h->opause = 2400; /* initial message delay 300ms (for BT) */
1248 h->obyten = h->omsg[1] + 3;
1252 sms_generate (struct ast_channel *chan, void *data, int len, int samples)
1254 struct ast_frame f = { 0 };
1255 unsigned char waste[AST_FRIENDLY_OFFSET];
1257 unsigned char buf[800];
1259 signed short buf[800];
1264 if (len > sizeof (buf))
1266 ast_log (LOG_WARNING, "Only doing %d bytes (%d bytes requested)\n", sizeof (buf) / sizeof (signed short), len);
1274 waste[0] = 0; /* make compiler happy */
1275 f.frametype = AST_FRAME_VOICE;
1277 f.subclass = AST_FORMAT_ALAW;
1278 f.datalen = samples;
1280 f.subclass = AST_FORMAT_SLINEAR;
1281 f.datalen = samples * 2;
1283 f.offset = AST_FRIENDLY_OFFSET;
1286 f.samples = samples;
1288 /* create a buffer containing the digital sms pattern */
1289 for (i = 0; i < samples; i++)
1298 else if (h->obyten || h->osync)
1299 { /* sending data */
1301 buf[i] = wavea[h->ophase];
1303 buf[i] = wave[h->ophase];
1305 if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
1307 if ((h->ophasep += 12) >= 80)
1311 h->osync--; /* sending sync bits */
1317 h->obyte = 0; /* start bit; */
1318 else if (h->obitp == 2)
1319 h->obyte = h->omsg[h->obytep];
1320 else if (h->obitp == 10)
1322 h->obyte = 1; /* stop bit */
1325 if (h->obytep == h->obyten)
1327 h->obytep = h->obyten = 0; /* sent */
1328 h->osync = 10; /* trailing marks */
1335 if (ast_write (chan, &f) < 0)
1337 ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
1344 sms_process (sms_t * h, int samples, signed short *data)
1346 if (h->obyten || h->osync)
1347 return; /* sending */
1350 unsigned long long m0,
1352 if (abs (*data) > h->imag)
1353 h->imag = abs (*data);
1355 h->imag = h->imag * 7 / 8;
1359 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
1360 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
1361 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
1362 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
1363 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
1364 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
1365 if ((h->ips0 += 21) >= 80)
1367 if ((h->ipc0 += 21) >= 80)
1369 if ((h->ips1 += 13) >= 80)
1371 if ((h->ipc1 += 13) >= 80)
1382 bit = ((h->ibitt > 1) ? 1 : 0);
1383 if (bit != h->ibitl)
1388 if (!h->ibitn && h->ibitc == 4 && !bit)
1393 if (bit && h->ibitc == 200)
1394 { /* sync, restart message */
1395 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1400 if (h->iphasep >= 80)
1403 if (h->ibitn++ == 9)
1405 if (!bit) /* bad stop bit */
1406 h->ierr = 0xFF; /* unknown error */
1409 if (h->ibytep < sizeof (h->imsg))
1411 h->imsg[h->ibytep] = h->ibytev;
1412 h->ibytec += h->ibytev;
1414 } else if (h->ibytep == sizeof (h->imsg))
1415 h->ierr = 2; /* bad message length */
1416 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr)
1421 h->ierr = 1; /* bad checksum */
1426 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1431 { /* lost carrier */
1432 if (h->idle++ == 80000)
1433 { /* nothing happening */
1434 ast_log (LOG_EVENT, "No data, hanging up\n");
1441 h->omsg[0] = 0x92; /* error */
1443 h->omsg[2] = h->ierr;
1444 sms_messagetx (h); /* send error */
1446 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1452 static struct ast_generator smsgen = {
1454 release:sms_release,
1455 generate:sms_generate,
1459 sms_exec (struct ast_channel *chan, void *data)
1462 struct localuser *u;
1463 struct ast_frame *f;
1465 h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1466 h.dcs = 0xF1; /* default */
1469 ast_log (LOG_ERROR, "Requires queue name at least\n");
1473 if (chan->cid.cid_num)
1474 strncpy (h.cli, chan->cid.cid_num, sizeof (h.cli) - 1);
1477 unsigned char *d = data,
1480 if (!*d || *d == '|')
1482 ast_log (LOG_ERROR, "Requires queue name\n");
1485 for (p = d; *p && *p != '|'; p++);
1486 if (p - d >= sizeof (h.queue))
1488 ast_log (LOG_ERROR, "Queue name too long\n");
1491 strncpy (h.queue, d, p - d);
1495 for (p = h.queue; *p; p++)
1497 *p = '-'; /* make very safe for filenames */
1498 while (*d && *d != '|')
1502 case 'a': /* we have to send the initial FSK sequence */
1505 case 's': /* we are acting as a service centre talking to a phone */
1508 /* the following apply if there is an arg3/4 and apply to the created message file */
1513 h.dcs |= 4; /* octets */
1521 case '7': /* set the pid for saved local message */
1522 h.pid = 0x40 + (*d & 0xF);
1529 /* submitting a message, not taking call. */
1530 /* depricated, use smsq instead */
1533 for (p = d; *p && *p != '|'; p++);
1536 if (strlen (d) >= sizeof (h.oa))
1538 ast_log (LOG_ERROR, "Address too long %s\n", d);
1543 strncpy (h.oa, d, sizeof (h.oa) - 1);
1546 strncpy (h.da, d, sizeof (h.da) - 1);
1549 strncpy (h.oa, h.cli, sizeof (h.oa) - 1);
1552 while (*p && h.udl < SMSLEN)
1553 h.ud[h.udl++] = utf8decode (&p);
1554 if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1555 ast_log (LOG_WARNING, "Invalid 7 bit GSM data\n");
1556 if (is8bit (h.dcs) && packsms8 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1557 ast_log (LOG_WARNING, "Invalid 8 bit data\n");
1558 if (is16bit (h.dcs) && packsms16 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1559 ast_log (LOG_WARNING, "Invalid 16 bit data\n");
1560 h.rx = 0; /* sent message */
1568 /* set up SMS_EST initial message */
1576 if (chan->_state != AST_STATE_UP)
1580 res = ast_set_write_format (chan, AST_FORMAT_ALAW);
1582 res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
1585 res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
1588 LOCAL_USER_REMOVE (u);
1589 ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
1593 if (ast_activate_generator (chan, &smsgen, &h) < 0)
1595 LOCAL_USER_REMOVE (u);
1596 ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
1600 /* Do our thing here */
1601 while (ast_waitfor (chan, -1) > -1 && !h.hangup)
1603 f = ast_read (chan);
1606 if (f->frametype == AST_FRAME_VOICE)
1608 sms_process (&h, f->samples, f->data);
1614 sms_log (&h, '?'); /* log incomplete message */
1616 LOCAL_USER_REMOVE (u);
1621 unload_module (void)
1623 STANDARD_HANGUP_LOCALUSERS;
1624 return ast_unregister_application (app);
1633 for (p = 0; p < 80; p++)
1634 wavea[p] = AST_LIN2A (wave[p]);
1637 snprintf (log_file, sizeof (log_file), "%s/sms", ast_config_AST_LOG_DIR);
1638 snprintf (spool_dir, sizeof (spool_dir), "%s/sms", ast_config_AST_SPOOL_DIR);
1639 return ast_register_application (app, sms_exec, synopsis, descrip);
1652 STANDARD_USECOUNT (res);
1659 return ASTERISK_GPL_KEY;