f00ec86487aa28c19832364ba45e2ac9cbd6cb83
[asterisk/asterisk.git] / res / res_adsi.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2005, Digium, Inc.
5  *
6  * Mark Spencer <markster@digium.com>
7  *
8  * Includes code and algorithms from the Zapata library.
9  *
10  * See http://www.asterisk.org for more information about
11  * the Asterisk project. Please do not directly contact
12  * any of the maintainers of this project for assistance;
13  * the project provides a web site, mailing lists and IRC
14  * channels for your use.
15  *
16  * This program is free software, distributed under the terms of
17  * the GNU General Public License Version 2. See the LICENSE file
18  * at the top of the source tree.
19  */
20
21 /*! \file
22  *
23  * \brief ADSI support
24  *
25  * \author Mark Spencer <markster@digium.com>
26  *
27  * \note this module is required by app_voicemail and app_getcpeid
28  * \todo Move app_getcpeid into this module
29  * \todo Create a core layer so that app_voicemail does not require
30  *      res_adsi to load
31  */
32
33 /*** MODULEINFO
34         <support_level>core</support_level>
35  ***/
36
37 #include "asterisk.h"
38
39 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
40
41 #include <time.h>
42 #include <math.h>
43
44 #include "asterisk/ulaw.h"
45 #include "asterisk/alaw.h"
46 #include "asterisk/callerid.h"
47 #include "asterisk/fskmodem.h"
48 #include "asterisk/channel.h"
49 #include "asterisk/module.h"
50 #include "asterisk/config.h"
51 #include "asterisk/file.h"
52
53 #define AST_API_MODULE
54 #include "asterisk/adsi.h"
55
56 #define DEFAULT_ADSI_MAX_RETRIES 3
57
58 #define ADSI_MAX_INTRO 20
59 #define ADSI_MAX_SPEED_DIAL 6
60
61 #define ADSI_FLAG_DATAMODE      (1 << 8)
62
63 static int maxretries = DEFAULT_ADSI_MAX_RETRIES;
64
65 /* Asterisk ADSI button definitions */
66 #define ADSI_SPEED_DIAL         10      /* 10-15 are reserved for speed dial */
67
68 static char intro[ADSI_MAX_INTRO][20];
69 static int aligns[ADSI_MAX_INTRO];
70
71 #define SPEEDDIAL_MAX_LEN       20
72 static char speeddial[ADSI_MAX_SPEED_DIAL][3][SPEEDDIAL_MAX_LEN];
73
74 static int alignment = 0;
75
76 static int adsi_generate(unsigned char *buf, int msgtype, unsigned char *msg, int msglen, int msgnum, int last, struct ast_format *codec)
77 {
78         int sum, x, bytes = 0;
79         /* Initial carrier (imaginary) */
80         float cr = 1.0, ci = 0.0, scont = 0.0;
81
82         if (msglen > 255) {
83                 msglen = 255;
84         }
85
86         /* If first message, Send 150ms of MARK's */
87         if (msgnum == 1) {
88                 for (x = 0; x < 150; x++) { /* was 150 */
89                         PUT_CLID_MARKMS;
90                 }
91         }
92
93         /* Put message type */
94         PUT_CLID(msgtype);
95         sum = msgtype;
96
97         /* Put message length (plus one for the message number) */
98         PUT_CLID(msglen + 1);
99         sum += msglen + 1;
100
101         /* Put message number */
102         PUT_CLID(msgnum);
103         sum += msgnum;
104
105         /* Put actual message */
106         for (x = 0; x < msglen; x++) {
107                 PUT_CLID(msg[x]);
108                 sum += msg[x];
109         }
110
111         /* Put 2's compliment of sum */
112         PUT_CLID(256-(sum & 0xff));
113
114 #if 0
115         if (last) {
116                 /* Put trailing marks */
117                 for (x = 0; x < 50; x++) {
118                         PUT_CLID_MARKMS;
119                 }
120         }
121 #endif
122         return bytes;
123
124 }
125
126 static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int len, int *remain)
127 {
128         /* Sends carefully on a full duplex channel by using reading for
129            timing */
130         struct ast_frame *inf, outf;
131         int amt;
132
133         /* Zero out our outgoing frame */
134         memset(&outf, 0, sizeof(outf));
135
136         if (remain && *remain) {
137                 amt = len;
138
139                 /* Send remainder if provided */
140                 if (amt > *remain) {
141                         amt = *remain;
142                 } else {
143                         *remain = *remain - amt;
144                 }
145                 outf.frametype = AST_FRAME_VOICE;
146                 ast_format_set(&outf.subclass.format, AST_FORMAT_ULAW, 0);
147                 outf.data.ptr = buf;
148                 outf.datalen = amt;
149                 outf.samples = amt;
150                 if (ast_write(chan, &outf)) {
151                         ast_log(LOG_WARNING, "Failed to carefully write frame\n");
152                         return -1;
153                 }
154                 /* Update pointers and lengths */
155                 buf += amt;
156                 len -= amt;
157         }
158
159         while (len) {
160                 amt = len;
161                 /* If we don't get anything at all back in a second, forget
162                    about it */
163                 if (ast_waitfor(chan, 1000) < 1) {
164                         return -1;
165                 }
166                 /* Detect hangup */
167                 if (!(inf = ast_read(chan))) {
168                         return -1;
169                 }
170
171                 /* Drop any frames that are not voice */
172                 if (inf->frametype != AST_FRAME_VOICE) {
173                         ast_frfree(inf);
174                         continue;
175                 }
176
177                 if (inf->subclass.format.id != AST_FORMAT_ULAW) {
178                         ast_log(LOG_WARNING, "Channel not in ulaw?\n");
179                         ast_frfree(inf);
180                         return -1;
181                 }
182                 /* Send no more than they sent us */
183                 if (amt > inf->datalen) {
184                         amt = inf->datalen;
185                 } else if (remain) {
186                         *remain = inf->datalen - amt;
187                 }
188                 outf.frametype = AST_FRAME_VOICE;
189                 ast_format_set(&outf.subclass.format, AST_FORMAT_ULAW, 0);
190                 outf.data.ptr = buf;
191                 outf.datalen = amt;
192                 outf.samples = amt;
193                 if (ast_write(chan, &outf)) {
194                         ast_log(LOG_WARNING, "Failed to carefully write frame\n");
195                         ast_frfree(inf);
196                         return -1;
197                 }
198                 /* Update pointers and lengths */
199                 buf += amt;
200                 len -= amt;
201                 ast_frfree(inf);
202         }
203         return 0;
204 }
205
206 static int __adsi_transmit_messages(struct ast_channel *chan, unsigned char **msg, int *msglen, int *msgtype)
207 {
208         /* msglen must be no more than 256 bits, each */
209         unsigned char buf[24000 * 5];
210         int pos = 0, res, x, start = 0, retries = 0, waittime, rem = 0, def;
211         char ack[3];
212         struct ast_frame *f;
213
214         if (ast_channel_adsicpe(chan) == AST_ADSI_UNAVAILABLE) {
215                 /* Don't bother if we know they don't support ADSI */
216                 errno = ENOSYS;
217                 return -1;
218         }
219
220         while (retries < maxretries) {
221                 struct ast_format tmpfmt;
222                 if (!(ast_channel_adsicpe(chan) & ADSI_FLAG_DATAMODE)) {
223                         /* Generate CAS (no SAS) */
224                         ast_format_set(&tmpfmt, AST_FORMAT_ULAW, 0);
225                         ast_gen_cas(buf, 0, 680, &tmpfmt);
226
227                         /* Send CAS */
228                         if (adsi_careful_send(chan, buf, 680, NULL)) {
229                                 ast_log(LOG_WARNING, "Unable to send CAS\n");
230                         }
231
232                         /* Wait For DTMF result */
233                         waittime = 500;
234                         for (;;) {
235                                 if (((res = ast_waitfor(chan, waittime)) < 1)) {
236                                         /* Didn't get back DTMF A in time */
237                                         ast_debug(1, "No ADSI CPE detected (%d)\n", res);
238                                         if (!ast_channel_adsicpe(chan)) {
239                                                 ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
240                                         }
241                                         errno = ENOSYS;
242                                         return -1;
243                                 }
244                                 waittime = res;
245                                 if (!(f = ast_read(chan))) {
246                                         ast_debug(1, "Hangup in ADSI\n");
247                                         return -1;
248                                 }
249                                 if (f->frametype == AST_FRAME_DTMF) {
250                                         if (f->subclass.integer == 'A') {
251                                                 /* Okay, this is an ADSI CPE.  Note this for future reference, too */
252                                                 if (!ast_channel_adsicpe(chan)) {
253                                                         ast_channel_adsicpe_set(chan, AST_ADSI_AVAILABLE);
254                                                 }
255                                                 break;
256                                         } else {
257                                                 if (f->subclass.integer == 'D') {
258                                                         ast_debug(1, "Off-hook capable CPE only, not ADSI\n");
259                                                 } else {
260                                                         ast_log(LOG_WARNING, "Unknown ADSI response '%c'\n", f->subclass.integer);
261                                                 }
262                                                 if (!ast_channel_adsicpe(chan)) {
263                                                         ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
264                                                 }
265                                                 errno = ENOSYS;
266                                                 ast_frfree(f);
267                                                 return -1;
268                                         }
269                                 }
270                                 ast_frfree(f);
271                         }
272
273                         ast_debug(1, "ADSI Compatible CPE Detected\n");
274                 } else {
275                         ast_debug(1, "Already in data mode\n");
276                 }
277
278                 x = 0;
279                 pos = 0;
280 #if 1
281                 def= ast_channel_defer_dtmf(chan);
282 #endif
283                 while ((x < 6) && msg[x]) {
284                         if ((res = adsi_generate(buf + pos, msgtype[x], msg[x], msglen[x], x+1 - start, (x == 5) || !msg[x+1], ast_format_set(&tmpfmt, AST_FORMAT_ULAW,0))) < 0) {
285                                 ast_log(LOG_WARNING, "Failed to generate ADSI message %d on channel %s\n", x + 1, ast_channel_name(chan));
286                                 return -1;
287                         }
288                         ast_debug(1, "Message %d, of %d input bytes, %d output bytes\n", x + 1, msglen[x], res);
289                         pos += res;
290                         x++;
291                 }
292
293
294                 rem = 0;
295                 res = adsi_careful_send(chan, buf, pos, &rem);
296                 if (!def) {
297                         ast_channel_undefer_dtmf(chan);
298                 }
299                 if (res) {
300                         return -1;
301                 }
302
303                 ast_debug(1, "Sent total spill of %d bytes\n", pos);
304
305                 memset(ack, 0, sizeof(ack));
306                 /* Get real result and check for hangup */
307                 if ((res = ast_readstring(chan, ack, 2, 1000, 1000, "")) < 0) {
308                         return -1;
309                 }
310                 if (ack[0] == 'D') {
311                         ast_debug(1, "Acked up to message %d\n", atoi(ack + 1)); start += atoi(ack + 1);
312                         if (start >= x) {
313                                 break;
314                         } else {
315                                 retries++;
316                                 ast_debug(1, "Retransmitting (%d), from %d\n", retries, start + 1);
317                         }
318                 } else {
319                         retries++;
320                         ast_log(LOG_WARNING, "Unexpected response to ack: %s (retry %d)\n", ack, retries);
321                 }
322         }
323         if (retries >= maxretries) {
324                 ast_log(LOG_WARNING, "Maximum ADSI Retries (%d) exceeded\n", maxretries);
325                 errno = ETIMEDOUT;
326                 return -1;
327         }
328         return 0;
329 }
330
331 int AST_OPTIONAL_API_NAME(ast_adsi_begin_download)(struct ast_channel *chan, char *service, unsigned char *fdn, unsigned char *sec, int version)
332 {
333         int bytes = 0;
334         unsigned char buf[256];
335         char ack[2];
336
337         /* Setup the resident soft key stuff, a piece at a time */
338         /* Upload what scripts we can for voicemail ahead of time */
339         bytes += ast_adsi_download_connect(buf + bytes, service, fdn, sec, version);
340         if (ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DOWNLOAD, 0)) {
341                 return -1;
342         }
343         if (ast_readstring(chan, ack, 1, 10000, 10000, "")) {
344                 return -1;
345         }
346         if (ack[0] == 'B') {
347                 return 0;
348         }
349         ast_debug(1, "Download was denied by CPE\n");
350         return -1;
351 }
352
353 int AST_OPTIONAL_API_NAME(ast_adsi_end_download)(struct ast_channel *chan)
354 {
355         int bytes = 0;
356         unsigned char buf[256];
357
358         /* Setup the resident soft key stuff, a piece at a time */
359         /* Upload what scripts we can for voicemail ahead of time */
360         bytes += ast_adsi_download_disconnect(buf + bytes);
361         if (ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DOWNLOAD, 0)) {
362                 return -1;
363         }
364         return 0;
365 }
366
367 int AST_OPTIONAL_API_NAME(ast_adsi_transmit_message_full)(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait)
368 {
369         unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL };
370         int msglens[5], msgtypes[5], newdatamode = (ast_channel_adsicpe(chan) & ADSI_FLAG_DATAMODE), res, x, waitforswitch = 0;
371         struct ast_format writeformat;
372         struct ast_format readformat;
373
374         ast_format_copy(&writeformat, ast_channel_writeformat(chan));
375         ast_format_copy(&readformat, ast_channel_readformat(chan));
376
377         for (x = 0; x < msglen; x += (msg[x+1]+2)) {
378                 if (msg[x] == ADSI_SWITCH_TO_DATA) {
379                         ast_debug(1, "Switch to data is sent!\n");
380                         waitforswitch++;
381                         newdatamode = ADSI_FLAG_DATAMODE;
382                 }
383
384                 if (msg[x] == ADSI_SWITCH_TO_VOICE) {
385                         ast_debug(1, "Switch to voice is sent!\n");
386                         waitforswitch++;
387                         newdatamode = 0;
388                 }
389         }
390         msgs[0] = msg;
391
392         msglens[0] = msglen;
393         msgtypes[0] = msgtype;
394
395         if (msglen > 253) {
396                 ast_log(LOG_WARNING, "Can't send ADSI message of %d bytes, too large\n", msglen);
397                 return -1;
398         }
399
400         ast_stopstream(chan);
401
402         if (ast_set_write_format_by_id(chan, AST_FORMAT_ULAW)) {
403                 ast_log(LOG_WARNING, "Unable to set write format to ULAW\n");
404                 return -1;
405         }
406
407         if (ast_set_read_format_by_id(chan, AST_FORMAT_ULAW)) {
408                 ast_log(LOG_WARNING, "Unable to set read format to ULAW\n");
409                 if (writeformat.id) {
410                         if (ast_set_write_format(chan, &writeformat)) {
411                                 ast_log(LOG_WARNING, "Unable to restore write format to %s\n", ast_getformatname(&writeformat));
412                         }
413                 }
414                 return -1;
415         }
416         res = __adsi_transmit_messages(chan, msgs, msglens, msgtypes);
417
418         if (dowait) {
419                 ast_debug(1, "Wait for switch is '%d'\n", waitforswitch);
420                 while (waitforswitch-- && ((res = ast_waitfordigit(chan, 1000)) > 0)) {
421                         res = 0;
422                         ast_debug(1, "Waiting for 'B'...\n");
423                 }
424         }
425
426         if (!res) {
427                 ast_channel_adsicpe_set(chan, (ast_channel_adsicpe(chan) & ~ADSI_FLAG_DATAMODE) | newdatamode);
428         }
429
430         if (writeformat.id) {
431                 ast_set_write_format(chan, &writeformat);
432         }
433         if (readformat.id) {
434                 ast_set_read_format(chan, &readformat);
435         }
436
437         if (!res) {
438                 res = ast_safe_sleep(chan, 100 );
439         }
440         return res;
441 }
442
443 int AST_OPTIONAL_API_NAME(ast_adsi_transmit_message)(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype)
444 {
445         return ast_adsi_transmit_message_full(chan, msg, msglen, msgtype, 1);
446 }
447
448 static inline int ccopy(unsigned char *dst, const unsigned char *src, int max)
449 {
450         int x = 0;
451         /* Carefully copy the requested data */
452         while ((x < max) && src[x] && (src[x] != 0xff)) {
453                 dst[x] = src[x];
454                 x++;
455         }
456         return x;
457 }
458
459 int AST_OPTIONAL_API_NAME(ast_adsi_load_soft_key)(unsigned char *buf, int key, const char *llabel, const char *slabel, char *ret, int data)
460 {
461         int bytes = 0;
462
463         /* Abort if invalid key specified */
464         if ((key < 2) || (key > 33)) {
465                 return -1;
466         }
467
468         buf[bytes++] = ADSI_LOAD_SOFTKEY;
469         /* Reserve for length */
470         bytes++;
471         /* Which key */
472         buf[bytes++] = key;
473
474         /* Carefully copy long label */
475         bytes += ccopy(buf + bytes, (const unsigned char *)llabel, 18);
476
477         /* Place delimiter */
478         buf[bytes++] = 0xff;
479
480         /* Short label */
481         bytes += ccopy(buf + bytes, (const unsigned char *)slabel, 7);
482
483
484         /* If specified, copy return string */
485         if (ret) {
486                 /* Place delimiter */
487                 buf[bytes++] = 0xff;
488                 if (data) {
489                         buf[bytes++] = ADSI_SWITCH_TO_DATA2;
490                 }
491                 /* Carefully copy return string */
492                 bytes += ccopy(buf + bytes, (const unsigned char *)ret, 20);
493
494         }
495         /* Replace parameter length */
496         buf[1] = bytes - 2;
497         return bytes;
498 }
499
500 int AST_OPTIONAL_API_NAME(ast_adsi_connect_session)(unsigned char *buf, unsigned char *fdn, int ver)
501 {
502         int bytes = 0, x;
503
504         /* Message type */
505         buf[bytes++] = ADSI_CONNECT_SESSION;
506
507         /* Reserve space for length */
508         bytes++;
509
510         if (fdn) {
511                 for (x = 0; x < 4; x++) {
512                         buf[bytes++] = fdn[x];
513                 }
514                 if (ver > -1) {
515                         buf[bytes++] = ver & 0xff;
516                 }
517         }
518
519         buf[1] = bytes - 2;
520         return bytes;
521
522 }
523
524 int AST_OPTIONAL_API_NAME(ast_adsi_download_connect)(unsigned char *buf, char *service,  unsigned char *fdn, unsigned char *sec, int ver)
525 {
526         int bytes = 0, x;
527
528         /* Message type */
529         buf[bytes++] = ADSI_DOWNLOAD_CONNECT;
530
531         /* Reserve space for length */
532         bytes++;
533
534         /* Primary column */
535         bytes+= ccopy(buf + bytes, (unsigned char *)service, 18);
536
537         /* Delimiter */
538         buf[bytes++] = 0xff;
539
540         for (x = 0; x < 4; x++) {
541                 buf[bytes++] = fdn[x];
542         }
543
544         for (x = 0; x < 4; x++) {
545                 buf[bytes++] = sec[x];
546         }
547
548         buf[bytes++] = ver & 0xff;
549
550         buf[1] = bytes - 2;
551
552         return bytes;
553
554 }
555
556 int AST_OPTIONAL_API_NAME(ast_adsi_disconnect_session)(unsigned char *buf)
557 {
558         int bytes = 0;
559
560         /* Message type */
561         buf[bytes++] = ADSI_DISC_SESSION;
562
563         /* Reserve space for length */
564         bytes++;
565
566         buf[1] = bytes - 2;
567         return bytes;
568
569 }
570
571 int AST_OPTIONAL_API_NAME(ast_adsi_query_cpeid)(unsigned char *buf)
572 {
573         int bytes = 0;
574         buf[bytes++] = ADSI_QUERY_CPEID;
575         /* Reserve space for length */
576         bytes++;
577         buf[1] = bytes - 2;
578         return bytes;
579 }
580
581 int AST_OPTIONAL_API_NAME(ast_adsi_query_cpeinfo)(unsigned char *buf)
582 {
583         int bytes = 0;
584         buf[bytes++] = ADSI_QUERY_CONFIG;
585         /* Reserve space for length */
586         bytes++;
587         buf[1] = bytes - 2;
588         return bytes;
589 }
590
591 int AST_OPTIONAL_API_NAME(ast_adsi_read_encoded_dtmf)(struct ast_channel *chan, unsigned char *buf, int maxlen)
592 {
593         int bytes = 0, res, gotstar = 0, pos = 0;
594         unsigned char current = 0;
595
596         memset(buf, 0, maxlen);
597
598         while (bytes <= maxlen) {
599                 /* Wait up to a second for a digit */
600                 if (!(res = ast_waitfordigit(chan, 1000))) {
601                         break;
602                 }
603                 if (res == '*') {
604                         gotstar = 1;
605                         continue;
606                 }
607                 /* Ignore anything other than a digit */
608                 if ((res < '0') || (res > '9')) {
609                         continue;
610                 }
611                 res -= '0';
612                 if (gotstar) {
613                         res += 9;
614                 }
615                 if (pos)  {
616                         pos = 0;
617                         buf[bytes++] = (res << 4) | current;
618                 } else {
619                         pos = 1;
620                         current = res;
621                 }
622                 gotstar = 0;
623         }
624
625         return bytes;
626 }
627
628 int AST_OPTIONAL_API_NAME(ast_adsi_get_cpeid)(struct ast_channel *chan, unsigned char *cpeid, int voice)
629 {
630         unsigned char buf[256] = "";
631         int bytes = 0, res;
632
633         bytes += ast_adsi_data_mode(buf);
634         ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
635
636         bytes = 0;
637         bytes += ast_adsi_query_cpeid(buf);
638         ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
639
640         /* Get response */
641         res = ast_adsi_read_encoded_dtmf(chan, cpeid, 4);
642         if (res != 4) {
643                 ast_log(LOG_WARNING, "Got %d bytes back of encoded DTMF, expecting 4\n", res);
644                 res = 0;
645         } else {
646                 res = 1;
647         }
648
649         if (voice) {
650                 bytes = 0;
651                 bytes += ast_adsi_voice_mode(buf, 0);
652                 ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
653                 /* Ignore the resulting DTMF B announcing it's in voice mode */
654                 ast_waitfordigit(chan, 1000);
655         }
656         return res;
657 }
658
659 int AST_OPTIONAL_API_NAME(ast_adsi_get_cpeinfo)(struct ast_channel *chan, int *width, int *height, int *buttons, int voice)
660 {
661         unsigned char buf[256] = "";
662         int bytes = 0, res;
663
664         bytes += ast_adsi_data_mode(buf);
665         ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
666
667         bytes = 0;
668         bytes += ast_adsi_query_cpeinfo(buf);
669         ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
670
671         /* Get width */
672         if ((res = ast_readstring(chan, (char *) buf, 2, 1000, 500, "")) < 0) {
673                 return res;
674         }
675         if (strlen((char *) buf) != 2) {
676                 ast_log(LOG_WARNING, "Got %d bytes of width, expecting 2\n", res);
677                 res = 0;
678         } else {
679                 res = 1;
680         }
681         if (width) {
682                 *width = atoi((char *) buf);
683         }
684         /* Get height */
685         memset(buf, 0, sizeof(buf));
686         if (res) {
687                 if ((res = ast_readstring(chan, (char *) buf, 2, 1000, 500, "")) < 0) {
688                         return res;
689                 }
690                 if (strlen((char *) buf) != 2) {
691                         ast_log(LOG_WARNING, "Got %d bytes of height, expecting 2\n", res);
692                         res = 0;
693                 } else {
694                         res = 1;
695                 }
696                 if (height) {
697                         *height = atoi((char *) buf);
698                 }
699         }
700         /* Get buttons */
701         memset(buf, 0, sizeof(buf));
702         if (res) {
703                 if ((res = ast_readstring(chan, (char *) buf, 1, 1000, 500, "")) < 0) {
704                         return res;
705                 }
706                 if (strlen((char *) buf) != 1) {
707                         ast_log(LOG_WARNING, "Got %d bytes of buttons, expecting 1\n", res);
708                         res = 0;
709                 } else {
710                         res = 1;
711                 }
712                 if (buttons) {
713                         *buttons = atoi((char *) buf);
714                 }
715         }
716         if (voice) {
717                 bytes = 0;
718                 bytes += ast_adsi_voice_mode(buf, 0);
719                 ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
720                 /* Ignore the resulting DTMF B announcing it's in voice mode */
721                 ast_waitfordigit(chan, 1000);
722         }
723         return res;
724 }
725
726 int AST_OPTIONAL_API_NAME(ast_adsi_data_mode)(unsigned char *buf)
727 {
728         int bytes = 0;
729
730         /* Message type */
731         buf[bytes++] = ADSI_SWITCH_TO_DATA;
732
733         /* Reserve space for length */
734         bytes++;
735
736         buf[1] = bytes - 2;
737         return bytes;
738
739 }
740
741 int AST_OPTIONAL_API_NAME(ast_adsi_clear_soft_keys)(unsigned char *buf)
742 {
743         int bytes = 0;
744
745         /* Message type */
746         buf[bytes++] = ADSI_CLEAR_SOFTKEY;
747
748         /* Reserve space for length */
749         bytes++;
750
751         buf[1] = bytes - 2;
752         return bytes;
753
754 }
755
756 int AST_OPTIONAL_API_NAME(ast_adsi_clear_screen)(unsigned char *buf)
757 {
758         int bytes = 0;
759
760         /* Message type */
761         buf[bytes++] = ADSI_CLEAR_SCREEN;
762
763         /* Reserve space for length */
764         bytes++;
765
766         buf[1] = bytes - 2;
767         return bytes;
768
769 }
770
771 int AST_OPTIONAL_API_NAME(ast_adsi_voice_mode)(unsigned char *buf, int when)
772 {
773         int bytes = 0;
774
775         /* Message type */
776         buf[bytes++] = ADSI_SWITCH_TO_VOICE;
777
778         /* Reserve space for length */
779         bytes++;
780
781         buf[bytes++] = when & 0x7f;
782
783         buf[1] = bytes - 2;
784         return bytes;
785
786 }
787
788 int AST_OPTIONAL_API_NAME(ast_adsi_available)(struct ast_channel *chan)
789 {
790         int cpe = ast_channel_adsicpe(chan) & 0xff;
791         if ((cpe == AST_ADSI_AVAILABLE) ||
792             (cpe == AST_ADSI_UNKNOWN)) {
793                 return 1;
794         }
795         return 0;
796 }
797
798 int AST_OPTIONAL_API_NAME(ast_adsi_download_disconnect)(unsigned char *buf)
799 {
800         int bytes = 0;
801
802         /* Message type */
803         buf[bytes++] = ADSI_DOWNLOAD_DISC;
804
805         /* Reserve space for length */
806         bytes++;
807
808         buf[1] = bytes - 2;
809         return bytes;
810
811 }
812
813 int AST_OPTIONAL_API_NAME(ast_adsi_display)(unsigned char *buf, int page, int line, int just, int wrap,
814                  char *col1, char *col2)
815 {
816         int bytes = 0;
817
818         /* Sanity check line number */
819
820         if (page) {
821                 if (line > 4) return -1;
822         } else {
823                 if (line > 33) return -1;
824         }
825
826         if (line < 1) {
827                 return -1;
828         }
829         /* Parameter type */
830         buf[bytes++] = ADSI_LOAD_VIRTUAL_DISP;
831
832         /* Reserve space for size */
833         bytes++;
834
835         /* Page and wrap indicator */
836         buf[bytes++] = ((page & 0x1) << 7) | ((wrap & 0x1) << 6) | (line & 0x3f);
837
838         /* Justification */
839         buf[bytes++] = (just & 0x3) << 5;
840
841         /* Omit highlight mode definition */
842         buf[bytes++] = 0xff;
843
844         /* Primary column */
845         bytes+= ccopy(buf + bytes, (unsigned char *)col1, 20);
846
847         /* Delimiter */
848         buf[bytes++] = 0xff;
849
850         /* Secondary column */
851         bytes += ccopy(buf + bytes, (unsigned char *)col2, 20);
852
853         /* Update length */
854         buf[1] = bytes - 2;
855
856         return bytes;
857
858 }
859
860 int AST_OPTIONAL_API_NAME(ast_adsi_input_control)(unsigned char *buf, int page, int line, int display, int format, int just)
861 {
862         int bytes = 0;
863
864         if (page) {
865                 if (line > 4) return -1;
866         } else {
867                 if (line > 33) return -1;
868         }
869
870         if (line < 1) {
871                 return -1;
872         }
873
874         buf[bytes++] = ADSI_INPUT_CONTROL;
875         bytes++;
876         buf[bytes++] = ((page & 1) << 7) | (line & 0x3f);
877         buf[bytes++] = ((display & 1) << 7) | ((just & 0x3) << 4) | (format & 0x7);
878
879         buf[1] = bytes - 2;
880         return bytes;
881 }
882
883 int AST_OPTIONAL_API_NAME(ast_adsi_input_format)(unsigned char *buf, int num, int dir, int wrap, char *format1, char *format2)
884 {
885         int bytes = 0;
886
887         if (ast_strlen_zero((char *) format1)) {
888                 return -1;
889         }
890
891         buf[bytes++] = ADSI_INPUT_FORMAT;
892         bytes++;
893         buf[bytes++] = ((dir & 1) << 7) | ((wrap & 1) << 6) | (num & 0x7);
894         bytes += ccopy(buf + bytes, (unsigned char *) format1, 20);
895         buf[bytes++] = 0xff;
896         if (!ast_strlen_zero(format2)) {
897                 bytes += ccopy(buf + bytes, (unsigned char *) format2, 20);
898         }
899         buf[1] = bytes - 2;
900         return bytes;
901 }
902
903 int AST_OPTIONAL_API_NAME(ast_adsi_set_keys)(unsigned char *buf, unsigned char *keys)
904 {
905         int bytes = 0, x;
906
907         /* Message type */
908         buf[bytes++] = ADSI_INIT_SOFTKEY_LINE;
909         /* Space for size */
910         bytes++;
911         /* Key definitions */
912         for (x = 0; x < 6; x++) {
913                 buf[bytes++] = (keys[x] & 0x3f) ? keys[x] : (keys[x] | 0x1);
914         }
915         buf[1] = bytes - 2;
916         return bytes;
917 }
918
919 int AST_OPTIONAL_API_NAME(ast_adsi_set_line)(unsigned char *buf, int page, int line)
920 {
921         int bytes = 0;
922
923         /* Sanity check line number */
924
925         if (page) {
926                 if (line > 4) return -1;
927         } else {
928                 if (line > 33) return -1;
929         }
930
931         if (line < 1) {
932                 return -1;
933         }
934         /* Parameter type */
935         buf[bytes++] = ADSI_LINE_CONTROL;
936
937         /* Reserve space for size */
938         bytes++;
939
940         /* Page and line */
941         buf[bytes++] = ((page & 0x1) << 7) | (line & 0x3f);
942
943         buf[1] = bytes - 2;
944         return bytes;
945 }
946
947 static int total = 0;
948 static int speeds = 0;
949
950 int AST_OPTIONAL_API_NAME(ast_adsi_channel_restore)(struct ast_channel *chan)
951 {
952         unsigned char dsp[256] = "", keyd[6] = "";
953         int bytes, x;
954
955         /* Start with initial display setup */
956         bytes = 0;
957         bytes += ast_adsi_set_line(dsp + bytes, ADSI_INFO_PAGE, 1);
958
959         /* Prepare key setup messages */
960
961         if (speeds) {
962                 for (x = 0; x < speeds; x++) {
963                         keyd[x] = ADSI_SPEED_DIAL + x;
964                 }
965                 bytes += ast_adsi_set_keys(dsp + bytes, keyd);
966         }
967         ast_adsi_transmit_message_full(chan, dsp, bytes, ADSI_MSG_DISPLAY, 0);
968         return 0;
969
970 }
971
972 int AST_OPTIONAL_API_NAME(ast_adsi_print)(struct ast_channel *chan, char **lines, int *alignments, int voice)
973 {
974         unsigned char buf[4096];
975         int bytes = 0, res, x;
976
977         for (x = 0; lines[x]; x++) {
978                 bytes += ast_adsi_display(buf + bytes, ADSI_INFO_PAGE, x+1, alignments[x], 0, lines[x], "");
979         }
980         bytes += ast_adsi_set_line(buf + bytes, ADSI_INFO_PAGE, 1);
981         if (voice) {
982                 bytes += ast_adsi_voice_mode(buf + bytes, 0);
983         }
984         res = ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
985         if (voice) {
986                 /* Ignore the resulting DTMF B announcing it's in voice mode */
987                 ast_waitfordigit(chan, 1000);
988         }
989         return res;
990 }
991
992 int AST_OPTIONAL_API_NAME(ast_adsi_load_session)(struct ast_channel *chan, unsigned char *app, int ver, int data)
993 {
994         unsigned char dsp[256] = "";
995         int bytes = 0, res;
996         char resp[2];
997
998         /* Connect to session */
999         bytes += ast_adsi_connect_session(dsp + bytes, app, ver);
1000
1001         if (data) {
1002                 bytes += ast_adsi_data_mode(dsp + bytes);
1003         }
1004
1005         /* Prepare key setup messages */
1006         if (ast_adsi_transmit_message_full(chan, dsp, bytes, ADSI_MSG_DISPLAY, 0)) {
1007                 return -1;
1008         }
1009         if (app) {
1010                 if ((res = ast_readstring(chan, resp, 1, 1200, 1200, "")) < 0) {
1011                         return -1;
1012                 }
1013                 if (res) {
1014                         ast_debug(1, "No response from CPE about version.  Assuming not there.\n");
1015                         return 0;
1016                 }
1017                 if (!strcmp(resp, "B")) {
1018                         ast_debug(1, "CPE has script '%s' version %d already loaded\n", app, ver);
1019                         return 1;
1020                 } else if (!strcmp(resp, "A")) {
1021                         ast_debug(1, "CPE hasn't script '%s' version %d already loaded\n", app, ver);
1022                 } else {
1023                         ast_log(LOG_WARNING, "Unexpected CPE response to script query: %s\n", resp);
1024                 }
1025         } else
1026                 return 1;
1027         return 0;
1028
1029 }
1030
1031 int AST_OPTIONAL_API_NAME(ast_adsi_unload_session)(struct ast_channel *chan)
1032 {
1033         unsigned char dsp[256] = "";
1034         int bytes = 0;
1035
1036         /* Connect to session */
1037         bytes += ast_adsi_disconnect_session(dsp + bytes);
1038         bytes += ast_adsi_voice_mode(dsp + bytes, 0);
1039
1040         /* Prepare key setup messages */
1041         if (ast_adsi_transmit_message_full(chan, dsp, bytes, ADSI_MSG_DISPLAY, 0)) {
1042                 return -1;
1043         }
1044
1045         return 0;
1046 }
1047
1048 static int str2align(const char *s)
1049 {
1050         if (!strncasecmp(s, "l", 1)) {
1051                 return ADSI_JUST_LEFT;
1052         } else if (!strncasecmp(s, "r", 1)) {
1053                 return ADSI_JUST_RIGHT;
1054         } else if (!strncasecmp(s, "i", 1)) {
1055                 return ADSI_JUST_IND;
1056         } else {
1057                 return ADSI_JUST_CENT;
1058         }
1059 }
1060
1061 static void init_state(void)
1062 {
1063         int x;
1064
1065         for (x = 0; x < ADSI_MAX_INTRO; x++) {
1066                 aligns[x] = ADSI_JUST_CENT;
1067         }
1068         ast_copy_string(intro[0], "Welcome to the", sizeof(intro[0]));
1069         ast_copy_string(intro[1], "Asterisk", sizeof(intro[1]));
1070         ast_copy_string(intro[2], "Open Source PBX", sizeof(intro[2]));
1071         total = 3;
1072         speeds = 0;
1073         for (x = 3; x < ADSI_MAX_INTRO; x++) {
1074                 intro[x][0] = '\0';
1075         }
1076         memset(speeddial, 0, sizeof(speeddial));
1077         alignment = ADSI_JUST_CENT;
1078 }
1079
1080 static void adsi_load(int reload)
1081 {
1082         int x = 0;
1083         struct ast_config *conf = NULL;
1084         struct ast_variable *v;
1085         struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
1086         char *name, *sname;
1087         init_state();
1088
1089         conf = ast_config_load("adsi.conf", config_flags);
1090         if (conf == CONFIG_STATUS_FILEMISSING || conf == CONFIG_STATUS_FILEUNCHANGED || conf == CONFIG_STATUS_FILEINVALID) {
1091                 return;
1092         }
1093         for (v = ast_variable_browse(conf, "intro"); v; v = v->next) {
1094                 if (!strcasecmp(v->name, "alignment")) {
1095                         alignment = str2align(v->value);
1096                 } else if (!strcasecmp(v->name, "greeting")) {
1097                         if (x < ADSI_MAX_INTRO) {
1098                                 aligns[x] = alignment;
1099                                 ast_copy_string(intro[x], v->value, sizeof(intro[x]));
1100                                 x++;
1101                         }
1102                 } else if (!strcasecmp(v->name, "maxretries")) {
1103                         if (atoi(v->value) > 0) {
1104                                 maxretries = atoi(v->value);
1105                         }
1106                 }
1107         }
1108         if (x) {
1109                 total = x;
1110         }
1111
1112         x = 0;
1113         for (v = ast_variable_browse(conf, "speeddial"); v; v = v->next) {
1114                 char buf[3 * SPEEDDIAL_MAX_LEN];
1115                 char *stringp = buf;
1116                 ast_copy_string(buf, v->value, sizeof(buf));
1117                 name = strsep(&stringp, ",");
1118                 sname = strsep(&stringp, ",");
1119                 if (!sname) {
1120                         sname = name;
1121                 }
1122                 if (x < ADSI_MAX_SPEED_DIAL) {
1123                         ast_copy_string(speeddial[x][0], v->name, sizeof(speeddial[x][0]));
1124                         ast_copy_string(speeddial[x][1], name, 18);
1125                         ast_copy_string(speeddial[x][2], sname, 7);
1126                         x++;
1127                 }
1128         }
1129         if (x) {
1130                 speeds = x;
1131         }
1132         ast_config_destroy(conf);
1133
1134         return;
1135 }
1136
1137 static int reload(void)
1138 {
1139         adsi_load(1);
1140         return 0;
1141 }
1142
1143 static int load_module(void)
1144 {
1145         adsi_load(0);
1146         return AST_MODULE_LOAD_SUCCESS;
1147 }
1148
1149 static int unload_module(void)
1150 {
1151         /* Can't unload this once we're loaded */
1152         return -1;
1153 }
1154
1155 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "ADSI Resource",
1156                 .load = load_module,
1157                 .unload = unload_module,
1158                 .reload = reload,
1159                 .load_pri = AST_MODPRI_APP_DEPEND,
1160                );