Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

channel.c

Go to the documentation of this file.
00001  /*
00002  * Asterisk -- A telephony toolkit for Linux.
00003  *
00004  * Channel Management
00005  * 
00006  * Copyright (C) 1999, Mark Spencer
00007  *
00008  * Mark Spencer <markster@linux-support.net>
00009  *
00010  * This program is free software, distributed under the terms of
00011  * the GNU General Public License
00012  */
00013 
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <pthread.h>
00017 #include <string.h>
00018 #include <sys/time.h>
00019 #include <signal.h>
00020 #include <errno.h>
00021 #include <unistd.h>
00022 #include <math.h>       /* For PI */
00023 #include <asterisk/pbx.h>
00024 #include <asterisk/frame.h>
00025 #include <asterisk/sched.h>
00026 #include <asterisk/options.h>
00027 #include <asterisk/channel.h>
00028 #include <asterisk/channel_pvt.h>
00029 #include <asterisk/logger.h>
00030 #include <asterisk/file.h>
00031 #include <asterisk/translate.h>
00032 #include <asterisk/manager.h>
00033 #include <asterisk/chanvars.h>
00034 #include <asterisk/linkedlists.h>
00035 #include <asterisk/indications.h>
00036 #include <asterisk/monitor.h>
00037 #include <asterisk/causes.h>
00038 #ifdef ZAPTEL_OPTIMIZATIONS
00039 #include <sys/ioctl.h>
00040 #include <linux/zaptel.h>
00041 #endif
00042 
00043 /* uncomment if you have problems with 'monitoring' synchronized files */
00044 #if 0
00045 #define MONITOR_CONSTANT_DELAY
00046 #define MONITOR_DELAY   150 * 8     /* 150 ms of MONITORING DELAY */
00047 #endif
00048 
00049 static int shutting_down = 0;
00050 static int uniqueint = 0;
00051 
00052 /* XXX Lock appropriately in more functions XXX */
00053 
00054 struct chanlist {
00055    char type[80];
00056    char description[80];
00057    int capabilities;
00058    struct ast_channel * (*requester)(char *type, int format, void *data);
00059    int (*devicestate)(void *data);
00060    struct chanlist *next;
00061 } *backends = NULL;
00062 struct ast_channel *channels = NULL;
00063 
00064 /* Protect the channel list (highly unlikely that two things would change
00065    it at the same time, but still! */
00066    
00067 static ast_mutex_t chlock = AST_MUTEX_INITIALIZER;
00068 
00069 int ast_check_hangup(struct ast_channel *chan)
00070 {
00071 time_t   myt;
00072 
00073      /* if soft hangup flag, return true */
00074    if (chan->_softhangup) return 1;
00075      /* if no private structure, return true */
00076    if (!chan->pvt->pvt) return 1;
00077      /* if no hangup scheduled, just return here */
00078    if (!chan->whentohangup) return 0;
00079    time(&myt); /* get current time */
00080      /* return, if not yet */
00081    if (chan->whentohangup > myt) return 0;
00082    chan->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
00083    return 1;
00084 }
00085 
00086 static int ast_check_hangup_locked(struct ast_channel *chan)
00087 {
00088    int res;
00089    ast_mutex_lock(&chan->lock);
00090    res = ast_check_hangup(chan);
00091    ast_mutex_unlock(&chan->lock);
00092    return res;
00093 }
00094 
00095 void ast_begin_shutdown(int hangup)
00096 {
00097    struct ast_channel *c;
00098    shutting_down = 1;
00099    if (hangup) {
00100       ast_mutex_lock(&chlock);
00101       c = channels;
00102       while(c) {
00103          ast_softhangup(c, AST_SOFTHANGUP_SHUTDOWN);
00104          c = c->next;
00105       }
00106       ast_mutex_unlock(&chlock);
00107    }
00108 }
00109 
00110 int ast_active_channels(void)
00111 {
00112    struct ast_channel *c;
00113    int cnt = 0;
00114    ast_mutex_lock(&chlock);
00115    c = channels;
00116    while(c) {
00117       cnt++;
00118       c = c->next;
00119    }
00120    ast_mutex_unlock(&chlock);
00121    return cnt;
00122 }
00123 
00124 void ast_cancel_shutdown(void)
00125 {
00126    shutting_down = 0;
00127 }
00128 
00129 int ast_shutting_down(void)
00130 {
00131    return shutting_down;
00132 }
00133 
00134 void ast_channel_setwhentohangup(struct ast_channel *chan, time_t offset)
00135 {
00136 time_t   myt;
00137 
00138    time(&myt);
00139         if (offset)
00140      chan->whentohangup = myt + offset;
00141         else
00142           chan->whentohangup = 0;
00143    return;
00144 }
00145 
00146 int ast_channel_register(char *type, char *description, int capabilities,
00147       struct ast_channel *(*requester)(char *type, int format, void *data))
00148 {
00149     return ast_channel_register_ex(type, description, capabilities, requester, NULL);
00150 }
00151 
00152 int ast_channel_register_ex(char *type, char *description, int capabilities,
00153       struct ast_channel *(*requester)(char *type, int format, void *data),
00154       int (*devicestate)(void *data))
00155 {
00156    struct chanlist *chan, *last=NULL;
00157    if (ast_mutex_lock(&chlock)) {
00158       ast_log(LOG_WARNING, "Unable to lock channel list\n");
00159       return -1;
00160    }
00161    chan = backends;
00162    while(chan) {
00163       if (!strcasecmp(type, chan->type)) {
00164          ast_log(LOG_WARNING, "Already have a handler for type '%s'\n", type);
00165          ast_mutex_unlock(&chlock);
00166          return -1;
00167       }
00168       last = chan;
00169       chan = chan->next;
00170    }
00171    chan = malloc(sizeof(struct chanlist));
00172    if (!chan) {
00173       ast_log(LOG_WARNING, "Out of memory\n");
00174       ast_mutex_unlock(&chlock);
00175       return -1;
00176    }
00177    strncpy(chan->type, type, sizeof(chan->type)-1);
00178    strncpy(chan->description, description, sizeof(chan->description)-1);
00179    chan->capabilities = capabilities;
00180    chan->requester = requester;
00181    chan->devicestate = devicestate;
00182    chan->next = NULL;
00183    if (last)
00184       last->next = chan;
00185    else
00186       backends = chan;
00187    if (option_debug)
00188       ast_log(LOG_DEBUG, "Registered handler for '%s' (%s)\n", chan->type, chan->description);
00189    else if (option_verbose > 1)
00190       ast_verbose( VERBOSE_PREFIX_2 "Registered channel type '%s' (%s)\n", chan->type, chan->description);
00191    ast_mutex_unlock(&chlock);
00192    return 0;
00193 }
00194 
00195 char *ast_state2str(int state)
00196 {
00197    /* XXX Not reentrant XXX */
00198    static char localtmp[256];
00199    switch(state) {
00200    case AST_STATE_DOWN:
00201       return "Down";
00202    case AST_STATE_RESERVED:
00203       return "Rsrvd";
00204    case AST_STATE_OFFHOOK:
00205       return "OffHook";
00206    case AST_STATE_DIALING:
00207       return "Dialing";
00208    case AST_STATE_RING:
00209       return "Ring";
00210    case AST_STATE_RINGING:
00211       return "Ringing";
00212    case AST_STATE_UP:
00213       return "Up";
00214    case AST_STATE_BUSY:
00215       return "Busy";
00216    default:
00217       snprintf(localtmp, sizeof(localtmp), "Unknown (%d)\n", state);
00218       return localtmp;
00219    }
00220 }
00221 
00222 
00223 int ast_best_codec(int fmts)
00224 {
00225    /* This just our opinion, expressed in code.  We are asked to choose
00226       the best codec to use, given no information */
00227    int x;
00228    static int prefs[] = 
00229    {
00230       /* Okay, ulaw is used by all telephony equipment, so start with it */
00231       AST_FORMAT_ULAW,
00232       /* Unless of course, you're a silly European, so then prefer ALAW */
00233       AST_FORMAT_ALAW,
00234       /* Okay, well, signed linear is easy to translate into other stuff */
00235       AST_FORMAT_SLINEAR,
00236       /* G.726 is standard ADPCM */
00237       AST_FORMAT_G726,
00238       /* ADPCM has great sound quality and is still pretty easy to translate */
00239       AST_FORMAT_ADPCM,
00240       /* Okay, we're down to vocoders now, so pick GSM because it's small and easier to
00241          translate and sounds pretty good */
00242       AST_FORMAT_GSM,
00243       /* iLBC is not too bad */
00244       AST_FORMAT_ILBC,
00245       /* Speex is free, but computationally more expensive than GSM */
00246       AST_FORMAT_SPEEX,
00247       /* Ick, LPC10 sounds terrible, but at least we have code for it, if you're tacky enough
00248          to use it */
00249       AST_FORMAT_LPC10,
00250       /* G.729a is faster than 723 and slightly less expensive */
00251       AST_FORMAT_G729A,
00252       /* Down to G.723.1 which is proprietary but at least designed for voice */
00253       AST_FORMAT_G723_1,
00254    };
00255    
00256    
00257    for (x=0;x<sizeof(prefs) / sizeof(prefs[0]); x++)
00258       if (fmts & prefs[x])
00259          return prefs[x];
00260    ast_log(LOG_WARNING, "Don't know any of 0x%x formats\n", fmts);
00261    return 0;
00262 }
00263 
00264 struct ast_channel *ast_channel_alloc(int needqueue)
00265 {
00266    struct ast_channel *tmp;
00267    struct ast_channel_pvt *pvt;
00268    int x;
00269    int flags;
00270    struct varshead *headp;        
00271            
00272    
00273    /* If shutting down, don't allocate any new channels */
00274    if (shutting_down)
00275       return NULL;
00276    ast_mutex_lock(&chlock);
00277    tmp = malloc(sizeof(struct ast_channel));
00278    if (tmp) {
00279       memset(tmp, 0, sizeof(struct ast_channel));
00280       pvt = malloc(sizeof(struct ast_channel_pvt));
00281       if (pvt) {
00282          memset(pvt, 0, sizeof(struct ast_channel_pvt));
00283          tmp->sched = sched_context_create();
00284          if (tmp->sched) {
00285             for (x=0;x<AST_MAX_FDS - 1;x++)
00286                tmp->fds[x] = -1;
00287             if (needqueue &&  
00288                pipe(pvt->alertpipe)) {
00289                ast_log(LOG_WARNING, "Alert pipe creation failed!\n");
00290                free(pvt);
00291                free(tmp);
00292                tmp = NULL;
00293                pvt = NULL;
00294             } else {
00295                /* Make sure we've got it done right if they don't */
00296                if (needqueue) {
00297                   flags = fcntl(pvt->alertpipe[0], F_GETFL);
00298                   fcntl(pvt->alertpipe[0], F_SETFL, flags | O_NONBLOCK);
00299                   flags = fcntl(pvt->alertpipe[1], F_GETFL);
00300                   fcntl(pvt->alertpipe[1], F_SETFL, flags | O_NONBLOCK);
00301                } else
00302                   pvt->alertpipe[0] = pvt->alertpipe[1] = -1;
00303 #ifdef ZAPTEL_OPTIMIZATIONS
00304                tmp->timingfd = open("/dev/zap/timer", O_RDWR);
00305 #else
00306                tmp->timingfd = -1;              
00307 #endif
00308                /* Always watch the alertpipe */
00309                tmp->fds[AST_MAX_FDS-1] = pvt->alertpipe[0];
00310                /* And timing pipe */
00311                tmp->fds[AST_MAX_FDS-2] = tmp->timingfd;
00312                strncpy(tmp->name, "**Unknown**", sizeof(tmp->name)-1);
00313                tmp->pvt = pvt;
00314                /* Initial state */
00315                tmp->_state = AST_STATE_DOWN;
00316                tmp->stack = -1;
00317                tmp->streamid = -1;
00318                tmp->appl = NULL;
00319                tmp->data = NULL;
00320                tmp->fin = 0;
00321                tmp->fout = 0;
00322                snprintf(tmp->uniqueid, sizeof(tmp->uniqueid), "%li.%d", (long)time(NULL), uniqueint++);
00323                headp=&tmp->varshead;
00324                ast_mutex_init(&tmp->lock);
00325                     AST_LIST_HEAD_INIT(headp);
00326                tmp->vars=ast_var_assign("tempvar","tempval");
00327                AST_LIST_INSERT_HEAD(headp,tmp->vars,entries);
00328                strncpy(tmp->context, "default", sizeof(tmp->context)-1);
00329                strncpy(tmp->language, defaultlanguage, sizeof(tmp->language)-1);
00330                strncpy(tmp->exten, "s", sizeof(tmp->exten)-1);
00331                tmp->priority=1;
00332                tmp->amaflags = ast_default_amaflags;
00333                strncpy(tmp->accountcode, ast_default_accountcode, sizeof(tmp->accountcode)-1);
00334                tmp->next = channels;
00335                channels= tmp;
00336             }
00337          } else {
00338             ast_log(LOG_WARNING, "Unable to create schedule context\n");
00339             free(tmp);
00340             tmp = NULL;
00341          }
00342       } else {
00343          ast_log(LOG_WARNING, "Out of memory\n");
00344          free(tmp);
00345          tmp = NULL;
00346       }
00347    } else 
00348       ast_log(LOG_WARNING, "Out of memory\n");
00349    ast_mutex_unlock(&chlock);
00350    return tmp;
00351 }
00352 
00353 int ast_queue_frame(struct ast_channel *chan, struct ast_frame *fin, int lock)
00354 {
00355    struct ast_frame *f;
00356    struct ast_frame *prev, *cur;
00357    int blah = 1;
00358    int qlen = 0;
00359    /* Build us a copy and free the original one */
00360    f = ast_frdup(fin);
00361    if (!f) {
00362       ast_log(LOG_WARNING, "Unable to duplicate frame\n");
00363       return -1;
00364    }
00365    if (lock)
00366       ast_mutex_lock(&chan->lock);
00367    prev = NULL;
00368    cur = chan->pvt->readq;
00369    while(cur) {
00370       prev = cur;
00371       cur = cur->next;
00372       qlen++;
00373    }
00374    /* Allow up to 96 voice frames outstanding, and up to 128 total frames */
00375    if (((fin->frametype == AST_FRAME_VOICE) && (qlen > 96)) || (qlen  > 128)) {
00376       if (fin->frametype != AST_FRAME_VOICE) {
00377          ast_log(LOG_WARNING, "Exceptionally long queue length queuing to %s\n", chan->name);
00378          CRASH;
00379       } else {
00380          ast_log(LOG_DEBUG, "Dropping voice to exceptionally long queue on %s\n", chan->name);
00381          ast_frfree(f);
00382          if (lock)
00383             ast_mutex_unlock(&chan->lock);
00384          return 0;
00385       }
00386    }
00387    if (prev)
00388       prev->next = f;
00389    else
00390       chan->pvt->readq = f;
00391    if (chan->pvt->alertpipe[1] > -1) {
00392       if (write(chan->pvt->alertpipe[1], &blah, sizeof(blah)) != sizeof(blah))
00393          ast_log(LOG_WARNING, "Unable to write to alert pipe on %s, frametype/subclass %d/%d (qlen = %d): %s!\n",
00394             chan->name, f->frametype, f->subclass, qlen, strerror(errno));
00395    } else if (chan->blocking) {
00396       pthread_kill(chan->blocker, SIGURG);
00397    }
00398    if (lock)
00399       ast_mutex_unlock(&chan->lock);
00400    return 0;
00401 }
00402 
00403 int ast_queue_hangup(struct ast_channel *chan, int lock)
00404 {
00405    struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_HANGUP };
00406    chan->_softhangup |= AST_SOFTHANGUP_DEV;
00407    return ast_queue_frame(chan, &f, lock);
00408 }
00409 
00410 int ast_queue_control(struct ast_channel *chan, int control, int lock)
00411 {
00412    struct ast_frame f = { AST_FRAME_CONTROL, };
00413    f.subclass = control;
00414    return ast_queue_frame(chan, &f, lock);
00415 }
00416 
00417 int ast_channel_defer_dtmf(struct ast_channel *chan)
00418 {
00419    int pre = 0;
00420    if (chan) {
00421       pre = chan->deferdtmf;
00422       chan->deferdtmf = 1;
00423    }
00424    return pre;
00425 }
00426 
00427 void ast_channel_undefer_dtmf(struct ast_channel *chan)
00428 {
00429    if (chan)
00430       chan->deferdtmf = 0;
00431 }
00432 
00433 struct ast_channel *ast_channel_walk(struct ast_channel *prev)
00434 {
00435    struct ast_channel *l, *ret=NULL;
00436    ast_mutex_lock(&chlock);
00437    l = channels;
00438    if (!prev) {
00439       ast_mutex_unlock(&chlock);
00440       return l;
00441    }
00442    while(l) {
00443       if (l == prev)
00444          ret = l->next;
00445       l = l->next;
00446    }
00447    ast_mutex_unlock(&chlock);
00448    return ret;
00449    
00450 }
00451 
00452 int ast_safe_sleep_conditional(  struct ast_channel *chan, int ms,
00453                         int (*cond)(void*), void *data )
00454 {
00455    struct ast_frame *f;
00456 
00457    while(ms > 0) {
00458       if( cond && ((*cond)(data) == 0 ) )
00459          return 0;
00460       ms = ast_waitfor(chan, ms);
00461       if (ms <0)
00462          return -1;
00463       if (ms > 0) {
00464          f = ast_read(chan);
00465          if (!f)
00466             return -1;
00467          ast_frfree(f);
00468       }
00469    }
00470    return 0;
00471 }
00472 
00473 int ast_safe_sleep(struct ast_channel *chan, int ms)
00474 {
00475    struct ast_frame *f;
00476    while(ms > 0) {
00477       ms = ast_waitfor(chan, ms);
00478       if (ms <0)
00479          return -1;
00480       if (ms > 0) {
00481          f = ast_read(chan);
00482          if (!f)
00483             return -1;
00484          ast_frfree(f);
00485       }
00486    }
00487    return 0;
00488 }
00489 
00490 void ast_channel_free(struct ast_channel *chan)
00491 {
00492    struct ast_channel *last=NULL, *cur;
00493    int fd;
00494    struct ast_var_t *vardata;
00495    struct ast_frame *f, *fp;
00496    struct varshead *headp;
00497    char name[AST_CHANNEL_NAME];
00498    
00499    headp=&chan->varshead;
00500    
00501    ast_mutex_lock(&chlock);
00502    cur = channels;
00503    while(cur) {
00504       if (cur == chan) {
00505          if (last)
00506             last->next = cur->next;
00507          else
00508             channels = cur->next;
00509          break;
00510       }
00511       last = cur;
00512       cur = cur->next;
00513    }
00514    if (!cur)
00515       ast_log(LOG_WARNING, "Unable to find channel in list\n");
00516    if (chan->pvt->pvt)
00517       ast_log(LOG_WARNING, "Channel '%s' may not have been hung up properly\n", chan->name);
00518 
00519    strncpy(name, chan->name, sizeof(name)-1);
00520    
00521    /* Stop monitoring */
00522    if (chan->monitor) {
00523       chan->monitor->stop( chan, 0 );
00524    }
00525 
00526    /* Free translatosr */
00527    if (chan->pvt->readtrans)
00528       ast_translator_free_path(chan->pvt->readtrans);
00529    if (chan->pvt->writetrans)
00530       ast_translator_free_path(chan->pvt->writetrans);
00531    if (chan->pbx) 
00532       ast_log(LOG_WARNING, "PBX may not have been terminated properly on '%s'\n", chan->name);
00533    if (chan->dnid)
00534       free(chan->dnid);
00535    if (chan->callerid)
00536       free(chan->callerid);   
00537    if (chan->ani)
00538       free(chan->ani);
00539    if (chan->rdnis)
00540       free(chan->rdnis);
00541    ast_mutex_destroy(&chan->lock);
00542    /* Close pipes if appropriate */
00543    if ((fd = chan->pvt->alertpipe[0]) > -1)
00544       close(fd);
00545    if ((fd = chan->pvt->alertpipe[1]) > -1)
00546       close(fd);
00547    if ((fd = chan->timingfd) > -1)
00548       close(fd);
00549    f = chan->pvt->readq;
00550    chan->pvt->readq = NULL;
00551    while(f) {
00552       fp = f;
00553       f = f->next;
00554       ast_frfree(fp);
00555    }
00556    
00557    /* loop over the variables list, freeing all data and deleting list items */
00558    /* no need to lock the list, as the channel is already locked */
00559    
00560    while (!AST_LIST_EMPTY(headp)) {           /* List Deletion. */
00561                vardata = AST_LIST_FIRST(headp);
00562                AST_LIST_REMOVE_HEAD(headp, entries);
00563 //             printf("deleting var %s=%s\n",ast_var_name(vardata),ast_var_value(vardata));
00564                ast_var_delete(vardata);
00565    }
00566                                                     
00567 
00568    free(chan->pvt);
00569    chan->pvt = NULL;
00570    free(chan);
00571    ast_mutex_unlock(&chlock);
00572 
00573    ast_device_state_changed(name);
00574 }
00575 
00576 int ast_softhangup_nolock(struct ast_channel *chan, int cause)
00577 {
00578    int res = 0;
00579    struct ast_frame f = { AST_FRAME_NULL };
00580    if (option_debug)
00581       ast_log(LOG_DEBUG, "Soft-Hanging up channel '%s'\n", chan->name);
00582    /* Inform channel driver that we need to be hung up, if it cares */
00583    chan->_softhangup |= cause;
00584    ast_queue_frame(chan, &f, 0);
00585    /* Interrupt any select call or such */
00586    if (chan->blocking)
00587       pthread_kill(chan->blocker, SIGURG);
00588    return res;
00589 }
00590 
00591 int ast_softhangup(struct ast_channel *chan, int cause)
00592 {
00593    int res;
00594    ast_mutex_lock(&chan->lock);
00595    res = ast_softhangup_nolock(chan, cause);
00596    ast_mutex_unlock(&chan->lock);
00597    return res;
00598 }
00599 
00600 static int ast_do_masquerade(struct ast_channel *original);
00601 
00602 static void free_translation(struct ast_channel *clone)
00603 {
00604    if (clone->pvt->writetrans)
00605       ast_translator_free_path(clone->pvt->writetrans);
00606    if (clone->pvt->readtrans)
00607       ast_translator_free_path(clone->pvt->readtrans);
00608    clone->pvt->writetrans = NULL;
00609    clone->pvt->readtrans = NULL;
00610    clone->pvt->rawwriteformat = clone->nativeformats;
00611    clone->pvt->rawreadformat = clone->nativeformats;
00612 }
00613 
00614 int ast_hangup(struct ast_channel *chan)
00615 {
00616    int res = 0;
00617    /* Don't actually hang up a channel that will masquerade as someone else, or
00618       if someone is going to masquerade as us */
00619    ast_mutex_lock(&chan->lock);
00620    if (chan->masq) {
00621       if (ast_do_masquerade(chan)) 
00622          ast_log(LOG_WARNING, "Failed to perform masquerade\n");
00623    }
00624 
00625    if (chan->masq) {
00626       ast_log(LOG_WARNING, "%s getting hung up, but someone is trying to masq into us?!?\n", chan->name);
00627       ast_mutex_unlock(&chan->lock);
00628       return 0;
00629    }
00630    /* If this channel is one which will be masqueraded into something, 
00631       mark it as a zombie already, so we know to free it later */
00632    if (chan->masqr) {
00633       chan->zombie=1;
00634       ast_mutex_unlock(&chan->lock);
00635       return 0;
00636    }
00637    free_translation(chan);
00638    if (chan->stream)
00639       ast_stopstream(chan);
00640    if (chan->sched)
00641       sched_context_destroy(chan->sched);
00642    /* Clear any tone stuff remaining */
00643    if (chan->generatordata)
00644       chan->generator->release(chan, chan->generatordata);
00645    chan->generatordata = NULL;
00646    chan->generator = NULL;
00647    if (chan->cdr) {
00648       /* End the CDR if it hasn't already */
00649       ast_cdr_end(chan->cdr);
00650       /* Post and Free the CDR */
00651       ast_cdr_post(chan->cdr);
00652       ast_cdr_free(chan->cdr);
00653    }
00654    if (chan->blocking) {
00655       ast_log(LOG_WARNING, "Hard hangup called by thread %ld on %s, while fd "
00656                "is blocked by thread %ld in procedure %s!  Expect a failure\n",
00657                (long)pthread_self(), chan->name, (long)chan->blocker, chan->blockproc);
00658       CRASH;
00659    }
00660    if (!chan->zombie) {
00661       if (option_debug)
00662          ast_log(LOG_DEBUG, "Hanging up channel '%s'\n", chan->name);
00663       if (chan->pvt->hangup)
00664          res = chan->pvt->hangup(chan);
00665    } else
00666       if (option_debug)
00667          ast_log(LOG_DEBUG, "Hanging up zombie '%s'\n", chan->name);
00668          
00669    ast_mutex_unlock(&chan->lock);
00670    manager_event(EVENT_FLAG_CALL, "Hangup", 
00671          "Channel: %s\r\n"
00672          "Uniqueid: %s\r\n",
00673          chan->name, chan->uniqueid);
00674    ast_channel_free(chan);
00675    return res;
00676 }
00677 
00678 void ast_channel_unregister(char *type)
00679 {
00680    struct chanlist *chan, *last=NULL;
00681    if (option_debug)
00682       ast_log(LOG_DEBUG, "Unregistering channel type '%s'\n", type);
00683    if (ast_mutex_lock(&chlock)) {
00684       ast_log(LOG_WARNING, "Unable to lock channel list\n");
00685       return;
00686    }
00687    if (option_verbose > 1)
00688       ast_verbose( VERBOSE_PREFIX_2 "Unregistered channel type '%s'\n", type);
00689 
00690    chan = backends;
00691    while(chan) {
00692       if (!strcasecmp(chan->type, type)) {
00693          if (last)
00694             last->next = chan->next;
00695          else
00696             backends = backends->next;
00697          free(chan);
00698          ast_mutex_unlock(&chlock);
00699          return;
00700       }
00701       last = chan;
00702       chan = chan->next;
00703    }
00704    ast_mutex_unlock(&chlock);
00705 }
00706 
00707 int ast_answer(struct ast_channel *chan)
00708 {
00709    int res = 0;
00710    /* Stop if we're a zombie or need a soft hangup */
00711    if (chan->zombie || ast_check_hangup(chan)) 
00712       return -1;
00713    switch(chan->_state) {
00714    case AST_STATE_RINGING:
00715    case AST_STATE_RING:
00716       ast_mutex_lock(&chan->lock);
00717       if (chan->pvt->answer)
00718          res = chan->pvt->answer(chan);
00719       ast_mutex_unlock(&chan->lock);
00720       ast_setstate(chan, AST_STATE_UP);
00721       if (chan->cdr)
00722          ast_cdr_answer(chan->cdr);
00723       return res;
00724       break;
00725    case AST_STATE_UP:
00726       if (chan->cdr)
00727          ast_cdr_answer(chan->cdr);
00728       break;
00729    }
00730    return 0;
00731 }
00732 
00733 void ast_deactivate_generator(struct ast_channel *chan)
00734 {
00735    if (chan->generatordata) {
00736       if (chan->generator && chan->generator->release) 
00737          chan->generator->release(chan, chan->generatordata);
00738       chan->generatordata = NULL;
00739       chan->generator = NULL;
00740       chan->writeinterrupt = 0;
00741    }
00742 }
00743 
00744 int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
00745 {
00746    if (chan->generatordata) {
00747       if (chan->generator && chan->generator->release)
00748          chan->generator->release(chan, chan->generatordata);
00749       chan->generatordata = NULL;
00750    }
00751    ast_prod(chan);
00752    if ((chan->generatordata = gen->alloc(chan, params))) {
00753       chan->generator = gen;
00754    } else {
00755       return -1;
00756    }
00757    return 0;
00758 }
00759 
00760 int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
00761 {
00762    /* Wait for x amount of time on a file descriptor to have input.  */
00763    struct timeval tv;
00764    fd_set rfds, efds;
00765    int res;
00766    int x, max=-1;
00767    int winner = -1;
00768    
00769    tv.tv_sec = *ms / 1000;
00770    tv.tv_usec = (*ms % 1000) * 1000;
00771    FD_ZERO(&rfds);
00772    FD_ZERO(&efds);
00773    for (x=0;x<n;x++) {
00774       if (fds[x] > -1) {
00775          FD_SET(fds[x], &rfds);
00776          FD_SET(fds[x], &efds);
00777          if (fds[x] > max)
00778             max = fds[x];
00779       }
00780    }
00781    if (*ms >= 0)
00782       res = ast_select(max + 1, &rfds, NULL, &efds, &tv);
00783    else
00784       res = ast_select(max + 1, &rfds, NULL, &efds, NULL);
00785 
00786    if (res < 0) {
00787       /* Simulate a timeout if we were interrupted */
00788       if (errno != EINTR)
00789          *ms = -1;
00790       else
00791          *ms = 0;
00792       return -1;
00793    }
00794 
00795    for (x=0;x<n;x++) {
00796       if ((fds[x] > -1) && (FD_ISSET(fds[x], &rfds) || FD_ISSET(fds[x], &efds)) && (winner < 0)) {
00797          if (exception)
00798             *exception = FD_ISSET(fds[x], &efds);
00799          winner = fds[x];
00800       }
00801    }
00802    *ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
00803    return winner;
00804 }
00805 
00806 struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds, 
00807    int *exception, int *outfd, int *ms)
00808 {
00809    /* Wait for x amount of time on a file descriptor to have input.  */
00810    struct timeval tv;
00811    fd_set rfds, efds;
00812    int res;
00813    int x, y, max=-1;
00814    time_t now = 0;
00815    long whentohangup = 0, havewhen = 0, diff;
00816    struct ast_channel *winner = NULL;
00817    if (outfd)
00818       *outfd = -99999;
00819    if (exception)
00820       *exception = 0;
00821    
00822    /* Perform any pending masquerades */
00823    for (x=0;x<n;x++) {
00824       ast_mutex_lock(&c[x]->lock);
00825       if (c[x]->whentohangup) {
00826          if (!havewhen)
00827             time(&now);
00828          diff = c[x]->whentohangup - now;
00829          if (!havewhen || (diff < whentohangup)) {
00830             havewhen++;
00831             whentohangup = diff;
00832          }
00833       }
00834       if (c[x]->masq) {
00835          if (ast_do_masquerade(c[x])) {
00836             ast_log(LOG_WARNING, "Masquerade failed\n");
00837             *ms = -1;
00838             ast_mutex_unlock(&c[x]->lock);
00839             return NULL;
00840          }
00841       }
00842       ast_mutex_unlock(&c[x]->lock);
00843    }
00844    
00845    tv.tv_sec = *ms / 1000;
00846    tv.tv_usec = (*ms % 1000) * 1000;
00847    
00848    if (havewhen) {
00849       if ((*ms < 0) || (whentohangup * 1000 < *ms)) {
00850          tv.tv_sec = whentohangup;
00851          tv.tv_usec = 0;
00852       }
00853    }
00854    FD_ZERO(&rfds);
00855    FD_ZERO(&efds);
00856 
00857    for (x=0;x<n;x++) {
00858       for (y=0;y<AST_MAX_FDS;y++) {
00859          if (c[x]->fds[y] > -1) {
00860             FD_SET(c[x]->fds[y], &rfds);
00861             FD_SET(c[x]->fds[y], &efds);
00862             if (c[x]->fds[y] > max)
00863                max = c[x]->fds[y];
00864          }
00865       }
00866       CHECK_BLOCKING(c[x]);
00867    }
00868    for (x=0;x<nfds; x++) {
00869       FD_SET(fds[x], &rfds);
00870       FD_SET(fds[x], &efds);
00871       if (fds[x] > max)
00872          max = fds[x];
00873    }
00874    if ((*ms >= 0) || (havewhen))
00875       res = ast_select(max + 1, &rfds, NULL, &efds, &tv);
00876    else
00877       res = ast_select(max + 1, &rfds, NULL, &efds, NULL);
00878 
00879    if (res < 0) {
00880       for (x=0;x<n;x++) 
00881          c[x]->blocking = 0;
00882       /* Simulate a timeout if we were interrupted */
00883       if (errno != EINTR)
00884          *ms = -1;
00885       else {
00886          /* Just an interrupt */
00887 #if 0
00888          *ms = 0;
00889 #endif         
00890       }
00891       return NULL;
00892    }
00893 
00894    if (havewhen)
00895       time(&now);
00896    for (x=0;x<n;x++) {
00897       c[x]->blocking = 0;
00898       if (havewhen && c[x]->whentohangup && (now > c[x]->whentohangup)) {
00899          c[x]->_softhangup |= AST_SOFTHANGUP_TIMEOUT;
00900          if (!winner)
00901             winner = c[x];
00902       }
00903       for (y=0;y<AST_MAX_FDS;y++) {
00904          if (c[x]->fds[y] > -1) {
00905             if ((FD_ISSET(c[x]->fds[y], &rfds) || FD_ISSET(c[x]->fds[y], &efds)) && !winner) {
00906                /* Set exception flag if appropriate */
00907                if (FD_ISSET(c[x]->fds[y], &efds))
00908                   c[x]->exception = 1;
00909                c[x]->fdno = y;
00910                winner = c[x];
00911             }
00912          }
00913       }
00914    }
00915    for (x=0;x<nfds;x++) {
00916       if ((FD_ISSET(fds[x], &rfds) || FD_ISSET(fds[x], &efds)) && !winner) {
00917          if (outfd)
00918             *outfd = fds[x];
00919          if (FD_ISSET(fds[x], &efds) && exception)
00920             *exception = 1;
00921          winner = NULL;
00922       }
00923    }
00924    *ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
00925    return winner;
00926 }
00927 
00928 struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
00929 {
00930    return ast_waitfor_nandfds(c, n, NULL, 0, NULL, NULL, ms);
00931 }
00932 
00933 int ast_waitfor(struct ast_channel *c, int ms)
00934 {
00935    struct ast_channel *chan;
00936    int oldms = ms;
00937    chan = ast_waitfor_n(&c, 1, &ms);
00938    if (ms < 0) {
00939       if (oldms < 0)
00940          return 0;
00941       else
00942          return -1;
00943    }
00944    return ms;
00945 }
00946 
00947 char ast_waitfordigit(struct ast_channel *c, int ms)
00948 {
00949    /* XXX Should I be merged with waitfordigit_full XXX */
00950    struct ast_frame *f;
00951    char result = 0;
00952    /* Stop if we're a zombie or need a soft hangup */
00953    if (c->zombie || ast_check_hangup(c)) 
00954       return -1;
00955    /* Wait for a digit, no more than ms milliseconds total. */
00956    while(ms && !result) {
00957       ms = ast_waitfor(c, ms);
00958       if (ms < 0) /* Error */
00959          result = -1; 
00960       else if (ms > 0) {
00961          /* Read something */
00962          f = ast_read(c);
00963          if (f) {
00964             if (f->frametype == AST_FRAME_DTMF) 
00965                result = f->subclass;
00966             ast_frfree(f);
00967          } else
00968             result = -1;
00969       }
00970    }
00971    return result;
00972 }
00973 
00974 int ast_settimeout(struct ast_channel *c, int samples, int (*func)(void *data), void *data)
00975 {
00976    int res = -1;
00977 #ifdef ZAPTEL_OPTIMIZATIONS
00978    if (c->timingfd > -1) {
00979       if (!func) {
00980          samples = 0;
00981          data = 0;
00982       }
00983       ast_log(LOG_DEBUG, "Scheduling timer at %d sample intervals\n", samples);
00984       res = ioctl(c->timingfd, ZT_TIMERCONFIG, &samples);
00985       c->timingfunc = func;
00986       c->timingdata = data;
00987    }
00988 #endif   
00989    return res;
00990 }
00991 char ast_waitfordigit_full(struct ast_channel *c, int ms, int audio, int ctrl)
00992 {
00993    struct ast_frame *f;
00994    char result = 0;
00995    struct ast_channel *rchan;
00996    int outfd;
00997    /* Stop if we're a zombie or need a soft hangup */
00998    if (c->zombie || ast_check_hangup(c)) 
00999       return -1;
01000    /* Wait for a digit, no more than ms milliseconds total. */
01001    while(ms && !result) {
01002       rchan = ast_waitfor_nandfds(&c, 1, &audio, (audio > -1) ? 1 : 0, NULL, &outfd, &ms);
01003       if ((!rchan) && (outfd < 0) && (ms)) /* Error */
01004          result = -1; 
01005       else if (outfd > -1) {
01006          result = 1;
01007       } else if (rchan) {
01008          /* Read something */
01009          f = ast_read(c);
01010          if (f) {
01011             if (f->frametype == AST_FRAME_DTMF) 
01012                result = f->subclass;
01013             ast_frfree(f);
01014          } else
01015             result = -1;
01016       }
01017    }
01018    return result;
01019 }
01020 
01021 struct ast_frame *ast_read(struct ast_channel *chan)
01022 {
01023    struct ast_frame *f = NULL;
01024    int blah;
01025 #ifdef ZAPTEL_OPTIMIZATIONS
01026    int (*func)(void *);
01027    void *data;
01028 #endif
01029    static struct ast_frame null_frame = 
01030    {
01031       AST_FRAME_NULL,
01032    };
01033    
01034    ast_mutex_lock(&chan->lock);
01035    if (chan->masq) {
01036       if (ast_do_masquerade(chan)) {
01037          ast_log(LOG_WARNING, "Failed to perform masquerade\n");
01038          f = NULL;
01039       } else
01040          f =  &null_frame;
01041       ast_mutex_unlock(&chan->lock);
01042       return f;
01043    }
01044 
01045    /* Stop if we're a zombie or need a soft hangup */
01046    if (chan->zombie || ast_check_hangup(chan)) {
01047       if (chan->generator)
01048          ast_deactivate_generator(chan);
01049       ast_mutex_unlock(&chan->lock);
01050       return NULL;
01051    }
01052 
01053    if (!chan->deferdtmf && strlen(chan->dtmfq)) {
01054       /* We have DTMF that has been deferred.  Return it now */
01055       chan->dtmff.frametype = AST_FRAME_DTMF;
01056       chan->dtmff.subclass = chan->dtmfq[0];
01057       /* Drop first digit */
01058       memmove(chan->dtmfq, chan->dtmfq + 1, sizeof(chan->dtmfq) - 1);
01059       ast_mutex_unlock(&chan->lock);
01060       return &chan->dtmff;
01061    }
01062    
01063    /* Read and ignore anything on the alertpipe, but read only
01064       one sizeof(blah) per frame that we send from it */
01065    if (chan->pvt->alertpipe[0] > -1) {
01066       read(chan->pvt->alertpipe[0], &blah, sizeof(blah));
01067    }
01068 #ifdef ZAPTEL_OPTIMIZATIONS
01069    if ((chan->timingfd > -1) && (chan->fdno == AST_MAX_FDS - 2) && chan->exception) {
01070       chan->exception = 0;
01071       blah = -1;
01072       ioctl(chan->timingfd, ZT_TIMERACK, &blah);
01073       func = chan->timingfunc;
01074       data = chan->timingdata;
01075       ast_mutex_unlock(&chan->lock);
01076       if (func) {
01077 #if 0
01078          ast_log(LOG_DEBUG, "Calling private function\n");
01079 #endif         
01080          func(data);
01081       } else {
01082          blah = 0;
01083          ast_mutex_lock(&chan->lock);
01084          ioctl(chan->timingfd, ZT_TIMERCONFIG, &blah);
01085          chan->timingdata = NULL;
01086          ast_mutex_unlock(&chan->lock);
01087       }
01088       f =  &null_frame;
01089       return f;
01090    }
01091 #endif
01092    /* Check for pending read queue */
01093    if (chan->pvt->readq) {
01094       f = chan->pvt->readq;
01095       chan->pvt->readq = f->next;
01096       /* Interpret hangup and return NULL */
01097       if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
01098          ast_frfree(f);
01099          f = NULL;
01100       }
01101    } else {
01102       chan->blocker = pthread_self();
01103       if (chan->exception) {
01104          if (chan->pvt->exception) 
01105             f = chan->pvt->exception(chan);
01106          else {
01107             ast_log(LOG_WARNING, "Exception flag set on '%s', but no exception handler\n", chan->name);
01108             f = &null_frame;
01109          }
01110          /* Clear the exception flag */
01111          chan->exception = 0;
01112       } else
01113       if (chan->pvt->read)
01114          f = chan->pvt->read(chan);
01115       else
01116          ast_log(LOG_WARNING, "No read routine on channel %s\n", chan->name);
01117    }
01118 
01119 
01120    if (f && (f->frametype == AST_FRAME_VOICE)) {
01121       if (!(f->subclass & chan->nativeformats)) {
01122          /* This frame can't be from the current native formats -- drop it on the
01123             floor */
01124          ast_log(LOG_NOTICE, "Dropping incompatible voice frame on %s of format %s since our native format has changed to %s\n", chan->name, ast_getformatname(f->subclass), ast_getformatname(chan->nativeformats));
01125          ast_frfree(f);
01126          f = &null_frame;
01127       } else {
01128          if (chan->monitor && chan->monitor->read_stream ) {
01129 #ifndef MONITOR_CONSTANT_DELAY
01130             int jump = chan->outsmpl - chan->insmpl - 2 * f->samples;
01131             if (jump >= 0) {
01132                if (ast_seekstream(chan->monitor->read_stream, jump + f->samples, SEEK_FORCECUR) == -1)
01133                   ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
01134                chan->insmpl += jump + 2 * f->samples;
01135             } else
01136                chan->insmpl+= f->samples;
01137 #else
01138             int jump = chan->outsmpl - chan->insmpl;
01139             if (jump - MONITOR_DELAY >= 0) {
01140                if (ast_seekstream(chan->monitor->read_stream, jump - f->samples, SEEK_FORCECUR) == -1)
01141                   ast_log(LOG_WARNING, "Failed to perform seek in monitoring read stream, synchronization between the files may be broken\n");
01142                chan->insmpl += jump;
01143             } else
01144                chan->insmpl += f->samples;
01145 #endif
01146             if (ast_writestream(chan->monitor->read_stream, f) < 0)
01147                ast_log(LOG_WARNING, "Failed to write data to channel monitor read stream\n");
01148          }
01149          if (chan->pvt->readtrans) {
01150             f = ast_translate(chan->pvt->readtrans, f, 1);
01151             if (!f)
01152                f = &null_frame;
01153          }
01154       }
01155    }
01156 
01157    /* Make sure we always return NULL in the future */
01158    if (!f) {
01159       chan->_softhangup |= AST_SOFTHANGUP_DEV;
01160       if (chan->generator)
01161          ast_deactivate_generator(chan);
01162       /* End the CDR if appropriate */
01163       if (chan->cdr)
01164          ast_cdr_end(chan->cdr);
01165    } else if (chan->deferdtmf && f->frametype == AST_FRAME_DTMF) {
01166       if (strlen(chan->dtmfq) < sizeof(chan->dtmfq) - 2)
01167          chan->dtmfq[strlen(chan->dtmfq)] = f->subclass;
01168       else
01169          ast_log(LOG_WARNING, "Dropping deferred DTMF digits on %s\n", chan->name);
01170       f = &null_frame;
01171    } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_ANSWER)) {
01172       /* Answer the CDR */
01173       ast_setstate(chan, AST_STATE_UP);
01174       ast_cdr_answer(chan->cdr);
01175    } 
01176    ast_mutex_unlock(&chan->lock);
01177 
01178    /* Run any generator sitting on the line */
01179    if (f && (f->frametype == AST_FRAME_VOICE) && chan->generatordata) {
01180       /* Mask generator data temporarily */
01181       void *tmp;
01182       int res;
01183       tmp = chan->generatordata;
01184       chan->generatordata = NULL;
01185       res = chan->generator->generate(chan, tmp, f->datalen, f->samples);
01186       chan->generatordata = tmp;
01187       if (res) {
01188          ast_log(LOG_DEBUG, "Auto-deactivating generator\n");
01189          ast_deactivate_generator(chan);
01190       }
01191    }
01192    if (chan->fin & 0x80000000)
01193       ast_frame_dump(chan->name, f, "<<");
01194    if ((chan->fin & 0x7fffffff) == 0x7fffffff)
01195       chan->fin &= 0x80000000;
01196    else
01197       chan->fin++;
01198    return f;
01199 }
01200 
01201 int ast_indicate(struct ast_channel *chan, int condition)
01202 {
01203    int res = -1;
01204    /* Stop if we're a zombie or need a soft hangup */
01205    if (chan->zombie || ast_check_hangup(chan)) 
01206       return -1;
01207    ast_mutex_lock(&chan->lock);
01208    if (chan->pvt->indicate)
01209       res = chan->pvt->indicate(chan, condition);
01210    ast_mutex_unlock(&chan->lock);
01211    if (!chan->pvt->indicate || res) {
01212       /*
01213        * Device does not support (that) indication, lets fake
01214        * it by doing our own tone generation. (PM2002)
01215        */
01216       if (condition >= 0) {
01217          const struct tone_zone_sound *ts = NULL;
01218          switch (condition) {
01219           case AST_CONTROL_RINGING:
01220             ts = ast_get_indication_tone(chan->zone, "ring");
01221             break;
01222           case AST_CONTROL_BUSY:
01223             ts = ast_get_indication_tone(chan->zone, "busy");
01224             break;
01225           case AST_CONTROL_CONGESTION:
01226             ts = ast_get_indication_tone(chan->zone, "congestion");
01227             break;
01228          }
01229          if (ts && ts->data[0]) {
01230             ast_log(LOG_DEBUG, "Driver for channel '%s' does not support indication %d, emulating it\n", chan->name, condition);
01231             ast_playtones_start(chan,0,ts->data, 1);
01232             res = 0;
01233          } else if (condition == AST_CONTROL_PROGRESS) {
01234             /* ast_playtones_stop(chan); */
01235          } else {
01236             /* not handled */
01237             ast_log(LOG_WARNING, "Unable to handle indication %d for '%s'\n", condition, chan->name);
01238             res = -1;
01239          }
01240       }
01241       else ast_playtones_stop(chan);
01242    }
01243    return res;
01244 }
01245 
01246 int ast_recvchar(struct ast_channel *chan, int timeout)
01247 {
01248    int res,ourto,c;
01249    struct ast_frame *f;
01250    
01251    ourto = timeout;
01252    for(;;)
01253       {
01254       if (ast_check_hangup(chan)) return -1;
01255       res = ast_waitfor(chan,ourto);
01256       if (res <= 0) /* if timeout */
01257          {
01258          return 0;
01259          }
01260       ourto = res;
01261       f = ast_read(chan);
01262       if (f == NULL) return -1; /* if hangup */
01263       if ((f->frametype == AST_FRAME_CONTROL) &&
01264           (f->subclass == AST_CONTROL_HANGUP)) return -1; /* if hangup */
01265       if (f->frametype == AST_FRAME_TEXT)  /* if a text frame */
01266          {
01267          c = *((char *)f->data);  /* get the data */
01268          ast_frfree(f);
01269          return(c);
01270          }
01271       ast_frfree(f);
01272    }
01273 }
01274 
01275 int ast_sendtext(struct ast_channel *chan, char *text)
01276 {
01277    int res = 0;
01278    /* Stop if we're a zombie or need a soft hangup */
01279    if (chan->zombie || ast_check_hangup(chan)) 
01280       return -1;
01281    CHECK_BLOCKING(chan);
01282    if (chan->pvt->send_text)
01283       res = chan->pvt->send_text(chan, text);
01284    chan->blocking = 0;
01285    return res;
01286 }
01287 
01288 static int do_senddigit(struct ast_channel *chan, char digit)
01289 {
01290    int res = -1;
01291 
01292    if (chan->pvt->send_digit)
01293       res = chan->pvt->send_digit(chan, digit);
01294    if (!chan->pvt->send_digit || res) {
01295       /*
01296        * Device does not support DTMF tones, lets fake
01297        * it by doing our own generation. (PM2002)
01298        */
01299       static const char* dtmf_tones[] = {
01300          "!941+1336/50,!0/50",   /* 0 */
01301          "!697+1209/50,!0/50",   /* 1 */
01302          "!697+1336/50,!0/50",   /* 2 */
01303          "!697+1477/50,!0/50",   /* 3 */
01304          "!770+1209/50,!0/50",   /* 4 */
01305          "!770+1336/50,!0/50",   /* 5 */
01306          "!770+1477/50,!0/50",   /* 6 */
01307          "!852+1209/50,!0/50",   /* 7 */
01308          "!852+1336/50,!0/50",   /* 8 */
01309          "!852+1477/50,!0/50",   /* 9 */
01310          "!697+1633/50,!0/50",   /* A */
01311          "!770+1633/50,!0/50",   /* B */
01312          "!852+1633/50,!0/50",   /* C */
01313          "!941+1633/50,!0/50",   /* D */
01314          "!941+1209/50,!0/50",   /* * */
01315          "!941+1477/50,!0/50" }; /* # */
01316       if (digit >= '0' && digit <='9')
01317          ast_playtones_start(chan,0,dtmf_tones[digit-'0'], 0);
01318       else if (digit >= 'A' && digit <= 'D')
01319          ast_playtones_start(chan,0,dtmf_tones[digit-'A'+10], 0);
01320       else if (digit == '*')
01321          ast_playtones_start(chan,0,dtmf_tones[14], 0);
01322       else if (digit == '#')
01323          ast_playtones_start(chan,0,dtmf_tones[15], 0);
01324       else {
01325          /* not handled */
01326          ast_log(LOG_WARNING, "Unable to handle DTMF tone '%c' for '%s'\n", digit, chan->name);
01327          return -1;
01328       }
01329    }
01330    return 0;
01331 }
01332 
01333 int ast_prod(struct ast_channel *chan)
01334 {
01335    struct ast_frame a = { AST_FRAME_VOICE };
01336    char nothing[128];
01337    /* Send an empty audio frame to get things moving */
01338    if (chan->_state != AST_STATE_UP) {
01339       ast_log(LOG_DEBUG, "Prodding channel '%s'\n", chan->name);
01340       a.subclass = chan->pvt->rawwriteformat;
01341       a.data = nothing + AST_FRIENDLY_OFFSET;
01342       if (ast_write(chan, &a))
01343          ast_log(LOG_WARNING, "Prodding channel '%s' failed\n", chan->name);
01344    }
01345    return 0;
01346 }
01347 
01348 int ast_write_video(struct ast_channel *chan, struct ast_frame *fr)
01349 {
01350    int res;
01351    if (!chan->pvt->write_video)
01352       return 0;
01353    res = ast_write(chan, fr);
01354    if (!res)
01355       res = 1;
01356    return res;
01357 }
01358 
01359 int ast_write(struct ast_channel *chan, struct ast_frame *fr)
01360 {
01361    int res = -1;
01362    struct ast_frame *f = NULL;
01363    /* Stop if we're a zombie or need a soft hangup */
01364    ast_mutex_lock(&chan->lock);
01365    if (chan->zombie || ast_check_hangup(chan))  {
01366       ast_mutex_unlock(&chan->lock);
01367       return -1;
01368    }
01369    /* Handle any pending masquerades */
01370    if (chan->masq) {
01371       if (ast_do_masquerade(chan)) {
01372          ast_log(LOG_WARNING, "Failed to perform masquerade\n");
01373          ast_mutex_unlock(&chan->lock);
01374          return -1;
01375       }
01376    }
01377    if (chan->masqr) {
01378       ast_mutex_unlock(&chan->lock);
01379       return 0;
01380    }
01381    if (chan->generatordata) {
01382       if (chan->writeinterrupt)
01383          ast_deactivate_generator(chan);
01384       else {
01385          ast_mutex_unlock(&chan->lock);
01386          return 0;
01387       }
01388    }
01389    if (chan->fout & 0x80000000)
01390       ast_frame_dump(chan->name, fr, ">>");
01391    CHECK_BLOCKING(chan);
01392    switch(fr->frametype) {
01393    case AST_FRAME_CONTROL:
01394       /* XXX Interpret control frames XXX */
01395       ast_log(LOG_WARNING, "Don't know how to handle control frames yet\n");
01396       break;
01397    case AST_FRAME_DTMF:
01398       chan->blocking = 0;
01399       ast_mutex_unlock(&chan->lock);
01400       res = do_senddigit(chan,fr->subclass);
01401       ast_mutex_lock(&chan->lock);
01402       CHECK_BLOCKING(chan);
01403       break;
01404    case AST_FRAME_TEXT:
01405       if (chan->pvt->send_text)
01406          res = chan->pvt->send_text(chan, (char *) fr->data);
01407       break;
01408    case AST_FRAME_VIDEO:
01409       /* XXX Handle translation of video codecs one day XXX */
01410       if (chan->pvt->write_video)
01411          res = chan->pvt->write_video(chan, fr);
01412       else
01413          res = 0;
01414       break;
01415    default:
01416       if (chan->pvt->write) {
01417          if (chan->pvt->writetrans) {
01418             f = ast_translate(chan->pvt->writetrans, fr, 0);
01419          } else
01420             f = fr;
01421          if (f) {
01422             res = chan->pvt->write(chan, f);
01423             if( chan->monitor &&
01424                   chan->monitor->write_stream &&
01425                   f && ( f->frametype == AST_FRAME_VOICE ) ) {
01426 #ifndef MONITOR_CONSTANT_DELAY
01427                int jump = chan->insmpl - chan->outsmpl - 2 * f->samples;
01428                if (jump >= 0) {
01429                   if (ast_seekstream(chan->monitor->write_stream, jump + f->samples, SEEK_FORCECUR) == -1)
01430                      ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
01431                   chan->outsmpl += jump + 2 * f->samples;
01432                } else
01433                   chan->outsmpl += f->samples;
01434 #else
01435                int jump = chan->insmpl - chan->outsmpl;
01436                if (jump - MONITOR_DELAY >= 0) {
01437                   if (ast_seekstream(chan->monitor->write_stream, jump - f->samples, SEEK_FORCECUR) == -1)
01438                      ast_log(LOG_WARNING, "Failed to perform seek in monitoring write stream, synchronization between the files may be broken\n");
01439                   chan->outsmpl += jump;
01440                } else
01441                   chan->outsmpl += f->samples;
01442 #endif
01443             if (ast_writestream(chan->monitor->write_stream, f) < 0)
01444                   ast_log(LOG_WARNING, "Failed to write data to channel monitor write stream\n");
01445             }
01446          } else
01447             res = 0;
01448       }
01449    }
01450    if (f && (f != fr))
01451       ast_frfree(f);
01452    chan->blocking = 0;
01453    /* Consider a write failure to force a soft hangup */
01454    if (res < 0)
01455       chan->_softhangup |= AST_SOFTHANGUP_DEV;
01456    else {
01457       if ((chan->fout & 0x7fffffff) == 0x7fffffff)
01458          chan->fout &= 0x80000000;
01459       else
01460          chan->fout++;
01461       chan->fout++;
01462    }
01463    ast_mutex_unlock(&chan->lock);
01464    return res;
01465 }
01466 
01467 int ast_set_write_format(struct ast_channel *chan, int fmts)
01468 {
01469    int fmt;
01470    int native;
01471    int res;
01472    
01473    native = chan->nativeformats;
01474    fmt = fmts;
01475    
01476    res = ast_translator_best_choice(&native, &fmt);
01477    if (res < 0) {
01478       ast_log(LOG_NOTICE, "Unable to find a path from %s to %s\n",
01479          ast_getformatname(fmts), ast_getformatname(chan->nativeformats));
01480       return -1;
01481    }
01482    
01483    /* Now we have a good choice for both.  We'll write using our native format. */
01484    chan->pvt->rawwriteformat = native;
01485    /* User perspective is fmt */
01486    chan->writeformat = fmt;
01487    /* Free any write translation we have right now */
01488    if (chan->pvt->writetrans)
01489       ast_translator_free_path(chan->pvt->writetrans);
01490    /* Build a translation path from the user write format to the raw writing format */
01491    chan->pvt->writetrans = ast_translator_build_path(chan->pvt->rawwriteformat, chan->writeformat);
01492    if (option_debug)
01493       ast_log(LOG_DEBUG, "Set channel %s to write format %s\n", chan->name, ast_getformatname(chan->writeformat));
01494    return 0;
01495 }
01496 
01497 int ast_set_read_format(struct ast_channel *chan, int fmts)
01498 {
01499    int fmt;
01500    int native;
01501    int res;
01502    
01503    native = chan->nativeformats;
01504    fmt = fmts;
01505    /* Find a translation path from the native read format to one of the user's read formats */
01506    res = ast_translator_best_choice(&fmt, &native);
01507    if (res < 0) {
01508       ast_log(LOG_NOTICE, "Unable to find a path from %s to %s\n",
01509          ast_getformatname(chan->nativeformats), ast_getformatname(fmts));
01510       return -1;
01511    }
01512    
01513    /* Now we have a good choice for both.  We'll write using our native format. */
01514    chan->pvt->rawreadformat = native;
01515    /* User perspective is fmt */
01516    chan->readformat = fmt;
01517    /* Free any read translation we have right now */
01518    if (chan->pvt->readtrans)
01519       ast_translator_free_path(chan->pvt->readtrans);
01520    /* Build a translation path from the raw read format to the user reading format */
01521    chan->pvt->readtrans = ast_translator_build_path(chan->readformat, chan->pvt->rawreadformat);
01522    if (option_debug)
01523       ast_log(LOG_DEBUG, "Set channel %s to read format %s\n", 
01524          chan->name, ast_getformatname(chan->readformat));
01525    return 0;
01526 }
01527 
01528 struct ast_channel *__ast_request_and_dial(char *type, int format, void *data, int timeout, int *outstate, char *callerid, struct outgoing_helper *oh)
01529 {
01530    int state = 0;
01531    struct ast_channel *chan;
01532    struct ast_frame *f;
01533    int res = 0;
01534    chan = ast_request(type, format, data);
01535    if (chan) {
01536       if (oh) {
01537          char *tmp, *var;
01538          /* JDG chanvar */
01539          tmp = oh->variable;
01540          /* FIXME replace this call with strsep  NOT*/
01541          while( (var = strtok_r(NULL, "|", &tmp)) ) {
01542             pbx_builtin_setvar( chan, var );
01543          } /* /JDG */
01544          if (oh->callerid && *oh->callerid)
01545             ast_set_callerid(chan, oh->callerid, 1);
01546          if (oh->account && *oh->account)
01547             ast_cdr_setaccount(chan, oh->account);
01548       }
01549       if (callerid && strlen(callerid))
01550          ast_set_callerid(chan, callerid, 1);
01551 
01552       if (!ast_call(chan, data, 0)) {
01553          while(timeout && (chan->_state != AST_STATE_UP)) {
01554             res = ast_waitfor(chan, timeout);
01555             if (res < 0) {
01556                /* Something not cool, or timed out */
01557                break;
01558             }
01559             /* If done, break out */
01560             if (!res)
01561                break;
01562             if (timeout > -1)
01563                timeout = res;
01564             f = ast_read(chan);
01565             if (!f) {
01566                state = AST_CONTROL_HANGUP;
01567                res = 0;
01568                break;
01569             }
01570             if (f->frametype == AST_FRAME_CONTROL) {
01571                if (f->subclass == AST_CONTROL_RINGING)
01572                   state = AST_CONTROL_RINGING;
01573                else if ((f->subclass == AST_CONTROL_BUSY) || (f->subclass == AST_CONTROL_CONGESTION)) {
01574                   state = f->subclass;
01575                   ast_frfree(f);
01576                   break;
01577                } else if (f->subclass == AST_CONTROL_ANSWER) {
01578                   state = f->subclass;
01579                   ast_frfree(f);
01580                   break;
01581                } else if (f->subclass == -1) {
01582                   /* Ignore -- just stopping indications */
01583                } else {
01584                   ast_log(LOG_NOTICE, "Don't know what to do with control frame %d\n", f->subclass);
01585                }
01586             }
01587             ast_frfree(f);
01588          }
01589       } else
01590          ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01591    } else
01592       ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
01593    if (chan) {
01594       /* Final fixups */
01595       if (oh) {
01596          if (oh->context && *oh->context)
01597             strncpy(chan->context, oh->context, sizeof(chan->context) - 1);
01598          if (oh->exten && *oh->exten)
01599             strncpy(chan->exten, oh->exten, sizeof(chan->exten) - 1);
01600          chan->priority = oh->priority;
01601       }
01602       if (chan->_state == AST_STATE_UP) 
01603          state = AST_CONTROL_ANSWER;
01604    }
01605    if (outstate)
01606       *outstate = state;
01607    if (chan && res <= 0) {
01608       if (!chan->cdr) {
01609          chan->cdr = ast_cdr_alloc();
01610          if (chan->cdr)
01611             ast_cdr_init(chan->cdr, chan);
01612       }
01613       if (chan->cdr) {
01614          char tmp[256];
01615          sprintf(tmp, "%s/%s",type,(char *)data);
01616          ast_cdr_setapp(chan->cdr,"Dial",tmp);
01617          ast_cdr_update(chan);
01618          ast_cdr_start(chan->cdr);
01619          ast_cdr_end(chan->cdr);
01620          /* If the cause wasn't handled properly */
01621          if (ast_cdr_disposition(chan->cdr,chan->hangupcause))
01622             ast_cdr_failed(chan->cdr);
01623       } else 
01624          ast_log(LOG_WARNING, "Unable to create Call Detail Record\n");
01625       ast_hangup(chan);
01626       chan = NULL;
01627    }
01628    return chan;
01629 }
01630 
01631 struct ast_channel *ast_request_and_dial(char *type, int format, void *data, int timeout, int *outstate, char *callerid)
01632 {
01633    return __ast_request_and_dial(type, format, data, timeout, outstate, callerid, NULL);
01634 }
01635 
01636 struct ast_channel *ast_request(char *type, int format, void *data)
01637 {
01638    struct chanlist *chan;
01639    struct ast_channel *c = NULL;
01640    int capabilities;
01641    int fmt;
01642    int res;
01643    if (ast_mutex_lock(&chlock)) {
01644       ast_log(LOG_WARNING, "Unable to lock channel list\n");
01645       return NULL;
01646    }
01647    chan = backends;
01648    while(chan) {
01649       if (!strcasecmp(type, chan->type)) {
01650          capabilities = chan->capabilities;
01651          fmt = format;
01652          res = ast_translator_best_choice(&fmt, &capabilities);
01653          if (res < 0) {
01654             ast_log(LOG_WARNING, "No translator path exists for channel type %s (native %d) to %d\n", type, chan->capabilities, format);
01655             ast_mutex_unlock(&chlock);
01656             return NULL;
01657          }
01658          ast_mutex_unlock(&chlock);
01659          if (chan->requester)
01660             c = chan->requester(type, capabilities, data);
01661          if (c) {
01662             if (c->_state == AST_STATE_DOWN) {
01663                manager_event(EVENT_FLAG_CALL, "Newchannel",
01664                "Channel: %s\r\n"
01665                "State: %s\r\n"
01666                "Callerid: %s\r\n"
01667                "Uniqueid: %s\r\n",
01668                c->name, ast_state2str(c->_state), c->callerid ? c->callerid : "<unknown>", c->uniqueid);
01669             }
01670          }
01671          return c;
01672       }
01673       chan = chan->next;
01674    }
01675    if (!chan)
01676       ast_log(LOG_WARNING, "No channel type registered for '%s'\n", type);
01677    ast_mutex_unlock(&chlock);
01678    return c;
01679 }
01680 
01681 int ast_parse_device_state(char *device)
01682 {
01683    char name[AST_CHANNEL_NAME] = "";
01684    char *cut;
01685    struct ast_channel *chan;
01686 
01687    chan = ast_channel_walk(NULL);
01688    while (chan) {
01689       strncpy(name, chan->name, sizeof(name)-1);
01690       cut = strchr(name,'-');
01691       if (cut)
01692               *cut = 0;
01693       if (!strcmp(name, device))
01694               return AST_DEVICE_INUSE;
01695       chan = ast_channel_walk(chan);
01696    }
01697    return AST_DEVICE_UNKNOWN;
01698 }
01699 
01700 int ast_device_state(char *device)
01701 {
01702    char tech[AST_MAX_EXTENSION] = "";
01703    char *number;
01704    struct chanlist *chanls;
01705    int res = 0;
01706    
01707    strncpy(tech, device, sizeof(tech)-1);
01708    number = strchr(tech, '/');
01709    if (!number) {
01710        return AST_DEVICE_INVALID;
01711    }
01712    *number = 0;
01713    number++;
01714       
01715    if (ast_mutex_lock(&chlock)) {
01716       ast_log(LOG_WARNING, "Unable to lock channel list\n");
01717       return -1;
01718    }
01719    chanls = backends;
01720    while(chanls) {
01721       if (!strcasecmp(tech, chanls->type)) {
01722          ast_mutex_unlock(&chlock);
01723          if (!chanls->devicestate) 
01724             return ast_parse_device_state(device);
01725          else {
01726             res = chanls->devicestate(number);
01727             if (res == AST_DEVICE_UNKNOWN)
01728                return ast_parse_device_state(device);
01729             else
01730                return res;
01731          }
01732       }
01733       chanls = chanls->next;
01734    }
01735    ast_mutex_unlock(&chlock);
01736    return AST_DEVICE_INVALID;
01737 }
01738 
01739 int ast_call(struct ast_channel *chan, char *addr, int timeout) 
01740 {
01741    /* Place an outgoing call, but don't wait any longer than timeout ms before returning. 
01742       If the remote end does not answer within the timeout, then do NOT hang up, but 
01743       return anyway.  */
01744    int res = -1;
01745    /* Stop if we're a zombie or need a soft hangup */
01746    ast_mutex_lock(&chan->lock);
01747    if (!chan->zombie && !ast_check_hangup(chan)) 
01748       if (chan->pvt->call)
01749          res = chan->pvt->call(chan, addr, timeout);
01750    ast_mutex_unlock(&chan->lock);
01751    return res;
01752 }
01753 
01754 int ast_transfer(struct ast_channel *chan, char *dest) 
01755 {
01756    /* Place an outgoing call, but don't wait any longer than timeout ms before returning. 
01757       If the remote end does not answer within the timeout, then do NOT hang up, but 
01758       return anyway.  */
01759    int res = -1;
01760    /* Stop if we're a zombie or need a soft hangup */
01761    ast_mutex_lock(&chan->lock);
01762    if (!chan->zombie && !ast_check_hangup(chan)) {
01763       if (chan->pvt->transfer) {
01764          res = chan->pvt->transfer(chan, dest);
01765          if (!res)
01766             res = 1;
01767       } else
01768          res = 0;
01769    }
01770    ast_mutex_unlock(&chan->lock);
01771    return res;
01772 }
01773 
01774 int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders)
01775 {
01776    int pos=0;
01777    int to = ftimeout;
01778    char d;
01779    /* XXX Merge with full version? XXX */
01780    /* Stop if we're a zombie or need a soft hangup */
01781    if (c->zombie || ast_check_hangup(c)) 
01782       return -1;
01783    if (!len)
01784       return -1;
01785    do {
01786       if (c->stream) {
01787          d = ast_waitstream(c, AST_DIGIT_ANY);
01788          ast_stopstream(c);
01789          usleep(1000);
01790          if (!d)
01791             d = ast_waitfordigit(c, to);
01792       } else {
01793          d = ast_waitfordigit(c, to);
01794       }
01795       if (d < 0)
01796          return -1;
01797       if (d == 0) {
01798          s[pos]='\0';
01799          return 1;
01800       }
01801       if (!strchr(enders, d))
01802          s[pos++] = d;
01803       if (strchr(enders, d) || (pos >= len)) {
01804          s[pos]='\0';
01805          return 0;
01806       }
01807       to = timeout;
01808    } while(1);
01809    /* Never reached */
01810    return 0;
01811 }
01812 
01813 int ast_readstring_full(struct ast_channel *c, char *s, int len, int timeout, int ftimeout, char *enders, int audiofd, int ctrlfd)
01814 {
01815    int pos=0;
01816    int to = ftimeout;
01817    char d;
01818    /* Stop if we're a zombie or need a soft hangup */
01819    if (c->zombie || ast_check_hangup(c)) 
01820       return -1;
01821    if (!len)
01822       return -1;
01823    do {
01824       if (c->stream) {
01825          d = ast_waitstream_full(c, AST_DIGIT_ANY, audiofd, ctrlfd);
01826          ast_stopstream(c);
01827          usleep(1000);
01828          if (!d)
01829             d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
01830       } else {
01831          d = ast_waitfordigit_full(c, to, audiofd, ctrlfd);
01832       }
01833       if (d < 0)
01834          return -1;
01835       if (d == 0) {
01836          s[pos]='\0';
01837          return 1;
01838       }
01839       if (d == 1) {
01840          s[pos]='\0';
01841          return 2;
01842       }
01843       if (!strchr(enders, d))
01844          s[pos++] = d;
01845       if (strchr(enders, d) || (pos >= len)) {
01846          s[pos]='\0';
01847          return 0;
01848       }
01849       to = timeout;
01850    } while(1);
01851    /* Never reached */
01852    return 0;
01853 }
01854 
01855 int ast_channel_supports_html(struct ast_channel *chan)
01856 {
01857    if (chan->pvt->send_html)
01858       return 1;
01859    return 0;
01860 }
01861 
01862 int ast_channel_sendhtml(struct ast_channel *chan, int subclass, char *data, int datalen)
01863 {
01864    if (chan->pvt->send_html)
01865       return chan->pvt->send_html(chan, subclass, data, datalen);
01866    return -1;
01867 }
01868 
01869 int ast_channel_sendurl(struct ast_channel *chan, char *url)
01870 {
01871    if (chan->pvt->send_html)
01872       return chan->pvt->send_html(chan, AST_HTML_URL, url, strlen(url) + 1);
01873    return -1;
01874 }
01875 
01876 int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
01877 {
01878    int peerf;
01879    int chanf;
01880    int res;
01881    peerf = peer->nativeformats;
01882    chanf = chan->nativeformats;
01883    res = ast_translator_best_choice(&peerf, &chanf);
01884    if (res < 0) {
01885       ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", chan->name, chan->nativeformats, peer->name, peer->nativeformats);
01886       return -1;
01887    }
01888    /* Set read format on channel */
01889    res = ast_set_read_format(chan, peerf);
01890    if (res < 0) {
01891       ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", chan->name, chanf);
01892       return -1;
01893    }
01894    /* Set write format on peer channel */
01895    res = ast_set_write_format(peer, peerf);
01896    if (res < 0) {
01897       ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", peer->name, peerf);
01898       return -1;
01899    }
01900    /* Now we go the other way */
01901    peerf = peer->nativeformats;
01902    chanf = chan->nativeformats;
01903    res = ast_translator_best_choice(&chanf, &peerf);
01904    if (res < 0) {
01905       ast_log(LOG_WARNING, "No path to translate from %s(%d) to %s(%d)\n", peer->name, peer->nativeformats, chan->name, chan->nativeformats);
01906       return -1;
01907    }
01908    /* Set writeformat on channel */
01909    res = ast_set_write_format(chan, chanf);
01910    if (res < 0) {
01911       ast_log(LOG_WARNING, "Unable to set write format on channel %s to %d\n", chan->name, chanf);
01912       return -1;
01913    }
01914    /* Set read format on peer channel */
01915    res = ast_set_read_format(peer, chanf);
01916    if (res < 0) {
01917       ast_log(LOG_WARNING, "Unable to set read format on channel %s to %d\n", peer->name, peerf);
01918       return -1;
01919    }
01920    return 0;
01921 }
01922 
01923 int ast_channel_masquerade(struct ast_channel *original, struct ast_channel *clone)
01924 {
01925    struct ast_frame null = { AST_FRAME_NULL, };
01926    ast_log(LOG_DEBUG, "Planning to masquerade %s into the structure of %s\n",
01927       clone->name, original->name);
01928    if (original->masq) {
01929       ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n", 
01930          original->masq->name, original->name);
01931       return -1;
01932    }
01933    if (clone->masqr) {
01934       ast_log(LOG_WARNING, "%s is already going to masquerade as %s\n", 
01935          clone->name, clone->masqr->name);
01936       return -1;
01937    }
01938    original->masq = clone;
01939    clone->masqr = original;
01940    /* XXX can't really hold the lock here, but at the same time, it' s
01941       not really safe not to XXX */
01942    ast_queue_frame(original, &null, 0);
01943    ast_queue_frame(clone, &null, 0);
01944    ast_log(LOG_DEBUG, "Done planning to masquerade %s into the structure of %s\n", original->name, clone->name);
01945    return 0;
01946 }
01947 
01948 void ast_change_name(struct ast_channel *chan, char *newname)
01949 {
01950    char tmp[256];
01951    strncpy(tmp, chan->name, 256);
01952    strncpy(chan->name, newname, sizeof(chan->name) - 1);
01953    manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\nUniqueid: %s\r\n", tmp, chan->name, chan->uniqueid);
01954 }
01955 
01956 static int ast_do_masquerade(struct ast_channel *original)
01957 {
01958    int x,i;
01959    int res=0;
01960    char *tmp;
01961    struct ast_var_t *varptr;
01962    struct ast_frame *cur, *prev;
01963    struct ast_channel_pvt *p;
01964    struct ast_channel *clone = original->masq;
01965    int rformat = original->readformat;
01966    int wformat = original->writeformat;
01967    char newn[100];
01968    char orig[100];
01969    char masqn[100];
01970    char zombn[100];
01971    
01972 #if 1
01973    ast_log(LOG_DEBUG, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
01974       clone->name, clone->_state, original->name, original->_state);
01975 #endif
01976    /* XXX This is a seriously wacked out operation.  We're essentially putting the guts of
01977       the clone channel into the original channel.  Start by killing off the original
01978       channel's backend.   I'm not sure we're going to keep this function, because 
01979       while the features are nice, the cost is very high in terms of pure nastiness. XXX */
01980 
01981    /* We need the clone's lock, too */
01982    ast_mutex_lock(&clone->lock);
01983 
01984    ast_log(LOG_DEBUG, "Got clone lock on '%s' at %p\n", clone->name, &clone->lock);
01985 
01986    /* Having remembered the original read/write formats, we turn off any translation on either
01987       one */
01988    free_translation(clone);
01989    free_translation(original);
01990 
01991 
01992    /* Unlink the masquerade */
01993    original->masq = NULL;
01994    clone->masqr = NULL;
01995    
01996    /* Save the original name */
01997    strncpy(orig, original->name, sizeof(orig) - 1);
01998    /* Save the new name */
01999    strncpy(newn, clone->name, sizeof(newn) - 1);
02000    /* Create the masq name */
02001    snprintf(masqn, sizeof(masqn), "%s<MASQ>", newn);
02002       
02003    /* Copy the name from the clone channel */
02004    strncpy(original->name, newn, sizeof(original->name)-1);
02005 
02006    /* Mangle the name of the clone channel */
02007    strncpy(clone->name, masqn, sizeof(clone->name) - 1);
02008    
02009    /* Notify any managers of the change, first the masq then the other */
02010    manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", newn, masqn);
02011    manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", orig, newn);
02012 
02013    /* Swap the guts */  
02014    p = original->pvt;
02015    original->pvt = clone->pvt;
02016    clone->pvt = p;
02017 
02018    /* Save any pending frames on both sides.  Start by counting
02019     * how many we're going to need... */
02020    prev = NULL;
02021    cur = clone->pvt->readq;
02022    x = 0;
02023    while(cur) {
02024       x++;
02025       prev = cur;
02026       cur = cur->next;
02027    }
02028    /* If we had any, prepend them to the ones already in the queue, and 
02029     * load up the alertpipe */
02030    if (prev) {
02031       prev->next = original->pvt->readq;
02032       original->pvt->readq = clone->pvt->readq;
02033       clone->pvt->readq = NULL;
02034       if (original->pvt->alertpipe[1] > -1) {
02035          for (i=0;i<x;i++)
02036             write(original->pvt->alertpipe[1], &x, sizeof(x));
02037       }
02038    }
02039    clone->_softhangup = AST_SOFTHANGUP_DEV;
02040 
02041 
02042    if (clone->pvt->fixup){
02043       res = clone->pvt->fixup(original, clone);
02044       if (res) 
02045          ast_log(LOG_WARNING, "Fixup failed on channel %s, strange things may happen.\n", clone->name);
02046    }
02047 
02048    /* Start by disconnecting the original's physical side */
02049    if (clone->pvt->hangup)
02050       res = clone->pvt->hangup(clone);
02051    if (res) {
02052       ast_log(LOG_WARNING, "Hangup failed!  Strange things may happen!\n");
02053       ast_mutex_unlock(&clone->lock);
02054       return -1;
02055    }
02056    
02057    snprintf(zombn, sizeof(zombn), "%s<ZOMBIE>", orig);
02058    /* Mangle the name of the clone channel */
02059    strncpy(clone->name, zombn, sizeof(clone->name) - 1);
02060    manager_event(EVENT_FLAG_CALL, "Rename", "Oldname: %s\r\nNewname: %s\r\n", masqn, zombn);
02061 
02062    /* Keep the same language.  */
02063    /* Update the type. */
02064    original->type = clone->type;
02065    /* Copy the FD's */
02066    for (x=0;x<AST_MAX_FDS;x++) {
02067       original->fds[x] = clone->fds[x];
02068    }
02069    /* Append variables from clone channel into original channel */
02070    /* XXX Is this always correct?  We have to in order to keep MACROS working XXX */
02071    varptr = original->varshead.first;
02072    if (varptr) {
02073       while(varptr->entries.next) {
02074          varptr = varptr->entries.next;
02075       }
02076       varptr->entries.next = clone->varshead.first;
02077    } else {
02078       original->varshead.first = clone->varshead.first;
02079    }
02080    clone->varshead.first = NULL;
02081    /* Presense of ADSI capable CPE follows clone */
02082    original->adsicpe = clone->adsicpe;
02083    /* Bridge remains the same */
02084    /* CDR fields remain the same */
02085    /* XXX What about blocking, softhangup, blocker, and lock and blockproc? XXX */
02086    /* Application and data remain the same */
02087    /* Clone exception  becomes real one, as with fdno */
02088    original->exception = clone->exception;
02089    original->fdno = clone->fdno;
02090    /* Schedule context remains the same */
02091    /* Stream stuff stays the same */
02092    /* Keep the original state.  The fixup code will need to work with it most likely */
02093 
02094    /* dnid and callerid change to become the new, HOWEVER, we also link the original's
02095       fields back into the defunct 'clone' so that they will be freed when
02096       ast_frfree is eventually called */
02097    tmp = original->dnid;
02098    original->dnid = clone->dnid;
02099    clone->dnid = tmp;
02100    
02101    tmp = original->callerid;
02102    original->callerid = clone->callerid;
02103    clone->callerid = tmp;
02104    
02105    /* Restore original timing file descriptor */
02106    original->fds[AST_MAX_FDS - 2] = original->timingfd;
02107    
02108    /* Our native formats are different now */
02109    original->nativeformats = clone->nativeformats;
02110 
02111    /* And of course, so does our current state.  Note we need not
02112       call ast_setstate since the event manager doesn't really consider
02113       these separate */
02114    original->_state = clone->_state;
02115    
02116    /* Context, extension, priority, app data, jump table,  remain the same */
02117    /* pvt switches.  pbx stays the same, as does next */
02118    
02119    /* Set the write format */
02120    ast_set_write_format(original, wformat);
02121 
02122    /* Set the read format */
02123    ast_set_read_format(original, rformat);
02124 
02125    ast_log(LOG_DEBUG, "Putting channel %s in %d/%d formats\n", original->name, wformat, rformat);
02126 
02127    /* Okay.  Last thing is to let the channel driver know about all this mess, so he
02128       can fix up everything as best as possible */
02129    if (original->pvt->fixup) {
02130       res = original->pvt->fixup(clone, original);
02131       if (res) {
02132          ast_log(LOG_WARNING, "Driver for '%s' could not fixup channel %s\n",
02133             original->type, original->name);
02134          return -1;
02135       }
02136    } else
02137       ast_log(LOG_WARNING, "Driver '%s' does not have a fixup routine (for %s)!  Bad things may happen.\n",
02138          original->type, original->name);
02139    
02140    /* Now, at this point, the "clone" channel is totally F'd up.  We mark it as
02141       a zombie so nothing tries to touch it.  If it's already been marked as a
02142       zombie, then free it now (since it already is considered invalid). */
02143    if (clone->zombie) {
02144       ast_log(LOG_DEBUG, "Destroying clone '%s'\n", clone->name);
02145       ast_mutex_unlock(&clone->lock);
02146       ast_channel_free(clone);
02147       manager_event(EVENT_FLAG_CALL, "Hangup", "Channel: %s\r\n", zombn);
02148    } else {
02149       ast_log(LOG_DEBUG, "Released clone lock on '%s'\n", clone->name);
02150       clone->zombie=1;
02151       ast_mutex_unlock(&clone->lock);
02152    }
02153    
02154    /* Signal any blocker */
02155    if (original->blocking)
02156       pthread_kill(original->blocker, SIGURG);
02157    ast_log(LOG_DEBUG, "Done Masquerading %s (%d)\n",
02158       original->name, original->_state);
02159    return 0;
02160 }
02161 
02162 void ast_set_callerid(struct ast_channel *chan, char *callerid, int anitoo)
02163 {
02164    if (chan->callerid)
02165       free(chan->callerid);
02166    if (anitoo && chan->ani)
02167       free(chan->ani);
02168    if (callerid) {
02169       chan->callerid = strdup(callerid);
02170       if (anitoo)
02171          chan->ani = strdup(callerid);
02172    } else {
02173       chan->callerid = NULL;
02174       if (anitoo)
02175          chan->ani = NULL;
02176    }
02177    if (chan->cdr)
02178       ast_cdr_setcid(chan->cdr, chan);
02179    manager_event(EVENT_FLAG_CALL, "Newcallerid", 
02180             "Channel: %s\r\n"
02181             "Callerid: %s\r\n"
02182             "Uniqueid: %s\r\n",
02183             chan->name, chan->callerid ? 
02184             chan->callerid : "<Unknown>",
02185             chan->uniqueid);
02186 }
02187 
02188 int ast_setstate(struct ast_channel *chan, int state)
02189 {
02190    if (chan->_state != state) {
02191       int oldstate = chan->_state;
02192       chan->_state = state;
02193       if (oldstate == AST_STATE_DOWN) {
02194          ast_device_state_changed(chan->name);
02195          manager_event(EVENT_FLAG_CALL, "Newchannel",
02196          "Channel: %s\r\n"
02197          "State: %s\r\n"
02198          "Callerid: %s\r\n"
02199          "Uniqueid: %s\r\n",
02200          chan->name, ast_state2str(chan->_state), chan->callerid ? chan->callerid : "<unknown>", chan->uniqueid);
02201       } else {
02202          manager_event(EVENT_FLAG_CALL, "Newstate", 
02203             "Channel: %s\r\n"
02204             "State: %s\r\n"
02205             "Callerid: %s\r\n"
02206             "Uniqueid: %s\r\n",
02207             chan->name, ast_state2str(chan->_state), chan->callerid ? chan->callerid : "<unknown>", chan->uniqueid);
02208       }
02209    }
02210    return 0;
02211 }
02212 
02213 int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc)
02214 {
02215    /* Copy voice back and forth between the two channels.  Give the peer
02216       the ability to transfer calls with '#<extension' syntax. */
02217    struct ast_channel *cs[3];
02218    int to = -1;
02219    struct ast_frame *f;
02220    struct ast_channel *who = NULL;
02221    int res;
02222    int nativefailed=0;
02223 
02224    /* Stop if we're a zombie or need a soft hangup */
02225    if (c0->zombie || ast_check_hangup_locked(c0) || c1->zombie || ast_check_hangup_locked(c1)) 
02226       return -1;
02227    if (c0->bridge) {
02228       ast_log(LOG_WARNING, "%s is already in a bridge with %s\n", 
02229          c0->name, c0->bridge->name);
02230       return -1;
02231    }
02232    if (c1->bridge) {
02233       ast_log(LOG_WARNING, "%s is already in a bridge with %s\n", 
02234          c1->name, c1->bridge->name);
02235       return -1;
02236    }
02237    
02238    /* Keep track of bridge */
02239    c0->bridge = c1;
02240    c1->bridge = c0;
02241    cs[0] = c0;
02242    cs[1] = c1;
02243    
02244    manager_event(EVENT_FLAG_CALL, "Link", 
02245          "Channel1: %s\r\n"
02246          "Channel2: %s\r\n",
02247          c0->name, c1->name);
02248 
02249    for (/* ever */;;) {
02250       /* Stop if we're a zombie or need a soft hangup */
02251       if (c0->zombie || ast_check_hangup_locked(c0) || c1->zombie || ast_check_hangup_locked(c1)) {
02252          *fo = NULL;
02253          if (who) *rc = who;
02254          res = 0;
02255          ast_log(LOG_DEBUG, "Bridge stops because we're zombie or need a soft hangup: c0=%s, c1=%s, flags: %s,%s,%s,%s\n",c0->name,c1->name,c0->zombie?"Yes":"No",ast_check_hangup(c0)?"Yes":"No",c1->zombie?"Yes":"No",ast_check_hangup(c1)?"Yes":"No");
02256          break;
02257       }
02258       if (c0->pvt->bridge && 
02259          (c0->pvt->bridge == c1->pvt->bridge) && !nativefailed && !c0->monitor && !c1->monitor) {
02260             /* Looks like they share a bridge code */
02261          if (option_verbose > 2) 
02262             ast_verbose(VERBOSE_PREFIX_3 "Attempting native bridge of %s and %s\n", c0->name, c1->name);
02263          if (!(res = c0->pvt->bridge(c0, c1, flags, fo, rc))) {
02264             c0->bridge = NULL;
02265             c1->bridge = NULL;
02266             manager_event(EVENT_FLAG_CALL, "Unlink", 
02267                "Channel1: %s\r\n"
02268                "Channel2: %s\r\n",
02269                c0->name, c1->name);
02270             ast_log(LOG_DEBUG, "Returning from native bridge, channels: %s, %s\n",c0->name ,c1->name);
02271             return 0;
02272          }
02273          /* If they return non-zero then continue on normally.  Let "-2" mean don't worry about
02274             my not wanting to bridge */
02275          if ((res != -2) && (res != -3))
02276             ast_log(LOG_WARNING, "Private bridge between %s and %s failed\n", c0->name, c1->name);
02277          if (res != -3) nativefailed++;
02278       }
02279    
02280          
02281       if (((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat)) &&
02282          !(c0->generator || c1->generator))  {
02283          if (ast_channel_make_compatible(c0, c1)) {
02284             ast_log(LOG_WARNING, "Can't make %s and %s compatible\n", c0->name, c1->name);
02285             manager_event(EVENT_FLAG_CALL, "Unlink", 
02286                "Channel1: %s\r\n"
02287                "Channel2: %s\r\n",
02288                c0->name, c1->name);
02289             return -1;
02290          }
02291       }
02292       who = ast_waitfor_n(cs, 2, &to);
02293       if (!who) {
02294          ast_log(LOG_DEBUG, "Nobody there, continuing...\n"); 
02295          continue;
02296       }
02297       f = ast_read(who);
02298       if (!f) {
02299          *fo = NULL;
02300          *rc = who;
02301          res = 0;
02302          ast_log(LOG_DEBUG, "Didn't get a frame from channel: %s\n",who->name);
02303          break;
02304       }
02305 
02306       if ((f->frametype == AST_FRAME_CONTROL) && !(flags & AST_BRIDGE_IGNORE_SIGS)) {
02307          *fo = f;
02308          *rc = who;
02309          res =  0;
02310          ast_log(LOG_DEBUG, "Got a FRAME_CONTROL (%d) frame on channel %s\n", f->subclass, who->name);
02311          break;
02312       }
02313       if ((f->frametype == AST_FRAME_VOICE) ||
02314          (f->frametype == AST_FRAME_TEXT) ||
02315          (f->frametype == AST_FRAME_VIDEO) || 
02316          (f->frametype == AST_FRAME_IMAGE) ||
02317          (f->frametype == AST_FRAME_DTMF)) {
02318          if ((f->frametype == AST_FRAME_DTMF) && 
02319             (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))) {
02320             if ((who == c0)) {
02321                if  ((flags & AST_BRIDGE_DTMF_CHANNEL_0)) {
02322                   *rc = c0;
02323                   *fo = f;
02324                   /* Take out of conference mode */
02325                   res = 0;
02326                   ast_log(LOG_DEBUG, "Got AST_BRIDGE_DTMF_CHANNEL_0 on c0 (%s)\n",c0->name);
02327                   break;
02328                } else 
02329                   goto tackygoto;
02330             } else
02331             if ((who == c1)) {
02332                if (flags & AST_BRIDGE_DTMF_CHANNEL_1) {
02333                   *rc = c1;
02334                   *fo = f;
02335                   res =  0;
02336                   ast_log(LOG_DEBUG, "Got AST_BRIDGE_DTMF_CHANNEL_1 on c1 (%s)\n",c1->name);
02337                   break;
02338                } else
02339                   goto tackygoto;
02340             }
02341          } else {
02342 #if 0
02343             ast_log(LOG_DEBUG, "Read from %s\n", who->name);
02344             if (who == last) 
02345                ast_log(LOG_DEBUG, "Servicing channel %s twice in a row?\n", last->name);
02346             last = who;
02347 #endif
02348 tackygoto:
02349             /* Don't copy packets if there is a generator on either one, since they're
02350                not supposed to be listening anyway */
02351             if (who == c0) 
02352                ast_write(c1, f);
02353             else 
02354                ast_write(c0, f);
02355          }
02356          ast_frfree(f);
02357       } else
02358          ast_frfree(f);
02359       /* Swap who gets priority */
02360       cs[2] = cs[0];
02361       cs[0] = cs[1];
02362       cs[1] = cs[2];
02363    }
02364    c0->bridge = NULL;
02365    c1->bridge = NULL;
02366    manager_event(EVENT_FLAG_CALL, "Unlink", 
02367                "Channel1: %s\r\n"
02368                "Channel2: %s\r\n",
02369                c0->name, c1->name);
02370    ast_log(LOG_DEBUG, "Bridge stops bridging channels %s and %s\n",c0->name,c1->name);
02371    return res;
02372 }
02373 
02374 int ast_channel_setoption(struct ast_channel *chan, int option, void *data, int datalen, int block)
02375 {
02376    int res;
02377    if (chan->pvt->setoption) {
02378       res = chan->pvt->setoption(chan, option, data, datalen);
02379       if (res < 0)
02380          return res;
02381    } else {
02382       errno = ENOSYS;
02383       return -1;
02384    }
02385    if (block) {
02386       /* XXX Implement blocking -- just wait for our option frame reply, discarding
02387          intermediate packets. XXX */
02388       ast_log(LOG_ERROR, "XXX Blocking not implemented yet XXX\n");
02389       return -1;
02390    }
02391    return 0;
02392 }
02393 
02394 struct tonepair_def {
02395    int freq1;
02396    int freq2;
02397    int duration;
02398    int vol;
02399 };
02400 
02401 struct tonepair_state {
02402    float freq1;
02403    float freq2;
02404    float vol;
02405    int duration;
02406    int pos;
02407    int origwfmt;
02408    struct ast_frame f;
02409    unsigned char offset[AST_FRIENDLY_OFFSET];
02410    short data[4000];
02411 };
02412 
02413 static void tonepair_release(struct ast_channel *chan, void *params)
02414 {
02415    struct tonepair_state *ts = params;
02416    if (chan) {
02417       ast_set_write_format(chan, ts->origwfmt);
02418    }
02419    free(ts);
02420 }
02421 
02422 static void * tonepair_alloc(struct ast_channel *chan, void *params)
02423 {
02424    struct tonepair_state *ts;
02425    struct tonepair_def *td = params;
02426    ts = malloc(sizeof(struct tonepair_state));
02427    if (!ts)
02428       return NULL;
02429    memset(ts, 0, sizeof(struct tonepair_state));
02430    ts->origwfmt = chan->writeformat;
02431    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
02432       ast_log(LOG_WARNING, "Unable to set '%s' to signed linear format (write)\n", chan->name);
02433       tonepair_release(NULL, ts);
02434       ts = NULL;
02435    } else {
02436       ts->freq1 = td->freq1;
02437       ts->freq2 = td->freq2;
02438       ts->duration = td->duration;
02439       ts->vol = td->vol;
02440    }
02441    /* Let interrupts interrupt :) */
02442    chan->writeinterrupt = 1;
02443    return ts;
02444 }
02445 
02446 static int tonepair_generator(struct ast_channel *chan, void *data, int len, int samples)
02447 {
02448    struct tonepair_state *ts = data;
02449    int x;
02450 
02451    /* we need to prepare a frame with 16 * timelen samples as we're 
02452     * generating SLIN audio
02453     */
02454    len = samples * 2;
02455 
02456    if (len > sizeof(ts->data) / 2 - 1) {
02457       ast_log(LOG_WARNING, "Can't generate that much data!\n");
02458       return -1;
02459    }
02460    memset(&ts->f, 0, sizeof(ts->f));
02461    for (x=0;x<len/2;x++) {
02462       ts->data[x] = ts->vol * (
02463             sin((ts->freq1 * 2.0 * M_PI / 8000.0) * (ts->pos + x)) +
02464             sin((ts->freq2 * 2.0 * M_PI / 8000.0) * (ts->pos + x))
02465          );
02466    }
02467    ts->f.frametype = AST_FRAME_VOICE;
02468    ts->f.subclass = AST_FORMAT_SLINEAR;
02469    ts->f.datalen = len;
02470    ts->f.samples = samples;
02471    ts->f.offset = AST_FRIENDLY_OFFSET;
02472    ts->f.data = ts->data;
02473    ast_write(chan, &ts->f);
02474    ts->pos += x;
02475    if (ts->duration > 0) {
02476       if (ts->pos >= ts->duration * 8)
02477          return -1;
02478    }
02479    return 0;
02480 }
02481 
02482 static struct ast_generator tonepair = {
02483    alloc: tonepair_alloc,
02484    release: tonepair_release,
02485    generate: tonepair_generator,
02486 };
02487 
02488 int ast_tonepair_start(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
02489 {
02490    struct tonepair_def d = { 0, };
02491    d.freq1 = freq1;
02492    d.freq2 = freq2;
02493    d.duration = duration;
02494    if (vol < 1)
02495       d.vol = 8192;
02496    else
02497       d.vol = vol;
02498    if (ast_activate_generator(chan, &tonepair, &d))
02499       return -1;
02500    return 0;
02501 }
02502 
02503 void ast_tonepair_stop(struct ast_channel *chan)
02504 {
02505    ast_deactivate_generator(chan);
02506 }
02507 
02508 int ast_tonepair(struct ast_channel *chan, int freq1, int freq2, int duration, int vol)
02509 {
02510    struct ast_frame *f;
02511    int res;
02512    if ((res = ast_tonepair_start(chan, freq1, freq2, duration, vol)))
02513       return res;
02514 
02515    /* Give us some wiggle room */
02516    while(chan->generatordata && (ast_waitfor(chan, 100) >= 0)) {
02517       f = ast_read(chan);
02518       if (f)
02519          ast_frfree(f);
02520       else
02521          return -1;
02522    }
02523    return 0;
02524 }
02525 
02526 unsigned int ast_get_group(char *s)
02527 {
02528    char *copy;
02529    char *piece;
02530    char *c=NULL;
02531    int start=0, finish=0,x;
02532    unsigned int group = 0;
02533    copy = ast_strdupa(s);
02534    if (!copy) {
02535       ast_log(LOG_ERROR, "Out of memory\n");
02536       return 0;
02537    }
02538    c = copy;
02539    
02540    while((piece = strsep(&c, ","))) {
02541       if (sscanf(piece, "%d-%d", &start, &finish) == 2) {
02542          /* Range */
02543       } else if (sscanf(piece, "%d", &start)) {
02544          /* Just one */
02545          finish = start;
02546       } else {
02547          ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'.  Using '0'\n", s,piece);
02548          return 0;
02549       }
02550       for (x=start;x<=finish;x++) {
02551          if ((x > 31) || (x < 0)) {
02552             ast_log(LOG_WARNING, "Ignoring invalid group %d (maximum group is 31)\n", x);
02553          } else
02554             group |= (1 << x);
02555       }
02556    }
02557    return group;
02558 }

Generated on Sun Apr 18 23:33:49 2004 for Asterisk by doxygen 1.3.6-20040222