00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037 #include "asterisk.h"
00038
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 328209 $")
00040
00041 #include <time.h>
00042 #include <math.h>
00043
00044 #include "asterisk/ulaw.h"
00045 #include "asterisk/alaw.h"
00046 #include "asterisk/callerid.h"
00047 #include "asterisk/fskmodem.h"
00048 #include "asterisk/channel.h"
00049 #include "asterisk/module.h"
00050 #include "asterisk/config.h"
00051 #include "asterisk/file.h"
00052
00053 #define AST_API_MODULE
00054 #include "asterisk/adsi.h"
00055
00056 #define DEFAULT_ADSI_MAX_RETRIES 3
00057
00058 #define ADSI_MAX_INTRO 20
00059 #define ADSI_MAX_SPEED_DIAL 6
00060
00061 #define ADSI_FLAG_DATAMODE (1 << 8)
00062
00063 static int maxretries = DEFAULT_ADSI_MAX_RETRIES;
00064
00065
00066 #define ADSI_SPEED_DIAL 10
00067
00068 static char intro[ADSI_MAX_INTRO][20];
00069 static int aligns[ADSI_MAX_INTRO];
00070
00071 #define SPEEDDIAL_MAX_LEN 20
00072 static char speeddial[ADSI_MAX_SPEED_DIAL][3][SPEEDDIAL_MAX_LEN];
00073
00074 static int alignment = 0;
00075
00076 static int adsi_generate(unsigned char *buf, int msgtype, unsigned char *msg, int msglen, int msgnum, int last, format_t codec)
00077 {
00078 int sum, x, bytes = 0;
00079
00080 float cr = 1.0, ci = 0.0, scont = 0.0;
00081
00082 if (msglen > 255) {
00083 msglen = 255;
00084 }
00085
00086
00087 if (msgnum == 1) {
00088 for (x = 0; x < 150; x++) {
00089 PUT_CLID_MARKMS;
00090 }
00091 }
00092
00093
00094 PUT_CLID(msgtype);
00095 sum = msgtype;
00096
00097
00098 PUT_CLID(msglen + 1);
00099 sum += msglen + 1;
00100
00101
00102 PUT_CLID(msgnum);
00103 sum += msgnum;
00104
00105
00106 for (x = 0; x < msglen; x++) {
00107 PUT_CLID(msg[x]);
00108 sum += msg[x];
00109 }
00110
00111
00112 PUT_CLID(256-(sum & 0xff));
00113
00114 #if 0
00115 if (last) {
00116
00117 for (x = 0; x < 50; x++) {
00118 PUT_CLID_MARKMS;
00119 }
00120 }
00121 #endif
00122 return bytes;
00123
00124 }
00125
00126 static int adsi_careful_send(struct ast_channel *chan, unsigned char *buf, int len, int *remain)
00127 {
00128
00129
00130 struct ast_frame *inf, outf;
00131 int amt;
00132
00133
00134 memset(&outf, 0, sizeof(outf));
00135
00136 if (remain && *remain) {
00137 amt = len;
00138
00139
00140 if (amt > *remain) {
00141 amt = *remain;
00142 } else {
00143 *remain = *remain - amt;
00144 }
00145 outf.frametype = AST_FRAME_VOICE;
00146 outf.subclass.codec = AST_FORMAT_ULAW;
00147 outf.data.ptr = buf;
00148 outf.datalen = amt;
00149 outf.samples = amt;
00150 if (ast_write(chan, &outf)) {
00151 ast_log(LOG_WARNING, "Failed to carefully write frame\n");
00152 return -1;
00153 }
00154
00155 buf += amt;
00156 len -= amt;
00157 }
00158
00159 while (len) {
00160 amt = len;
00161
00162
00163 if (ast_waitfor(chan, 1000) < 1) {
00164 return -1;
00165 }
00166
00167 if (!(inf = ast_read(chan))) {
00168 return -1;
00169 }
00170
00171
00172 if (inf->frametype != AST_FRAME_VOICE) {
00173 ast_frfree(inf);
00174 continue;
00175 }
00176
00177 if (inf->subclass.codec != AST_FORMAT_ULAW) {
00178 ast_log(LOG_WARNING, "Channel not in ulaw?\n");
00179 ast_frfree(inf);
00180 return -1;
00181 }
00182
00183 if (amt > inf->datalen) {
00184 amt = inf->datalen;
00185 } else if (remain) {
00186 *remain = inf->datalen - amt;
00187 }
00188 outf.frametype = AST_FRAME_VOICE;
00189 outf.subclass.codec = AST_FORMAT_ULAW;
00190 outf.data.ptr = buf;
00191 outf.datalen = amt;
00192 outf.samples = amt;
00193 if (ast_write(chan, &outf)) {
00194 ast_log(LOG_WARNING, "Failed to carefully write frame\n");
00195 ast_frfree(inf);
00196 return -1;
00197 }
00198
00199 buf += amt;
00200 len -= amt;
00201 ast_frfree(inf);
00202 }
00203 return 0;
00204 }
00205
00206 static int __adsi_transmit_messages(struct ast_channel *chan, unsigned char **msg, int *msglen, int *msgtype)
00207 {
00208
00209 unsigned char buf[24000 * 5];
00210 int pos = 0, res, x, start = 0, retries = 0, waittime, rem = 0, def;
00211 char ack[3];
00212 struct ast_frame *f;
00213
00214 if (chan->adsicpe == AST_ADSI_UNAVAILABLE) {
00215
00216 errno = ENOSYS;
00217 return -1;
00218 }
00219
00220 while (retries < maxretries) {
00221 if (!(chan->adsicpe & ADSI_FLAG_DATAMODE)) {
00222
00223 ast_gen_cas(buf, 0, 680, AST_FORMAT_ULAW);
00224
00225
00226 if (adsi_careful_send(chan, buf, 680, NULL)) {
00227 ast_log(LOG_WARNING, "Unable to send CAS\n");
00228 }
00229
00230
00231 waittime = 500;
00232 for (;;) {
00233 if (((res = ast_waitfor(chan, waittime)) < 1)) {
00234
00235 ast_debug(1, "No ADSI CPE detected (%d)\n", res);
00236 if (!chan->adsicpe) {
00237 chan->adsicpe = AST_ADSI_UNAVAILABLE;
00238 }
00239 errno = ENOSYS;
00240 return -1;
00241 }
00242 waittime = res;
00243 if (!(f = ast_read(chan))) {
00244 ast_debug(1, "Hangup in ADSI\n");
00245 return -1;
00246 }
00247 if (f->frametype == AST_FRAME_DTMF) {
00248 if (f->subclass.integer == 'A') {
00249
00250 if (!chan->adsicpe) {
00251 chan->adsicpe = AST_ADSI_AVAILABLE;
00252 }
00253 break;
00254 } else {
00255 if (f->subclass.integer == 'D') {
00256 ast_debug(1, "Off-hook capable CPE only, not ADSI\n");
00257 } else {
00258 ast_log(LOG_WARNING, "Unknown ADSI response '%c'\n", f->subclass.integer);
00259 }
00260 if (!chan->adsicpe) {
00261 chan->adsicpe = AST_ADSI_UNAVAILABLE;
00262 }
00263 errno = ENOSYS;
00264 ast_frfree(f);
00265 return -1;
00266 }
00267 }
00268 ast_frfree(f);
00269 }
00270
00271 ast_debug(1, "ADSI Compatible CPE Detected\n");
00272 } else {
00273 ast_debug(1, "Already in data mode\n");
00274 }
00275
00276 x = 0;
00277 pos = 0;
00278 #if 1
00279 def= ast_channel_defer_dtmf(chan);
00280 #endif
00281 while ((x < 6) && msg[x]) {
00282 if ((res = adsi_generate(buf + pos, msgtype[x], msg[x], msglen[x], x+1 - start, (x == 5) || !msg[x+1], AST_FORMAT_ULAW)) < 0) {
00283 ast_log(LOG_WARNING, "Failed to generate ADSI message %d on channel %s\n", x + 1, chan->name);
00284 return -1;
00285 }
00286 ast_debug(1, "Message %d, of %d input bytes, %d output bytes\n", x + 1, msglen[x], res);
00287 pos += res;
00288 x++;
00289 }
00290
00291
00292 rem = 0;
00293 res = adsi_careful_send(chan, buf, pos, &rem);
00294 if (!def) {
00295 ast_channel_undefer_dtmf(chan);
00296 }
00297 if (res) {
00298 return -1;
00299 }
00300
00301 ast_debug(1, "Sent total spill of %d bytes\n", pos);
00302
00303 memset(ack, 0, sizeof(ack));
00304
00305 if ((res = ast_readstring(chan, ack, 2, 1000, 1000, "")) < 0) {
00306 return -1;
00307 }
00308 if (ack[0] == 'D') {
00309 ast_debug(1, "Acked up to message %d\n", atoi(ack + 1)); start += atoi(ack + 1);
00310 if (start >= x) {
00311 break;
00312 } else {
00313 retries++;
00314 ast_debug(1, "Retransmitting (%d), from %d\n", retries, start + 1);
00315 }
00316 } else {
00317 retries++;
00318 ast_log(LOG_WARNING, "Unexpected response to ack: %s (retry %d)\n", ack, retries);
00319 }
00320 }
00321 if (retries >= maxretries) {
00322 ast_log(LOG_WARNING, "Maximum ADSI Retries (%d) exceeded\n", maxretries);
00323 errno = ETIMEDOUT;
00324 return -1;
00325 }
00326 return 0;
00327 }
00328
00329 int AST_OPTIONAL_API_NAME(ast_adsi_begin_download)(struct ast_channel *chan, char *service, unsigned char *fdn, unsigned char *sec, int version)
00330 {
00331 int bytes = 0;
00332 unsigned char buf[256];
00333 char ack[2];
00334
00335
00336
00337 bytes += ast_adsi_download_connect(buf + bytes, service, fdn, sec, version);
00338 if (ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DOWNLOAD, 0)) {
00339 return -1;
00340 }
00341 if (ast_readstring(chan, ack, 1, 10000, 10000, "")) {
00342 return -1;
00343 }
00344 if (ack[0] == 'B') {
00345 return 0;
00346 }
00347 ast_debug(1, "Download was denied by CPE\n");
00348 return -1;
00349 }
00350
00351 int AST_OPTIONAL_API_NAME(ast_adsi_end_download)(struct ast_channel *chan)
00352 {
00353 int bytes = 0;
00354 unsigned char buf[256];
00355
00356
00357
00358 bytes += ast_adsi_download_disconnect(buf + bytes);
00359 if (ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DOWNLOAD, 0)) {
00360 return -1;
00361 }
00362 return 0;
00363 }
00364
00365 int AST_OPTIONAL_API_NAME(ast_adsi_transmit_message_full)(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait)
00366 {
00367 unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL };
00368 int msglens[5], msgtypes[5], newdatamode = (chan->adsicpe & ADSI_FLAG_DATAMODE), res, x, writeformat = chan->writeformat, readformat = chan->readformat, waitforswitch = 0;
00369
00370 for (x = 0; x < msglen; x += (msg[x+1]+2)) {
00371 if (msg[x] == ADSI_SWITCH_TO_DATA) {
00372 ast_debug(1, "Switch to data is sent!\n");
00373 waitforswitch++;
00374 newdatamode = ADSI_FLAG_DATAMODE;
00375 }
00376
00377 if (msg[x] == ADSI_SWITCH_TO_VOICE) {
00378 ast_debug(1, "Switch to voice is sent!\n");
00379 waitforswitch++;
00380 newdatamode = 0;
00381 }
00382 }
00383 msgs[0] = msg;
00384
00385 msglens[0] = msglen;
00386 msgtypes[0] = msgtype;
00387
00388 if (msglen > 253) {
00389 ast_log(LOG_WARNING, "Can't send ADSI message of %d bytes, too large\n", msglen);
00390 return -1;
00391 }
00392
00393 ast_stopstream(chan);
00394
00395 if (ast_set_write_format(chan, AST_FORMAT_ULAW)) {
00396 ast_log(LOG_WARNING, "Unable to set write format to ULAW\n");
00397 return -1;
00398 }
00399
00400 if (ast_set_read_format(chan, AST_FORMAT_ULAW)) {
00401 ast_log(LOG_WARNING, "Unable to set read format to ULAW\n");
00402 if (writeformat) {
00403 if (ast_set_write_format(chan, writeformat)) {
00404 ast_log(LOG_WARNING, "Unable to restore write format to %d\n", writeformat);
00405 }
00406 }
00407 return -1;
00408 }
00409 res = __adsi_transmit_messages(chan, msgs, msglens, msgtypes);
00410
00411 if (dowait) {
00412 ast_debug(1, "Wait for switch is '%d'\n", waitforswitch);
00413 while (waitforswitch-- && ((res = ast_waitfordigit(chan, 1000)) > 0)) {
00414 res = 0;
00415 ast_debug(1, "Waiting for 'B'...\n");
00416 }
00417 }
00418
00419 if (!res) {
00420 chan->adsicpe = (chan->adsicpe & ~ADSI_FLAG_DATAMODE) | newdatamode;
00421 }
00422
00423 if (writeformat) {
00424 ast_set_write_format(chan, writeformat);
00425 }
00426 if (readformat) {
00427 ast_set_read_format(chan, readformat);
00428 }
00429
00430 if (!res) {
00431 res = ast_safe_sleep(chan, 100 );
00432 }
00433 return res;
00434 }
00435
00436 int AST_OPTIONAL_API_NAME(ast_adsi_transmit_message)(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype)
00437 {
00438 return ast_adsi_transmit_message_full(chan, msg, msglen, msgtype, 1);
00439 }
00440
00441 static inline int ccopy(unsigned char *dst, const unsigned char *src, int max)
00442 {
00443 int x = 0;
00444
00445 while ((x < max) && src[x] && (src[x] != 0xff)) {
00446 dst[x] = src[x];
00447 x++;
00448 }
00449 return x;
00450 }
00451
00452 int AST_OPTIONAL_API_NAME(ast_adsi_load_soft_key)(unsigned char *buf, int key, const char *llabel, const char *slabel, char *ret, int data)
00453 {
00454 int bytes = 0;
00455
00456
00457 if ((key < 2) || (key > 33)) {
00458 return -1;
00459 }
00460
00461 buf[bytes++] = ADSI_LOAD_SOFTKEY;
00462
00463 bytes++;
00464
00465 buf[bytes++] = key;
00466
00467
00468 bytes += ccopy(buf + bytes, (const unsigned char *)llabel, 18);
00469
00470
00471 buf[bytes++] = 0xff;
00472
00473
00474 bytes += ccopy(buf + bytes, (const unsigned char *)slabel, 7);
00475
00476
00477
00478 if (ret) {
00479
00480 buf[bytes++] = 0xff;
00481 if (data) {
00482 buf[bytes++] = ADSI_SWITCH_TO_DATA2;
00483 }
00484
00485 bytes += ccopy(buf + bytes, (const unsigned char *)ret, 20);
00486
00487 }
00488
00489 buf[1] = bytes - 2;
00490 return bytes;
00491 }
00492
00493 int AST_OPTIONAL_API_NAME(ast_adsi_connect_session)(unsigned char *buf, unsigned char *fdn, int ver)
00494 {
00495 int bytes = 0, x;
00496
00497
00498 buf[bytes++] = ADSI_CONNECT_SESSION;
00499
00500
00501 bytes++;
00502
00503 if (fdn) {
00504 for (x = 0; x < 4; x++) {
00505 buf[bytes++] = fdn[x];
00506 }
00507 if (ver > -1) {
00508 buf[bytes++] = ver & 0xff;
00509 }
00510 }
00511
00512 buf[1] = bytes - 2;
00513 return bytes;
00514
00515 }
00516
00517 int AST_OPTIONAL_API_NAME(ast_adsi_download_connect)(unsigned char *buf, char *service, unsigned char *fdn, unsigned char *sec, int ver)
00518 {
00519 int bytes = 0, x;
00520
00521
00522 buf[bytes++] = ADSI_DOWNLOAD_CONNECT;
00523
00524
00525 bytes++;
00526
00527
00528 bytes+= ccopy(buf + bytes, (unsigned char *)service, 18);
00529
00530
00531 buf[bytes++] = 0xff;
00532
00533 for (x = 0; x < 4; x++) {
00534 buf[bytes++] = fdn[x];
00535 }
00536
00537 for (x = 0; x < 4; x++) {
00538 buf[bytes++] = sec[x];
00539 }
00540
00541 buf[bytes++] = ver & 0xff;
00542
00543 buf[1] = bytes - 2;
00544
00545 return bytes;
00546
00547 }
00548
00549 int AST_OPTIONAL_API_NAME(ast_adsi_disconnect_session)(unsigned char *buf)
00550 {
00551 int bytes = 0;
00552
00553
00554 buf[bytes++] = ADSI_DISC_SESSION;
00555
00556
00557 bytes++;
00558
00559 buf[1] = bytes - 2;
00560 return bytes;
00561
00562 }
00563
00564 int AST_OPTIONAL_API_NAME(ast_adsi_query_cpeid)(unsigned char *buf)
00565 {
00566 int bytes = 0;
00567 buf[bytes++] = ADSI_QUERY_CPEID;
00568
00569 bytes++;
00570 buf[1] = bytes - 2;
00571 return bytes;
00572 }
00573
00574 int AST_OPTIONAL_API_NAME(ast_adsi_query_cpeinfo)(unsigned char *buf)
00575 {
00576 int bytes = 0;
00577 buf[bytes++] = ADSI_QUERY_CONFIG;
00578
00579 bytes++;
00580 buf[1] = bytes - 2;
00581 return bytes;
00582 }
00583
00584 int AST_OPTIONAL_API_NAME(ast_adsi_read_encoded_dtmf)(struct ast_channel *chan, unsigned char *buf, int maxlen)
00585 {
00586 int bytes = 0, res, gotstar = 0, pos = 0;
00587 unsigned char current = 0;
00588
00589 memset(buf, 0, sizeof(buf));
00590
00591 while (bytes <= maxlen) {
00592
00593 if (!(res = ast_waitfordigit(chan, 1000))) {
00594 break;
00595 }
00596 if (res == '*') {
00597 gotstar = 1;
00598 continue;
00599 }
00600
00601 if ((res < '0') || (res > '9')) {
00602 continue;
00603 }
00604 res -= '0';
00605 if (gotstar) {
00606 res += 9;
00607 }
00608 if (pos) {
00609 pos = 0;
00610 buf[bytes++] = (res << 4) | current;
00611 } else {
00612 pos = 1;
00613 current = res;
00614 }
00615 gotstar = 0;
00616 }
00617
00618 return bytes;
00619 }
00620
00621 int AST_OPTIONAL_API_NAME(ast_adsi_get_cpeid)(struct ast_channel *chan, unsigned char *cpeid, int voice)
00622 {
00623 unsigned char buf[256] = "";
00624 int bytes = 0, res;
00625
00626 bytes += ast_adsi_data_mode(buf);
00627 ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
00628
00629 bytes = 0;
00630 bytes += ast_adsi_query_cpeid(buf);
00631 ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
00632
00633
00634 res = ast_adsi_read_encoded_dtmf(chan, cpeid, 4);
00635 if (res != 4) {
00636 ast_log(LOG_WARNING, "Got %d bytes back of encoded DTMF, expecting 4\n", res);
00637 res = 0;
00638 } else {
00639 res = 1;
00640 }
00641
00642 if (voice) {
00643 bytes = 0;
00644 bytes += ast_adsi_voice_mode(buf, 0);
00645 ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
00646
00647 ast_waitfordigit(chan, 1000);
00648 }
00649 return res;
00650 }
00651
00652 int AST_OPTIONAL_API_NAME(ast_adsi_get_cpeinfo)(struct ast_channel *chan, int *width, int *height, int *buttons, int voice)
00653 {
00654 unsigned char buf[256] = "";
00655 int bytes = 0, res;
00656
00657 bytes += ast_adsi_data_mode(buf);
00658 ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
00659
00660 bytes = 0;
00661 bytes += ast_adsi_query_cpeinfo(buf);
00662 ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
00663
00664
00665 if ((res = ast_readstring(chan, (char *) buf, 2, 1000, 500, "")) < 0) {
00666 return res;
00667 }
00668 if (strlen((char *) buf) != 2) {
00669 ast_log(LOG_WARNING, "Got %d bytes of width, expecting 2\n", res);
00670 res = 0;
00671 } else {
00672 res = 1;
00673 }
00674 if (width) {
00675 *width = atoi((char *) buf);
00676 }
00677
00678 memset(buf, 0, sizeof(buf));
00679 if (res) {
00680 if ((res = ast_readstring(chan, (char *) buf, 2, 1000, 500, "")) < 0) {
00681 return res;
00682 }
00683 if (strlen((char *) buf) != 2) {
00684 ast_log(LOG_WARNING, "Got %d bytes of height, expecting 2\n", res);
00685 res = 0;
00686 } else {
00687 res = 1;
00688 }
00689 if (height) {
00690 *height = atoi((char *) buf);
00691 }
00692 }
00693
00694 memset(buf, 0, sizeof(buf));
00695 if (res) {
00696 if ((res = ast_readstring(chan, (char *) buf, 1, 1000, 500, "")) < 0) {
00697 return res;
00698 }
00699 if (strlen((char *) buf) != 1) {
00700 ast_log(LOG_WARNING, "Got %d bytes of buttons, expecting 1\n", res);
00701 res = 0;
00702 } else {
00703 res = 1;
00704 }
00705 if (buttons) {
00706 *buttons = atoi((char *) buf);
00707 }
00708 }
00709 if (voice) {
00710 bytes = 0;
00711 bytes += ast_adsi_voice_mode(buf, 0);
00712 ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
00713
00714 ast_waitfordigit(chan, 1000);
00715 }
00716 return res;
00717 }
00718
00719 int AST_OPTIONAL_API_NAME(ast_adsi_data_mode)(unsigned char *buf)
00720 {
00721 int bytes = 0;
00722
00723
00724 buf[bytes++] = ADSI_SWITCH_TO_DATA;
00725
00726
00727 bytes++;
00728
00729 buf[1] = bytes - 2;
00730 return bytes;
00731
00732 }
00733
00734 int AST_OPTIONAL_API_NAME(ast_adsi_clear_soft_keys)(unsigned char *buf)
00735 {
00736 int bytes = 0;
00737
00738
00739 buf[bytes++] = ADSI_CLEAR_SOFTKEY;
00740
00741
00742 bytes++;
00743
00744 buf[1] = bytes - 2;
00745 return bytes;
00746
00747 }
00748
00749 int AST_OPTIONAL_API_NAME(ast_adsi_clear_screen)(unsigned char *buf)
00750 {
00751 int bytes = 0;
00752
00753
00754 buf[bytes++] = ADSI_CLEAR_SCREEN;
00755
00756
00757 bytes++;
00758
00759 buf[1] = bytes - 2;
00760 return bytes;
00761
00762 }
00763
00764 int AST_OPTIONAL_API_NAME(ast_adsi_voice_mode)(unsigned char *buf, int when)
00765 {
00766 int bytes = 0;
00767
00768
00769 buf[bytes++] = ADSI_SWITCH_TO_VOICE;
00770
00771
00772 bytes++;
00773
00774 buf[bytes++] = when & 0x7f;
00775
00776 buf[1] = bytes - 2;
00777 return bytes;
00778
00779 }
00780
00781 int AST_OPTIONAL_API_NAME(ast_adsi_available)(struct ast_channel *chan)
00782 {
00783 int cpe = chan->adsicpe & 0xff;
00784 if ((cpe == AST_ADSI_AVAILABLE) ||
00785 (cpe == AST_ADSI_UNKNOWN)) {
00786 return 1;
00787 }
00788 return 0;
00789 }
00790
00791 int AST_OPTIONAL_API_NAME(ast_adsi_download_disconnect)(unsigned char *buf)
00792 {
00793 int bytes = 0;
00794
00795
00796 buf[bytes++] = ADSI_DOWNLOAD_DISC;
00797
00798
00799 bytes++;
00800
00801 buf[1] = bytes - 2;
00802 return bytes;
00803
00804 }
00805
00806 int AST_OPTIONAL_API_NAME(ast_adsi_display)(unsigned char *buf, int page, int line, int just, int wrap,
00807 char *col1, char *col2)
00808 {
00809 int bytes = 0;
00810
00811
00812
00813 if (page) {
00814 if (line > 4) return -1;
00815 } else {
00816 if (line > 33) return -1;
00817 }
00818
00819 if (line < 1) {
00820 return -1;
00821 }
00822
00823 buf[bytes++] = ADSI_LOAD_VIRTUAL_DISP;
00824
00825
00826 bytes++;
00827
00828
00829 buf[bytes++] = ((page & 0x1) << 7) | ((wrap & 0x1) << 6) | (line & 0x3f);
00830
00831
00832 buf[bytes++] = (just & 0x3) << 5;
00833
00834
00835 buf[bytes++] = 0xff;
00836
00837
00838 bytes+= ccopy(buf + bytes, (unsigned char *)col1, 20);
00839
00840
00841 buf[bytes++] = 0xff;
00842
00843
00844 bytes += ccopy(buf + bytes, (unsigned char *)col2, 20);
00845
00846
00847 buf[1] = bytes - 2;
00848
00849 return bytes;
00850
00851 }
00852
00853 int AST_OPTIONAL_API_NAME(ast_adsi_input_control)(unsigned char *buf, int page, int line, int display, int format, int just)
00854 {
00855 int bytes = 0;
00856
00857 if (page) {
00858 if (line > 4) return -1;
00859 } else {
00860 if (line > 33) return -1;
00861 }
00862
00863 if (line < 1) {
00864 return -1;
00865 }
00866
00867 buf[bytes++] = ADSI_INPUT_CONTROL;
00868 bytes++;
00869 buf[bytes++] = ((page & 1) << 7) | (line & 0x3f);
00870 buf[bytes++] = ((display & 1) << 7) | ((just & 0x3) << 4) | (format & 0x7);
00871
00872 buf[1] = bytes - 2;
00873 return bytes;
00874 }
00875
00876 int AST_OPTIONAL_API_NAME(ast_adsi_input_format)(unsigned char *buf, int num, int dir, int wrap, char *format1, char *format2)
00877 {
00878 int bytes = 0;
00879
00880 if (ast_strlen_zero((char *) format1)) {
00881 return -1;
00882 }
00883
00884 buf[bytes++] = ADSI_INPUT_FORMAT;
00885 bytes++;
00886 buf[bytes++] = ((dir & 1) << 7) | ((wrap & 1) << 6) | (num & 0x7);
00887 bytes += ccopy(buf + bytes, (unsigned char *) format1, 20);
00888 buf[bytes++] = 0xff;
00889 if (!ast_strlen_zero(format2)) {
00890 bytes += ccopy(buf + bytes, (unsigned char *) format2, 20);
00891 }
00892 buf[1] = bytes - 2;
00893 return bytes;
00894 }
00895
00896 int AST_OPTIONAL_API_NAME(ast_adsi_set_keys)(unsigned char *buf, unsigned char *keys)
00897 {
00898 int bytes = 0, x;
00899
00900
00901 buf[bytes++] = ADSI_INIT_SOFTKEY_LINE;
00902
00903 bytes++;
00904
00905 for (x = 0; x < 6; x++) {
00906 buf[bytes++] = (keys[x] & 0x3f) ? keys[x] : (keys[x] | 0x1);
00907 }
00908 buf[1] = bytes - 2;
00909 return bytes;
00910 }
00911
00912 int AST_OPTIONAL_API_NAME(ast_adsi_set_line)(unsigned char *buf, int page, int line)
00913 {
00914 int bytes = 0;
00915
00916
00917
00918 if (page) {
00919 if (line > 4) return -1;
00920 } else {
00921 if (line > 33) return -1;
00922 }
00923
00924 if (line < 1) {
00925 return -1;
00926 }
00927
00928 buf[bytes++] = ADSI_LINE_CONTROL;
00929
00930
00931 bytes++;
00932
00933
00934 buf[bytes++] = ((page & 0x1) << 7) | (line & 0x3f);
00935
00936 buf[1] = bytes - 2;
00937 return bytes;
00938 }
00939
00940 static int total = 0;
00941 static int speeds = 0;
00942
00943 int AST_OPTIONAL_API_NAME(ast_adsi_channel_restore)(struct ast_channel *chan)
00944 {
00945 unsigned char dsp[256] = "", keyd[6] = "";
00946 int bytes, x;
00947
00948
00949 bytes = 0;
00950 bytes += ast_adsi_set_line(dsp + bytes, ADSI_INFO_PAGE, 1);
00951
00952
00953
00954 if (speeds) {
00955 for (x = 0; x < speeds; x++) {
00956 keyd[x] = ADSI_SPEED_DIAL + x;
00957 }
00958 bytes += ast_adsi_set_keys(dsp + bytes, keyd);
00959 }
00960 ast_adsi_transmit_message_full(chan, dsp, bytes, ADSI_MSG_DISPLAY, 0);
00961 return 0;
00962
00963 }
00964
00965 int AST_OPTIONAL_API_NAME(ast_adsi_print)(struct ast_channel *chan, char **lines, int *alignments, int voice)
00966 {
00967 unsigned char buf[4096];
00968 int bytes = 0, res, x;
00969
00970 for (x = 0; lines[x]; x++) {
00971 bytes += ast_adsi_display(buf + bytes, ADSI_INFO_PAGE, x+1, alignments[x], 0, lines[x], "");
00972 }
00973 bytes += ast_adsi_set_line(buf + bytes, ADSI_INFO_PAGE, 1);
00974 if (voice) {
00975 bytes += ast_adsi_voice_mode(buf + bytes, 0);
00976 }
00977 res = ast_adsi_transmit_message_full(chan, buf, bytes, ADSI_MSG_DISPLAY, 0);
00978 if (voice) {
00979
00980 ast_waitfordigit(chan, 1000);
00981 }
00982 return res;
00983 }
00984
00985 int AST_OPTIONAL_API_NAME(ast_adsi_load_session)(struct ast_channel *chan, unsigned char *app, int ver, int data)
00986 {
00987 unsigned char dsp[256] = "";
00988 int bytes = 0, res;
00989 char resp[2];
00990
00991
00992 bytes += ast_adsi_connect_session(dsp + bytes, app, ver);
00993
00994 if (data) {
00995 bytes += ast_adsi_data_mode(dsp + bytes);
00996 }
00997
00998
00999 if (ast_adsi_transmit_message_full(chan, dsp, bytes, ADSI_MSG_DISPLAY, 0)) {
01000 return -1;
01001 }
01002 if (app) {
01003 if ((res = ast_readstring(chan, resp, 1, 1200, 1200, "")) < 0) {
01004 return -1;
01005 }
01006 if (res) {
01007 ast_debug(1, "No response from CPE about version. Assuming not there.\n");
01008 return 0;
01009 }
01010 if (!strcmp(resp, "B")) {
01011 ast_debug(1, "CPE has script '%s' version %d already loaded\n", app, ver);
01012 return 1;
01013 } else if (!strcmp(resp, "A")) {
01014 ast_debug(1, "CPE hasn't script '%s' version %d already loaded\n", app, ver);
01015 } else {
01016 ast_log(LOG_WARNING, "Unexpected CPE response to script query: %s\n", resp);
01017 }
01018 } else
01019 return 1;
01020 return 0;
01021
01022 }
01023
01024 int AST_OPTIONAL_API_NAME(ast_adsi_unload_session)(struct ast_channel *chan)
01025 {
01026 unsigned char dsp[256] = "";
01027 int bytes = 0;
01028
01029
01030 bytes += ast_adsi_disconnect_session(dsp + bytes);
01031 bytes += ast_adsi_voice_mode(dsp + bytes, 0);
01032
01033
01034 if (ast_adsi_transmit_message_full(chan, dsp, bytes, ADSI_MSG_DISPLAY, 0)) {
01035 return -1;
01036 }
01037
01038 return 0;
01039 }
01040
01041 static int str2align(const char *s)
01042 {
01043 if (!strncasecmp(s, "l", 1)) {
01044 return ADSI_JUST_LEFT;
01045 } else if (!strncasecmp(s, "r", 1)) {
01046 return ADSI_JUST_RIGHT;
01047 } else if (!strncasecmp(s, "i", 1)) {
01048 return ADSI_JUST_IND;
01049 } else {
01050 return ADSI_JUST_CENT;
01051 }
01052 }
01053
01054 static void init_state(void)
01055 {
01056 int x;
01057
01058 for (x = 0; x < ADSI_MAX_INTRO; x++) {
01059 aligns[x] = ADSI_JUST_CENT;
01060 }
01061 ast_copy_string(intro[0], "Welcome to the", sizeof(intro[0]));
01062 ast_copy_string(intro[1], "Asterisk", sizeof(intro[1]));
01063 ast_copy_string(intro[2], "Open Source PBX", sizeof(intro[2]));
01064 total = 3;
01065 speeds = 0;
01066 for (x = 3; x < ADSI_MAX_INTRO; x++) {
01067 intro[x][0] = '\0';
01068 }
01069 memset(speeddial, 0, sizeof(speeddial));
01070 alignment = ADSI_JUST_CENT;
01071 }
01072
01073 static void adsi_load(int reload)
01074 {
01075 int x = 0;
01076 struct ast_config *conf = NULL;
01077 struct ast_variable *v;
01078 struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
01079 char *name, *sname;
01080 init_state();
01081
01082 conf = ast_config_load("adsi.conf", config_flags);
01083 if (conf == CONFIG_STATUS_FILEMISSING || conf == CONFIG_STATUS_FILEUNCHANGED || conf == CONFIG_STATUS_FILEINVALID) {
01084 return;
01085 }
01086 for (v = ast_variable_browse(conf, "intro"); v; v = v->next) {
01087 if (!strcasecmp(v->name, "alignment")) {
01088 alignment = str2align(v->value);
01089 } else if (!strcasecmp(v->name, "greeting")) {
01090 if (x < ADSI_MAX_INTRO) {
01091 aligns[x] = alignment;
01092 ast_copy_string(intro[x], v->value, sizeof(intro[x]));
01093 x++;
01094 }
01095 } else if (!strcasecmp(v->name, "maxretries")) {
01096 if (atoi(v->value) > 0) {
01097 maxretries = atoi(v->value);
01098 }
01099 }
01100 }
01101 if (x) {
01102 total = x;
01103 }
01104
01105 x = 0;
01106 for (v = ast_variable_browse(conf, "speeddial"); v; v = v->next) {
01107 char buf[3 * SPEEDDIAL_MAX_LEN];
01108 char *stringp = buf;
01109 ast_copy_string(buf, v->value, sizeof(buf));
01110 name = strsep(&stringp, ",");
01111 sname = strsep(&stringp, ",");
01112 if (!sname) {
01113 sname = name;
01114 }
01115 if (x < ADSI_MAX_SPEED_DIAL) {
01116 ast_copy_string(speeddial[x][0], v->name, sizeof(speeddial[x][0]));
01117 ast_copy_string(speeddial[x][1], name, 18);
01118 ast_copy_string(speeddial[x][2], sname, 7);
01119 x++;
01120 }
01121 }
01122 if (x) {
01123 speeds = x;
01124 }
01125 ast_config_destroy(conf);
01126
01127 return;
01128 }
01129
01130 static int reload(void)
01131 {
01132 adsi_load(1);
01133 return 0;
01134 }
01135
01136 static int load_module(void)
01137 {
01138 adsi_load(0);
01139 return AST_MODULE_LOAD_SUCCESS;
01140 }
01141
01142 static int unload_module(void)
01143 {
01144
01145 return -1;
01146 }
01147
01148 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS | AST_MODFLAG_LOAD_ORDER, "ADSI Resource",
01149 .load = load_module,
01150 .unload = unload_module,
01151 .reload = reload,
01152 .load_pri = AST_MODPRI_APP_DEPEND,
01153 );