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>
29 #include "../astconf.h"
31 /* output using Alaw rather than linear */
35 /* Add full VP support */
36 /* Handle status report messages (generation and reception) */
37 /* Time zones on time stamps */
40 static volatile unsigned char message_ref; /* arbitary message ref */
41 static volatile unsigned int seq; /* arbitrary message sequence number for unqiue files */
43 static char log_file[255];
44 static char spool_dir[255];
46 static char *tdesc = "SMS/PSTN handler";
48 static char *app = "SMS";
50 static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
52 static char *descrip =
53 " SMS(name|[a][s]): SMS handles exchange of SMS data with a call to/from SMS capabale\n"
54 "phone or SMS PSTN service centre. Can send and/or receive SMS messages.\n"
55 "Returns 0 if call handled correctly, or -1 if there were any problems.\n"
56 "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n"
57 "Typical usage is to use to handle called from the SMS service centre CLI,\n"
58 "or to set up a call using 'outgoing' or manager interface to connect service centre to SMS()\n"
59 "name is the name of the queue used in /var/spool/asterisk/sms\n"
60 "Argument 'a' means answer, i.e. send initial FSK packet.\n"
61 "Argument 's' means act as service centre talking to a phone.\n"
62 "Messages are processed as per text file message queues.\n" "smsq is a command to generate message queues and send messages.\n";
64 static signed short wave[] =
65 { 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
66 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
68 -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
70 -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
74 static unsigned char wavea[80];
81 /* SMS 7 bit character mapping to UCS-2 */
82 static const unsigned short defaultalphabet[] = {
83 0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
84 0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
85 0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
86 0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
87 ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
88 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
89 161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
90 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
91 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
92 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
95 static const unsigned short escapes[] = {
96 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x000C, 0, 0, 0, 0, 0,
97 0, 0, 0, 0, 0x005E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
98 0, 0, 0, 0, 0, 0, 0, 0, 0x007B, 0x007D, 0, 0, 0, 0, 0, 0x005C,
99 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x005B, 0x007E, 0x005D, 0,
100 0x007C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
102 0, 0, 0, 0, 0, 0x20AC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
103 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
106 #define SMSLEN 160 /* max SMS length */
110 unsigned char hangup; /* we are done... */
111 unsigned char err; /* set for any errors */
112 unsigned char smsc:1; /* we are SMSC */
113 unsigned char rx:1; /* this is a received message */
114 char queue[30]; /* queue name */
115 char oa[20]; /* originating address */
116 char da[20]; /* destination address */
117 time_t scts; /* time stamp, UTC */
118 unsigned char pid; /* protocol ID */
119 unsigned char dcs; /* data coding scheme */
120 short mr; /* message reference - actually a byte, but usde -1 for not set */
121 int udl; /* user data length */
122 int udhl; /* user data header length */
123 unsigned char srr:1; /* Status Report request */
124 unsigned char udhi:1; /* User Data Header required, even if length 0 */
125 unsigned char rp:1; /* Reply Path */
126 unsigned int vp; /* validity period in minutes, 0 for not set */
127 unsigned short ud[SMSLEN]; /* user data (message), UCS-2 coded */
128 unsigned char udh[SMSLEN]; /* user data header */
129 unsigned char cli[20]; /* caller ID */
130 unsigned char ophase; /* phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
131 unsigned char ophasep; /* phase (0-79) for 1200 bps */
132 unsigned char obyte; /* byte being sent */
133 unsigned int opause; /* silent pause before sending (in sample periods) */
134 unsigned char obitp; /* bit in byte */
135 unsigned char osync; /* sync bits to send */
136 unsigned char obytep; /* byte in data */
137 unsigned char obyten; /* bytes in data */
138 unsigned char omsg[256]; /* data buffer (out) */
139 unsigned char imsg[200]; /* data buffer (in) */
140 signed long long ims0,
143 imc1; /* magnitude averages sin/cos 0/1 */
145 unsigned short imag; /* signal level */
149 ipc1; /* phase sin/cos 0/1 */
150 unsigned char ibitl; /* last bit */
151 unsigned char ibitc; /* bit run length count */
152 unsigned char iphasep; /* bit phase (0-79) for 1200 bps */
153 unsigned char ibitn; /* bit number in byte being received */
154 unsigned char ibytev; /* byte value being received */
155 unsigned char ibytep; /* byte pointer in messafe */
156 unsigned char ibytec; /* byte checksum for message */
157 unsigned char ierr; /* error flag */
158 unsigned char ibith; /* history of last bits */
159 unsigned char ibitt; /* total of 1's in last 3 bites */
160 /* more to go here */
163 /* different types of encoding */
164 #define is7bit(dcs) (((dcs)&0xC0)?(!((dcs)&4)):(!((dcs)&12)))
165 #define is8bit(dcs) (((dcs)&0xC0)?(((dcs)&4)):(((dcs)&12)==4))
166 #define is16bit(dcs) (((dcs)&0xC0)?0:(((dcs)&12)==8))
169 sms_alloc (struct ast_channel *chan, void *params)
175 sms_release (struct ast_channel *chan, void *data)
180 static void sms_messagetx (sms_t * h);
182 /* copy number, skipping non digits apart from leading + */
184 numcpy (char *d, char *s)
199 { /* static, return a date/time in ISO format */
200 static char date[20];
201 strftime (date, sizeof (date), "%Y-%m-%dT%H:%M:%S", localtime (&t));
205 /* reads next UCS character from null terminated UTF-8 string and advanced pointer */
206 /* for non valid UTF-8 sequences, returns character as is */
207 /* Does not advance pointer for null termination */
209 utf8decode (unsigned char **pp)
211 unsigned char *p = *pp;
213 return 0; /* null termination of string */
216 return *p; /* ascii or continuation character */
219 if (*p < 0xC2 || (p[1] & 0xC0) != 0x80)
220 return *p; /* not valid UTF-8 */
222 return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
226 if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80)
227 return *p; /* not valid UTF-8 */
229 return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
233 if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80)
234 return *p; /* not valid UTF-8 */
236 return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
240 if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
241 || (p[4] & 0xC0) != 0x80)
242 return *p; /* not valid UTF-8 */
244 return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
248 if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
249 || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80)
250 return *p; /* not valid UTF-8 */
252 return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) +
255 return *p; /* not sensible */
258 /* 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 */
259 /* The return value is the number of septets packed in to o, which is internally limited to SMSLEN */
260 /* o can be null, in which case this is used to validate or count only */
261 /* if the input contains invalid characters then the return value is -1 */
263 packsms7 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
292 }; /* filling to septet boundary */
302 for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
303 if (v == 128 && u && n + 1 < SMSLEN)
305 for (v = 0; v < 128 && escapes[v] != u; v++);
307 { /* escaped sequence */
316 o[p] = (27 >> (7 - b));
322 return -1; /* invalid character */
331 o[p] = (v >> (7 - b));
339 /* 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 */
340 /* The return value is the number of bytes packed in to o, which is internally limited to 140 */
341 /* o can be null, in which case this is used to validate or count only */
342 /* if the input contains invalid characters then the return value is -1 */
344 packsms8 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
347 /* header - no encoding */
364 if (u < 0 || u > 0xFF)
365 return -1; /* not valid */
374 /* 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 */
375 /* The return value is the number of bytes packed in to o, which is internally limited to 140 */
376 /* o can be null, in which case this is used to validate or count only */
377 /* if the input contains invalid characters then the return value is -1 */
379 packsms16 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
382 /* header - no encoding */
402 return p - 1; /* could not fit last character */
411 /* general pack, with length and data, returns number of bytes of target used */
413 packsms (unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
415 unsigned char *p = base;
421 l = packsms7 (p + 1, udhl, udh, udl, ud);
425 p += (l * 7 + 7) / 8;
426 } else if (is8bit (dcs))
428 l = packsms8 (p + 1, udhl, udh, udl, ud);
435 l = packsms16 (p + 1, udhl, udh, udl, ud);
442 *p++ = 0; /* no user data */
447 /* pack a date and return */
449 packdate (unsigned char *o, time_t w)
451 struct tm *t = localtime (&w);
452 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
453 int z = -t->tm_gmtoff / 60 / 15;
455 int z = timezone / 60 / 15;
457 *o++ = ((t->tm_year % 10) << 4) + (t->tm_year % 100) / 10;
458 *o++ = (((t->tm_mon + 1) % 10) << 4) + (t->tm_mon + 1) / 10;
459 *o++ = ((t->tm_mday % 10) << 4) + t->tm_mday / 10;
460 *o++ = ((t->tm_hour % 10) << 4) + t->tm_hour / 10;
461 *o++ = ((t->tm_min % 10) << 4) + t->tm_min / 10;
462 *o++ = ((t->tm_sec % 10) << 4) + t->tm_sec / 10;
464 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
466 *o++ = ((z % 10) << 4) + z / 10;
469 /* unpack a date and return */
471 unpackdate (unsigned char *i)
474 t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
475 t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
476 t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
477 t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
478 t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
479 t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
482 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
484 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
488 /* 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 */
490 unpacksms7 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
494 unsigned short *o = ud;
517 /* adjust for fill, septets */
529 v = ((i[p] >> b) & 0x7F);
531 v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
538 if (o > ud && o[-1] == 0x00A0 && escapes[v])
541 *o++ = defaultalphabet[v];
546 /* 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 */
548 unpacksms8 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
550 unsigned short *o = ud;
569 *o++ = *i++; /* not to UTF-8 as explicitely 8 bit coding in DCS */
573 /* 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 */
575 unpacksms16 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
577 unsigned short *o = ud;
605 /* general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
607 unpacksms (unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
612 unpacksms7 (i, l, udh, udhl, ud, udl, udhi);
613 l = (l * 7 + 7) / 8; /* adjust length to return */
614 } else if (is8bit (dcs))
615 unpacksms8 (i, l, udh, udhl, ud, udl, udhi);
617 unpacksms16 (i, l, udh, udhl, ud, udl, udhi);
621 /* unpack an address from i, return byte length, unpack to o */
623 unpackaddress (char *o, unsigned char *i)
625 unsigned char l = i[0],
629 for (p = 0; p < l; p++)
632 *o++ = (i[2 + p / 2] >> 4) + '0';
634 *o++ = (i[2 + p / 2] & 0xF) + '0';
640 /* store an address at o, and return number of bytes used */
642 packaddress (unsigned char *o, char *i)
656 o[p++] |= ((*i & 0xF) << 4);
664 o[p++] |= 0xF0; /* pad */
669 sms_log (sms_t * h, char status)
670 { /* log the output, and remove file */
671 if (*h->oa || *h->da)
673 int o = open (log_file, O_CREAT | O_APPEND | O_WRONLY, 0666);
681 snprintf (mrs, sizeof (mrs), "%02X", h->mr);
682 snprintf (line, sizeof (line), "%s %c%c%c%s %s %s %s ",
683 isodate (time (0)), status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue, *h->oa ? h->oa : "-",
684 *h->da ? h->da : "-");
685 p = line + strlen (line);
686 for (n = 0; n < h->udl; n++)
687 if (h->ud[n] == '\\')
691 } else if (h->ud[n] == '\n')
695 } else if (h->ud[n] == '\r')
699 } else if (h->ud[n] < 32 || h->ud[n] == 127)
705 write (o, line, strlen (line));
708 *h->oa = *h->da = h->udl = 0;
712 /* parse and delete a file */
714 sms_readfile (sms_t * h, char *fn)
718 char dcsset = 0; /* if DSC set */
719 ast_log (LOG_EVENT, "Sending %s\n", fn);
720 h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
722 h->dcs = 0xF1; /* normal messages class 1 */
728 { /* concurrent access, we lost */
732 while (fgets (line, sizeof (line), s))
733 { /* process line in file */
735 for (p = line; *p && *p != '\n' && *p != '\r'; p++);
736 *p = 0; /* strip eoln */
738 if (!*p || *p == ';')
739 continue; /* blank line or comment, ignore */
750 if (!strcmp (line, "ud"))
751 { /* parse message (UTF-8) */
753 while (*p && o < SMSLEN)
754 h->ud[o++] = utf8decode (&p);
757 ast_log (LOG_WARNING, "UD too long in %s\n", fn);
762 if (!strcmp (line, "oa") && strlen (p) < sizeof (h->oa))
764 else if (!strcmp (line, "da") && strlen (p) < sizeof (h->oa))
766 else if (!strcmp (line, "pid"))
768 else if (!strcmp (line, "dcs"))
772 } else if (!strcmp (line, "mr"))
774 else if (!strcmp (line, "srr"))
775 h->srr = (atoi (p) ? 1 : 0);
776 else if (!strcmp (line, "vp"))
778 else if (!strcmp (line, "rp"))
779 h->rp = (atoi (p) ? 1 : 0);
780 else if (!strcmp (line, "scts"))
781 { /* get date/time */
788 if (sscanf (p, "%d-%d-%dT%d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6)
791 t.tm_year = Y - 1900;
798 h->scts = mktime (&t);
799 if (h->scts == (time_t) - 1)
800 ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
803 ast_log (LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
805 } else if (*p == '#')
806 { /* raw hex format */
811 if (!strcmp (line, "ud"))
814 while (*p && o < SMSLEN)
816 if (isxdigit (*p) && isxdigit (p[1]) && isxdigit (p[2]) && isxdigit (p[3]))
819 (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 12) +
820 (((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
821 (((isalpha (p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha (p[3]) ? 9 : 0) + (p[3] & 0xF));
828 ast_log (LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
830 ast_log (LOG_WARNING, "Only ud can use ## format, %s\n", fn);
831 } else if (!strcmp (line, "ud"))
834 while (*p && o < SMSLEN)
836 if (isxdigit (*p) && isxdigit (p[1]))
838 h->ud[o++] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
845 ast_log (LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
846 } else if (!strcmp (line, "udh"))
847 { /* user data header */
850 while (*p && o < SMSLEN)
852 if (isxdigit (*p) && isxdigit (p[1]))
854 h->udh[o] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
862 ast_log (LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
864 ast_log (LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
866 ast_log (LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
869 if (!dcsset && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
871 if (packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
873 if (packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
874 ast_log (LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
877 h->dcs = 0x08; /* default to 16 bit */
878 ast_log (LOG_WARNING, "Sending in 16 bit format (%s)\n", fn);
882 h->dcs = 0xF5; /* default to 8 bit */
883 ast_log (LOG_WARNING, "Sending in 8 bit format (%s)\n", fn);
886 if (is7bit (h->dcs) && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
887 ast_log (LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
888 if (is8bit (h->dcs) && packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
889 ast_log (LOG_WARNING, "Invalid 8 bit data %s\n", fn);
890 if (is16bit (h->dcs) && packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
891 ast_log (LOG_WARNING, "Invalid 16 bit data %s\n", fn);
895 /* white a received text message to a file */
897 sms_writefile (sms_t * h)
902 strncpy (fn, spool_dir, sizeof (fn) - 1);
903 mkdir (fn, 0777); /* ensure it exists */
904 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
905 mkdir (fn, 0777); /* ensure it exists */
906 strncpy (fn2, fn, sizeof (fn2) - 1);
907 snprintf (fn2 + strlen (fn2), sizeof (fn2) - strlen (fn2), "/%s.%s-%d", h->queue, isodate (h->scts), seq++);
908 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/.%s", fn2 + strlen (fn) + 1);
913 fprintf (o, "oa=%s\n", h->oa);
915 fprintf (o, "da=%s\n", h->da);
920 for (p = 0; p < h->udhl; p++)
921 fprintf (o, "%02X", h->udh[p]);
927 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
929 fputc (';', o); /* cannot use ud=, but include as a comment for human readable */
931 for (p = 0; p < h->udl; p++)
933 unsigned short v = h->ud[p];
940 fputc (0xC0 + (v >> 6), o);
941 fputc (0x80 + (v & 0x3F), o);
944 fputc (0xE0 + (v >> 12), o);
945 fputc (0x80 + ((v >> 6) & 0x3F), o);
946 fputc (0x80 + (v & 0x3F), o);
950 for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
953 for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
955 { /* can write in ucs-1 hex */
957 for (p = 0; p < h->udl; p++)
958 fprintf (o, "%02X", h->ud[p]);
961 { /* write in UCS-2 */
963 for (p = 0; p < h->udl; p++)
964 fprintf (o, "%04X", h->ud[p]);
970 fprintf (o, "scts=%s\n", isodate (h->scts));
972 fprintf (o, "pid=%d\n", h->pid);
974 fprintf (o, "dcs=%d\n", h->dcs);
976 fprintf (o, "vp=%d\n", h->vp);
978 fprintf (o, "srr=1\n");
980 fprintf (o, "mr=%d\n", h->mr);
982 fprintf (o, "rp=1\n");
984 if (rename (fn, fn2))
987 ast_log (LOG_EVENT, "Received to %s\n", fn2);
991 /* read dir skipping dot files... */
992 static struct dirent *
993 readdirqueue (DIR * d, char *queue)
1000 while (f && (*f->d_name == '.' || strncmp (f->d_name, queue, strlen (queue)) || f->d_name[strlen (queue)] != '.'));
1004 /* handle the incoming message */
1005 static unsigned char
1006 sms_handleincoming (sms_t * h)
1008 unsigned char p = 3;
1011 if ((h->imsg[2] & 3) == 1)
1013 h->udhl = h->udl = 0;
1015 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
1016 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
1017 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1018 strncpy (h->oa, h->cli, sizeof (h->oa) - 1);
1020 h->mr = h->imsg[p++];
1021 p += unpackaddress (h->da, h->imsg + p);
1022 h->pid = h->imsg[p++];
1023 h->dcs = h->imsg[p++];
1024 if ((h->imsg[2] & 0x18) == 0x10)
1026 if (h->imsg[p] < 144)
1027 h->vp = (h->imsg[p] + 1) * 5;
1028 else if (h->imsg[p] < 168)
1029 h->vp = 720 + (h->imsg[p] - 143) * 30;
1030 else if (h->imsg[p] < 197)
1031 h->vp = (h->imsg[p] - 166) * 1440;
1033 h->vp = (h->imsg[p] - 192) * 10080;
1035 } else if (h->imsg[2] & 0x18)
1036 p += 7; /* ignore enhanced / absolute VP */
1037 p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1038 h->rx = 1; /* received message */
1039 sms_writefile (h); /* write the file */
1040 if (p != h->imsg[1] + 2)
1042 ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1043 return 0xFF; /* duh! */
1047 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
1052 if (!(h->imsg[2] & 3))
1054 *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
1055 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
1056 h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
1057 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
1059 p += unpackaddress (h->oa, h->imsg + p);
1060 h->pid = h->imsg[p++];
1061 h->dcs = h->imsg[p++];
1062 h->scts = unpackdate (h->imsg + p);
1064 p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1065 h->rx = 1; /* received message */
1066 sms_writefile (h); /* write the file */
1067 if (p != h->imsg[1] + 2)
1069 ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1070 return 0xFF; /* duh! */
1074 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
1078 return 0; /* no error */
1082 #define NAME_MAX 1024
1086 sms_nextoutgoing (sms_t * h)
1087 { /* find and fill in next message, or send a REL if none waiting */
1088 char fn[100 + NAME_MAX] = "";
1091 strncpy (fn, spool_dir, sizeof (fn) - 1);
1092 mkdir (fn, 0777); /* ensure it exists */
1093 h->rx = 0; /* outgoing message */
1094 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? "mttx" : "motx");
1095 mkdir (fn, 0777); /* ensure it exists */
1099 struct dirent *f = readdirqueue (d, h->queue);
1102 snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", f->d_name);
1103 sms_readfile (h, fn);
1104 if (readdirqueue (d, h->queue))
1105 more = 1; /* more to send */
1109 if (*h->da || *h->oa)
1110 { /* message to send */
1111 unsigned char p = 2;
1112 h->omsg[0] = 0x91; /* SMS_DATA */
1115 h->omsg[p++] = (more ? 4 : 0);
1116 p += packaddress (h->omsg + p, h->oa);
1117 h->omsg[p++] = h->pid;
1118 h->omsg[p++] = h->dcs;
1119 packdate (h->omsg + p, h->scts);
1121 p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1125 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
1127 h->mr = message_ref++;
1128 h->omsg[p++] = h->mr;
1129 p += packaddress (h->omsg + p, h->da);
1130 h->omsg[p++] = h->pid;
1131 h->omsg[p++] = h->dcs;
1135 h->omsg[p++] = (h->vp + 4) / 5 - 1;
1136 else if (h->vp < 1440)
1137 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
1138 else if (h->vp < 43200)
1139 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
1140 else if (h->vp < 635040)
1141 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
1143 h->omsg[p++] = 255; /* max */
1145 p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1151 h->omsg[0] = 0x94; /* SMS_REL */
1158 sms_debug (char *dir, unsigned char *msg)
1160 char txt[259 * 3 + 1],
1161 *p = txt; /* always long enough */
1164 while (q < n && q < 30)
1166 sprintf (p, " %02X", msg[q++]);
1171 ast_verbose (VERBOSE_PREFIX_3 "SMS %s%s\n", dir, txt);
1175 sms_messagerx (sms_t * h)
1177 sms_debug ("RX", h->imsg);
1181 case 0x91: /* SMS_DATA */
1183 unsigned char cause = sms_handleincoming (h);
1187 h->omsg[0] = 0x95; /* SMS_ACK */
1189 h->omsg[2] = 0x00; /* deliver report */
1190 h->omsg[3] = 0x00; /* no parameters */
1194 h->omsg[0] = 0x96; /* SMS_NACK */
1196 h->omsg[2] = 0; /* delivery report */
1197 h->omsg[3] = cause; /* cause */
1198 h->omsg[4] = 0; /* no parameters */
1203 case 0x92: /* SMS_ERROR */
1205 sms_messagetx (h); /* send whatever we sent again */
1207 case 0x93: /* SMS_EST */
1208 sms_nextoutgoing (h);
1210 case 0x94: /* SMS_REL */
1211 h->hangup = 1; /* hangup */
1213 case 0x95: /* SMS_ACK */
1215 sms_nextoutgoing (h);
1217 case 0x96: /* SMS_NACK */
1220 sms_nextoutgoing (h);
1222 default: /* Unknown */
1223 h->omsg[0] = 0x92; /* SMS_ERROR */
1225 h->omsg[2] = 3; /* unknown message type; */
1232 sms_messagetx (sms_t * h)
1234 unsigned char c = 0,
1236 for (p = 0; p < h->omsg[1] + 2; p++)
1238 h->omsg[h->omsg[1] + 2] = 0 - c;
1239 sms_debug ("TX", h->omsg);
1242 if (h->omsg[0] == 0x93)
1243 h->opause = 2400; /* initial message delay 300ms (for BT) */
1247 h->obyten = h->omsg[1] + 3;
1251 sms_generate (struct ast_channel *chan, void *data, int len, int samples)
1253 struct ast_frame f = { 0 };
1254 unsigned char waste[AST_FRIENDLY_OFFSET];
1256 unsigned char buf[800];
1258 signed short buf[800];
1263 if (len > sizeof (buf))
1265 ast_log (LOG_WARNING, "Only doing %d bytes (%d bytes requested)\n", sizeof (buf) / sizeof (signed short), len);
1273 waste[0] = 0; /* make compiler happy */
1274 f.frametype = AST_FRAME_VOICE;
1276 f.subclass = AST_FORMAT_ALAW;
1277 f.datalen = samples;
1279 f.subclass = AST_FORMAT_SLINEAR;
1280 f.datalen = samples * 2;
1282 f.offset = AST_FRIENDLY_OFFSET;
1285 f.samples = samples;
1287 /* create a buffer containing the digital sms pattern */
1288 for (i = 0; i < samples; i++)
1297 else if (h->obyten || h->osync)
1298 { /* sending data */
1300 buf[i] = wavea[h->ophase];
1302 buf[i] = wave[h->ophase];
1304 if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
1306 if ((h->ophasep += 12) >= 80)
1310 h->osync--; /* sending sync bits */
1316 h->obyte = 0; /* start bit; */
1317 else if (h->obitp == 2)
1318 h->obyte = h->omsg[h->obytep];
1319 else if (h->obitp == 10)
1321 h->obyte = 1; /* stop bit */
1324 if (h->obytep == h->obyten)
1326 h->obytep = h->obyten = 0; /* sent */
1327 h->osync = 10; /* trailing marks */
1334 if (ast_write (chan, &f) < 0)
1336 ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
1343 sms_process (sms_t * h, int samples, signed short *data)
1345 if (h->obyten || h->osync)
1346 return; /* sending */
1349 unsigned long long m0,
1351 if (abs (*data) > h->imag)
1352 h->imag = abs (*data);
1354 h->imag = h->imag * 7 / 8;
1358 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
1359 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
1360 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
1361 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
1362 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
1363 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
1364 if ((h->ips0 += 21) >= 80)
1366 if ((h->ipc0 += 21) >= 80)
1368 if ((h->ips1 += 13) >= 80)
1370 if ((h->ipc1 += 13) >= 80)
1381 bit = ((h->ibitt > 1) ? 1 : 0);
1382 if (bit != h->ibitl)
1387 if (!h->ibitn && h->ibitc == 4 && !bit)
1392 if (bit && h->ibitc == 200)
1393 { /* sync, restart message */
1394 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1399 if (h->iphasep >= 80)
1402 if (h->ibitn++ == 9)
1404 if (!bit) /* bad stop bit */
1405 h->ierr = 0xFF; /* unknown error */
1408 if (h->ibytep < sizeof (h->imsg))
1410 h->imsg[h->ibytep] = h->ibytev;
1411 h->ibytec += h->ibytev;
1413 } else if (h->ibytep == sizeof (h->imsg))
1414 h->ierr = 2; /* bad message length */
1415 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr)
1420 h->ierr = 1; /* bad checksum */
1425 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1430 { /* lost carrier */
1431 if (h->idle++ == 80000)
1432 { /* nothing happening */
1433 ast_log (LOG_EVENT, "No data, hanging up\n");
1440 h->omsg[0] = 0x92; /* error */
1442 h->omsg[2] = h->ierr;
1443 sms_messagetx (h); /* send error */
1445 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1451 static struct ast_generator smsgen = {
1453 release:sms_release,
1454 generate:sms_generate,
1458 sms_exec (struct ast_channel *chan, void *data)
1461 struct localuser *u;
1462 struct ast_frame *f;
1464 h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1465 h.dcs = 0xF1; /* default */
1468 ast_log (LOG_ERROR, "Requires queue name at least\n");
1472 if (chan->cid.cid_num)
1473 strncpy (h.cli, chan->cid.cid_num, sizeof (h.cli) - 1);
1476 unsigned char *d = data,
1479 if (!*d || *d == '|')
1481 ast_log (LOG_ERROR, "Requires queue name\n");
1484 for (p = d; *p && *p != '|'; p++);
1485 if (p - d >= sizeof (h.queue))
1487 ast_log (LOG_ERROR, "Queue name too long\n");
1490 strncpy (h.queue, d, p - d);
1494 for (p = h.queue; *p; p++)
1496 *p = '-'; /* make very safe for filenames */
1497 while (*d && *d != '|')
1501 case 'a': /* we have to send the initial FSK sequence */
1504 case 's': /* we are acting as a service centre talking to a phone */
1507 /* the following apply if there is an arg3/4 and apply to the created message file */
1512 h.dcs |= 4; /* octets */
1520 case '7': /* set the pid for saved local message */
1521 h.pid = 0x40 + (*d & 0xF);
1528 /* submitting a message, not taking call. */
1529 /* depricated, use smsq instead */
1532 for (p = d; *p && *p != '|'; p++);
1535 if (strlen (d) >= sizeof (h.oa))
1537 ast_log (LOG_ERROR, "Address too long %s\n", d);
1542 strncpy (h.oa, d, sizeof (h.oa) - 1);
1545 strncpy (h.da, d, sizeof (h.da) - 1);
1548 strncpy (h.oa, h.cli, sizeof (h.oa) - 1);
1551 while (*p && h.udl < SMSLEN)
1552 h.ud[h.udl++] = utf8decode (&p);
1553 if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1554 ast_log (LOG_WARNING, "Invalid 7 bit GSM data\n");
1555 if (is8bit (h.dcs) && packsms8 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1556 ast_log (LOG_WARNING, "Invalid 8 bit data\n");
1557 if (is16bit (h.dcs) && packsms16 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1558 ast_log (LOG_WARNING, "Invalid 16 bit data\n");
1559 h.rx = 0; /* sent message */
1567 /* set up SMS_EST initial message */
1575 if (chan->_state != AST_STATE_UP)
1579 res = ast_set_write_format (chan, AST_FORMAT_ALAW);
1581 res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
1584 res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
1587 LOCAL_USER_REMOVE (u);
1588 ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
1592 if (ast_activate_generator (chan, &smsgen, &h) < 0)
1594 LOCAL_USER_REMOVE (u);
1595 ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
1599 /* Do our thing here */
1600 while (ast_waitfor (chan, -1) > -1 && !h.hangup)
1602 f = ast_read (chan);
1605 if (f->frametype == AST_FRAME_VOICE)
1607 sms_process (&h, f->samples, f->data);
1613 sms_log (&h, '?'); /* log incomplete message */
1615 LOCAL_USER_REMOVE (u);
1620 unload_module (void)
1622 STANDARD_HANGUP_LOCALUSERS;
1623 return ast_unregister_application (app);
1632 for (p = 0; p < 80; p++)
1633 wavea[p] = AST_LIN2A (wave[p]);
1636 snprintf (log_file, sizeof (log_file), "%s/sms", ast_config_AST_LOG_DIR);
1637 snprintf (spool_dir, sizeof (spool_dir), "%s/sms", ast_config_AST_SPOOL_DIR);
1638 return ast_register_application (app, sms_exec, synopsis, descrip);
1651 STANDARD_USECOUNT (res);
1658 return ASTERISK_GPL_KEY;