Version 0.1.11 from FTP
[asterisk/asterisk.git] / res / res_adsi.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * ADSI support 
5  * 
6  * Copyright (C) 2001, Linux Support Services, Inc.
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License.
12  *
13  * Includes code and algorithms from the Zapata library.
14  *
15  */
16
17 #include <time.h>
18 #include <string.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <math.h>
23 #include <asterisk/ulaw.h>
24 #include <asterisk/callerid.h>
25 #include <asterisk/logger.h>
26 #include <asterisk/fskmodem.h>
27 #include <asterisk/channel.h>
28 #include <asterisk/adsi.h>
29 #include <asterisk/module.h>
30 #include <asterisk/config.h>
31 #include <asterisk/file.h>
32
33 #define DEFAULT_ADSI_MAX_RETRIES 3
34
35 #define ADSI_MAX_INTRO 20
36 #define ADSI_MAX_SPEED_DIAL 6
37
38 #define ADSI_FLAG_DATAMODE      (1 << 8)
39
40 static int maxretries = DEFAULT_ADSI_MAX_RETRIES;
41
42 /* Asterisk ADSI button definitions */
43 #define ADSI_SPEED_DIAL         10      /* 10-15 are reserved for speed dial */
44
45 static char intro[ADSI_MAX_INTRO][20];
46 static int aligns[ADSI_MAX_INTRO];
47
48 static char speeddial[ADSI_MAX_SPEED_DIAL][3][20];
49
50 static int alignment = 0;
51
52 static int adsi_generate(unsigned char *buf, int msgtype, char *msg, int msglen, int msgnum, int last)
53 {
54         int sum;
55         int x;  
56         int bytes=0;
57         /* Initial carrier (imaginary) */
58         float cr = 1.0;
59         float ci = 0.0;
60         float scont = 0.0;
61
62         if (msglen > 255)
63                 msglen = 255;
64
65         /* If first message, Send 150ms of MARK's */
66         if (msgnum == 1) {
67                 for (x=0;x<150;x++)     /* was 150 */
68                         PUT_CLID_MARKMS;
69         }
70         /* Put message type */
71         PUT_CLID(msgtype);
72         sum = msgtype;
73
74         /* Put message length (plus one  for the message number) */
75         PUT_CLID(msglen + 1);
76         sum += msglen + 1;
77
78         /* Put message number */
79         PUT_CLID(msgnum);
80         sum += msgnum;
81
82         /* Put actual message */
83         for (x=0;x<msglen;x++) {
84                 PUT_CLID(msg[x]);
85                 sum += msg[x];
86         }
87
88         /* Put 2's compliment of sum */
89         PUT_CLID(256-(sum & 0xff));
90
91 #if 0
92         if (last) {
93                 /* Put trailing marks */
94                 for (x=0;x<50;x++)
95                         PUT_CLID_MARKMS;
96         }
97 #endif
98         return bytes;
99
100 }
101
102 #if 0
103 static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int len, int *remainder)
104 {
105         int res;
106         fd_set fds;
107         while(len) {
108                 FD_ZERO(&fds);
109                 FD_SET(chan->fds[0], &fds);
110                 select(chan->fds[0] + 1, NULL, &fds, NULL, NULL);
111                 res = write(chan->fds[0], buf, len);
112                 if (res < 1) {
113                         ast_log(LOG_WARNING, "Failed to write: %s\n", strerror(errno));
114                         return -1;
115                 }
116                 buf += res;
117                 len -= res;
118         }
119         return 0;
120 }
121
122 #else
123 static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int len, int *remainder)
124 {
125         /* Sends carefully on a full duplex channel by using reading for
126            timing */
127         struct ast_frame *inf, outf;
128         int amt;
129
130         /* Zero out our outgoing frame */
131         memset(&outf, 0, sizeof(outf));
132
133         if (remainder && *remainder) {
134                 amt = len;
135
136                 /* Send remainder if provided */
137                 if (amt > *remainder)
138                         amt = *remainder;
139                 else
140                         *remainder = *remainder - amt;
141                 outf.frametype = AST_FRAME_VOICE;
142                 outf.subclass = AST_FORMAT_ULAW;
143                 outf.data = buf;
144                 outf.datalen = amt;
145                 outf.timelen = amt * 8;
146                 if (ast_write(chan, &outf)) {
147                         ast_log(LOG_WARNING, "Failed to carefully write frame\n");
148                         return -1;
149                 }
150                 /* Update pointers and lengths */
151                 buf += amt;
152                 len -= amt;
153         }
154
155         while(len) {
156                 amt = len;
157                 /* If we don't get anything at all back in a second, forget
158                    about it */
159                 if (ast_waitfor(chan, 1000) < 1)
160                         return -1;
161                 inf = ast_read(chan);
162                 /* Detect hangup */
163                 if (!inf)
164                         return -1;
165                 if (inf->frametype == AST_FRAME_VOICE) {
166                         /* Read a voice frame */
167                         if (inf->subclass != AST_FORMAT_ULAW) {
168                                 ast_log(LOG_WARNING, "Channel not in ulaw?\n");
169                                 return -1;
170                         }
171                         /* Send no more than they sent us */
172                         if (amt > inf->datalen)
173                                 amt = inf->datalen;
174                         else if (remainder)
175                                 *remainder = inf->datalen - amt;
176                         outf.frametype = AST_FRAME_VOICE;
177                         outf.subclass = AST_FORMAT_ULAW;
178                         outf.data = buf;
179                         outf.datalen = amt;
180                         outf.timelen = amt * 8;
181                         if (ast_write(chan, &outf)) {
182                                 ast_log(LOG_WARNING, "Failed to carefully write frame\n");
183                                 return -1;
184                         }
185                         /* Update pointers and lengths */
186                         buf += amt;
187                         len -= amt;
188                 }
189                 ast_frfree(inf);
190         }
191         return 0;
192 }
193 #endif
194
195 static int __adsi_transmit_messages(struct ast_channel *chan, unsigned char **msg, int *msglen, int *msgtype)
196 {
197         /* msglen must be no more than 256 bits, each */
198         unsigned char buf[24000 * 5];
199         int pos = 0, res;
200         int x;
201         int start=0;
202         int retries = 0;
203
204         char ack[3];
205
206         /* Wait up to 500 ms for initial ACK */
207         int waittime;
208         struct ast_frame *f;
209         int rem = 0;
210         int def;
211
212         if (chan->adsicpe == AST_ADSI_UNAVAILABLE) {
213                 /* Don't bother if we know they don't support ADSI */
214                 errno = ENOSYS;
215                 return -1;
216         }
217
218         while(retries < maxretries) {
219                 if (!(chan->adsicpe & ADSI_FLAG_DATAMODE)) {
220                         /* Generate CAS (no SAS) */
221                         ast_gen_cas(buf, 0, 680);
222                 
223                         /* Send CAS */
224                         if (adsi_careful_send(chan, buf, 680, NULL)) {
225                                 ast_log(LOG_WARNING, "Unable to send CAS\n");
226                         }
227                         /* Wait For DTMF result */
228                         waittime = 500;
229                         for(;;) {
230                                 if (((res = ast_waitfor(chan, waittime)) < 1)) {
231                                         /* Didn't get back DTMF A in time */
232                                         ast_log(LOG_DEBUG, "No ADSI CPE detected (%d)\n", res);
233                                         if (!chan->adsicpe)
234                                                 chan->adsicpe = AST_ADSI_UNAVAILABLE;
235                                         errno = ENOSYS;
236                                         return -1;
237                                 }
238                                 waittime = res;
239                                 f = ast_read(chan);
240                                 if (!f) {
241                                         ast_log(LOG_DEBUG, "Hangup in ADSI\n");
242                                         return -1;
243                                 }
244                                 if (f->frametype == AST_FRAME_DTMF) {
245                                         if (f->subclass == 'A') {
246                                                 /* Okay, this is an ADSI CPE.  Note this for future reference, too */
247                                                 if (!chan->adsicpe)
248                                                         chan->adsicpe = AST_ADSI_AVAILABLE;
249                                                 break;
250                                         } else {
251                                                 if (f->subclass == 'D')  {
252                                                         ast_log(LOG_DEBUG, "Off-hook capable CPE only, not ADSI\n");
253                                                 } else
254                                                         ast_log(LOG_WARNING, "Unknown ADSI response '%c'\n", f->subclass);
255                                                 if (!chan->adsicpe)
256                                                         chan->adsicpe = AST_ADSI_UNAVAILABLE;
257                                                 errno = ENOSYS;
258                                                 return -1;
259                                         }
260                                 }
261                                 ast_frfree(f);
262                         }
263
264                         ast_log(LOG_DEBUG, "ADSI Compatible CPE Detected\n");
265                 } else
266                         ast_log(LOG_DEBUG, "Already in data mode\n");
267
268                 x = 0;
269                 pos = 0;
270 #if 1
271                 def= ast_channel_defer_dtmf(chan);
272 #endif
273                 while((x < 6) && msg[x]) {
274                         res = adsi_generate(buf + pos, msgtype[x], msg[x], msglen[x], x+1 - start, (x == 5) || !msg[x+1]);
275                         if (res < 0) {
276                                 ast_log(LOG_WARNING, "Failed to generate ADSI message %d on channel %s\n", x + 1, chan->name);
277                                 return -1;
278                         }
279                         ast_log(LOG_DEBUG, "Message %d, of %d input bytes, %d output bytes\n", 
280                                         x + 1, msglen[x], res);
281                         pos += res; 
282                         x++;
283                 }
284
285
286                 rem = 0;
287                 res = adsi_careful_send(chan, buf, pos, &rem); 
288                 if (!def)
289                         ast_channel_undefer_dtmf(chan);
290                 if (res)
291                         return -1;
292
293                 ast_log(LOG_DEBUG, "Sent total spill of %d bytes\n", pos);
294
295                 memset(ack, 0, sizeof(ack));
296                 /* Get real result */
297                 res = ast_readstring(chan, ack, 2, 1000, 1000, "");
298                 /* Check for hangup */
299                 if (res < 0)
300                         return -1;
301                 if (ack[0] == 'D') {
302                         ast_log(LOG_DEBUG, "Acked up to message %d\n", atoi(ack + 1));
303                         start += atoi(ack + 1);
304                         if (start >= x)
305                                 break;
306                         else {
307                                 retries++;
308                                 ast_log(LOG_DEBUG, "Retransmitting (%d), from %d\n", start + 1);
309                         }
310                 } else {
311                         retries++;
312                         ast_log(LOG_WARNING, "Unexpected response to ack: %s (retry %d)\n", ack, retries);
313                 } 
314         }
315         if (retries >= maxretries) {
316                 ast_log(LOG_WARNING, "Maximum ADSI Retries (%d) exceeded\n", maxretries);
317                 errno = ETIMEDOUT;
318                 return -1;
319         }
320         return 0;
321         
322 }
323
324 int adsi_begin_download(struct ast_channel *chan, char *service, char *fdn, char *sec, int version)
325 {
326         int bytes;
327         unsigned char buf[256];
328         char ack[2];
329         bytes = 0;
330         /* Setup the resident soft key stuff, a piece at a time */
331         /* Upload what scripts we can for voicemail ahead of time */
332         bytes += adsi_download_connect(buf + bytes, service, fdn, sec, version);
333         if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD))
334                 return -1;
335         if (ast_readstring(chan, ack, 1, 10000, 10000, ""))
336                 return -1;
337         if (ack[0] == 'B')
338                 return 0;
339         ast_log(LOG_DEBUG, "Download was denied by CPE\n");
340         return -1;
341 }
342
343 int adsi_end_download(struct ast_channel *chan)
344 {
345         int bytes;
346         unsigned char buf[256];
347         bytes = 0;
348         /* Setup the resident soft key stuff, a piece at a time */
349         /* Upload what scripts we can for voicemail ahead of time */
350         bytes += adsi_download_disconnect(buf + bytes);
351         if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD))
352                 return -1;
353         return 0;
354 }
355
356 int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype)
357 {
358         unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL };
359         int msglens[5];
360         int msgtypes[5];
361         int newdatamode;
362         int res;
363         int x;
364         int writeformat, readformat;
365
366         writeformat = chan->writeformat;
367         readformat = chan->readformat;
368
369         newdatamode = chan->adsicpe & ADSI_FLAG_DATAMODE;
370
371         for (x=0;x<msglen;x+=(msg[x+1]+2)) {
372                 if (msg[x] == ADSI_SWITCH_TO_DATA) 
373                         newdatamode = ADSI_FLAG_DATAMODE;
374                 
375                 if (msg[x] == ADSI_SWITCH_TO_VOICE)
376                         newdatamode = 0;
377         }
378         msgs[0] = msg;
379
380         msglens[0] = msglen;
381         msgtypes[0] = msgtype;
382
383         if (msglen > 253) {
384                 ast_log(LOG_WARNING, "Can't send ADSI message of %d bytes, too large\n", msglen);
385                 return -1;
386         }
387
388         ast_stopstream(chan);
389
390         if (ast_set_write_format(chan, AST_FORMAT_ULAW)) {
391                 ast_log(LOG_WARNING, "Unable to set write format to ULAW\n");
392                 return -1;
393         }
394
395         if (ast_set_read_format(chan, AST_FORMAT_ULAW)) {
396                 ast_log(LOG_WARNING, "Unable to set read format to ULAW\n");
397                 if (writeformat) {
398                         if (ast_set_write_format(chan, writeformat)) 
399                                 ast_log(LOG_WARNING, "Unable to restore write format to %d\n", writeformat);
400                 }
401                 return -1;
402         }
403         res = __adsi_transmit_messages(chan, msgs, msglens, msgtypes);
404         if (!res)
405                 chan->adsicpe = (chan->adsicpe & ~ADSI_FLAG_DATAMODE) | newdatamode;
406
407         if (writeformat)
408                 ast_set_write_format(chan, writeformat);
409         if (readformat)
410                 ast_set_read_format(chan, readformat);
411
412         return res;
413 }
414
415 static inline int ccopy(unsigned char *dst, unsigned char *src, int max)
416 {
417         int x=0;
418         /* Carefully copy the requested data */
419         while ((x < max) && src[x] && (src[x] != 0xff)) {
420                 dst[x] = src[x];
421                 x++;
422         }
423         return x;
424 }
425
426 int adsi_load_soft_key(unsigned char *buf, int key, unsigned char *llabel, unsigned char *slabel, unsigned char *ret, int data)
427 {
428         int bytes=0;
429
430         /* Abort if invalid key specified */
431         if ((key < 2) || (key > 33))
432                 return -1;
433         buf[bytes++] = ADSI_LOAD_SOFTKEY;
434         /* Reserve for length */
435         bytes++;
436         /* Which key */
437         buf[bytes++] = key;
438
439         /* Carefully copy long label */
440         bytes += ccopy(buf + bytes, llabel, 18);
441
442         /* Place delimiter */
443         buf[bytes++] = 0xff;
444
445         /* Short label */
446         bytes += ccopy(buf + bytes, slabel, 7);
447
448
449         /* If specified, copy return string */
450         if (ret) {
451                 /* Place delimiter */
452                 buf[bytes++] = 0xff;
453                 if (data)
454                         buf[bytes++] = ADSI_SWITCH_TO_DATA2;
455                 /* Carefully copy return string */
456                 bytes += ccopy(buf + bytes, ret, 20);
457
458         }
459         /* Replace parameter length */
460         buf[1] = bytes - 2;
461         return bytes;
462         
463 }
464
465 int adsi_connect_session(unsigned char *buf, unsigned char *fdn, int ver)
466 {
467         int bytes=0;
468         int x;
469
470         /* Message type */
471         buf[bytes++] = ADSI_CONNECT_SESSION;
472
473         /* Reserve space for length */
474         bytes++;
475
476         if (fdn) {
477                 for (x=0;x<4;x++)
478                         buf[bytes++] = fdn[x];
479                 if (ver > -1)
480                         buf[bytes++] = ver & 0xff;
481         }
482
483         buf[1] = bytes - 2;
484         return bytes;
485
486 }
487
488 int adsi_download_connect(unsigned char *buf, unsigned char *service,  unsigned char *fdn, unsigned char *sec, int ver)
489 {
490         int bytes=0;
491         int x;
492
493         /* Message type */
494         buf[bytes++] = ADSI_DOWNLOAD_CONNECT;
495
496         /* Reserve space for length */
497         bytes++;
498
499         /* Primary column */
500         bytes+= ccopy(buf + bytes, service, 18);
501
502         /* Delimiter */
503         buf[bytes++] = 0xff;
504         
505         for (x=0;x<4;x++)
506                 buf[bytes++] = fdn[x];
507         for (x=0;x<4;x++)
508                 buf[bytes++] = sec[x];
509         if (ver > -1)
510                 buf[bytes++] = ver & 0xff;
511
512         buf[1] = bytes - 2;
513         return bytes;
514
515 }
516
517 int adsi_disconnect_session(unsigned char *buf)
518 {
519         int bytes=0;
520
521         /* Message type */
522         buf[bytes++] = ADSI_DISC_SESSION;
523
524         /* Reserve space for length */
525         bytes++;
526
527         buf[1] = bytes - 2;
528         return bytes;
529
530 }
531
532 int adsi_data_mode(unsigned char *buf)
533 {
534         int bytes=0;
535
536         /* Message type */
537         buf[bytes++] = ADSI_SWITCH_TO_DATA;
538
539         /* Reserve space for length */
540         bytes++;
541
542         buf[1] = bytes - 2;
543         return bytes;
544
545 }
546
547 int adsi_voice_mode(unsigned char *buf, int when)
548 {
549         int bytes=0;
550
551         /* Message type */
552         buf[bytes++] = ADSI_SWITCH_TO_VOICE;
553
554         /* Reserve space for length */
555         bytes++;
556
557         buf[bytes++] = when & 0x7f;
558
559         buf[1] = bytes - 2;
560         return bytes;
561
562 }
563
564 int adsi_available(struct ast_channel *chan)
565 {
566         int cpe = chan->adsicpe & 0xff;
567         if ((cpe == AST_ADSI_AVAILABLE) ||
568             (cpe == AST_ADSI_UNKNOWN))
569                 return 1;
570         return 0;
571 }
572
573 int adsi_download_disconnect(unsigned char *buf)
574 {
575         int bytes=0;
576
577         /* Message type */
578         buf[bytes++] = ADSI_DOWNLOAD_DISC;
579
580         /* Reserve space for length */
581         bytes++;
582
583         buf[1] = bytes - 2;
584         return bytes;
585
586 }
587
588 int adsi_display(unsigned char *buf, int page, int line, int just, int wrap, 
589                  unsigned char *col1, unsigned char *col2)
590 {
591         int bytes=0;
592
593         /* Sanity check line number */
594
595         if (page) {
596                 if (line > 4) return -1;
597         } else {
598                 if (line > 33) return -1;
599         }
600
601         if (line < 1)
602                 return -1;
603         /* Parameter type */
604         buf[bytes++] = ADSI_LOAD_VIRTUAL_DISP;
605         
606         /* Reserve space for size */
607         bytes++;
608
609         /* Page and wrap indicator */
610         buf[bytes++] = ((page & 0x1) << 7) | ((wrap & 0x1) << 6) | (line & 0x3f);
611
612         /* Justification */
613         buf[bytes++] = (just & 0x3) << 5;
614
615         /* Omit highlight mode definition */
616         buf[bytes++] = 0xff;
617
618         /* Primary column */
619         bytes+= ccopy(buf + bytes, col1, 20);
620
621         /* Delimiter */
622         buf[bytes++] = 0xff;
623         
624         /* Secondary column */
625         bytes += ccopy(buf + bytes, col2, 20);
626
627         /* Update length */
628         buf[1] = bytes - 2;
629         
630         return bytes;
631
632 }
633
634 int adsi_input_control(unsigned char *buf, int page, int line, int display, int format, int just)
635 {
636         int bytes=0;
637
638         if (page) {
639                 if (line > 4) return -1;
640         } else {
641                 if (line > 33) return -1;
642         }
643
644         if (line < 1)
645                 return -1;
646
647         buf[bytes++] = ADSI_INPUT_CONTROL;
648         bytes++;
649         buf[bytes++] = ((page & 1) << 7) | (line & 0x3f);
650         buf[bytes++] = ((display & 1) << 7) | ((just & 0x3) << 4) | (format & 0x7);
651         
652         buf[1] = bytes - 2;
653         return bytes;
654
655 }
656
657 int adsi_input_format(unsigned char *buf, int num, int dir, int wrap, unsigned char *format1, unsigned char *format2)
658 {
659         int bytes = 0;
660
661         if (!strlen(format1))
662                 return -1;
663
664         buf[bytes++] = ADSI_INPUT_FORMAT;
665         bytes++;
666         buf[bytes++] = ((dir & 1) << 7) | ((wrap & 1) << 6) | (num & 0x7);
667         bytes += ccopy(buf + bytes, format1, 20);
668         buf[bytes++] = 0xff;
669         if (format2 && strlen(format2)) {
670                 bytes += ccopy(buf + bytes, format2, 20);
671         }
672         buf[1] = bytes - 2;
673         return bytes;
674 }
675
676 int adsi_set_keys(unsigned char *buf, unsigned char *keys)
677 {
678         int bytes=0;
679         int x;
680         /* Message type */
681         buf[bytes++] = ADSI_INIT_SOFTKEY_LINE;
682         /* Space for size */
683         bytes++;
684         /* Key definitions */
685         for (x=0;x<6;x++)
686                 buf[bytes++] = (keys[x] & 0x3f) ? keys[x] : (keys[x] | 0x1);
687         buf[1] = bytes - 2;
688         return bytes;
689 }
690
691 int adsi_set_line(unsigned char *buf, int page, int line)
692 {
693         int bytes=0;
694
695         /* Sanity check line number */
696
697         if (page) {
698                 if (line > 4) return -1;
699         } else {
700                 if (line > 33) return -1;
701         }
702
703         if (line < 1)
704                 return -1;
705         /* Parameter type */
706         buf[bytes++] = ADSI_LINE_CONTROL;
707         
708         /* Reserve space for size */
709         bytes++;
710
711         /* Page and line */
712         buf[bytes++] = ((page & 0x1) << 7) | (line & 0x3f);
713
714         buf[1] = bytes - 2;
715         return bytes;
716
717 };
718
719 static int total = 0;
720 static int speeds = 0;
721
722 #if 0
723 int adsi_channel_init(struct ast_channel *chan)
724 {
725         char dsp[256];
726         char keys[256];
727         int bytes;
728         int x;
729         unsigned char *msgs[3];
730         unsigned char keyd[6];
731         int lens[3];
732         int types[3];
733         memset(dsp, 0, sizeof(dsp));
734         memset(keys, 0, sizeof(keys));
735         memset(msgs, 0, sizeof(msgs));
736
737         /* Start with initial display setup */
738         bytes = 0;
739         bytes += adsi_connect_session(dsp, NULL, -1);
740         for (x=0;x<total;x++) {
741                 bytes += adsi_display(dsp + bytes, ADSI_INFO_PAGE, x + 1, aligns[x], 0,
742                         strlen(intro[x]) ? intro[x] : " ", "");
743         }
744         bytes += adsi_set_line(dsp + bytes, ADSI_INFO_PAGE, 1);
745         msgs[0] = dsp;
746         lens[0] = bytes;
747         types[0] = ADSI_MSG_DISPLAY;
748
749         /* Prepare key setup messages */
750
751         if (speeds) {
752                 bytes = 0;
753                 memset(keyd, 0, sizeof(keyd));
754                 for (x=0;x<speeds;x++) {
755                         bytes += adsi_load_soft_key(keys + bytes, ADSI_SPEED_DIAL + x,
756                                         speeddial[x][1], speeddial[x][2], speeddial[x][0]);
757                         keyd[x] = ADSI_SPEED_DIAL + x;
758                 }
759                 bytes += adsi_set_keys(keys + bytes, keyd);
760                 msgs[1] = keys;
761                 lens[1] = bytes;
762                 types[1] = ADSI_MSG_DISPLAY;
763         }
764         adsi_transmit_messages(chan, msgs, lens, types);
765         return 0;
766 }
767 #else
768 int adsi_channel_init(struct ast_channel *chan)
769 {
770         char dsp[256];
771         int bytes;
772         int x;
773         unsigned char keyd[6];
774
775         memset(dsp, 0, sizeof(dsp));
776
777         /* Start with initial display setup */
778         bytes = 0;
779         bytes += adsi_connect_session(dsp, NULL, -1);
780         for (x=0;x<total;x++) {
781                 bytes += adsi_display(dsp + bytes, ADSI_INFO_PAGE, x + 1, aligns[x], 0,
782                         strlen(intro[x]) ? intro[x] : " ", "");
783         }
784         bytes += adsi_set_line(dsp + bytes, ADSI_INFO_PAGE, 1);
785
786         /* Prepare key setup messages */
787
788         if (speeds) {
789                 memset(keyd, 0, sizeof(keyd));
790                 for (x=0;x<speeds;x++) {
791                         bytes += adsi_load_soft_key(dsp + bytes, ADSI_SPEED_DIAL + x,
792                                         speeddial[x][1], speeddial[x][2], speeddial[x][0], 0);
793                         keyd[x] = ADSI_SPEED_DIAL + x;
794                 }
795                 bytes += adsi_set_keys(dsp + bytes, keyd);
796         }
797         adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY);
798         return 0;
799 }
800 #endif
801
802 int adsi_channel_restore(struct ast_channel *chan)
803 {
804         char dsp[256];
805         int bytes;
806         int x;
807         unsigned char keyd[6];
808
809         memset(dsp, 0, sizeof(dsp));
810
811         /* Start with initial display setup */
812         bytes = 0;
813         bytes += adsi_set_line(dsp + bytes, ADSI_INFO_PAGE, 1);
814
815         /* Prepare key setup messages */
816
817         if (speeds) {
818                 memset(keyd, 0, sizeof(keyd));
819                 for (x=0;x<speeds;x++) {
820                         keyd[x] = ADSI_SPEED_DIAL + x;
821                 }
822                 bytes += adsi_set_keys(dsp + bytes, keyd);
823         }
824         adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY);
825         return 0;
826
827 }
828
829 int adsi_load_session(struct ast_channel *chan, unsigned char *app, int ver, int data)
830 {
831         char dsp[256];
832         int bytes;
833         int res;
834         char resp[2];
835
836         memset(dsp, 0, sizeof(dsp));
837
838         /* Connect to session */
839         bytes = 0;
840         bytes += adsi_connect_session(dsp + bytes, app,ver);
841
842         if (data)
843                 bytes += adsi_data_mode(dsp + bytes);
844
845         /* Prepare key setup messages */
846         if (adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY))
847                 return -1;
848         res = ast_readstring(chan, resp, 1, 1200, 1200, "");
849         if (res < 0)
850                 return -1;
851         if (res) {
852                 ast_log(LOG_DEBUG, "No response from CPE about version.  Assuming not there.\n");
853                 return 0;
854         }
855         if (!strcmp(resp, "B")) {
856                 ast_log(LOG_DEBUG, "CPE has script '%s' version %d already loaded\n", app, ver);
857                 return 1;
858         } else if (!strcmp(resp, "A")) {
859                 ast_log(LOG_DEBUG, "CPE hasn't script '%s' version %d already loaded\n", app, ver);
860         } else {
861                 ast_log(LOG_WARNING, "Unexpected CPE response to script query: %s\n", resp);
862         }
863         return 0;
864
865 }
866
867 int adsi_unload_session(struct ast_channel *chan)
868 {
869         char dsp[256];
870         int bytes;
871
872         memset(dsp, 0, sizeof(dsp));
873
874         /* Connect to session */
875         bytes = 0;
876         bytes += adsi_disconnect_session(dsp + bytes);
877         bytes += adsi_voice_mode(dsp + bytes, 0);
878
879         /* Prepare key setup messages */
880         if (adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY))
881                 return -1;
882         return 0;
883 }
884
885 static int str2align(char *s)
886 {
887         if (!strncasecmp(s, "l", 1))
888                 return ADSI_JUST_LEFT;
889         else if (!strncasecmp(s, "r", 1))
890                 return ADSI_JUST_RIGHT;
891         else if (!strncasecmp(s, "i", 1))
892                 return ADSI_JUST_IND;
893         else
894                 return ADSI_JUST_CENT;
895 }
896
897 static void init_state(void)
898 {
899         int x;
900
901         for (x=0;x<ADSI_MAX_INTRO;x++)
902                 aligns[x] = ADSI_JUST_CENT;
903         strcpy(intro[0], "Welcome to the");
904         strcpy(intro[1], "Asterisk");
905         strcpy(intro[2], "Open Source PBX");
906         total = 3;
907         speeds = 0;
908         for (x=3;x<ADSI_MAX_INTRO;x++)
909                 strcpy(intro[x], "");
910         memset(speeddial, 0, sizeof(speeddial));
911         alignment = ADSI_JUST_CENT;
912 }
913
914 static void adsi_load(void)
915 {
916         int x;
917         struct ast_config *conf;
918         struct ast_variable *v;
919         char *name, *sname;
920         init_state();
921         conf = ast_load("adsi.conf");
922         if (conf) {
923                 x=0;
924                 v = ast_variable_browse(conf, "intro");
925                 while(v) {
926                         if (!strcasecmp(v->name, "alignment"))
927                                 alignment = str2align(v->value);
928                         else if (!strcasecmp(v->name, "greeting")) {
929                                 if (x < ADSI_MAX_INTRO) {
930                                         aligns[x] = alignment;
931                                         strncpy(intro[x], v->value, 20);
932                                         x++;
933                                 }
934                         } else if (!strcasecmp(v->name, "maxretries")) {
935                                 if (atoi(v->value) > 0)
936                                         maxretries = atoi(v->value);
937                         }
938                         v = v->next;
939                 }
940                 v = ast_variable_browse(conf, "speeddial");
941                 if (x)
942                         total = x;
943                 x = 0;
944                 while(v) {
945                         name = strtok(v->value, ",");
946                         sname = strtok(NULL, ",");
947                         if (!sname) 
948                                 sname = name;
949                         if (x < ADSI_MAX_SPEED_DIAL) {
950                                 /* Up to 20 digits */
951                                 strncpy(speeddial[x][0], v->name, 20);
952                                 strncpy(speeddial[x][1], name, 18);
953                                 strncpy(speeddial[x][2], sname, 7);
954                                 x++;
955                         }
956                         v = v->next;
957                                 
958                 }
959                 if (x)
960                         speeds = x;
961                 ast_destroy(conf);
962         }
963 }
964
965 int reload(void)
966 {
967         adsi_load();
968         return 0;
969 }
970
971 int load_module(void)
972 {
973         adsi_load();
974         return 0;
975 }
976
977 int unload_module(void)
978 {
979         /* Can't unload this once we're loaded */
980         return -1;
981 }
982
983 char *description(void)
984 {
985         return "Call Parking Resource";
986 }
987
988 int usecount(void)
989 {
990         /* We should never be unloaded */
991         return 1;
992 }
993
994 char *key()
995 {
996         return ASTERISK_GPL_KEY;
997 }