2 * Asterisk -- A telephony toolkit for Linux.
4 * SMS application - ETSI ES 201 912 protocol 1 implimentation
6 * Copyright (C) 2004, Adrian Kennard, rights assigned to Digium
8 * This program is free software, distributed under the terms of
9 * the GNU General Public License
12 #include <asterisk/lock.h>
13 #include <asterisk/file.h>
14 #include <asterisk/logger.h>
15 #include <asterisk/options.h>
16 #include <asterisk/channel.h>
17 #include <asterisk/pbx.h>
18 #include <asterisk/module.h>
19 #include <asterisk/callerid.h>
26 #include <sys/types.h>
31 /* When acting as SC and answering, should check for messages and send instead of sending EST as first packet */
32 /* Add full VP support */
33 /* Handle status report messages (generation and reception) */
34 /* Log to show oa and da with no spaces to allow parsing */
37 static unsigned char message_ref; /* arbitary message ref */
39 static char *tdesc = "SMS/PSTN handler";
41 static char *app = "SMS";
43 static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
45 static char *descrip =
46 " SMS(name|[a][s]): SMS handles exchange of SMS data with a call to/from SMS capabale\n"
47 "phone or SMS PSTN service centre. Can send and/or receive SMS messages.\n"
48 "Returns 0 if call handled correctly, or -1 if there were any problems.\n"
49 "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n"
50 "Typical usage is to use to handle called from the SMS service centre CLI,\n"
51 "or to set up a call using 'outgoing' or manager interface to connect service centre to SMS()\n"
52 "name is the name of the queue used in /var/spool/asterisk/sms\n"
53 "Argument 'a' means answer, i.e. send initial FSK packet.\n"
54 "Argument 's' means act as service centre talking to a phone.\n"
55 "Messages are processed as per text file message queues.\n"
56 "Can also call as SMS(name|[s]|number|message) to queue a message.\n";
58 static signed short wave[] =
59 { 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
60 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
62 -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
64 -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
71 /* SMS 7 bit character mapping */
72 /* Note that some greek characters are simply coded as 191 (inverted question mark) as ISO-8859-1 does not do greek */
73 /* Note 27 (escape) is to be displayed as a space as per GSM 03.38 */
74 static unsigned char sms7to8[] = {
75 '@', 163, '$', 165, 232, 233, 249, 236, 242, 199, 10, 216, 248, 13, 197, 229,
76 191, '_', 191, 191, 191, 191, 191, 191, 191, 191, 191, ' ', 198, 230, 223, 201,
77 ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
78 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
79 161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
80 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
81 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
82 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
84 unsigned char sms8to7[256];
88 unsigned char hangup; /* we are done... */
89 unsigned char smsc; /* we are SMSC */
90 char queue[30]; /* queue name */
91 char oa[20]; /* originating address */
92 char da[20]; /* destination address */
93 time_t scts; /* time stamp */
94 unsigned char pid; /* protocol ID */
95 unsigned char dcs; /* data coding scheme */
96 unsigned char mr; /* message reference */
97 unsigned char udl; /* user date length */
98 unsigned char srr:1; /* Status Report request */
99 unsigned char rp:1; /* Reply Path */
100 unsigned int vp; /* validity period in minutes, 0 for not set */
101 unsigned char ud[160]; /* user data (message) */
102 unsigned char cli[20]; /* caller ID */
103 unsigned char ophase; /* phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
104 unsigned char ophasep; /* phase (0-79) for 1200 bps */
105 unsigned char obyte; /* byte being sent */
106 unsigned int opause; /* silent pause before sending (in sample periods) */
107 unsigned char obitp; /* bit in byte */
108 unsigned char osync; /* sync bits to send */
109 unsigned char obytep; /* byte in data */
110 unsigned char obyten; /* bytes in data */
111 unsigned char omsg[256]; /* data buffer (out) */
112 unsigned char imsg[200]; /* data buffer (in) */
113 signed long long ims0, imc0, ims1, imc1; /* magnitude averages sin/cos 0/1 */
115 unsigned short imag; /* signal level */
116 unsigned char ips0, ips1, ipc0, ipc1; /* phase sin/cos 0/1 */
117 unsigned char ibitl; /* last bit */
118 unsigned char ibitc; /* bit run length count */
119 unsigned char iphasep; /* bit phase (0-79) for 1200 bps */
120 unsigned char ibitn; /* bit number in byte being received */
121 unsigned char ibytev; /* byte value being received */
122 unsigned char ibytep; /* byte pointer in messafe */
123 unsigned char ibytec; /* byte checksum for message */
124 unsigned char ierr; /* error flag */
125 unsigned char ibith; /* history of last bits */
126 unsigned char ibitt; /* total of 1's in last 3 bites */
127 /* more to go here */
131 sms_alloc (struct ast_channel *chan, void *params)
137 sms_release (struct ast_channel *chan, void *data)
142 static void sms_messagetx (sms_t * h);
144 /* copy number, skipping non digits apart from leading + */
146 numcpy (char *d, char *s)
161 { /* static, return a date/time in ISO format */
162 static char date[20];
163 strftime (date, sizeof (date), "%Y-%m-%d %H:%M:%S", localtime (&t));
167 /* pack n bytes from i to o and return number of bytes */
169 pack7 (unsigned char *o, unsigned char *i, unsigned char n)
171 unsigned char p = 0, b = 0;
172 /* fixup - map character set perhaps... */
176 o[p] |= ((sms8to7[*i] & 0x7F) << b);
182 o[p] = ((sms8to7[*i] & 0x7F) >> (7 - b));
191 /* check if all characters are valid 7 bit coding characters */
193 check7 (unsigned char l, unsigned char *p)
196 if (sms8to7[*p++] & 0x80)
201 /* pack a date and return */
203 packdate (unsigned char *o, time_t w)
205 struct tm *t = localtime (&w);
206 #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
207 int z = - t->tm_gmtoff / 3600 / 15;
209 int z = timezone / 3600 / 15;
211 *o++ = ((t->tm_year % 10) << 4) + (t->tm_year % 100) / 10;
212 *o++ = (((t->tm_mon + 1) % 10) << 4) + (t->tm_mon + 1) / 10;
213 *o++ = ((t->tm_mday % 10) << 4) + t->tm_mday / 10;
214 *o++ = ((t->tm_hour % 10) << 4) + t->tm_hour / 10;
215 *o++ = ((t->tm_min % 10) << 4) + t->tm_min / 10;
216 *o++ = ((t->tm_sec % 10) << 4) + t->tm_sec / 10;
218 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
220 *o++ = ((z % 10) << 4) + z / 10;
223 /* unpack a date and return */
225 unpackdate (unsigned char *i)
228 t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
229 t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
230 t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
231 t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
232 t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
233 t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
236 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
238 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
242 /* unpack bytes from i to o and return number of source bytes. */
244 unpack7 (unsigned char *o, unsigned char *i, unsigned char l)
246 unsigned char b = 0, p = 0;
250 *o++ = sms7to8[((i[p] >> b) & 0x7F)];
252 *o++ = sms7to8[((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F)];
265 /* unpack an address from i, return byte length, unpack to o */
267 unpackaddress (char *o, unsigned char *i)
269 unsigned char l = i[0], p;
272 for (p = 0; p < l; p++)
275 *o++ = (i[2 + p / 2] >> 4) + '0';
277 *o++ = (i[2 + p / 2] & 0xF) + '0';
283 /* store an address at o, and return number of bytes used */
285 packaddress (unsigned char *o, char *i)
300 o[p++] |= ((*i & 0xF) << 4);
309 o[p++] |= 0xF0; /* pad */
314 sms_log (sms_t * h, char status)
315 { /* log the output, and remove file */
316 if (*h->oa || *h->da)
318 int o = open ("/var/log/asterisk/sms", O_CREAT | O_APPEND | O_WRONLY, 0666);
323 sprintf (line, "%s %c %s %s %s ", isodate (time (0)), status, h->queue, *h->oa ? h->oa : "-",
324 *h->da ? h->da : "-");
325 p = line + strlen (line);
326 for (n = 0; n < h->udl; n++)
327 if (h->ud[n] == '\\')
332 else if (h->ud[n] == '\n')
337 else if (h->ud[n] == '\r')
342 else if (h->ud[n] < 32 || h->ud[n] == 127)
348 write (o, line, strlen (line));
351 *h->oa = *h->da = h->udl = 0;
355 /* parse and delete a file */
357 sms_readfile (sms_t * h, char *fn)
361 char dcsset = 0; /* if DSC set */
362 ast_log (LOG_EVENT, "Sending %s\n", fn);
363 h->udl = *h->oa = *h->da = h->pid = h->srr = h->rp = h->vp = 0;
364 h->dcs = 0xF1; /* normal messages class 1 */
366 h->mr = message_ref++;
371 { /* concurrent access, we lost */
375 while (fgets (line, sizeof (line), s))
376 { /* process line in file */
378 for (p = line; *p && *p != '\n' && *p != '\r'; p++);
379 *p = 0; /* strip eoln */
380 //ast_log (LOG_EVENT, "Line %s\n", line);
382 if (!*p || *p == ';')
383 continue; /* blank line or comment, ignore */
394 if (!strcmp (line, "ud"))
395 { /* parse message */
397 while (*p && o < 160)
420 ast_log (LOG_WARNING, "UD too long in %s\n", fn);
426 if (!strcmp (line, "oa") && strlen (p) < sizeof (h->oa))
428 else if (!strcmp (line, "da") && strlen (p) < sizeof (h->oa))
430 else if (!strcmp (line, "pid"))
432 else if (!strcmp (line, "dcs"))
437 else if (!strcmp (line, "mr"))
439 else if (!strcmp (line, "srr"))
440 h->srr = (atoi (p) ? 1 : 0);
441 else if (!strcmp (line, "vp"))
443 else if (!strcmp (line, "rp"))
444 h->rp = (atoi (p) ? 1 : 0);
445 else if (!strcmp (line, "scts"))
446 { /* get date/time */
447 int Y, m, d, H, M, S;
448 if (sscanf (p, "%d-%d-%d %d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6)
451 t.tm_year = Y - 1900;
458 h->scts = mktime (&t);
459 if (h->scts == (time_t) - 1)
460 ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
464 ast_log (LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
468 { /* raw hex format */
470 if (!strcmp (line, "ud"))
473 while (*p && o < 160)
475 if (isxdigit (*p) && isxdigit (p[1]))
478 (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
487 ast_log (LOG_WARNING, "UD too long / invalid hex in %s\n", fn);
490 ast_log (LOG_WARNING, "Only ud can use 8 bit key format with # instead of =\n");
493 ast_log (LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
496 if (!dcsset && h->udl <= 140 && check7 (h->udl, h->ud))
498 h->dcs = 0xF5; // default to 8 bit
499 ast_log (LOG_WARNING, "Sending in 8 bit format because of illegal characters %s\n", fn);
501 if ((h->dcs & 4) && h->udl > 140)
503 ast_log (LOG_WARNING, "8 bit data too long, truncated %s\n", fn);
506 else if (!(h->dcs & 4) && check7 (h->udl, h->ud))
507 ast_log (LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
509 //ast_log (LOG_EVENT, "Loaded %s\n", fn);
512 /* white a received text message to a file */
514 sms_writefile (sms_t * h)
516 char fn[200], fn2[200];
518 strcpy (fn, "/var/spool/asterisk/sms");
519 mkdir (fn, 0777); /* ensure it exists */
520 sprintf (fn + strlen (fn), "/%s.%s", h->smsc ? "me-sc" : "sc-me", h->queue);
521 mkdir (fn, 0777); /* ensure it exists */
523 strftime (fn2 + strlen (fn2), 30, "/%Y-%m-%d_%H:%M:%S", localtime (&h->scts));
524 sprintf (fn2 + strlen (fn2), "-%02X", h->mr);
525 sprintf (fn + strlen (fn), "/.%s", fn2 + strlen (fn) + 1);
529 fprintf (o, "mr=%d\n", h->mr);
531 fprintf (o, "oa=%s\n", h->oa);
533 fprintf (o, "da=%s\n", h->da);
535 fprintf (o, "pid=%d\n", h->pid);
537 fprintf (o, "dcs=%d\n", h->dcs);
539 fprintf (o, "srr=%d\n", h->vp);
541 fprintf (o, "srr=1\n");
543 fprintf (o, "rp=1\n");
545 fprintf (o, "scts=%s\n", isodate (h->scts));
549 for (p = 0; p < h->udl && ((h->ud[p] >= 32 && h->ud[p] != 127) || h->ud[p] == '\n' || h->ud[p] == '\r'); p++);
551 { // use a hex format as unprintable characters
553 for (p = 0; p < h->udl; p++)
554 fprintf (o, "%02X", h->ud[p]);
556 /* followed by commented line using printable characters */
559 for (p = 0; p < h->udl; p++)
561 if (h->ud[p] == '\\')
563 else if (h->ud[p] == '\r')
565 else if (h->ud[p] == '\n')
567 else if (h->ud[p] < 32 || h->ud[p] == 127)
575 if (rename (fn, fn2))
578 ast_log (LOG_EVENT, "Received to %s\n", fn2);
582 /* read dir skipping dot files... */
583 static struct dirent *
591 while (f && *f->d_name == '.');
595 /* handle the incoming message */
597 sms_handleincoming (sms_t * h)
602 if ((h->imsg[2] & 3) == 1)
605 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
606 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
607 strcpy (h->oa, h->cli);
609 h->mr = h->imsg[p++];
610 p += unpackaddress (h->da, h->imsg + p);
611 h->pid = h->imsg[p++];
612 h->dcs = h->imsg[p++];
613 if ((h->imsg[2] & 0x18) == 0x10)
615 if (h->imsg[p] < 144)
616 h->vp = (h->imsg[p] + 1) * 5;
617 else if (h->imsg[p] < 168)
618 h->vp = 720 + (h->imsg[p] - 143) * 30;
619 else if (h->imsg[p] < 197)
620 h->vp = (h->imsg[p] - 166) * 1440;
622 h->vp = (h->imsg[p] - 192) * 10080;
625 else if (h->imsg[2] & 0x18)
626 p += 7; /* ignore enhanced / absolute VP */
627 h->udl = h->imsg[p++];
632 memcpy (h->ud, h->imsg + p, h->udl);
636 p += unpack7 (h->ud, h->imsg + p, h->udl);
638 sms_writefile (h); /* write the file */
639 if (p != h->imsg[1] + 2)
640 return 0xFF; /* duh! */
644 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
650 if (!(h->imsg[2] & 3))
652 *h->da = h->srr = h->rp = h->vp = 0;
653 h->mr = message_ref++;
654 p += unpackaddress (h->oa, h->imsg + p);
655 h->pid = h->imsg[p++];
656 h->dcs = h->imsg[p++];
657 h->scts = unpackdate (h->imsg + p);
659 h->udl = h->imsg[p++];
664 memcpy (h->ud, h->imsg + p, h->udl);
668 p += unpack7 (h->ud, h->imsg + p, h->udl);
670 sms_writefile (h); /* write the file */
671 if (p != h->imsg[1] + 2)
672 return 0xFF; /* duh! */
676 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
680 return 0; /* no error */
684 sms_nextoutgoing (sms_t * h)
685 { /* find and fill in next message, or send a REL if none waiting */
686 char fn[100 + NAME_MAX];
689 strcpy (fn, "/var/spool/asterisk/sms");
690 mkdir (fn, 0777); /* ensure it exists */
691 sprintf (fn + strlen (fn), "/%s.%s", h->smsc ? "sc-me" : "me-sc", h->queue);
692 mkdir (fn, 0777); /* ensure it exists */
696 struct dirent *f = readdirdot (d);
699 sprintf (fn + strlen (fn), "/%s", f->d_name);
700 sms_readfile (h, fn);
702 more = 1; /* more to send */
706 if (*h->da || *h->oa)
707 { /* message to send */
709 h->omsg[0] = 0x91; /* SMS_DATA */
712 h->omsg[p++] = (more ? 4 : 0);
713 p += packaddress (h->omsg + p, h->oa);
714 h->omsg[p++] = h->pid;
715 h->omsg[p++] = h->dcs;
716 packdate (h->omsg + p, h->scts);
718 h->omsg[p++] = h->udl;
723 memcpy (h->omsg + p, h->ud, h->udl);
727 p += pack7 (h->omsg + p, h->ud, h->udl);
732 h->omsg[p++] = 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0);
733 h->omsg[p++] = h->mr;
734 p += packaddress (h->omsg + p, h->da);
735 h->omsg[p++] = h->pid;
736 h->omsg[p++] = h->dcs;
740 h->omsg[p++] = (h->vp + 4) / 5 - 1;
741 else if (h->vp < 1440)
742 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
743 else if (h->vp < 43200)
744 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
745 else if (h->vp < 635040)
746 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
748 h->omsg[p++] = 255; /* max */
750 h->omsg[p++] = h->udl;
755 memcpy (h->omsg + p, h->ud, h->udl);
759 p += pack7 (h->omsg + p, h->ud, h->udl);
767 h->omsg[0] = 0x94; /* SMS_REL */
774 sms_messagerx (sms_t * h)
776 ast_verbose (VERBOSE_PREFIX_3 "SMS RX %02X %02X %02X %02X %02X %02X...\n", h->imsg[0], h->imsg[1], h->imsg[2],
777 h->imsg[3], h->imsg[4], h->imsg[5]);
781 case 0x91: /* SMS_DATA */
783 unsigned char cause = sms_handleincoming (h);
787 h->omsg[0] = 0x95; /* SMS_ACK */
789 h->omsg[2] = 0x00; /* deliver report */
790 h->omsg[3] = 0x00; /* no parameters */
795 h->omsg[0] = 0x96; /* SMS_NACK */
797 h->omsg[2] = 0; /* delivery report */
798 h->omsg[3] = cause; /* cause */
799 h->omsg[4] = 0; /* no parameters */
804 case 0x92: /* SMS_ERROR */
805 sms_messagetx (h); /* send whatever we sent again */
807 case 0x93: /* SMS_EST */
808 sms_nextoutgoing (h);
810 case 0x94: /* SMS_REL */
811 h->hangup = 1; /* hangup */
813 case 0x95: /* SMS_ACK */
815 sms_nextoutgoing (h);
817 case 0x96: /* SMS_NACK */
819 sms_nextoutgoing (h);
821 default: /* Unknown */
822 h->omsg[0] = 0x92; /* SMS_ERROR */
824 h->omsg[2] = 3; /* unknown message type; */
831 sms_messagetx (sms_t * h)
833 unsigned char c = 0, p;
834 for (p = 0; p < h->omsg[1] + 2; p++)
836 h->omsg[h->omsg[1] + 2] = 0 - c;
837 ast_verbose (VERBOSE_PREFIX_3 "SMS TX %02X %02X %02X %02X %02X %02X...\n", h->omsg[0], h->omsg[1], h->omsg[2],
838 h->omsg[3], h->omsg[4], h->omsg[5]);
841 if (h->omsg[0] == 0x93)
842 h->opause = 2400; /* initial message delay 300ms (for BT) */
846 h->obyten = h->omsg[1] + 3;
851 sms_generate (struct ast_channel *chan, void *data, int len, int samples)
854 unsigned char waste[AST_FRIENDLY_OFFSET];
855 signed short buf[800];
859 if (len > sizeof (buf))
861 ast_log (LOG_WARNING, "Only doing %d bytes (%d bytes requested)\n", (int)(sizeof (buf) / sizeof (signed short)), len);
865 waste[0] = 0; /* make compiler happy */
866 f.frametype = AST_FRAME_VOICE;
867 f.subclass = AST_FORMAT_SLINEAR;
868 f.offset = AST_FRIENDLY_OFFSET;
871 f.datalen = samples * 2;
874 /* create a buffer containing the digital sms pattern */
875 for (i = 0; i < samples; i++)
880 else if (h->obyten || h->osync)
882 buf[i] = wave[h->ophase];
883 if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
885 if ((h->ophasep += 12) >= 80)
889 h->osync--; /* sending sync bits */
895 h->obyte = 0; /* start bit; */
896 else if (h->obitp == 2)
897 h->obyte = h->omsg[h->obytep];
898 else if (h->obitp == 10)
900 h->obyte = 1; /* stop bit */
903 if (h->obytep == h->obyten)
905 h->obytep = h->obyten = 0; /* sent */
906 h->osync = 10; /* trailing marks */
913 if (ast_write (chan, &f) < 0)
915 ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
922 sms_process (sms_t * h, int samples, signed short *data)
924 if (h->obyten || h->osync)
925 return; /* sending */
928 unsigned long long m0, m1;
929 if (abs (*data) > h->imag)
930 h->imag = abs (*data);
932 h->imag = h->imag * 7 / 8;
935 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
937 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
938 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
939 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
940 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
941 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
942 if ((h->ips0 += 21) >= 80)
944 if ((h->ipc0 += 21) >= 80)
946 if ((h->ips1 += 13) >= 80)
948 if ((h->ipc1 += 13) >= 80)
959 bit = ((h->ibitt > 1) ? 1 : 0);
965 if (!h->ibitn && h->ibitc == 4 && !bit)
970 if (bit && h->ibitc == 200)
971 { /* sync, restart message */
972 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
977 if (h->iphasep >= 80)
982 if (!bit) /* bad stop bit */
983 h->ierr = 0xFF; /* unknown error */
986 if (h->ibytep < sizeof (h->imsg))
988 h->imsg[h->ibytep] = h->ibytev;
989 h->ibytec += h->ibytev;
992 else if (h->ibytep == sizeof (h->imsg))
993 h->ierr = 2; /* bad message length */
994 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr)
999 h->ierr = 1; /* bad checksum */
1004 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1010 { /* lost carrier */
1011 if (h->idle++ == 80000)
1012 { /* nothing happening */
1013 ast_log (LOG_EVENT, "No data, hanging up\n");
1018 h->omsg[0] = 0x92; /* error */
1020 h->omsg[2] = h->ierr;
1021 sms_messagetx (h); /* send error */
1023 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1029 static struct ast_generator smsgen = {
1031 release:sms_release,
1032 generate:sms_generate,
1036 sms_exec (struct ast_channel *chan, void *data)
1039 struct localuser *u;
1040 struct ast_frame *f;
1042 h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1043 h.dcs = 0xF1; /* default */
1046 ast_log (LOG_ERROR, "Requires queue name at least\n");
1051 { /* get caller ID. Used as originating address on sc side receives */
1052 char temp[256], *name, *num;
1053 strncpy (temp, chan->callerid, sizeof (temp));
1054 ast_callerid_parse (temp, &name, &num);
1057 ast_shrink_phone_number (num);
1058 if (strlen (num) < sizeof (h.cli))
1059 strcpy (h.cli, num);
1063 char *d = data, *p, answer = 0;
1064 if (!*d || *d == '|')
1066 ast_log (LOG_ERROR, "Requires queue name\n");
1069 for (p = d; *p && *p != '|'; p++);
1070 if (p - d >= sizeof (h.queue))
1072 ast_log (LOG_ERROR, "Queue name too long\n");
1075 strncpy (h.queue, d, p - d);
1079 for (p = h.queue; *p; p++)
1081 *p = '-'; /* make very safe for filenames */
1082 while (*d && *d != '|')
1086 case 'a': /* we have to send the initial FSK sequence */
1089 case 's': /* we are acting as a service centre talking to a phone */
1092 /* the following apply if there is an arg3/4 and apply to the created message file */
1097 h.dcs |= 4; /* octets */
1105 case '7': /* set the pid for saved local message */
1106 h.pid = 0x40 + (*d & 0xF);
1112 { /* submitting a message, not taking call. */
1115 for (p = d; *p && *p != '|'; p++);
1118 if (strlen (d) >= sizeof (h.oa))
1120 ast_log (LOG_ERROR, "Address too long %s\n", d);
1123 strcpy (h.smsc ? h.oa : h.da, d);
1125 strcpy (h.oa, h.cli);
1127 if (!(h.dcs & 4) && check7 (h.udl, h.ud))
1128 ast_log (LOG_WARNING, "Invalid GSM characters in %.*s\n", h.udl, h.ud);
1129 if (strlen (d) > ((h.dcs & 4) ? 140 : 160))
1131 ast_log (LOG_ERROR, "Message too long %s\n", d);
1132 h.udl = ((h.dcs & 4) ? 140 : 160);
1137 memcpy (h.ud, d, h.udl);
1138 h.smsc = !h.smsc; /* file woul go in wrong directory otherwise... */
1144 { /* set up SMS_EST initial message */
1152 if (chan->_state != AST_STATE_UP)
1155 res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
1157 res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
1160 LOCAL_USER_REMOVE (u);
1161 ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
1165 if (ast_activate_generator (chan, &smsgen, &h) < 0)
1167 LOCAL_USER_REMOVE (u);
1168 ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
1172 /* Do our thing here */
1173 while (ast_waitfor (chan, -1) > -1 && !h.hangup)
1175 f = ast_read (chan);
1178 if (f->frametype == AST_FRAME_VOICE)
1180 sms_process (&h, f->samples, f->data);
1186 sms_log (&h, '?'); /* log incomplete message */
1188 LOCAL_USER_REMOVE (u);
1193 unload_module (void)
1195 STANDARD_HANGUP_LOCALUSERS;
1196 return ast_unregister_application (app);
1202 { /* fill in sms8to7 from sms7to8 */
1204 for (p = 0; p < 256; p++)
1205 sms8to7[p] = 0xE0; /* inverted question mark and invalid */
1206 for (p = 0; p < 128; p++)
1207 sms8to7[sms7to8[p]] = p;
1209 return ast_register_application (app, sms_exec, synopsis, descrip);
1222 STANDARD_USECOUNT (res);
1229 return ASTERISK_GPL_KEY;