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>
25 #include <sys/types.h>
32 /* When acting as SC and answering, should check for messages and send instead of sending EST as first packet */
33 /* Add full VP support */
34 /* Handle status report messages (generation and reception) */
35 /* Log to show oa and da with no spaces to allow parsing */
38 static unsigned char message_ref; /* arbitary message ref */
40 static char *tdesc = "SMS/PSTN handler";
42 static char *app = "SMS";
44 static char *synopsis = "Communicates with SMS service centres and SMS capable analogue phones";
46 static char *descrip =
47 " SMS(name|[a][s]): SMS handles exchange of SMS data with a call to/from SMS capabale\n"
48 "phone or SMS PSTN service centre. Can send and/or receive SMS messages.\n"
49 "Returns 0 if call handled correctly, or -1 if there were any problems.\n"
50 "Works to ETSI ES 201 912 compatible with BT SMS PSTN service in UK\n"
51 "Typical usage is to use to handle called from the SMS service centre CLI,\n"
52 "or to set up a call using 'outgoing' or manager interface to connect service centre to SMS()\n"
53 "name is the name of the queue used in /var/spool/asterisk/sms\n"
54 "Argument 'a' means answer, i.e. send initial FSK packet.\n"
55 "Argument 's' means act as service centre talking to a phone.\n"
56 "Messages are processed as per text file message queues.\n"
57 "Can also call as SMS(name|[s]|number|message) to queue a message.\n";
59 static signed short wave[] =
60 { 0, 392, 782, 1167, 1545, 1913, 2270, 2612, 2939, 3247, 3536, 3802, 4045, 4263, 4455, 4619, 4755, 4862, 4938, 4985,
61 5000, 4985, 4938, 4862, 4755, 4619, 4455, 4263, 4045, 3802, 3536, 3247, 2939, 2612, 2270, 1913, 1545, 1167, 782, 392,
63 -1545, -1913, -2270, -2612, -2939, -3247, -3536, -3802, -4045, -4263, -4455, -4619, -4755, -4862, -4938, -4985, -5000,
65 -4755, -4619, -4455, -4263, -4045, -3802, -3536, -3247, -2939, -2612, -2270, -1913, -1545, -1167, -782, -392
72 /* SMS 7 bit character mapping */
73 /* Note that some greek characters are simply coded as 191 (inverted question mark) as ISO-8859-1 does not do greek */
74 /* Note 27 (escape) is to be displayed as a space as per GSM 03.38 */
75 static unsigned char sms7to8[] = {
76 '@', 163, '$', 165, 232, 233, 249, 236, 242, 199, 10, 216, 248, 13, 197, 229,
77 191, '_', 191, 191, 191, 191, 191, 191, 191, 191, 191, ' ', 198, 230, 223, 201,
78 ' ', '!', '"', '#', 164, '%', '&', 39, '(', ')', '*', '+', ',', '-', '.', '/',
79 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?',
80 161, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
81 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 196, 214, 209, 220, 167,
82 191, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
83 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 228, 246, 241, 252, 224,
85 unsigned char sms8to7[256];
89 unsigned char hangup; /* we are done... */
90 unsigned char smsc; /* we are SMSC */
91 char queue[30]; /* queue name */
92 char oa[20]; /* originating address */
93 char da[20]; /* destination address */
94 time_t scts; /* time stamp */
95 unsigned char pid; /* protocol ID */
96 unsigned char dcs; /* data coding scheme */
97 unsigned char mr; /* message reference */
98 unsigned char udl; /* user date length */
99 unsigned char srr:1; /* Status Report request */
100 unsigned char rp:1; /* Reply Path */
101 unsigned int vp; /* validity period in minutes, 0 for not set */
102 unsigned char ud[160]; /* user data (message) */
103 unsigned char cli[20]; /* caller ID */
104 unsigned char ophase; /* phase (0-79) for 0 and 1 frequencies (1300Hz and 2100Hz) */
105 unsigned char ophasep; /* phase (0-79) for 1200 bps */
106 unsigned char obyte; /* byte being sent */
107 unsigned int opause; /* silent pause before sending (in sample periods) */
108 unsigned char obitp; /* bit in byte */
109 unsigned char osync; /* sync bits to send */
110 unsigned char obytep; /* byte in data */
111 unsigned char obyten; /* bytes in data */
112 unsigned char omsg[256]; /* data buffer (out) */
113 unsigned char imsg[200]; /* data buffer (in) */
114 signed long long ims0, imc0, ims1, imc1; /* magnitude averages sin/cos 0/1 */
116 unsigned short imag; /* signal level */
117 unsigned char ips0, ips1, ipc0, ipc1; /* phase sin/cos 0/1 */
118 unsigned char ibitl; /* last bit */
119 unsigned char ibitc; /* bit run length count */
120 unsigned char iphasep; /* bit phase (0-79) for 1200 bps */
121 unsigned char ibitn; /* bit number in byte being received */
122 unsigned char ibytev; /* byte value being received */
123 unsigned char ibytep; /* byte pointer in messafe */
124 unsigned char ibytec; /* byte checksum for message */
125 unsigned char ierr; /* error flag */
126 unsigned char ibith; /* history of last bits */
127 unsigned char ibitt; /* total of 1's in last 3 bites */
128 /* more to go here */
132 sms_alloc (struct ast_channel *chan, void *params)
138 sms_release (struct ast_channel *chan, void *data)
143 static void sms_messagetx (sms_t * h);
145 /* copy number, skipping non digits apart from leading + */
147 numcpy (char *d, char *s)
162 { /* static, return a date/time in ISO format */
163 static char date[20];
164 strftime (date, sizeof (date), "%Y-%m-%d %H:%M:%S", localtime (&t));
168 /* pack n bytes from i to o and return number of bytes */
170 pack7 (unsigned char *o, unsigned char *i, unsigned char n)
172 unsigned char p = 0, b = 0;
173 /* fixup - map character set perhaps... */
177 o[p] |= ((sms8to7[*i] & 0x7F) << b);
183 o[p] = ((sms8to7[*i] & 0x7F) >> (7 - b));
192 /* check if all characters are valid 7 bit coding characters */
194 check7 (unsigned char l, unsigned char *p)
197 if (sms8to7[*p++] & 0x80)
202 /* pack a date and return */
204 packdate (unsigned char *o, time_t w)
206 struct tm *t = localtime (&w);
207 int z = timezone / 3600 / 15;
208 *o++ = ((t->tm_year % 10) << 4) + (t->tm_year % 100) / 10;
209 *o++ = (((t->tm_mon + 1) % 10) << 4) + (t->tm_mon + 1) / 10;
210 *o++ = ((t->tm_mday % 10) << 4) + t->tm_mday / 10;
211 *o++ = ((t->tm_hour % 10) << 4) + t->tm_hour / 10;
212 *o++ = ((t->tm_min % 10) << 4) + t->tm_min / 10;
213 *o++ = ((t->tm_sec % 10) << 4) + t->tm_sec / 10;
215 *o++ = (((-z) % 10) << 4) + (-z) / 10 + 0x08;
217 *o++ = ((z % 10) << 4) + z / 10;
220 /* unpack a date and return */
222 unpackdate (unsigned char *i)
225 t.tm_year = 100 + (i[0] & 0xF) * 10 + (i[0] >> 4);
226 t.tm_mon = (i[1] & 0xF) * 10 + (i[1] >> 4) - 1;
227 t.tm_mday = (i[2] & 0xF) * 10 + (i[2] >> 4);
228 t.tm_hour = (i[3] & 0xF) * 10 + (i[3] >> 4);
229 t.tm_min = (i[4] & 0xF) * 10 + (i[4] >> 4);
230 t.tm_sec = (i[5] & 0xF) * 10 + (i[5] >> 4);
233 t.tm_min += 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
235 t.tm_min -= 15 * ((i[6] & 0x7) * 10 + (i[6] >> 4));
239 /* unpack bytes from i to o and return number of source bytes. */
241 unpack7 (unsigned char *o, unsigned char *i, unsigned char l)
243 unsigned char b = 0, p = 0;
247 *o++ = sms7to8[((i[p] >> b) & 0x7F)];
249 *o++ = sms7to8[((((i[p] >> b) + (i[p + 1] << (8 - b)))) & 0x7F)];
262 /* unpack an address from i, return byte length, unpack to o */
264 unpackaddress (char *o, unsigned char *i)
266 unsigned char l = i[0], p;
269 for (p = 0; p < l; p++)
272 *o++ = (i[2 + p / 2] >> 4) + '0';
274 *o++ = (i[2 + p / 2] & 0xF) + '0';
280 /* store an address at o, and return number of bytes used */
282 packaddress (unsigned char *o, char *i)
297 o[p++] |= ((*i & 0xF) << 4);
306 o[p++] |= 0xF0; /* pad */
311 sms_log (sms_t * h, char status)
312 { /* log the output, and remove file */
313 if (*h->oa || *h->da)
315 int o = open ("/var/log/asterisk/sms", O_CREAT | O_APPEND | O_WRONLY, 0666);
320 sprintf (line, "%s %c %s %s %s ", isodate (time (0)), status, h->queue, *h->oa ? h->oa : "-",
321 *h->da ? h->da : "-");
322 p = line + strlen (line);
323 for (n = 0; n < h->udl; n++)
324 if (h->ud[n] == '\\')
329 else if (h->ud[n] == '\n')
334 else if (h->ud[n] == '\r')
339 else if (h->ud[n] < 32 || h->ud[n] == 127)
345 write (o, line, strlen (line));
348 *h->oa = *h->da = h->udl = 0;
352 /* parse and delete a file */
354 sms_readfile (sms_t * h, char *fn)
358 char dcsset = 0; /* if DSC set */
359 ast_log (LOG_EVENT, "Sending %s\n", fn);
360 h->udl = *h->oa = *h->da = h->pid = h->srr = h->rp = h->vp = 0;
361 h->dcs = 0xF1; /* normal messages class 1 */
363 h->mr = message_ref++;
368 { /* concurrent access, we lost */
372 while (fgets (line, sizeof (line), s))
373 { /* process line in file */
375 for (p = line; *p && *p != '\n' && *p != '\r'; p++);
376 *p = 0; /* strip eoln */
377 //ast_log (LOG_EVENT, "Line %s\n", line);
379 if (!*p || *p == ';')
380 continue; /* blank line or comment, ignore */
391 if (!strcmp (line, "ud"))
392 { /* parse message */
394 while (*p && o < 160)
417 ast_log (LOG_WARNING, "UD too long in %s\n", fn);
423 if (!strcmp (line, "oa") && strlen (p) < sizeof (h->oa))
425 else if (!strcmp (line, "da") && strlen (p) < sizeof (h->oa))
427 else if (!strcmp (line, "pid"))
429 else if (!strcmp (line, "dcs"))
434 else if (!strcmp (line, "mr"))
436 else if (!strcmp (line, "srr"))
437 h->srr = (atoi (p) ? 1 : 0);
438 else if (!strcmp (line, "vp"))
440 else if (!strcmp (line, "rp"))
441 h->rp = (atoi (p) ? 1 : 0);
442 else if (!strcmp (line, "scts"))
443 { /* get date/time */
444 int Y, m, d, H, M, S;
445 if (sscanf (p, "%d-%d-%d %d:%d:%d", &Y, &m, &d, &H, &M, &S) == 6)
448 t.tm_year = Y - 1900;
455 h->scts = mktime (&t);
456 if (h->scts == (time_t) - 1)
457 ast_log (LOG_WARNING, "Bad date/timein %s: %s", fn, p);
461 ast_log (LOG_WARNING, "Cannot parse in %s: %s=%si\n", fn, line, p);
465 { /* raw hex format */
467 if (!strcmp (line, "ud"))
470 while (*p && o < 160)
472 if (isxdigit (*p) && isxdigit (p[1]))
475 (((isalpha (*p) ? 9 : 0) + (*p & 0xF)) << 4) + ((isalpha (p[1]) ? 9 : 0) + (p[1] & 0xF));
484 ast_log (LOG_WARNING, "UD too long / invalid hex in %s\n", fn);
487 ast_log (LOG_WARNING, "Only ud can use 8 bit key format with # instead of =\n");
490 ast_log (LOG_WARNING, "Cannot parse in %s: %s\n", fn, line);
493 if (!dcsset && h->udl <= 140 && check7 (h->udl, h->ud))
495 h->dcs = 0xF5; // default to 8 bit
496 ast_log (LOG_WARNING, "Sending in 8 bit format because of illegal characters %s\n", fn);
498 if ((h->dcs & 4) && h->udl > 140)
500 ast_log (LOG_WARNING, "8 bit data too long, truncated %s\n", fn);
503 else if (!(h->dcs & 4) && check7 (h->udl, h->ud))
504 ast_log (LOG_WARNING, "Invalid 7 bit GSM data %s\n", fn);
506 //ast_log (LOG_EVENT, "Loaded %s\n", fn);
509 /* white a received text message to a file */
511 sms_writefile (sms_t * h)
513 char fn[200], fn2[200];
515 strcpy (fn, "/var/spool/asterisk/sms");
516 mkdir (fn, 0777); /* ensure it exists */
517 sprintf (fn + strlen (fn), "/%s.%s", h->smsc ? "me-sc" : "sc-me", h->queue);
518 mkdir (fn, 0777); /* ensure it exists */
520 strftime (fn2 + strlen (fn2), 30, "/%Y-%m-%d_%H:%M:%S", localtime (&h->scts));
521 sprintf (fn2 + strlen (fn2), "-%02X", h->mr);
522 sprintf (fn + strlen (fn), "/.%s", fn2 + strlen (fn) + 1);
526 fprintf (o, "mr=%d\n", h->mr);
528 fprintf (o, "oa=%s\n", h->oa);
530 fprintf (o, "da=%s\n", h->da);
532 fprintf (o, "pid=%d\n", h->pid);
534 fprintf (o, "dcs=%d\n", h->dcs);
536 fprintf (o, "srr=%d\n", h->vp);
538 fprintf (o, "srr=1\n");
540 fprintf (o, "rp=1\n");
542 fprintf (o, "scts=%s\n", isodate (h->scts));
546 for (p = 0; p < h->udl && ((h->ud[p] >= 32 && h->ud[p] != 127) || h->ud[p] == '\n' || h->ud[p] == '\r'); p++);
548 { // use a hex format as unprintable characters
550 for (p = 0; p < h->udl; p++)
551 fprintf (o, "%02X", h->ud[p]);
553 /* followed by commented line using printable characters */
556 for (p = 0; p < h->udl; p++)
558 if (h->ud[p] == '\\')
560 else if (h->ud[p] == '\r')
562 else if (h->ud[p] == '\n')
564 else if (h->ud[p] < 32 || h->ud[p] == 127)
572 if (rename (fn, fn2))
575 ast_log (LOG_EVENT, "Received to %s\n", fn2);
579 /* read dir skipping dot files... */
580 static struct dirent *
588 while (f && *f->d_name == '.');
592 /* handle the incoming message */
594 sms_handleincoming (sms_t * h)
599 if ((h->imsg[2] & 3) == 1)
602 h->srr = ((h->imsg[2] & 0x20) ? 1 : 0);
603 h->rp = ((h->imsg[2] & 0x80) ? 1 : 0);
604 strcpy (h->oa, h->cli);
606 h->mr = h->imsg[p++];
607 p += unpackaddress (h->da, h->imsg + p);
608 h->pid = h->imsg[p++];
609 h->dcs = h->imsg[p++];
610 if ((h->imsg[2] & 0x18) == 0x10)
612 if (h->imsg[p] < 144)
613 h->vp = (h->imsg[p] + 1) * 5;
614 else if (h->imsg[p] < 168)
615 h->vp = 720 + (h->imsg[p] - 143) * 30;
616 else if (h->imsg[p] < 197)
617 h->vp = (h->imsg[p] - 166) * 1440;
619 h->vp = (h->imsg[p] - 192) * 10080;
622 else if (h->imsg[2] & 0x18)
623 p += 7; /* ignore enhanced / absolute VP */
624 h->udl = h->imsg[p++];
629 memcpy (h->ud, h->imsg + p, h->udl);
633 p += unpack7 (h->ud, h->imsg + p, h->udl);
635 sms_writefile (h); /* write the file */
636 if (p != h->imsg[1] + 2)
637 return 0xFF; /* duh! */
641 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
647 if (!(h->imsg[2] & 3))
649 *h->da = h->srr = h->rp = h->vp = 0;
650 h->mr = message_ref++;
651 p += unpackaddress (h->oa, h->imsg + p);
652 h->pid = h->imsg[p++];
653 h->dcs = h->imsg[p++];
654 h->scts = unpackdate (h->imsg + p);
656 h->udl = h->imsg[p++];
661 memcpy (h->ud, h->imsg + p, h->udl);
665 p += unpack7 (h->ud, h->imsg + p, h->udl);
667 sms_writefile (h); /* write the file */
668 if (p != h->imsg[1] + 2)
669 return 0xFF; /* duh! */
673 ast_log (LOG_WARNING, "Unknown message type %02X\n", h->imsg[2]);
677 return 0; /* no error */
681 sms_nextoutgoing (sms_t * h)
682 { /* find and fill in next message, or send a REL if none waiting */
683 char fn[100 + NAME_MAX];
686 strcpy (fn, "/var/spool/asterisk/sms");
687 mkdir (fn, 0777); /* ensure it exists */
688 sprintf (fn + strlen (fn), "/%s.%s", h->smsc ? "sc-me" : "me-sc", h->queue);
689 mkdir (fn, 0777); /* ensure it exists */
693 struct dirent *f = readdirdot (d);
696 sprintf (fn + strlen (fn), "/%s", f->d_name);
697 sms_readfile (h, fn);
699 more = 1; /* more to send */
703 if (*h->da || *h->oa)
704 { /* message to send */
706 h->omsg[0] = 0x91; /* SMS_DATA */
709 h->omsg[p++] = (more ? 4 : 0);
710 p += packaddress (h->omsg + p, h->oa);
711 h->omsg[p++] = h->pid;
712 h->omsg[p++] = h->dcs;
713 packdate (h->omsg + p, h->scts);
715 h->omsg[p++] = h->udl;
720 memcpy (h->omsg + p, h->ud, h->udl);
724 p += pack7 (h->omsg + p, h->ud, h->udl);
729 h->omsg[p++] = 0x01 + (more ? 4 : 0) + (h->srr ? 0x20 : 0) + (h->rp ? 0x80 : 0) + (h->vp ? 0x10 : 0);
730 h->omsg[p++] = h->mr;
731 p += packaddress (h->omsg + p, h->da);
732 h->omsg[p++] = h->pid;
733 h->omsg[p++] = h->dcs;
737 h->omsg[p++] = (h->vp + 4) / 5 - 1;
738 else if (h->vp < 1440)
739 h->omsg[p++] = (h->vp - 720 + 29) / 30 + 143;
740 else if (h->vp < 43200)
741 h->omsg[p++] = (h->vp + 1439) / 1440 + 166;
742 else if (h->vp < 635040)
743 h->omsg[p++] = (h->vp + 10079) / 10080 + 192;
745 h->omsg[p++] = 255; /* max */
747 h->omsg[p++] = h->udl;
752 memcpy (h->omsg + p, h->ud, h->udl);
756 p += pack7 (h->omsg + p, h->ud, h->udl);
764 h->omsg[0] = 0x94; /* SMS_REL */
771 sms_messagerx (sms_t * h)
773 ast_verbose (VERBOSE_PREFIX_3 "SMS RX %02X %02X %02X %02X %02X %02X...\n", h->imsg[0], h->imsg[1], h->imsg[2],
774 h->imsg[3], h->imsg[4], h->imsg[5]);
778 case 0x91: /* SMS_DATA */
780 unsigned char cause = sms_handleincoming (h);
784 h->omsg[0] = 0x95; /* SMS_ACK */
786 h->omsg[2] = 0x00; /* deliver report */
787 h->omsg[3] = 0x00; /* no parameters */
792 h->omsg[0] = 0x96; /* SMS_NACK */
794 h->omsg[2] = 0; /* delivery report */
795 h->omsg[3] = cause; /* cause */
796 h->omsg[4] = 0; /* no parameters */
801 case 0x92: /* SMS_ERROR */
802 sms_messagetx (h); /* send whatever we sent again */
804 case 0x93: /* SMS_EST */
805 sms_nextoutgoing (h);
807 case 0x94: /* SMS_REL */
808 h->hangup = 1; /* hangup */
810 case 0x95: /* SMS_ACK */
812 sms_nextoutgoing (h);
814 case 0x96: /* SMS_NACK */
816 sms_nextoutgoing (h);
818 default: /* Unknown */
819 h->omsg[0] = 0x92; /* SMS_ERROR */
821 h->omsg[2] = 3; /* unknown message type; */
828 sms_messagetx (sms_t * h)
830 unsigned char c = 0, p;
831 for (p = 0; p < h->omsg[1] + 2; p++)
833 h->omsg[h->omsg[1] + 2] = 0 - c;
834 ast_verbose (VERBOSE_PREFIX_3 "SMS TX %02X %02X %02X %02X %02X %02X...\n", h->omsg[0], h->omsg[1], h->omsg[2],
835 h->omsg[3], h->omsg[4], h->omsg[5]);
838 if (h->omsg[0] == 0x93)
839 h->opause = 2400; /* initial message delay 300ms (for BT) */
843 h->obyten = h->omsg[1] + 3;
848 sms_generate (struct ast_channel *chan, void *data, int len, int samples)
851 unsigned char waste[AST_FRIENDLY_OFFSET];
852 signed short buf[800];
856 if (len > sizeof (buf))
858 ast_log (LOG_WARNING, "Only doing %d bytes (%d bytes requested)\n", sizeof (buf) / sizeof (signed short), len);
862 waste[0] = 0; /* make compiler happy */
863 f.frametype = AST_FRAME_VOICE;
864 f.subclass = AST_FORMAT_SLINEAR;
865 f.offset = AST_FRIENDLY_OFFSET;
868 f.datalen = samples * 2;
871 /* create a buffer containing the digital sms pattern */
872 for (i = 0; i < samples; i++)
877 else if (h->obyten || h->osync)
879 buf[i] = wave[h->ophase];
880 if ((h->ophase += ((h->obyte & 1) ? 13 : 21)) >= 80)
882 if ((h->ophasep += 12) >= 80)
886 h->osync--; /* sending sync bits */
892 h->obyte = 0; /* start bit; */
893 else if (h->obitp == 2)
894 h->obyte = h->omsg[h->obytep];
895 else if (h->obitp == 10)
897 h->obyte = 1; /* stop bit */
900 if (h->obytep == h->obyten)
902 h->obytep = h->obyten = 0; /* sent */
903 h->osync = 10; /* trailing marks */
910 if (ast_write (chan, &f) < 0)
912 ast_log (LOG_WARNING, "Failed to write frame to '%s': %s\n", chan->name, strerror (errno));
919 sms_process (sms_t * h, int samples, signed short *data)
921 if (h->obyten || h->osync)
922 return; /* sending */
925 unsigned long long m0, m1;
926 if (abs (*data) > h->imag)
927 h->imag = abs (*data);
929 h->imag = h->imag * 7 / 8;
932 h->ims0 = (h->ims0 * 6 + *data * wave[h->ips0]) / 7;
934 h->imc0 = (h->imc0 * 6 + *data * wave[h->ipc0]) / 7;
935 h->ims1 = (h->ims1 * 6 + *data * wave[h->ips1]) / 7;
936 h->imc1 = (h->imc1 * 6 + *data * wave[h->ipc1]) / 7;
937 m0 = h->ims0 * h->ims0 + h->imc0 * h->imc0;
938 m1 = h->ims1 * h->ims1 + h->imc1 * h->imc1;
939 if ((h->ips0 += 21) >= 80)
941 if ((h->ipc0 += 21) >= 80)
943 if ((h->ips1 += 13) >= 80)
945 if ((h->ipc1 += 13) >= 80)
956 bit = ((h->ibitt > 1) ? 1 : 0);
962 if (!h->ibitn && h->ibitc == 4 && !bit)
967 if (bit && h->ibitc == 200)
968 { /* sync, restart message */
969 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
974 if (h->iphasep >= 80)
979 if (!bit) /* bad stop bit */
980 h->ierr = 0xFF; /* unknown error */
983 if (h->ibytep < sizeof (h->imsg))
985 h->imsg[h->ibytep] = h->ibytev;
986 h->ibytec += h->ibytev;
989 else if (h->ibytep == sizeof (h->imsg))
990 h->ierr = 2; /* bad message length */
991 if (h->ibytep > 1 && h->ibytep == 3 + h->imsg[1] && !h->ierr)
996 h->ierr = 1; /* bad checksum */
1001 h->ibytev = (h->ibytev >> 1) + (bit ? 0x80 : 0);
1007 { /* lost carrier */
1008 if (h->idle++ == 80000)
1009 { /* nothing happening */
1010 ast_log (LOG_EVENT, "No data, hanging up\n");
1015 h->omsg[0] = 0x92; /* error */
1017 h->omsg[2] = h->ierr;
1018 sms_messagetx (h); /* send error */
1020 h->ierr = h->ibitn = h->ibytep = h->ibytec = 0;
1026 static struct ast_generator smsgen = {
1028 release:sms_release,
1029 generate:sms_generate,
1033 sms_exec (struct ast_channel *chan, void *data)
1036 struct localuser *u;
1037 struct ast_frame *f;
1039 h.ipc0 = h.ipc1 = 20; /* phase for cosine */
1040 h.dcs = 0xF1; /* default */
1043 ast_log (LOG_ERROR, "Requires queue name at least\n");
1048 { /* get caller ID. Used as originating address on sc side receives */
1049 char temp[256], *name, *num;
1050 strncpy (temp, chan->callerid, sizeof (temp));
1051 ast_callerid_parse (temp, &name, &num);
1054 ast_shrink_phone_number (num);
1055 if (strlen (num) < sizeof (h.cli))
1056 strcpy (h.cli, num);
1060 char *d = data, *p, answer = 0;
1061 if (!*d || *d == '|')
1063 ast_log (LOG_ERROR, "Requires queue name\n");
1066 for (p = d; *p && *p != '|'; p++);
1067 if (p - d >= sizeof (h.queue))
1069 ast_log (LOG_ERROR, "Queue name too long\n");
1072 strncpy (h.queue, d, p - d);
1076 for (p = h.queue; *p; p++)
1078 *p = '-'; /* make very safe for filenames */
1079 while (*d && *d != '|')
1083 case 'a': /* we have to send the initial FSK sequence */
1086 case 's': /* we are acting as a service centre talking to a phone */
1089 /* the following apply if there is an arg3/4 and apply to the created message file */
1094 h.dcs |= 4; /* octets */
1102 case '7': /* set the pid for saved local message */
1103 h.pid = 0x40 + (*d & 0xF);
1109 { /* submitting a message, not taking call. */
1112 for (p = d; *p && *p != '|'; p++);
1115 if (strlen (d) >= sizeof (h.oa))
1117 ast_log (LOG_ERROR, "Address too long %s\n", d);
1120 strcpy (h.smsc ? h.oa : h.da, d);
1122 strcpy (h.oa, h.cli);
1124 if (!(h.dcs & 4) && check7 (h.udl, h.ud))
1125 ast_log (LOG_WARNING, "Invalid GSM characters in %.*s\n", h.udl, h.ud);
1126 if (strlen (d) > ((h.dcs & 4) ? 140 : 160))
1128 ast_log (LOG_ERROR, "Message too long %s\n", d);
1129 h.udl = ((h.dcs & 4) ? 140 : 160);
1134 memcpy (h.ud, d, h.udl);
1135 h.smsc = !h.smsc; /* file woul go in wrong directory otherwise... */
1141 { /* set up SMS_EST initial message */
1149 if (chan->_state != AST_STATE_UP)
1152 res = ast_set_write_format (chan, AST_FORMAT_SLINEAR);
1154 res = ast_set_read_format (chan, AST_FORMAT_SLINEAR);
1157 LOCAL_USER_REMOVE (u);
1158 ast_log (LOG_ERROR, "Unable to set to linear mode, giving up\n");
1162 if (ast_activate_generator (chan, &smsgen, &h) < 0)
1164 LOCAL_USER_REMOVE (u);
1165 ast_log (LOG_ERROR, "Failed to activate generator on '%s'\n", chan->name);
1169 /* Do our thing here */
1170 while (ast_waitfor (chan, -1) > -1 && !h.hangup)
1172 f = ast_read (chan);
1175 if (f->frametype == AST_FRAME_VOICE)
1177 sms_process (&h, f->samples, f->data);
1183 sms_log (&h, '?'); /* log incomplete message */
1185 LOCAL_USER_REMOVE (u);
1190 unload_module (void)
1192 STANDARD_HANGUP_LOCALUSERS;
1193 return ast_unregister_application (app);
1199 { /* fill in sms8to7 from sms7to8 */
1201 for (p = 0; p < 256; p++)
1202 sms8to7[p] = 0xE0; /* inverted question mark and invalid */
1203 for (p = 0; p < 128; p++)
1204 sms8to7[sms7to8[p]] = p;
1206 return ast_register_application (app, sms_exec, synopsis, descrip);
1219 STANDARD_USECOUNT (res);
1226 return ASTERISK_GPL_KEY;