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