Sat Mar 10 01:54:22 2012

Asterisk developer's documentation


res_adsi.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2005, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * Includes code and algorithms from the Zapata library.
00009  *
00010  * See http://www.asterisk.org for more information about
00011  * the Asterisk project. Please do not directly contact
00012  * any of the maintainers of this project for assistance;
00013  * the project provides a web site, mailing lists and IRC
00014  * channels for your use.
00015  *
00016  * This program is free software, distributed under the terms of
00017  * the GNU General Public License Version 2. See the LICENSE file
00018  * at the top of the source tree.
00019  */
00020 
00021 /*! \file
00022  *
00023  * \brief ADSI support
00024  *
00025  * \author Mark Spencer <markster@digium.com>
00026  *
00027  * \note this module is required by app_voicemail and app_getcpeid
00028  * \todo Move app_getcpeid into this module
00029  * \todo Create a core layer so that app_voicemail does not require
00030  *    res_adsi to load
00031  */
00032 
00033 /*** MODULEINFO
00034    <support_level>extended</support_level>
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 /* Asterisk ADSI button definitions */
00066 #define ADSI_SPEED_DIAL    10 /* 10-15 are reserved for speed dial */
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    /* Initial carrier (imaginary) */
00080    float cr = 1.0, ci = 0.0, scont = 0.0;
00081 
00082    if (msglen > 255) {
00083       msglen = 255;
00084    }
00085 
00086    /* If first message, Send 150ms of MARK's */
00087    if (msgnum == 1) {
00088       for (x = 0; x < 150; x++) { /* was 150 */
00089          PUT_CLID_MARKMS;
00090       }
00091    }
00092 
00093    /* Put message type */
00094    PUT_CLID(msgtype);
00095    sum = msgtype;
00096 
00097    /* Put message length (plus one for the message number) */
00098    PUT_CLID(msglen + 1);
00099    sum += msglen + 1;
00100 
00101    /* Put message number */
00102    PUT_CLID(msgnum);
00103    sum += msgnum;
00104 
00105    /* Put actual message */
00106    for (x = 0; x < msglen; x++) {
00107       PUT_CLID(msg[x]);
00108       sum += msg[x];
00109    }
00110 
00111    /* Put 2's compliment of sum */
00112    PUT_CLID(256-(sum & 0xff));
00113 
00114 #if 0
00115    if (last) {
00116       /* Put trailing marks */
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    /* Sends carefully on a full duplex channel by using reading for
00129       timing */
00130    struct ast_frame *inf, outf;
00131    int amt;
00132 
00133    /* Zero out our outgoing frame */
00134    memset(&outf, 0, sizeof(outf));
00135 
00136    if (remain && *remain) {
00137       amt = len;
00138 
00139       /* Send remainder if provided */
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       /* Update pointers and lengths */
00155       buf += amt;
00156       len -= amt;
00157    }
00158 
00159    while (len) {
00160       amt = len;
00161       /* If we don't get anything at all back in a second, forget
00162          about it */
00163       if (ast_waitfor(chan, 1000) < 1) {
00164          return -1;
00165       }
00166       /* Detect hangup */
00167       if (!(inf = ast_read(chan))) {
00168          return -1;
00169       }
00170 
00171       /* Drop any frames that are not voice */
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       /* Send no more than they sent us */
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       /* Update pointers and lengths */
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    /* msglen must be no more than 256 bits, each */
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       /* Don't bother if we know they don't support ADSI */
00216       errno = ENOSYS;
00217       return -1;
00218    }
00219 
00220    while (retries < maxretries) {
00221       if (!(chan->adsicpe & ADSI_FLAG_DATAMODE)) {
00222          /* Generate CAS (no SAS) */
00223          ast_gen_cas(buf, 0, 680, AST_FORMAT_ULAW);
00224 
00225          /* Send CAS */
00226          if (adsi_careful_send(chan, buf, 680, NULL)) {
00227             ast_log(LOG_WARNING, "Unable to send CAS\n");
00228          }
00229 
00230          /* Wait For DTMF result */
00231          waittime = 500;
00232          for (;;) {
00233             if (((res = ast_waitfor(chan, waittime)) < 1)) {
00234                /* Didn't get back DTMF A in time */
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                   /* Okay, this is an ADSI CPE.  Note this for future reference, too */
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       /* Get real result and check for hangup */
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    /* Setup the resident soft key stuff, a piece at a time */
00336    /* Upload what scripts we can for voicemail ahead of time */
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    /* Setup the resident soft key stuff, a piece at a time */
00357    /* Upload what scripts we can for voicemail ahead of time */
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    /* Carefully copy the requested data */
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    /* Abort if invalid key specified */
00457    if ((key < 2) || (key > 33)) {
00458       return -1;
00459    }
00460 
00461    buf[bytes++] = ADSI_LOAD_SOFTKEY;
00462    /* Reserve for length */
00463    bytes++;
00464    /* Which key */
00465    buf[bytes++] = key;
00466 
00467    /* Carefully copy long label */
00468    bytes += ccopy(buf + bytes, (const unsigned char *)llabel, 18);
00469 
00470    /* Place delimiter */
00471    buf[bytes++] = 0xff;
00472 
00473    /* Short label */
00474    bytes += ccopy(buf + bytes, (const unsigned char *)slabel, 7);
00475 
00476 
00477    /* If specified, copy return string */
00478    if (ret) {
00479       /* Place delimiter */
00480       buf[bytes++] = 0xff;
00481       if (data) {
00482          buf[bytes++] = ADSI_SWITCH_TO_DATA2;
00483       }
00484       /* Carefully copy return string */
00485       bytes += ccopy(buf + bytes, (const unsigned char *)ret, 20);
00486 
00487    }
00488    /* Replace parameter length */
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    /* Message type */
00498    buf[bytes++] = ADSI_CONNECT_SESSION;
00499 
00500    /* Reserve space for length */
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    /* Message type */
00522    buf[bytes++] = ADSI_DOWNLOAD_CONNECT;
00523 
00524    /* Reserve space for length */
00525    bytes++;
00526 
00527    /* Primary column */
00528    bytes+= ccopy(buf + bytes, (unsigned char *)service, 18);
00529 
00530    /* Delimiter */
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    /* Message type */
00554    buf[bytes++] = ADSI_DISC_SESSION;
00555 
00556    /* Reserve space for length */
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    /* Reserve space for length */
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    /* Reserve space for length */
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       /* Wait up to a second for a digit */
00593       if (!(res = ast_waitfordigit(chan, 1000))) {
00594          break;
00595       }
00596       if (res == '*') {
00597          gotstar = 1;
00598          continue;
00599       }
00600       /* Ignore anything other than a digit */
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    /* Get response */
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       /* Ignore the resulting DTMF B announcing it's in voice mode */
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    /* Get width */
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    /* Get height */
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    /* Get buttons */
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       /* Ignore the resulting DTMF B announcing it's in voice mode */
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    /* Message type */
00724    buf[bytes++] = ADSI_SWITCH_TO_DATA;
00725 
00726    /* Reserve space for length */
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    /* Message type */
00739    buf[bytes++] = ADSI_CLEAR_SOFTKEY;
00740 
00741    /* Reserve space for length */
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    /* Message type */
00754    buf[bytes++] = ADSI_CLEAR_SCREEN;
00755 
00756    /* Reserve space for length */
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    /* Message type */
00769    buf[bytes++] = ADSI_SWITCH_TO_VOICE;
00770 
00771    /* Reserve space for length */
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    /* Message type */
00796    buf[bytes++] = ADSI_DOWNLOAD_DISC;
00797 
00798    /* Reserve space for length */
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    /* Sanity check line number */
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    /* Parameter type */
00823    buf[bytes++] = ADSI_LOAD_VIRTUAL_DISP;
00824 
00825    /* Reserve space for size */
00826    bytes++;
00827 
00828    /* Page and wrap indicator */
00829    buf[bytes++] = ((page & 0x1) << 7) | ((wrap & 0x1) << 6) | (line & 0x3f);
00830 
00831    /* Justification */
00832    buf[bytes++] = (just & 0x3) << 5;
00833 
00834    /* Omit highlight mode definition */
00835    buf[bytes++] = 0xff;
00836 
00837    /* Primary column */
00838    bytes+= ccopy(buf + bytes, (unsigned char *)col1, 20);
00839 
00840    /* Delimiter */
00841    buf[bytes++] = 0xff;
00842 
00843    /* Secondary column */
00844    bytes += ccopy(buf + bytes, (unsigned char *)col2, 20);
00845 
00846    /* Update length */
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    /* Message type */
00901    buf[bytes++] = ADSI_INIT_SOFTKEY_LINE;
00902    /* Space for size */
00903    bytes++;
00904    /* Key definitions */
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    /* Sanity check line number */
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    /* Parameter type */
00928    buf[bytes++] = ADSI_LINE_CONTROL;
00929 
00930    /* Reserve space for size */
00931    bytes++;
00932 
00933    /* Page and line */
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    /* Start with initial display setup */
00949    bytes = 0;
00950    bytes += ast_adsi_set_line(dsp + bytes, ADSI_INFO_PAGE, 1);
00951 
00952    /* Prepare key setup messages */
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       /* Ignore the resulting DTMF B announcing it's in voice mode */
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    /* Connect to session */
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    /* Prepare key setup messages */
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    /* Connect to session */
01030    bytes += ast_adsi_disconnect_session(dsp + bytes);
01031    bytes += ast_adsi_voice_mode(dsp + bytes, 0);
01032 
01033    /* Prepare key setup messages */
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    /* Can't unload this once we're loaded */
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           );

Generated on Sat Mar 10 01:54:23 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7