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