Sat Feb 11 06:33:20 2012

Asterisk developer's documentation


res_adsi.c

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

Generated on Sat Feb 11 06:33:20 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.5.6