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