Merged revisions 46200 via svnmerge from
[asterisk/asterisk.git] / apps / app_sms.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2004 - 2005, Adrian Kennard, rights assigned to Digium
5  *
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.
11  *
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.
15  */
16
17 /*! \file
18  *
19  * \brief SMS application - ETSI ES 201 912 protocol 1 implimentation
20  * \ingroup applications
21  *
22  * \author Adrian Kennard
23  */
24
25 #include "asterisk.h"
26
27 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <errno.h>
34 #include <dirent.h>
35 #include <ctype.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38
39 #include "asterisk/lock.h"
40 #include "asterisk/file.h"
41 #include "asterisk/logger.h"
42 #include "asterisk/options.h"
43 #include "asterisk/channel.h"
44 #include "asterisk/pbx.h"
45 #include "asterisk/module.h"
46 #include "asterisk/alaw.h"
47 #include "asterisk/callerid.h"
48
49 /* output using Alaw rather than linear */
50 /* #define OUTALAW */
51
52 /* ToDo */
53 /* Add full VP support */
54 /* Handle status report messages (generation and reception) */
55 /* Time zones on time stamps */
56 /* user ref field */
57
58 static volatile unsigned char message_ref;      /* arbitary message ref */
59 static volatile unsigned int seq;       /* arbitrary message sequence number for unqiue files */
60
61 static char log_file[255];
62 static char spool_dir[255];
63
64 static char *app = "SMS";
65
66 static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
67
68 static char *descrip =
69         "  SMS(name|[a][s]):  SMS handles exchange of SMS data with a call to/from SMS capabale\n"
70         "phone or SMS PSTN service center. Can send and/or receive SMS messages.\n"
71         "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n"
72         "Typical usage is to use to handle called from the SMS service centre CLI,\n"
73         "or to set up a call using 'outgoing' or manager interface to connect\n"
74         "service centre to SMS()\n"
75         "name is the name of the queue used in /var/spool/asterisk/sms\n"
76         "Arguments:\n"
77         " a: answer, i.e. send initial FSK packet.\n"
78         " s: act as service centre talking to a phone.\n"
79         "Messages are processed as per text file message queues.\n" 
80         "smsq (a separate software) is a command to generate message\n"
81         "queues and send messages.\n";
82
83 static signed short wave[] = {
84         0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
85         5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
86         0, -392, -782, -1167,
87          -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
88         -4985, -4938, -4862,
89         -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
90 };
91
92 #ifdef OUTALAW
93 static unsigned char wavea[80];
94 #endif
95
96
97 /* SMS 7 bit character mapping to UCS-2 */
98 static const unsigned short defaultalphabet[] = {
99         0x0040, 0x00A3, 0x0024, 0x00A5, 0x00E8, 0x00E9, 0x00F9, 0x00EC,
100         0x00F2, 0x00E7, 0x000A, 0x00D8, 0x00F8, 0x000D, 0x00C5, 0x00E5,
101         0x0394, 0x005F, 0x03A6, 0x0393, 0x039B, 0x03A9, 0x03A0, 0x03A8,
102         0x03A3, 0x0398, 0x039E, 0x00A0, 0x00C6, 0x00E6, 0x00DF, 0x00C9,
103         ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
104         '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
105         161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
106         'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
107         191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
108         'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
109 };
110
111 static const unsigned short escapes[] = {
112         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x000C, 0, 0, 0, 0, 0,
113         0, 0, 0, 0, 0x005E, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
114         0, 0, 0, 0, 0, 0, 0, 0, 0x007B, 0x007D, 0, 0, 0, 0, 0, 0x005C,
115         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x005B, 0x007E, 0x005D, 0,
116         0x007C, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118         0, 0, 0, 0, 0, 0x20AC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
120 };
121
122 #define SMSLEN 160              /* max SMS length */
123
124 typedef struct sms_s
125 {
126         unsigned char hangup;        /* we are done... */
127         unsigned char err;           /* set for any errors */
128         unsigned char smsc:1;        /* we are SMSC */
129         unsigned char rx:1;          /* this is a received message */
130         char queue[30];              /* queue name */
131         char oa[20];                 /* originating address */
132         char da[20];                 /* destination address */
133         time_t scts;                 /* time stamp, UTC */
134         unsigned char pid;           /* protocol ID */
135         unsigned char dcs;           /* data coding scheme */
136         short mr;                    /* message reference - actually a byte, but usde -1 for not set */
137         int udl;                     /* user data length */
138         int udhl;                    /* user data header length */
139         unsigned char srr:1;         /* Status Report request */
140         unsigned char udhi:1;        /* User Data Header required, even if length 0 */
141         unsigned char rp:1;          /* Reply Path */
142         unsigned int vp;             /* validity period in minutes, 0 for not set */
143         unsigned short ud[SMSLEN];   /* user data (message), UCS-2 coded */
144         unsigned char udh[SMSLEN];   /* user data header */
145         char cli[20];                /* caller ID */
146         unsigned char ophase;        /* phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
147         unsigned char ophasep;       /* phase (0-79) for 1200 bps */
148         unsigned char obyte;         /* byte being sent */
149         unsigned int opause;         /* silent pause before sending (in sample periods) */
150         unsigned char obitp;         /* bit in byte */
151         unsigned char osync;         /* sync bits to send */
152         unsigned char obytep;        /* byte in data */
153         unsigned char obyten;        /* bytes in data */
154         unsigned char omsg[256];     /* data buffer (out) */
155         unsigned char imsg[200];     /* data buffer (in) */
156         signed long long ims0,
157                 imc0,
158                 ims1,
159                 imc1;                      /* magnitude averages sin/cos 0/1 */
160         unsigned int idle;
161         unsigned short imag;         /* signal level */
162         unsigned char ips0,
163                 ips1,
164                 ipc0,
165                 ipc1;                      /* phase sin/cos 0/1 */
166         unsigned char ibitl;         /* last bit */
167         unsigned char ibitc;         /* bit run length count */
168         unsigned char iphasep;       /* bit phase (0-79) for 1200 bps */
169         unsigned char ibitn;         /* bit number in byte being received */
170         unsigned char ibytev;        /* byte value being received */
171         unsigned char ibytep;        /* byte pointer in messafe */
172         unsigned char ibytec;        /* byte checksum for message */
173         unsigned char ierr;          /* error flag */
174         unsigned char ibith;         /* history of last bits */
175         unsigned char ibitt;         /* total of 1's in last 3 bites */
176         /* more to go here */
177 } sms_t;
178
179 /* different types of encoding */
180 #define is7bit(dcs) (((dcs)&0xC0)?(!((dcs)&4)):(!((dcs)&12)))
181 #define is8bit(dcs) (((dcs)&0xC0)?(((dcs)&4)):(((dcs)&12)==4))
182 #define is16bit(dcs) (((dcs)&0xC0)?0:(((dcs)&12)==8))
183
184 static void *sms_alloc (struct ast_channel *chan, void *params)
185 {
186         return params;
187 }
188
189 static void sms_release (struct ast_channel *chan, void *data)
190 {
191         return;
192 }
193
194 static void sms_messagetx (sms_t * h);
195
196 /*! \brief copy number, skipping non digits apart from leading + */
197 static void numcpy (char *d, char *s)
198 {
199         if (*s == '+')
200                 *d++ = *s++;
201         while (*s) {
202                 if (isdigit (*s))
203                         *d++ = *s;
204                 s++;
205         }
206         *d = 0;
207 }
208
209 /*! \brief static, return a date/time in ISO format */
210 static char * isodate (time_t t)
211 {
212         static char date[20];
213         strftime (date, sizeof (date), "%Y-%m-%dT%H:%M:%S", localtime (&t));
214         return date;
215 }
216
217 /*! \brief reads next UCS character from null terminated UTF-8 string and advanced pointer */
218 /* for non valid UTF-8 sequences, returns character as is */
219 /* Does not advance pointer for null termination */
220 static long utf8decode (unsigned char **pp)
221 {
222         unsigned char *p = *pp;
223         if (!*p)
224                 return 0;                 /* null termination of string */
225         (*pp)++;
226         if (*p < 0xC0)
227                 return *p;                /* ascii or continuation character */
228         if (*p < 0xE0) {
229                 if (*p < 0xC2 || (p[1] & 0xC0) != 0x80)
230                         return *p;             /* not valid UTF-8 */
231                 (*pp)++;
232                 return ((*p & 0x1F) << 6) + (p[1] & 0x3F);
233         }
234         if (*p < 0xF0) {
235                 if ((*p == 0xE0 && p[1] < 0xA0) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80)
236                          return *p;             /* not valid UTF-8 */
237                 (*pp) += 2;
238                 return ((*p & 0x0F) << 12) + ((p[1] & 0x3F) << 6) + (p[2] & 0x3F);
239         }
240         if (*p < 0xF8) {
241                 if ((*p == 0xF0 && p[1] < 0x90) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80)
242                         return *p;             /* not valid UTF-8 */
243                 (*pp) += 3;
244                 return ((*p & 0x07) << 18) + ((p[1] & 0x3F) << 12) + ((p[2] & 0x3F) << 6) + (p[3] & 0x3F);
245         }
246         if (*p < 0xFC) {
247                 if ((*p == 0xF8 && p[1] < 0x88) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
248                         || (p[4] & 0xC0) != 0x80)
249                         return *p;             /* not valid UTF-8 */
250                 (*pp) += 4;
251                 return ((*p & 0x03) << 24) + ((p[1] & 0x3F) << 18) + ((p[2] & 0x3F) << 12) + ((p[3] & 0x3F) << 6) + (p[4] & 0x3F);
252         }
253         if (*p < 0xFE) {
254                 if ((*p == 0xFC && p[1] < 0x84) || (p[1] & 0xC0) != 0x80 || (p[2] & 0xC0) != 0x80 || (p[3] & 0xC0) != 0x80
255                         || (p[4] & 0xC0) != 0x80 || (p[5] & 0xC0) != 0x80)
256                         return *p;             /* not valid UTF-8 */
257                 (*pp) += 5;
258                 return ((*p & 0x01) << 30) + ((p[1] & 0x3F) << 24) + ((p[2] & 0x3F) << 18) + ((p[3] & 0x3F) << 12) + ((p[4] & 0x3F) << 6) + (p[5] & 0x3F);
259         }
260         return *p;                   /* not sensible */
261 }
262
263 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using SMS 7 bit character codes */
264 /* The return value is the number of septets packed in to o, which is internally limited to SMSLEN */
265 /* o can be null, in which case this is used to validate or count only */
266 /* if the input contains invalid characters then the return value is -1 */
267 static int packsms7 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
268 {
269          unsigned char p = 0, b = 0, n = 0;
270
271         if (udhl) {                            /* header */
272                 if (o)
273                         o[p++] = udhl;
274                 b = 1;
275                 n = 1;
276                 while (udhl--) {
277                         if (o)
278                                 o[p++] = *udh++;
279                         b += 8;
280                         while (b >= 7) {
281                                 b -= 7;
282                                 n++;
283                         }
284                         if (n >= SMSLEN)
285                                 return n;
286                 }
287                 if (b) {
288                         b = 7 - b;
289                         if (++n >= SMSLEN)
290                                 return n;
291                         };      /* filling to septet boundary */
292                 }
293                 if (o)
294                         o[p] = 0;
295                 /* message */
296                 while (udl--) {
297                         long u;
298                         unsigned char v;
299                         u = *ud++;
300                         for (v = 0; v < 128 && defaultalphabet[v] != u; v++);
301                         if (v == 128 && u && n + 1 < SMSLEN) {
302                                 for (v = 0; v < 128 && escapes[v] != u; v++);
303                                 if (v < 128) {  /* escaped sequence */
304                                 if (o)
305                                         o[p] |= (27 << b);
306                                 b += 7;
307                                 if (b >= 8) {
308                                         b -= 8;
309                                         p++;
310                                         if (o)
311                                                 o[p] = (27 >> (7 - b));
312                                 }
313                                 n++;
314                         }
315                 }
316                 if (v == 128)
317                         return -1;             /* invalid character */
318                 if (o)
319                         o[p] |= (v << b);
320                 b += 7;
321                 if (b >= 8) {
322                         b -= 8;
323                         p++;
324                         if (o)
325                                 o[p] = (v >> (7 - b));
326                 }
327                 if (++n >= SMSLEN)
328                         return n;
329         }
330         return n;
331 }
332
333 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 message (udl characters at ud) and packs in to o using 8 bit character codes */
334 /* The return value is the number of bytes packed in to o, which is internally limited to 140 */
335 /* o can be null, in which case this is used to validate or count only */
336 /* if the input contains invalid characters then the return value is -1 */
337 static int packsms8 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
338 {
339         unsigned char p = 0;
340
341         /* header - no encoding */
342         if (udhl) {
343                 if (o)
344                         o[p++] = udhl;
345                 while (udhl--) {
346                         if (o)
347                                 o[p++] = *udh++;
348                         if (p >= 140)
349                                 return p;
350                 }
351         }
352         while (udl--) {
353                 long u;
354                 u = *ud++;
355                 if (u < 0 || u > 0xFF)
356                         return -1;             /* not valid */
357                 if (o)
358                         o[p++] = u;
359                 if (p >= 140)
360                         return p;
361         }
362         return p;
363 }
364
365 /*! \brief takes a binary header (udhl bytes at udh) and UCS-2 
366         message (udl characters at ud) and packs in to o using 16 bit 
367         UCS-2 character codes 
368         The return value is the number of bytes packed in to o, which is 
369         internally limited to 140 
370         o can be null, in which case this is used to validate or count 
371         only if the input contains invalid characters then 
372         the return value is -1 */
373 static int packsms16 (unsigned char *o, int udhl, unsigned char *udh, int udl, unsigned short *ud)
374 {
375         unsigned char p = 0;
376         /* header - no encoding */
377         if (udhl) {
378                 if (o)
379                         o[p++] = udhl;
380                 while (udhl--) {
381                         if (o)
382                                 o[p++] = *udh++;
383                         if (p >= 140)
384                                 return p;
385                 }
386         }
387         while (udl--) {
388                 long u;
389                 u = *ud++;
390                 if (o)
391                         o[p++] = (u >> 8);
392                 if (p >= 140)
393                         return p - 1;          /* could not fit last character */
394                 if (o)
395                         o[p++] = u;
396                 if (p >= 140)
397                         return p;
398         }
399         return p;
400 }
401
402 /*! \brief general pack, with length and data, 
403         returns number of bytes of target used */
404 static int packsms (unsigned char dcs, unsigned char *base, unsigned int udhl, unsigned char *udh, int udl, unsigned short *ud)
405 {
406         unsigned char *p = base;
407         if (udl) {
408                 int l = 0;
409                 if (is7bit (dcs)) {              /* 7 bit */
410                         l = packsms7 (p + 1, udhl, udh, udl, ud);
411                         if (l < 0)
412                                 l = 0;
413                         *p++ = l;
414                         p += (l * 7 + 7) / 8;
415                 } else if (is8bit (dcs)) {                                                               /* 8 bit */
416                         l = packsms8 (p + 1, udhl, udh, udl, ud);
417                         if (l < 0)
418                                 l = 0;
419                         *p++ = l;
420                         p += l;
421                 } else {                         /* UCS-2 */
422                         l = packsms16 (p + 1, udhl, udh, udl, ud);
423                         if (l < 0)
424                                 l = 0;
425                         *p++ = l;
426                         p += l;
427                 }
428         } else
429                 *p++ = 0;                         /* no user data */
430         return p - base;
431 }
432
433
434 /*! \brief pack a date and return */
435 static void packdate (unsigned char *o, time_t w)
436 {
437         struct tm *t = localtime (&w);
438 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined( __NetBSD__ ) || defined(__APPLE__)
439         int z = -t->tm_gmtoff / 60 / 15;
440 #else
441         int z = timezone / 60 / 15;
442 #endif
443         *o++ = ((t->tm_year % 10) << 4) + (t->tm_year % 100) / 10;
444         *o++ = (((t->tm_mon + 1) % 10) << 4) + (t->tm_mon + 1) / 10;
445         *o++ = ((t->tm_mday % 10) << 4) + t->tm_mday / 10;
446         *o++ = ((t->tm_hour % 10) << 4) + t->tm_hour / 10;
447         *o++ = ((t->tm_min % 10) << 4) + t->tm_min / 10;
448         *o++ = ((t->tm_sec % 10) << 4) + t->tm_sec / 10;
449         if (z < 0)
450                 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
451         else
452                 *o++ = ((z % 10) << 4) + z / 10;
453 }
454
455 /*! \brief unpack a date and return */
456 static time_t unpackdate (unsigned char *i)
457 {
458         struct tm t;
459         t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
460         t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
461         t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
462         t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
463         t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
464         t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
465         t.tm_isdst = 0;
466         if (i[6] & 0x08)
467                 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
468         else
469                 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
470         return mktime (&t);
471 }
472
473 /*! \brief unpacks bytes (7 bit encoding) at i, len l septets, 
474         and places in udh and ud setting udhl and udl. udh not used 
475         if udhi not set */
476 static void unpacksms7 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
477 {
478         unsigned char b = 0, p = 0;
479         unsigned short *o = ud;
480         *udhl = 0;
481         if (udhi && l) {                 /* header */
482                 int h = i[p];
483                 *udhl = h;
484                 if (h) {
485                         b = 1;
486                         p++;
487                         l--;
488                         while (h-- && l) {
489                                 *udh++ = i[p++];
490                                 b += 8;
491                                 while (b >= 7) {
492                                         b -= 7;
493                                         l--;
494                                         if (!l)
495                                                 break;
496                                 }
497                         }
498                         /* adjust for fill, septets */
499                         if (b) {
500                                 b = 7 - b;
501                                 l--;
502                         }
503                 }
504         }
505         while (l--) {
506                 unsigned char v;
507                 if (b < 2)
508                         v = ((i[p] >> b) & 0x7F);
509                 else
510                         v = ((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F);
511                 b += 7;
512                 if (b >= 8) {
513                         b -= 8;
514                         p++;
515                 }
516                 if (o > ud && o[-1] == 0x00A0 && escapes[v])
517                         o[-1] = escapes[v];
518                 else
519                         *o++ = defaultalphabet[v];
520         }
521         *udl = (o - ud);
522 }
523
524 /*! \brief unpacks bytes (8 bit encoding) at i, len l septets, 
525       and places in udh and ud setting udhl and udl. udh not used 
526       if udhi not set */
527 static void unpacksms8 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
528 {
529         unsigned short *o = ud;
530         *udhl = 0;
531         if (udhi) {
532                 int n = *i;
533                 *udhl = n;
534                 if (n) {
535                         i++;
536                         l--;
537                         while (l && n) {
538                                 l--;
539                                 n--;
540                                 *udh++ = *i++;
541                         }
542                 }
543         }
544         while (l--)
545                 *o++ = *i++;      /* not to UTF-8 as explicitely 8 bit coding in DCS */
546         *udl = (o - ud);
547 }
548
549 /*! \brief unpacks bytes (16 bit encoding) at i, len l septets,
550          and places in udh and ud setting udhl and udl. 
551         udh not used if udhi not set */
552 static void unpacksms16 (unsigned char *i, unsigned char l, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
553 {
554         unsigned short *o = ud;
555         *udhl = 0;
556         if (udhi) {
557                 int n = *i;
558                 *udhl = n;
559                 if (n) {
560                         i++;
561                         l--;
562                         while (l && n) {
563                                 l--;
564                                 n--;
565                                 *udh++ = *i++;
566                         }
567                 }
568         }
569         while (l--) {
570                 int v = *i++;
571                 if (l--)
572                         v = (v << 8) + *i++;
573                 *o++ = v;
574         }
575         *udl = (o - ud);
576 }
577
578 /*! \brief general unpack - starts with length byte (octet or septet) and returns number of bytes used, inc length */
579 static int unpacksms (unsigned char dcs, unsigned char *i, unsigned char *udh, int *udhl, unsigned short *ud, int *udl, char udhi)
580 {
581         int l = *i++;
582         if (is7bit (dcs)) {
583                 unpacksms7 (i, l, udh, udhl, ud, udl, udhi);
584                 l = (l * 7 + 7) / 8;            /* adjust length to return */
585         } else if (is8bit (dcs))
586                 unpacksms8 (i, l, udh, udhl, ud, udl, udhi);
587         else
588                 unpacksms16 (i, l, udh, udhl, ud, udl, udhi);
589         return l + 1;
590 }
591
592 /*! \brief unpack an address from i, return byte length, unpack to o */
593 static unsigned char unpackaddress (char *o, unsigned char *i)
594 {
595         unsigned char l = i[0],
596                 p;
597         if (i[1] == 0x91)
598                 *o++ = '+';
599         for (p = 0; p < l; p++) {
600                 if (p & 1)
601                         *o++ = (i[2 + p / 2] >> 4) + '0';
602                 else
603                         *o++ = (i[2 + p / 2] & 0xF) + '0';
604         }
605         *o = 0;
606         return (l + 5) / 2;
607 }
608
609 /*! \brief store an address at o, and return number of bytes used */
610 static unsigned char packaddress (unsigned char *o, char *i)
611 {
612         unsigned char p = 2;
613         o[0] = 0;
614         if (*i == '+') {
615                 i++;
616                 o[1] = 0x91;
617         } else
618                 o[1] = 0x81;
619         while (*i)
620                 if (isdigit (*i)) {
621                         if (o[0] & 1)
622                                 o[p++] |= ((*i & 0xF) << 4);
623                         else
624                                 o[p] = (*i & 0xF);
625                         o[0]++;
626                         i++;
627                 } else
628                         i++;
629         if (o[0] & 1)
630                 o[p++] |= 0xF0;                   /* pad */
631         return p;
632 }
633
634 /*! \brief Log the output, and remove file */
635 static void sms_log (sms_t * h, char status)
636 {
637         if (*h->oa || *h->da) {
638                 int o = open (log_file, O_CREAT | O_APPEND | O_WRONLY, 0666);
639                 if (o >= 0) {
640                         char line[1000], mrs[3] = "", *p;
641                         unsigned char n;
642
643                         if (h->mr >= 0)
644                                 snprintf (mrs, sizeof (mrs), "%02X", h->mr);
645                         snprintf (line, sizeof (line), "%s %c%c%c%s %s %s %s ",
646                                  isodate (time (0)), status, h->rx ? 'I' : 'O', h->smsc ? 'S' : 'M', mrs, h->queue, *h->oa ? h->oa : "-",
647                                  *h->da ? h->da : "-");
648                         p = line + strlen (line);
649                         for (n = 0; n < h->udl; n++)
650                                 if (h->ud[n] == '\\') {
651                                         *p++ = '\\';
652                                         *p++ = '\\';
653                                 } else if (h->ud[n] == '\n') {
654                                         *p++ = '\\';
655                                         *p++ = 'n';
656                                 } else if (h->ud[n] == '\r') {
657                                         *p++ = '\\';
658                                         *p++ = 'r';
659                                 } else if (h->ud[n] < 32 || h->ud[n] == 127)
660                                         *p++ = 191;
661                                 else
662                                         *p++ = h->ud[n];
663                         *p++ = '\n';
664                         *p = 0;
665                         write (o, line, strlen (line));
666                         close (o);
667                 }
668                 *h->oa = *h->da = h->udl = 0;
669         }
670 }
671
672 /*! \brief parse and delete a file */
673 static void sms_readfile (sms_t * h, char *fn)
674 {
675         char line[1000];
676         FILE *s;
677         char dcsset = 0;                                 /* if DSC set */
678         ast_log (LOG_EVENT, "Sending %s\n", fn);
679         h->rx = h->udl = *h->oa = *h->da = h->pid = h->srr = h->udhi = h->rp = h->vp = h->udhl = 0;
680         h->mr = -1;
681         h->dcs = 0xF1;                                  /* normal messages class 1 */
682         h->scts = time (0);
683         s = fopen (fn, "r");
684         if (s)
685         {
686                 if (unlink (fn))
687                 {                                                                /* concurrent access, we lost */
688                         fclose (s);
689                         return;
690                 }
691                 while (fgets (line, sizeof (line), s))
692                 {                                                                /* process line in file */
693                         char *p;
694                         void *pp = &p;
695                         for (p = line; *p && *p != '\n' && *p != '\r'; p++);
696                         *p = 0;                                  /* strip eoln */
697                         p = line;
698                         if (!*p || *p == ';')
699                                 continue;                         /* blank line or comment, ignore */
700                         while (isalnum (*p))
701                         {
702                                 *p = tolower (*p);
703                                 p++;
704                         }
705                         while (isspace (*p))
706                                 *p++ = 0;
707                         if (*p == '=')
708                         {
709                                 *p++ = 0;
710                                 if (!strcmp (line, "ud"))
711                                 {                                                /* parse message (UTF-8) */
712                                         unsigned char o = 0;
713                                         while (*p && o < SMSLEN)
714                                                 h->ud[o++] = utf8decode(pp);
715                                         h->udl = o;
716                                         if (*p)
717                                                 ast_log (LOG_WARNING, "UD too long in %s\n", fn);
718                                 } else
719                                 {
720                                         while (isspace (*p))
721                                                 p++;
722                                         if (!strcmp (line, "oa") && strlen (p) < sizeof (h->oa))
723                                                 numcpy (h->oa, p);
724                                         else if (!strcmp (line, "da") && strlen (p) < sizeof (h->oa))
725                                                 numcpy (h->da, p);
726                                         else if (!strcmp (line, "pid"))
727                                                 h->pid = atoi (p);
728                                         else if (!strcmp (line, "dcs"))
729                                         {
730                                                 h->dcs = atoi (p);
731                                                 dcsset = 1;
732                                         } else if (!strcmp (line, "mr"))
733                                                 h->mr = atoi (p);
734                                         else if (!strcmp (line, "srr"))
735                                                 h->srr = (atoi (p) ? 1 : 0);
736                                         else if (!strcmp (line, "vp"))
737                                                 h->vp = atoi (p);
738                                         else if (!strcmp (line, "rp"))
739                                                 h->rp = (atoi (p) ? 1 : 0);
740                                         else if (!strcmp (line, "scts"))
741                                         {                                        /* get date/time */
742                                                 int Y,
743                                                   m,
744                                                   d,
745                                                   H,
746                                                   M,
747                                                   S;
748                                                 if (sscanf (p, "%d-%d-%dT%d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6)
749                                                 {
750                                                         struct tm t;
751                                                         t.tm_year = Y - 1900;
752                                                         t.tm_mon = m - 1;
753                                                         t.tm_mday = d;
754                                                         t.tm_hour = H;
755                                                         t.tm_min = M;
756                                                         t.tm_sec = S;
757                                                         t.tm_isdst = -1;
758                                                         h->scts = mktime (&t);
759                                                         if (h->scts == (time_t) - 1)
760                                                                 ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
761                                                 }
762                                         } else
763                                                 ast_log (LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
764                                 }
765                         } else if (*p == '#')
766                         {                                                        /* raw hex format */
767                                 *p++ = 0;
768                                 if (*p == '#')
769                                 {
770                                         p++;
771                                         if (!strcmp (line, "ud"))
772                                         {                                        /* user data */
773                                                 int o = 0;
774                                                 while (*p && o < SMSLEN)
775                                                 {
776                                                         if (isxdigit (*p) && isxdigit (p[1]) && isxdigit (p[2]) && isxdigit (p[3]))
777                                                         {
778                                                                 h->ud[o++] =
779                                                                         (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 12) +
780                                                                         (((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF)) << 8) +
781                                                                         (((isalpha (p[2]) ? 9 : 0) + (p[2] & 0xF)) << 4) + ((isalpha (p[3]) ? 9 : 0) + (p[3] & 0xF));
782                                                                 p += 4;
783                                                         } else
784                                                                 break;
785                                                 }
786                                                 h->udl = o;
787                                                 if (*p)
788                                                         ast_log (LOG_WARNING, "UD too long / invalid UCS-2 hex in %s\n", fn);
789                                         } else
790                                                 ast_log (LOG_WARNING, "Only ud can use ## format, %s\n", fn);
791                                 } else if (!strcmp (line, "ud"))
792                                 {                                                /* user data */
793                                         int o = 0;
794                                         while (*p && o < SMSLEN)
795                                         {
796                                                 if (isxdigit (*p) && isxdigit (p[1]))
797                                                 {
798                                                         h->ud[o++] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
799                                                         p += 2;
800                                                 } else
801                                                         break;
802                                         }
803                                         h->udl = o;
804                                         if (*p)
805                                                 ast_log (LOG_WARNING, "UD too long / invalid UCS-1 hex in %s\n", fn);
806                                 } else if (!strcmp (line, "udh"))
807                                 {                                                /* user data header */
808                                         unsigned char o = 0;
809                                         h->udhi = 1;
810                                         while (*p && o < SMSLEN)
811                                         {
812                                                 if (isxdigit (*p) && isxdigit (p[1]))
813                                                 {
814                                                         h->udh[o] = (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
815                                                         o++;
816                                                         p += 2;
817                                                 } else
818                                                         break;
819                                         }
820                                         h->udhl = o;
821                                         if (*p)
822                                                 ast_log (LOG_WARNING, "UDH too long / invalid hex in %s\n", fn);
823                                 } else
824                                         ast_log (LOG_WARNING, "Only ud and udh can use # format, %s\n", fn);
825                         } else
826                                 ast_log (LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
827                 }
828                 fclose (s);
829                 if (!dcsset && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
830                 {
831                         if (packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
832                         {
833                                 if (packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
834                                         ast_log (LOG_WARNING, "Invalid UTF-8 message even for UCS-2 (%s)\n", fn);
835                                 else
836                                 {
837                                         h->dcs = 0x08;  /* default to 16 bit */
838                                         ast_log (LOG_WARNING, "Sending in 16 bit format (%s)\n", fn);
839                                 }
840                         } else
841                         {
842                                 h->dcs = 0xF5;          /* default to 8 bit */
843                                 ast_log (LOG_WARNING, "Sending in 8 bit format (%s)\n", fn);
844                         }
845                 }
846                 if (is7bit (h->dcs) && packsms7 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
847                         ast_log (LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
848                 if (is8bit (h->dcs) && packsms8 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
849                         ast_log (LOG_WARNING, "Invalid 8 bit data %s\n", fn);
850                 if (is16bit (h->dcs) && packsms16 (0, h->udhl, h->udh, h->udl, h->ud) < 0)
851                         ast_log (LOG_WARNING, "Invalid 16 bit data %s\n", fn);
852         }
853 }
854
855 /*! \brief white a received text message to a file */
856 static void sms_writefile (sms_t * h)
857 {
858         char fn[200] = "", fn2[200] = "";
859         FILE *o;
860         ast_copy_string (fn, spool_dir, sizeof (fn));
861         mkdir (fn, 0777);                       /* ensure it exists */
862         snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? h->rx ? "morx" : "mttx" : h->rx ? "mtrx" : "motx");
863         mkdir (fn, 0777);                       /* ensure it exists */
864         ast_copy_string (fn2, fn, sizeof (fn2));
865         snprintf (fn2 + strlen (fn2), sizeof (fn2) - strlen (fn2), "/%s.%s-%d", h->queue, isodate (h->scts), seq++);
866         snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/.%s", fn2 + strlen (fn) + 1);
867         o = fopen (fn, "w");
868         if (o) {
869                 if (*h->oa)
870                         fprintf (o, "oa=%s\n", h->oa);
871                 if (*h->da)
872                         fprintf (o, "da=%s\n", h->da);
873                 if (h->udhi) {
874                         unsigned int p;
875                         fprintf (o, "udh#");
876                         for (p = 0; p < h->udhl; p++)
877                                 fprintf (o, "%02X", h->udh[p]);
878                         fprintf (o, "\n");
879                 }
880                 if (h->udl) {
881                         unsigned int p;
882                         for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
883                         if (p < h->udl)
884                                 fputc (';', o);   /* cannot use ud=, but include as a comment for human readable */
885                         fprintf (o, "ud=");
886                         for (p = 0; p < h->udl; p++) {
887                                 unsigned short v = h->ud[p];
888                                 if (v < 32)
889                                         fputc (191, o);
890                                 else if (v < 0x80)
891                                         fputc (v, o);
892                                 else if (v < 0x800)
893                                 {
894                                         fputc (0xC0 + (v >> 6), o);
895                                         fputc (0x80 + (v & 0x3F), o);
896                                 } else
897                                 {
898                                         fputc (0xE0 + (v >> 12), o);
899                                         fputc (0x80 + ((v >> 6) & 0x3F), o);
900                                         fputc (0x80 + (v & 0x3F), o);
901                                 }
902                         }
903                         fprintf (o, "\n");
904                         for (p = 0; p < h->udl && h->ud[p] >= ' '; p++);
905                         if (p < h->udl) {
906                                 for (p = 0; p < h->udl && h->ud[p] < 0x100; p++);
907                                 if (p == h->udl) {                                               /* can write in ucs-1 hex */
908                                         fprintf (o, "ud#");
909                                         for (p = 0; p < h->udl; p++)
910                                                 fprintf (o, "%02X", h->ud[p]);
911                                         fprintf (o, "\n");
912                                 } else {                                                 /* write in UCS-2 */
913                                         fprintf (o, "ud##");
914                                         for (p = 0; p < h->udl; p++)
915                                                 fprintf (o, "%04X", h->ud[p]);
916                                         fprintf (o, "\n");
917                                 }
918                         }
919                 }
920                 if (h->scts)
921                         fprintf (o, "scts=%s\n", isodate (h->scts));
922                 if (h->pid)
923                         fprintf (o, "pid=%d\n", h->pid);
924                 if (h->dcs != 0xF1)
925                         fprintf (o, "dcs=%d\n", h->dcs);
926                 if (h->vp)
927                         fprintf (o, "vp=%d\n", h->vp);
928                 if (h->srr)
929                         fprintf (o, "srr=1\n");
930                 if (h->mr >= 0)
931                         fprintf (o, "mr=%d\n", h->mr);
932                 if (h->rp)
933                         fprintf (o, "rp=1\n");
934                 fclose (o);
935                 if (rename (fn, fn2))
936                         unlink (fn);
937                 else
938                         ast_log (LOG_EVENT, "Received to %s\n", fn2);
939         }
940 }
941
942 /*! \brief read dir skipping dot files... */
943 static struct dirent *readdirqueue (DIR * d, char *queue)
944 {
945    struct dirent *f;
946    do {
947       f = readdir (d);
948    } while (f && (*f->d_name == '.' || strncmp (f->d_name, queue, strlen (queue)) || f->d_name[strlen (queue)] != '.'));
949    return f;
950 }
951
952 /*! \brief handle the incoming message */
953 static unsigned char sms_handleincoming (sms_t * h)
954 {
955         unsigned char p = 3;
956         if (h->smsc) {                                                                   /* SMSC */
957                 if ((h->imsg[2] & 3) == 1) {                            /* SMS-SUBMIT */
958                         h->udhl = h->udl = 0;
959                         h->vp = 0;
960                         h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
961                         h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
962                         h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
963                         ast_copy_string (h->oa, h->cli, sizeof (h->oa));
964                         h->scts = time (0);
965                         h->mr = h->imsg[p++];
966                         p += unpackaddress (h->da, h->imsg + p);
967                         h->pid = h->imsg[p++];
968                         h->dcs = h->imsg[p++];
969                         if ((h->imsg[2] & 0x18) == 0x10) {                                                       /* relative VP */
970                                 if (h->imsg[p] < 144)
971                                         h->vp = (h->imsg[p] + 1) * 5;
972                                 else if (h->imsg[p] < 168)
973                                         h->vp = 720 + (h->imsg[p] - 143) * 30;
974                                 else if (h->imsg[p] < 197)
975                                         h->vp = (h->imsg[p] - 166) * 1440;
976                                 else
977                                         h->vp = (h->imsg[p] - 192) * 10080;
978                                 p++;
979                         } else if (h->imsg[2] & 0x18)
980                                 p += 7;                          /* ignore enhanced / absolute VP */
981                         p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
982                         h->rx = 1;                               /* received message */
983                         sms_writefile (h);        /* write the file */
984                         if (p != h->imsg[1] + 2) {
985                                 ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
986                                 return 0xFF;              /* duh! */
987                         }
988                 } else {
989                         ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
990                         return 0xFF;
991                 }
992         } else {                                                                         /* client */
993                 if (!(h->imsg[2] & 3)) {                                                                 /* SMS-DELIVER */
994                         *h->da = h->srr = h->rp = h->vp = h->udhi = h->udhl = h->udl = 0;
995                         h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
996                         h->udhi = ((h->imsg[2] & 0x40) ? 1 : 0);
997                         h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
998                         h->mr = -1;
999                         p += unpackaddress (h->oa, h->imsg + p);
1000                         h->pid = h->imsg[p++];
1001                         h->dcs = h->imsg[p++];
1002                         h->scts = unpackdate (h->imsg + p);
1003                         p += 7;
1004                         p += unpacksms (h->dcs, h->imsg + p, h->udh, &h->udhl, h->ud, &h->udl, h->udhi);
1005                         h->rx = 1;                               /* received message */
1006                         sms_writefile (h);        /* write the file */
1007                         if (p != h->imsg[1] + 2) {
1008                                 ast_log (LOG_WARNING, "Mismatch receive unpacking %d/%d\n", p, h->imsg[1] + 2);
1009                                 return 0xFF;              /* duh! */
1010                         }
1011                 } else {
1012                         ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
1013                         return 0xFF;
1014                 }
1015         }
1016         return 0;                                                 /* no error */
1017 }
1018
1019 #ifdef SOLARIS
1020 #define NAME_MAX 1024
1021 #endif
1022
1023 /*! \brief find and fill in next message, or send a REL if none waiting */
1024 static void sms_nextoutgoing (sms_t * h)
1025 {          
1026         char fn[100 + NAME_MAX] = "";
1027         DIR *d;
1028         char more = 0;
1029         ast_copy_string (fn, spool_dir, sizeof (fn));
1030         mkdir (fn, 0777);                               /* ensure it exists */
1031         h->rx = 0;                                               /* outgoing message */
1032         snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", h->smsc ? "mttx" : "motx");
1033         mkdir (fn, 0777);                               /* ensure it exists */
1034         d = opendir (fn);
1035         if (d) {
1036                 struct dirent *f = readdirqueue (d, h->queue);
1037                 if (f) {
1038                         snprintf (fn + strlen (fn), sizeof (fn) - strlen (fn), "/%s", f->d_name);
1039                         sms_readfile (h, fn);
1040                         if (readdirqueue (d, h->queue))
1041                                 more = 1;                         /* more to send */
1042                 }
1043                 closedir (d);
1044         }
1045         if (*h->da || *h->oa) {                                                                  /* message to send */
1046                 unsigned char p = 2;
1047                 h->omsg[0] = 0x91;                /* SMS_DATA */
1048                 if (h->smsc) {                   /* deliver */
1049                         h->omsg[p++] = (more ? 4 : 0);
1050                         p += packaddress (h->omsg + p, h->oa);
1051                         h->omsg[p++] = h->pid;
1052                         h->omsg[p++] = h->dcs;
1053                         packdate (h->omsg + p, h->scts);
1054                         p += 7;
1055                         p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1056                 } else {                         /* submit */
1057                         h->omsg[p++] =
1058                                 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0) + (h->udhi ? 0x40 : 0);
1059                         if (h->mr < 0)
1060                                 h->mr = message_ref++;
1061                         h->omsg[p++] = h->mr;
1062                         p += packaddress (h->omsg + p, h->da);
1063                         h->omsg[p++] = h->pid;
1064                         h->omsg[p++] = h->dcs;
1065                         if (h->vp) {             /* relative VP */
1066                                 if (h->vp < 720)
1067                                         h->omsg[p++] = (h->vp + 4) / 5 - 1;
1068                                 else if (h->vp < 1440)
1069                                         h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
1070                                 else if (h->vp < 43200)
1071                                         h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
1072                                 else if (h->vp < 635040)
1073                                         h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
1074                                 else
1075                                         h->omsg[p++] = 255;             /* max */
1076                         }
1077                         p += packsms (h->dcs, h->omsg + p, h->udhl, h->udh, h->udl, h->ud);
1078                 }
1079                 h->omsg[1] = p - 2;
1080                 sms_messagetx (h);
1081         } else {                                 /* no message */
1082                 h->omsg[0] = 0x94;                /* SMS_REL */
1083                 h->omsg[1] = 0;
1084                 sms_messagetx (h);
1085         }
1086 }
1087
1088 static void sms_debug (char *dir, unsigned char *msg)
1089 {
1090         char txt[259 * 3 + 1],
1091          *p = txt;                                               /* always long enough */
1092         int n = msg[1] + 3,
1093                 q = 0;
1094         while (q < n && q < 30) {
1095                 sprintf (p, " %02X", msg[q++]);
1096                 p += 3;
1097         }
1098         if (q < n)
1099                 sprintf (p, "...");
1100         if (option_verbose > 2)
1101                 ast_verbose (VERBOSE_PREFIX_3 "SMS %s%s\n", dir, txt);
1102 }
1103
1104 static void sms_messagerx(sms_t * h)
1105 {
1106         sms_debug ("RX", h->imsg);
1107         /* testing */
1108         switch (h->imsg[0]) {
1109         case 0x91:                                              /* SMS_DATA */
1110                 {
1111                         unsigned char cause = sms_handleincoming (h);
1112                         if (!cause) {
1113                                 sms_log (h, 'Y');
1114                                 h->omsg[0] = 0x95;  /* SMS_ACK */
1115                                 h->omsg[1] = 0x02;
1116                                 h->omsg[2] = 0x00;  /* deliver report */
1117                                 h->omsg[3] = 0x00;  /* no parameters */
1118                         } else {                                                         /* NACK */
1119                                 sms_log (h, 'N');
1120                                 h->omsg[0] = 0x96;  /* SMS_NACK */
1121                                 h->omsg[1] = 3;
1122                                 h->omsg[2] = 0;   /* delivery report */
1123                                 h->omsg[3] = cause; /* cause */
1124                                 h->omsg[4] = 0;   /* no parameters */
1125                         }
1126                         sms_messagetx (h);
1127                 }
1128                 break;
1129         case 0x92:                                              /* SMS_ERROR */
1130                 h->err = 1;
1131                 sms_messagetx (h);                /* send whatever we sent again */
1132                 break;
1133         case 0x93:                                              /* SMS_EST */
1134                 sms_nextoutgoing (h);
1135                 break;
1136         case 0x94:                                              /* SMS_REL */
1137                 h->hangup = 1;                          /* hangup */
1138                 break;
1139         case 0x95:                                              /* SMS_ACK */
1140                 sms_log (h, 'Y');
1141                 sms_nextoutgoing (h);
1142                 break;
1143         case 0x96:                                              /* SMS_NACK */
1144                 h->err = 1;
1145                 sms_log (h, 'N');
1146                 sms_nextoutgoing (h);
1147                 break;
1148         default:                                                  /* Unknown */
1149                 h->omsg[0] = 0x92;                /* SMS_ERROR */
1150                 h->omsg[1] = 1;
1151                 h->omsg[2] = 3;                   /* unknown message type; */
1152                 sms_messagetx (h);
1153                 break;
1154         }
1155 }
1156
1157 static void sms_messagetx(sms_t * h)
1158 {
1159         unsigned char c = 0, p;
1160         for (p = 0; p < h->omsg[1] + 2; p++)
1161                 c += h->omsg[p];
1162         h->omsg[h->omsg[1] + 2] = 0 - c;
1163         sms_debug ("TX", h->omsg);
1164         h->obyte = 1;
1165         h->opause = 200;
1166         if (h->omsg[0] == 0x93)
1167                 h->opause = 2400;                       /* initial message delay 300ms (for BT) */
1168         h->obytep = 0;
1169         h->obitp = 0;
1170         h->osync = 80;
1171         h->obyten = h->omsg[1] + 3;
1172 }
1173
1174 static int sms_generate (struct ast_channel *chan, void *data, int len, int samples)
1175 {
1176         struct ast_frame f = { 0 };
1177 #define MAXSAMPLES (800)
1178 #ifdef OUTALAW
1179         unsigned char *buf;
1180 #else
1181         short *buf;
1182 #endif
1183 #define SAMPLE2LEN sizeof(*buf)
1184         sms_t *h = data;
1185         int i;
1186
1187         if (samples > MAXSAMPLES) {
1188                 ast_log (LOG_WARNING, "Only doing %d samples (%d requested)\n",
1189                          MAXSAMPLES, samples);
1190                 samples = MAXSAMPLES;
1191         }
1192         len = samples * SAMPLE2LEN + AST_FRIENDLY_OFFSET;
1193         buf = alloca(len);
1194
1195         f.frametype = AST_FRAME_VOICE;
1196 #ifdef OUTALAW
1197         f.subclass = AST_FORMAT_ALAW;
1198 #else
1199         f.subclass = AST_FORMAT_SLINEAR;
1200 #endif
1201         f.datalen = len;
1202         f.offset = AST_FRIENDLY_OFFSET;
1203         f.mallocd = 0;
1204         f.data = buf;
1205         f.samples = samples;
1206         f.src = "app_sms";
1207         /* create a buffer containing the digital sms pattern */
1208         for (i = 0; i < samples; i++) {
1209 #ifdef OUTALAW
1210                 buf[i] = wavea[0];
1211 #else
1212                 buf[i] = wave[0];
1213 #endif
1214                 if (h->opause)
1215                         h->opause--;
1216                 else if (h->obyten || h->osync) {                                                                /* sending data */
1217 #ifdef OUTALAW
1218                         buf[i] = wavea[h->ophase];
1219 #else
1220                         buf[i] = wave[h->ophase];
1221 #endif
1222                         if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
1223                                 h->ophase -= 80;
1224                         if ((h->ophasep += 12) >= 80) {                                                  /* next bit */
1225                                 h->ophasep -= 80;
1226                                 if (h->osync)
1227                                         h->osync--;             /* sending sync bits */
1228                                 else {
1229                                         h->obyte >>= 1;
1230                                         h->obitp++;
1231                                         if (h->obitp == 1)
1232                                                 h->obyte = 0; /* start bit; */
1233                                         else if (h->obitp == 2)
1234                                                 h->obyte = h->omsg[h->obytep];
1235                                         else if (h->obitp == 10) {
1236                                                 h->obyte = 1; /* stop bit */
1237                                                 h->obitp = 0;
1238                                                 h->obytep++;
1239                                                 if (h->obytep == h->obyten) {
1240                                                         h->obytep = h->obyten = 0; /* sent */
1241                                                         h->osync = 10;    /* trailing marks */
1242                                                 }
1243                                         }
1244                                 }
1245                         }
1246                 }
1247         }
1248         if (ast_write (chan, &f) < 0) {
1249                 ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
1250                 return -1;
1251         }
1252         return 0;
1253 #undef SAMPLE2LEN
1254 #undef MAXSAMPLES
1255 }
1256
1257 static void sms_process (sms_t * h, int samples, signed short *data)
1258 {
1259         if (h->obyten || h->osync)
1260                 return;                                          /* sending */
1261         while (samples--) {
1262                 unsigned long long m0, m1;
1263                 if (abs (*data) > h->imag)
1264                         h->imag = abs (*data);
1265                 else
1266                         h->imag = h->imag * 7 / 8;
1267                 if (h->imag > 500) {
1268                         h->idle = 0;
1269                         h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
1270                         h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
1271                         h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
1272                         h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
1273                         m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
1274                         m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
1275                         if ((h->ips0 += 21) >= 80)
1276                                 h->ips0 -= 80;
1277                         if ((h->ipc0 += 21) >= 80)
1278                                 h->ipc0 -= 80;
1279                         if ((h->ips1 += 13) >= 80)
1280                                 h->ips1 -= 80;
1281                         if ((h->ipc1 += 13) >= 80)
1282                                 h->ipc1 -= 80;
1283                         {
1284                                 char bit;
1285                                 h->ibith <<= 1;
1286                                 if (m1 > m0)
1287                                         h->ibith |= 1;
1288                                 if (h->ibith & 8)
1289                                         h->ibitt--;
1290                                 if (h->ibith & 1)
1291                                         h->ibitt++;
1292                                 bit = ((h->ibitt > 1) ? 1 : 0);
1293                                 if (bit != h->ibitl)
1294                                         h->ibitc = 1;
1295                                 else
1296                                         h->ibitc++;
1297                                 h->ibitl = bit;
1298                                 if (!h->ibitn && h->ibitc == 4 && !bit) {
1299                                         h->ibitn = 1;
1300                                         h->iphasep = 0;
1301                                 }
1302                                 if (bit && h->ibitc == 200) {                                            /* sync, restart message */
1303                                         h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1304                                 }
1305                                 if (h->ibitn) {
1306                                         h->iphasep += 12;
1307                                         if (h->iphasep >= 80) {                                  /* next bit */
1308                                                 h->iphasep -= 80;
1309                                                 if (h->ibitn++ == 9) {                           /* end of byte */
1310                                                         if (!bit)  /* bad stop bit */
1311                                                                 h->ierr = 0xFF; /* unknown error */
1312                                                         else {
1313                                                                 if (h->ibytep < sizeof (h->imsg)) {
1314                                                                         h->imsg[h->ibytep] = h->ibytev;
1315                                                                         h->ibytec += h->ibytev;
1316                                                                         h->ibytep++;
1317                                                                 } else if (h->ibytep == sizeof (h->imsg))
1318                                                                         h->ierr = 2; /* bad message length */
1319                                                                 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr) {
1320                                                                         if (!h->ibytec)
1321                                                                                 sms_messagerx (h);
1322                                                                         else
1323                                                                                 h->ierr = 1;            /* bad checksum */
1324                                                                 }
1325                                                         }
1326                                                         h->ibitn = 0;
1327                                                 }
1328                                                 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1329                                         }
1330                                 }
1331                         }
1332                 } else {                         /* lost carrier */
1333                         if (h->idle++ == 80000) {                /* nothing happening */
1334                                 ast_log (LOG_EVENT, "No data, hanging up\n");
1335                                 h->hangup = 1;
1336                                 h->err = 1;
1337                         }
1338                         if (h->ierr) {                                                   /* error */
1339                                 h->err = 1;
1340                                 h->omsg[0] = 0x92;  /* error */
1341                                 h->omsg[1] = 1;
1342                                 h->omsg[2] = h->ierr;
1343                                 sms_messagetx (h);  /* send error */
1344                         }
1345                         h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1346                 }
1347                 data++;
1348         }
1349 }
1350
1351 static struct ast_generator smsgen = {
1352         alloc:sms_alloc,
1353         release:sms_release,
1354         generate:sms_generate,
1355 };
1356
1357 static int sms_exec (struct ast_channel *chan, void *data)
1358 {
1359         int res = -1;
1360         struct ast_module_user *u;
1361         struct ast_frame *f;
1362         sms_t h = { 0 };
1363         
1364         u = ast_module_user_add(chan);
1365
1366         h.ipc0 = h.ipc1 = 20;             /* phase for cosine */
1367         h.dcs = 0xF1;                                    /* default */
1368         if (!data) {
1369                 ast_log (LOG_ERROR, "Requires queue name at least\n");
1370                 ast_module_user_remove(u);
1371                 return -1;
1372         }
1373
1374         if (chan->cid.cid_num)
1375                 ast_copy_string (h.cli, chan->cid.cid_num, sizeof (h.cli));
1376
1377         {
1378                 unsigned char *p;
1379                 unsigned char *d = data,
1380                         answer = 0;
1381                 if (!*d || *d == '|') {
1382                         ast_log (LOG_ERROR, "Requires queue name\n");
1383                         ast_module_user_remove(u);
1384                         return -1;
1385                 }
1386                 for (p = d; *p && *p != '|'; p++);
1387                 if (p - d >= sizeof (h.queue)) {
1388                         ast_log (LOG_ERROR, "Queue name too long\n");
1389                         ast_module_user_remove(u);
1390                         return -1;
1391                 }
1392                 strncpy(h.queue, (char *)d, p - d);
1393                 if (*p == '|')
1394                         p++;
1395                 d = p;
1396                 for (p = (unsigned char *)h.queue; *p; p++)
1397                         if (!isalnum (*p))
1398                                 *p = '-';                         /* make very safe for filenames */
1399                 while (*d && *d != '|') {
1400                         switch (*d) {
1401                         case 'a':                                /* we have to send the initial FSK sequence */
1402                                 answer = 1;
1403                                 break;
1404                         case 's':                                /* we are acting as a service centre talking to a phone */
1405                                 h.smsc = 1;
1406                                 break;
1407                                 /* the following apply if there is an arg3/4 and apply to the created message file */
1408                         case 'r':
1409                                 h.srr = 1;
1410                                 break;
1411                         case 'o':
1412                                 h.dcs |= 4;                     /* octets */
1413                                 break;
1414                         case '1':
1415                         case '2':
1416                         case '3':
1417                         case '4':
1418                         case '5':
1419                         case '6':
1420                         case '7':                                /* set the pid for saved local message */
1421                                 h.pid = 0x40 + (*d & 0xF);
1422                                 break;
1423                         }
1424                         d++;
1425                 }
1426                 if (*d == '|') {
1427                         /* submitting a message, not taking call. */
1428                         /* deprecated, use smsq instead */
1429                         d++;
1430                         h.scts = time (0);
1431                         for (p = d; *p && *p != '|'; p++);
1432                         if (*p)
1433                                 *p++ = 0;
1434                         if (strlen ((char *)d) >= sizeof (h.oa)) {
1435                                 ast_log (LOG_ERROR, "Address too long %s\n", d);
1436                                 return 0;
1437                         }
1438                         if (h.smsc) {
1439                                 ast_copy_string (h.oa, (char *)d, sizeof (h.oa));
1440                         } else {
1441                                 ast_copy_string (h.da, (char *)d, sizeof (h.da));
1442                         }
1443                         if (!h.smsc)
1444                                 ast_copy_string (h.oa, h.cli, sizeof (h.oa));
1445                         d = p;
1446                         h.udl = 0;
1447                         while (*p && h.udl < SMSLEN)
1448                                 h.ud[h.udl++] = utf8decode(&p);
1449                         if (is7bit (h.dcs) && packsms7 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1450                                 ast_log (LOG_WARNING, "Invalid 7 bit GSM data\n");
1451                         if (is8bit (h.dcs) && packsms8 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1452                                 ast_log (LOG_WARNING, "Invalid 8 bit data\n");
1453                         if (is16bit (h.dcs) && packsms16 (0, h.udhl, h.udh, h.udl, h.ud) < 0)
1454                                 ast_log (LOG_WARNING, "Invalid 16 bit data\n");
1455                         h.rx = 0;                                 /* sent message */
1456                         h.mr = -1;
1457                         sms_writefile (&h);
1458                         ast_module_user_remove(u);
1459                         return 0;
1460                 }
1461
1462                 if (answer) {
1463                         /* set up SMS_EST initial message */
1464                         h.omsg[0] = 0x93;
1465                         h.omsg[1] = 0;
1466                         sms_messagetx (&h);
1467                 }
1468         }
1469
1470         if (chan->_state != AST_STATE_UP)
1471                 ast_answer (chan);
1472
1473 #ifdef OUTALAW
1474         res = ast_set_write_format (chan, AST_FORMAT_ALAW);
1475 #else
1476         res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
1477 #endif
1478         if (res >= 0)
1479                 res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
1480         if (res < 0) {
1481                 ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
1482                 ast_module_user_remove(u);
1483                 return -1;
1484         }
1485
1486         if (ast_activate_generator (chan, &smsgen, &h) < 0) {
1487                 ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
1488                 ast_module_user_remove(u);
1489                 return -1;
1490         }
1491
1492         /* Do our thing here */
1493         while (ast_waitfor (chan, -1) > -1 && !h.hangup)
1494         {
1495                 f = ast_read (chan);
1496                 if (!f)
1497                         break;
1498                 if (f->frametype == AST_FRAME_VOICE) {
1499                         sms_process (&h, f->samples, f->data);
1500                 }
1501
1502                 ast_frfree (f);
1503         }
1504
1505         sms_log (&h, '?');                        /* log incomplete message */
1506
1507         ast_module_user_remove(u);
1508         return (h.err);
1509 }
1510
1511 static int unload_module(void)
1512 {
1513         int res;
1514
1515         res = ast_unregister_application (app);
1516         
1517         ast_module_user_hangup_all();
1518
1519         return res;     
1520 }
1521
1522 static int load_module(void)
1523 {
1524 #ifdef OUTALAW
1525         {
1526                 int p;
1527                 for (p = 0; p < 80; p++)
1528                         wavea[p] = AST_LIN2A (wave[p]);
1529         }
1530 #endif
1531         snprintf (log_file, sizeof (log_file), "%s/sms", ast_config_AST_LOG_DIR);
1532         snprintf (spool_dir, sizeof (spool_dir), "%s/sms", ast_config_AST_SPOOL_DIR);
1533         return ast_register_application (app, sms_exec, synopsis, descrip);
1534 }
1535
1536 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "SMS/PSTN handler");