Wed Aug 18 22:33:54 2010

Asterisk developer's documentation


res_adsi.c

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

Generated on Wed Aug 18 22:33:54 2010 for Asterisk - the Open Source PBX by  doxygen 1.4.7