Version 0.1.10 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
211         if (chan->adsicpe == AST_ADSI_UNAVAILABLE) {
212                 /* Don't bother if we know they don't support ADSI */
213                 errno = ENOSYS;
214                 return -1;
215         }
216
217         while(retries < maxretries) {
218                 if (!(chan->adsicpe & ADSI_FLAG_DATAMODE)) {
219                         /* Generate CAS (no SAS) */
220                         ast_gen_cas(buf, 0, 680);
221                 
222                         /* Send CAS */
223                         if (adsi_careful_send(chan, buf, 680, NULL)) {
224                                 ast_log(LOG_WARNING, "Unable to send CAS\n");
225                         }
226                         /* Wait For DTMF result */
227                         waittime = 500;
228                         for(;;) {
229                                 if (((res = ast_waitfor(chan, waittime)) < 1)) {
230                                         /* Didn't get back DTMF A in time */
231                                         ast_log(LOG_DEBUG, "No ADSI CPE detected (%d)\n", res);
232                                         if (!chan->adsicpe)
233                                                 chan->adsicpe = AST_ADSI_UNAVAILABLE;
234                                         errno = ENOSYS;
235                                         return -1;
236                                 }
237                                 waittime = res;
238                                 f = ast_read(chan);
239                                 if (!f) {
240                                         ast_log(LOG_DEBUG, "Hangup in ADSI\n");
241                                         return -1;
242                                 }
243                                 if (f->frametype == AST_FRAME_DTMF) {
244                                         if (f->subclass == 'A') {
245                                                 /* Okay, this is an ADSI CPE.  Note this for future reference, too */
246                                                 if (!chan->adsicpe)
247                                                         chan->adsicpe = AST_ADSI_AVAILABLE;
248                                                 break;
249                                         } else {
250                                                 if (f->subclass == 'D')  {
251                                                         ast_log(LOG_DEBUG, "Off-hook capable CPE only, not ADSI\n");
252                                                 } else
253                                                         ast_log(LOG_WARNING, "Unknown ADSI response '%c'\n", f->subclass);
254                                                 if (!chan->adsicpe)
255                                                         chan->adsicpe = AST_ADSI_UNAVAILABLE;
256                                                 errno = ENOSYS;
257                                                 return -1;
258                                         }
259                                 }
260                                 ast_frfree(f);
261                         }
262
263                         ast_log(LOG_DEBUG, "ADSI Compatible CPE Detected\n");
264                 } else
265                         ast_log(LOG_DEBUG, "Already in data mode\n");
266
267                 x = 0;
268                 pos = 0;
269 #if 0
270                 def= ast_channel_defer_dtmf(chan);
271 #endif
272                 while((x < 6) && msg[x]) {
273                         res = adsi_generate(buf + pos, msgtype[x], msg[x], msglen[x], x+1 - start, (x == 5) || !msg[x+1]);
274                         if (res < 0) {
275                                 ast_log(LOG_WARNING, "Failed to generate ADSI message %d on channel %s\n", x + 1, chan->name);
276                                 return -1;
277                         }
278                         ast_log(LOG_DEBUG, "Message %d, of %d input bytes, %d output bytes\n", 
279                                         x + 1, msglen[x], res);
280                         pos += res; 
281                         x++;
282                 }
283
284
285                 rem = 0;
286                 if (adsi_careful_send(chan, buf, pos, &rem))
287                         return -1;
288
289                 ast_log(LOG_DEBUG, "Sent total spill of %d bytes\n", pos);
290
291                 memset(ack, 0, sizeof(ack));
292                 /* Get real result */
293                 res = ast_readstring(chan, ack, 3, 1000, 1000, "");
294                 /* Check for hangup */
295                 if (res < 0)
296                         return -1;
297                 if (ack[0] == 'D') {
298                         ast_log(LOG_DEBUG, "Acked up to message %d\n", atoi(ack + 1));
299                         start += atoi(ack + 1);
300                         if (start >= x)
301                                 break;
302                         else {
303                                 retries++;
304                                 ast_log(LOG_DEBUG, "Retransmitting (%d), from %d\n", start + 1);
305                         }
306                 } else {
307                         retries++;
308                         ast_log(LOG_WARNING, "Unexpected response to ack: %s (retry %d)\n", ack, retries);
309                 } 
310         }
311         if (retries >= maxretries) {
312                 ast_log(LOG_WARNING, "Maximum ADSI Retries (%d) exceeded\n", maxretries);
313                 errno = ETIMEDOUT;
314                 return -1;
315         }
316         return 0;
317         
318 }
319
320 int adsi_begin_download(struct ast_channel *chan, char *service, char *fdn, char *sec, int version)
321 {
322         int bytes;
323         unsigned char buf[256];
324         char ack[2];
325         bytes = 0;
326         /* Setup the resident soft key stuff, a piece at a time */
327         /* Upload what scripts we can for voicemail ahead of time */
328         bytes += adsi_download_connect(buf + bytes, service, fdn, sec, version);
329         if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD))
330                 return -1;
331         if (ast_readstring(chan, ack, 1, 10000, 10000, ""))
332                 return -1;
333         if (ack[0] == 'B')
334                 return 0;
335         ast_log(LOG_DEBUG, "Download was denied by CPE\n");
336         return -1;
337 }
338
339 int adsi_end_download(struct ast_channel *chan)
340 {
341         int bytes;
342         unsigned char buf[256];
343         bytes = 0;
344         /* Setup the resident soft key stuff, a piece at a time */
345         /* Upload what scripts we can for voicemail ahead of time */
346         bytes += adsi_download_disconnect(buf + bytes);
347         if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD))
348                 return -1;
349         return 0;
350 }
351
352 int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype)
353 {
354         unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL };
355         int msglens[5];
356         int msgtypes[5];
357         int newdatamode;
358         int res;
359         int x;
360         int writeformat, readformat;
361
362         writeformat = chan->writeformat;
363         readformat = chan->readformat;
364
365         newdatamode = chan->adsicpe & ADSI_FLAG_DATAMODE;
366
367         for (x=0;x<msglen;x+=(msg[x+1]+2)) {
368                 if (msg[x] == ADSI_SWITCH_TO_DATA) 
369                         newdatamode = ADSI_FLAG_DATAMODE;
370                 
371                 if (msg[x] == ADSI_SWITCH_TO_VOICE)
372                         newdatamode = 0;
373         }
374         msgs[0] = msg;
375
376         msglens[0] = msglen;
377         msgtypes[0] = msgtype;
378
379         if (msglen > 253) {
380                 ast_log(LOG_WARNING, "Can't send ADSI message of %d bytes, too large\n", msglen);
381                 return -1;
382         }
383
384         ast_stopstream(chan);
385
386         if (ast_set_write_format(chan, AST_FORMAT_ULAW)) {
387                 ast_log(LOG_WARNING, "Unable to set write format to ULAW\n");
388                 return -1;
389         }
390
391         if (ast_set_read_format(chan, AST_FORMAT_ULAW)) {
392                 ast_log(LOG_WARNING, "Unable to set read format to ULAW\n");
393                 if (writeformat) {
394                         if (ast_set_write_format(chan, writeformat)) 
395                                 ast_log(LOG_WARNING, "Unable to restore write format to %d\n", writeformat);
396                 }
397                 return -1;
398         }
399         res = __adsi_transmit_messages(chan, msgs, msglens, msgtypes);
400         if (!res)
401                 chan->adsicpe = (chan->adsicpe & ~ADSI_FLAG_DATAMODE) | newdatamode;
402
403         if (writeformat)
404                 ast_set_write_format(chan, writeformat);
405         if (readformat)
406                 ast_set_read_format(chan, readformat);
407
408         return res;
409 }
410
411 static inline int ccopy(unsigned char *dst, unsigned char *src, int max)
412 {
413         int x=0;
414         /* Carefully copy the requested data */
415         while ((x < max) && src[x] && (src[x] != 0xff)) {
416                 dst[x] = src[x];
417                 x++;
418         }
419         return x;
420 }
421
422 int adsi_load_soft_key(unsigned char *buf, int key, unsigned char *llabel, unsigned char *slabel, unsigned char *ret, int data)
423 {
424         int bytes=0;
425
426         /* Abort if invalid key specified */
427         if ((key < 2) || (key > 33))
428                 return -1;
429         buf[bytes++] = ADSI_LOAD_SOFTKEY;
430         /* Reserve for length */
431         bytes++;
432         /* Which key */
433         buf[bytes++] = key;
434
435         /* Carefully copy long label */
436         bytes += ccopy(buf + bytes, llabel, 18);
437
438         /* Place delimiter */
439         buf[bytes++] = 0xff;
440
441         /* Short label */
442         bytes += ccopy(buf + bytes, slabel, 7);
443
444
445         /* If specified, copy return string */
446         if (ret) {
447                 /* Place delimiter */
448                 buf[bytes++] = 0xff;
449                 if (data)
450                         buf[bytes++] = ADSI_SWITCH_TO_DATA2;
451                 /* Carefully copy return string */
452                 bytes += ccopy(buf + bytes, ret, 20);
453
454         }
455         /* Replace parameter length */
456         buf[1] = bytes - 2;
457         return bytes;
458         
459 }
460
461 int adsi_connect_session(unsigned char *buf, unsigned char *fdn, int ver)
462 {
463         int bytes=0;
464         int x;
465
466         /* Message type */
467         buf[bytes++] = ADSI_CONNECT_SESSION;
468
469         /* Reserve space for length */
470         bytes++;
471
472         if (fdn) {
473                 for (x=0;x<4;x++)
474                         buf[bytes++] = fdn[x];
475                 if (ver > -1)
476                         buf[bytes++] = ver & 0xff;
477         }
478
479         buf[1] = bytes - 2;
480         return bytes;
481
482 }
483
484 int adsi_download_connect(unsigned char *buf, unsigned char *service,  unsigned char *fdn, unsigned char *sec, int ver)
485 {
486         int bytes=0;
487         int x;
488
489         /* Message type */
490         buf[bytes++] = ADSI_DOWNLOAD_CONNECT;
491
492         /* Reserve space for length */
493         bytes++;
494
495         /* Primary column */
496         bytes+= ccopy(buf + bytes, service, 18);
497
498         /* Delimiter */
499         buf[bytes++] = 0xff;
500         
501         for (x=0;x<4;x++)
502                 buf[bytes++] = fdn[x];
503         for (x=0;x<4;x++)
504                 buf[bytes++] = sec[x];
505         if (ver > -1)
506                 buf[bytes++] = ver & 0xff;
507
508         buf[1] = bytes - 2;
509         return bytes;
510
511 }
512
513 int adsi_disconnect_session(unsigned char *buf)
514 {
515         int bytes=0;
516
517         /* Message type */
518         buf[bytes++] = ADSI_DISC_SESSION;
519
520         /* Reserve space for length */
521         bytes++;
522
523         buf[1] = bytes - 2;
524         return bytes;
525
526 }
527
528 int adsi_data_mode(unsigned char *buf)
529 {
530         int bytes=0;
531
532         /* Message type */
533         buf[bytes++] = ADSI_SWITCH_TO_DATA;
534
535         /* Reserve space for length */
536         bytes++;
537
538         buf[1] = bytes - 2;
539         return bytes;
540
541 }
542
543 int adsi_voice_mode(unsigned char *buf, int when)
544 {
545         int bytes=0;
546
547         /* Message type */
548         buf[bytes++] = ADSI_SWITCH_TO_VOICE;
549
550         /* Reserve space for length */
551         bytes++;
552
553         buf[bytes++] = when & 0x7f;
554
555         buf[1] = bytes - 2;
556         return bytes;
557
558 }
559
560 int adsi_available(struct ast_channel *chan)
561 {
562         int cpe = chan->adsicpe & 0xff;
563         if ((cpe == AST_ADSI_AVAILABLE) ||
564             (cpe == AST_ADSI_UNKNOWN))
565                 return 1;
566         return 0;
567 }
568
569 int adsi_download_disconnect(unsigned char *buf)
570 {
571         int bytes=0;
572
573         /* Message type */
574         buf[bytes++] = ADSI_DOWNLOAD_DISC;
575
576         /* Reserve space for length */
577         bytes++;
578
579         buf[1] = bytes - 2;
580         return bytes;
581
582 }
583
584 int adsi_display(unsigned char *buf, int page, int line, int just, int wrap, 
585                  unsigned char *col1, unsigned char *col2)
586 {
587         int bytes=0;
588
589         /* Sanity check line number */
590
591         if (page) {
592                 if (line > 4) return -1;
593         } else {
594                 if (line > 33) return -1;
595         }
596
597         if (line < 1)
598                 return -1;
599         /* Parameter type */
600         buf[bytes++] = ADSI_LOAD_VIRTUAL_DISP;
601         
602         /* Reserve space for size */
603         bytes++;
604
605         /* Page and wrap indicator */
606         buf[bytes++] = ((page & 0x1) << 7) | ((wrap & 0x1) << 6) | (line & 0x3f);
607
608         /* Justification */
609         buf[bytes++] = (just & 0x3) << 5;
610
611         /* Omit highlight mode definition */
612         buf[bytes++] = 0xff;
613
614         /* Primary column */
615         bytes+= ccopy(buf + bytes, col1, 20);
616
617         /* Delimiter */
618         buf[bytes++] = 0xff;
619         
620         /* Secondary column */
621         bytes += ccopy(buf + bytes, col2, 20);
622
623         /* Update length */
624         buf[1] = bytes - 2;
625         
626         return bytes;
627
628 }
629
630 int adsi_input_control(unsigned char *buf, int page, int line, int display, int format, int just)
631 {
632         int bytes=0;
633
634         if (page) {
635                 if (line > 4) return -1;
636         } else {
637                 if (line > 33) return -1;
638         }
639
640         if (line < 1)
641                 return -1;
642
643         buf[bytes++] = ADSI_INPUT_CONTROL;
644         bytes++;
645         buf[bytes++] = ((page & 1) << 7) | (line & 0x3f);
646         buf[bytes++] = ((display & 1) << 7) | ((just & 0x3) << 4) | (format & 0x7);
647         
648         buf[1] = bytes - 2;
649         return bytes;
650
651 }
652
653 int adsi_input_format(unsigned char *buf, int num, int dir, int wrap, unsigned char *format1, unsigned char *format2)
654 {
655         int bytes = 0;
656
657         if (!strlen(format1))
658                 return -1;
659
660         buf[bytes++] = ADSI_INPUT_FORMAT;
661         bytes++;
662         buf[bytes++] = ((dir & 1) << 7) | ((wrap & 1) << 6) | (num & 0x7);
663         bytes += ccopy(buf + bytes, format1, 20);
664         buf[bytes++] = 0xff;
665         if (format2 && strlen(format2)) {
666                 bytes += ccopy(buf + bytes, format2, 20);
667         }
668         buf[1] = bytes - 2;
669         return bytes;
670 }
671
672 int adsi_set_keys(unsigned char *buf, unsigned char *keys)
673 {
674         int bytes=0;
675         int x;
676         /* Message type */
677         buf[bytes++] = ADSI_INIT_SOFTKEY_LINE;
678         /* Space for size */
679         bytes++;
680         /* Key definitions */
681         for (x=0;x<6;x++)
682                 buf[bytes++] = (keys[x] & 0x3f) ? keys[x] : (keys[x] | 0x1);
683         buf[1] = bytes - 2;
684         return bytes;
685 }
686
687 int adsi_set_line(unsigned char *buf, int page, int line)
688 {
689         int bytes=0;
690
691         /* Sanity check line number */
692
693         if (page) {
694                 if (line > 4) return -1;
695         } else {
696                 if (line > 33) return -1;
697         }
698
699         if (line < 1)
700                 return -1;
701         /* Parameter type */
702         buf[bytes++] = ADSI_LINE_CONTROL;
703         
704         /* Reserve space for size */
705         bytes++;
706
707         /* Page and line */
708         buf[bytes++] = ((page & 0x1) << 7) | (line & 0x3f);
709
710         buf[1] = bytes - 2;
711         return bytes;
712
713 };
714
715 static int total = 0;
716 static int speeds = 0;
717
718 #if 0
719 int adsi_channel_init(struct ast_channel *chan)
720 {
721         char dsp[256];
722         char keys[256];
723         int bytes;
724         int x;
725         unsigned char *msgs[3];
726         unsigned char keyd[6];
727         int lens[3];
728         int types[3];
729         memset(dsp, 0, sizeof(dsp));
730         memset(keys, 0, sizeof(keys));
731         memset(msgs, 0, sizeof(msgs));
732
733         /* Start with initial display setup */
734         bytes = 0;
735         bytes += adsi_connect_session(dsp, NULL, -1);
736         for (x=0;x<total;x++) {
737                 bytes += adsi_display(dsp + bytes, ADSI_INFO_PAGE, x + 1, aligns[x], 0,
738                         strlen(intro[x]) ? intro[x] : " ", "");
739         }
740         bytes += adsi_set_line(dsp + bytes, ADSI_INFO_PAGE, 1);
741         msgs[0] = dsp;
742         lens[0] = bytes;
743         types[0] = ADSI_MSG_DISPLAY;
744
745         /* Prepare key setup messages */
746
747         if (speeds) {
748                 bytes = 0;
749                 memset(keyd, 0, sizeof(keyd));
750                 for (x=0;x<speeds;x++) {
751                         bytes += adsi_load_soft_key(keys + bytes, ADSI_SPEED_DIAL + x,
752                                         speeddial[x][1], speeddial[x][2], speeddial[x][0]);
753                         keyd[x] = ADSI_SPEED_DIAL + x;
754                 }
755                 bytes += adsi_set_keys(keys + bytes, keyd);
756                 msgs[1] = keys;
757                 lens[1] = bytes;
758                 types[1] = ADSI_MSG_DISPLAY;
759         }
760         adsi_transmit_messages(chan, msgs, lens, types);
761         return 0;
762 }
763 #else
764 int adsi_channel_init(struct ast_channel *chan)
765 {
766         char dsp[256];
767         int bytes;
768         int x;
769         unsigned char keyd[6];
770
771         memset(dsp, 0, sizeof(dsp));
772
773         /* Start with initial display setup */
774         bytes = 0;
775         bytes += adsi_connect_session(dsp, NULL, -1);
776         for (x=0;x<total;x++) {
777                 bytes += adsi_display(dsp + bytes, ADSI_INFO_PAGE, x + 1, aligns[x], 0,
778                         strlen(intro[x]) ? intro[x] : " ", "");
779         }
780         bytes += adsi_set_line(dsp + bytes, ADSI_INFO_PAGE, 1);
781
782         /* Prepare key setup messages */
783
784         if (speeds) {
785                 memset(keyd, 0, sizeof(keyd));
786                 for (x=0;x<speeds;x++) {
787                         bytes += adsi_load_soft_key(dsp + bytes, ADSI_SPEED_DIAL + x,
788                                         speeddial[x][1], speeddial[x][2], speeddial[x][0], 0);
789                         keyd[x] = ADSI_SPEED_DIAL + x;
790                 }
791                 bytes += adsi_set_keys(dsp + bytes, keyd);
792         }
793         adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY);
794         return 0;
795 }
796 #endif
797
798 int adsi_channel_restore(struct ast_channel *chan)
799 {
800         char dsp[256];
801         int bytes;
802         int x;
803         unsigned char keyd[6];
804
805         memset(dsp, 0, sizeof(dsp));
806
807         /* Start with initial display setup */
808         bytes = 0;
809         bytes += adsi_set_line(dsp + bytes, ADSI_INFO_PAGE, 1);
810
811         /* Prepare key setup messages */
812
813         if (speeds) {
814                 memset(keyd, 0, sizeof(keyd));
815                 for (x=0;x<speeds;x++) {
816                         keyd[x] = ADSI_SPEED_DIAL + x;
817                 }
818                 bytes += adsi_set_keys(dsp + bytes, keyd);
819         }
820         adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY);
821         return 0;
822
823 }
824
825 int adsi_load_session(struct ast_channel *chan, unsigned char *app, int ver, int data)
826 {
827         char dsp[256];
828         int bytes;
829         int res;
830         char resp[2];
831
832         memset(dsp, 0, sizeof(dsp));
833
834         /* Connect to session */
835         bytes = 0;
836         bytes += adsi_connect_session(dsp + bytes, app,ver);
837
838         if (data)
839                 bytes += adsi_data_mode(dsp + bytes);
840
841         /* Prepare key setup messages */
842         if (adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY))
843                 return -1;
844         res = ast_readstring(chan, resp, 1, 1200, 1200, "");
845         if (res < 0)
846                 return -1;
847         if (res) {
848                 ast_log(LOG_DEBUG, "No response from CPE about version.  Assuming not there.\n");
849                 return 0;
850         }
851         if (!strcmp(resp, "B")) {
852                 ast_log(LOG_DEBUG, "CPE has script '%s' version %d already loaded\n", app, ver);
853                 return 1;
854         } else if (!strcmp(resp, "A")) {
855                 ast_log(LOG_DEBUG, "CPE hasn't script '%s' version %d already loaded\n", app, ver);
856         } else {
857                 ast_log(LOG_WARNING, "Unexpected CPE response to script query: %s\n", resp);
858         }
859         return 0;
860
861 }
862
863 int adsi_unload_session(struct ast_channel *chan)
864 {
865         char dsp[256];
866         int bytes;
867
868         memset(dsp, 0, sizeof(dsp));
869
870         /* Connect to session */
871         bytes = 0;
872         bytes += adsi_disconnect_session(dsp + bytes);
873         bytes += adsi_voice_mode(dsp + bytes, 0);
874
875         /* Prepare key setup messages */
876         if (adsi_transmit_message(chan, dsp, bytes, ADSI_MSG_DISPLAY))
877                 return -1;
878         return 0;
879 }
880
881 static int str2align(char *s)
882 {
883         if (!strncasecmp(s, "l", 1))
884                 return ADSI_JUST_LEFT;
885         else if (!strncasecmp(s, "r", 1))
886                 return ADSI_JUST_RIGHT;
887         else if (!strncasecmp(s, "i", 1))
888                 return ADSI_JUST_IND;
889         else
890                 return ADSI_JUST_CENT;
891 }
892
893 static void init_state(void)
894 {
895         int x;
896         for (x=0;x<ADSI_MAX_INTRO;x++)
897                 aligns[x] = ADSI_JUST_CENT;
898         strcpy(intro[0], "Welcome to the");
899         strcpy(intro[1], "Asterisk");
900         strcpy(intro[2], "Open Source PBX");
901         total = 3;
902         speeds = 0;
903         for (x=3;x<ADSI_MAX_INTRO;x++)
904                 strcpy(intro[x], "");
905         memset(speeddial, 0, sizeof(speeddial));
906         alignment = ADSI_JUST_CENT;
907 }
908
909 static void adsi_load(void)
910 {
911         int x;
912         struct ast_config *conf;
913         struct ast_variable *v;
914         char *name, *sname;
915         init_state();
916         conf = ast_load("adsi.conf");
917         if (conf) {
918                 x=0;
919                 v = ast_variable_browse(conf, "intro");
920                 while(v) {
921                         if (!strcasecmp(v->name, "alignment"))
922                                 alignment = str2align(v->value);
923                         else if (!strcasecmp(v->name, "greeting")) {
924                                 if (x < ADSI_MAX_INTRO) {
925                                         aligns[x] = alignment;
926                                         strncpy(intro[x], v->value, 20);
927                                         x++;
928                                 }
929                         } else if (!strcasecmp(v->name, "maxretries")) {
930                                 if (atoi(v->value) > 0)
931                                         maxretries = atoi(v->value);
932                         }
933                         v = v->next;
934                 }
935                 v = ast_variable_browse(conf, "speeddial");
936                 if (x)
937                         total = x;
938                 x = 0;
939                 while(v) {
940                         name = strtok(v->value, ",");
941                         sname = strtok(NULL, ",");
942                         if (!sname) 
943                                 sname = name;
944                         if (x < ADSI_MAX_SPEED_DIAL) {
945                                 /* Up to 20 digits */
946                                 strncpy(speeddial[x][0], v->name, 20);
947                                 strncpy(speeddial[x][1], name, 18);
948                                 strncpy(speeddial[x][2], sname, 7);
949                                 x++;
950                         }
951                         v = v->next;
952                                 
953                 }
954                 if (x)
955                         speeds = x;
956                 ast_destroy(conf);
957         }
958 }
959
960 int reload(void)
961 {
962         adsi_load();
963         return 0;
964 }
965
966 int load_module(void)
967 {
968         adsi_load();
969         return 0;
970 }
971
972 int unload_module(void)
973 {
974         /* Can't unload this once we're loaded */
975         return -1;
976 }
977
978 char *description(void)
979 {
980         return "Call Parking Resource";
981 }
982
983 int usecount(void)
984 {
985         /* We should never be unloaded */
986         return 1;
987 }
988
989 char *key()
990 {
991         return ASTERISK_GPL_KEY;
992 }