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