Wed Apr 6 11:29:46 2011

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

Generated on Wed Apr 6 11:29:46 2011 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7