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 snprintf(line, sizeof(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)
520 strncpy(fn, "/var/spool/asterisk/sms", sizeof(fn) - 1);
521 mkdir (fn, 0777); /* ensure it exists */
522 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s.%s", h->smsc ? "me-sc" : "sc-me", h->queue);
523 mkdir (fn, 0777); /* ensure it exists */
524 strncpy(fn2, fn, sizeof(fn2) - 1);
525 strftime(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "/%Y-%m-%d_%H:%M:%S", localtime(&h->scts));
526 snprintf(fn2 + strlen(fn2), sizeof(fn2) - strlen(fn2), "-%02X", h->mr);
527 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/.%s", fn2 + strlen(fn) + 1);
531 fprintf (o, "mr=%d\n", h->mr);
533 fprintf (o, "oa=%s\n", h->oa);
535 fprintf (o, "da=%s\n", h->da);
537 fprintf (o, "pid=%d\n", h->pid);
539 fprintf (o, "dcs=%d\n", h->dcs);
541 fprintf (o, "srr=%d\n", h->vp);
543 fprintf (o, "srr=1\n");
545 fprintf (o, "rp=1\n");
547 fprintf (o, "scts=%s\n", isodate (h->scts));
551 for (p = 0; p < h->udl && ((h->ud[p] >= 32 && h->ud[p] != 127) || h->ud[p] == '\n' || h->ud[p] == '\r'); p++);
553 { // use a hex format as unprintable characters
555 for (p = 0; p < h->udl; p++)
556 fprintf (o, "%02X", h->ud[p]);
558 /* followed by commented line using printable characters */
561 for (p = 0; p < h->udl; p++)
563 if (h->ud[p] == '\\')
565 else if (h->ud[p] == '\r')
567 else if (h->ud[p] == '\n')
569 else if (h->ud[p] < 32 || h->ud[p] == 127)
577 if (rename (fn, fn2))
580 ast_log (LOG_EVENT, "Received to %s\n", fn2);
584 /* read dir skipping dot files... */
585 static struct dirent *
593 while (f && *f->d_name == '.');
597 /* handle the incoming message */
599 sms_handleincoming (sms_t * h)
604 if ((h->imsg[2] & 3) == 1)
607 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
608 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
609 strncpy (h->oa, h->cli, sizeof(h->oa) - 1);
611 h->mr = h->imsg[p++];
612 p += unpackaddress (h->da, h->imsg + p);
613 h->pid = h->imsg[p++];
614 h->dcs = h->imsg[p++];
615 if ((h->imsg[2] & 0x18) == 0x10)
617 if (h->imsg[p] < 144)
618 h->vp = (h->imsg[p] + 1) * 5;
619 else if (h->imsg[p] < 168)
620 h->vp = 720 + (h->imsg[p] - 143) * 30;
621 else if (h->imsg[p] < 197)
622 h->vp = (h->imsg[p] - 166) * 1440;
624 h->vp = (h->imsg[p] - 192) * 10080;
627 else if (h->imsg[2] & 0x18)
628 p += 7; /* ignore enhanced / absolute VP */
629 h->udl = h->imsg[p++];
634 memcpy (h->ud, h->imsg + p, h->udl);
638 p += unpack7 (h->ud, h->imsg + p, h->udl);
640 sms_writefile (h); /* write the file */
641 if (p != h->imsg[1] + 2)
642 return 0xFF; /* duh! */
646 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
652 if (!(h->imsg[2] & 3))
654 *h->da = h->srr = h->rp = h->vp = 0;
655 h->mr = message_ref++;
656 p += unpackaddress (h->oa, h->imsg + p);
657 h->pid = h->imsg[p++];
658 h->dcs = h->imsg[p++];
659 h->scts = unpackdate (h->imsg + p);
661 h->udl = h->imsg[p++];
666 memcpy (h->ud, h->imsg + p, h->udl);
670 p += unpack7 (h->ud, h->imsg + p, h->udl);
672 sms_writefile (h); /* write the file */
673 if (p != h->imsg[1] + 2)
674 return 0xFF; /* duh! */
678 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
682 return 0; /* no error */
686 sms_nextoutgoing (sms_t * h)
687 { /* find and fill in next message, or send a REL if none waiting */
688 char fn[100 + NAME_MAX] = "";
692 strncpy(fn, "/var/spool/asterisk/sms", sizeof(fn) - 1);
693 mkdir(fn, 0777); /* ensure it exists */
694 snprintf(fn + strlen (fn), sizeof(fn) - strlen(fn), "/%s.%s", h->smsc ? "sc-me" : "me-sc", h->queue);
695 mkdir (fn, 0777); /* ensure it exists */
699 struct dirent *f = readdirdot (d);
702 snprintf(fn + strlen(fn), sizeof(fn) - strlen(fn), "/%s", f->d_name);
703 sms_readfile (h, fn);
705 more = 1; /* more to send */
709 if (*h->da || *h->oa)
710 { /* message to send */
712 h->omsg[0] = 0x91; /* SMS_DATA */
715 h->omsg[p++] = (more ? 4 : 0);
716 p += packaddress (h->omsg + p, h->oa);
717 h->omsg[p++] = h->pid;
718 h->omsg[p++] = h->dcs;
719 packdate (h->omsg + p, h->scts);
721 h->omsg[p++] = h->udl;
726 memcpy (h->omsg + p, h->ud, h->udl);
730 p += pack7 (h->omsg + p, h->ud, h->udl);
735 h->omsg[p++] = 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0);
736 h->omsg[p++] = h->mr;
737 p += packaddress (h->omsg + p, h->da);
738 h->omsg[p++] = h->pid;
739 h->omsg[p++] = h->dcs;
743 h->omsg[p++] = (h->vp + 4) / 5 - 1;
744 else if (h->vp < 1440)
745 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
746 else if (h->vp < 43200)
747 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
748 else if (h->vp < 635040)
749 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
751 h->omsg[p++] = 255; /* max */
753 h->omsg[p++] = h->udl;
758 memcpy (h->omsg + p, h->ud, h->udl);
762 p += pack7 (h->omsg + p, h->ud, h->udl);
770 h->omsg[0] = 0x94; /* SMS_REL */
777 sms_messagerx (sms_t * h)
779 ast_verbose (VERBOSE_PREFIX_3 "SMS RX %02X %02X %02X %02X %02X %02X...\n", h->imsg[0], h->imsg[1], h->imsg[2],
780 h->imsg[3], h->imsg[4], h->imsg[5]);
784 case 0x91: /* SMS_DATA */
786 unsigned char cause = sms_handleincoming (h);
790 h->omsg[0] = 0x95; /* SMS_ACK */
792 h->omsg[2] = 0x00; /* deliver report */
793 h->omsg[3] = 0x00; /* no parameters */
798 h->omsg[0] = 0x96; /* SMS_NACK */
800 h->omsg[2] = 0; /* delivery report */
801 h->omsg[3] = cause; /* cause */
802 h->omsg[4] = 0; /* no parameters */
807 case 0x92: /* SMS_ERROR */
808 sms_messagetx (h); /* send whatever we sent again */
810 case 0x93: /* SMS_EST */
811 sms_nextoutgoing (h);
813 case 0x94: /* SMS_REL */
814 h->hangup = 1; /* hangup */
816 case 0x95: /* SMS_ACK */
818 sms_nextoutgoing (h);
820 case 0x96: /* SMS_NACK */
822 sms_nextoutgoing (h);
824 default: /* Unknown */
825 h->omsg[0] = 0x92; /* SMS_ERROR */
827 h->omsg[2] = 3; /* unknown message type; */
834 sms_messagetx (sms_t * h)
836 unsigned char c = 0, p;
837 for (p = 0; p < h->omsg[1] + 2; p++)
839 h->omsg[h->omsg[1] + 2] = 0 - c;
840 ast_verbose (VERBOSE_PREFIX_3 "SMS TX %02X %02X %02X %02X %02X %02X...\n", h->omsg[0], h->omsg[1], h->omsg[2],
841 h->omsg[3], h->omsg[4], h->omsg[5]);
844 if (h->omsg[0] == 0x93)
845 h->opause = 2400; /* initial message delay 300ms (for BT) */
849 h->obyten = h->omsg[1] + 3;
854 sms_generate (struct ast_channel *chan, void *data, int len, int samples)
857 unsigned char waste[AST_FRIENDLY_OFFSET];
858 signed short buf[800];
862 if (len > sizeof (buf))
864 ast_log (LOG_WARNING, "Only doing %d bytes (%d bytes requested)\n", (int)(sizeof (buf) / sizeof (signed short)), len);
868 waste[0] = 0; /* make compiler happy */
869 f.frametype = AST_FRAME_VOICE;
870 f.subclass = AST_FORMAT_SLINEAR;
871 f.offset = AST_FRIENDLY_OFFSET;
874 f.datalen = samples * 2;
877 /* create a buffer containing the digital sms pattern */
878 for (i = 0; i < samples; i++)
883 else if (h->obyten || h->osync)
885 buf[i] = wave[h->ophase];
886 if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
888 if ((h->ophasep += 12) >= 80)
892 h->osync--; /* sending sync bits */
898 h->obyte = 0; /* start bit; */
899 else if (h->obitp == 2)
900 h->obyte = h->omsg[h->obytep];
901 else if (h->obitp == 10)
903 h->obyte = 1; /* stop bit */
906 if (h->obytep == h->obyten)
908 h->obytep = h->obyten = 0; /* sent */
909 h->osync = 10; /* trailing marks */
916 if (ast_write (chan, &f) < 0)
918 ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
925 sms_process (sms_t * h, int samples, signed short *data)
927 if (h->obyten || h->osync)
928 return; /* sending */
931 unsigned long long m0, m1;
932 if (abs (*data) > h->imag)
933 h->imag = abs (*data);
935 h->imag = h->imag * 7 / 8;
938 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
940 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
941 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
942 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
943 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
944 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
945 if ((h->ips0 += 21) >= 80)
947 if ((h->ipc0 += 21) >= 80)
949 if ((h->ips1 += 13) >= 80)
951 if ((h->ipc1 += 13) >= 80)
962 bit = ((h->ibitt > 1) ? 1 : 0);
968 if (!h->ibitn && h->ibitc == 4 && !bit)
973 if (bit && h->ibitc == 200)
974 { /* sync, restart message */
975 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
980 if (h->iphasep >= 80)
985 if (!bit) /* bad stop bit */
986 h->ierr = 0xFF; /* unknown error */
989 if (h->ibytep < sizeof (h->imsg))
991 h->imsg[h->ibytep] = h->ibytev;
992 h->ibytec += h->ibytev;
995 else if (h->ibytep == sizeof (h->imsg))
996 h->ierr = 2; /* bad message length */
997 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr)
1002 h->ierr = 1; /* bad checksum */
1007 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1013 { /* lost carrier */
1014 if (h->idle++ == 80000)
1015 { /* nothing happening */
1016 ast_log (LOG_EVENT, "No data, hanging up\n");
1021 h->omsg[0] = 0x92; /* error */
1023 h->omsg[2] = h->ierr;
1024 sms_messagetx (h); /* send error */
1026 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1032 static struct ast_generator smsgen = {
1034 release:sms_release,
1035 generate:sms_generate,
1039 sms_exec(struct ast_channel *chan, void *data)
1042 struct localuser *u;
1043 struct ast_frame *f;
1046 h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1047 h.dcs = 0xF1; /* default */
1049 ast_log (LOG_ERROR, "Requires queue name at least\n");
1053 if (chan->callerid) {
1054 /* get caller ID. Used as originating address on sc side receives */
1055 char temp[256], *name, *num;
1056 strncpy (temp, chan->callerid, sizeof(temp) - 1);
1057 ast_callerid_parse (temp, &name, &num);
1060 ast_shrink_phone_number (num);
1061 if (strlen (num) < sizeof (h.cli))
1062 strncpy(h.cli, num, sizeof(h.cli) - 1);
1066 char *d = data, *p, answer = 0;
1067 if (!*d || *d == '|') {
1068 ast_log (LOG_ERROR, "Requires queue name\n");
1071 for (p = d; *p && *p != '|'; p++);
1072 if (p - d + 1 >= sizeof (h.queue)) {
1073 ast_log (LOG_ERROR, "Queue name too long\n");
1076 strncpy(h.queue, d, p - d);
1080 for (p = h.queue; *p; p++)
1082 *p = '-'; /* make very safe for filenames */
1083 while (*d && *d != '|') {
1085 case 'a': /* we have to send the initial FSK sequence */
1088 case 's': /* we are acting as a service centre talking to a phone */
1091 /* the following apply if there is an arg3/4 and apply to the created message file */
1096 h.dcs |= 4; /* octets */
1104 case '7': /* set the pid for saved local message */
1105 h.pid = 0x40 + (*d & 0xF);
1111 /* submitting a message, not taking call. */
1114 for (p = d; *p && *p != '|'; p++);
1117 if (strlen (d) >= sizeof (h.oa)) {
1118 ast_log (LOG_ERROR, "Address too long %s\n", d);
1122 strncpy(h.oa, d, sizeof(h.oa) - 1);
1125 strncpy(h.da, d, sizeof(h.da) - 1);
1128 strncpy(h.oa, h.cli, sizeof(h.oa) - 1);
1130 if (!(h.dcs & 4) && check7 (h.udl, h.ud))
1131 ast_log (LOG_WARNING, "Invalid GSM characters in %.*s\n", h.udl, h.ud);
1132 if (strlen (d) > ((h.dcs & 4) ? 140 : 160)) {
1133 ast_log (LOG_ERROR, "Message too long %s\n", d);
1134 h.udl = ((h.dcs & 4) ? 140 : 160);
1139 memcpy (h.ud, d, h.udl);
1140 h.smsc = !h.smsc; /* file woul go in wrong directory otherwise... */
1146 /* set up SMS_EST initial message */
1154 if (chan->_state != AST_STATE_UP)
1157 res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
1159 res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
1161 LOCAL_USER_REMOVE (u);
1162 ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
1166 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) {
1174 f = ast_read (chan);
1177 if (f->frametype == AST_FRAME_VOICE) {
1178 sms_process (&h, f->samples, f->data);
1184 sms_log (&h, '?'); /* log incomplete message */
1186 LOCAL_USER_REMOVE (u);
1191 unload_module (void)
1193 STANDARD_HANGUP_LOCALUSERS;
1194 return ast_unregister_application (app);
1200 { /* fill in sms8to7 from sms7to8 */
1202 for (p = 0; p < 256; p++)
1203 sms8to7[p] = 0xE0; /* inverted question mark and invalid */
1204 for (p = 0; p < 128; p++)
1205 sms8to7[sms7to8[p]] = p;
1207 return ast_register_application (app, sms_exec, synopsis, descrip);
1220 STANDARD_USECOUNT (res);
1227 return ASTERISK_GPL_KEY;