2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * Includes code and algorithms from the Zapata library.
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.
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.
25 * \author Mark Spencer <markster@digium.com>
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
35 ASTERISK_FILE_VERSION(__FILE__
, "$Revision$")
40 #include "asterisk/adsi.h"
41 #include "asterisk/ulaw.h"
42 #include "asterisk/alaw.h"
43 #include "asterisk/callerid.h"
44 #include "asterisk/fskmodem.h"
45 #include "asterisk/channel.h"
46 #include "asterisk/module.h"
47 #include "asterisk/config.h"
48 #include "asterisk/file.h"
50 #define DEFAULT_ADSI_MAX_RETRIES 3
52 #define ADSI_MAX_INTRO 20
53 #define ADSI_MAX_SPEED_DIAL 6
55 #define ADSI_FLAG_DATAMODE (1 << 8)
57 static int maxretries
= DEFAULT_ADSI_MAX_RETRIES
;
59 /* Asterisk ADSI button definitions */
60 #define ADSI_SPEED_DIAL 10 /* 10-15 are reserved for speed dial */
62 static char intro
[ADSI_MAX_INTRO
][20];
63 static int aligns
[ADSI_MAX_INTRO
];
65 #define SPEEDDIAL_MAX_LEN 20
66 static char speeddial
[ADSI_MAX_SPEED_DIAL
][3][SPEEDDIAL_MAX_LEN
];
68 static int alignment
= 0;
70 static int adsi_generate(unsigned char *buf
, int msgtype
, unsigned char *msg
, int msglen
, int msgnum
, int last
, int codec
)
72 int sum
, x
, bytes
= 0;
73 /* Initial carrier (imaginary) */
74 float cr
= 1.0, ci
= 0.0, scont
= 0.0;
79 /* If first message, Send 150ms of MARK's */
81 for (x
= 0; x
< 150; x
++) /* was 150 */
85 /* Put message type */
89 /* Put message length (plus one for the message number) */
93 /* Put message number */
97 /* Put actual message */
98 for (x
= 0; x
< msglen
; x
++) {
103 /* Put 2's compliment of sum */
104 PUT_CLID(256-(sum
& 0xff));
108 /* Put trailing marks */
109 for (x
= 0; x
< 50; x
++)
117 static int adsi_careful_send(struct ast_channel
*chan
, unsigned char *buf
, int len
, int *remainder
)
119 /* Sends carefully on a full duplex channel by using reading for
121 struct ast_frame
*inf
, outf
;
124 /* Zero out our outgoing frame */
125 memset(&outf
, 0, sizeof(outf
));
127 if (remainder
&& *remainder
) {
130 /* Send remainder if provided */
131 if (amt
> *remainder
)
134 *remainder
= *remainder
- amt
;
135 outf
.frametype
= AST_FRAME_VOICE
;
136 outf
.subclass
= AST_FORMAT_ULAW
;
140 if (ast_write(chan
, &outf
)) {
141 ast_log(LOG_WARNING
, "Failed to carefully write frame\n");
144 /* Update pointers and lengths */
151 /* If we don't get anything at all back in a second, forget
153 if (ast_waitfor(chan
, 1000) < 1)
156 if (!(inf
= ast_read(chan
)))
159 /* Drop any frames that are not voice */
160 if (inf
->frametype
!= AST_FRAME_VOICE
) {
165 if (inf
->subclass
!= AST_FORMAT_ULAW
) {
166 ast_log(LOG_WARNING
, "Channel not in ulaw?\n");
170 /* Send no more than they sent us */
171 if (amt
> inf
->datalen
)
174 *remainder
= inf
->datalen
- amt
;
175 outf
.frametype
= AST_FRAME_VOICE
;
176 outf
.subclass
= AST_FORMAT_ULAW
;
180 if (ast_write(chan
, &outf
)) {
181 ast_log(LOG_WARNING
, "Failed to carefully write frame\n");
185 /* Update pointers and lengths */
193 static int __adsi_transmit_messages(struct ast_channel
*chan
, unsigned char **msg
, int *msglen
, int *msgtype
)
195 /* msglen must be no more than 256 bits, each */
196 unsigned char buf
[24000 * 5];
197 int pos
= 0, res
, x
, start
= 0, retries
= 0, waittime
, rem
= 0, def
;
201 if (chan
->adsicpe
== AST_ADSI_UNAVAILABLE
) {
202 /* Don't bother if we know they don't support ADSI */
207 while(retries
< maxretries
) {
208 if (!(chan
->adsicpe
& ADSI_FLAG_DATAMODE
)) {
209 /* Generate CAS (no SAS) */
210 ast_gen_cas(buf
, 0, 680, AST_FORMAT_ULAW
);
213 if (adsi_careful_send(chan
, buf
, 680, NULL
))
214 ast_log(LOG_WARNING
, "Unable to send CAS\n");
216 /* Wait For DTMF result */
219 if (((res
= ast_waitfor(chan
, waittime
)) < 1)) {
220 /* Didn't get back DTMF A in time */
221 ast_debug(1, "No ADSI CPE detected (%d)\n", res
);
223 chan
->adsicpe
= AST_ADSI_UNAVAILABLE
;
228 if (!(f
= ast_read(chan
))) {
229 ast_debug(1, "Hangup in ADSI\n");
232 if (f
->frametype
== AST_FRAME_DTMF
) {
233 if (f
->subclass
== 'A') {
234 /* Okay, this is an ADSI CPE. Note this for future reference, too */
236 chan
->adsicpe
= AST_ADSI_AVAILABLE
;
239 if (f
->subclass
== 'D')
240 ast_debug(1, "Off-hook capable CPE only, not ADSI\n");
242 ast_log(LOG_WARNING
, "Unknown ADSI response '%c'\n", f
->subclass
);
244 chan
->adsicpe
= AST_ADSI_UNAVAILABLE
;
253 ast_debug(1, "ADSI Compatible CPE Detected\n");
255 ast_debug(1, "Already in data mode\n");
261 def
= ast_channel_defer_dtmf(chan
);
263 while ((x
< 6) && msg
[x
]) {
264 if ((res
= adsi_generate(buf
+ pos
, msgtype
[x
], msg
[x
], msglen
[x
], x
+1 - start
, (x
== 5) || !msg
[x
+1], AST_FORMAT_ULAW
)) < 0) {
265 ast_log(LOG_WARNING
, "Failed to generate ADSI message %d on channel %s\n", x
+ 1, chan
->name
);
268 ast_debug(1, "Message %d, of %d input bytes, %d output bytes\n", x
+ 1, msglen
[x
], res
);
275 res
= adsi_careful_send(chan
, buf
, pos
, &rem
);
277 ast_channel_undefer_dtmf(chan
);
281 ast_debug(1, "Sent total spill of %d bytes\n", pos
);
283 memset(ack
, 0, sizeof(ack
));
284 /* Get real result and check for hangup */
285 if ((res
= ast_readstring(chan
, ack
, 2, 1000, 1000, "")) < 0)
288 ast_debug(1, "Acked up to message %d\n", atoi(ack
+ 1)); start
+= atoi(ack
+ 1);
293 ast_debug(1, "Retransmitting (%d), from %d\n", retries
, start
+ 1);
297 ast_log(LOG_WARNING
, "Unexpected response to ack: %s (retry %d)\n", ack
, retries
);
300 if (retries
>= maxretries
) {
301 ast_log(LOG_WARNING
, "Maximum ADSI Retries (%d) exceeded\n", maxretries
);
309 static int _ast_adsi_begin_download(struct ast_channel
*chan
, char *service
, unsigned char *fdn
, unsigned char *sec
, int version
)
312 unsigned char buf
[256];
315 /* Setup the resident soft key stuff, a piece at a time */
316 /* Upload what scripts we can for voicemail ahead of time */
317 bytes
+= ast_adsi_download_connect(buf
+ bytes
, service
, fdn
, sec
, version
);
318 if (ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
, 0))
320 if (ast_readstring(chan
, ack
, 1, 10000, 10000, ""))
324 ast_debug(1, "Download was denied by CPE\n");
328 static int _ast_adsi_end_download(struct ast_channel
*chan
)
331 unsigned char buf
[256];
333 /* Setup the resident soft key stuff, a piece at a time */
334 /* Upload what scripts we can for voicemail ahead of time */
335 bytes
+= ast_adsi_download_disconnect(buf
+ bytes
);
336 if (ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
, 0))
341 static int _ast_adsi_transmit_message_full(struct ast_channel
*chan
, unsigned char *msg
, int msglen
, int msgtype
, int dowait
)
343 unsigned char *msgs
[5] = { NULL
, NULL
, NULL
, NULL
, NULL
};
344 int msglens
[5], msgtypes
[5], newdatamode
= (chan
->adsicpe
& ADSI_FLAG_DATAMODE
), res
, x
, writeformat
= chan
->writeformat
, readformat
= chan
->readformat
, waitforswitch
= 0;
346 for (x
= 0; x
< msglen
; x
+= (msg
[x
+1]+2)) {
347 if (msg
[x
] == ADSI_SWITCH_TO_DATA
) {
348 ast_debug(1, "Switch to data is sent!\n");
350 newdatamode
= ADSI_FLAG_DATAMODE
;
353 if (msg
[x
] == ADSI_SWITCH_TO_VOICE
) {
354 ast_debug(1, "Switch to voice is sent!\n");
362 msgtypes
[0] = msgtype
;
365 ast_log(LOG_WARNING
, "Can't send ADSI message of %d bytes, too large\n", msglen
);
369 ast_stopstream(chan
);
371 if (ast_set_write_format(chan
, AST_FORMAT_ULAW
)) {
372 ast_log(LOG_WARNING
, "Unable to set write format to ULAW\n");
376 if (ast_set_read_format(chan
, AST_FORMAT_ULAW
)) {
377 ast_log(LOG_WARNING
, "Unable to set read format to ULAW\n");
379 if (ast_set_write_format(chan
, writeformat
))
380 ast_log(LOG_WARNING
, "Unable to restore write format to %d\n", writeformat
);
384 res
= __adsi_transmit_messages(chan
, msgs
, msglens
, msgtypes
);
387 ast_debug(1, "Wait for switch is '%d'\n", waitforswitch
);
388 while (waitforswitch
-- && ((res
= ast_waitfordigit(chan
, 1000)) > 0)) {
390 ast_debug(1, "Waiting for 'B'...\n");
395 chan
->adsicpe
= (chan
->adsicpe
& ~ADSI_FLAG_DATAMODE
) | newdatamode
;
398 ast_set_write_format(chan
, writeformat
);
400 ast_set_read_format(chan
, readformat
);
403 res
= ast_safe_sleep(chan
, 100 );
407 static int _ast_adsi_transmit_message(struct ast_channel
*chan
, unsigned char *msg
, int msglen
, int msgtype
)
409 return ast_adsi_transmit_message_full(chan
, msg
, msglen
, msgtype
, 1);
412 static inline int ccopy(unsigned char *dst
, const unsigned char *src
, int max
)
415 /* Carefully copy the requested data */
416 while ((x
< max
) && src
[x
] && (src
[x
] != 0xff)) {
423 static int _ast_adsi_load_soft_key(unsigned char *buf
, int key
, const char *llabel
, const char *slabel
, char *ret
, int data
)
427 /* Abort if invalid key specified */
428 if ((key
< 2) || (key
> 33))
431 buf
[bytes
++] = ADSI_LOAD_SOFTKEY
;
432 /* Reserve for length */
437 /* Carefully copy long label */
438 bytes
+= ccopy(buf
+ bytes
, (const unsigned char *)llabel
, 18);
440 /* Place delimiter */
444 bytes
+= ccopy(buf
+ bytes
, (const unsigned char *)slabel
, 7);
447 /* If specified, copy return string */
449 /* Place delimiter */
452 buf
[bytes
++] = ADSI_SWITCH_TO_DATA2
;
453 /* Carefully copy return string */
454 bytes
+= ccopy(buf
+ bytes
, (const unsigned char *)ret
, 20);
457 /* Replace parameter length */
463 static int _ast_adsi_connect_session(unsigned char *buf
, unsigned char *fdn
, int ver
)
468 buf
[bytes
++] = ADSI_CONNECT_SESSION
;
470 /* Reserve space for length */
474 for (x
= 0; x
< 4; x
++)
475 buf
[bytes
++] = fdn
[x
];
477 buf
[bytes
++] = ver
& 0xff;
485 static int _ast_adsi_download_connect(unsigned char *buf
, char *service
, unsigned char *fdn
, unsigned char *sec
, int ver
)
490 buf
[bytes
++] = ADSI_DOWNLOAD_CONNECT
;
492 /* Reserve space for length */
496 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)service
, 18);
501 for (x
= 0; x
< 4; x
++)
502 buf
[bytes
++] = fdn
[x
];
504 for (x
= 0; x
< 4; x
++)
505 buf
[bytes
++] = sec
[x
];
507 buf
[bytes
++] = ver
& 0xff;
515 static int _ast_adsi_disconnect_session(unsigned char *buf
)
520 buf
[bytes
++] = ADSI_DISC_SESSION
;
522 /* Reserve space for length */
530 static int _ast_adsi_query_cpeid(unsigned char *buf
)
533 buf
[bytes
++] = ADSI_QUERY_CPEID
;
534 /* Reserve space for length */
540 static int _ast_adsi_query_cpeinfo(unsigned char *buf
)
543 buf
[bytes
++] = ADSI_QUERY_CONFIG
;
544 /* Reserve space for length */
550 static int _ast_adsi_read_encoded_dtmf(struct ast_channel
*chan
, unsigned char *buf
, int maxlen
)
552 int bytes
= 0, res
, gotstar
= 0, pos
= 0;
553 unsigned char current
= 0;
555 memset(buf
, 0, sizeof(buf
));
557 while(bytes
<= maxlen
) {
558 /* Wait up to a second for a digit */
559 if (!(res
= ast_waitfordigit(chan
, 1000)))
565 /* Ignore anything other than a digit */
566 if ((res
< '0') || (res
> '9'))
573 buf
[bytes
++] = (res
<< 4) | current
;
584 static int _ast_adsi_get_cpeid(struct ast_channel
*chan
, unsigned char *cpeid
, int voice
)
586 unsigned char buf
[256] = "";
589 bytes
+= ast_adsi_data_mode(buf
);
590 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
593 bytes
+= ast_adsi_query_cpeid(buf
);
594 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
597 res
= ast_adsi_read_encoded_dtmf(chan
, cpeid
, 4);
599 ast_log(LOG_WARNING
, "Got %d bytes back of encoded DTMF, expecting 4\n", res
);
607 bytes
+= ast_adsi_voice_mode(buf
, 0);
608 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
609 /* Ignore the resulting DTMF B announcing it's in voice mode */
610 ast_waitfordigit(chan
, 1000);
615 static int _ast_adsi_get_cpeinfo(struct ast_channel
*chan
, int *width
, int *height
, int *buttons
, int voice
)
617 unsigned char buf
[256] = "";
620 bytes
+= ast_adsi_data_mode(buf
);
621 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
624 bytes
+= ast_adsi_query_cpeinfo(buf
);
625 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
628 if ((res
= ast_readstring(chan
, (char *)buf
, 2, 1000, 500, "")) < 0)
630 if (strlen((char *)buf
) != 2) {
631 ast_log(LOG_WARNING
, "Got %d bytes of width, expecting 2\n", res
);
637 *width
= atoi((char *)buf
);
639 memset(buf
, 0, sizeof(buf
));
641 if ((res
= ast_readstring(chan
, (char *)buf
, 2, 1000, 500, "")) < 0)
643 if (strlen((char *)buf
) != 2) {
644 ast_log(LOG_WARNING
, "Got %d bytes of height, expecting 2\n", res
);
650 *height
= atoi((char *)buf
);
653 memset(buf
, 0, sizeof(buf
));
655 if ((res
= ast_readstring(chan
, (char *)buf
, 1, 1000, 500, "")) < 0)
657 if (strlen((char *)buf
) != 1) {
658 ast_log(LOG_WARNING
, "Got %d bytes of buttons, expecting 1\n", res
);
664 *buttons
= atoi((char *)buf
);
668 bytes
+= ast_adsi_voice_mode(buf
, 0);
669 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
670 /* Ignore the resulting DTMF B announcing it's in voice mode */
671 ast_waitfordigit(chan
, 1000);
676 static int _ast_adsi_data_mode(unsigned char *buf
)
681 buf
[bytes
++] = ADSI_SWITCH_TO_DATA
;
683 /* Reserve space for length */
691 static int _ast_adsi_clear_soft_keys(unsigned char *buf
)
696 buf
[bytes
++] = ADSI_CLEAR_SOFTKEY
;
698 /* Reserve space for length */
706 static int _ast_adsi_clear_screen(unsigned char *buf
)
711 buf
[bytes
++] = ADSI_CLEAR_SCREEN
;
713 /* Reserve space for length */
721 static int _ast_adsi_voice_mode(unsigned char *buf
, int when
)
726 buf
[bytes
++] = ADSI_SWITCH_TO_VOICE
;
728 /* Reserve space for length */
731 buf
[bytes
++] = when
& 0x7f;
738 static int _ast_adsi_available(struct ast_channel
*chan
)
740 int cpe
= chan
->adsicpe
& 0xff;
741 if ((cpe
== AST_ADSI_AVAILABLE
) ||
742 (cpe
== AST_ADSI_UNKNOWN
))
747 static int _ast_adsi_download_disconnect(unsigned char *buf
)
752 buf
[bytes
++] = ADSI_DOWNLOAD_DISC
;
754 /* Reserve space for length */
762 static int _ast_adsi_display(unsigned char *buf
, int page
, int line
, int just
, int wrap
,
763 char *col1
, char *col2
)
767 /* Sanity check line number */
770 if (line
> 4) return -1;
772 if (line
> 33) return -1;
778 buf
[bytes
++] = ADSI_LOAD_VIRTUAL_DISP
;
780 /* Reserve space for size */
783 /* Page and wrap indicator */
784 buf
[bytes
++] = ((page
& 0x1) << 7) | ((wrap
& 0x1) << 6) | (line
& 0x3f);
787 buf
[bytes
++] = (just
& 0x3) << 5;
789 /* Omit highlight mode definition */
793 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)col1
, 20);
798 /* Secondary column */
799 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)col2
, 20);
808 static int _ast_adsi_input_control(unsigned char *buf
, int page
, int line
, int display
, int format
, int just
)
813 if (line
> 4) return -1;
815 if (line
> 33) return -1;
821 buf
[bytes
++] = ADSI_INPUT_CONTROL
;
823 buf
[bytes
++] = ((page
& 1) << 7) | (line
& 0x3f);
824 buf
[bytes
++] = ((display
& 1) << 7) | ((just
& 0x3) << 4) | (format
& 0x7);
831 static int _ast_adsi_input_format(unsigned char *buf
, int num
, int dir
, int wrap
, char *format1
, char *format2
)
835 if (!strlen((char *)format1
))
838 buf
[bytes
++] = ADSI_INPUT_FORMAT
;
840 buf
[bytes
++] = ((dir
& 1) << 7) | ((wrap
& 1) << 6) | (num
& 0x7);
841 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)format1
, 20);
843 if (format2
&& strlen((char *)format2
)) {
844 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)format2
, 20);
850 static int _ast_adsi_set_keys(unsigned char *buf
, unsigned char *keys
)
855 buf
[bytes
++] = ADSI_INIT_SOFTKEY_LINE
;
858 /* Key definitions */
859 for (x
= 0; x
< 6; x
++)
860 buf
[bytes
++] = (keys
[x
] & 0x3f) ? keys
[x
] : (keys
[x
] | 0x1);
865 static int _ast_adsi_set_line(unsigned char *buf
, int page
, int line
)
869 /* Sanity check line number */
872 if (line
> 4) return -1;
874 if (line
> 33) return -1;
880 buf
[bytes
++] = ADSI_LINE_CONTROL
;
882 /* Reserve space for size */
886 buf
[bytes
++] = ((page
& 0x1) << 7) | (line
& 0x3f);
893 static int total
= 0;
894 static int speeds
= 0;
896 static int _ast_adsi_channel_restore(struct ast_channel
*chan
)
898 unsigned char dsp
[256] = "", keyd
[6] = "";
901 /* Start with initial display setup */
903 bytes
+= ast_adsi_set_line(dsp
+ bytes
, ADSI_INFO_PAGE
, 1);
905 /* Prepare key setup messages */
908 for (x
= 0; x
< speeds
; x
++)
909 keyd
[x
] = ADSI_SPEED_DIAL
+ x
;
910 bytes
+= ast_adsi_set_keys(dsp
+ bytes
, keyd
);
912 ast_adsi_transmit_message_full(chan
, dsp
, bytes
, ADSI_MSG_DISPLAY
, 0);
917 static int _ast_adsi_print(struct ast_channel
*chan
, char **lines
, int *aligns
, int voice
)
919 unsigned char buf
[4096];
920 int bytes
= 0, res
, x
;
922 for(x
= 0; lines
[x
]; x
++)
923 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_INFO_PAGE
, x
+1, aligns
[x
], 0, lines
[x
], "");
924 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_INFO_PAGE
, 1);
926 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
927 res
= ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
929 /* Ignore the resulting DTMF B announcing it's in voice mode */
930 ast_waitfordigit(chan
, 1000);
934 static int _ast_adsi_load_session(struct ast_channel
*chan
, unsigned char *app
, int ver
, int data
)
936 unsigned char dsp
[256] = "";
940 /* Connect to session */
941 bytes
+= ast_adsi_connect_session(dsp
+ bytes
, app
, ver
);
944 bytes
+= ast_adsi_data_mode(dsp
+ bytes
);
946 /* Prepare key setup messages */
947 if (ast_adsi_transmit_message_full(chan
, dsp
, bytes
, ADSI_MSG_DISPLAY
, 0))
950 if ((res
= ast_readstring(chan
, resp
, 1, 1200, 1200, "")) < 0)
953 ast_debug(1, "No response from CPE about version. Assuming not there.\n");
956 if (!strcmp(resp
, "B")) {
957 ast_debug(1, "CPE has script '%s' version %d already loaded\n", app
, ver
);
959 } else if (!strcmp(resp
, "A")) {
960 ast_debug(1, "CPE hasn't script '%s' version %d already loaded\n", app
, ver
);
962 ast_log(LOG_WARNING
, "Unexpected CPE response to script query: %s\n", resp
);
970 static int _ast_adsi_unload_session(struct ast_channel
*chan
)
972 unsigned char dsp
[256] = "";
975 /* Connect to session */
976 bytes
+= ast_adsi_disconnect_session(dsp
+ bytes
);
977 bytes
+= ast_adsi_voice_mode(dsp
+ bytes
, 0);
979 /* Prepare key setup messages */
980 if (ast_adsi_transmit_message_full(chan
, dsp
, bytes
, ADSI_MSG_DISPLAY
, 0))
986 static int str2align(const char *s
)
988 if (!strncasecmp(s
, "l", 1))
989 return ADSI_JUST_LEFT
;
990 else if (!strncasecmp(s
, "r", 1))
991 return ADSI_JUST_RIGHT
;
992 else if (!strncasecmp(s
, "i", 1))
993 return ADSI_JUST_IND
;
995 return ADSI_JUST_CENT
;
998 static void init_state(void)
1002 for (x
= 0; x
< ADSI_MAX_INTRO
; x
++)
1003 aligns
[x
] = ADSI_JUST_CENT
;
1004 ast_copy_string(intro
[0], "Welcome to the", sizeof(intro
[0]));
1005 ast_copy_string(intro
[1], "Asterisk", sizeof(intro
[1]));
1006 ast_copy_string(intro
[2], "Open Source PBX", sizeof(intro
[2]));
1009 for (x
= 3; x
< ADSI_MAX_INTRO
; x
++)
1011 memset(speeddial
, 0, sizeof(speeddial
));
1012 alignment
= ADSI_JUST_CENT
;
1015 static void adsi_load(int reload
)
1018 struct ast_config
*conf
= NULL
;
1019 struct ast_variable
*v
;
1020 struct ast_flags config_flags
= { reload
? CONFIG_FLAG_FILEUNCHANGED
: 0 };
1024 if (!(conf
= ast_config_load("adsi.conf", config_flags
)))
1026 else if (conf
== CONFIG_STATUS_FILEUNCHANGED
)
1028 for (v
= ast_variable_browse(conf
, "intro"); v
; v
= v
->next
) {
1029 if (!strcasecmp(v
->name
, "alignment"))
1030 alignment
= str2align(v
->value
);
1031 else if (!strcasecmp(v
->name
, "greeting")) {
1032 if (x
< ADSI_MAX_INTRO
) {
1033 aligns
[x
] = alignment
;
1034 ast_copy_string(intro
[x
], v
->value
, sizeof(intro
[x
]));
1037 } else if (!strcasecmp(v
->name
, "maxretries")) {
1038 if (atoi(v
->value
) > 0)
1039 maxretries
= atoi(v
->value
);
1046 for (v
= ast_variable_browse(conf
, "speeddial"); v
; v
= v
->next
) {
1047 char buf
[3 * SPEEDDIAL_MAX_LEN
];
1048 char *stringp
= buf
;
1049 ast_copy_string(buf
, v
->value
, sizeof(buf
));
1050 name
= strsep(&stringp
, ",");
1051 sname
= strsep(&stringp
, ",");
1054 if (x
< ADSI_MAX_SPEED_DIAL
) {
1055 ast_copy_string(speeddial
[x
][0], v
->name
, sizeof(speeddial
[x
][0]));
1056 ast_copy_string(speeddial
[x
][1], name
, 18);
1057 ast_copy_string(speeddial
[x
][2], sname
, 7);
1063 ast_config_destroy(conf
);
1068 static int reload(void)
1074 static int load_module(void)
1078 ast_adsi_begin_download
= _ast_adsi_begin_download
;
1079 ast_adsi_end_download
= _ast_adsi_end_download
;
1080 ast_adsi_channel_restore
= _ast_adsi_channel_restore
;
1081 ast_adsi_print
= _ast_adsi_print
;
1082 ast_adsi_load_session
= _ast_adsi_load_session
;
1083 ast_adsi_unload_session
= _ast_adsi_unload_session
;
1084 ast_adsi_transmit_message
= _ast_adsi_transmit_message
;
1085 ast_adsi_transmit_message_full
= _ast_adsi_transmit_message_full
;
1086 ast_adsi_read_encoded_dtmf
= _ast_adsi_read_encoded_dtmf
;
1087 ast_adsi_connect_session
= _ast_adsi_connect_session
;
1088 ast_adsi_query_cpeid
= _ast_adsi_query_cpeid
;
1089 ast_adsi_query_cpeinfo
= _ast_adsi_query_cpeinfo
;
1090 ast_adsi_get_cpeid
= _ast_adsi_get_cpeid
;
1091 ast_adsi_get_cpeinfo
= _ast_adsi_get_cpeinfo
;
1092 ast_adsi_download_connect
= _ast_adsi_download_connect
;
1093 ast_adsi_disconnect_session
= _ast_adsi_disconnect_session
;
1094 ast_adsi_download_disconnect
= _ast_adsi_download_disconnect
;
1095 ast_adsi_data_mode
= _ast_adsi_data_mode
;
1096 ast_adsi_clear_soft_keys
= _ast_adsi_clear_soft_keys
;
1097 ast_adsi_clear_screen
= _ast_adsi_clear_screen
;
1098 ast_adsi_voice_mode
= _ast_adsi_voice_mode
;
1099 ast_adsi_available
= _ast_adsi_available
;
1100 ast_adsi_display
= _ast_adsi_display
;
1101 ast_adsi_set_line
= _ast_adsi_set_line
;
1102 ast_adsi_load_soft_key
= _ast_adsi_load_soft_key
;
1103 ast_adsi_set_keys
= _ast_adsi_set_keys
;
1104 ast_adsi_input_control
= _ast_adsi_input_control
;
1105 ast_adsi_input_format
= _ast_adsi_input_format
;
1107 return AST_MODULE_LOAD_SUCCESS
;
1110 static int unload_module(void)
1112 /* Can't unload this once we're loaded */
1116 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_DEFAULT
, "ADSI Resource",
1117 .load
= load_module
,
1118 .unload
= unload_module
,