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");
173 /* Send no more than they sent us */
174 if (amt
> inf
->datalen
)
177 *remainder
= inf
->datalen
- amt
;
178 outf
.frametype
= AST_FRAME_VOICE
;
179 outf
.subclass
= AST_FORMAT_ULAW
;
183 if (ast_write(chan
, &outf
)) {
184 ast_log(LOG_WARNING
, "Failed to carefully write frame\n");
187 /* Update pointers and lengths */
196 static int __adsi_transmit_messages(struct ast_channel
*chan
, unsigned char **msg
, int *msglen
, int *msgtype
)
198 /* msglen must be no more than 256 bits, each */
199 unsigned char buf
[24000 * 5];
207 /* Wait up to 500 ms for initial ACK */
213 if (chan
->adsicpe
== AST_ADSI_UNAVAILABLE
) {
214 /* Don't bother if we know they don't support ADSI */
219 while(retries
< maxretries
) {
220 if (!(chan
->adsicpe
& ADSI_FLAG_DATAMODE
)) {
221 /* Generate CAS (no SAS) */
222 ast_gen_cas(buf
, 0, 680, AST_FORMAT_ULAW
);
225 if (adsi_careful_send(chan
, buf
, 680, NULL
)) {
226 ast_log(LOG_WARNING
, "Unable to send CAS\n");
228 /* Wait For DTMF result */
231 if (((res
= ast_waitfor(chan
, waittime
)) < 1)) {
232 /* Didn't get back DTMF A in time */
233 ast_log(LOG_DEBUG
, "No ADSI CPE detected (%d)\n", res
);
235 chan
->adsicpe
= AST_ADSI_UNAVAILABLE
;
242 ast_log(LOG_DEBUG
, "Hangup in ADSI\n");
245 if (f
->frametype
== AST_FRAME_DTMF
) {
246 if (f
->subclass
== 'A') {
247 /* Okay, this is an ADSI CPE. Note this for future reference, too */
249 chan
->adsicpe
= AST_ADSI_AVAILABLE
;
252 if (f
->subclass
== 'D') {
253 ast_log(LOG_DEBUG
, "Off-hook capable CPE only, not ADSI\n");
255 ast_log(LOG_WARNING
, "Unknown ADSI response '%c'\n", f
->subclass
);
257 chan
->adsicpe
= AST_ADSI_UNAVAILABLE
;
265 ast_log(LOG_DEBUG
, "ADSI Compatible CPE Detected\n");
267 ast_log(LOG_DEBUG
, "Already in data mode\n");
272 def
= ast_channel_defer_dtmf(chan
);
274 while((x
< 6) && msg
[x
]) {
275 res
= adsi_generate(buf
+ pos
, msgtype
[x
], msg
[x
], msglen
[x
], x
+1 - start
, (x
== 5) || !msg
[x
+1], AST_FORMAT_ULAW
);
277 ast_log(LOG_WARNING
, "Failed to generate ADSI message %d on channel %s\n", x
+ 1, chan
->name
);
280 ast_log(LOG_DEBUG
, "Message %d, of %d input bytes, %d output bytes\n",
281 x
+ 1, msglen
[x
], res
);
288 res
= adsi_careful_send(chan
, buf
, pos
, &rem
);
290 ast_channel_undefer_dtmf(chan
);
294 ast_log(LOG_DEBUG
, "Sent total spill of %d bytes\n", pos
);
296 memset(ack
, 0, sizeof(ack
));
297 /* Get real result */
298 res
= ast_readstring(chan
, ack
, 2, 1000, 1000, "");
299 /* Check for hangup */
303 ast_log(LOG_DEBUG
, "Acked up to message %d\n", atoi(ack
+ 1));
304 start
+= atoi(ack
+ 1);
309 ast_log(LOG_DEBUG
, "Retransmitting (%d), from %d\n", retries
, start
+ 1);
313 ast_log(LOG_WARNING
, "Unexpected response to ack: %s (retry %d)\n", ack
, retries
);
316 if (retries
>= maxretries
) {
317 ast_log(LOG_WARNING
, "Maximum ADSI Retries (%d) exceeded\n", maxretries
);
325 int ast_adsi_begin_download(struct ast_channel
*chan
, char *service
, unsigned char *fdn
, unsigned char *sec
, int version
)
328 unsigned char buf
[256];
331 /* Setup the resident soft key stuff, a piece at a time */
332 /* Upload what scripts we can for voicemail ahead of time */
333 bytes
+= ast_adsi_download_connect(buf
+ bytes
, service
, fdn
, sec
, version
);
334 if (ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
, 0))
336 if (ast_readstring(chan
, ack
, 1, 10000, 10000, ""))
340 ast_log(LOG_DEBUG
, "Download was denied by CPE\n");
344 int ast_adsi_end_download(struct ast_channel
*chan
)
347 unsigned char buf
[256];
349 /* Setup the resident soft key stuff, a piece at a time */
350 /* Upload what scripts we can for voicemail ahead of time */
351 bytes
+= ast_adsi_download_disconnect(buf
+ bytes
);
352 if (ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DOWNLOAD
, 0))
357 int ast_adsi_transmit_message_full(struct ast_channel
*chan
, unsigned char *msg
, int msglen
, int msgtype
, int dowait
)
359 unsigned char *msgs
[5] = { NULL
, NULL
, NULL
, NULL
, NULL
};
365 int writeformat
, readformat
;
366 int waitforswitch
= 0;
368 writeformat
= chan
->writeformat
;
369 readformat
= chan
->readformat
;
371 newdatamode
= chan
->adsicpe
& ADSI_FLAG_DATAMODE
;
373 for (x
=0;x
<msglen
;x
+=(msg
[x
+1]+2)) {
374 if (msg
[x
] == ADSI_SWITCH_TO_DATA
) {
375 ast_log(LOG_DEBUG
, "Switch to data is sent!\n");
377 newdatamode
= ADSI_FLAG_DATAMODE
;
380 if (msg
[x
] == ADSI_SWITCH_TO_VOICE
) {
381 ast_log(LOG_DEBUG
, "Switch to voice is sent!\n");
389 msgtypes
[0] = msgtype
;
392 ast_log(LOG_WARNING
, "Can't send ADSI message of %d bytes, too large\n", msglen
);
396 ast_stopstream(chan
);
398 if (ast_set_write_format(chan
, AST_FORMAT_ULAW
)) {
399 ast_log(LOG_WARNING
, "Unable to set write format to ULAW\n");
403 if (ast_set_read_format(chan
, AST_FORMAT_ULAW
)) {
404 ast_log(LOG_WARNING
, "Unable to set read format to ULAW\n");
406 if (ast_set_write_format(chan
, writeformat
))
407 ast_log(LOG_WARNING
, "Unable to restore write format to %d\n", writeformat
);
411 res
= __adsi_transmit_messages(chan
, msgs
, msglens
, msgtypes
);
414 ast_log(LOG_DEBUG
, "Wait for switch is '%d'\n", waitforswitch
);
415 while(waitforswitch
-- && ((res
= ast_waitfordigit(chan
, 1000)) > 0)) { res
= 0; ast_log(LOG_DEBUG
, "Waiting for 'B'...\n"); }
419 chan
->adsicpe
= (chan
->adsicpe
& ~ADSI_FLAG_DATAMODE
) | newdatamode
;
422 ast_set_write_format(chan
, writeformat
);
424 ast_set_read_format(chan
, readformat
);
427 res
= ast_safe_sleep(chan
, 100 );
431 int ast_adsi_transmit_message(struct ast_channel
*chan
, unsigned char *msg
, int msglen
, int msgtype
)
433 return ast_adsi_transmit_message_full(chan
, msg
, msglen
, msgtype
, 1);
436 static inline int ccopy(unsigned char *dst
, const unsigned char *src
, int max
)
439 /* Carefully copy the requested data */
440 while ((x
< max
) && src
[x
] && (src
[x
] != 0xff)) {
447 int ast_adsi_load_soft_key(unsigned char *buf
, int key
, const char *llabel
, const char *slabel
, const char *ret
, int data
)
451 /* Abort if invalid key specified */
452 if ((key
< 2) || (key
> 33))
454 buf
[bytes
++] = ADSI_LOAD_SOFTKEY
;
455 /* Reserve for length */
460 /* Carefully copy long label */
461 bytes
+= ccopy(buf
+ bytes
, (const unsigned char *)llabel
, 18);
463 /* Place delimiter */
467 bytes
+= ccopy(buf
+ bytes
, (const unsigned char *)slabel
, 7);
470 /* If specified, copy return string */
472 /* Place delimiter */
475 buf
[bytes
++] = ADSI_SWITCH_TO_DATA2
;
476 /* Carefully copy return string */
477 bytes
+= ccopy(buf
+ bytes
, (const unsigned char *)ret
, 20);
480 /* Replace parameter length */
486 int ast_adsi_connect_session(unsigned char *buf
, unsigned char *fdn
, int ver
)
492 buf
[bytes
++] = ADSI_CONNECT_SESSION
;
494 /* Reserve space for length */
499 buf
[bytes
++] = fdn
[x
];
501 buf
[bytes
++] = ver
& 0xff;
509 int ast_adsi_download_connect(unsigned char *buf
, char *service
, unsigned char *fdn
, unsigned char *sec
, int ver
)
515 buf
[bytes
++] = ADSI_DOWNLOAD_CONNECT
;
517 /* Reserve space for length */
521 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)service
, 18);
527 buf
[bytes
++] = fdn
[x
];
530 buf
[bytes
++] = sec
[x
];
531 buf
[bytes
++] = ver
& 0xff;
539 int ast_adsi_disconnect_session(unsigned char *buf
)
544 buf
[bytes
++] = ADSI_DISC_SESSION
;
546 /* Reserve space for length */
554 int ast_adsi_query_cpeid(unsigned char *buf
)
557 buf
[bytes
++] = ADSI_QUERY_CPEID
;
558 /* Reserve space for length */
564 int ast_adsi_query_cpeinfo(unsigned char *buf
)
567 buf
[bytes
++] = ADSI_QUERY_CONFIG
;
568 /* Reserve space for length */
574 int ast_adsi_read_encoded_dtmf(struct ast_channel
*chan
, unsigned char *buf
, int maxlen
)
578 unsigned char current
= 0;
581 memset(buf
, 0, sizeof(buf
));
582 while(bytes
<= maxlen
) {
583 /* Wait up to a second for a digit */
584 res
= ast_waitfordigit(chan
, 1000);
591 /* Ignore anything other than a digit */
592 if ((res
< '0') || (res
> '9'))
599 buf
[bytes
++] = (res
<< 4) | current
;
609 int ast_adsi_get_cpeid(struct ast_channel
*chan
, unsigned char *cpeid
, int voice
)
611 unsigned char buf
[256];
614 bytes
+= ast_adsi_data_mode(buf
);
615 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
618 bytes
+= ast_adsi_query_cpeid(buf
);
619 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
622 memset(buf
, 0, sizeof(buf
));
623 res
= ast_adsi_read_encoded_dtmf(chan
, cpeid
, 4);
625 ast_log(LOG_WARNING
, "Got %d bytes back of encoded DTMF, expecting 4\n", res
);
633 bytes
+= ast_adsi_voice_mode(buf
, 0);
634 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
635 /* Ignore the resulting DTMF B announcing it's in voice mode */
636 ast_waitfordigit(chan
, 1000);
641 int ast_adsi_get_cpeinfo(struct ast_channel
*chan
, int *width
, int *height
, int *buttons
, int voice
)
643 unsigned char buf
[256];
646 bytes
+= ast_adsi_data_mode(buf
);
647 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
650 bytes
+= ast_adsi_query_cpeinfo(buf
);
651 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
654 memset(buf
, 0, sizeof(buf
));
655 res
= ast_readstring(chan
, (char *)buf
, 2, 1000, 500, "");
658 if (strlen((char *)buf
) != 2) {
659 ast_log(LOG_WARNING
, "Got %d bytes of width, expecting 2\n", res
);
665 *width
= atoi((char *)buf
);
667 memset(buf
, 0, sizeof(buf
));
669 res
= ast_readstring(chan
, (char *)buf
, 2, 1000, 500, "");
672 if (strlen((char *)buf
) != 2) {
673 ast_log(LOG_WARNING
, "Got %d bytes of height, expecting 2\n", res
);
679 *height
= atoi((char *)buf
);
682 memset(buf
, 0, sizeof(buf
));
684 res
= ast_readstring(chan
, (char *)buf
, 1, 1000, 500, "");
687 if (strlen((char *)buf
) != 1) {
688 ast_log(LOG_WARNING
, "Got %d bytes of buttons, expecting 1\n", res
);
694 *buttons
= atoi((char *)buf
);
698 bytes
+= ast_adsi_voice_mode(buf
, 0);
699 ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
700 /* Ignore the resulting DTMF B announcing it's in voice mode */
701 ast_waitfordigit(chan
, 1000);
706 int ast_adsi_data_mode(unsigned char *buf
)
711 buf
[bytes
++] = ADSI_SWITCH_TO_DATA
;
713 /* Reserve space for length */
721 int ast_adsi_clear_soft_keys(unsigned char *buf
)
726 buf
[bytes
++] = ADSI_CLEAR_SOFTKEY
;
728 /* Reserve space for length */
736 int ast_adsi_clear_screen(unsigned char *buf
)
741 buf
[bytes
++] = ADSI_CLEAR_SCREEN
;
743 /* Reserve space for length */
751 int ast_adsi_voice_mode(unsigned char *buf
, int when
)
756 buf
[bytes
++] = ADSI_SWITCH_TO_VOICE
;
758 /* Reserve space for length */
761 buf
[bytes
++] = when
& 0x7f;
768 int ast_adsi_available(struct ast_channel
*chan
)
770 int cpe
= chan
->adsicpe
& 0xff;
771 if ((cpe
== AST_ADSI_AVAILABLE
) ||
772 (cpe
== AST_ADSI_UNKNOWN
))
777 int ast_adsi_download_disconnect(unsigned char *buf
)
782 buf
[bytes
++] = ADSI_DOWNLOAD_DISC
;
784 /* Reserve space for length */
792 int ast_adsi_display(unsigned char *buf
, int page
, int line
, int just
, int wrap
,
793 char *col1
, char *col2
)
797 /* Sanity check line number */
800 if (line
> 4) return -1;
802 if (line
> 33) return -1;
808 buf
[bytes
++] = ADSI_LOAD_VIRTUAL_DISP
;
810 /* Reserve space for size */
813 /* Page and wrap indicator */
814 buf
[bytes
++] = ((page
& 0x1) << 7) | ((wrap
& 0x1) << 6) | (line
& 0x3f);
817 buf
[bytes
++] = (just
& 0x3) << 5;
819 /* Omit highlight mode definition */
823 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)col1
, 20);
828 /* Secondary column */
829 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)col2
, 20);
838 int ast_adsi_input_control(unsigned char *buf
, int page
, int line
, int display
, int format
, int just
)
843 if (line
> 4) return -1;
845 if (line
> 33) return -1;
851 buf
[bytes
++] = ADSI_INPUT_CONTROL
;
853 buf
[bytes
++] = ((page
& 1) << 7) | (line
& 0x3f);
854 buf
[bytes
++] = ((display
& 1) << 7) | ((just
& 0x3) << 4) | (format
& 0x7);
861 int ast_adsi_input_format(unsigned char *buf
, int num
, int dir
, int wrap
, char *format1
, char *format2
)
865 if (!strlen((char *)format1
))
868 buf
[bytes
++] = ADSI_INPUT_FORMAT
;
870 buf
[bytes
++] = ((dir
& 1) << 7) | ((wrap
& 1) << 6) | (num
& 0x7);
871 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)format1
, 20);
873 if (format2
&& strlen((char *)format2
)) {
874 bytes
+= ccopy(buf
+ bytes
, (unsigned char *)format2
, 20);
880 int ast_adsi_set_keys(unsigned char *buf
, unsigned char *keys
)
885 buf
[bytes
++] = ADSI_INIT_SOFTKEY_LINE
;
888 /* Key definitions */
890 buf
[bytes
++] = (keys
[x
] & 0x3f) ? keys
[x
] : (keys
[x
] | 0x1);
895 int ast_adsi_set_line(unsigned char *buf
, int page
, int line
)
899 /* Sanity check line number */
902 if (line
> 4) return -1;
904 if (line
> 33) return -1;
910 buf
[bytes
++] = ADSI_LINE_CONTROL
;
912 /* Reserve space for size */
916 buf
[bytes
++] = ((page
& 0x1) << 7) | (line
& 0x3f);
923 static int total
= 0;
924 static int speeds
= 0;
926 int ast_adsi_channel_restore(struct ast_channel
*chan
)
928 unsigned char dsp
[256];
931 unsigned char keyd
[6];
933 memset(dsp
, 0, sizeof(dsp
));
935 /* Start with initial display setup */
937 bytes
+= ast_adsi_set_line(dsp
+ bytes
, ADSI_INFO_PAGE
, 1);
939 /* Prepare key setup messages */
942 memset(keyd
, 0, sizeof(keyd
));
943 for (x
=0;x
<speeds
;x
++) {
944 keyd
[x
] = ADSI_SPEED_DIAL
+ x
;
946 bytes
+= ast_adsi_set_keys(dsp
+ bytes
, keyd
);
948 ast_adsi_transmit_message_full(chan
, dsp
, bytes
, ADSI_MSG_DISPLAY
, 0);
953 int ast_adsi_print(struct ast_channel
*chan
, char **lines
, int *aligns
, int voice
)
955 unsigned char buf
[4096];
959 for(x
=0;lines
[x
];x
++)
960 bytes
+= ast_adsi_display(buf
+ bytes
, ADSI_INFO_PAGE
, x
+1, aligns
[x
], 0, lines
[x
], "");
961 bytes
+= ast_adsi_set_line(buf
+ bytes
, ADSI_INFO_PAGE
, 1);
963 bytes
+= ast_adsi_voice_mode(buf
+ bytes
, 0);
965 res
= ast_adsi_transmit_message_full(chan
, buf
, bytes
, ADSI_MSG_DISPLAY
, 0);
967 /* Ignore the resulting DTMF B announcing it's in voice mode */
968 ast_waitfordigit(chan
, 1000);
973 int ast_adsi_load_session(struct ast_channel
*chan
, unsigned char *app
, int ver
, int data
)
975 unsigned char dsp
[256];
980 memset(dsp
, 0, sizeof(dsp
));
982 /* Connect to session */
984 bytes
+= ast_adsi_connect_session(dsp
+ bytes
, app
, ver
);
987 bytes
+= ast_adsi_data_mode(dsp
+ bytes
);
989 /* Prepare key setup messages */
990 if (ast_adsi_transmit_message_full(chan
, dsp
, bytes
, ADSI_MSG_DISPLAY
, 0))
993 res
= ast_readstring(chan
, resp
, 1, 1200, 1200, "");
997 ast_log(LOG_DEBUG
, "No response from CPE about version. Assuming not there.\n");
1000 if (!strcmp(resp
, "B")) {
1001 ast_log(LOG_DEBUG
, "CPE has script '%s' version %d already loaded\n", app
, ver
);
1003 } else if (!strcmp(resp
, "A")) {
1004 ast_log(LOG_DEBUG
, "CPE hasn't script '%s' version %d already loaded\n", app
, ver
);
1006 ast_log(LOG_WARNING
, "Unexpected CPE response to script query: %s\n", resp
);
1014 int ast_adsi_unload_session(struct ast_channel
*chan
)
1016 unsigned char dsp
[256];
1019 memset(dsp
, 0, sizeof(dsp
));
1021 /* Connect to session */
1023 bytes
+= ast_adsi_disconnect_session(dsp
+ bytes
);
1024 bytes
+= ast_adsi_voice_mode(dsp
+ bytes
, 0);
1026 /* Prepare key setup messages */
1027 if (ast_adsi_transmit_message_full(chan
, dsp
, bytes
, ADSI_MSG_DISPLAY
, 0))
1032 static int str2align(char *s
)
1034 if (!strncasecmp(s
, "l", 1))
1035 return ADSI_JUST_LEFT
;
1036 else if (!strncasecmp(s
, "r", 1))
1037 return ADSI_JUST_RIGHT
;
1038 else if (!strncasecmp(s
, "i", 1))
1039 return ADSI_JUST_IND
;
1041 return ADSI_JUST_CENT
;
1044 static void init_state(void)
1048 for (x
=0;x
<ADSI_MAX_INTRO
;x
++)
1049 aligns
[x
] = ADSI_JUST_CENT
;
1050 ast_copy_string(intro
[0], "Welcome to the", sizeof(intro
[0]));
1051 ast_copy_string(intro
[1], "Asterisk", sizeof(intro
[1]));
1052 ast_copy_string(intro
[2], "Open Source PBX", sizeof(intro
[2]));
1055 for (x
=3;x
<ADSI_MAX_INTRO
;x
++)
1057 memset(speeddial
, 0, sizeof(speeddial
));
1058 alignment
= ADSI_JUST_CENT
;
1061 static void adsi_load(void)
1064 struct ast_config
*conf
;
1065 struct ast_variable
*v
;
1068 conf
= ast_config_load("adsi.conf");
1071 for (v
= ast_variable_browse(conf
, "intro"); v
; v
= v
->next
) {
1072 if (!strcasecmp(v
->name
, "alignment"))
1073 alignment
= str2align(v
->value
);
1074 else if (!strcasecmp(v
->name
, "greeting")) {
1075 if (x
< ADSI_MAX_INTRO
) {
1076 aligns
[x
] = alignment
;
1077 ast_copy_string(intro
[x
], v
->value
, sizeof(intro
[x
]));
1080 } else if (!strcasecmp(v
->name
, "maxretries")) {
1081 if (atoi(v
->value
) > 0)
1082 maxretries
= atoi(v
->value
);
1088 for (v
= ast_variable_browse(conf
, "speeddial"); v
; v
= v
->next
) {
1089 char *stringp
= v
->value
;
1090 name
= strsep(&stringp
, ",");
1091 sname
= strsep(&stringp
, ",");
1094 if (x
< ADSI_MAX_SPEED_DIAL
) {
1095 ast_copy_string(speeddial
[x
][0], v
->name
, sizeof(speeddial
[x
][0]));
1096 ast_copy_string(speeddial
[x
][1], name
, 18);
1097 ast_copy_string(speeddial
[x
][2], sname
, 7);
1103 ast_config_destroy(conf
);
1107 static int reload(void)
1113 static int load_module(void)
1119 static int unload_module(void)
1121 /* Can't unload this once we're loaded */
1125 AST_MODULE_INFO(ASTERISK_GPL_KEY
, AST_MODFLAG_GLOBAL_SYMBOLS
, "ADSI Resource",
1126 .load
= load_module
,
1127 .unload
= unload_module
,