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