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$")
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"
56 #define DEFAULT_ADSI_MAX_RETRIES 3
58 #define ADSI_MAX_INTRO 20
59 #define ADSI_MAX_SPEED_DIAL 6
61 #define ADSI_FLAG_DATAMODE (1 << 8)
63 static int maxretries
= DEFAULT_ADSI_MAX_RETRIES
;
65 /* Asterisk ADSI button definitions */
66 #define ADSI_SPEED_DIAL 10 /* 10-15 are reserved for speed dial */
68 static char intro
[ADSI_MAX_INTRO
][20];
69 static int aligns
[ADSI_MAX_INTRO
];
71 static char speeddial
[ADSI_MAX_SPEED_DIAL
][3][20];
73 static int alignment
= 0;
75 static int adsi_generate(unsigned char *buf
, int msgtype
, unsigned char *msg
, int msglen
, int msgnum
, int last
, int codec
)
80 /* Initial carrier (imaginary) */
88 /* If first message, Send 150ms of MARK's */
90 for (x
=0;x
<150;x
++) /* was 150 */
93 /* Put message type */
97 /* Put message length (plus one for the message number) */
101 /* Put message number */
105 /* Put actual message */
106 for (x
=0;x
<msglen
;x
++) {
111 /* Put 2's compliment of sum */
112 PUT_CLID(256-(sum
& 0xff));
116 /* Put trailing marks */
125 static int adsi_careful_send(struct ast_channel
*chan
, unsigned char *buf
, int len
, int *remainder
)
127 /* Sends carefully on a full duplex channel by using reading for
129 struct ast_frame
*inf
, outf
;
132 /* Zero out our outgoing frame */
133 memset(&outf
, 0, sizeof(outf
));
135 if (remainder
&& *remainder
) {
138 /* Send remainder if provided */
139 if (amt
> *remainder
)
142 *remainder
= *remainder
- amt
;
143 outf
.frametype
= AST_FRAME_VOICE
;
144 outf
.subclass
= AST_FORMAT_ULAW
;
148 if (ast_write(chan
, &outf
)) {
149 ast_log(LOG_WARNING
, "Failed to carefully write frame\n");
152 /* Update pointers and lengths */
159 /* If we don't get anything at all back in a second, forget
161 if (ast_waitfor(chan
, 1000) < 1)
163 inf
= ast_read(chan
);
167 if (inf
->frametype
== AST_FRAME_VOICE
) {
168 /* Read a voice frame */
169 if (inf
->subclass
!= AST_FORMAT_ULAW
) {
170 ast_log(LOG_WARNING
, "Channel not in ulaw?\n");
174 /* Send no more than they sent us */
175 if (amt
> inf
->datalen
)
178 *remainder
= inf
->datalen
- amt
;
179 outf
.frametype
= AST_FRAME_VOICE
;
180 outf
.subclass
= AST_FORMAT_ULAW
;
184 if (ast_write(chan
, &outf
)) {
185 ast_log(LOG_WARNING
, "Failed to carefully write frame\n");
189 /* Update pointers and lengths */
198 static int __adsi_transmit_messages(struct ast_channel
*chan
, unsigned char **msg
, int *msglen
, int *msgtype
)
200 /* msglen must be no more than 256 bits, each */
201 unsigned char buf
[24000 * 5];
209 /* Wait up to 500 ms for initial ACK */
215 if (chan
->adsicpe
== AST_ADSI_UNAVAILABLE
) {
216 /* Don't bother if we know they don't support ADSI */
221 while(retries
< maxretries
) {
222 if (!(chan
->adsicpe
& ADSI_FLAG_DATAMODE
)) {
223 /* Generate CAS (no SAS) */
224 ast_gen_cas(buf
, 0, 680, AST_FORMAT_ULAW
);
227 if (adsi_careful_send(chan
, buf
, 680, NULL
)) {
228 ast_log(LOG_WARNING
, "Unable to send CAS\n");
230 /* Wait For DTMF result */
233 if (((res
= ast_waitfor(chan
, waittime
)) < 1)) {
234 /* Didn't get back DTMF A in time */
235 ast_log(LOG_DEBUG
, "No ADSI CPE detected (%d)\n", res
);
237 chan
->adsicpe
= AST_ADSI_UNAVAILABLE
;
244 ast_log(LOG_DEBUG
, "Hangup in ADSI\n");
247 if (f
->frametype
== AST_FRAME_DTMF
) {
248 if (f
->subclass
== 'A') {
249 /* Okay, this is an ADSI CPE. Note this for future reference, too */
251 chan
->adsicpe
= AST_ADSI_AVAILABLE
;
254 if (f
->subclass
== 'D') {
255 ast_log(LOG_DEBUG
, "Off-hook capable CPE only, not ADSI\n");
257 ast_log(LOG_WARNING
, "Unknown ADSI response '%c'\n", f
->subclass
);
259 chan
->adsicpe
= AST_ADSI_UNAVAILABLE
;
268 ast_log(LOG_DEBUG
, "ADSI Compatible CPE Detected\n");
270 ast_log(LOG_DEBUG
, "Already in data mode\n");
275 def
= ast_channel_defer_dtmf(chan
);
277 while((x
< 6) && msg
[x
]) {
278 res
= adsi_generate(buf
+ pos
, msgtype
[x
], msg
[x
], msglen
[x
], x
+1 - start
, (x
== 5) || !msg
[x
+1], AST_FORMAT_ULAW
);
280 ast_log(LOG_WARNING
, "Failed to generate ADSI message %d on channel %s\n", x
+ 1, chan
->name
);
283 ast_log(LOG_DEBUG
, "Message %d, of %d input bytes, %d output bytes\n",
284 x
+ 1, msglen
[x
], res
);
291 res
= adsi_careful_send(chan
, buf
, pos
, &rem
);
293 ast_channel_undefer_dtmf(chan
);
297 ast_log(LOG_DEBUG
, "Sent total spill of %d bytes\n", pos
);
299 memset(ack
, 0, sizeof(ack
));
300 /* Get real result */
301 res
= ast_readstring(chan
, ack
, 2, 1000, 1000, "");
302 /* Check for hangup */
306 ast_log(LOG_DEBUG
, "Acked up to message %d\n", atoi(ack
+ 1));
307 start
+= atoi(ack
+ 1);
312 ast_log(LOG_DEBUG
, "Retransmitting (%d), from %d\n", retries
, start
+ 1);
316 ast_log(LOG_WARNING
, "Unexpected response to ack: %s (retry %d)\n", ack
, retries
);
319 if (retries
>= maxretries
) {
320 ast_log(LOG_WARNING
, "Maximum ADSI Retries (%d) exceeded\n", maxretries
);
328 int ast_adsi_begin_download(struct ast_channel
*chan
, char *service
, unsigned char *fdn
, unsigned char *sec
, int version
)
331 unsigned char buf
[256];
334 /* Setup the resident soft key stuff, a piece at a time */
335 /* Upload what scripts we can for voicemail ahead of time */
336 bytes
+= ast_adsi_download_connect(buf
+ bytes
, service
, fdn
, sec
, version
);
337 if (ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
, 0))
339 if (ast_readstring(chan
, ack
, 1, 10000, 10000, ""))
343 ast_log(LOG_DEBUG
, "Download was denied by CPE\n");
347 int ast_adsi_end_download(struct ast_channel
*chan
)
350 unsigned char buf
[256];
352 /* Setup the resident soft key stuff, a piece at a time */
353 /* Upload what scripts we can for voicemail ahead of time */
354 bytes
+= ast_adsi_download_disconnect(buf
+ bytes
);
355 if (ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
, 0))
360 int ast_adsi_transmit_message_full(struct ast_channel
*chan
, unsigned char *msg
, int msglen
, int msgtype
, int dowait
)
362 unsigned char *msgs
[5] = { NULL
, NULL
, NULL
, NULL
, NULL
};
368 int writeformat
, readformat
;
369 int waitforswitch
= 0;
371 writeformat
= chan
->writeformat
;
372 readformat
= chan
->readformat
;
374 newdatamode
= chan
->adsicpe
& ADSI_FLAG_DATAMODE
;
376 for (x
=0;x
<msglen
;x
+=(msg
[x
+1]+2)) {
377 if (msg
[x
] == ADSI_SWITCH_TO_DATA
) {
378 ast_log(LOG_DEBUG
, "Switch to data is sent!\n");
380 newdatamode
= ADSI_FLAG_DATAMODE
;
383 if (msg
[x
] == ADSI_SWITCH_TO_VOICE
) {
384 ast_log(LOG_DEBUG
, "Switch to voice is sent!\n");
392 msgtypes
[0] = msgtype
;
395 ast_log(LOG_WARNING
, "Can't send ADSI message of %d bytes, too large\n", msglen
);
399 ast_stopstream(chan
);
401 if (ast_set_write_format(chan
, AST_FORMAT_ULAW
)) {
402 ast_log(LOG_WARNING
, "Unable to set write format to ULAW\n");
406 if (ast_set_read_format(chan
, AST_FORMAT_ULAW
)) {
407 ast_log(LOG_WARNING
, "Unable to set read format to ULAW\n");
409 if (ast_set_write_format(chan
, writeformat
))
410 ast_log(LOG_WARNING
, "Unable to restore write format to %d\n", writeformat
);
414 res
= __adsi_transmit_messages(chan
, msgs
, msglens
, msgtypes
);
417 ast_log(LOG_DEBUG
, "Wait for switch is '%d'\n", waitforswitch
);
418 while(waitforswitch
-- && ((res
= ast_waitfordigit(chan
, 1000)) > 0)) { res
= 0; ast_log(LOG_DEBUG
, "Waiting for 'B'...\n"); }
422 chan
->adsicpe
= (chan
->adsicpe
& ~ADSI_FLAG_DATAMODE
) | newdatamode
;
425 ast_set_write_format(chan
, writeformat
);
427 ast_set_read_format(chan
, readformat
);
430 res
= ast_safe_sleep(chan
, 100 );
434 int ast_adsi_transmit_message(struct ast_channel
*chan
, unsigned char *msg
, int msglen
, int msgtype
)
436 return ast_adsi_transmit_message_full(chan
, msg
, msglen
, msgtype
, 1);
439 static inline int ccopy(unsigned char *dst
, const unsigned char *src
, int max
)
442 /* Carefully copy the requested data */
443 while ((x
< max
) && src
[x
] && (src
[x
] != 0xff)) {
450 int ast_adsi_load_soft_key(unsigned char *buf
, int key
, const char *llabel
, const char *slabel
, const char *ret
, int data
)
454 /* Abort if invalid key specified */
455 if ((key
< 2) || (key
> 33))
457 buf
[bytes
++] = ADSI_LOAD_SOFTKEY
;
458 /* Reserve for length */
463 /* Carefully copy long label */
464 bytes
+= ccopy(buf
+ bytes
, (const unsigned char *)llabel
, 18);
466 /* Place delimiter */
470 bytes
+= ccopy(buf
+ bytes
, (const unsigned char *)slabel
, 7);
473 /* If specified, copy return string */
475 /* Place delimiter */
478 buf
[bytes
++] = ADSI_SWITCH_TO_DATA2
;
479 /* Carefully copy return string */
480 bytes
+= ccopy(buf
+ bytes
, (const unsigned char *)ret
, 20);
483 /* Replace parameter length */
489 int ast_adsi_connect_session(unsigned char *buf
, unsigned char *fdn
, int ver
)
495 buf
[bytes
++] = ADSI_CONNECT_SESSION
;
497 /* Reserve space for length */
502 buf
[bytes
++] = fdn
[x
];
504 buf
[bytes
++] = ver
& 0xff;
512 int ast_adsi_download_connect(unsigned char *buf
, char *service
, unsigned char *fdn
, unsigned char *sec
, int ver
)
518 buf
[bytes
++] = ADSI_DOWNLOAD_CONNECT
;
520 /* Reserve space for length */
524 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)service
, 18);
530 buf
[bytes
++] = fdn
[x
];
533 buf
[bytes
++] = sec
[x
];
534 buf
[bytes
++] = ver
& 0xff;
542 int ast_adsi_disconnect_session(unsigned char *buf
)
547 buf
[bytes
++] = ADSI_DISC_SESSION
;
549 /* Reserve space for length */
557 int ast_adsi_query_cpeid(unsigned char *buf
)
560 buf
[bytes
++] = ADSI_QUERY_CPEID
;
561 /* Reserve space for length */
567 int ast_adsi_query_cpeinfo(unsigned char *buf
)
570 buf
[bytes
++] = ADSI_QUERY_CONFIG
;
571 /* Reserve space for length */
577 int ast_adsi_read_encoded_dtmf(struct ast_channel
*chan
, unsigned char *buf
, int maxlen
)
581 unsigned char current
= 0;
584 memset(buf
, 0, sizeof(buf
));
585 while(bytes
<= maxlen
) {
586 /* Wait up to a second for a digit */
587 res
= ast_waitfordigit(chan
, 1000);
594 /* Ignore anything other than a digit */
595 if ((res
< '0') || (res
> '9'))
602 buf
[bytes
++] = (res
<< 4) | current
;
612 int ast_adsi_get_cpeid(struct ast_channel
*chan
, unsigned char *cpeid
, int voice
)
614 unsigned char buf
[256];
617 bytes
+= ast_adsi_data_mode(buf
);
618 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
621 bytes
+= ast_adsi_query_cpeid(buf
);
622 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
625 memset(buf
, 0, sizeof(buf
));
626 res
= ast_adsi_read_encoded_dtmf(chan
, cpeid
, 4);
628 ast_log(LOG_WARNING
, "Got %d bytes back of encoded DTMF, expecting 4\n", res
);
636 bytes
+= ast_adsi_voice_mode(buf
, 0);
637 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
638 /* Ignore the resulting DTMF B announcing it's in voice mode */
639 ast_waitfordigit(chan
, 1000);
644 int ast_adsi_get_cpeinfo(struct ast_channel
*chan
, int *width
, int *height
, int *buttons
, int voice
)
646 unsigned char buf
[256];
649 bytes
+= ast_adsi_data_mode(buf
);
650 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
653 bytes
+= ast_adsi_query_cpeinfo(buf
);
654 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
657 memset(buf
, 0, sizeof(buf
));
658 res
= ast_readstring(chan
, (char *)buf
, 2, 1000, 500, "");
661 if (strlen((char *)buf
) != 2) {
662 ast_log(LOG_WARNING
, "Got %d bytes of width, expecting 2\n", res
);
668 *width
= atoi((char *)buf
);
670 memset(buf
, 0, sizeof(buf
));
672 res
= ast_readstring(chan
, (char *)buf
, 2, 1000, 500, "");
675 if (strlen((char *)buf
) != 2) {
676 ast_log(LOG_WARNING
, "Got %d bytes of height, expecting 2\n", res
);
682 *height
= atoi((char *)buf
);
685 memset(buf
, 0, sizeof(buf
));
687 res
= ast_readstring(chan
, (char *)buf
, 1, 1000, 500, "");
690 if (strlen((char *)buf
) != 1) {
691 ast_log(LOG_WARNING
, "Got %d bytes of buttons, expecting 1\n", res
);
697 *buttons
= atoi((char *)buf
);
701 bytes
+= ast_adsi_voice_mode(buf
, 0);
702 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
703 /* Ignore the resulting DTMF B announcing it's in voice mode */
704 ast_waitfordigit(chan
, 1000);
709 int ast_adsi_data_mode(unsigned char *buf
)
714 buf
[bytes
++] = ADSI_SWITCH_TO_DATA
;
716 /* Reserve space for length */
724 int ast_adsi_clear_soft_keys(unsigned char *buf
)
729 buf
[bytes
++] = ADSI_CLEAR_SOFTKEY
;
731 /* Reserve space for length */
739 int ast_adsi_clear_screen(unsigned char *buf
)
744 buf
[bytes
++] = ADSI_CLEAR_SCREEN
;
746 /* Reserve space for length */
754 int ast_adsi_voice_mode(unsigned char *buf
, int when
)
759 buf
[bytes
++] = ADSI_SWITCH_TO_VOICE
;
761 /* Reserve space for length */
764 buf
[bytes
++] = when
& 0x7f;
771 int ast_adsi_available(struct ast_channel
*chan
)
773 int cpe
= chan
->adsicpe
& 0xff;
774 if ((cpe
== AST_ADSI_AVAILABLE
) ||
775 (cpe
== AST_ADSI_UNKNOWN
))
780 int ast_adsi_download_disconnect(unsigned char *buf
)
785 buf
[bytes
++] = ADSI_DOWNLOAD_DISC
;
787 /* Reserve space for length */
795 int ast_adsi_display(unsigned char *buf
, int page
, int line
, int just
, int wrap
,
796 char *col1
, char *col2
)
800 /* Sanity check line number */
803 if (line
> 4) return -1;
805 if (line
> 33) return -1;
811 buf
[bytes
++] = ADSI_LOAD_VIRTUAL_DISP
;
813 /* Reserve space for size */
816 /* Page and wrap indicator */
817 buf
[bytes
++] = ((page
& 0x1) << 7) | ((wrap
& 0x1) << 6) | (line
& 0x3f);
820 buf
[bytes
++] = (just
& 0x3) << 5;
822 /* Omit highlight mode definition */
826 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)col1
, 20);
831 /* Secondary column */
832 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)col2
, 20);
841 int ast_adsi_input_control(unsigned char *buf
, int page
, int line
, int display
, int format
, int just
)
846 if (line
> 4) return -1;
848 if (line
> 33) return -1;
854 buf
[bytes
++] = ADSI_INPUT_CONTROL
;
856 buf
[bytes
++] = ((page
& 1) << 7) | (line
& 0x3f);
857 buf
[bytes
++] = ((display
& 1) << 7) | ((just
& 0x3) << 4) | (format
& 0x7);
864 int ast_adsi_input_format(unsigned char *buf
, int num
, int dir
, int wrap
, char *format1
, char *format2
)
868 if (!strlen((char *)format1
))
871 buf
[bytes
++] = ADSI_INPUT_FORMAT
;
873 buf
[bytes
++] = ((dir
& 1) << 7) | ((wrap
& 1) << 6) | (num
& 0x7);
874 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)format1
, 20);
876 if (format2
&& strlen((char *)format2
)) {
877 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)format2
, 20);
883 int ast_adsi_set_keys(unsigned char *buf
, unsigned char *keys
)
888 buf
[bytes
++] = ADSI_INIT_SOFTKEY_LINE
;
891 /* Key definitions */
893 buf
[bytes
++] = (keys
[x
] & 0x3f) ? keys
[x
] : (keys
[x
] | 0x1);
898 int ast_adsi_set_line(unsigned char *buf
, int page
, int line
)
902 /* Sanity check line number */
905 if (line
> 4) return -1;
907 if (line
> 33) return -1;
913 buf
[bytes
++] = ADSI_LINE_CONTROL
;
915 /* Reserve space for size */
919 buf
[bytes
++] = ((page
& 0x1) << 7) | (line
& 0x3f);
926 static int total
= 0;
927 static int speeds
= 0;
929 int ast_adsi_channel_restore(struct ast_channel
*chan
)
931 unsigned char dsp
[256];
934 unsigned char keyd
[6];
936 memset(dsp
, 0, sizeof(dsp
));
938 /* Start with initial display setup */
940 bytes
+= ast_adsi_set_line(dsp
+ bytes
, ADSI_INFO_PAGE
, 1);
942 /* Prepare key setup messages */
945 memset(keyd
, 0, sizeof(keyd
));
946 for (x
=0;x
<speeds
;x
++) {
947 keyd
[x
] = ADSI_SPEED_DIAL
+ x
;
949 bytes
+= ast_adsi_set_keys(dsp
+ bytes
, keyd
);
951 ast_adsi_transmit_message_full(chan
, dsp
, bytes
, ADSI_MSG_DISPLAY
, 0);
956 int ast_adsi_print(struct ast_channel
*chan
, char **lines
, int *aligns
, int voice
)
958 unsigned char buf
[4096];
962 for(x
=0;lines
[x
];x
++)
963 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_INFO_PAGE
, x
+1, aligns
[x
], 0, lines
[x
], "");
964 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_INFO_PAGE
, 1);
966 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
968 res
= ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
970 /* Ignore the resulting DTMF B announcing it's in voice mode */
971 ast_waitfordigit(chan
, 1000);
976 int ast_adsi_load_session(struct ast_channel
*chan
, unsigned char *app
, int ver
, int data
)
978 unsigned char dsp
[256];
983 memset(dsp
, 0, sizeof(dsp
));
985 /* Connect to session */
987 bytes
+= ast_adsi_connect_session(dsp
+ bytes
, app
, ver
);
990 bytes
+= ast_adsi_data_mode(dsp
+ bytes
);
992 /* Prepare key setup messages */
993 if (ast_adsi_transmit_message_full(chan
, dsp
, bytes
, ADSI_MSG_DISPLAY
, 0))
996 res
= ast_readstring(chan
, resp
, 1, 1200, 1200, "");
1000 ast_log(LOG_DEBUG
, "No response from CPE about version. Assuming not there.\n");
1003 if (!strcmp(resp
, "B")) {
1004 ast_log(LOG_DEBUG
, "CPE has script '%s' version %d already loaded\n", app
, ver
);
1006 } else if (!strcmp(resp
, "A")) {
1007 ast_log(LOG_DEBUG
, "CPE hasn't script '%s' version %d already loaded\n", app
, ver
);
1009 ast_log(LOG_WARNING
, "Unexpected CPE response to script query: %s\n", resp
);
1017 int ast_adsi_unload_session(struct ast_channel
*chan
)
1019 unsigned char dsp
[256];
1022 memset(dsp
, 0, sizeof(dsp
));
1024 /* Connect to session */
1026 bytes
+= ast_adsi_disconnect_session(dsp
+ bytes
);
1027 bytes
+= ast_adsi_voice_mode(dsp
+ bytes
, 0);
1029 /* Prepare key setup messages */
1030 if (ast_adsi_transmit_message_full(chan
, dsp
, bytes
, ADSI_MSG_DISPLAY
, 0))
1035 static int str2align(char *s
)
1037 if (!strncasecmp(s
, "l", 1))
1038 return ADSI_JUST_LEFT
;
1039 else if (!strncasecmp(s
, "r", 1))
1040 return ADSI_JUST_RIGHT
;
1041 else if (!strncasecmp(s
, "i", 1))
1042 return ADSI_JUST_IND
;
1044 return ADSI_JUST_CENT
;
1047 static void init_state(void)
1051 for (x
=0;x
<ADSI_MAX_INTRO
;x
++)
1052 aligns
[x
] = ADSI_JUST_CENT
;
1053 ast_copy_string(intro
[0], "Welcome to the", sizeof(intro
[0]));
1054 ast_copy_string(intro
[1], "Asterisk", sizeof(intro
[1]));
1055 ast_copy_string(intro
[2], "Open Source PBX", sizeof(intro
[2]));
1058 for (x
=3;x
<ADSI_MAX_INTRO
;x
++)
1060 memset(speeddial
, 0, sizeof(speeddial
));
1061 alignment
= ADSI_JUST_CENT
;
1064 static void adsi_load(void)
1067 struct ast_config
*conf
;
1068 struct ast_variable
*v
;
1071 conf
= ast_config_load("adsi.conf");
1074 for (v
= ast_variable_browse(conf
, "intro"); v
; v
= v
->next
) {
1075 if (!strcasecmp(v
->name
, "alignment"))
1076 alignment
= str2align(v
->value
);
1077 else if (!strcasecmp(v
->name
, "greeting")) {
1078 if (x
< ADSI_MAX_INTRO
) {
1079 aligns
[x
] = alignment
;
1080 ast_copy_string(intro
[x
], v
->value
, sizeof(intro
[x
]));
1083 } else if (!strcasecmp(v
->name
, "maxretries")) {
1084 if (atoi(v
->value
) > 0)
1085 maxretries
= atoi(v
->value
);
1091 for (v
= ast_variable_browse(conf
, "speeddial"); v
; v
= v
->next
) {
1092 char *stringp
= v
->value
;
1093 name
= strsep(&stringp
, ",");
1094 sname
= strsep(&stringp
, ",");
1097 if (x
< ADSI_MAX_SPEED_DIAL
) {
1098 ast_copy_string(speeddial
[x
][0], v
->name
, sizeof(speeddial
[x
][0]));
1099 ast_copy_string(speeddial
[x
][1], name
, 18);
1100 ast_copy_string(speeddial
[x
][2], sname
, 7);
1106 ast_config_destroy(conf
);
1110 static int reload(void)
1116 static int load_module(void)
1122 static int unload_module(void)
1124 /* Can't unload this once we're loaded */
1128 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_GLOBAL_SYMBOLS
, "ADSI Resource",
1129 .load
= load_module
,
1130 .unload
= unload_module
,