Wed Jan 27 20:02:13 2016

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

Generated on 27 Jan 2016 for Asterisk - The Open Source Telephony Project by  doxygen 1.6.1