Sat Apr 26 2014 22:01:39

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