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