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>
33 /* When acting as SC and answering, should check for messages and send instead of sending EST as first packet */
34 /* Add full VP support */
35 /* Handle status report messages (generation and reception) */
36 /* Log to show oa and da with no spaces to allow parsing */
39 static unsigned char message_ref; /* arbitary message ref */
41 static char *tdesc = "SMS/PSTN handler";
43 static char *app = "SMS";
45 static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
47 static char *descrip =
48 " SMS(name|[a][s]): SMS handles exchange of SMS data with a call to/from SMS capabale\n"
49 "phone or SMS PSTN service centre. Can send and/or receive SMS messages.\n"
50 "Returns 0 if call handled correctly, or -1 if there were any problems.\n"
51 "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n"
52 "Typical usage is to use to handle called from the SMS service centre CLI,\n"
53 "or to set up a call using 'outgoing' or manager interface to connect service centre to SMS()\n"
54 "name is the name of the queue used in /var/spool/asterisk/sms\n"
55 "Argument 'a' means answer, i.e. send initial FSK packet.\n"
56 "Argument 's' means act as service centre talking to a phone.\n"
57 "Messages are processed as per text file message queues.\n"
58 "Can also call as SMS(name|[s]|number|message) to queue a message.\n";
60 static signed short wave[] =
61 { 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
62 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
64 -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
66 -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
73 /* SMS 7 bit character mapping */
74 /* Note that some greek characters are simply coded as 191 (inverted question mark) as ISO-8859-1 does not do greek */
75 /* Note 27 (escape) is to be displayed as a space as per GSM 03.38 */
76 static unsigned char sms7to8[] = {
77 '@', 163, '$', 165, 232, 233, 249, 236, 242, 199, 10, 216, 248, 13, 197, 229,
78 191, '_', 191, 191, 191, 191, 191, 191, 191, 191, 191, ' ', 198, 230, 223, 201,
79 ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
80 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
81 161, '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', 196, 214, 209, 220, 167,
83 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
84 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
86 unsigned char sms8to7[256];
90 unsigned char hangup; /* we are done... */
91 unsigned char smsc; /* we are SMSC */
92 char queue[30]; /* queue name */
93 char oa[20]; /* originating address */
94 char da[20]; /* destination address */
95 time_t scts; /* time stamp */
96 unsigned char pid; /* protocol ID */
97 unsigned char dcs; /* data coding scheme */
98 unsigned char mr; /* message reference */
99 unsigned char udl; /* user date length */
100 unsigned char srr:1; /* Status Report request */
101 unsigned char rp:1; /* Reply Path */
102 unsigned int vp; /* validity period in minutes, 0 for not set */
103 unsigned char ud[160]; /* user data (message) */
104 unsigned char cli[20]; /* caller ID */
105 unsigned char ophase; /* phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
106 unsigned char ophasep; /* phase (0-79) for 1200 bps */
107 unsigned char obyte; /* byte being sent */
108 unsigned int opause; /* silent pause before sending (in sample periods) */
109 unsigned char obitp; /* bit in byte */
110 unsigned char osync; /* sync bits to send */
111 unsigned char obytep; /* byte in data */
112 unsigned char obyten; /* bytes in data */
113 unsigned char omsg[256]; /* data buffer (out) */
114 unsigned char imsg[200]; /* data buffer (in) */
115 signed long long ims0, imc0, ims1, imc1; /* magnitude averages sin/cos 0/1 */
117 unsigned short imag; /* signal level */
118 unsigned char ips0, ips1, ipc0, ipc1; /* phase sin/cos 0/1 */
119 unsigned char ibitl; /* last bit */
120 unsigned char ibitc; /* bit run length count */
121 unsigned char iphasep; /* bit phase (0-79) for 1200 bps */
122 unsigned char ibitn; /* bit number in byte being received */
123 unsigned char ibytev; /* byte value being received */
124 unsigned char ibytep; /* byte pointer in messafe */
125 unsigned char ibytec; /* byte checksum for message */
126 unsigned char ierr; /* error flag */
127 unsigned char ibith; /* history of last bits */
128 unsigned char ibitt; /* total of 1's in last 3 bites */
129 /* more to go here */
133 sms_alloc (struct ast_channel *chan, void *params)
139 sms_release (struct ast_channel *chan, void *data)
144 static void sms_messagetx (sms_t * h);
146 /* copy number, skipping non digits apart from leading + */
148 numcpy (char *d, char *s)
163 { /* static, return a date/time in ISO format */
164 static char date[20];
165 strftime (date, sizeof (date), "%Y-%m-%d %H:%M:%S", localtime (&t));
169 /* pack n bytes from i to o and return number of bytes */
171 pack7 (unsigned char *o, unsigned char *i, unsigned char n)
173 unsigned char p = 0, b = 0;
174 /* fixup - map character set perhaps... */
178 o[p] |= ((sms8to7[*i] & 0x7F) << b);
184 o[p] = ((sms8to7[*i] & 0x7F) >> (7 - b));
193 /* check if all characters are valid 7 bit coding characters */
195 check7 (unsigned char l, unsigned char *p)
198 if (sms8to7[*p++] & 0x80)
203 /* pack a date and return */
205 packdate (unsigned char *o, time_t w)
207 struct tm *t = localtime (&w);
209 int z = - t->tm_gmtoff / 3600 / 15;
211 int z = timezone / 3600 / 15;
213 *o++ = ((t->tm_year % 10) << 4) + (t->tm_year % 100) / 10;
214 *o++ = (((t->tm_mon + 1) % 10) << 4) + (t->tm_mon + 1) / 10;
215 *o++ = ((t->tm_mday % 10) << 4) + t->tm_mday / 10;
216 *o++ = ((t->tm_hour % 10) << 4) + t->tm_hour / 10;
217 *o++ = ((t->tm_min % 10) << 4) + t->tm_min / 10;
218 *o++ = ((t->tm_sec % 10) << 4) + t->tm_sec / 10;
220 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
222 *o++ = ((z % 10) << 4) + z / 10;
225 /* unpack a date and return */
227 unpackdate (unsigned char *i)
230 t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
231 t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
232 t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
233 t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
234 t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
235 t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
238 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
240 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
244 /* unpack bytes from i to o and return number of source bytes. */
246 unpack7 (unsigned char *o, unsigned char *i, unsigned char l)
248 unsigned char b = 0, p = 0;
252 *o++ = sms7to8[((i[p] >> b) & 0x7F)];
254 *o++ = sms7to8[((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F)];
267 /* unpack an address from i, return byte length, unpack to o */
269 unpackaddress (char *o, unsigned char *i)
271 unsigned char l = i[0], p;
274 for (p = 0; p < l; p++)
277 *o++ = (i[2 + p / 2] >> 4) + '0';
279 *o++ = (i[2 + p / 2] & 0xF) + '0';
285 /* store an address at o, and return number of bytes used */
287 packaddress (unsigned char *o, char *i)
302 o[p++] |= ((*i & 0xF) << 4);
311 o[p++] |= 0xF0; /* pad */
316 sms_log (sms_t * h, char status)
317 { /* log the output, and remove file */
318 if (*h->oa || *h->da)
320 int o = open ("/var/log/asterisk/sms", O_CREAT | O_APPEND | O_WRONLY, 0666);
325 sprintf (line, "%s %c %s %s %s ", isodate (time (0)), status, h->queue, *h->oa ? h->oa : "-",
326 *h->da ? h->da : "-");
327 p = line + strlen (line);
328 for (n = 0; n < h->udl; n++)
329 if (h->ud[n] == '\\')
334 else if (h->ud[n] == '\n')
339 else if (h->ud[n] == '\r')
344 else if (h->ud[n] < 32 || h->ud[n] == 127)
350 write (o, line, strlen (line));
353 *h->oa = *h->da = h->udl = 0;
357 /* parse and delete a file */
359 sms_readfile (sms_t * h, char *fn)
363 char dcsset = 0; /* if DSC set */
364 ast_log (LOG_EVENT, "Sending %s\n", fn);
365 h->udl = *h->oa = *h->da = h->pid = h->srr = h->rp = h->vp = 0;
366 h->dcs = 0xF1; /* normal messages class 1 */
368 h->mr = message_ref++;
373 { /* concurrent access, we lost */
377 while (fgets (line, sizeof (line), s))
378 { /* process line in file */
380 for (p = line; *p && *p != '\n' && *p != '\r'; p++);
381 *p = 0; /* strip eoln */
382 //ast_log (LOG_EVENT, "Line %s\n", line);
384 if (!*p || *p == ';')
385 continue; /* blank line or comment, ignore */
396 if (!strcmp (line, "ud"))
397 { /* parse message */
399 while (*p && o < 160)
422 ast_log (LOG_WARNING, "UD too long in %s\n", fn);
428 if (!strcmp (line, "oa") && strlen (p) < sizeof (h->oa))
430 else if (!strcmp (line, "da") && strlen (p) < sizeof (h->oa))
432 else if (!strcmp (line, "pid"))
434 else if (!strcmp (line, "dcs"))
439 else if (!strcmp (line, "mr"))
441 else if (!strcmp (line, "srr"))
442 h->srr = (atoi (p) ? 1 : 0);
443 else if (!strcmp (line, "vp"))
445 else if (!strcmp (line, "rp"))
446 h->rp = (atoi (p) ? 1 : 0);
447 else if (!strcmp (line, "scts"))
448 { /* get date/time */
449 int Y, m, d, H, M, S;
450 if (sscanf (p, "%d-%d-%d %d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6)
453 t.tm_year = Y - 1900;
460 h->scts = mktime (&t);
461 if (h->scts == (time_t) - 1)
462 ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
466 ast_log (LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
470 { /* raw hex format */
472 if (!strcmp (line, "ud"))
475 while (*p && o < 160)
477 if (isxdigit (*p) && isxdigit (p[1]))
480 (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
489 ast_log (LOG_WARNING, "UD too long / invalid hex in %s\n", fn);
492 ast_log (LOG_WARNING, "Only ud can use 8 bit key format with # instead of =\n");
495 ast_log (LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
498 if (!dcsset && h->udl <= 140 && check7 (h->udl, h->ud))
500 h->dcs = 0xF5; // default to 8 bit
501 ast_log (LOG_WARNING, "Sending in 8 bit format because of illegal characters %s\n", fn);
503 if ((h->dcs & 4) && h->udl > 140)
505 ast_log (LOG_WARNING, "8 bit data too long, truncated %s\n", fn);
508 else if (!(h->dcs & 4) && check7 (h->udl, h->ud))
509 ast_log (LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
511 //ast_log (LOG_EVENT, "Loaded %s\n", fn);
514 /* white a received text message to a file */
516 sms_writefile (sms_t * h)
518 char fn[200], fn2[200];
520 strcpy (fn, "/var/spool/asterisk/sms");
521 mkdir (fn, 0777); /* ensure it exists */
522 sprintf (fn + strlen (fn), "/%s.%s", h->smsc ? "me-sc" : "sc-me", h->queue);
523 mkdir (fn, 0777); /* ensure it exists */
525 strftime (fn2 + strlen (fn2), 30, "/%Y-%m-%d_%H:%M:%S", localtime (&h->scts));
526 sprintf (fn2 + strlen (fn2), "-%02X", h->mr);
527 sprintf (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 strcpy (h->oa, h->cli);
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];
691 strcpy (fn, "/var/spool/asterisk/sms");
692 mkdir (fn, 0777); /* ensure it exists */
693 sprintf (fn + strlen (fn), "/%s.%s", h->smsc ? "sc-me" : "me-sc", h->queue);
694 mkdir (fn, 0777); /* ensure it exists */
698 struct dirent *f = readdirdot (d);
701 sprintf (fn + strlen (fn), "/%s", f->d_name);
702 sms_readfile (h, fn);
704 more = 1; /* more to send */
708 if (*h->da || *h->oa)
709 { /* message to send */
711 h->omsg[0] = 0x91; /* SMS_DATA */
714 h->omsg[p++] = (more ? 4 : 0);
715 p += packaddress (h->omsg + p, h->oa);
716 h->omsg[p++] = h->pid;
717 h->omsg[p++] = h->dcs;
718 packdate (h->omsg + p, h->scts);
720 h->omsg[p++] = h->udl;
725 memcpy (h->omsg + p, h->ud, h->udl);
729 p += pack7 (h->omsg + p, h->ud, h->udl);
734 h->omsg[p++] = 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0);
735 h->omsg[p++] = h->mr;
736 p += packaddress (h->omsg + p, h->da);
737 h->omsg[p++] = h->pid;
738 h->omsg[p++] = h->dcs;
742 h->omsg[p++] = (h->vp + 4) / 5 - 1;
743 else if (h->vp < 1440)
744 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
745 else if (h->vp < 43200)
746 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
747 else if (h->vp < 635040)
748 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
750 h->omsg[p++] = 255; /* max */
752 h->omsg[p++] = h->udl;
757 memcpy (h->omsg + p, h->ud, h->udl);
761 p += pack7 (h->omsg + p, h->ud, h->udl);
769 h->omsg[0] = 0x94; /* SMS_REL */
776 sms_messagerx (sms_t * h)
778 ast_verbose (VERBOSE_PREFIX_3 "SMS RX %02X %02X %02X %02X %02X %02X...\n", h->imsg[0], h->imsg[1], h->imsg[2],
779 h->imsg[3], h->imsg[4], h->imsg[5]);
783 case 0x91: /* SMS_DATA */
785 unsigned char cause = sms_handleincoming (h);
789 h->omsg[0] = 0x95; /* SMS_ACK */
791 h->omsg[2] = 0x00; /* deliver report */
792 h->omsg[3] = 0x00; /* no parameters */
797 h->omsg[0] = 0x96; /* SMS_NACK */
799 h->omsg[2] = 0; /* delivery report */
800 h->omsg[3] = cause; /* cause */
801 h->omsg[4] = 0; /* no parameters */
806 case 0x92: /* SMS_ERROR */
807 sms_messagetx (h); /* send whatever we sent again */
809 case 0x93: /* SMS_EST */
810 sms_nextoutgoing (h);
812 case 0x94: /* SMS_REL */
813 h->hangup = 1; /* hangup */
815 case 0x95: /* SMS_ACK */
817 sms_nextoutgoing (h);
819 case 0x96: /* SMS_NACK */
821 sms_nextoutgoing (h);
823 default: /* Unknown */
824 h->omsg[0] = 0x92; /* SMS_ERROR */
826 h->omsg[2] = 3; /* unknown message type; */
833 sms_messagetx (sms_t * h)
835 unsigned char c = 0, p;
836 for (p = 0; p < h->omsg[1] + 2; p++)
838 h->omsg[h->omsg[1] + 2] = 0 - c;
839 ast_verbose (VERBOSE_PREFIX_3 "SMS TX %02X %02X %02X %02X %02X %02X...\n", h->omsg[0], h->omsg[1], h->omsg[2],
840 h->omsg[3], h->omsg[4], h->omsg[5]);
843 if (h->omsg[0] == 0x93)
844 h->opause = 2400; /* initial message delay 300ms (for BT) */
848 h->obyten = h->omsg[1] + 3;
853 sms_generate (struct ast_channel *chan, void *data, int len, int samples)
856 unsigned char waste[AST_FRIENDLY_OFFSET];
857 signed short buf[800];
861 if (len > sizeof (buf))
863 ast_log (LOG_WARNING, "Only doing %d bytes (%d bytes requested)\n", sizeof (buf) / sizeof (signed short), len);
867 waste[0] = 0; /* make compiler happy */
868 f.frametype = AST_FRAME_VOICE;
869 f.subclass = AST_FORMAT_SLINEAR;
870 f.offset = AST_FRIENDLY_OFFSET;
873 f.datalen = samples * 2;
876 /* create a buffer containing the digital sms pattern */
877 for (i = 0; i < samples; i++)
882 else if (h->obyten || h->osync)
884 buf[i] = wave[h->ophase];
885 if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
887 if ((h->ophasep += 12) >= 80)
891 h->osync--; /* sending sync bits */
897 h->obyte = 0; /* start bit; */
898 else if (h->obitp == 2)
899 h->obyte = h->omsg[h->obytep];
900 else if (h->obitp == 10)
902 h->obyte = 1; /* stop bit */
905 if (h->obytep == h->obyten)
907 h->obytep = h->obyten = 0; /* sent */
908 h->osync = 10; /* trailing marks */
915 if (ast_write (chan, &f) < 0)
917 ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
924 sms_process (sms_t * h, int samples, signed short *data)
926 if (h->obyten || h->osync)
927 return; /* sending */
930 unsigned long long m0, m1;
931 if (abs (*data) > h->imag)
932 h->imag = abs (*data);
934 h->imag = h->imag * 7 / 8;
937 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
939 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
940 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
941 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
942 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
943 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
944 if ((h->ips0 += 21) >= 80)
946 if ((h->ipc0 += 21) >= 80)
948 if ((h->ips1 += 13) >= 80)
950 if ((h->ipc1 += 13) >= 80)
961 bit = ((h->ibitt > 1) ? 1 : 0);
967 if (!h->ibitn && h->ibitc == 4 && !bit)
972 if (bit && h->ibitc == 200)
973 { /* sync, restart message */
974 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
979 if (h->iphasep >= 80)
984 if (!bit) /* bad stop bit */
985 h->ierr = 0xFF; /* unknown error */
988 if (h->ibytep < sizeof (h->imsg))
990 h->imsg[h->ibytep] = h->ibytev;
991 h->ibytec += h->ibytev;
994 else if (h->ibytep == sizeof (h->imsg))
995 h->ierr = 2; /* bad message length */
996 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr)
1001 h->ierr = 1; /* bad checksum */
1006 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1012 { /* lost carrier */
1013 if (h->idle++ == 80000)
1014 { /* nothing happening */
1015 ast_log (LOG_EVENT, "No data, hanging up\n");
1020 h->omsg[0] = 0x92; /* error */
1022 h->omsg[2] = h->ierr;
1023 sms_messagetx (h); /* send error */
1025 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1031 static struct ast_generator smsgen = {
1033 release:sms_release,
1034 generate:sms_generate,
1038 sms_exec (struct ast_channel *chan, void *data)
1041 struct localuser *u;
1042 struct ast_frame *f;
1044 h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1045 h.dcs = 0xF1; /* default */
1048 ast_log (LOG_ERROR, "Requires queue name at least\n");
1053 { /* get caller ID. Used as originating address on sc side receives */
1054 char temp[256], *name, *num;
1055 strncpy (temp, chan->callerid, sizeof (temp));
1056 ast_callerid_parse (temp, &name, &num);
1059 ast_shrink_phone_number (num);
1060 if (strlen (num) < sizeof (h.cli))
1061 strcpy (h.cli, num);
1065 char *d = data, *p, answer = 0;
1066 if (!*d || *d == '|')
1068 ast_log (LOG_ERROR, "Requires queue name\n");
1071 for (p = d; *p && *p != '|'; p++);
1072 if (p - d >= sizeof (h.queue))
1074 ast_log (LOG_ERROR, "Queue name too long\n");
1077 strncpy (h.queue, d, p - d);
1081 for (p = h.queue; *p; p++)
1083 *p = '-'; /* make very safe for filenames */
1084 while (*d && *d != '|')
1088 case 'a': /* we have to send the initial FSK sequence */
1091 case 's': /* we are acting as a service centre talking to a phone */
1094 /* the following apply if there is an arg3/4 and apply to the created message file */
1099 h.dcs |= 4; /* octets */
1107 case '7': /* set the pid for saved local message */
1108 h.pid = 0x40 + (*d & 0xF);
1114 { /* submitting a message, not taking call. */
1117 for (p = d; *p && *p != '|'; p++);
1120 if (strlen (d) >= sizeof (h.oa))
1122 ast_log (LOG_ERROR, "Address too long %s\n", d);
1125 strcpy (h.smsc ? h.oa : h.da, d);
1127 strcpy (h.oa, h.cli);
1129 if (!(h.dcs & 4) && check7 (h.udl, h.ud))
1130 ast_log (LOG_WARNING, "Invalid GSM characters in %.*s\n", h.udl, h.ud);
1131 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);
1162 LOCAL_USER_REMOVE (u);
1163 ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
1167 if (ast_activate_generator (chan, &smsgen, &h) < 0)
1169 LOCAL_USER_REMOVE (u);
1170 ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
1174 /* Do our thing here */
1175 while (ast_waitfor (chan, -1) > -1 && !h.hangup)
1177 f = ast_read (chan);
1180 if (f->frametype == AST_FRAME_VOICE)
1182 sms_process (&h, f->samples, f->data);
1188 sms_log (&h, '?'); /* log incomplete message */
1190 LOCAL_USER_REMOVE (u);
1195 unload_module (void)
1197 STANDARD_HANGUP_LOCALUSERS;
1198 return ast_unregister_application (app);
1204 { /* fill in sms8to7 from sms7to8 */
1206 for (p = 0; p < 256; p++)
1207 sms8to7[p] = 0xE0; /* inverted question mark and invalid */
1208 for (p = 0; p < 128; p++)
1209 sms8to7[sms7to8[p]] = p;
1211 return ast_register_application (app, sms_exec, synopsis, descrip);
1224 STANDARD_USECOUNT (res);
1231 return ASTERISK_GPL_KEY;