Fri Jun 19 12:09:32 2009

Asterisk developer's documentation


chan_dahdi.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 1999 - 2006, Digium, Inc.
00005  *
00006  * Mark Spencer <markster@digium.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  */
00018 
00019 /*! \file
00020  *
00021  * \brief DAHDI for Pseudo TDM
00022  *
00023  * \author Mark Spencer <markster@digium.com>
00024  * 
00025  * Connects to the DAHDI telephony library as well as 
00026  * libpri. Libpri is optional and needed only if you are
00027  * going to use ISDN connections.
00028  *
00029  * You need to install libraries before you attempt to compile
00030  * and install the DAHDI channel.
00031  *
00032  * \par See also
00033  * \arg \ref Config_dahdi
00034  *
00035  * \ingroup channel_drivers
00036  *
00037  * \todo Deprecate the "musiconhold" configuration option post 1.4
00038  */
00039 
00040 /*** MODULEINFO
00041    <depend>res_smdi</depend>
00042    <depend>dahdi</depend>
00043    <depend>tonezone</depend>
00044    <use>pri</use>
00045    <use>ss7</use>
00046  ***/
00047 
00048 #include "asterisk.h"
00049 
00050 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 188940 $")
00051 
00052 #ifdef __NetBSD__
00053 #include <pthread.h>
00054 #include <signal.h>
00055 #else
00056 #include <sys/signal.h>
00057 #endif
00058 #include <sys/ioctl.h>
00059 #include <math.h>
00060 #include <ctype.h>
00061 
00062 #include <dahdi/user.h>
00063 #include <dahdi/tonezone.h>
00064 
00065 #ifdef HAVE_PRI
00066 #include <libpri.h>
00067 #endif
00068 
00069 #ifdef HAVE_SS7
00070 #include <libss7.h>
00071 #endif
00072 
00073 #include "asterisk/lock.h"
00074 #include "asterisk/channel.h"
00075 #include "asterisk/config.h"
00076 #include "asterisk/module.h"
00077 #include "asterisk/pbx.h"
00078 #include "asterisk/file.h"
00079 #include "asterisk/ulaw.h"
00080 #include "asterisk/alaw.h"
00081 #include "asterisk/callerid.h"
00082 #include "asterisk/adsi.h"
00083 #include "asterisk/cli.h"
00084 #include "asterisk/cdr.h"
00085 #include "asterisk/features.h"
00086 #include "asterisk/musiconhold.h"
00087 #include "asterisk/say.h"
00088 #include "asterisk/tdd.h"
00089 #include "asterisk/app.h"
00090 #include "asterisk/dsp.h"
00091 #include "asterisk/astdb.h"
00092 #include "asterisk/manager.h"
00093 #include "asterisk/causes.h"
00094 #include "asterisk/term.h"
00095 #include "asterisk/utils.h"
00096 #include "asterisk/transcap.h"
00097 #include "asterisk/stringfields.h"
00098 #include "asterisk/abstract_jb.h"
00099 #include "asterisk/smdi.h"
00100 #include "asterisk/astobj.h"
00101 #include "asterisk/event.h"
00102 #include "asterisk/devicestate.h"
00103 
00104 #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
00105 
00106 static const char *lbostr[] = {
00107 "0 db (CSU)/0-133 feet (DSX-1)",
00108 "133-266 feet (DSX-1)",
00109 "266-399 feet (DSX-1)",
00110 "399-533 feet (DSX-1)",
00111 "533-655 feet (DSX-1)",
00112 "-7.5db (CSU)",
00113 "-15db (CSU)",
00114 "-22.5db (CSU)"
00115 };
00116 
00117 /*! Global jitterbuffer configuration - by default, jb is disabled */
00118 static struct ast_jb_conf default_jbconf =
00119 {
00120    .flags = 0,
00121    .max_size = -1,
00122    .resync_threshold = -1,
00123    .impl = ""
00124 };
00125 static struct ast_jb_conf global_jbconf;
00126 
00127 /* define this to send PRI user-user information elements */
00128 #undef SUPPORT_USERUSER
00129 
00130 /*! 
00131  * \note Define ZHONE_HACK to cause us to go off hook and then back on hook when
00132  * the user hangs up to reset the state machine so ring works properly.
00133  * This is used to be able to support kewlstart by putting the zhone in
00134  * groundstart mode since their forward disconnect supervision is entirely
00135  * broken even though their documentation says it isn't and their support
00136  * is entirely unwilling to provide any assistance with their channel banks
00137  * even though their web site says they support their products for life.
00138  */
00139 /* #define ZHONE_HACK */
00140 
00141 /*! \note
00142  * Define if you want to check the hook state for an FXO (FXS signalled) interface
00143  * before dialing on it.  Certain FXO interfaces always think they're out of
00144  * service with this method however.
00145  */
00146 /* #define DAHDI_CHECK_HOOKSTATE */
00147 
00148 /*! \brief Typically, how many rings before we should send Caller*ID */
00149 #define DEFAULT_CIDRINGS 1
00150 
00151 #define CHANNEL_PSEUDO -12
00152 
00153 #define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? AST_FORMAT_ALAW : AST_FORMAT_ULAW)
00154 
00155 
00156 /*! \brief Signaling types that need to use MF detection should be placed in this macro */
00157 #define NEED_MFDETECT(p) (((p)->sig == SIG_FEATDMF) || ((p)->sig == SIG_FEATDMF_TA) || ((p)->sig == SIG_E911) || ((p)->sig == SIG_FGC_CAMA) || ((p)->sig == SIG_FGC_CAMAMF) || ((p)->sig == SIG_FEATB)) 
00158 
00159 static const char tdesc[] = "DAHDI Telephony Driver"
00160 #ifdef HAVE_PRI
00161                " w/PRI"
00162 #endif
00163 #ifdef HAVE_SS7
00164           " w/SS7"
00165 #endif
00166 ;
00167 
00168 static const char config[] = "chan_dahdi.conf";
00169 
00170 #define SIG_EM    DAHDI_SIG_EM
00171 #define SIG_EMWINK   (0x0100000 | DAHDI_SIG_EM)
00172 #define SIG_FEATD (0x0200000 | DAHDI_SIG_EM)
00173 #define  SIG_FEATDMF (0x0400000 | DAHDI_SIG_EM)
00174 #define  SIG_FEATB   (0x0800000 | DAHDI_SIG_EM)
00175 #define  SIG_E911 (0x1000000 | DAHDI_SIG_EM)
00176 #define  SIG_FEATDMF_TA (0x2000000 | DAHDI_SIG_EM)
00177 #define  SIG_FGC_CAMA   (0x4000000 | DAHDI_SIG_EM)
00178 #define  SIG_FGC_CAMAMF (0x8000000 | DAHDI_SIG_EM)
00179 #define SIG_FXSLS DAHDI_SIG_FXSLS
00180 #define SIG_FXSGS DAHDI_SIG_FXSGS
00181 #define SIG_FXSKS DAHDI_SIG_FXSKS
00182 #define SIG_FXOLS DAHDI_SIG_FXOLS
00183 #define SIG_FXOGS DAHDI_SIG_FXOGS
00184 #define SIG_FXOKS DAHDI_SIG_FXOKS
00185 #define SIG_PRI      DAHDI_SIG_CLEAR
00186 #define SIG_BRI      (0x2000000 | DAHDI_SIG_CLEAR)
00187 #define SIG_BRI_PTMP (0X4000000 | DAHDI_SIG_CLEAR)
00188 #define SIG_SS7      (0x1000000 | DAHDI_SIG_CLEAR)
00189 #define  SIG_SF      DAHDI_SIG_SF
00190 #define SIG_SFWINK   (0x0100000 | DAHDI_SIG_SF)
00191 #define SIG_SF_FEATD (0x0200000 | DAHDI_SIG_SF)
00192 #define  SIG_SF_FEATDMF (0x0400000 | DAHDI_SIG_SF)
00193 #define  SIG_SF_FEATB   (0x0800000 | DAHDI_SIG_SF)
00194 #define SIG_EM_E1 DAHDI_SIG_EM_E1
00195 #define SIG_GR303FXOKS  (0x0100000 | DAHDI_SIG_FXOKS)
00196 #define SIG_GR303FXSKS  (0x0100000 | DAHDI_SIG_FXSKS)
00197 
00198 #ifdef LOTS_OF_SPANS
00199 #define NUM_SPANS DAHDI_MAX_SPANS
00200 #else
00201 #define NUM_SPANS       32
00202 #endif
00203 #define NUM_DCHANS      4  /*!< No more than 4 d-channels */
00204 #define MAX_CHANNELS 672      /*!< No more than a DS3 per trunk group */
00205 
00206 #define CHAN_PSEUDO  -2
00207 
00208 #define DCHAN_PROVISIONED (1 << 0)
00209 #define DCHAN_NOTINALARM  (1 << 1)
00210 #define DCHAN_UP          (1 << 2)
00211 
00212 #define DCHAN_AVAILABLE (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP)
00213 
00214 /* Overlap dialing option types */
00215 #define DAHDI_OVERLAPDIAL_NONE 0
00216 #define DAHDI_OVERLAPDIAL_OUTGOING 1
00217 #define DAHDI_OVERLAPDIAL_INCOMING 2
00218 #define DAHDI_OVERLAPDIAL_BOTH (DAHDI_OVERLAPDIAL_INCOMING|DAHDI_OVERLAPDIAL_OUTGOING)
00219 
00220 
00221 #define CALLPROGRESS_PROGRESS    1
00222 #define CALLPROGRESS_FAX_OUTGOING   2
00223 #define CALLPROGRESS_FAX_INCOMING   4
00224 #define CALLPROGRESS_FAX      (CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
00225 
00226 static char defaultcic[64] = "";
00227 static char defaultozz[64] = "";
00228 
00229 static char parkinglot[AST_MAX_EXTENSION] = "";    /*!< Default parking lot for this channel */
00230 
00231 /*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */
00232 static char mwimonitornotify[PATH_MAX] = "";
00233 static int  mwisend_rpas = 0;
00234 
00235 static char progzone[10] = "";
00236 
00237 static int usedistinctiveringdetection = 0;
00238 static int distinctiveringaftercid = 0;
00239 
00240 static int numbufs = 4;
00241 
00242 static int mwilevel = 512;
00243 
00244 #ifdef HAVE_PRI
00245 static struct ast_channel inuse;
00246 #ifdef PRI_GETSET_TIMERS
00247 static int pritimers[PRI_MAX_TIMERS];
00248 #endif
00249 static int pridebugfd = -1;
00250 static char pridebugfilename[1024] = "";
00251 #endif
00252 
00253 /*! \brief Wait up to 16 seconds for first digit (FXO logic) */
00254 static int firstdigittimeout = 16000;
00255 
00256 /*! \brief How long to wait for following digits (FXO logic) */
00257 static int gendigittimeout = 8000;
00258 
00259 /*! \brief How long to wait for an extra digit, if there is an ambiguous match */
00260 static int matchdigittimeout = 3000;
00261 
00262 /*! \brief Protect the interface list (of dahdi_pvt's) */
00263 AST_MUTEX_DEFINE_STATIC(iflock);
00264 
00265 
00266 static int ifcount = 0;
00267 
00268 #ifdef HAVE_PRI
00269 AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
00270 #endif
00271 
00272 /*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
00273    when it's doing something critical. */
00274 AST_MUTEX_DEFINE_STATIC(monlock);
00275 
00276 /*! \brief This is the thread for the monitor which checks for input on the channels
00277    which are not currently in use. */
00278 static pthread_t monitor_thread = AST_PTHREADT_NULL;
00279 static ast_cond_t mwi_thread_complete;
00280 static ast_cond_t ss_thread_complete;
00281 AST_MUTEX_DEFINE_STATIC(mwi_thread_lock);
00282 AST_MUTEX_DEFINE_STATIC(ss_thread_lock);
00283 AST_MUTEX_DEFINE_STATIC(restart_lock);
00284 static int mwi_thread_count = 0;
00285 static int ss_thread_count = 0;
00286 static int num_restart_pending = 0;
00287 
00288 static int restart_monitor(void);
00289 
00290 static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
00291 
00292 static int dahdi_sendtext(struct ast_channel *c, const char *text);
00293 
00294 static void mwi_event_cb(const struct ast_event *event, void *userdata)
00295 {
00296    /* This module does not handle MWI in an event-based manner.  However, it
00297     * subscribes to MWI for each mailbox that is configured so that the core
00298     * knows that we care about it.  Then, chan_dahdi will get the MWI from the
00299     * event cache instead of checking the mailbox directly. */
00300 }
00301 
00302 /*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
00303 static inline int dahdi_get_event(int fd)
00304 {
00305    int j;
00306    if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
00307       return -1;
00308    return j;
00309 }
00310 
00311 /*! \brief Avoid the silly dahdi_waitevent which ignores a bunch of events */
00312 static inline int dahdi_wait_event(int fd)
00313 {
00314    int i, j = 0;
00315    i = DAHDI_IOMUX_SIGEVENT;
00316    if (ioctl(fd, DAHDI_IOMUX, &i) == -1)
00317       return -1;
00318    if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
00319       return -1;
00320    return j;
00321 }
00322 
00323 /*! Chunk size to read -- we use 20ms chunks to make things happy. */
00324 #define READ_SIZE 160
00325 
00326 #define MASK_AVAIL      (1 << 0) /*!< Channel available for PRI use */
00327 #define MASK_INUSE      (1 << 1) /*!< Channel currently in use */
00328 
00329 #define CALLWAITING_SILENT_SAMPLES  ( (300 * 8) / READ_SIZE) /*!< 300 ms */
00330 #define CALLWAITING_REPEAT_SAMPLES  ( (10000 * 8) / READ_SIZE) /*!< 10,000 ms */
00331 #define CIDCW_EXPIRE_SAMPLES     ( (500 * 8) / READ_SIZE) /*!< 500 ms */
00332 #define MIN_MS_SINCE_FLASH       ( (2000) )  /*!< 2000 ms */
00333 #define DEFAULT_RINGT            ( (8000 * 8) / READ_SIZE) /*!< 8,000 ms */
00334 
00335 struct dahdi_pvt;
00336 
00337 /*!
00338  * \brief Configured ring timeout base.
00339  * \note Value computed from "ringtimeout" read in from chan_dahdi.conf if it exists.
00340  */
00341 static int ringt_base = DEFAULT_RINGT;
00342 
00343 #ifdef HAVE_SS7
00344 
00345 #define LINKSTATE_INALARM  (1 << 0)
00346 #define LINKSTATE_STARTING (1 << 1)
00347 #define LINKSTATE_UP    (1 << 2)
00348 #define LINKSTATE_DOWN     (1 << 3)
00349 
00350 #define SS7_NAI_DYNAMIC    -1
00351 
00352 #define LINKSET_FLAG_EXPLICITACM (1 << 0)
00353 
00354 struct dahdi_ss7 {
00355    pthread_t master;                /*!< Thread of master */
00356    ast_mutex_t lock;
00357    int fds[NUM_DCHANS];
00358    int numsigchans;
00359    int linkstate[NUM_DCHANS];
00360    int numchans;
00361    int type;
00362    enum {
00363       LINKSET_STATE_DOWN = 0,
00364       LINKSET_STATE_UP
00365    } state;
00366    char called_nai;                 /*!< Called Nature of Address Indicator */
00367    char calling_nai;                /*!< Calling Nature of Address Indicator */
00368    char internationalprefix[10];             /*!< country access code ('00' for european dialplans) */
00369    char nationalprefix[10];               /*!< area access code ('0' for european dialplans) */
00370    char subscriberprefix[20];             /*!< area access code + area code ('0'+area code for european dialplans) */
00371    char unknownprefix[20];                /*!< for unknown dialplans */
00372    struct ss7 *ss7;
00373    struct dahdi_pvt *pvts[MAX_CHANNELS];           /*!< Member channel pvt structs */
00374    int flags;                    /*!< Linkset flags */
00375 };
00376 
00377 static struct dahdi_ss7 linksets[NUM_SPANS];
00378 
00379 static int cur_ss7type = -1;
00380 static int cur_linkset = -1;
00381 static int cur_pointcode = -1;
00382 static int cur_cicbeginswith = -1;
00383 static int cur_adjpointcode = -1;
00384 static int cur_networkindicator = -1;
00385 static int cur_defaultdpc = -1;
00386 #endif /* HAVE_SS7 */
00387 
00388 #ifdef HAVE_PRI
00389 
00390 #define PVT_TO_CHANNEL(p) (((p)->prioffset) | ((p)->logicalspan << 8) | (p->pri->mastertrunkgroup ? 0x10000 : 0))
00391 #define PRI_CHANNEL(p) ((p) & 0xff)
00392 #define PRI_SPAN(p) (((p) >> 8) & 0xff)
00393 #define PRI_EXPLICIT(p) (((p) >> 16) & 0x01)
00394 
00395 struct dahdi_pri {
00396    pthread_t master;                /*!< Thread of master */
00397    ast_mutex_t lock;                /*!< Mutex */
00398    char idleext[AST_MAX_EXTENSION];          /*!< Where to idle extra calls */
00399    char idlecontext[AST_MAX_CONTEXT];           /*!< What context to use for idle */
00400    char idledial[AST_MAX_EXTENSION];            /*!< What to dial before dumping */
00401    int minunused;                   /*!< Min # of channels to keep empty */
00402    int minidle;                     /*!< Min # of "idling" calls to keep active */
00403    int nodetype;                    /*!< Node type */
00404    int switchtype;                     /*!< Type of switch to emulate */
00405    int nsf;                   /*!< Network-Specific Facilities */
00406    int dialplan;                    /*!< Dialing plan */
00407    int localdialplan;                  /*!< Local dialing plan */
00408    char internationalprefix[10];             /*!< country access code ('00' for european dialplans) */
00409    char nationalprefix[10];               /*!< area access code ('0' for european dialplans) */
00410    char localprefix[20];                  /*!< area access code + area code ('0'+area code for european dialplans) */
00411    char privateprefix[20];                /*!< for private dialplans */
00412    char unknownprefix[20];                /*!< for unknown dialplans */
00413    int dchannels[NUM_DCHANS];             /*!< What channel are the dchannels on */
00414    int trunkgroup;                     /*!< What our trunkgroup is */
00415    int mastertrunkgroup;                  /*!< What trunk group is our master */
00416    int prilogicalspan;                 /*!< Logical span number within trunk group */
00417    int numchans;                    /*!< Num of channels we represent */
00418    int overlapdial;                 /*!< In overlap dialing mode */
00419    int facilityenable;                 /*!< Enable facility IEs */
00420    struct pri *dchans[NUM_DCHANS];              /*!< Actual d-channels */
00421    int dchanavail[NUM_DCHANS];               /*!< Whether each channel is available */
00422    struct pri *pri;                 /*!< Currently active D-channel */
00423    /*! \brief TRUE if to dump PRI event info (Tested but never set) */
00424    int debug;
00425    int fds[NUM_DCHANS];                /*!< FD's for d-channels */
00426    /*! \brief Value set but not used */
00427    int offset;
00428    /*! \brief Span number put into user output messages */
00429    int span;
00430    /*! \brief TRUE if span is being reset/restarted */
00431    int resetting;
00432    /*! \brief Current position during a reset (-1 if not started) */
00433    int resetpos;
00434 #ifdef HAVE_PRI_INBANDDISCONNECT
00435    unsigned int inbanddisconnect:1;          /*!< Should we support inband audio after receiving DISCONNECT? */
00436 #endif
00437    time_t lastreset;                /*!< time when unused channels were last reset */
00438    long resetinterval;                 /*!< Interval (in seconds) for resetting unused channels */
00439    /*! \brief ISDN signalling type (SIG_PRI, SIG_BRI, SIG_BRI_PTMP, etc...) */
00440    int sig;
00441    struct dahdi_pvt *pvts[MAX_CHANNELS];           /*!< Member channel pvt structs */
00442    struct dahdi_pvt *crvs;                /*!< Member CRV structs */
00443    struct dahdi_pvt *crvend;                 /*!< Pointer to end of CRV structs */
00444 };
00445 
00446 
00447 static struct dahdi_pri pris[NUM_SPANS];
00448 
00449 #if 0
00450 #define DEFAULT_PRI_DEBUG (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE)
00451 #else
00452 #define DEFAULT_PRI_DEBUG 0
00453 #endif
00454 
00455 static inline void pri_rel(struct dahdi_pri *pri)
00456 {
00457    ast_mutex_unlock(&pri->lock);
00458 }
00459 
00460 #else
00461 /*! Shut up the compiler */
00462 struct dahdi_pri;
00463 #endif
00464 
00465 #define SUB_REAL  0        /*!< Active call */
00466 #define SUB_CALLWAIT 1        /*!< Call-Waiting call on hold */
00467 #define SUB_THREEWAY 2        /*!< Three-way call */
00468 
00469 /* Polarity states */
00470 #define POLARITY_IDLE   0
00471 #define POLARITY_REV    1
00472 
00473 
00474 struct distRingData {
00475    int ring[3];
00476    int range;
00477 };
00478 struct ringContextData {
00479    char contextData[AST_MAX_CONTEXT];
00480 };
00481 struct dahdi_distRings {
00482    struct distRingData ringnum[3];
00483    struct ringContextData ringContext[3];
00484 };
00485 
00486 static char *subnames[] = {
00487    "Real",
00488    "Callwait",
00489    "Threeway"
00490 };
00491 
00492 struct dahdi_subchannel {
00493    int dfd;
00494    struct ast_channel *owner;
00495    int chan;
00496    short buffer[AST_FRIENDLY_OFFSET/2 + READ_SIZE];
00497    struct ast_frame f;     /*!< One frame for each channel.  How did this ever work before? */
00498    unsigned int needringing:1;
00499    unsigned int needbusy:1;
00500    unsigned int needcongestion:1;
00501    unsigned int needcallerid:1;
00502    unsigned int needanswer:1;
00503    unsigned int needflash:1;
00504    unsigned int needhold:1;
00505    unsigned int needunhold:1;
00506    unsigned int linear:1;
00507    unsigned int inthreeway:1;
00508    struct dahdi_confinfo curconf;
00509 };
00510 
00511 #define CONF_USER_REAL     (1 << 0)
00512 #define CONF_USER_THIRDCALL   (1 << 1)
00513 
00514 #define MAX_SLAVES   4
00515 
00516 static struct dahdi_pvt {
00517    ast_mutex_t lock;
00518    struct ast_channel *owner;       /*!< Our current active owner (if applicable) */
00519                      /*!< Up to three channels can be associated with this call */
00520       
00521    struct dahdi_subchannel sub_unused;    /*!< Just a safety precaution */
00522    struct dahdi_subchannel subs[3];       /*!< Sub-channels */
00523    struct dahdi_confinfo saveconf;        /*!< Saved conference info */
00524 
00525    struct dahdi_pvt *slaves[MAX_SLAVES];     /*!< Slave to us (follows our conferencing) */
00526    struct dahdi_pvt *master;           /*!< Master to us (we follow their conferencing) */
00527    int inconference;          /*!< If our real should be in the conference */
00528    
00529    int buf_no;             /*!< Number of buffers */
00530    int buf_policy;            /*!< Buffer policy */
00531    int sig;             /*!< Signalling style */
00532    /*!
00533     * \brief Nonzero if the signaling type is sent over a radio.
00534     * \note Set to a couple of nonzero values but it is only tested like a boolean.
00535     */
00536    int radio;
00537    int outsigmod;             /*!< Outbound Signalling style (modifier) */
00538    int oprmode;               /*!< "Operator Services" mode */
00539    struct dahdi_pvt *oprpeer;          /*!< "Operator Services" peer tech_pvt ptr */
00540    /*! \brief Amount of gain to increase during caller id */
00541    float cid_rxgain;
00542    /*! \brief Rx gain set by chan_dahdi.conf */
00543    float rxgain;
00544    /*! \brief Tx gain set by chan_dahdi.conf */
00545    float txgain;
00546    int tonezone;              /*!< tone zone for this chan, or -1 for default */
00547    struct dahdi_pvt *next;          /*!< Next channel in list */
00548    struct dahdi_pvt *prev;          /*!< Prev channel in list */
00549 
00550    /* flags */
00551 
00552    /*!
00553     * \brief TRUE if ADSI (Analog Display Services Interface) available
00554     * \note Set from the "adsi" value read in from chan_dahdi.conf
00555     */
00556    unsigned int adsi:1;
00557    /*!
00558     * \brief TRUE if we can use a polarity reversal to mark when an outgoing
00559     * call is answered by the remote party.
00560     * \note Set from the "answeronpolarityswitch" value read in from chan_dahdi.conf
00561     */
00562    unsigned int answeronpolarityswitch:1;
00563    /*!
00564     * \brief TRUE if busy detection is enabled.
00565     * (Listens for the beep-beep busy pattern.)
00566     * \note Set from the "busydetect" value read in from chan_dahdi.conf
00567     */
00568    unsigned int busydetect:1;
00569    /*!
00570     * \brief TRUE if call return is enabled.
00571     * (*69, if your dialplan doesn't catch this first)
00572     * \note Set from the "callreturn" value read in from chan_dahdi.conf
00573     */
00574    unsigned int callreturn:1;
00575    /*!
00576     * \brief TRUE if busy extensions will hear the call-waiting tone
00577     * and can use hook-flash to switch between callers.
00578     * \note Can be disabled by dialing *70.
00579     * \note Initialized with the "callwaiting" value read in from chan_dahdi.conf
00580     */
00581    unsigned int callwaiting:1;
00582    /*!
00583     * \brief TRUE if send caller ID for Call Waiting
00584     * \note Set from the "callwaitingcallerid" value read in from chan_dahdi.conf
00585     */
00586    unsigned int callwaitingcallerid:1;
00587    /*!
00588     * \brief TRUE if support for call forwarding enabled.
00589     * Dial *72 to enable call forwarding.
00590     * Dial *73 to disable call forwarding.
00591     * \note Set from the "cancallforward" value read in from chan_dahdi.conf
00592     */
00593    unsigned int cancallforward:1;
00594    /*!
00595     * \brief TRUE if support for call parking is enabled.
00596     * \note Set from the "canpark" value read in from chan_dahdi.conf
00597     */
00598    unsigned int canpark:1;
00599    /*! \brief TRUE if to wait for a DTMF digit to confirm answer */
00600    unsigned int confirmanswer:1;
00601    /*!
00602     * \brief TRUE if the channel is to be destroyed on hangup.
00603     * (Used by pseudo channels.)
00604     */
00605    unsigned int destroy:1;
00606    unsigned int didtdd:1;           /*!< flag to say its done it once */
00607    /*! \brief TRUE if analog type line dialed no digits in Dial() */
00608    unsigned int dialednone:1;
00609    /*! \brief TRUE if in the process of dialing digits or sending something. */
00610    unsigned int dialing:1;
00611    /*! \brief TRUE if the transfer capability of the call is digital. */
00612    unsigned int digital:1;
00613    /*! \brief TRUE if Do-Not-Disturb is enabled. */
00614    unsigned int dnd:1;
00615    /*! \brief XXX BOOLEAN Purpose??? */
00616    unsigned int echobreak:1;
00617    /*!
00618     * \brief TRUE if echo cancellation enabled when bridged.
00619     * \note Initialized with the "echocancelwhenbridged" value read in from chan_dahdi.conf
00620     * \note Disabled if the echo canceller is not setup.
00621     */
00622    unsigned int echocanbridged:1;
00623    /*! \brief TRUE if echo cancellation is turned on. */
00624    unsigned int echocanon:1;
00625    /*! \brief TRUE if a fax tone has already been handled. */
00626    unsigned int faxhandled:1;
00627    /*! \brief TRUE if over a radio and dahdi_read() has been called. */
00628    unsigned int firstradio:1;
00629    /*!
00630     * \brief TRUE if the call will be considered "hung up" on a polarity reversal.
00631     * \note Set from the "hanguponpolarityswitch" value read in from chan_dahdi.conf
00632     */
00633    unsigned int hanguponpolarityswitch:1;
00634    /*! \brief TRUE if DTMF detection needs to be done by hardware. */
00635    unsigned int hardwaredtmf:1;
00636    /*!
00637     * \brief TRUE if the outgoing caller ID is blocked/hidden.
00638     * \note Caller ID can be disabled by dialing *67.
00639     * \note Caller ID can be enabled by dialing *82.
00640     * \note Initialized with the "hidecallerid" value read in from chan_dahdi.conf
00641     */
00642    unsigned int hidecallerid:1;
00643    /*!
00644     * \brief TRUE if hide just the name not the number for legacy PBX use.
00645     * \note Only applies to PRI channels.
00646     * \note Set from the "hidecalleridname" value read in from chan_dahdi.conf
00647     */
00648    unsigned int hidecalleridname:1;
00649    /*! \brief TRUE if DTMF detection is disabled. */
00650    unsigned int ignoredtmf:1;
00651    /*!
00652     * \brief TRUE if the channel should be answered immediately
00653     * without attempting to gather any digits.
00654     * \note Set from the "immediate" value read in from chan_dahdi.conf
00655     */
00656    unsigned int immediate:1;
00657    /*! \brief TRUE if in an alarm condition. */
00658    unsigned int inalarm:1;
00659    /*! \brief TRUE if TDD in MATE mode */
00660    unsigned int mate:1;
00661    /*! \brief TRUE if we originated the call leg. */
00662    unsigned int outgoing:1;
00663    /* unsigned int overlapdial:1;         unused and potentially confusing */
00664    /*!
00665     * \brief TRUE if busy extensions will hear the call-waiting tone
00666     * and can use hook-flash to switch between callers.
00667     * \note Set from the "callwaiting" value read in from chan_dahdi.conf
00668     */
00669    unsigned int permcallwaiting:1;
00670    /*!
00671     * \brief TRUE if the outgoing caller ID is blocked/restricted/hidden.
00672     * \note Set from the "hidecallerid" value read in from chan_dahdi.conf
00673     */
00674    unsigned int permhidecallerid:1;
00675    /*!
00676     * \brief TRUE if PRI congestion/busy indications are sent out-of-band.
00677     * \note Set from the "priindication" value read in from chan_dahdi.conf
00678     */
00679    unsigned int priindication_oob:1;
00680    /*!
00681     * \brief TRUE if PRI B channels are always exclusively selected.
00682     * \note Set from the "priexclusive" value read in from chan_dahdi.conf
00683     */
00684    unsigned int priexclusive:1;
00685    /*!
00686     * \brief TRUE if we will pulse dial.
00687     * \note Set from the "pulsedial" value read in from chan_dahdi.conf
00688     */
00689    unsigned int pulse:1;
00690    /*! \brief TRUE if a pulsed digit was detected. (Pulse dial phone detected) */
00691    unsigned int pulsedial:1;
00692    unsigned int restartpending:1;      /*!< flag to ensure counted only once for restart */
00693    /*!
00694     * \brief TRUE if caller ID is restricted.
00695     * \note Set but not used.  Should be deleted.  Redundant with permhidecallerid.
00696     * \note Set from the "restrictcid" value read in from chan_dahdi.conf
00697     */
00698    unsigned int restrictcid:1;
00699    /*!
00700     * \brief TRUE if three way calling is enabled
00701     * \note Set from the "threewaycalling" value read in from chan_dahdi.conf
00702     */
00703    unsigned int threewaycalling:1;
00704    /*!
00705     * \brief TRUE if call transfer is enabled
00706     * \note For FXS ports (either direct analog or over T1/E1):
00707     *   Support flash-hook call transfer
00708     * \note For digital ports using ISDN PRI protocols:
00709     *   Support switch-side transfer (called 2BCT, RLT or other names)
00710     * \note Set from the "transfer" value read in from chan_dahdi.conf
00711     */
00712    unsigned int transfer:1;
00713    /*!
00714     * \brief TRUE if caller ID is used on this channel.
00715     * \note PRI and SS7 spans will save caller ID from the networking peer.
00716     * \note FXS ports will generate the caller ID spill.
00717     * \note FXO ports will listen for the caller ID spill.
00718     * \note Set from the "usecallerid" value read in from chan_dahdi.conf
00719     */
00720    unsigned int use_callerid:1;
00721    /*!
00722     * \brief TRUE if we will use the calling presentation setting
00723     * from the Asterisk channel for outgoing calls.
00724     * \note Only applies to PRI and SS7 channels.
00725     * \note Set from the "usecallingpres" value read in from chan_dahdi.conf
00726     */
00727    unsigned int use_callingpres:1;
00728    /*!
00729     * \brief TRUE if distinctive rings are to be detected.
00730     * \note For FXO lines
00731     * \note Set indirectly from the "usedistinctiveringdetection" value read in from chan_dahdi.conf
00732     */
00733    unsigned int usedistinctiveringdetection:1;
00734    /*!
00735     * \brief TRUE if we should use the callerid from incoming call on dahdi transfer.
00736     * \note Set from the "useincomingcalleridondahditransfer" value read in from chan_dahdi.conf
00737     */
00738    unsigned int dahditrcallerid:1;
00739    /*!
00740     * \brief TRUE if allowed to flash-transfer to busy channels.
00741     * \note Set from the "transfertobusy" value read in from chan_dahdi.conf
00742     */
00743    unsigned int transfertobusy:1;
00744    /*!
00745     * \brief TRUE if the FXO port monitors for neon type MWI indications from the other end.
00746     * \note Set if the "mwimonitor" value read in contains "neon" from chan_dahdi.conf
00747     */
00748    unsigned int mwimonitor_neon:1;
00749    /*!
00750     * \brief TRUE if the FXO port monitors for fsk type MWI indications from the other end.
00751     * \note Set if the "mwimonitor" value read in contains "fsk" from chan_dahdi.conf
00752     */
00753    unsigned int mwimonitor_fsk:1;
00754    /*!
00755     * \brief TRUE if the FXO port monitors for rpas precursor to fsk MWI indications from the other end.
00756     * \note RPAS - Ring Pulse Alert Signal
00757     * \note Set if the "mwimonitor" value read in contains "rpas" from chan_dahdi.conf
00758     */
00759    unsigned int mwimonitor_rpas:1;
00760    /*! \brief TRUE if an MWI monitor thread is currently active */
00761    unsigned int mwimonitoractive:1;
00762    /*! \brief TRUE if a MWI message sending thread is active */
00763    unsigned int mwisendactive:1;
00764    /*!
00765     * \brief TRUE if channel is out of reset and ready
00766     * \note Set but not used.
00767     */
00768    unsigned int inservice:1;
00769    /*!
00770     * \brief TRUE if the channel is locally blocked.
00771     * \note Applies to SS7 channels.
00772     */
00773    unsigned int locallyblocked:1;
00774    /*!
00775     * \brief TRUE if the channel is remotely blocked.
00776     * \note Applies to SS7 channels.
00777     */
00778    unsigned int remotelyblocked:1;
00779 #if defined(HAVE_PRI) || defined(HAVE_SS7)
00780    /*!
00781     * \brief XXX BOOLEAN Purpose???
00782     * \note Applies to SS7 channels.
00783     */
00784    unsigned int rlt:1;
00785    /*! \brief TRUE if channel is alerting/ringing */
00786    unsigned int alerting:1;
00787    /*! \brief TRUE if the call has already gone/hungup */
00788    unsigned int alreadyhungup:1;
00789    /*!
00790     * \brief TRUE if this is an idle call
00791     * \note Applies to PRI channels.
00792     */
00793    unsigned int isidlecall:1;
00794    /*!
00795     * \brief TRUE if call is in a proceeding state.
00796     * The call has started working its way through the network.
00797     */
00798    unsigned int proceeding:1;
00799    /*! \brief TRUE if the call has seen progress through the network. */
00800    unsigned int progress:1;
00801    /*!
00802     * \brief TRUE if this channel is being reset/restarted
00803     * \note Applies to PRI channels.
00804     */
00805    unsigned int resetting:1;
00806    /*!
00807     * \brief TRUE if this channel has received a SETUP_ACKNOWLEDGE
00808     * \note Applies to PRI channels.
00809     */
00810    unsigned int setup_ack:1;
00811 #endif
00812    /*!
00813     * \brief TRUE if SMDI (Simplified Message Desk Interface) is enabled
00814     * \note Set from the "usesmdi" value read in from chan_dahdi.conf
00815     */
00816    unsigned int use_smdi:1;
00817    /*! \brief The serial port to listen for SMDI data on */
00818    struct ast_smdi_interface *smdi_iface;
00819 
00820    /*! \brief Distinctive Ring data */
00821    struct dahdi_distRings drings;
00822 
00823    /*!
00824     * \brief The configured context for incoming calls.
00825     * \note The "context" string read in from chan_dahdi.conf
00826     */
00827    char context[AST_MAX_CONTEXT];
00828    /*!
00829     * \brief Saved context string.
00830     */
00831    char defcontext[AST_MAX_CONTEXT];
00832    /*! \brief Extension to use in the dialplan. */
00833    char exten[AST_MAX_EXTENSION];
00834    /*!
00835     * \brief Language configured for calls.
00836     * \note The "language" string read in from chan_dahdi.conf
00837     */
00838    char language[MAX_LANGUAGE];
00839    /*!
00840     * \brief The configured music-on-hold class to use for calls.
00841     * \note The "musicclass" or "mohinterpret" or "musiconhold" string read in from chan_dahdi.conf
00842     */
00843    char mohinterpret[MAX_MUSICCLASS];
00844    /*!
00845     * \brief Sugggested music-on-hold class for peer channel to use for calls.
00846     * \note The "mohsuggest" string read in from chan_dahdi.conf
00847     */
00848    char mohsuggest[MAX_MUSICCLASS];
00849    char parkinglot[AST_MAX_EXTENSION]; /*!< Parking lot for this channel */
00850 #if defined(PRI_ANI) || defined(HAVE_SS7)
00851    /*! \brief Automatic Number Identification number (Alternate PRI caller ID number) */
00852    char cid_ani[AST_MAX_EXTENSION];
00853 #endif
00854    /*! \brief Automatic Number Identification code from PRI */
00855    int cid_ani2;
00856    /*! \brief Caller ID number from an incoming call. */
00857    char cid_num[AST_MAX_EXTENSION];
00858    /*! \brief Caller ID Q.931 TON/NPI field values.  Set by PRI. Zero otherwise. */
00859    int cid_ton;
00860    /*! \brief Caller ID name from an incoming call. */
00861    char cid_name[AST_MAX_EXTENSION];
00862    /*! \brief Last Caller ID number from an incoming call. */
00863    char lastcid_num[AST_MAX_EXTENSION];
00864    /*! \brief Last Caller ID name from an incoming call. */
00865    char lastcid_name[AST_MAX_EXTENSION];
00866    char *origcid_num;            /*!< malloced original callerid */
00867    char *origcid_name;           /*!< malloced original callerid */
00868    /*! \brief Call waiting number. */
00869    char callwait_num[AST_MAX_EXTENSION];
00870    /*! \brief Call waiting name. */
00871    char callwait_name[AST_MAX_EXTENSION];
00872    /*! \brief Redirecting Directory Number Information Service (RDNIS) number */
00873    char rdnis[AST_MAX_EXTENSION];
00874    /*! \brief Dialed Number Identifier */
00875    char dnid[AST_MAX_EXTENSION];
00876    /*!
00877     * \brief Bitmapped groups this belongs to.
00878     * \note The "group" bitmapped group string read in from chan_dahdi.conf
00879     */
00880    ast_group_t group;
00881    /*! \brief Active PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW */
00882    int law;
00883    int confno;             /*!< Our conference */
00884    int confusers;             /*!< Who is using our conference */
00885    int propconfno;               /*!< Propagated conference number */
00886    /*!
00887     * \brief Bitmapped call groups this belongs to.
00888     * \note The "callgroup" bitmapped group string read in from chan_dahdi.conf
00889     */
00890    ast_group_t callgroup;
00891    /*!
00892     * \brief Bitmapped pickup groups this belongs to.
00893     * \note The "pickupgroup" bitmapped group string read in from chan_dahdi.conf
00894     */
00895    ast_group_t pickupgroup;
00896    /*!
00897     * \brief Channel variable list with associated values to set when a channel is created.
00898     * \note The "setvar" strings read in from chan_dahdi.conf
00899     */
00900    struct ast_variable *vars;
00901    int channel;               /*!< Channel Number or CRV */
00902    int span;               /*!< Span number */
00903    time_t guardtime;          /*!< Must wait this much time before using for new call */
00904    int cid_signalling;           /*!< CID signalling type bell202 or v23 */
00905    int cid_start;             /*!< CID start indicator, polarity or ring */
00906    int callingpres;           /*!< The value of callling presentation that we're going to use when placing a PRI call */
00907    int callwaitingrepeat;           /*!< How many samples to wait before repeating call waiting */
00908    int cidcwexpire;           /*!< When to expire our muting for CID/CW */
00909    /*! \brief Analog caller ID waveform sample buffer */
00910    unsigned char *cidspill;
00911    /*! \brief Position in the cidspill buffer to send out next. */
00912    int cidpos;
00913    /*! \brief Length of the cidspill buffer containing samples. */
00914    int cidlen;
00915    /*! \brief Ring timeout timer?? */
00916    int ringt;
00917    /*!
00918     * \brief Ring timeout base.
00919     * \note Value computed indirectly from "ringtimeout" read in from chan_dahdi.conf
00920     */
00921    int ringt_base;
00922    /*!
00923     * \brief Number of most significant digits/characters to strip from the dialed number.
00924     * \note Feature is deprecated.  Use dialplan logic.
00925     * \note The characters are stripped before the PRI TON/NPI prefix
00926     * characters are processed.
00927     */
00928    int stripmsd;
00929    /*! \brief BOOLEAN. XXX Meaning what?? */
00930    int callwaitcas;
00931    /*! \brief Number of call waiting rings. */
00932    int callwaitrings;
00933    /*! \brief Echo cancel parameters. */
00934    struct {
00935       struct dahdi_echocanparams head;
00936       struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS];
00937    } echocancel;
00938    /*!
00939     * \brief Echo training time. 0 = disabled
00940     * \note Set from the "echotraining" value read in from chan_dahdi.conf
00941     */
00942    int echotraining;
00943    /*! \brief Filled with 'w'.  XXX Purpose?? */
00944    char echorest[20];
00945    /*!
00946     * \brief Number of times to see "busy" tone before hanging up.
00947     * \note Set from the "busycount" value read in from chan_dahdi.conf
00948     */
00949    int busycount;
00950    /*!
00951     * \brief If your country has a busy tone with the same length tone and silence (as many countries do), consider using this option in order to compare tone and silence lengths
00952     * \note Set from the "busycompare" value read in from chan_dahdi.conf
00953     */
00954    int busycompare;
00955    /*!
00956     * \brief Lenght of "tone" in ms.
00957     * \note Set from the "busypattern" value read in from chan_dahdi.conf
00958     */
00959    int busytonelength;
00960    /*!
00961     * \brief Lenght of "silence" in ms.
00962     * \note Set from the "busypattern" value read in from chan_dahdi.conf
00963     */
00964    int busyquietlength;
00965    /*!
00966     * \brief  Maximun percentage difference allowed between measured and actual pattern
00967     * \note Set from the "busyfuzziness" value read in from chan_dahdi.conf
00968     */
00969    int busyfuzziness;
00970    /*!
00971     * \brief Maximun signal average level considered as silence in this channel
00972     * \note Set from the "silencethreshold" value read in from chan_dahdi.conf
00973     */
00974    int silencethreshold;
00975    /*!
00976     * \brief Bitmapped call progress detection flags. CALLPROGRESS_xxx values.
00977     * \note Bits set from the "callprogress" and "faxdetect" values read in from chan_dahdi.conf
00978     */
00979    int callprogress;
00980    struct timeval flashtime;        /*!< Last flash-hook time */
00981    /*! \brief Opaque DSP configuration structure. */
00982    struct ast_dsp *dsp;
00983    //int cref;             /*!< Call reference number (Not used) */
00984    /*! \brief DAHDI dial operation command struct for ioctl() call. */
00985    struct dahdi_dialoperation dop;
00986    int whichwink;             /*!< SIG_FEATDMF_TA Which wink are we on? */
00987    /*! \brief Second part of SIG_FEATDMF_TA wink operation. */
00988    char finaldial[64];
00989    char accountcode[AST_MAX_ACCOUNT_CODE];      /*!< Account code */
00990    int amaflags;              /*!< AMA Flags */
00991    struct tdd_state *tdd;           /*!< TDD flag */
00992    /*! \brief Accumulated call forwarding number. */
00993    char call_forward[AST_MAX_EXTENSION];
00994    /*!
00995     * \brief Voice mailbox location.
00996     * \note Set from the "mailbox" string read in from chan_dahdi.conf
00997     */
00998    char mailbox[AST_MAX_EXTENSION];
00999    /*! \brief Opaque event subscription parameters for message waiting indication support. */
01000    struct ast_event_sub *mwi_event_sub;
01001    /*! \brief Delayed dialing for E911.  Overlap digits for ISDN. */
01002    char dialdest[256];
01003    /*! \brief Time the interface went on-hook. */
01004    int onhooktime;
01005    /*! \brief -1 = unknown, 0 = no messages, 1 = new messages available */
01006    int msgstate;
01007    int distinctivering;          /*!< Which distinctivering to use */
01008    int cidrings;              /*!< Which ring to deliver CID on */
01009    int dtmfrelax;             /*!< whether to run in relaxed DTMF mode */
01010    /*! \brief Holding place for event injected from outside normal operation. */
01011    int fake_event;
01012    /*!
01013     * \brief Minimal time period (ms) between the answer polarity
01014     * switch and hangup polarity switch.
01015     */
01016    int polarityonanswerdelay;
01017    /*! \brief Start delay time if polarityonanswerdelay is nonzero. */
01018    struct timeval polaritydelaytv;
01019    /*!
01020     * \brief Send caller ID after this many rings.
01021     * \note Set from the "sendcalleridafter" value read in from chan_dahdi.conf
01022     */
01023    int sendcalleridafter;
01024 #ifdef HAVE_PRI
01025    /*! \brief DAHDI PRI control parameters */
01026    struct dahdi_pri *pri;
01027    /*! \brief XXX Purpose??? */
01028    struct dahdi_pvt *bearer;
01029    /*! \brief XXX Purpose??? */
01030    struct dahdi_pvt *realcall;
01031    /*! \brief Opaque libpri call control structure */
01032    q931_call *call;
01033    /*! \brief Channel number in span. */
01034    int prioffset;
01035    /*! \brief Logical span number within trunk group */
01036    int logicalspan;
01037 #endif   
01038    /*! \brief Current line interface polarity. POLARITY_IDLE, POLARITY_REV */
01039    int polarity;
01040    /*! \brief DSP feature flags: DSP_FEATURE_xxx */
01041    int dsp_features;
01042 #ifdef HAVE_SS7
01043    /*! \brief SS7 control parameters */
01044    struct dahdi_ss7 *ss7;
01045    /*! \brief Opaque libss7 call control structure */
01046    struct isup_call *ss7call;
01047    char charge_number[50];
01048    char gen_add_number[50];
01049    char gen_dig_number[50];
01050    char orig_called_num[50];
01051    char redirecting_num[50];
01052    char generic_name[50];
01053    unsigned char gen_add_num_plan;
01054    unsigned char gen_add_nai;
01055    unsigned char gen_add_pres_ind;
01056    unsigned char gen_add_type;
01057    unsigned char gen_dig_type;
01058    unsigned char gen_dig_scheme;
01059    char jip_number[50];
01060    unsigned char lspi_type;
01061    unsigned char lspi_scheme;
01062    unsigned char lspi_context;
01063    char lspi_ident[50];
01064    unsigned int call_ref_ident;
01065    unsigned int call_ref_pc;
01066    unsigned char calling_party_cat;
01067    int transcap;
01068    int cic;                   /*!< CIC associated with channel */
01069    unsigned int dpc;                /*!< CIC's DPC */
01070    unsigned int loopedback:1;
01071 #endif
01072    /*! \brief DTMF digit in progress.  0 when no digit in progress. */
01073    char begindigit;
01074    /*! \brief TRUE if confrence is muted. */
01075    int muting;
01076 } *iflist = NULL, *ifend = NULL;
01077 
01078 /*! \brief Channel configuration from chan_dahdi.conf .
01079  * This struct is used for parsing the [channels] section of chan_dahdi.conf.
01080  * Generally there is a field here for every possible configuration item.
01081  *
01082  * The state of fields is saved along the parsing and whenever a 'channel'
01083  * statement is reached, the current dahdi_chan_conf is used to configure the 
01084  * channel (struct dahdi_pvt)
01085  *
01086  * \see dahdi_chan_init for the default values.
01087  */
01088 struct dahdi_chan_conf {
01089    struct dahdi_pvt chan;
01090 #ifdef HAVE_PRI
01091    struct dahdi_pri pri;
01092 #endif
01093 
01094 #ifdef HAVE_SS7
01095    struct dahdi_ss7 ss7;
01096 #endif
01097    struct dahdi_params timing;
01098    int is_sig_auto; /*!< Use channel signalling from DAHDI? */
01099 
01100    /*!
01101     * \brief The serial port to listen for SMDI data on
01102     * \note Set from the "smdiport" string read in from chan_dahdi.conf
01103     */
01104    char smdi_port[SMDI_MAX_FILENAME_LEN];
01105 };
01106 
01107 /*! returns a new dahdi_chan_conf with default values (by-value) */
01108 static struct dahdi_chan_conf dahdi_chan_conf_default(void) {
01109    /* recall that if a field is not included here it is initialized
01110     * to 0 or equivalent
01111     */
01112    struct dahdi_chan_conf conf = {
01113 #ifdef HAVE_PRI
01114       .pri = {
01115          .nsf = PRI_NSF_NONE,
01116          .switchtype = PRI_SWITCH_NI2,
01117          .dialplan = PRI_UNKNOWN + 1,
01118          .localdialplan = PRI_NATIONAL_ISDN + 1,
01119          .nodetype = PRI_CPE,
01120 
01121          .minunused = 2,
01122          .idleext = "",
01123          .idledial = "",
01124          .internationalprefix = "",
01125          .nationalprefix = "",
01126          .localprefix = "",
01127          .privateprefix = "",
01128          .unknownprefix = "",
01129          .resetinterval = -1,
01130       },
01131 #endif
01132 #ifdef HAVE_SS7
01133       .ss7 = {
01134          .called_nai = SS7_NAI_NATIONAL,
01135          .calling_nai = SS7_NAI_NATIONAL,
01136          .internationalprefix = "",
01137          .nationalprefix = "",
01138          .subscriberprefix = "",
01139          .unknownprefix = ""
01140       },
01141 #endif
01142       .chan = {
01143          .context = "default",
01144          .cid_num = "",
01145          .cid_name = "",
01146          .mohinterpret = "default",
01147          .mohsuggest = "",
01148          .parkinglot = "",
01149          .transfertobusy = 1,
01150 
01151          .cid_signalling = CID_SIG_BELL,
01152          .cid_start = CID_START_RING,
01153          .dahditrcallerid = 0,
01154          .use_callerid = 1,
01155          .sig = -1,
01156          .outsigmod = -1,
01157 
01158          .cid_rxgain = +5.0,
01159 
01160          .tonezone = -1,
01161 
01162          .echocancel.head.tap_length = 1,
01163 
01164          .busycount = 3,
01165          .busycompare = 0,
01166          .busytonelength = 0,
01167          .busyquietlength = 0,
01168          .busyfuzziness = 0,
01169          .silencethreshold = 0,
01170 
01171          .accountcode = "",
01172 
01173          .mailbox = "",
01174 
01175 
01176          .polarityonanswerdelay = 600,
01177 
01178          .sendcalleridafter = DEFAULT_CIDRINGS,
01179       
01180          .buf_policy = DAHDI_POLICY_IMMEDIATE,
01181          .buf_no = numbufs
01182       },
01183       .timing = {
01184          .prewinktime = -1,
01185          .preflashtime = -1,
01186          .winktime = -1,
01187          .flashtime = -1,
01188          .starttime = -1,
01189          .rxwinktime = -1,
01190          .rxflashtime = -1,
01191          .debouncetime = -1
01192       },
01193       .is_sig_auto = 1,
01194       .smdi_port = "/dev/ttyS0",
01195    };
01196 
01197    return conf;
01198 }
01199 
01200 
01201 static struct ast_channel *dahdi_request(const char *type, int format, void *data, int *cause);
01202 static int dahdi_digit_begin(struct ast_channel *ast, char digit);
01203 static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
01204 static int dahdi_sendtext(struct ast_channel *c, const char *text);
01205 static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout);
01206 static int dahdi_hangup(struct ast_channel *ast);
01207 static int dahdi_answer(struct ast_channel *ast);
01208 static struct ast_frame *dahdi_read(struct ast_channel *ast);
01209 static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame);
01210 static struct ast_frame *dahdi_exception(struct ast_channel *ast);
01211 static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
01212 static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
01213 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
01214 static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
01215 static int handle_init_event(struct dahdi_pvt *i, int event);
01216 
01217 static const struct ast_channel_tech dahdi_tech = {
01218    .type = "DAHDI",
01219    .description = tdesc,
01220    .capabilities = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW,
01221    .requester = dahdi_request,
01222    .send_digit_begin = dahdi_digit_begin,
01223    .send_digit_end = dahdi_digit_end,
01224    .send_text = dahdi_sendtext,
01225    .call = dahdi_call,
01226    .hangup = dahdi_hangup,
01227    .answer = dahdi_answer,
01228    .read = dahdi_read,
01229    .write = dahdi_write,
01230    .bridge = dahdi_bridge,
01231    .exception = dahdi_exception,
01232    .indicate = dahdi_indicate,
01233    .fixup = dahdi_fixup,
01234    .setoption = dahdi_setoption,
01235    .func_channel_read = dahdi_func_read,
01236 };
01237 
01238 #ifdef HAVE_PRI
01239 #define GET_CHANNEL(p) ((p)->bearer ? (p)->bearer->channel : p->channel)
01240 #else
01241 #define GET_CHANNEL(p) ((p)->channel)
01242 #endif
01243 
01244 struct dahdi_pvt *round_robin[32];
01245 
01246 #ifdef HAVE_PRI
01247 static inline int pri_grab(struct dahdi_pvt *pvt, struct dahdi_pri *pri)
01248 {
01249    int res;
01250    /* Grab the lock first */
01251    do {
01252       res = ast_mutex_trylock(&pri->lock);
01253       if (res) {
01254          DEADLOCK_AVOIDANCE(&pvt->lock);
01255       }
01256    } while (res);
01257    /* Then break the poll */
01258    if (pri->master != AST_PTHREADT_NULL)
01259       pthread_kill(pri->master, SIGURG);
01260    return 0;
01261 }
01262 #endif
01263 
01264 #ifdef HAVE_SS7
01265 static inline void ss7_rel(struct dahdi_ss7 *ss7)
01266 {
01267    ast_mutex_unlock(&ss7->lock);
01268 }
01269 
01270 static inline int ss7_grab(struct dahdi_pvt *pvt, struct dahdi_ss7 *pri)
01271 {
01272    int res;
01273    /* Grab the lock first */
01274    do {
01275       res = ast_mutex_trylock(&pri->lock);
01276       if (res) {
01277          DEADLOCK_AVOIDANCE(&pvt->lock);
01278       }
01279    } while (res);
01280    /* Then break the poll */
01281    if (pri->master != AST_PTHREADT_NULL)
01282       pthread_kill(pri->master, SIGURG);
01283    return 0;
01284 }
01285 #endif
01286 #define NUM_CADENCE_MAX 25
01287 static int num_cadence = 4;
01288 static int user_has_defined_cadences = 0;
01289 
01290 static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
01291    { { 125, 125, 2000, 4000 } },       /*!< Quick chirp followed by normal ring */
01292    { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
01293    { { 125, 125, 125, 125, 125, 4000 } }, /*!< Three short bursts */
01294    { { 1000, 500, 2500, 5000 } },   /*!< Long ring */
01295 };
01296 
01297 /*! \brief cidrings says in which pause to transmit the cid information, where the first pause
01298  * is 1, the second pause is 2 and so on.
01299  */
01300 
01301 static int cidrings[NUM_CADENCE_MAX] = {
01302    2,                            /*!< Right after first long ring */
01303    4,                            /*!< Right after long part */
01304    3,                            /*!< After third chirp */
01305    2,                            /*!< Second spell */
01306 };
01307 
01308 /* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
01309 static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}};
01310 
01311 #define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
01312          (p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
01313 
01314 #define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
01315 #define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
01316 
01317 static int dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok)
01318 {
01319    int res;
01320    if (p->subs[SUB_REAL].owner == ast)
01321       res = 0;
01322    else if (p->subs[SUB_CALLWAIT].owner == ast)
01323       res = 1;
01324    else if (p->subs[SUB_THREEWAY].owner == ast)
01325       res = 2;
01326    else {
01327       res = -1;
01328       if (!nullok)
01329          ast_log(LOG_WARNING, "Unable to get index, and nullok is not asserted\n");
01330    }
01331    return res;
01332 }
01333 
01334 #ifdef HAVE_PRI
01335 static void wakeup_sub(struct dahdi_pvt *p, int a, struct dahdi_pri *pri)
01336 #else
01337 static void wakeup_sub(struct dahdi_pvt *p, int a, void *pri)
01338 #endif
01339 {
01340 #ifdef HAVE_PRI
01341    if (pri)
01342       ast_mutex_unlock(&pri->lock);
01343 #endif         
01344    for (;;) {
01345       if (p->subs[a].owner) {
01346          if (ast_channel_trylock(p->subs[a].owner)) {
01347             DEADLOCK_AVOIDANCE(&p->lock);
01348          } else {
01349             ast_queue_frame(p->subs[a].owner, &ast_null_frame);
01350             ast_channel_unlock(p->subs[a].owner);
01351             break;
01352          }
01353       } else
01354          break;
01355    }
01356 #ifdef HAVE_PRI
01357    if (pri)
01358       ast_mutex_lock(&pri->lock);
01359 #endif         
01360 }
01361 
01362 static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f, void *data)
01363 {
01364 #ifdef HAVE_PRI
01365    struct dahdi_pri *pri = (struct dahdi_pri*) data;
01366 #endif
01367 #ifdef HAVE_SS7
01368    struct dahdi_ss7 *ss7 = (struct dahdi_ss7*) data;
01369 #endif
01370    /* We must unlock the PRI to avoid the possibility of a deadlock */
01371 #if defined(HAVE_PRI) || defined(HAVE_SS7)
01372    if (data) {
01373       switch (p->sig) {
01374 #ifdef HAVE_PRI
01375       case SIG_BRI:
01376       case SIG_BRI_PTMP:
01377       case SIG_PRI:
01378          ast_mutex_unlock(&pri->lock);
01379          break;
01380 #endif
01381 #ifdef HAVE_SS7
01382       case SIG_SS7:
01383          ast_mutex_unlock(&ss7->lock);
01384          break;
01385 #endif
01386       default:
01387          break;
01388       }
01389    }
01390 #endif      
01391    for (;;) {
01392       if (p->owner) {
01393          if (ast_channel_trylock(p->owner)) {
01394             DEADLOCK_AVOIDANCE(&p->lock);
01395          } else {
01396             ast_queue_frame(p->owner, f);
01397             ast_channel_unlock(p->owner);
01398             break;
01399          }
01400       } else
01401          break;
01402    }
01403 #if defined(HAVE_PRI) || defined(HAVE_SS7)
01404    if (data) {
01405       switch (p->sig) {
01406 #ifdef HAVE_PRI
01407       case SIG_BRI:
01408       case SIG_BRI_PTMP:
01409       case SIG_PRI:
01410          ast_mutex_lock(&pri->lock);
01411          break;
01412 #endif
01413 #ifdef HAVE_SS7
01414       case SIG_SS7:
01415          ast_mutex_lock(&ss7->lock);
01416          break;
01417 #endif
01418       default:
01419          break;
01420       }
01421    }
01422 
01423 #endif      
01424 }
01425 
01426 static int restore_gains(struct dahdi_pvt *p);
01427 
01428 static void swap_subs(struct dahdi_pvt *p, int a, int b)
01429 {
01430    int tchan;
01431    int tinthreeway;
01432    struct ast_channel *towner;
01433 
01434    ast_debug(1, "Swapping %d and %d\n", a, b);
01435 
01436    tchan = p->subs[a].chan;
01437    towner = p->subs[a].owner;
01438    tinthreeway = p->subs[a].inthreeway;
01439 
01440    p->subs[a].chan = p->subs[b].chan;
01441    p->subs[a].owner = p->subs[b].owner;
01442    p->subs[a].inthreeway = p->subs[b].inthreeway;
01443 
01444    p->subs[b].chan = tchan;
01445    p->subs[b].owner = towner;
01446    p->subs[b].inthreeway = tinthreeway;
01447 
01448    if (p->subs[a].owner) 
01449       ast_channel_set_fd(p->subs[a].owner, 0, p->subs[a].dfd);
01450    if (p->subs[b].owner) 
01451       ast_channel_set_fd(p->subs[b].owner, 0, p->subs[b].dfd);
01452    wakeup_sub(p, a, NULL);
01453    wakeup_sub(p, b, NULL);
01454 }
01455 
01456 static int dahdi_open(char *fn)
01457 {
01458    int fd;
01459    int isnum;
01460    int chan = 0;
01461    int bs;
01462    int x;
01463    isnum = 1;
01464    for (x = 0; x < strlen(fn); x++) {
01465       if (!isdigit(fn[x])) {
01466          isnum = 0;
01467          break;
01468       }
01469    }
01470    if (isnum) {
01471       chan = atoi(fn);
01472       if (chan < 1) {
01473          ast_log(LOG_WARNING, "Invalid channel number '%s'\n", fn);
01474          return -1;
01475       }
01476       fn = "/dev/dahdi/channel";
01477    }
01478    fd = open(fn, O_RDWR | O_NONBLOCK);
01479    if (fd < 0) {
01480       ast_log(LOG_WARNING, "Unable to open '%s': %s\n", fn, strerror(errno));
01481       return -1;
01482    }
01483    if (chan) {
01484       if (ioctl(fd, DAHDI_SPECIFY, &chan)) {
01485          x = errno;
01486          close(fd);
01487          errno = x;
01488          ast_log(LOG_WARNING, "Unable to specify channel %d: %s\n", chan, strerror(errno));
01489          return -1;
01490       }
01491    }
01492    bs = READ_SIZE;
01493    if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &bs) == -1) {
01494       ast_log(LOG_WARNING, "Unable to set blocksize '%d': %s\n", bs,  strerror(errno));
01495       x = errno;
01496       close(fd);
01497       errno = x;
01498       return -1;
01499    }
01500    return fd;
01501 }
01502 
01503 static void dahdi_close(int fd)
01504 {
01505    if (fd > 0)
01506       close(fd);
01507 }
01508 
01509 static void dahdi_close_sub(struct dahdi_pvt *chan_pvt, int sub_num)
01510 {
01511    dahdi_close(chan_pvt->subs[sub_num].dfd);
01512    chan_pvt->subs[sub_num].dfd = -1;
01513 }
01514 
01515 #ifdef HAVE_PRI
01516 static void dahdi_close_pri_fd(struct dahdi_pri *pri, int fd_num)
01517 {
01518    dahdi_close(pri->fds[fd_num]);
01519    pri->fds[fd_num] = -1;
01520 }
01521 #endif
01522 
01523 #ifdef HAVE_SS7
01524 static void dahdi_close_ss7_fd(struct dahdi_ss7 *ss7, int fd_num)
01525 {
01526    dahdi_close(ss7->fds[fd_num]);
01527    ss7->fds[fd_num] = -1;
01528 }
01529 #endif
01530 
01531 static int dahdi_setlinear(int dfd, int linear)
01532 {
01533    int res;
01534    res = ioctl(dfd, DAHDI_SETLINEAR, &linear);
01535    if (res)
01536       return res;
01537    return 0;
01538 }
01539 
01540 
01541 static int alloc_sub(struct dahdi_pvt *p, int x)
01542 {
01543    struct dahdi_bufferinfo bi;
01544    int res;
01545    if (p->subs[x].dfd >= 0) {
01546       ast_log(LOG_WARNING, "%s subchannel of %d already in use\n", subnames[x], p->channel);
01547       return -1;
01548    }
01549 
01550    p->subs[x].dfd = dahdi_open("/dev/dahdi/pseudo");
01551    if (p->subs[x].dfd <= -1) {
01552       ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
01553       return -1;
01554    }
01555 
01556    res = ioctl(p->subs[x].dfd, DAHDI_GET_BUFINFO, &bi);
01557    if (!res) {
01558       bi.txbufpolicy = p->buf_policy;
01559       bi.rxbufpolicy = p->buf_policy;
01560       bi.numbufs = p->buf_no;
01561       res = ioctl(p->subs[x].dfd, DAHDI_SET_BUFINFO, &bi);
01562       if (res < 0) {
01563          ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", x, strerror(errno));
01564       }
01565    } else 
01566       ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", x, strerror(errno));
01567 
01568    if (ioctl(p->subs[x].dfd, DAHDI_CHANNO, &p->subs[x].chan) == 1) {
01569       ast_log(LOG_WARNING, "Unable to get channel number for pseudo channel on FD %d: %s\n", p->subs[x].dfd, strerror(errno));
01570       dahdi_close_sub(p, x);
01571       p->subs[x].dfd = -1;
01572       return -1;
01573    }
01574    ast_debug(1, "Allocated %s subchannel on FD %d channel %d\n", subnames[x], p->subs[x].dfd, p->subs[x].chan);
01575    return 0;
01576 }
01577 
01578 static int unalloc_sub(struct dahdi_pvt *p, int x)
01579 {
01580    if (!x) {
01581       ast_log(LOG_WARNING, "Trying to unalloc the real channel %d?!?\n", p->channel);
01582       return -1;
01583    }
01584    ast_debug(1, "Released sub %d of channel %d\n", x, p->channel);
01585    dahdi_close_sub(p, x);
01586    p->subs[x].linear = 0;
01587    p->subs[x].chan = 0;
01588    p->subs[x].owner = NULL;
01589    p->subs[x].inthreeway = 0;
01590    p->polarity = POLARITY_IDLE;
01591    memset(&p->subs[x].curconf, 0, sizeof(p->subs[x].curconf));
01592    return 0;
01593 }
01594 
01595 static int digit_to_dtmfindex(char digit)
01596 {
01597    if (isdigit(digit))
01598       return DAHDI_TONE_DTMF_BASE + (digit - '0');
01599    else if (digit >= 'A' && digit <= 'D')
01600       return DAHDI_TONE_DTMF_A + (digit - 'A');
01601    else if (digit >= 'a' && digit <= 'd')
01602       return DAHDI_TONE_DTMF_A + (digit - 'a');
01603    else if (digit == '*')
01604       return DAHDI_TONE_DTMF_s;
01605    else if (digit == '#')
01606       return DAHDI_TONE_DTMF_p;
01607    else
01608       return -1;
01609 }
01610 
01611 static int dahdi_digit_begin(struct ast_channel *chan, char digit)
01612 {
01613    struct dahdi_pvt *pvt;
01614    int idx;
01615    int dtmf = -1;
01616    
01617    pvt = chan->tech_pvt;
01618 
01619    ast_mutex_lock(&pvt->lock);
01620 
01621    idx = dahdi_get_index(chan, pvt, 0);
01622 
01623    if ((idx != SUB_REAL) || !pvt->owner)
01624       goto out;
01625 
01626 #ifdef HAVE_PRI
01627    if (((pvt->sig == SIG_PRI) || (pvt->sig == SIG_BRI) || (pvt->sig == SIG_BRI_PTMP)) 
01628          && (chan->_state == AST_STATE_DIALING) && !pvt->proceeding) {
01629       if (pvt->setup_ack) {
01630          if (!pri_grab(pvt, pvt->pri)) {
01631             pri_information(pvt->pri->pri, pvt->call, digit);
01632             pri_rel(pvt->pri);
01633          } else
01634             ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", pvt->span);
01635       } else if (strlen(pvt->dialdest) < sizeof(pvt->dialdest) - 1) {
01636          int res;
01637          ast_debug(1, "Queueing digit '%c' since setup_ack not yet received\n", digit);
01638          res = strlen(pvt->dialdest);
01639          pvt->dialdest[res++] = digit;
01640          pvt->dialdest[res] = '\0';
01641       }
01642       goto out;
01643    }
01644 #endif
01645    if ((dtmf = digit_to_dtmfindex(digit)) == -1)
01646       goto out;
01647 
01648    if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &dtmf)) {
01649       int res;
01650       struct dahdi_dialoperation zo = {
01651          .op = DAHDI_DIAL_OP_APPEND,
01652       };
01653 
01654       zo.dialstr[0] = 'T';
01655       zo.dialstr[1] = digit;
01656       zo.dialstr[2] = '\0';
01657       if ((res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo)))
01658          ast_log(LOG_WARNING, "Couldn't dial digit %c: %s\n", digit, strerror(errno));
01659       else
01660          pvt->dialing = 1;
01661    } else {
01662       ast_debug(1, "Started VLDTMF digit '%c'\n", digit);
01663       pvt->dialing = 1;
01664       pvt->begindigit = digit;
01665    }
01666 
01667 out:
01668    ast_mutex_unlock(&pvt->lock);
01669 
01670    return 0;
01671 }
01672 
01673 static int dahdi_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
01674 {
01675    struct dahdi_pvt *pvt;
01676    int res = 0;
01677    int idx;
01678    int x;
01679    
01680    pvt = chan->tech_pvt;
01681 
01682    ast_mutex_lock(&pvt->lock);
01683    
01684    idx = dahdi_get_index(chan, pvt, 0);
01685 
01686    if ((idx != SUB_REAL) || !pvt->owner || pvt->pulse)
01687       goto out;
01688 
01689 #ifdef HAVE_PRI
01690    /* This means that the digit was already sent via PRI signalling */
01691    if (((pvt->sig == SIG_PRI) || (pvt->sig == SIG_BRI) || (pvt->sig == SIG_BRI_PTMP))
01692          && !pvt->begindigit)
01693       goto out;
01694 #endif
01695 
01696    if (pvt->begindigit) {
01697       x = -1;
01698       ast_debug(1, "Ending VLDTMF digit '%c'\n", digit);
01699       res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &x);
01700       pvt->dialing = 0;
01701       pvt->begindigit = 0;
01702    }
01703 
01704 out:
01705    ast_mutex_unlock(&pvt->lock);
01706 
01707    return res;
01708 }
01709 
01710 static char *events[] = {
01711    "No event",
01712    "On hook",
01713    "Ring/Answered",
01714    "Wink/Flash",
01715    "Alarm",
01716    "No more alarm",
01717    "HDLC Abort",
01718    "HDLC Overrun",
01719    "HDLC Bad FCS",
01720    "Dial Complete",
01721    "Ringer On",
01722    "Ringer Off",
01723    "Hook Transition Complete",
01724    "Bits Changed",
01725    "Pulse Start",
01726    "Timer Expired",
01727    "Timer Ping",
01728    "Polarity Reversal",
01729    "Ring Begin",
01730 };
01731 
01732 static struct {
01733    int alarm;
01734    char *name;
01735 } alarms[] = {
01736    { DAHDI_ALARM_RED, "Red Alarm" },
01737    { DAHDI_ALARM_YELLOW, "Yellow Alarm" },
01738    { DAHDI_ALARM_BLUE, "Blue Alarm" },
01739    { DAHDI_ALARM_RECOVER, "Recovering" },
01740    { DAHDI_ALARM_LOOPBACK, "Loopback" },
01741    { DAHDI_ALARM_NOTOPEN, "Not Open" },
01742    { DAHDI_ALARM_NONE, "None" },
01743 };
01744 
01745 static char *alarm2str(int alm)
01746 {
01747    int x;
01748    for (x = 0; x < ARRAY_LEN(alarms); x++) {
01749       if (alarms[x].alarm & alm)
01750          return alarms[x].name;
01751    }
01752    return alm ? "Unknown Alarm" : "No Alarm";
01753 }
01754 
01755 static char *event2str(int event)
01756 {
01757    static char buf[256];
01758    if ((event < (ARRAY_LEN(events))) && (event > -1))
01759       return events[event];
01760    sprintf(buf, "Event %d", event); /* safe */
01761    return buf;
01762 }
01763 
01764 #ifdef HAVE_PRI
01765 static char *dialplan2str(int dialplan)
01766 {
01767    if (dialplan == -1 || dialplan == -2) {
01768       return("Dynamically set dialplan in ISDN");
01769    }
01770    return (pri_plan2str(dialplan));
01771 }
01772 #endif
01773 
01774 static char *dahdi_sig2str(int sig)
01775 {
01776    static char buf[256];
01777    switch (sig) {
01778    case SIG_EM:
01779       return "E & M Immediate";
01780    case SIG_EMWINK:
01781       return "E & M Wink";
01782    case SIG_EM_E1:
01783       return "E & M E1";
01784    case SIG_FEATD:
01785       return "Feature Group D (DTMF)";
01786    case SIG_FEATDMF:
01787       return "Feature Group D (MF)";
01788    case SIG_FEATDMF_TA:
01789       return "Feature Groud D (MF) Tandem Access";
01790    case SIG_FEATB:
01791       return "Feature Group B (MF)";
01792    case SIG_E911:
01793       return "E911 (MF)";
01794    case SIG_FGC_CAMA:
01795       return "FGC/CAMA (Dialpulse)";
01796    case SIG_FGC_CAMAMF:
01797       return "FGC/CAMA (MF)";
01798    case SIG_FXSLS:
01799       return "FXS Loopstart";
01800    case SIG_FXSGS:
01801       return "FXS Groundstart";
01802    case SIG_FXSKS:
01803       return "FXS Kewlstart";
01804    case SIG_FXOLS:
01805       return "FXO Loopstart";
01806    case SIG_FXOGS:
01807       return "FXO Groundstart";
01808    case SIG_FXOKS:
01809       return "FXO Kewlstart";
01810    case SIG_PRI:
01811       return "ISDN PRI";
01812    case SIG_BRI:
01813       return "ISDN BRI Point to Point";
01814    case SIG_BRI_PTMP:
01815       return "ISDN BRI Point to MultiPoint";
01816    case SIG_SS7:
01817       return "SS7";
01818    case SIG_SF:
01819       return "SF (Tone) Immediate";
01820    case SIG_SFWINK:
01821       return "SF (Tone) Wink";
01822    case SIG_SF_FEATD:
01823       return "SF (Tone) with Feature Group D (DTMF)";
01824    case SIG_SF_FEATDMF:
01825       return "SF (Tone) with Feature Group D (MF)";
01826    case SIG_SF_FEATB:
01827       return "SF (Tone) with Feature Group B (MF)";
01828    case SIG_GR303FXOKS:
01829       return "GR-303 with FXOKS";
01830    case SIG_GR303FXSKS:
01831       return "GR-303 with FXSKS";
01832    case 0:
01833       return "Pseudo";
01834    default:
01835       snprintf(buf, sizeof(buf), "Unknown signalling %d", sig);
01836       return buf;
01837    }
01838 }
01839 
01840 #define sig2str dahdi_sig2str
01841 
01842 static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx, int slavechannel)
01843 {
01844    /* If the conference already exists, and we're already in it
01845       don't bother doing anything */
01846    struct dahdi_confinfo zi;
01847    
01848    memset(&zi, 0, sizeof(zi));
01849    zi.chan = 0;
01850 
01851    if (slavechannel > 0) {
01852       /* If we have only one slave, do a digital mon */
01853       zi.confmode = DAHDI_CONF_DIGITALMON;
01854       zi.confno = slavechannel;
01855    } else {
01856       if (!idx) {
01857          /* Real-side and pseudo-side both participate in conference */
01858          zi.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER |
01859             DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
01860       } else
01861          zi.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
01862       zi.confno = p->confno;
01863    }
01864    if ((zi.confno == c->curconf.confno) && (zi.confmode == c->curconf.confmode))
01865       return 0;
01866    if (c->dfd < 0)
01867       return 0;
01868    if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
01869       ast_log(LOG_WARNING, "Failed to add %d to conference %d/%d: %s\n", c->dfd, zi.confmode, zi.confno, strerror(errno));
01870       return -1;
01871    }
01872    if (slavechannel < 1) {
01873       p->confno = zi.confno;
01874    }
01875    memcpy(&c->curconf, &zi, sizeof(c->curconf));
01876    ast_debug(1, "Added %d to conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
01877    return 0;
01878 }
01879 
01880 static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c)
01881 {
01882    /* If they're listening to our channel, they're ours */  
01883    if ((p->channel == c->curconf.confno) && (c->curconf.confmode == DAHDI_CONF_DIGITALMON))
01884       return 1;
01885    /* If they're a talker on our (allocated) conference, they're ours */
01886    if ((p->confno > 0) && (p->confno == c->curconf.confno) && (c->curconf.confmode & DAHDI_CONF_TALKER))
01887       return 1;
01888    return 0;
01889 }
01890 
01891 static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx)
01892 {
01893    struct dahdi_confinfo zi;
01894    if (/* Can't delete if there's no dfd */
01895       (c->dfd < 0) ||
01896       /* Don't delete from the conference if it's not our conference */
01897       !isourconf(p, c)
01898       /* Don't delete if we don't think it's conferenced at all (implied) */
01899       ) return 0;
01900    memset(&zi, 0, sizeof(zi));
01901    if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
01902       ast_log(LOG_WARNING, "Failed to drop %d from conference %d/%d: %s\n", c->dfd, c->curconf.confmode, c->curconf.confno, strerror(errno));
01903       return -1;
01904    }
01905    ast_debug(1, "Removed %d from conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
01906    memcpy(&c->curconf, &zi, sizeof(c->curconf));
01907    return 0;
01908 }
01909 
01910 static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out)
01911 {
01912    int x;
01913    int useslavenative;
01914    struct dahdi_pvt *slave = NULL;
01915    /* Start out optimistic */
01916    useslavenative = 1;
01917    /* Update conference state in a stateless fashion */
01918    for (x = 0; x < 3; x++) {
01919       /* Any three-way calling makes slave native mode *definitely* out
01920          of the question */
01921       if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway)
01922          useslavenative = 0;
01923    }
01924    /* If we don't have any 3-way calls, check to see if we have
01925       precisely one slave */
01926    if (useslavenative) {
01927       for (x = 0; x < MAX_SLAVES; x++) {
01928          if (p->slaves[x]) {
01929             if (slave) {
01930                /* Whoops already have a slave!  No 
01931                   slave native and stop right away */
01932                slave = NULL;
01933                useslavenative = 0;
01934                break;
01935             } else {
01936                /* We have one slave so far */
01937                slave = p->slaves[x];
01938             }
01939          }
01940       }
01941    }
01942    /* If no slave, slave native definitely out */
01943    if (!slave)
01944       useslavenative = 0;
01945    else if (slave->law != p->law) {
01946       useslavenative = 0;
01947       slave = NULL;
01948    }
01949    if (out)
01950       *out = slave;
01951    return useslavenative;
01952 }
01953 
01954 static int reset_conf(struct dahdi_pvt *p)
01955 {
01956    p->confno = -1;
01957    memset(&p->subs[SUB_REAL].curconf, 0, sizeof(p->subs[SUB_REAL].curconf));
01958    if (p->subs[SUB_REAL].dfd > -1) {
01959       struct dahdi_confinfo zi;
01960 
01961       memset(&zi, 0, sizeof(zi));
01962       if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &zi))
01963          ast_log(LOG_WARNING, "Failed to reset conferencing on channel %d: %s\n", p->channel, strerror(errno));
01964    }
01965    return 0;
01966 }
01967 
01968 static int update_conf(struct dahdi_pvt *p)
01969 {
01970    int needconf = 0;
01971    int x;
01972    int useslavenative;
01973    struct dahdi_pvt *slave = NULL;
01974 
01975    useslavenative = isslavenative(p, &slave);
01976    /* Start with the obvious, general stuff */
01977    for (x = 0; x < 3; x++) {
01978       /* Look for three way calls */
01979       if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway) {
01980          conf_add(p, &p->subs[x], x, 0);
01981          needconf++;
01982       } else {
01983          conf_del(p, &p->subs[x], x);
01984       }
01985    }
01986    /* If we have a slave, add him to our conference now. or DAX
01987       if this is slave native */
01988    for (x = 0; x < MAX_SLAVES; x++) {
01989       if (p->slaves[x]) {
01990          if (useslavenative)
01991             conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
01992          else {
01993             conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
01994             needconf++;
01995          }
01996       }
01997    }
01998    /* If we're supposed to be in there, do so now */
01999    if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
02000       if (useslavenative)
02001          conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
02002       else {
02003          conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
02004          needconf++;
02005       }
02006    }
02007    /* If we have a master, add ourselves to his conference */
02008    if (p->master) {
02009       if (isslavenative(p->master, NULL)) {
02010          conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p->master));
02011       } else {
02012          conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
02013       }
02014    }
02015    if (!needconf) {
02016       /* Nobody is left (or should be left) in our conference.
02017          Kill it. */
02018       p->confno = -1;
02019    }
02020    ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
02021    return 0;
02022 }
02023 
02024 static void dahdi_enable_ec(struct dahdi_pvt *p)
02025 {
02026    int x;
02027    int res;
02028    if (!p)
02029       return;
02030    if (p->echocanon) {
02031       ast_debug(1, "Echo cancellation already on\n");
02032       return;
02033    }
02034    if (p->digital) {
02035       ast_debug(1, "Echo cancellation isn't required on digital connection\n");
02036       return;
02037    }
02038    if (p->echocancel.head.tap_length) {
02039       if ((p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP) || (p->sig == SIG_PRI) || (p->sig == SIG_SS7)) {
02040          x = 1;
02041          res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x);
02042          if (res)
02043             ast_log(LOG_WARNING, "Unable to enable audio mode on channel %d (%s)\n", p->channel, strerror(errno));
02044       }
02045       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &p->echocancel);
02046       if (res)  {
02047          ast_log(LOG_WARNING, "Unable to enable echo cancellation on channel %d (%s)\n", p->channel, strerror(errno));
02048       } else {
02049          p->echocanon = 1;
02050          ast_debug(1, "Enabled echo cancellation on channel %d\n", p->channel);
02051       }
02052    } else
02053       ast_debug(1, "No echo cancellation requested\n");
02054 }
02055 
02056 static void dahdi_train_ec(struct dahdi_pvt *p)
02057 {
02058    int x;
02059    int res;
02060    
02061    if (p && p->echocanon && p->echotraining) {
02062       x = p->echotraining;
02063       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOTRAIN, &x);
02064       if (res)
02065          ast_log(LOG_WARNING, "Unable to request echo training on channel %d: %s\n", p->channel, strerror(errno));
02066       else
02067          ast_debug(1, "Engaged echo training on channel %d\n", p->channel);
02068    } else {
02069       ast_debug(1, "No echo training requested\n");
02070    }
02071 }
02072 
02073 static void dahdi_disable_ec(struct dahdi_pvt *p)
02074 {
02075    int res;
02076 
02077    if (p->echocanon) {
02078       struct dahdi_echocanparams ecp = { .tap_length = 0 };
02079 
02080       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &ecp);
02081 
02082       if (res)
02083          ast_log(LOG_WARNING, "Unable to disable echo cancellation on channel %d: %s\n", p->channel, strerror(errno));
02084       else
02085          ast_debug(1, "Disabled echo cancellation on channel %d\n", p->channel);
02086    }
02087 
02088    p->echocanon = 0;
02089 }
02090 
02091 static void fill_txgain(struct dahdi_gains *g, float gain, int law)
02092 {
02093    int j;
02094    int k;
02095    float linear_gain = pow(10.0, gain / 20.0);
02096 
02097    switch (law) {
02098    case DAHDI_LAW_ALAW:
02099       for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
02100          if (gain) {
02101             k = (int) (((float) AST_ALAW(j)) * linear_gain);
02102             if (k > 32767) k = 32767;
02103             if (k < -32767) k = -32767;
02104             g->txgain[j] = AST_LIN2A(k);
02105          } else {
02106             g->txgain[j] = j;
02107          }
02108       }
02109       break;
02110    case DAHDI_LAW_MULAW:
02111       for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
02112          if (gain) {
02113             k = (int) (((float) AST_MULAW(j)) * linear_gain);
02114             if (k > 32767) k = 32767;
02115             if (k < -32767) k = -32767;
02116             g->txgain[j] = AST_LIN2MU(k);
02117          } else {
02118             g->txgain[j] = j;
02119          }
02120       }
02121       break;
02122    }
02123 }
02124 
02125 static void fill_rxgain(struct dahdi_gains *g, float gain, int law)
02126 {
02127    int j;
02128    int k;
02129    float linear_gain = pow(10.0, gain / 20.0);
02130 
02131    switch (law) {
02132    case DAHDI_LAW_ALAW:
02133       for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
02134          if (gain) {
02135             k = (int) (((float) AST_ALAW(j)) * linear_gain);
02136             if (k > 32767) k = 32767;
02137             if (k < -32767) k = -32767;
02138             g->rxgain[j] = AST_LIN2A(k);
02139          } else {
02140             g->rxgain[j] = j;
02141          }
02142       }
02143       break;
02144    case DAHDI_LAW_MULAW:
02145       for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
02146          if (gain) {
02147             k = (int) (((float) AST_MULAW(j)) * linear_gain);
02148             if (k > 32767) k = 32767;
02149             if (k < -32767) k = -32767;
02150             g->rxgain[j] = AST_LIN2MU(k);
02151          } else {
02152             g->rxgain[j] = j;
02153          }
02154       }
02155       break;
02156    }
02157 }
02158 
02159 static int set_actual_txgain(int fd, int chan, float gain, int law)
02160 {
02161    struct dahdi_gains g;
02162    int res;
02163 
02164    memset(&g, 0, sizeof(g));
02165    g.chan = chan;
02166    res = ioctl(fd, DAHDI_GETGAINS, &g);
02167    if (res) {
02168       ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
02169       return res;
02170    }
02171 
02172    fill_txgain(&g, gain, law);
02173 
02174    return ioctl(fd, DAHDI_SETGAINS, &g);
02175 }
02176 
02177 static int set_actual_rxgain(int fd, int chan, float gain, int law)
02178 {
02179    struct dahdi_gains g;
02180    int res;
02181 
02182    memset(&g, 0, sizeof(g));
02183    g.chan = chan;
02184    res = ioctl(fd, DAHDI_GETGAINS, &g);
02185    if (res) {
02186       ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
02187       return res;
02188    }
02189 
02190    fill_rxgain(&g, gain, law);
02191 
02192    return ioctl(fd, DAHDI_SETGAINS, &g);
02193 }
02194 
02195 static int set_actual_gain(int fd, int chan, float rxgain, float txgain, int law)
02196 {
02197    return set_actual_txgain(fd, chan, txgain, law) | set_actual_rxgain(fd, chan, rxgain, law);
02198 }
02199 
02200 static int bump_gains(struct dahdi_pvt *p)
02201 {
02202    int res;
02203 
02204    /* Bump receive gain by value stored in cid_rxgain */
02205    res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain + p->cid_rxgain, p->txgain, p->law);
02206    if (res) {
02207       ast_log(LOG_WARNING, "Unable to bump gain: %s\n", strerror(errno));
02208       return -1;
02209    }
02210 
02211    return 0;
02212 }
02213 
02214 static int restore_gains(struct dahdi_pvt *p)
02215 {
02216    int res;
02217 
02218    res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law);
02219    if (res) {
02220       ast_log(LOG_WARNING, "Unable to restore gains: %s\n", strerror(errno));
02221       return -1;
02222    }
02223 
02224    return 0;
02225 }
02226 
02227 static inline int dahdi_set_hook(int fd, int hs)
02228 {
02229    int x, res;
02230 
02231    x = hs;
02232    res = ioctl(fd, DAHDI_HOOK, &x);
02233 
02234    if (res < 0) {
02235       if (errno == EINPROGRESS)
02236          return 0;
02237       ast_log(LOG_WARNING, "DAHDI hook failed returned %d (trying %d): %s\n", res, hs, strerror(errno));
02238       /* will expectedly fail if phone is off hook during operation, such as during a restart */
02239    }
02240 
02241    return res;
02242 }
02243 
02244 static inline int dahdi_confmute(struct dahdi_pvt *p, int muted)
02245 {
02246    int x, y, res;
02247    x = muted;
02248    if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
02249       y = 1;
02250       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &y);
02251       if (res)
02252          ast_log(LOG_WARNING, "Unable to set audio mode on %d: %s\n", p->channel, strerror(errno));
02253    }
02254    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_CONFMUTE, &x);
02255    if (res < 0)
02256       ast_log(LOG_WARNING, "DAHDI confmute(%d) failed on channel %d: %s\n", muted, p->channel, strerror(errno));
02257    return res;
02258 }
02259 
02260 static int save_conference(struct dahdi_pvt *p)
02261 {
02262    struct dahdi_confinfo c;
02263    int res;
02264    if (p->saveconf.confmode) {
02265       ast_log(LOG_WARNING, "Can't save conference -- already in use\n");
02266       return -1;
02267    }
02268    p->saveconf.chan = 0;
02269    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &p->saveconf);
02270    if (res) {
02271       ast_log(LOG_WARNING, "Unable to get conference info: %s\n", strerror(errno));
02272       p->saveconf.confmode = 0;
02273       return -1;
02274    }
02275    memset(&c, 0, sizeof(c));
02276    c.confmode = DAHDI_CONF_NORMAL;
02277    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &c);
02278    if (res) {
02279       ast_log(LOG_WARNING, "Unable to set conference info: %s\n", strerror(errno));
02280       return -1;
02281    }
02282    ast_debug(1, "Disabled conferencing\n");
02283    return 0;
02284 }
02285 
02286 /*!
02287  * \brief Send MWI state change
02288  *
02289  * \arg mailbox_full This is the mailbox associated with the FXO line that the
02290  *      MWI state has changed on.
02291  * \arg thereornot This argument should simply be set to 1 or 0, to indicate
02292  *      whether there are messages waiting or not.
02293  *
02294  *  \return nothing
02295  *
02296  * This function does two things:
02297  *
02298  * 1) It generates an internal Asterisk event notifying any other module that
02299  *    cares about MWI that the state of a mailbox has changed.
02300  *
02301  * 2) It runs the script specified by the mwimonitornotify option to allow
02302  *    some custom handling of the state change.
02303  */
02304 static void notify_message(char *mailbox_full, int thereornot)
02305 {
02306    char s[sizeof(mwimonitornotify) + 80];
02307    struct ast_event *event;
02308    char *mailbox, *context;
02309 
02310    /* Strip off @default */
02311    context = mailbox = ast_strdupa(mailbox_full);
02312    strsep(&context, "@");
02313    if (ast_strlen_zero(context))
02314       context = "default";
02315 
02316    if (!(event = ast_event_new(AST_EVENT_MWI,
02317          AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
02318          AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
02319          AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
02320          AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
02321          AST_EVENT_IE_END))) {
02322       return;
02323    }
02324 
02325    ast_event_queue_and_cache(event);
02326 
02327    if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(mwimonitornotify)) {
02328       snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
02329       ast_safe_system(s);
02330    }
02331 }
02332 
02333 static int restore_conference(struct dahdi_pvt *p)
02334 {
02335    int res;
02336    if (p->saveconf.confmode) {
02337       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &p->saveconf);
02338       p->saveconf.confmode = 0;
02339       if (res) {
02340          ast_log(LOG_WARNING, "Unable to restore conference info: %s\n", strerror(errno));
02341          return -1;
02342       }
02343    }
02344    ast_debug(1, "Restored conferencing\n");
02345    return 0;
02346 }
02347 
02348 static int send_callerid(struct dahdi_pvt *p);
02349 
02350 static int send_cwcidspill(struct dahdi_pvt *p)
02351 {
02352    p->callwaitcas = 0;
02353    p->cidcwexpire = 0;
02354    if (!(p->cidspill = ast_malloc(MAX_CALLERID_SIZE)))
02355       return -1;
02356    p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, p->callwait_name, p->callwait_num, AST_LAW(p));
02357    /* Make sure we account for the end */
02358    p->cidlen += READ_SIZE * 4;
02359    p->cidpos = 0;
02360    send_callerid(p);
02361    ast_verb(3, "CPE supports Call Waiting Caller*ID.  Sending '%s/%s'\n", p->callwait_name, p->callwait_num);
02362    return 0;
02363 }
02364 
02365 static int has_voicemail(struct dahdi_pvt *p)
02366 {
02367    int new_msgs;
02368    struct ast_event *event;
02369    char *mailbox, *context;
02370 
02371    mailbox = context = ast_strdupa(p->mailbox);
02372    strsep(&context, "@");
02373    if (ast_strlen_zero(context))
02374       context = "default";
02375 
02376    event = ast_event_get_cached(AST_EVENT_MWI,
02377       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
02378       AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
02379       AST_EVENT_IE_END);
02380 
02381    if (event) {
02382       new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
02383       ast_event_destroy(event);
02384    } else
02385       new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
02386 
02387    return new_msgs;
02388 }
02389 
02390 static int send_callerid(struct dahdi_pvt *p)
02391 {
02392    /* Assumes spill in p->cidspill, p->cidlen in length and we're p->cidpos into it */
02393    int res;
02394    /* Take out of linear mode if necessary */
02395    if (p->subs[SUB_REAL].linear) {
02396       p->subs[SUB_REAL].linear = 0;
02397       dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
02398    }
02399    while (p->cidpos < p->cidlen) {
02400       res = write(p->subs[SUB_REAL].dfd, p->cidspill + p->cidpos, p->cidlen - p->cidpos);
02401       if (res < 0) {
02402          if (errno == EAGAIN)
02403             return 0;
02404          else {
02405             ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
02406             return -1;
02407          }
02408       }
02409       if (!res)
02410          return 0;
02411       p->cidpos += res;
02412    }
02413    ast_free(p->cidspill);
02414    p->cidspill = NULL;
02415    if (p->callwaitcas) {
02416       /* Wait for CID/CW to expire */
02417       p->cidcwexpire = CIDCW_EXPIRE_SAMPLES;
02418    } else
02419       restore_conference(p);
02420    return 0;
02421 }
02422 
02423 static int dahdi_callwait(struct ast_channel *ast)
02424 {
02425    struct dahdi_pvt *p = ast->tech_pvt;
02426    p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES;
02427    if (p->cidspill) {
02428       ast_log(LOG_WARNING, "Spill already exists?!?\n");
02429       ast_free(p->cidspill);
02430    }
02431    if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
02432       return -1;
02433    save_conference(p);
02434    /* Silence */
02435    memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
02436    if (!p->callwaitrings && p->callwaitingcallerid) {
02437       ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
02438       p->callwaitcas = 1;
02439       p->cidlen = 2400 + 680 + READ_SIZE * 4;
02440    } else {
02441       ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
02442       p->callwaitcas = 0;
02443       p->cidlen = 2400 + READ_SIZE * 4;
02444    }
02445    p->cidpos = 0;
02446    send_callerid(p);
02447    
02448    return 0;
02449 }
02450 
02451 #ifdef HAVE_SS7
02452 static unsigned char cid_pres2ss7pres(int cid_pres)
02453 {
02454     return (cid_pres >> 5) & 0x03;
02455 }
02456 
02457 static unsigned char cid_pres2ss7screen(int cid_pres)
02458 {
02459    return cid_pres & 0x03;
02460 }
02461 #endif
02462 
02463 static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
02464 {
02465    struct dahdi_pvt *p = ast->tech_pvt;
02466    int x, res, idx,mysig;
02467    char *c, *n, *l;
02468 #ifdef HAVE_PRI
02469    char *s = NULL;
02470 #endif
02471    char dest[256]; /* must be same length as p->dialdest */
02472    ast_mutex_lock(&p->lock);
02473    ast_copy_string(dest, rdest, sizeof(dest));
02474    ast_copy_string(p->dialdest, rdest, sizeof(p->dialdest));
02475    if ((ast->_state == AST_STATE_BUSY)) {
02476       p->subs[SUB_REAL].needbusy = 1;
02477       ast_mutex_unlock(&p->lock);
02478       return 0;
02479    }
02480    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
02481       ast_log(LOG_WARNING, "dahdi_call called on %s, neither down nor reserved\n", ast->name);
02482       ast_mutex_unlock(&p->lock);
02483       return -1;
02484    }
02485    p->dialednone = 0;
02486    if ((p->radio || (p->oprmode < 0)))  /* if a radio channel, up immediately */
02487    {
02488       /* Special pseudo -- automatically up */
02489       ast_setstate(ast, AST_STATE_UP); 
02490       ast_mutex_unlock(&p->lock);
02491       return 0;
02492    }
02493    x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE;
02494    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
02495    if (res)
02496       ast_log(LOG_WARNING, "Unable to flush input on channel %d: %s\n", p->channel, strerror(errno));
02497    p->outgoing = 1;
02498 
02499    set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law);
02500 
02501    mysig = p->sig;
02502    if (p->outsigmod > -1)
02503       mysig = p->outsigmod;
02504 
02505    switch (mysig) {
02506    case SIG_FXOLS:
02507    case SIG_FXOGS:
02508    case SIG_FXOKS:
02509       if (p->owner == ast) {
02510          /* Normal ring, on hook */
02511          
02512          /* Don't send audio while on hook, until the call is answered */
02513          p->dialing = 1;
02514          if (p->use_callerid) {
02515             /* Generate the Caller-ID spill if desired */
02516             if (p->cidspill) {
02517                ast_log(LOG_WARNING, "cidspill already exists??\n");
02518                ast_free(p->cidspill);
02519             }
02520             p->callwaitcas = 0;
02521             if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) {
02522                p->cidlen = ast_callerid_generate(p->cidspill, ast->cid.cid_name, ast->cid.cid_num, AST_LAW(p));
02523                p->cidpos = 0;
02524                send_callerid(p);
02525             }
02526          }
02527          /* Choose proper cadence */
02528          if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
02529             if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
02530                ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast->name, strerror(errno));
02531             p->cidrings = cidrings[p->distinctivering - 1];
02532          } else {
02533             if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
02534                ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast->name, strerror(errno));
02535             p->cidrings = p->sendcalleridafter;
02536          }
02537 
02538          /* nick@dccinc.com 4/3/03 mods to allow for deferred dialing */
02539          c = strchr(dest, '/');
02540          if (c)
02541             c++;
02542          if (c && (strlen(c) < p->stripmsd)) {
02543             ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
02544             c = NULL;
02545          }
02546          if (c) {
02547             p->dop.op = DAHDI_DIAL_OP_REPLACE;
02548             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "Tw%s", c);
02549             ast_debug(1, "FXO: setup deferred dialstring: %s\n", c);
02550          } else {
02551             p->dop.dialstr[0] = '\0';
02552          }
02553          x = DAHDI_RING;
02554          if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x) && (errno != EINPROGRESS)) {
02555             ast_log(LOG_WARNING, "Unable to ring phone: %s\n", strerror(errno));
02556             ast_mutex_unlock(&p->lock);
02557             return -1;
02558          }
02559          p->dialing = 1;
02560       } else {
02561          /* Call waiting call */
02562          p->callwaitrings = 0;
02563          if (ast->cid.cid_num)
02564             ast_copy_string(p->callwait_num, ast->cid.cid_num, sizeof(p->callwait_num));
02565          else
02566             p->callwait_num[0] = '\0';
02567          if (ast->cid.cid_name)
02568             ast_copy_string(p->callwait_name, ast->cid.cid_name, sizeof(p->callwait_name));
02569          else
02570             p->callwait_name[0] = '\0';
02571          /* Call waiting tone instead */
02572          if (dahdi_callwait(ast)) {
02573             ast_mutex_unlock(&p->lock);
02574             return -1;
02575          }
02576          /* Make ring-back */
02577          if (tone_zone_play_tone(p->subs[SUB_CALLWAIT].dfd, DAHDI_TONE_RINGTONE))
02578             ast_log(LOG_WARNING, "Unable to generate call-wait ring-back on channel %s\n", ast->name);
02579             
02580       }
02581       n = ast->cid.cid_name;
02582       l = ast->cid.cid_num;
02583       if (l)
02584          ast_copy_string(p->lastcid_num, l, sizeof(p->lastcid_num));
02585       else
02586          p->lastcid_num[0] = '\0';
02587       if (n)
02588          ast_copy_string(p->lastcid_name, n, sizeof(p->lastcid_name));
02589       else
02590          p->lastcid_name[0] = '\0';
02591       ast_setstate(ast, AST_STATE_RINGING);
02592       idx = dahdi_get_index(ast, p, 0);
02593       if (idx > -1) {
02594          p->subs[idx].needringing = 1;
02595       }
02596       break;
02597    case SIG_FXSLS:
02598    case SIG_FXSGS:
02599    case SIG_FXSKS:
02600    case SIG_EMWINK:
02601    case SIG_EM:
02602    case SIG_EM_E1:
02603    case SIG_FEATD:
02604    case SIG_FEATDMF:
02605    case SIG_E911:
02606    case SIG_FGC_CAMA:
02607    case SIG_FGC_CAMAMF:
02608    case SIG_FEATB:
02609    case SIG_SFWINK:
02610    case SIG_SF:
02611    case SIG_SF_FEATD:
02612    case SIG_SF_FEATDMF:
02613    case SIG_FEATDMF_TA:
02614    case SIG_SF_FEATB:
02615       c = strchr(dest, '/');
02616       if (c)
02617          c++;
02618       else
02619          c = "";
02620       if (strlen(c) < p->stripmsd) {
02621          ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
02622          ast_mutex_unlock(&p->lock);
02623          return -1;
02624       }
02625 #ifdef HAVE_PRI
02626       /* Start the trunk, if not GR-303 */
02627       if (!p->pri) {
02628 #endif
02629          x = DAHDI_START;
02630          res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
02631          if (res < 0) {
02632             if (errno != EINPROGRESS) {
02633                ast_log(LOG_WARNING, "Unable to start channel: %s\n", strerror(errno));
02634                ast_mutex_unlock(&p->lock);
02635                return -1;
02636             }
02637          }
02638 #ifdef HAVE_PRI
02639       }
02640 #endif
02641       ast_debug(1, "Dialing '%s'\n", c);
02642       p->dop.op = DAHDI_DIAL_OP_REPLACE;
02643 
02644       c += p->stripmsd;
02645 
02646       switch (mysig) {
02647       case SIG_FEATD:
02648          l = ast->cid.cid_num;
02649          if (l) 
02650             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T*%s*%s*", l, c);
02651          else
02652             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T**%s*", c);
02653          break;
02654       case SIG_FEATDMF:
02655          l = ast->cid.cid_num;
02656          if (l) 
02657             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*00%s#*%s#", l, c);
02658          else
02659             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*02#*%s#", c);
02660          break;
02661       case SIG_FEATDMF_TA:
02662       {
02663          const char *cic, *ozz;
02664 
02665          /* If you have to go through a Tandem Access point you need to use this */
02666          ozz = pbx_builtin_getvar_helper(p->owner, "FEATDMF_OZZ");
02667          if (!ozz)
02668             ozz = defaultozz;
02669          cic = pbx_builtin_getvar_helper(p->owner, "FEATDMF_CIC");
02670          if (!cic)
02671             cic = defaultcic;
02672          if (!ozz || !cic) {
02673             ast_log(LOG_WARNING, "Unable to dial channel of type feature group D MF tandem access without CIC or OZZ set\n");
02674             ast_mutex_unlock(&p->lock);
02675             return -1;
02676          }
02677          snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s%s#", ozz, cic);
02678          snprintf(p->finaldial, sizeof(p->finaldial), "M*%s#", c);
02679          p->whichwink = 0;
02680       }
02681          break;
02682       case SIG_E911:
02683          ast_copy_string(p->dop.dialstr, "M*911#", sizeof(p->dop.dialstr));
02684          break;
02685       case SIG_FGC_CAMA:
02686          snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%s", c);
02687          break;
02688       case SIG_FGC_CAMAMF:
02689       case SIG_FEATB:
02690          snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s#", c);
02691          break;
02692       default:
02693          if (p->pulse)
02694             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%sw", c);
02695          else
02696             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T%sw", c);
02697          break;
02698       }
02699 
02700       if (p->echotraining && (strlen(p->dop.dialstr) > 4)) {
02701          memset(p->echorest, 'w', sizeof(p->echorest) - 1);
02702          strcpy(p->echorest + (p->echotraining / 400) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
02703          p->echorest[sizeof(p->echorest) - 1] = '\0';
02704          p->echobreak = 1;
02705          p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
02706       } else
02707          p->echobreak = 0;
02708       if (!res) {
02709          if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
02710             int saveerr = errno;
02711 
02712             x = DAHDI_ONHOOK;
02713             ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
02714             ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
02715             ast_mutex_unlock(&p->lock);
02716             return -1;
02717          }
02718       } else
02719          ast_debug(1, "Deferring dialing...\n");
02720 
02721       p->dialing = 1;
02722       if (ast_strlen_zero(c))
02723          p->dialednone = 1;
02724       ast_setstate(ast, AST_STATE_DIALING);
02725       break;
02726    case 0:
02727       /* Special pseudo -- automatically up*/
02728       ast_setstate(ast, AST_STATE_UP);
02729       break;      
02730    case SIG_PRI:
02731    case SIG_BRI:
02732    case SIG_BRI_PTMP:
02733    case SIG_SS7:
02734       /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
02735       p->dialdest[0] = '\0';
02736       p->dialing = 1;
02737       break;
02738    default:
02739       ast_debug(1, "not yet implemented\n");
02740       ast_mutex_unlock(&p->lock);
02741       return -1;
02742    }
02743 #ifdef HAVE_SS7
02744    if (p->ss7) {
02745       char ss7_called_nai;
02746       int called_nai_strip;
02747       char ss7_calling_nai;
02748       int calling_nai_strip;
02749       const char *charge_str = NULL;
02750       const char *gen_address = NULL;
02751       const char *gen_digits = NULL;
02752       const char *gen_dig_type = NULL;
02753       const char *gen_dig_scheme = NULL;
02754       const char *gen_name = NULL;
02755       const char *jip_digits = NULL;
02756       const char *lspi_ident = NULL;
02757       const char *rlt_flag = NULL;
02758       const char *call_ref_id = NULL;
02759       const char *call_ref_pc = NULL;
02760       const char *send_far = NULL;
02761 
02762       c = strchr(dest, '/');
02763       if (c) {
02764          c++;
02765       } else {
02766          c = "";
02767       }
02768       if (strlen(c) < p->stripmsd) {
02769          ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
02770          ast_mutex_unlock(&p->lock);
02771          return -1;
02772       }
02773 
02774       if (!p->hidecallerid) {
02775          l = ast->cid.cid_num;
02776       } else {
02777          l = NULL;
02778       }
02779 
02780       if (ss7_grab(p, p->ss7)) {
02781          ast_log(LOG_WARNING, "Failed to grab SS7!\n");
02782          ast_mutex_unlock(&p->lock);
02783          return -1;
02784       }
02785       p->digital = IS_DIGITAL(ast->transfercapability);
02786       p->ss7call = isup_new_call(p->ss7->ss7);
02787 
02788       if (!p->ss7call) {
02789          ss7_rel(p->ss7);
02790          ast_mutex_unlock(&p->lock);
02791          ast_log(LOG_ERROR, "Unable to allocate new SS7 call!\n");
02792          return -1;
02793       }
02794 
02795       called_nai_strip = 0;
02796       ss7_called_nai = p->ss7->called_nai;
02797       if (ss7_called_nai == SS7_NAI_DYNAMIC) { /* compute dynamically */
02798          if (strncmp(c + p->stripmsd, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
02799             called_nai_strip = strlen(p->ss7->internationalprefix);
02800             ss7_called_nai = SS7_NAI_INTERNATIONAL;
02801          } else if (strncmp(c + p->stripmsd, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
02802             called_nai_strip = strlen(p->ss7->nationalprefix);
02803             ss7_called_nai = SS7_NAI_NATIONAL;
02804          } else {
02805             ss7_called_nai = SS7_NAI_SUBSCRIBER;
02806          }
02807       }
02808       isup_set_called(p->ss7call, c + p->stripmsd + called_nai_strip, ss7_called_nai, p->ss7->ss7);
02809 
02810       calling_nai_strip = 0;
02811       ss7_calling_nai = p->ss7->calling_nai;
02812       if ((l != NULL) && (ss7_calling_nai == SS7_NAI_DYNAMIC)) { /* compute dynamically */
02813          if (strncmp(l, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
02814             calling_nai_strip = strlen(p->ss7->internationalprefix);
02815             ss7_calling_nai = SS7_NAI_INTERNATIONAL;
02816          } else if (strncmp(l, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
02817             calling_nai_strip = strlen(p->ss7->nationalprefix);
02818             ss7_calling_nai = SS7_NAI_NATIONAL;
02819          } else {
02820             ss7_calling_nai = SS7_NAI_SUBSCRIBER;
02821          }
02822       }
02823       isup_set_calling(p->ss7call, l ? (l + calling_nai_strip) : NULL, ss7_calling_nai,
02824          p->use_callingpres ? cid_pres2ss7pres(ast->cid.cid_pres) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED),
02825          p->use_callingpres ? cid_pres2ss7screen(ast->cid.cid_pres) : SS7_SCREENING_USER_PROVIDED );
02826 
02827       isup_set_oli(p->ss7call, ast->cid.cid_ani2);
02828       isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc);
02829 
02830       ast_channel_lock(ast);
02831       /* Set the charge number if it is set */
02832       charge_str = pbx_builtin_getvar_helper(ast, "SS7_CHARGE_NUMBER");
02833       if (charge_str)
02834          isup_set_charge(p->ss7call, charge_str, SS7_ANI_CALLING_PARTY_SUB_NUMBER, 0x10);
02835       
02836       gen_address = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_ADDRESS");
02837       if (gen_address)
02838          isup_set_gen_address(p->ss7call, gen_address, p->gen_add_nai,p->gen_add_pres_ind, p->gen_add_num_plan,p->gen_add_type); /* need to add some types here for NAI,PRES,TYPE */
02839       
02840       gen_digits = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGITS");
02841       gen_dig_type = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGTYPE");
02842       gen_dig_scheme = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGSCHEME");
02843       if (gen_digits)
02844          isup_set_gen_digits(p->ss7call, gen_digits, atoi(gen_dig_type), atoi(gen_dig_scheme)); 
02845       
02846       gen_name = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_NAME");
02847       if (gen_name)
02848          isup_set_generic_name(p->ss7call, gen_name, GEN_NAME_TYPE_CALLING_NAME, GEN_NAME_AVAIL_AVAILABLE, GEN_NAME_PRES_ALLOWED);
02849 
02850       jip_digits = pbx_builtin_getvar_helper(ast, "SS7_JIP");
02851       if (jip_digits)
02852          isup_set_jip_digits(p->ss7call, jip_digits);
02853       
02854       lspi_ident = pbx_builtin_getvar_helper(ast, "SS7_LSPI_IDENT");
02855       if (lspi_ident)
02856          isup_set_lspi(p->ss7call, lspi_ident, 0x18, 0x7, 0x00); 
02857       
02858       rlt_flag = pbx_builtin_getvar_helper(ast, "SS7_RLT_ON");
02859       if ((rlt_flag) && ((strncmp("NO", rlt_flag, strlen(rlt_flag))) != 0 )) {
02860          isup_set_lspi(p->ss7call, rlt_flag, 0x18, 0x7, 0x00); /* Setting for Nortel DMS-250/500 */
02861       }
02862       
02863       call_ref_id = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_IDENT");
02864       call_ref_pc = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_PC");
02865       if (call_ref_id && call_ref_pc) {
02866          isup_set_callref(p->ss7call, atoi(call_ref_id),
02867                 call_ref_pc ? atoi(call_ref_pc) : 0);
02868       }
02869       
02870       send_far = pbx_builtin_getvar_helper(ast, "SS7_SEND_FAR");
02871       if ((send_far) && ((strncmp("NO", send_far, strlen(send_far))) != 0 ))
02872          (isup_far(p->ss7->ss7, p->ss7call));
02873       
02874       ast_channel_unlock(ast);
02875 
02876       isup_iam(p->ss7->ss7, p->ss7call);
02877       ast_setstate(ast, AST_STATE_DIALING);
02878       ss7_rel(p->ss7);
02879    }
02880 #endif /* HAVE_SS7 */
02881 #ifdef HAVE_PRI
02882    if (p->pri) {
02883       struct pri_sr *sr;
02884 #ifdef SUPPORT_USERUSER
02885       const char *useruser;
02886 #endif
02887       int pridialplan;
02888       int dp_strip;
02889       int prilocaldialplan;
02890       int ldp_strip;
02891       int exclusive;
02892       const char *rr_str;
02893       int redirect_reason;
02894 
02895       c = strchr(dest, '/');
02896       if (c) {
02897          c++;
02898       } else {
02899          c = "";
02900       }
02901 
02902       l = NULL;
02903       n = NULL;
02904       if (!p->hidecallerid) {
02905          l = ast->cid.cid_num;
02906          if (!p->hidecalleridname) {
02907             n = ast->cid.cid_name;
02908          }
02909       }
02910 
02911       if (strlen(c) < p->stripmsd) {
02912          ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
02913          ast_mutex_unlock(&p->lock);
02914          return -1;
02915       }
02916       if (mysig != SIG_FXSKS) {
02917          p->dop.op = DAHDI_DIAL_OP_REPLACE;
02918          s = strchr(c + p->stripmsd, 'w');
02919          if (s) {
02920             if (strlen(s) > 1)
02921                snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T%s", s);
02922             else
02923                p->dop.dialstr[0] = '\0';
02924             *s = '\0';
02925          } else {
02926             p->dop.dialstr[0] = '\0';
02927          }
02928       }
02929       if (pri_grab(p, p->pri)) {
02930          ast_log(LOG_WARNING, "Failed to grab PRI!\n");
02931          ast_mutex_unlock(&p->lock);
02932          return -1;
02933       }
02934       if (!(p->call = pri_new_call(p->pri->pri))) {
02935          ast_log(LOG_WARNING, "Unable to create call on channel %d\n", p->channel);
02936          pri_rel(p->pri);
02937          ast_mutex_unlock(&p->lock);
02938          return -1;
02939       }
02940       if (!(sr = pri_sr_new())) {
02941          ast_log(LOG_WARNING, "Failed to allocate setup request channel %d\n", p->channel);
02942          pri_rel(p->pri);
02943          ast_mutex_unlock(&p->lock);
02944       }
02945       if (p->bearer || (mysig == SIG_FXSKS)) {
02946          if (p->bearer) {
02947             ast_debug(1, "Oooh, I have a bearer on %d (%d:%d)\n", PVT_TO_CHANNEL(p->bearer), p->bearer->logicalspan, p->bearer->channel);
02948             p->bearer->call = p->call;
02949          } else
02950             ast_debug(1, "I'm being setup with no bearer right now...\n");
02951 
02952          pri_set_crv(p->pri->pri, p->call, p->channel, 0);
02953       }
02954       p->digital = IS_DIGITAL(ast->transfercapability);
02955       /* Add support for exclusive override */
02956       if (p->priexclusive)
02957          exclusive = 1;
02958       else {
02959       /* otherwise, traditional behavior */
02960          if (p->pri->nodetype == PRI_NETWORK)
02961             exclusive = 0;
02962          else
02963             exclusive = 1;
02964       }
02965       
02966       pri_sr_set_channel(sr, p->bearer ? PVT_TO_CHANNEL(p->bearer) : PVT_TO_CHANNEL(p), exclusive, 1);
02967       pri_sr_set_bearer(sr, p->digital ? PRI_TRANS_CAP_DIGITAL : ast->transfercapability, 
02968                (p->digital ? -1 : 
02969                   ((p->law == DAHDI_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW)));
02970       if (p->pri->facilityenable)
02971          pri_facility_enable(p->pri->pri);
02972 
02973       ast_verb(3, "Requested transfer capability: 0x%.2x - %s\n", ast->transfercapability, ast_transfercapability2str(ast->transfercapability));
02974       dp_strip = 0;
02975       pridialplan = p->pri->dialplan - 1;
02976       if (pridialplan == -2 || pridialplan == -3) { /* compute dynamically */
02977          if (strncmp(c + p->stripmsd, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
02978             if (pridialplan == -2) {
02979                dp_strip = strlen(p->pri->internationalprefix);
02980             }
02981             pridialplan = PRI_INTERNATIONAL_ISDN;
02982          } else if (strncmp(c + p->stripmsd, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
02983             if (pridialplan == -2) {
02984                dp_strip = strlen(p->pri->nationalprefix);
02985             }
02986             pridialplan = PRI_NATIONAL_ISDN;
02987          } else {
02988             pridialplan = PRI_LOCAL_ISDN;
02989          }
02990       }
02991       while (c[p->stripmsd] > '9' && c[p->stripmsd] != '*' && c[p->stripmsd] != '#') {
02992          switch (c[p->stripmsd]) {
02993          case 'U':
02994             pridialplan = (PRI_TON_UNKNOWN << 4) | (pridialplan & 0xf);
02995             break;
02996          case 'I':
02997             pridialplan = (PRI_TON_INTERNATIONAL << 4) | (pridialplan & 0xf);
02998             break;
02999          case 'N':
03000             pridialplan = (PRI_TON_NATIONAL << 4) | (pridialplan & 0xf);
03001             break;
03002          case 'L':
03003             pridialplan = (PRI_TON_NET_SPECIFIC << 4) | (pridialplan & 0xf);
03004             break;
03005          case 'S':
03006             pridialplan = (PRI_TON_SUBSCRIBER << 4) | (pridialplan & 0xf);
03007             break;
03008          case 'V':
03009             pridialplan = (PRI_TON_ABBREVIATED << 4) | (pridialplan & 0xf);
03010             break;
03011          case 'R':
03012             pridialplan = (PRI_TON_RESERVED << 4) | (pridialplan & 0xf);
03013             break;
03014          case 'u':
03015             pridialplan = PRI_NPI_UNKNOWN | (pridialplan & 0xf0);
03016             break;
03017          case 'e':
03018             pridialplan = PRI_NPI_E163_E164 | (pridialplan & 0xf0);
03019             break;
03020          case 'x':
03021             pridialplan = PRI_NPI_X121 | (pridialplan & 0xf0);
03022             break;
03023          case 'f':
03024             pridialplan = PRI_NPI_F69 | (pridialplan & 0xf0);
03025             break;
03026          case 'n':
03027             pridialplan = PRI_NPI_NATIONAL | (pridialplan & 0xf0);
03028             break;
03029          case 'p':
03030             pridialplan = PRI_NPI_PRIVATE | (pridialplan & 0xf0);
03031             break;
03032          case 'r':
03033             pridialplan = PRI_NPI_RESERVED | (pridialplan & 0xf0);
03034             break;
03035          default:
03036             if (isalpha(c[p->stripmsd])) {
03037                ast_log(LOG_WARNING, "Unrecognized pridialplan %s modifier: %c\n",
03038                   c[p->stripmsd] > 'Z' ? "NPI" : "TON", c[p->stripmsd]);
03039             }
03040             break;
03041          }
03042          c++;
03043       }
03044       pri_sr_set_called(sr, c + p->stripmsd + dp_strip, pridialplan, s ? 1 : 0);
03045 
03046       ldp_strip = 0;
03047       prilocaldialplan = p->pri->localdialplan - 1;
03048       if ((l != NULL) && (prilocaldialplan == -2 || prilocaldialplan == -3)) { /* compute dynamically */
03049          if (strncmp(l, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
03050             if (prilocaldialplan == -2) {
03051                ldp_strip = strlen(p->pri->internationalprefix);
03052             }
03053             prilocaldialplan = PRI_INTERNATIONAL_ISDN;
03054          } else if (strncmp(l, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
03055             if (prilocaldialplan == -2) {
03056                ldp_strip = strlen(p->pri->nationalprefix);
03057             }
03058             prilocaldialplan = PRI_NATIONAL_ISDN;
03059          } else {
03060             prilocaldialplan = PRI_LOCAL_ISDN;
03061          }
03062       }
03063       if (l != NULL) {
03064          while (*l > '9' && *l != '*' && *l != '#') {
03065             switch (*l) {
03066             case 'U':
03067                prilocaldialplan = (PRI_TON_UNKNOWN << 4) | (prilocaldialplan & 0xf);
03068                break;
03069             case 'I':
03070                prilocaldialplan = (PRI_TON_INTERNATIONAL << 4) | (prilocaldialplan & 0xf);
03071                break;
03072             case 'N':
03073                prilocaldialplan = (PRI_TON_NATIONAL << 4) | (prilocaldialplan & 0xf);
03074                break;
03075             case 'L':
03076                prilocaldialplan = (PRI_TON_NET_SPECIFIC << 4) | (prilocaldialplan & 0xf);
03077                break;
03078             case 'S':
03079                prilocaldialplan = (PRI_TON_SUBSCRIBER << 4) | (prilocaldialplan & 0xf);
03080                break;
03081             case 'V':
03082                prilocaldialplan = (PRI_TON_ABBREVIATED << 4) | (prilocaldialplan & 0xf);
03083                break;
03084             case 'R':
03085                prilocaldialplan = (PRI_TON_RESERVED << 4) | (prilocaldialplan & 0xf);
03086                break;
03087             case 'u':
03088                prilocaldialplan = PRI_NPI_UNKNOWN | (prilocaldialplan & 0xf0);
03089                break;
03090             case 'e':
03091                prilocaldialplan = PRI_NPI_E163_E164 | (prilocaldialplan & 0xf0);
03092                break;
03093             case 'x':
03094                prilocaldialplan = PRI_NPI_X121 | (prilocaldialplan & 0xf0);
03095                break;
03096             case 'f':
03097                prilocaldialplan = PRI_NPI_F69 | (prilocaldialplan & 0xf0);
03098                break;
03099             case 'n':
03100                prilocaldialplan = PRI_NPI_NATIONAL | (prilocaldialplan & 0xf0);
03101                break;
03102             case 'p':
03103                prilocaldialplan = PRI_NPI_PRIVATE | (prilocaldialplan & 0xf0);
03104                break;
03105             case 'r':
03106                prilocaldialplan = PRI_NPI_RESERVED | (prilocaldialplan & 0xf0);
03107                break;
03108             default:
03109                if (isalpha(*l)) {
03110                   ast_log(LOG_WARNING,
03111                      "Unrecognized prilocaldialplan %s modifier: %c\n",
03112                      *l > 'Z' ? "NPI" : "TON", *l);
03113                }
03114                break;
03115             }
03116             l++;
03117          }
03118       }
03119       pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan,
03120          p->use_callingpres ? ast->cid.cid_pres : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE));
03121       if ((rr_str = pbx_builtin_getvar_helper(ast, "PRIREDIRECTREASON"))) {
03122          if (!strcasecmp(rr_str, "UNKNOWN"))
03123             redirect_reason = 0;
03124          else if (!strcasecmp(rr_str, "BUSY"))
03125             redirect_reason = 1;
03126          else if (!strcasecmp(rr_str, "NO_REPLY"))
03127             redirect_reason = 2;
03128          else if (!strcasecmp(rr_str, "UNCONDITIONAL"))
03129             redirect_reason = 15;
03130          else
03131             redirect_reason = PRI_REDIR_UNCONDITIONAL;
03132       } else
03133          redirect_reason = PRI_REDIR_UNCONDITIONAL;
03134       pri_sr_set_redirecting(sr, ast->cid.cid_rdnis, p->pri->localdialplan - 1, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, redirect_reason);
03135 
03136 #ifdef SUPPORT_USERUSER
03137       /* User-user info */
03138       useruser = pbx_builtin_getvar_helper(p->owner, "USERUSERINFO");
03139 
03140       if (useruser)
03141          pri_sr_set_useruser(sr, useruser);
03142 #endif
03143 
03144       if (pri_setup(p->pri->pri, p->call, sr)) {
03145          ast_log(LOG_WARNING, "Unable to setup call to %s (using %s)\n", 
03146             c + p->stripmsd + dp_strip, dialplan2str(p->pri->dialplan));
03147          pri_rel(p->pri);
03148          ast_mutex_unlock(&p->lock);
03149          pri_sr_free(sr);
03150          return -1;
03151       }
03152       pri_sr_free(sr);
03153       ast_setstate(ast, AST_STATE_DIALING);
03154       pri_rel(p->pri);
03155    }
03156 #endif      
03157    ast_mutex_unlock(&p->lock);
03158    return 0;
03159 }
03160 
03161 static void destroy_dahdi_pvt(struct dahdi_pvt **pvt)
03162 {
03163    struct dahdi_pvt *p = *pvt;
03164    /* Remove channel from the list */
03165    if (p->prev)
03166       p->prev->next = p->next;
03167    if (p->next)
03168       p->next->prev = p->prev;
03169    if (p->use_smdi)
03170       ast_smdi_interface_unref(p->smdi_iface);
03171    if (p->mwi_event_sub)
03172       ast_event_unsubscribe(p->mwi_event_sub);
03173    if (p->vars)
03174       ast_variables_destroy(p->vars);
03175    ast_mutex_destroy(&p->lock);
03176    dahdi_close_sub(p, SUB_REAL);
03177    if (p->owner)
03178       p->owner->tech_pvt = NULL;
03179    free(p);
03180    *pvt = NULL;
03181 }
03182 
03183 static int destroy_channel(struct dahdi_pvt *prev, struct dahdi_pvt *cur, int now)
03184 {
03185    int owned = 0;
03186    int i = 0;
03187 
03188    if (!now) {
03189       if (cur->owner) {
03190          owned = 1;
03191       }
03192 
03193       for (i = 0; i < 3; i++) {
03194          if (cur->subs[i].owner) {
03195             owned = 1;
03196          }
03197       }
03198       if (!owned) {
03199          if (prev) {
03200             prev->next = cur->next;
03201             if (prev->next)
03202                prev->next->prev = prev;
03203             else
03204                ifend = prev;
03205          } else {
03206             iflist = cur->next;
03207             if (iflist)
03208                iflist->prev = NULL;
03209             else
03210                ifend = NULL;
03211          }
03212          destroy_dahdi_pvt(&cur);
03213       }
03214    } else {
03215       if (prev) {
03216          prev->next = cur->next;
03217          if (prev->next)
03218             prev->next->prev = prev;
03219          else
03220             ifend = prev;
03221       } else {
03222          iflist = cur->next;
03223          if (iflist)
03224             iflist->prev = NULL;
03225          else
03226             ifend = NULL;
03227       }
03228       destroy_dahdi_pvt(&cur);
03229    }
03230    return 0;
03231 }
03232 
03233 static void destroy_all_channels(void)
03234 {
03235    int x;
03236    struct dahdi_pvt *p, *pl;
03237 
03238    while (num_restart_pending) {
03239       usleep(1);
03240    }
03241 
03242    ast_mutex_lock(&iflock);
03243    /* Destroy all the interfaces and free their memory */
03244    p = iflist;
03245    while (p) {
03246       /* Free any callerid */
03247       if (p->cidspill)
03248          ast_free(p->cidspill);
03249       pl = p;
03250       p = p->next;
03251       x = pl->channel;
03252       /* Free associated memory */
03253       if (pl)
03254          destroy_dahdi_pvt(&pl);
03255       if (option_verbose > 2) 
03256          ast_verbose(VERBOSE_PREFIX_2 "Unregistered channel %d\n", x);
03257    }
03258    iflist = NULL;
03259    ifcount = 0;
03260    ast_mutex_unlock(&iflock);
03261 }
03262 
03263 #ifdef HAVE_PRI
03264 static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility";
03265 
03266 static char *dahdi_send_keypad_facility_synopsis = "Send digits out of band over a PRI";
03267 
03268 static char *dahdi_send_keypad_facility_descrip = 
03269 "  DAHDISendKeypadFacility(): This application will send the given string of digits in a Keypad Facility\n"
03270 "  IE over the current channel.\n";
03271 
03272 static int dahdi_send_keypad_facility_exec(struct ast_channel *chan, void *data)
03273 {
03274    /* Data will be our digit string */
03275    struct dahdi_pvt *p;
03276    char *digits = (char *) data;
03277 
03278    if (ast_strlen_zero(digits)) {
03279       ast_debug(1, "No digit string sent to application!\n");
03280       return -1;
03281    }
03282 
03283    p = (struct dahdi_pvt *)chan->tech_pvt;
03284 
03285    if (!p) {
03286       ast_debug(1, "Unable to find technology private\n");
03287       return -1;
03288    }
03289 
03290    ast_mutex_lock(&p->lock);
03291 
03292    if (!p->pri || !p->call) {
03293       ast_debug(1, "Unable to find pri or call on channel!\n");
03294       ast_mutex_unlock(&p->lock);
03295       return -1;
03296    }
03297 
03298    if (!pri_grab(p, p->pri)) {
03299       pri_keypad_facility(p->pri->pri, p->call, digits);
03300       pri_rel(p->pri);
03301    } else {
03302       ast_debug(1, "Unable to grab pri to send keypad facility!\n");
03303       ast_mutex_unlock(&p->lock);
03304       return -1;
03305    }
03306 
03307    ast_mutex_unlock(&p->lock);
03308 
03309    return 0;
03310 }
03311 
03312 static int pri_is_up(struct dahdi_pri *pri)
03313 {
03314    int x;
03315    for (x = 0; x < NUM_DCHANS; x++) {
03316       if (pri->dchanavail[x] == DCHAN_AVAILABLE)
03317          return 1;
03318    }
03319    return 0;
03320 }
03321 
03322 static int pri_assign_bearer(struct dahdi_pvt *crv, struct dahdi_pri *pri, struct dahdi_pvt *bearer)
03323 {
03324    bearer->owner = &inuse;
03325    bearer->realcall = crv;
03326    crv->subs[SUB_REAL].dfd = bearer->subs[SUB_REAL].dfd;
03327    if (crv->subs[SUB_REAL].owner)
03328       ast_channel_set_fd(crv->subs[SUB_REAL].owner, 0, crv->subs[SUB_REAL].dfd);
03329    crv->bearer = bearer;
03330    crv->call = bearer->call;
03331    crv->pri = pri;
03332    return 0;
03333 }
03334 
03335 static char *pri_order(int level)
03336 {
03337    switch (level) {
03338    case 0:
03339       return "Primary";
03340    case 1:
03341       return "Secondary";
03342    case 2:
03343       return "Tertiary";
03344    case 3:
03345       return "Quaternary";
03346    default:
03347       return "<Unknown>";
03348    }     
03349 }
03350 
03351 /* Returns fd of the active dchan */
03352 static int pri_active_dchan_fd(struct dahdi_pri *pri)
03353 {
03354    int x = -1;
03355 
03356    for (x = 0; x < NUM_DCHANS; x++) {
03357       if ((pri->dchans[x] == pri->pri))
03358          break;
03359    }
03360 
03361    return pri->fds[x];
03362 }
03363 
03364 static int pri_find_dchan(struct dahdi_pri *pri)
03365 {
03366    int oldslot = -1;
03367    struct pri *old;
03368    int newslot = -1;
03369    int x;
03370    old = pri->pri;
03371    for (x = 0; x < NUM_DCHANS; x++) {
03372       if ((pri->dchanavail[x] == DCHAN_AVAILABLE) && (newslot < 0))
03373          newslot = x;
03374       if (pri->dchans[x] == old) {
03375          oldslot = x;
03376       }
03377    }
03378    if (newslot < 0) {
03379       newslot = 0;
03380       ast_log(LOG_WARNING, "No D-channels available!  Using Primary channel %d as D-channel anyway!\n",
03381          pri->dchannels[newslot]);
03382    }
03383    if (old && (oldslot != newslot))
03384       ast_log(LOG_NOTICE, "Switching from from d-channel %d to channel %d!\n",
03385          pri->dchannels[oldslot], pri->dchannels[newslot]);
03386    pri->pri = pri->dchans[newslot];
03387    return 0;
03388 }
03389 #endif
03390 
03391 static int dahdi_hangup(struct ast_channel *ast)
03392 {
03393    int res;
03394    int idx,x, law;
03395    /*static int restore_gains(struct dahdi_pvt *p);*/
03396    struct dahdi_pvt *p = ast->tech_pvt;
03397    struct dahdi_pvt *tmp = NULL;
03398    struct dahdi_pvt *prev = NULL;
03399    struct dahdi_params par;
03400 
03401    ast_debug(1, "dahdi_hangup(%s)\n", ast->name);
03402    if (!ast->tech_pvt) {
03403       ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
03404       return 0;
03405    }
03406    
03407    ast_mutex_lock(&p->lock);
03408    
03409    idx = dahdi_get_index(ast, p, 1);
03410 
03411    if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
03412       x = 1;
03413       ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
03414    }
03415 
03416    x = 0;
03417    dahdi_confmute(p, 0);
03418    p->muting = 0;
03419    restore_gains(p);
03420    if (p->origcid_num) {
03421       ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num));
03422       ast_free(p->origcid_num);
03423       p->origcid_num = NULL;
03424    }  
03425    if (p->origcid_name) {
03426       ast_copy_string(p->cid_name, p->origcid_name, sizeof(p->cid_name));
03427       ast_free(p->origcid_name);
03428       p->origcid_name = NULL;
03429    }  
03430    if (p->dsp)
03431       ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
03432    p->exten[0] = '\0';
03433 
03434    ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
03435       p->channel, idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
03436    p->ignoredtmf = 0;
03437    
03438    if (idx > -1) {
03439       /* Real channel, do some fixup */
03440       p->subs[idx].owner = NULL;
03441       p->subs[idx].needanswer = 0;
03442       p->subs[idx].needflash = 0;
03443       p->subs[idx].needringing = 0;
03444       p->subs[idx].needbusy = 0;
03445       p->subs[idx].needcongestion = 0;
03446       p->subs[idx].linear = 0;
03447       p->subs[idx].needcallerid = 0;
03448       p->polarity = POLARITY_IDLE;
03449       dahdi_setlinear(p->subs[idx].dfd, 0);
03450       if (idx == SUB_REAL) {
03451          if ((p->subs[SUB_CALLWAIT].dfd > -1) && (p->subs[SUB_THREEWAY].dfd > -1)) {
03452             ast_debug(1, "Normal call hung up with both three way call and a call waiting call in place?\n");
03453             if (p->subs[SUB_CALLWAIT].inthreeway) {
03454                /* We had flipped over to answer a callwait and now it's gone */
03455                ast_debug(1, "We were flipped over to the callwait, moving back and unowning.\n");
03456                /* Move to the call-wait, but un-own us until they flip back. */
03457                swap_subs(p, SUB_CALLWAIT, SUB_REAL);
03458                unalloc_sub(p, SUB_CALLWAIT);
03459                p->owner = NULL;
03460             } else {
03461                /* The three way hung up, but we still have a call wait */
03462                ast_debug(1, "We were in the threeway and have a callwait still.  Ditching the threeway.\n");
03463                swap_subs(p, SUB_THREEWAY, SUB_REAL);
03464                unalloc_sub(p, SUB_THREEWAY);
03465                if (p->subs[SUB_REAL].inthreeway) {
03466                   /* This was part of a three way call.  Immediately make way for
03467                      another call */
03468                   ast_debug(1, "Call was complete, setting owner to former third call\n");
03469                   p->owner = p->subs[SUB_REAL].owner;
03470                } else {
03471                   /* This call hasn't been completed yet...  Set owner to NULL */
03472                   ast_debug(1, "Call was incomplete, setting owner to NULL\n");
03473                   p->owner = NULL;
03474                }
03475                p->subs[SUB_REAL].inthreeway = 0;
03476             }
03477          } else if (p->subs[SUB_CALLWAIT].dfd > -1) {
03478             /* Move to the call-wait and switch back to them. */
03479             swap_subs(p, SUB_CALLWAIT, SUB_REAL);
03480             unalloc_sub(p, SUB_CALLWAIT);
03481             p->owner = p->subs[SUB_REAL].owner;
03482             if (p->owner->_state != AST_STATE_UP)
03483                p->subs[SUB_REAL].needanswer = 1;
03484             if (ast_bridged_channel(p->subs[SUB_REAL].owner))
03485                ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
03486          } else if (p->subs[SUB_THREEWAY].dfd > -1) {
03487             swap_subs(p, SUB_THREEWAY, SUB_REAL);
03488             unalloc_sub(p, SUB_THREEWAY);
03489             if (p->subs[SUB_REAL].inthreeway) {
03490                /* This was part of a three way call.  Immediately make way for
03491                   another call */
03492                ast_debug(1, "Call was complete, setting owner to former third call\n");
03493                p->owner = p->subs[SUB_REAL].owner;
03494             } else {
03495                /* This call hasn't been completed yet...  Set owner to NULL */
03496                ast_debug(1, "Call was incomplete, setting owner to NULL\n");
03497                p->owner = NULL;
03498             }
03499             p->subs[SUB_REAL].inthreeway = 0;
03500          }
03501       } else if (idx == SUB_CALLWAIT) {
03502          /* Ditch the holding callwait call, and immediately make it availabe */
03503          if (p->subs[SUB_CALLWAIT].inthreeway) {
03504             /* This is actually part of a three way, placed on hold.  Place the third part
03505                on music on hold now */
03506             if (p->subs[SUB_THREEWAY].owner && ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
03507                ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD, 
03508                   S_OR(p->mohsuggest, NULL),
03509                   !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
03510             }
03511             p->subs[SUB_THREEWAY].inthreeway = 0;
03512             /* Make it the call wait now */
03513             swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
03514             unalloc_sub(p, SUB_THREEWAY);
03515          } else
03516             unalloc_sub(p, SUB_CALLWAIT);
03517       } else if (idx == SUB_THREEWAY) {
03518          if (p->subs[SUB_CALLWAIT].inthreeway) {
03519             /* The other party of the three way call is currently in a call-wait state.
03520                Start music on hold for them, and take the main guy out of the third call */
03521             if (p->subs[SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
03522                ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD, 
03523                   S_OR(p->mohsuggest, NULL),
03524                   !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
03525             }
03526             p->subs[SUB_CALLWAIT].inthreeway = 0;
03527          }
03528          p->subs[SUB_REAL].inthreeway = 0;
03529          /* If this was part of a three way call index, let us make
03530             another three way call */
03531          unalloc_sub(p, SUB_THREEWAY);
03532       } else {
03533          /* This wasn't any sort of call, but how are we an index? */
03534          ast_log(LOG_WARNING, "Index found but not any type of call?\n");
03535       }
03536    }
03537 
03538    if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
03539       p->owner = NULL;
03540       p->ringt = 0;
03541       p->distinctivering = 0;
03542       p->confirmanswer = 0;
03543       p->cidrings = 1;
03544       p->outgoing = 0;
03545       p->digital = 0;
03546       p->faxhandled = 0;
03547       p->pulsedial = 0;
03548       p->onhooktime = time(NULL);
03549 #if defined(HAVE_PRI) || defined(HAVE_SS7)
03550       p->proceeding = 0;
03551       p->dialing = 0;
03552       p->progress = 0;
03553       p->alerting = 0;
03554       p->setup_ack = 0;
03555       p->rlt = 0;
03556 #endif      
03557       if (p->dsp) {
03558          ast_dsp_free(p->dsp);
03559          p->dsp = NULL;
03560       }
03561 
03562       law = DAHDI_LAW_DEFAULT;
03563       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
03564       if (res < 0) 
03565          ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
03566       /* Perform low level hangup if no owner left */
03567 #ifdef HAVE_SS7
03568       if (p->ss7) {
03569          if (p->ss7call) {
03570             if (!ss7_grab(p, p->ss7)) {
03571                if (!p->alreadyhungup) {
03572                   const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
03573                   int icause = ast->hangupcause ? ast->hangupcause : -1;
03574 
03575                   if (cause) {
03576                      if (atoi(cause))
03577                         icause = atoi(cause);
03578                   }
03579                   isup_rel(p->ss7->ss7, p->ss7call, icause);
03580                   ss7_rel(p->ss7);
03581                   p->alreadyhungup = 1;
03582                } else
03583                   ast_log(LOG_WARNING, "Trying to hangup twice!\n");
03584             } else {
03585                ast_log(LOG_WARNING, "Unable to grab SS7 on CIC %d\n", p->cic);
03586                res = -1;
03587             }
03588          }
03589       }
03590 #endif
03591 #ifdef HAVE_PRI
03592       if (p->pri) {
03593 #ifdef SUPPORT_USERUSER
03594          const char *useruser = pbx_builtin_getvar_helper(ast,"USERUSERINFO");
03595 #endif
03596 
03597          /* Make sure we have a call (or REALLY have a call in the case of a PRI) */
03598          if (p->call && (!p->bearer || (p->bearer->call == p->call))) {
03599             if (!pri_grab(p, p->pri)) {
03600                if (p->alreadyhungup) {
03601                   ast_debug(1, "Already hungup...  Calling hangup once, and clearing call\n");
03602 
03603 #ifdef SUPPORT_USERUSER
03604                   pri_call_set_useruser(p->call, useruser);
03605 #endif
03606 
03607                   pri_hangup(p->pri->pri, p->call, -1);
03608                   p->call = NULL;
03609                   if (p->bearer) 
03610                      p->bearer->call = NULL;
03611                } else {
03612                   const char *cause = pbx_builtin_getvar_helper(ast,"PRI_CAUSE");
03613                   int icause = ast->hangupcause ? ast->hangupcause : -1;
03614                   ast_debug(1, "Not yet hungup...  Calling hangup once with icause, and clearing call\n");
03615 
03616 #ifdef SUPPORT_USERUSER
03617                   pri_call_set_useruser(p->call, useruser);
03618 #endif
03619 
03620                   p->alreadyhungup = 1;
03621                   if (p->bearer)
03622                      p->bearer->alreadyhungup = 1;
03623                   if (cause) {
03624                      if (atoi(cause))
03625                         icause = atoi(cause);
03626                   }
03627                   pri_hangup(p->pri->pri, p->call, icause);
03628                }
03629                if (res < 0) 
03630                   ast_log(LOG_WARNING, "pri_disconnect failed\n");
03631                pri_rel(p->pri);        
03632             } else {
03633                ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
03634                res = -1;
03635             }
03636          } else {
03637             if (p->bearer)
03638                ast_debug(1, "Bearer call is %p, while ours is still %p\n", p->bearer->call, p->call);
03639             p->call = NULL;
03640             res = 0;
03641          }
03642       }
03643 #endif
03644       if (p->sig && ((p->sig != SIG_PRI) && (p->sig != SIG_SS7) && (p->sig != SIG_BRI) && (p->sig != SIG_BRI_PTMP)))
03645          res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
03646       if (res < 0) {
03647          ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
03648       }
03649       switch (p->sig) {
03650       case SIG_FXOGS:
03651       case SIG_FXOLS:
03652       case SIG_FXOKS:
03653          memset(&par, 0, sizeof(par));
03654          res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
03655          if (!res) {
03656 #if 0
03657             ast_debug(1, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
03658 #endif
03659             /* If they're off hook, try playing congestion */
03660             if ((par.rxisoffhook) && (!(p->radio || (p->oprmode < 0))))
03661                tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
03662             else
03663                tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
03664          }
03665          break;
03666       case SIG_FXSGS:
03667       case SIG_FXSLS:
03668       case SIG_FXSKS:
03669          /* Make sure we're not made available for at least two seconds assuming
03670             we were actually used for an inbound or outbound call. */
03671          if (ast->_state != AST_STATE_RESERVED) {
03672             time(&p->guardtime);
03673             p->guardtime += 2;
03674          }
03675          break;
03676       default:
03677          tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
03678       }
03679       if (p->cidspill)
03680          ast_free(p->cidspill);
03681       if (p->sig)
03682          dahdi_disable_ec(p);
03683       x = 0;
03684       ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
03685       ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
03686       p->didtdd = 0;
03687       p->cidspill = NULL;
03688       p->callwaitcas = 0;
03689       p->callwaiting = p->permcallwaiting;
03690       p->hidecallerid = p->permhidecallerid;
03691       p->dialing = 0;
03692       p->rdnis[0] = '\0';
03693       update_conf(p);
03694       reset_conf(p);
03695       /* Restore data mode */
03696       if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
03697          x = 0;
03698          ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
03699       }
03700 #ifdef HAVE_PRI
03701       if (p->bearer) {
03702          ast_debug(1, "Freeing up bearer channel %d\n", p->bearer->channel);
03703          /* Free up the bearer channel as well, and
03704             don't use its file descriptor anymore */
03705          update_conf(p->bearer);
03706          reset_conf(p->bearer);
03707          p->bearer->owner = NULL;
03708          p->bearer->realcall = NULL;
03709          p->bearer = NULL;
03710          p->subs[SUB_REAL].dfd = -1;
03711          p->pri = NULL;
03712       }
03713 #endif
03714       if (num_restart_pending == 0)
03715          restart_monitor();
03716    }
03717 
03718    p->callwaitingrepeat = 0;
03719    p->cidcwexpire = 0;
03720    p->oprmode = 0;
03721    ast->tech_pvt = NULL;
03722    ast_mutex_unlock(&p->lock);
03723    ast_module_unref(ast_module_info->self);
03724    ast_verb(3, "Hungup '%s'\n", ast->name);
03725 
03726    ast_mutex_lock(&iflock);
03727 
03728    if (p->restartpending) {
03729       num_restart_pending--;
03730    }
03731 
03732    tmp = iflist;
03733    prev = NULL;
03734    if (p->destroy) {
03735       while (tmp) {
03736          if (tmp == p) {
03737             destroy_channel(prev, tmp, 0);
03738             break;
03739          } else {
03740             prev = tmp;
03741             tmp = tmp->next;
03742          }
03743       }
03744    }
03745    ast_mutex_unlock(&iflock);
03746    return 0;
03747 }
03748 
03749 static int dahdi_answer(struct ast_channel *ast)
03750 {
03751    struct dahdi_pvt *p = ast->tech_pvt;
03752    int res = 0;
03753    int idx;
03754    int oldstate = ast->_state;
03755    ast_setstate(ast, AST_STATE_UP);
03756    ast_mutex_lock(&p->lock);
03757    idx = dahdi_get_index(ast, p, 0);
03758    if (idx < 0)
03759       idx = SUB_REAL;
03760    /* nothing to do if a radio channel */
03761    if ((p->radio || (p->oprmode < 0))) {
03762       ast_mutex_unlock(&p->lock);
03763       return 0;
03764    }
03765    switch (p->sig) {
03766    case SIG_FXSLS:
03767    case SIG_FXSGS:
03768    case SIG_FXSKS:
03769       p->ringt = 0;
03770       /* Fall through */
03771    case SIG_EM:
03772    case SIG_EM_E1:
03773    case SIG_EMWINK:
03774    case SIG_FEATD:
03775    case SIG_FEATDMF:
03776    case SIG_FEATDMF_TA:
03777    case SIG_E911:
03778    case SIG_FGC_CAMA:
03779    case SIG_FGC_CAMAMF:
03780    case SIG_FEATB:
03781    case SIG_SF:
03782    case SIG_SFWINK:
03783    case SIG_SF_FEATD:
03784    case SIG_SF_FEATDMF:
03785    case SIG_SF_FEATB:
03786    case SIG_FXOLS:
03787    case SIG_FXOGS:
03788    case SIG_FXOKS:
03789       /* Pick up the line */
03790       ast_debug(1, "Took %s off hook\n", ast->name);
03791       if (p->hanguponpolarityswitch) {
03792          p->polaritydelaytv = ast_tvnow();
03793       }
03794       res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
03795       tone_zone_play_tone(p->subs[idx].dfd, -1);
03796       p->dialing = 0;
03797       if ((idx == SUB_REAL) && p->subs[SUB_THREEWAY].inthreeway) {
03798          if (oldstate == AST_STATE_RINGING) {
03799             ast_debug(1, "Finally swapping real and threeway\n");
03800             tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, -1);
03801             swap_subs(p, SUB_THREEWAY, SUB_REAL);
03802             p->owner = p->subs[SUB_REAL].owner;
03803          }
03804       }
03805       if (p->sig & __DAHDI_SIG_FXS) {
03806          dahdi_enable_ec(p);
03807          dahdi_train_ec(p);
03808       }
03809       break;
03810 #ifdef HAVE_PRI
03811    case SIG_BRI:
03812    case SIG_BRI_PTMP:
03813    case SIG_PRI:
03814       /* Send a pri acknowledge */
03815       if (!pri_grab(p, p->pri)) {
03816          p->proceeding = 1;
03817          p->dialing = 0;
03818          res = pri_answer(p->pri->pri, p->call, 0, !p->digital);
03819          pri_rel(p->pri);
03820       } else {
03821          ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
03822          res = -1;
03823       }
03824       break;
03825 #endif
03826 #ifdef HAVE_SS7
03827    case SIG_SS7:
03828       if (!ss7_grab(p, p->ss7)) {
03829          p->proceeding = 1;
03830          res = isup_anm(p->ss7->ss7, p->ss7call);
03831          ss7_rel(p->ss7);
03832       } else {
03833          ast_log(LOG_WARNING, "Unable to grab SS7 on span %d\n", p->span);
03834          res = -1;
03835       }
03836       break;
03837 #endif
03838    case 0:
03839       ast_mutex_unlock(&p->lock);
03840       return 0;
03841    default:
03842       ast_log(LOG_WARNING, "Don't know how to answer signalling %d (channel %d)\n", p->sig, p->channel);
03843       res = -1;
03844    }
03845    ast_mutex_unlock(&p->lock);
03846    return res;
03847 }
03848 
03849 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
03850 {
03851    char *cp;
03852    signed char *scp;
03853    int x;
03854    int idx;
03855    struct dahdi_pvt *p = chan->tech_pvt, *pp;
03856    struct oprmode *oprmode;
03857    
03858 
03859    /* all supported options require data */
03860    if (!data || (datalen < 1)) {
03861       errno = EINVAL;
03862       return -1;
03863    }
03864 
03865    switch (option) {
03866    case AST_OPTION_TXGAIN:
03867       scp = (signed char *) data;
03868       idx = dahdi_get_index(chan, p, 0);
03869       if (idx < 0) {
03870          ast_log(LOG_WARNING, "No index in TXGAIN?\n");
03871          return -1;
03872       }
03873       ast_debug(1, "Setting actual tx gain on %s to %f\n", chan->name, p->txgain + (float) *scp);
03874       return set_actual_txgain(p->subs[idx].dfd, 0, p->txgain + (float) *scp, p->law);
03875    case AST_OPTION_RXGAIN:
03876       scp = (signed char *) data;
03877       idx = dahdi_get_index(chan, p, 0);
03878       if (idx < 0) {
03879          ast_log(LOG_WARNING, "No index in RXGAIN?\n");
03880          return -1;
03881       }
03882       ast_debug(1, "Setting actual rx gain on %s to %f\n", chan->name, p->rxgain + (float) *scp);
03883       return set_actual_rxgain(p->subs[idx].dfd, 0, p->rxgain + (float) *scp, p->law);
03884    case AST_OPTION_TONE_VERIFY:
03885       if (!p->dsp)
03886          break;
03887       cp = (char *) data;
03888       switch (*cp) {
03889       case 1:
03890          ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",chan->name);
03891          ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | p->dtmfrelax);  /* set mute mode if desired */
03892          break;
03893       case 2:
03894          ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",chan->name);
03895          ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX | p->dtmfrelax);  /* set mute mode if desired */
03896          break;
03897       default:
03898          ast_debug(1, "Set option TONE VERIFY, mode: OFF(0) on %s\n",chan->name);
03899          ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);  /* set mute mode if desired */
03900          break;
03901       }
03902       break;
03903    case AST_OPTION_TDD:
03904       /* turn on or off TDD */
03905       cp = (char *) data;
03906       p->mate = 0;
03907       if (!*cp) { /* turn it off */
03908          ast_debug(1, "Set option TDD MODE, value: OFF(0) on %s\n",chan->name);
03909          if (p->tdd)
03910             tdd_free(p->tdd);
03911          p->tdd = 0;
03912          break;
03913       }
03914       ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
03915          (*cp == 2) ? "MATE" : "ON", (int) *cp, chan->name);
03916       dahdi_disable_ec(p);
03917       /* otherwise, turn it on */
03918       if (!p->didtdd) { /* if havent done it yet */
03919          unsigned char mybuf[41000];/*! \todo XXX This is an abuse of the stack!! */
03920          unsigned char *buf;
03921          int size, res, fd, len;
03922          struct pollfd fds[1];
03923 
03924          buf = mybuf;
03925          memset(buf, 0x7f, sizeof(mybuf)); /* set to silence */
03926          ast_tdd_gen_ecdisa(buf + 16000, 16000);  /* put in tone */
03927          len = 40000;
03928          idx = dahdi_get_index(chan, p, 0);
03929          if (idx < 0) {
03930             ast_log(LOG_WARNING, "No index in TDD?\n");
03931             return -1;
03932          }
03933          fd = p->subs[idx].dfd;
03934          while (len) {
03935             if (ast_check_hangup(chan))
03936                return -1;
03937             size = len;
03938             if (size > READ_SIZE)
03939                size = READ_SIZE;
03940             fds[0].fd = fd;
03941             fds[0].events = POLLPRI | POLLOUT;
03942             fds[0].revents = 0;
03943             res = poll(fds, 1, -1);
03944             if (!res) {
03945                ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
03946                continue;
03947             }
03948             /* if got exception */
03949             if (fds[0].revents & POLLPRI)
03950                return -1;
03951             if (!(fds[0].revents & POLLOUT)) {
03952                ast_debug(1, "write fd not ready on channel %d\n", p->channel);
03953                continue;
03954             }
03955             res = write(fd, buf, size);
03956             if (res != size) {
03957                if (res == -1) return -1;
03958                ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
03959                break;
03960             }
03961             len -= size;
03962             buf += size;
03963          }
03964          p->didtdd = 1; /* set to have done it now */    
03965       }
03966       if (*cp == 2) { /* Mate mode */
03967          if (p->tdd)
03968             tdd_free(p->tdd);
03969          p->tdd = 0;
03970          p->mate = 1;
03971          break;
03972       }     
03973       if (!p->tdd) { /* if we dont have one yet */
03974          p->tdd = tdd_new(); /* allocate one */
03975       }     
03976       break;
03977    case AST_OPTION_RELAXDTMF:  /* Relax DTMF decoding (or not) */
03978       if (!p->dsp)
03979          break;
03980       cp = (char *) data;
03981       ast_debug(1, "Set option RELAX DTMF, value: %s(%d) on %s\n",
03982          *cp ? "ON" : "OFF", (int) *cp, chan->name);
03983       ast_dsp_set_digitmode(p->dsp, ((*cp) ? DSP_DIGITMODE_RELAXDTMF : DSP_DIGITMODE_DTMF) | p->dtmfrelax);
03984       break;
03985    case AST_OPTION_AUDIO_MODE:  /* Set AUDIO mode (or not) */
03986       cp = (char *) data;
03987       if (!*cp) {    
03988          ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", chan->name);
03989          x = 0;
03990          dahdi_disable_ec(p);
03991       } else {    
03992          ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", chan->name);
03993          x = 1;
03994       }
03995       if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x) == -1)
03996          ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, x, strerror(errno));
03997       break;
03998    case AST_OPTION_OPRMODE:  /* Operator services mode */
03999       oprmode = (struct oprmode *) data;
04000       pp = oprmode->peer->tech_pvt;
04001       p->oprmode = pp->oprmode = 0;
04002       /* setup peers */
04003       p->oprpeer = pp;
04004       pp->oprpeer = p;
04005       /* setup modes, if any */
04006       if (oprmode->mode) 
04007       {
04008          pp->oprmode = oprmode->mode;
04009          p->oprmode = -oprmode->mode;
04010       }
04011       ast_debug(1, "Set Operator Services mode, value: %d on %s/%s\n",
04012          oprmode->mode, chan->name,oprmode->peer->name);
04013       break;
04014    case AST_OPTION_ECHOCAN:
04015       cp = (char *) data;
04016       if (*cp) {
04017          ast_debug(1, "Enabling echo cancelation on %s\n", chan->name);
04018          dahdi_enable_ec(p);
04019       } else {
04020          ast_debug(1, "Disabling echo cancelation on %s\n", chan->name);
04021          dahdi_disable_ec(p);
04022       }
04023       break;
04024    }
04025    errno = 0;
04026 
04027    return 0;
04028 }
04029 
04030 static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
04031 {
04032    struct dahdi_pvt *p = chan->tech_pvt;
04033    
04034    if (!strcasecmp(data, "rxgain")) {
04035       ast_mutex_lock(&p->lock);
04036       snprintf(buf, len, "%f", p->rxgain);
04037       ast_mutex_unlock(&p->lock);   
04038    } else if (!strcasecmp(data, "txgain")) {
04039       ast_mutex_lock(&p->lock);
04040       snprintf(buf, len, "%f", p->txgain);
04041       ast_mutex_unlock(&p->lock);   
04042    } else {
04043       ast_copy_string(buf, "", len);
04044    }
04045    return 0;
04046 }
04047 
04048 
04049 static void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
04050 {
04051    /* Unlink a specific slave or all slaves/masters from a given master */
04052    int x;
04053    int hasslaves;
04054    if (!master)
04055       return;
04056    if (needlock) {
04057       ast_mutex_lock(&master->lock);
04058       if (slave) {
04059          while (ast_mutex_trylock(&slave->lock)) {
04060             DEADLOCK_AVOIDANCE(&master->lock);
04061          }
04062       }
04063    }
04064    hasslaves = 0;
04065    for (x = 0; x < MAX_SLAVES; x++) {
04066       if (master->slaves[x]) {
04067          if (!slave || (master->slaves[x] == slave)) {
04068             /* Take slave out of the conference */
04069             ast_debug(1, "Unlinking slave %d from %d\n", master->slaves[x]->channel, master->channel);
04070             conf_del(master, &master->slaves[x]->subs[SUB_REAL], SUB_REAL);
04071             conf_del(master->slaves[x], &master->subs[SUB_REAL], SUB_REAL);
04072             master->slaves[x]->master = NULL;
04073             master->slaves[x] = NULL;
04074          } else
04075             hasslaves = 1;
04076       }
04077       if (!hasslaves)
04078          master->inconference = 0;
04079    }
04080    if (!slave) {
04081       if (master->master) {
04082          /* Take master out of the conference */
04083          conf_del(master->master, &master->subs[SUB_REAL], SUB_REAL);
04084          conf_del(master, &master->master->subs[SUB_REAL], SUB_REAL);
04085          hasslaves = 0;
04086          for (x = 0; x < MAX_SLAVES; x++) {
04087             if (master->master->slaves[x] == master)
04088                master->master->slaves[x] = NULL;
04089             else if (master->master->slaves[x])
04090                hasslaves = 1;
04091          }
04092          if (!hasslaves)
04093             master->master->inconference = 0;
04094       }
04095       master->master = NULL;
04096    }
04097    update_conf(master);
04098    if (needlock) {
04099       if (slave)
04100          ast_mutex_unlock(&slave->lock);
04101       ast_mutex_unlock(&master->lock);
04102    }
04103 }
04104 
04105 static void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master) {
04106    int x;
04107    if (!slave || !master) {
04108       ast_log(LOG_WARNING, "Tried to link to/from NULL??\n");
04109       return;
04110    }
04111    for (x = 0; x < MAX_SLAVES; x++) {
04112       if (!master->slaves[x]) {
04113          master->slaves[x] = slave;
04114          break;
04115       }
04116    }
04117    if (x >= MAX_SLAVES) {
04118       ast_log(LOG_WARNING, "Replacing slave %d with new slave, %d\n", master->slaves[MAX_SLAVES - 1]->channel, slave->channel);
04119       master->slaves[MAX_SLAVES - 1] = slave;
04120    }
04121    if (slave->master) 
04122       ast_log(LOG_WARNING, "Replacing master %d with new master, %d\n", slave->master->channel, master->channel);
04123    slave->master = master;
04124    
04125    ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
04126 }
04127 
04128 static void disable_dtmf_detect(struct dahdi_pvt *p)
04129 {
04130    int val;
04131 
04132    p->ignoredtmf = 1;
04133 
04134    val = 0;
04135    ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
04136 
04137    if (!p->hardwaredtmf && p->dsp) {
04138       p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
04139       ast_dsp_set_features(p->dsp, p->dsp_features);
04140    }
04141 }
04142 
04143 static void enable_dtmf_detect(struct dahdi_pvt *p)
04144 {
04145    int val;
04146 
04147    if (p->channel == CHAN_PSEUDO)
04148       return;
04149 
04150    p->ignoredtmf = 0;
04151 
04152    val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
04153    ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
04154 
04155    if (!p->hardwaredtmf && p->dsp) {
04156       p->dsp_features |= DSP_FEATURE_DIGIT_DETECT;
04157       ast_dsp_set_features(p->dsp, p->dsp_features);
04158    }
04159 }
04160 
04161 static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
04162 {
04163    struct ast_channel *who;
04164    struct dahdi_pvt *p0, *p1, *op0, *op1;
04165    struct dahdi_pvt *master = NULL, *slave = NULL;
04166    struct ast_frame *f;
04167    int inconf = 0;
04168    int nothingok = 1;
04169    int ofd0, ofd1;
04170    int oi0, oi1, i0 = -1, i1 = -1, t0, t1;
04171    int os0 = -1, os1 = -1;
04172    int priority = 0;
04173    struct ast_channel *oc0, *oc1;
04174    enum ast_bridge_result res;
04175 
04176 #ifdef PRI_2BCT
04177    int triedtopribridge = 0;
04178    q931_call *q931c0 = NULL, *q931c1 = NULL;
04179 #endif
04180 
04181    /* For now, don't attempt to native bridge if either channel needs DTMF detection.
04182       There is code below to handle it properly until DTMF is actually seen,
04183       but due to currently unresolved issues it's ignored...
04184    */
04185 
04186    if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
04187       return AST_BRIDGE_FAILED_NOWARN;
04188 
04189    ast_channel_lock(c0);
04190    while (ast_channel_trylock(c1)) {
04191       CHANNEL_DEADLOCK_AVOIDANCE(c0);
04192    }
04193 
04194    p0 = c0->tech_pvt;
04195    p1 = c1->tech_pvt;
04196    /* cant do pseudo-channels here */
04197    if (!p0 || (!p0->sig) || !p1 || (!p1->sig)) {
04198       ast_channel_unlock(c0);
04199       ast_channel_unlock(c1);
04200       return AST_BRIDGE_FAILED_NOWARN;
04201    }
04202 
04203    oi0 = dahdi_get_index(c0, p0, 0);
04204    oi1 = dahdi_get_index(c1, p1, 0);
04205    if ((oi0 < 0) || (oi1 < 0)) {
04206       ast_channel_unlock(c0);
04207       ast_channel_unlock(c1);
04208       return AST_BRIDGE_FAILED;
04209    }
04210 
04211    op0 = p0 = c0->tech_pvt;
04212    op1 = p1 = c1->tech_pvt;
04213    ofd0 = c0->fds[0];
04214    ofd1 = c1->fds[0];
04215    oc0 = p0->owner;
04216    oc1 = p1->owner;
04217 
04218    if (ast_mutex_trylock(&p0->lock)) {
04219       /* Don't block, due to potential for deadlock */
04220       ast_channel_unlock(c0);
04221       ast_channel_unlock(c1);
04222       ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
04223       return AST_BRIDGE_RETRY;
04224    }
04225    if (ast_mutex_trylock(&p1->lock)) {
04226       /* Don't block, due to potential for deadlock */
04227       ast_mutex_unlock(&p0->lock);
04228       ast_channel_unlock(c0);
04229       ast_channel_unlock(c1);
04230       ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
04231       return AST_BRIDGE_RETRY;
04232    }
04233 
04234    if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
04235       if (p0->owner && p1->owner) {
04236          /* If we don't have a call-wait in a 3-way, and we aren't in a 3-way, we can be master */
04237          if (!p0->subs[SUB_CALLWAIT].inthreeway && !p1->subs[SUB_REAL].inthreeway) {
04238             master = p0;
04239             slave = p1;
04240             inconf = 1;
04241          } else if (!p1->subs[SUB_CALLWAIT].inthreeway && !p0->subs[SUB_REAL].inthreeway) {
04242             master = p1;
04243             slave = p0;
04244             inconf = 1;
04245          } else {
04246             ast_log(LOG_WARNING, "Huh?  Both calls are callwaits or 3-ways?  That's clever...?\n");
04247             ast_log(LOG_WARNING, "p0: chan %d/%d/CW%d/3W%d, p1: chan %d/%d/CW%d/3W%d\n",
04248                p0->channel,
04249                oi0, (p0->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
04250                p0->subs[SUB_REAL].inthreeway, p0->channel,
04251                oi0, (p1->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
04252                p1->subs[SUB_REAL].inthreeway);
04253          }
04254          nothingok = 0;
04255       }
04256    } else if ((oi0 == SUB_REAL) && (oi1 == SUB_THREEWAY)) {
04257       if (p1->subs[SUB_THREEWAY].inthreeway) {
04258          master = p1;
04259          slave = p0;
04260          nothingok = 0;
04261       }
04262    } else if ((oi0 == SUB_THREEWAY) && (oi1 == SUB_REAL)) {
04263       if (p0->subs[SUB_THREEWAY].inthreeway) {
04264          master = p0;
04265          slave = p1;
04266          nothingok = 0;
04267       }
04268    } else if ((oi0 == SUB_REAL) && (oi1 == SUB_CALLWAIT)) {
04269       /* We have a real and a call wait.  If we're in a three way call, put us in it, otherwise, 
04270          don't put us in anything */
04271       if (p1->subs[SUB_CALLWAIT].inthreeway) {
04272          master = p1;
04273          slave = p0;
04274          nothingok = 0;
04275       }
04276    } else if ((oi0 == SUB_CALLWAIT) && (oi1 == SUB_REAL)) {
04277       /* Same as previous */
04278       if (p0->subs[SUB_CALLWAIT].inthreeway) {
04279          master = p0;
04280          slave = p1;
04281          nothingok = 0;
04282       }
04283    }
04284    ast_debug(1, "master: %d, slave: %d, nothingok: %d\n",
04285       master ? master->channel : 0, slave ? slave->channel : 0, nothingok);
04286    if (master && slave) {
04287       /* Stop any tones, or play ringtone as appropriate.  If they're bridged
04288          in an active threeway call with a channel that is ringing, we should
04289          indicate ringing. */
04290       if ((oi1 == SUB_THREEWAY) && 
04291           p1->subs[SUB_THREEWAY].inthreeway && 
04292           p1->subs[SUB_REAL].owner && 
04293           p1->subs[SUB_REAL].inthreeway && 
04294           (p1->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
04295          ast_debug(1, "Playing ringback on %s since %s is in a ringing three-way\n", c0->name, c1->name);
04296          tone_zone_play_tone(p0->subs[oi0].dfd, DAHDI_TONE_RINGTONE);
04297          os1 = p1->subs[SUB_REAL].owner->_state;
04298       } else {
04299          ast_debug(1, "Stopping tones on %d/%d talking to %d/%d\n", p0->channel, oi0, p1->channel, oi1);
04300          tone_zone_play_tone(p0->subs[oi0].dfd, -1);
04301       }
04302       if ((oi0 == SUB_THREEWAY) && 
04303           p0->subs[SUB_THREEWAY].inthreeway && 
04304           p0->subs[SUB_REAL].owner && 
04305           p0->subs[SUB_REAL].inthreeway && 
04306           (p0->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
04307          ast_debug(1, "Playing ringback on %s since %s is in a ringing three-way\n", c1->name, c0->name);
04308          tone_zone_play_tone(p1->subs[oi1].dfd, DAHDI_TONE_RINGTONE);
04309          os0 = p0->subs[SUB_REAL].owner->_state;
04310       } else {
04311          ast_debug(1, "Stopping tones on %d/%d talking to %d/%d\n", p1->channel, oi1, p0->channel, oi0);
04312          tone_zone_play_tone(p1->subs[oi0].dfd, -1);
04313       }
04314       if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
04315          if (!p0->echocanbridged || !p1->echocanbridged) {
04316             /* Disable echo cancellation if appropriate */
04317             dahdi_disable_ec(p0);
04318             dahdi_disable_ec(p1);
04319          }
04320       }
04321       dahdi_link(slave, master);
04322       master->inconference = inconf;
04323    } else if (!nothingok)
04324       ast_log(LOG_WARNING, "Can't link %d/%s with %d/%s\n", p0->channel, subnames[oi0], p1->channel, subnames[oi1]);
04325 
04326    update_conf(p0);
04327    update_conf(p1);
04328    t0 = p0->subs[SUB_REAL].inthreeway;
04329    t1 = p1->subs[SUB_REAL].inthreeway;
04330 
04331    ast_mutex_unlock(&p0->lock);
04332    ast_mutex_unlock(&p1->lock);
04333 
04334    ast_channel_unlock(c0);
04335    ast_channel_unlock(c1);
04336 
04337    /* Native bridge failed */
04338    if ((!master || !slave) && !nothingok) {
04339       dahdi_enable_ec(p0);
04340       dahdi_enable_ec(p1);
04341       return AST_BRIDGE_FAILED;
04342    }
04343    
04344    ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);
04345 
04346    if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
04347       disable_dtmf_detect(op0);
04348 
04349    if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
04350       disable_dtmf_detect(op1);
04351 
04352    for (;;) {
04353       struct ast_channel *c0_priority[2] = {c0, c1};
04354       struct ast_channel *c1_priority[2] = {c1, c0};
04355 
04356       /* Here's our main loop...  Start by locking things, looking for private parts, 
04357          and then balking if anything is wrong */
04358       
04359       ast_channel_lock(c0);
04360       while (ast_channel_trylock(c1)) {
04361          CHANNEL_DEADLOCK_AVOIDANCE(c0);
04362       }
04363 
04364       p0 = c0->tech_pvt;
04365       p1 = c1->tech_pvt;
04366 
04367       if (op0 == p0)
04368          i0 = dahdi_get_index(c0, p0, 1);
04369       if (op1 == p1)
04370          i1 = dahdi_get_index(c1, p1, 1);
04371 
04372       ast_channel_unlock(c0);
04373       ast_channel_unlock(c1);
04374 
04375       if (!timeoutms || 
04376           (op0 != p0) ||
04377           (op1 != p1) || 
04378           (ofd0 != c0->fds[0]) || 
04379           (ofd1 != c1->fds[0]) ||
04380           (p0->subs[SUB_REAL].owner && (os0 > -1) && (os0 != p0->subs[SUB_REAL].owner->_state)) || 
04381           (p1->subs[SUB_REAL].owner && (os1 > -1) && (os1 != p1->subs[SUB_REAL].owner->_state)) || 
04382           (oc0 != p0->owner) || 
04383           (oc1 != p1->owner) ||
04384           (t0 != p0->subs[SUB_REAL].inthreeway) ||
04385           (t1 != p1->subs[SUB_REAL].inthreeway) ||
04386           (oi0 != i0) ||
04387           (oi1 != i1)) {
04388          ast_debug(1, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n",
04389             op0->channel, oi0, op1->channel, oi1);
04390          res = AST_BRIDGE_RETRY;
04391          goto return_from_bridge;
04392       }
04393 
04394 #ifdef PRI_2BCT
04395       q931c0 = p0->call;
04396       q931c1 = p1->call;
04397       if (p0->transfer && p1->transfer 
04398           && q931c0 && q931c1 
04399           && !triedtopribridge) {
04400          pri_channel_bridge(q931c0, q931c1);
04401          triedtopribridge = 1;
04402       }
04403 #endif
04404 
04405       who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &timeoutms);
04406       if (!who) {
04407          ast_debug(1, "Ooh, empty read...\n");
04408          continue;
04409       }
04410       f = ast_read(who);
04411       if (!f || (f->frametype == AST_FRAME_CONTROL)) {
04412          *fo = f;
04413          *rc = who;
04414          res = AST_BRIDGE_COMPLETE;
04415          goto return_from_bridge;
04416       }
04417       if (f->frametype == AST_FRAME_DTMF) {
04418          if ((who == c0) && p0->pulsedial) {
04419             ast_write(c1, f);
04420          } else if ((who == c1) && p1->pulsedial) {
04421             ast_write(c0, f);
04422          } else {
04423             *fo = f;
04424             *rc = who;
04425             res = AST_BRIDGE_COMPLETE;
04426             goto return_from_bridge;
04427          }
04428       }
04429       ast_frfree(f);
04430       
04431       /* Swap who gets priority */
04432       priority = !priority;
04433    }
04434 
04435 return_from_bridge:
04436    if (op0 == p0)
04437       dahdi_enable_ec(p0);
04438 
04439    if (op1 == p1)
04440       dahdi_enable_ec(p1);
04441 
04442    if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
04443       enable_dtmf_detect(op0);
04444 
04445    if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
04446       enable_dtmf_detect(op1);
04447 
04448    dahdi_unlink(slave, master, 1);
04449 
04450    return res;
04451 }
04452 
04453 static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
04454 {
04455    struct dahdi_pvt *p = newchan->tech_pvt;
04456    int x;
04457    ast_mutex_lock(&p->lock);
04458    ast_debug(1, "New owner for channel %d is %s\n", p->channel, newchan->name);
04459    if (p->owner == oldchan) {
04460       p->owner = newchan;
04461    }
04462    for (x = 0; x < 3; x++)
04463       if (p->subs[x].owner == oldchan) {
04464          if (!x)
04465             dahdi_unlink(NULL, p, 0);
04466          p->subs[x].owner = newchan;
04467       }
04468    if (newchan->_state == AST_STATE_RINGING) 
04469       dahdi_indicate(newchan, AST_CONTROL_RINGING, NULL, 0);
04470    update_conf(p);
04471    ast_mutex_unlock(&p->lock);
04472    return 0;
04473 }
04474 
04475 static int dahdi_ring_phone(struct dahdi_pvt *p)
04476 {
04477    int x;
04478    int res;
04479    /* Make sure our transmit state is on hook */
04480    x = 0;
04481    x = DAHDI_ONHOOK;
04482    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
04483    do {
04484       x = DAHDI_RING;
04485       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
04486       if (res) {
04487          switch (errno) {
04488          case EBUSY:
04489          case EINTR:
04490             /* Wait just in case */
04491             usleep(10000);
04492             continue;
04493          case EINPROGRESS:
04494             res = 0;
04495             break;
04496          default:
04497             ast_log(LOG_WARNING, "Couldn't ring the phone: %s\n", strerror(errno));
04498             res = 0;
04499          }
04500       }
04501    } while (res);
04502    return res;
04503 }
04504 
04505 static void *ss_thread(void *data);
04506 
04507 static struct ast_channel *dahdi_new(struct dahdi_pvt *, int, int, int, int, int);
04508 
04509 static int attempt_transfer(struct dahdi_pvt *p)
04510 {
04511    /* In order to transfer, we need at least one of the channels to
04512       actually be in a call bridge.  We can't conference two applications
04513       together (but then, why would we want to?) */
04514    if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
04515       /* The three-way person we're about to transfer to could still be in MOH, so
04516          stop if now if appropriate */
04517       if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner))
04518          ast_queue_control(p->subs[SUB_THREEWAY].owner, AST_CONTROL_UNHOLD);
04519       if (p->subs[SUB_REAL].owner->_state == AST_STATE_RINGING) {
04520          ast_indicate(ast_bridged_channel(p->subs[SUB_REAL].owner), AST_CONTROL_RINGING);
04521       }
04522       if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RING) {
04523          tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
04524       }
04525        if (ast_channel_masquerade(p->subs[SUB_THREEWAY].owner, ast_bridged_channel(p->subs[SUB_REAL].owner))) {
04526          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
04527                ast_bridged_channel(p->subs[SUB_REAL].owner)->name, p->subs[SUB_THREEWAY].owner->name);
04528          return -1;
04529       }
04530       /* Orphan the channel after releasing the lock */
04531       ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04532       unalloc_sub(p, SUB_THREEWAY);
04533    } else if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
04534       ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
04535       if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RINGING) {
04536          ast_indicate(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), AST_CONTROL_RINGING);
04537       }
04538       if (p->subs[SUB_REAL].owner->_state == AST_STATE_RING) {
04539          tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
04540       }
04541       if (ast_channel_masquerade(p->subs[SUB_REAL].owner, ast_bridged_channel(p->subs[SUB_THREEWAY].owner))) {
04542          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
04543                ast_bridged_channel(p->subs[SUB_THREEWAY].owner)->name, p->subs[SUB_REAL].owner->name);
04544          return -1;
04545       }
04546       /* Three-way is now the REAL */
04547       swap_subs(p, SUB_THREEWAY, SUB_REAL);
04548       ast_channel_unlock(p->subs[SUB_REAL].owner);
04549       unalloc_sub(p, SUB_THREEWAY);
04550       /* Tell the caller not to hangup */
04551       return 1;
04552    } else {
04553       ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
04554          p->subs[SUB_REAL].owner->name, p->subs[SUB_THREEWAY].owner->name);
04555       p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
04556       return -1;
04557    }
04558    return 0;
04559 }
04560 
04561 static int check_for_conference(struct dahdi_pvt *p)
04562 {
04563    struct dahdi_confinfo ci;
04564    /* Fine if we already have a master, etc */
04565    if (p->master || (p->confno > -1))
04566       return 0;
04567    memset(&ci, 0, sizeof(ci));
04568    if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
04569       ast_log(LOG_WARNING, "Failed to get conference info on channel %d: %s\n", p->channel, strerror(errno));
04570       return 0;
04571    }
04572    /* If we have no master and don't have a confno, then 
04573       if we're in a conference, it's probably a MeetMe room or
04574       some such, so don't let us 3-way out! */
04575    if ((p->subs[SUB_REAL].curconf.confno != ci.confno) || (p->subs[SUB_REAL].curconf.confmode != ci.confmode)) {
04576       ast_verb(3, "Avoiding 3-way call when in an external conference\n");
04577       return 1;
04578    }
04579    return 0;
04580 }
04581 
04582 /*! Checks channel for alarms
04583  * \param p a channel to check for alarms.
04584  * \returns the alarms on the span to which the channel belongs, or alarms on
04585  *          the channel if no span alarms.
04586  */
04587 static int get_alarms(struct dahdi_pvt *p)
04588 {
04589    int res;
04590    struct dahdi_spaninfo zi;
04591    struct dahdi_params params;
04592 
04593    memset(&zi, 0, sizeof(zi));
04594    zi.spanno = p->span;
04595 
04596    if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SPANSTAT, &zi)) >= 0) {
04597       if (zi.alarms != DAHDI_ALARM_NONE)
04598          return zi.alarms;
04599    } else {
04600       ast_log(LOG_WARNING, "Unable to determine alarm on channel %d: %s\n", p->channel, strerror(errno));
04601       return 0;
04602    }
04603 
04604    /* No alarms on the span. Check for channel alarms. */
04605    memset(&params, 0, sizeof(params));
04606    if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &params)) >= 0)
04607       return params.chan_alarms;
04608 
04609    ast_log(LOG_WARNING, "Unable to determine alarm on channel %d\n", p->channel);
04610 
04611    return DAHDI_ALARM_NONE;
04612 }
04613 
04614 static void dahdi_handle_dtmfup(struct ast_channel *ast, int idx, struct ast_frame **dest)
04615 {
04616    struct dahdi_pvt *p = ast->tech_pvt;
04617    struct ast_frame *f = *dest;
04618 
04619    ast_debug(1, "DTMF digit: %c on %s\n", f->subclass, ast->name);
04620 
04621    if (p->confirmanswer) {
04622       ast_debug(1, "Confirm answer on %s!\n", ast->name);
04623       /* Upon receiving a DTMF digit, consider this an answer confirmation instead
04624          of a DTMF digit */
04625       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04626       p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
04627       *dest = &p->subs[idx].f;
04628       /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
04629       p->confirmanswer = 0;
04630    } else if (p->callwaitcas) {
04631       if ((f->subclass == 'A') || (f->subclass == 'D')) {
04632          ast_debug(1, "Got some DTMF, but it's for the CAS\n");
04633          if (p->cidspill)
04634             ast_free(p->cidspill);
04635          send_cwcidspill(p);
04636       }
04637       p->callwaitcas = 0;
04638       p->subs[idx].f.frametype = AST_FRAME_NULL;
04639       p->subs[idx].f.subclass = 0;
04640       *dest = &p->subs[idx].f;
04641    } else if (f->subclass == 'f') {
04642       /* Fax tone -- Handle and return NULL */
04643       if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
04644          p->faxhandled = 1;
04645          if (strcmp(ast->exten, "fax")) {
04646             const char *target_context = S_OR(ast->macrocontext, ast->context);
04647 
04648             /* We need to unlock 'ast' here because ast_exists_extension has the
04649              * potential to start autoservice on the channel. Such action is prone
04650              * to deadlock.
04651              */
04652             ast_mutex_unlock(&p->lock);
04653             ast_channel_unlock(ast);
04654             if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
04655                ast_channel_lock(ast);
04656                ast_mutex_lock(&p->lock);
04657                ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
04658                /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
04659                pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
04660                if (ast_async_goto(ast, target_context, "fax", 1))
04661                   ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
04662             } else {
04663                ast_channel_lock(ast);
04664                ast_mutex_lock(&p->lock);
04665                ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
04666             }
04667          } else {
04668             ast_debug(1, "Already in a fax extension, not redirecting\n");
04669          }
04670       } else {
04671          ast_debug(1, "Fax already handled\n");
04672       }
04673       dahdi_confmute(p, 0);
04674       p->subs[idx].f.frametype = AST_FRAME_NULL;
04675       p->subs[idx].f.subclass = 0;
04676       *dest = &p->subs[idx].f;
04677    }
04678 }
04679          
04680 static void handle_alarms(struct dahdi_pvt *p, int alms)
04681 {
04682    const char *alarm_str = alarm2str(alms);
04683 
04684    ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
04685    manager_event(EVENT_FLAG_SYSTEM, "Alarm",
04686             "Alarm: %s\r\n"
04687             "Channel: %d\r\n",
04688             alarm_str, p->channel);
04689 }
04690 
04691 static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
04692 {
04693    int res, x;
04694    int idx, mysig;
04695    char *c;
04696    struct dahdi_pvt *p = ast->tech_pvt;
04697    pthread_t threadid;
04698    struct ast_channel *chan;
04699    struct ast_frame *f;
04700 
04701    idx = dahdi_get_index(ast, p, 0);
04702    mysig = p->sig;
04703    if (p->outsigmod > -1)
04704       mysig = p->outsigmod;
04705    p->subs[idx].f.frametype = AST_FRAME_NULL;
04706    p->subs[idx].f.subclass = 0;
04707    p->subs[idx].f.datalen = 0;
04708    p->subs[idx].f.samples = 0;
04709    p->subs[idx].f.mallocd = 0;
04710    p->subs[idx].f.offset = 0;
04711    p->subs[idx].f.src = "dahdi_handle_event";
04712    p->subs[idx].f.data.ptr = NULL;
04713    f = &p->subs[idx].f;
04714 
04715    if (idx < 0)
04716       return &p->subs[idx].f;
04717    if (p->fake_event) {
04718       res = p->fake_event;
04719       p->fake_event = 0;
04720    } else
04721       res = dahdi_get_event(p->subs[idx].dfd);
04722 
04723    ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, idx);
04724 
04725    if (res & (DAHDI_EVENT_PULSEDIGIT | DAHDI_EVENT_DTMFUP)) {
04726       p->pulsedial =  (res & DAHDI_EVENT_PULSEDIGIT) ? 1 : 0;
04727       ast_debug(1, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
04728 #ifdef HAVE_PRI
04729       if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
04730          /* absorb event */
04731       } else {
04732 #endif
04733          p->subs[idx].f.frametype = AST_FRAME_DTMF_END;
04734          p->subs[idx].f.subclass = res & 0xff;
04735 #ifdef HAVE_PRI
04736       }
04737 #endif
04738       dahdi_handle_dtmfup(ast, idx, &f);
04739       return f;
04740    }
04741 
04742    if (res & DAHDI_EVENT_DTMFDOWN) {
04743       ast_debug(1, "DTMF Down '%c'\n", res & 0xff);
04744       /* Mute conference */
04745       dahdi_confmute(p, 1);
04746       p->subs[idx].f.frametype = AST_FRAME_DTMF_BEGIN;
04747       p->subs[idx].f.subclass = res & 0xff;
04748       return &p->subs[idx].f;
04749    }
04750 
04751    switch (res) {
04752       case DAHDI_EVENT_EC_DISABLED:
04753          ast_verb(3, "Channel %d echo canceler disabled due to CED detection\n", p->channel);
04754          p->echocanon = 0;
04755          break;
04756       case DAHDI_EVENT_BITSCHANGED:
04757          ast_log(LOG_WARNING, "Recieved bits changed on %s signalling?\n", sig2str(p->sig));
04758       case DAHDI_EVENT_PULSE_START:
04759          /* Stop tone if there's a pulse start and the PBX isn't started */
04760          if (!ast->pbx)
04761             tone_zone_play_tone(p->subs[idx].dfd, -1);
04762          break;   
04763       case DAHDI_EVENT_DIALCOMPLETE:
04764          if (p->inalarm) break;
04765          if ((p->radio || (p->oprmode < 0))) break;
04766          if (ioctl(p->subs[idx].dfd,DAHDI_DIALING,&x) == -1) {
04767             ast_log(LOG_DEBUG, "DAHDI_DIALING ioctl failed on %s: %s\n",ast->name, strerror(errno));
04768             return NULL;
04769          }
04770          if (!x) { /* if not still dialing in driver */
04771             dahdi_enable_ec(p);
04772             if (p->echobreak) {
04773                dahdi_train_ec(p);
04774                ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
04775                p->dop.op = DAHDI_DIAL_OP_REPLACE;
04776                res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
04777                p->echobreak = 0;
04778             } else {
04779                p->dialing = 0;
04780                if ((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) {
04781                   /* if thru with dialing after offhook */
04782                   if (ast->_state == AST_STATE_DIALING_OFFHOOK) {
04783                      ast_setstate(ast, AST_STATE_UP);
04784                      p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04785                      p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
04786                      break;
04787                   } else { /* if to state wait for offhook to dial rest */
04788                      /* we now wait for off hook */
04789                      ast_setstate(ast,AST_STATE_DIALING_OFFHOOK);
04790                   }
04791                }
04792                if (ast->_state == AST_STATE_DIALING) {
04793                   if ((p->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
04794                      ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n");
04795                   } else if (p->confirmanswer || (!p->dialednone && ((mysig == SIG_EM) || (mysig == SIG_EM_E1) ||  (mysig == SIG_EMWINK) || (mysig == SIG_FEATD) || (mysig == SIG_FEATDMF_TA) || (mysig == SIG_FEATDMF) || (mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF) || (mysig == SIG_FEATB) || (mysig == SIG_SF) || (mysig == SIG_SFWINK) || (mysig == SIG_SF_FEATD) || (mysig == SIG_SF_FEATDMF) || (mysig == SIG_SF_FEATB)))) {
04796                      ast_setstate(ast, AST_STATE_RINGING);
04797                   } else if (!p->answeronpolarityswitch) {
04798                      ast_setstate(ast, AST_STATE_UP);
04799                      p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04800                      p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
04801                      /* If aops=0 and hops=1, this is necessary */
04802                      p->polarity = POLARITY_REV;
04803                   } else {
04804                      /* Start clean, so we can catch the change to REV polarity when party answers */
04805                      p->polarity = POLARITY_IDLE;
04806                   }
04807                }
04808             }
04809          }
04810          break;
04811       case DAHDI_EVENT_ALARM:
04812 #ifdef HAVE_PRI
04813          if ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
04814             if (!p->pri || !p->pri->pri || (pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0)) {
04815                /* T309 is not enabled : hangup calls when alarm occurs */
04816                if (p->call) {
04817                   if (p->pri && p->pri->pri) {
04818                      if (!pri_grab(p, p->pri)) {
04819                         pri_hangup(p->pri->pri, p->call, -1);
04820                         pri_destroycall(p->pri->pri, p->call);
04821                         p->call = NULL;
04822                         pri_rel(p->pri);
04823                      } else
04824                         ast_log(LOG_WARNING, "Failed to grab PRI!\n");
04825                   } else
04826                      ast_log(LOG_WARNING, "The PRI Call has not been destroyed\n");
04827                }
04828                if (p->owner)
04829                   p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
04830             }
04831          }
04832          if (p->bearer)
04833             p->bearer->inalarm = 1;
04834          else
04835 #endif
04836          p->inalarm = 1;
04837          res = get_alarms(p);
04838          handle_alarms(p, res);
04839 #ifdef HAVE_PRI
04840          if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
04841             /* fall through intentionally */
04842          } else {
04843             break;
04844          }
04845 #endif
04846 #ifdef HAVE_SS7
04847          if (p->sig == SIG_SS7)
04848             break;
04849 #endif
04850       case DAHDI_EVENT_ONHOOK:
04851          if (p->radio) {
04852             p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04853             p->subs[idx].f.subclass = AST_CONTROL_RADIO_UNKEY;
04854             break;
04855          }
04856          if (p->oprmode < 0)
04857          {
04858             if (p->oprmode != -1) break;
04859             if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
04860             {
04861                /* Make sure it starts ringing */
04862                dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
04863                dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RING);
04864                save_conference(p->oprpeer);
04865                tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
04866             }
04867             break;
04868          }
04869          switch (p->sig) {
04870          case SIG_FXOLS:
04871          case SIG_FXOGS:
04872          case SIG_FXOKS:
04873             p->onhooktime = time(NULL);
04874             p->msgstate = -1;
04875             /* Check for some special conditions regarding call waiting */
04876             if (idx == SUB_REAL) {
04877                /* The normal line was hung up */
04878                if (p->subs[SUB_CALLWAIT].owner) {
04879                   /* There's a call waiting call, so ring the phone, but make it unowned in the mean time */
04880                   swap_subs(p, SUB_CALLWAIT, SUB_REAL);
04881                   ast_verb(3, "Channel %d still has (callwait) call, ringing phone\n", p->channel);
04882                   unalloc_sub(p, SUB_CALLWAIT); 
04883 #if 0
04884                   p->subs[idx].needanswer = 0;
04885                   p->subs[idx].needringing = 0;
04886 #endif                  
04887                   p->callwaitingrepeat = 0;
04888                   p->cidcwexpire = 0;
04889                   p->owner = NULL;
04890                   /* Don't start streaming audio yet if the incoming call isn't up yet */
04891                   if (p->subs[SUB_REAL].owner->_state != AST_STATE_UP)
04892                      p->dialing = 1;
04893                   dahdi_ring_phone(p);
04894                } else if (p->subs[SUB_THREEWAY].owner) {
04895                   unsigned int mssinceflash;
04896                   /* Here we have to retain the lock on both the main channel, the 3-way channel, and
04897                      the private structure -- not especially easy or clean */
04898                   while (p->subs[SUB_THREEWAY].owner && ast_channel_trylock(p->subs[SUB_THREEWAY].owner)) {
04899                      /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
04900                      DLA_UNLOCK(&p->lock);
04901                      CHANNEL_DEADLOCK_AVOIDANCE(ast);
04902                      /* We can grab ast and p in that order, without worry.  We should make sure
04903                         nothing seriously bad has happened though like some sort of bizarre double
04904                         masquerade! */
04905                      DLA_LOCK(&p->lock);
04906                      if (p->owner != ast) {
04907                         ast_log(LOG_WARNING, "This isn't good...\n");
04908                         return NULL;
04909                      }
04910                   }
04911                   if (!p->subs[SUB_THREEWAY].owner) {
04912                      ast_log(LOG_NOTICE, "Whoa, threeway disappeared kinda randomly.\n");
04913                      return NULL;
04914                   }
04915                   mssinceflash = ast_tvdiff_ms(ast_tvnow(), p->flashtime);
04916                   ast_debug(1, "Last flash was %d ms ago\n", mssinceflash);
04917                   if (mssinceflash < MIN_MS_SINCE_FLASH) {
04918                      /* It hasn't been long enough since the last flashook.  This is probably a bounce on 
04919                         hanging up.  Hangup both channels now */
04920                      if (p->subs[SUB_THREEWAY].owner)
04921                         ast_queue_hangup_with_cause(p->subs[SUB_THREEWAY].owner, AST_CAUSE_NO_ANSWER);
04922                      p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
04923                      ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
04924                      ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04925                   } else if ((ast->pbx) || (ast->_state == AST_STATE_UP)) {
04926                      if (p->transfer) {
04927                         /* In any case this isn't a threeway call anymore */
04928                         p->subs[SUB_REAL].inthreeway = 0;
04929                         p->subs[SUB_THREEWAY].inthreeway = 0;
04930                         /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
04931                         if (!p->transfertobusy && ast->_state == AST_STATE_BUSY) {
04932                            ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04933                            /* Swap subs and dis-own channel */
04934                            swap_subs(p, SUB_THREEWAY, SUB_REAL);
04935                            p->owner = NULL;
04936                            /* Ring the phone */
04937                            dahdi_ring_phone(p);
04938                         } else {
04939                            if ((res = attempt_transfer(p)) < 0) {
04940                               p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
04941                               if (p->subs[SUB_THREEWAY].owner)
04942                                  ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04943                            } else if (res) {
04944                               /* Don't actually hang up at this point */
04945                               if (p->subs[SUB_THREEWAY].owner)
04946                                  ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04947                               break;
04948                            }
04949                         }
04950                      } else {
04951                         p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
04952                         if (p->subs[SUB_THREEWAY].owner)
04953                            ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04954                      }
04955                   } else {
04956                      ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04957                      /* Swap subs and dis-own channel */
04958                      swap_subs(p, SUB_THREEWAY, SUB_REAL);
04959                      p->owner = NULL;
04960                      /* Ring the phone */
04961                      dahdi_ring_phone(p);
04962                   }
04963                }
04964             } else {
04965                ast_log(LOG_WARNING, "Got a hangup and my index is %d?\n", idx);
04966             }
04967             /* Fall through */
04968          default:
04969             dahdi_disable_ec(p);
04970             return NULL;
04971          }
04972          break;
04973       case DAHDI_EVENT_RINGOFFHOOK:
04974          if (p->inalarm) break;
04975          if (p->oprmode < 0)
04976          {
04977             if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
04978             {
04979                /* Make sure it stops ringing */
04980                dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
04981                tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, -1);
04982                restore_conference(p->oprpeer);
04983             }
04984             break;
04985          }
04986          if (p->radio)
04987          {
04988             p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04989             p->subs[idx].f.subclass = AST_CONTROL_RADIO_KEY;
04990             break;
04991          }
04992          /* for E911, its supposed to wait for offhook then dial
04993             the second half of the dial string */
04994          if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast->_state == AST_STATE_DIALING_OFFHOOK)) {
04995             c = strchr(p->dialdest, '/');
04996             if (c)
04997                c++;
04998             else
04999                c = p->dialdest;
05000             if (*c) snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
05001             else ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
05002             if (strlen(p->dop.dialstr) > 4) {
05003                memset(p->echorest, 'w', sizeof(p->echorest) - 1);
05004                strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
05005                p->echorest[sizeof(p->echorest) - 1] = '\0';
05006                p->echobreak = 1;
05007                p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
05008             } else
05009                p->echobreak = 0;
05010             if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
05011                int saveerr = errno;
05012 
05013                x = DAHDI_ONHOOK;
05014                ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
05015                ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
05016                return NULL;
05017                }
05018             p->dialing = 1;
05019             return &p->subs[idx].f;
05020          }
05021          switch (p->sig) {
05022          case SIG_FXOLS:
05023          case SIG_FXOGS:
05024          case SIG_FXOKS:
05025             switch (ast->_state) {
05026             case AST_STATE_RINGING:
05027                dahdi_enable_ec(p);
05028                dahdi_train_ec(p);
05029                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05030                p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
05031                /* Make sure it stops ringing */
05032                dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
05033                ast_debug(1, "channel %d answered\n", p->channel);
05034                if (p->cidspill) {
05035                   /* Cancel any running CallerID spill */
05036                   ast_free(p->cidspill);
05037                   p->cidspill = NULL;
05038                }
05039                p->dialing = 0;
05040                p->callwaitcas = 0;
05041                if (p->confirmanswer) {
05042                   /* Ignore answer if "confirm answer" is enabled */
05043                   p->subs[idx].f.frametype = AST_FRAME_NULL;
05044                   p->subs[idx].f.subclass = 0;
05045                } else if (!ast_strlen_zero(p->dop.dialstr)) {
05046                   /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
05047                   res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
05048                   if (res < 0) {
05049                      ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
05050                      p->dop.dialstr[0] = '\0';
05051                      return NULL;
05052                   } else {
05053                      ast_debug(1, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
05054                      p->subs[idx].f.frametype = AST_FRAME_NULL;
05055                      p->subs[idx].f.subclass = 0;
05056                      p->dialing = 1;
05057                   }
05058                   p->dop.dialstr[0] = '\0';
05059                   ast_setstate(ast, AST_STATE_DIALING);
05060                } else
05061                   ast_setstate(ast, AST_STATE_UP);
05062                return &p->subs[idx].f;
05063             case AST_STATE_DOWN:
05064                ast_setstate(ast, AST_STATE_RING);
05065                ast->rings = 1;
05066                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05067                p->subs[idx].f.subclass = AST_CONTROL_OFFHOOK;
05068                ast_debug(1, "channel %d picked up\n", p->channel);
05069                return &p->subs[idx].f;
05070             case AST_STATE_UP:
05071                /* Make sure it stops ringing */
05072                dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
05073                /* Okay -- probably call waiting*/
05074                if (ast_bridged_channel(p->owner))
05075                   ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
05076                p->subs[idx].needunhold = 1;
05077                break;
05078             case AST_STATE_RESERVED:
05079                /* Start up dialtone */
05080                if (has_voicemail(p))
05081                   res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
05082                else
05083                   res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
05084                break;
05085             default:
05086                ast_log(LOG_WARNING, "FXO phone off hook in weird state %d??\n", ast->_state);
05087             }
05088             break;
05089          case SIG_FXSLS:
05090          case SIG_FXSGS:
05091          case SIG_FXSKS:
05092             if (ast->_state == AST_STATE_RING) {
05093                p->ringt = p->ringt_base;
05094             }
05095 
05096             /* If we get a ring then we cannot be in 
05097              * reversed polarity. So we reset to idle */
05098             ast_debug(1, "Setting IDLE polarity due "
05099                "to ring. Old polarity was %d\n", 
05100                p->polarity);
05101             p->polarity = POLARITY_IDLE;
05102 
05103             /* Fall through */
05104          case SIG_EM:
05105          case SIG_EM_E1:
05106          case SIG_EMWINK:
05107          case SIG_FEATD:
05108          case SIG_FEATDMF:
05109          case SIG_FEATDMF_TA:
05110          case SIG_E911:
05111          case SIG_FGC_CAMA:
05112          case SIG_FGC_CAMAMF:
05113          case SIG_FEATB:
05114          case SIG_SF:
05115          case SIG_SFWINK:
05116          case SIG_SF_FEATD:
05117          case SIG_SF_FEATDMF:
05118          case SIG_SF_FEATB:
05119             if (ast->_state == AST_STATE_PRERING)
05120                ast_setstate(ast, AST_STATE_RING);
05121             if ((ast->_state == AST_STATE_DOWN) || (ast->_state == AST_STATE_RING)) {
05122                ast_debug(1, "Ring detected\n");
05123                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05124                p->subs[idx].f.subclass = AST_CONTROL_RING;
05125             } else if (p->outgoing && ((ast->_state == AST_STATE_RINGING) || (ast->_state == AST_STATE_DIALING))) {
05126                ast_debug(1, "Line answered\n");
05127                if (p->confirmanswer) {
05128                   p->subs[idx].f.frametype = AST_FRAME_NULL;
05129                   p->subs[idx].f.subclass = 0;
05130                } else {
05131                   p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05132                   p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
05133                   ast_setstate(ast, AST_STATE_UP);
05134                }
05135             } else if (ast->_state != AST_STATE_RING)
05136                ast_log(LOG_WARNING, "Ring/Off-hook in strange state %d on channel %d\n", ast->_state, p->channel);
05137             break;
05138          default:
05139             ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
05140          }
05141          break;
05142       case DAHDI_EVENT_RINGBEGIN:
05143          switch (p->sig) {
05144          case SIG_FXSLS:
05145          case SIG_FXSGS:
05146          case SIG_FXSKS:
05147             if (ast->_state == AST_STATE_RING) {
05148                p->ringt = p->ringt_base;
05149             }
05150             break;
05151          }
05152          break;
05153       case DAHDI_EVENT_RINGEROFF:
05154          if (p->inalarm) break;
05155          if ((p->radio || (p->oprmode < 0))) break;
05156          ast->rings++;
05157          if ((ast->rings > p->cidrings) && (p->cidspill)) {
05158             ast_log(LOG_WARNING, "Didn't finish Caller-ID spill.  Cancelling.\n");
05159             ast_free(p->cidspill);
05160             p->cidspill = NULL;
05161             p->callwaitcas = 0;
05162          }
05163          p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05164          p->subs[idx].f.subclass = AST_CONTROL_RINGING;
05165          break;
05166       case DAHDI_EVENT_RINGERON:
05167          break;
05168       case DAHDI_EVENT_NOALARM:
05169          p->inalarm = 0;
05170 #ifdef HAVE_PRI
05171          /* Extremely unlikely but just in case */
05172          if (p->bearer)
05173             p->bearer->inalarm = 0;
05174 #endif            
05175          ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
05176          manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
05177                         "Channel: %d\r\n", p->channel);
05178          break;
05179       case DAHDI_EVENT_WINKFLASH:
05180          if (p->inalarm) break;
05181          if (p->radio) break;
05182          if (p->oprmode < 0) break;
05183          if (p->oprmode > 1)
05184          {
05185             struct dahdi_params par;
05186 
05187             memset(&par, 0, sizeof(par));
05188             if (ioctl(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par) != -1)
05189             {
05190                if (!par.rxisoffhook)
05191                {
05192                   /* Make sure it stops ringing */
05193                   dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
05194                   dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RING);
05195                   save_conference(p);
05196                   tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
05197                }
05198             }
05199             break;
05200          }
05201          /* Remember last time we got a flash-hook */
05202          p->flashtime = ast_tvnow();
05203          switch (mysig) {
05204          case SIG_FXOLS:
05205          case SIG_FXOGS:
05206          case SIG_FXOKS:
05207             ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
05208                idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
05209             p->callwaitcas = 0;
05210 
05211             if (idx != SUB_REAL) {
05212                ast_log(LOG_WARNING, "Got flash hook with index %d on channel %d?!?\n", idx, p->channel);
05213                goto winkflashdone;
05214             }
05215             
05216             if (p->subs[SUB_CALLWAIT].owner) {
05217                /* Swap to call-wait */
05218                swap_subs(p, SUB_REAL, SUB_CALLWAIT);
05219                tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
05220                p->owner = p->subs[SUB_REAL].owner;
05221                ast_debug(1, "Making %s the new owner\n", p->owner->name);
05222                if (p->owner->_state == AST_STATE_RINGING) {
05223                   ast_setstate(p->owner, AST_STATE_UP);
05224                   p->subs[SUB_REAL].needanswer = 1;
05225                }
05226                p->callwaitingrepeat = 0;
05227                p->cidcwexpire = 0;
05228                /* Start music on hold if appropriate */
05229                if (!p->subs[SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
05230                   ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
05231                      S_OR(p->mohsuggest, NULL),
05232                      !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
05233                }
05234                p->subs[SUB_CALLWAIT].needhold = 1;
05235                if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
05236                   ast_queue_control_data(p->subs[SUB_REAL].owner, AST_CONTROL_HOLD,
05237                      S_OR(p->mohsuggest, NULL),
05238                      !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
05239                }
05240                p->subs[SUB_REAL].needunhold = 1;
05241             } else if (!p->subs[SUB_THREEWAY].owner) {
05242                if (!p->threewaycalling) {
05243                   /* Just send a flash if no 3-way calling */
05244                   p->subs[SUB_REAL].needflash = 1;
05245                   goto winkflashdone;
05246                } else if (!check_for_conference(p)) {
05247                   char cid_num[256];
05248                   char cid_name[256];
05249 
05250                   cid_num[0] = 0;
05251                   cid_name[0] = 0;
05252                   if (p->dahditrcallerid && p->owner) {
05253                      if (p->owner->cid.cid_num)
05254                         ast_copy_string(cid_num, p->owner->cid.cid_num, sizeof(cid_num));
05255                      if (p->owner->cid.cid_name)
05256                         ast_copy_string(cid_name, p->owner->cid.cid_name, sizeof(cid_name));
05257                   }
05258                   /* XXX This section needs much more error checking!!! XXX */
05259                   /* Start a 3-way call if feasible */
05260                   if (!((ast->pbx) ||
05261                         (ast->_state == AST_STATE_UP) ||
05262                         (ast->_state == AST_STATE_RING))) {
05263                      ast_debug(1, "Flash when call not up or ringing\n");
05264                      goto winkflashdone;
05265                   }
05266                   if (alloc_sub(p, SUB_THREEWAY)) {
05267                      ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
05268                      goto winkflashdone;
05269                   }
05270                   /* Make new channel */
05271                   chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, 0);
05272                   if (p->dahditrcallerid) {
05273                      if (!p->origcid_num)
05274                         p->origcid_num = ast_strdup(p->cid_num);
05275                      if (!p->origcid_name)
05276                         p->origcid_name = ast_strdup(p->cid_name);
05277                      ast_copy_string(p->cid_num, cid_num, sizeof(p->cid_num));
05278                      ast_copy_string(p->cid_name, cid_name, sizeof(p->cid_name));
05279                   }
05280                   /* Swap things around between the three-way and real call */
05281                   swap_subs(p, SUB_THREEWAY, SUB_REAL);
05282                   /* Disable echo canceller for better dialing */
05283                   dahdi_disable_ec(p);
05284                   res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
05285                   if (res)
05286                      ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
05287                   p->owner = chan;
05288                   if (!chan) {
05289                      ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", p->channel);
05290                   } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
05291                      ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
05292                      res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
05293                      dahdi_enable_ec(p);
05294                      ast_hangup(chan);
05295                   } else {
05296                      struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner);
05297                      int way3bridge = 0, cdr3way = 0;
05298                      
05299                      if (!other) {
05300                         other = ast_bridged_channel(p->subs[SUB_REAL].owner);
05301                      } else
05302                         way3bridge = 1;
05303                      
05304                      if (p->subs[SUB_THREEWAY].owner->cdr)
05305                         cdr3way = 1;
05306                      
05307                      ast_verb(3, "Started three way call on channel %d\n", p->channel);
05308 
05309                      /* Start music on hold if appropriate */
05310                      if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
05311                         ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
05312                            S_OR(p->mohsuggest, NULL),
05313                            !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
05314                      }
05315                      p->subs[SUB_THREEWAY].needhold = 1;
05316                   }
05317                }
05318             } else {
05319                /* Already have a 3 way call */
05320                if (p->subs[SUB_THREEWAY].inthreeway) {
05321                   /* Call is already up, drop the last person */
05322                   ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
05323                   /* If the primary call isn't answered yet, use it */
05324                   if ((p->subs[SUB_REAL].owner->_state != AST_STATE_UP) && (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_UP)) {
05325                      /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
05326                      swap_subs(p, SUB_THREEWAY, SUB_REAL);
05327                      p->owner = p->subs[SUB_REAL].owner;
05328                   }
05329                   /* Drop the last call and stop the conference */
05330                   ast_verb(3, "Dropping three-way call on %s\n", p->subs[SUB_THREEWAY].owner->name);
05331                   p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
05332                   p->subs[SUB_REAL].inthreeway = 0;
05333                   p->subs[SUB_THREEWAY].inthreeway = 0;
05334                } else {
05335                   /* Lets see what we're up to */
05336                   if (((ast->pbx) || (ast->_state == AST_STATE_UP)) && 
05337                       (p->transfertobusy || (ast->_state != AST_STATE_BUSY))) {
05338                      int otherindex = SUB_THREEWAY;
05339                      struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner);
05340                      int way3bridge = 0, cdr3way = 0;
05341                      
05342                      if (!other) {
05343                         other = ast_bridged_channel(p->subs[SUB_REAL].owner);
05344                      } else
05345                         way3bridge = 1;
05346                      
05347                      if (p->subs[SUB_THREEWAY].owner->cdr)
05348                         cdr3way = 1;
05349 
05350                      ast_verb(3, "Building conference on call on %s and %s\n", p->subs[SUB_THREEWAY].owner->name, p->subs[SUB_REAL].owner->name);
05351                      /* Put them in the threeway, and flip */
05352                      p->subs[SUB_THREEWAY].inthreeway = 1;
05353                      p->subs[SUB_REAL].inthreeway = 1;
05354                      if (ast->_state == AST_STATE_UP) {
05355                         swap_subs(p, SUB_THREEWAY, SUB_REAL);
05356                         otherindex = SUB_REAL;
05357                      }
05358                      if (p->subs[otherindex].owner && ast_bridged_channel(p->subs[otherindex].owner))
05359                         ast_queue_control(p->subs[otherindex].owner, AST_CONTROL_UNHOLD);
05360                      p->subs[otherindex].needunhold = 1;
05361                      p->owner = p->subs[SUB_REAL].owner;
05362                      if (ast->_state == AST_STATE_RINGING) {
05363                         ast_debug(1, "Enabling ringtone on real and threeway\n");
05364                         res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
05365                         res = tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
05366                      }
05367                   } else {
05368                      ast_verb(3, "Dumping incomplete call on on %s\n", p->subs[SUB_THREEWAY].owner->name);
05369                      swap_subs(p, SUB_THREEWAY, SUB_REAL);
05370                      p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
05371                      p->owner = p->subs[SUB_REAL].owner;
05372                      if (p->subs[SUB_REAL].owner && ast_bridged_channel(p->subs[SUB_REAL].owner))
05373                         ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
05374                      p->subs[SUB_REAL].needunhold = 1;
05375                      dahdi_enable_ec(p);
05376                   }
05377                      
05378                }
05379             }
05380          winkflashdone:              
05381             update_conf(p);
05382             break;
05383          case SIG_EM:
05384          case SIG_EM_E1:
05385          case SIG_EMWINK:
05386          case SIG_FEATD:
05387          case SIG_SF:
05388          case SIG_SFWINK:
05389          case SIG_SF_FEATD:
05390          case SIG_FXSLS:
05391          case SIG_FXSGS:
05392             if (option_debug) {
05393                if (p->dialing)
05394                   ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
05395                else
05396                   ast_debug(1, "Got wink in weird state %d on channel %d\n", ast->_state, p->channel);
05397             }
05398             break;
05399          case SIG_FEATDMF_TA:
05400             switch (p->whichwink) {
05401             case 0:
05402                ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
05403                snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
05404                break;
05405             case 1:
05406                ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
05407                break;
05408             case 2:
05409                ast_log(LOG_WARNING, "Received unexpected wink on channel of type SIG_FEATDMF_TA\n");
05410                return NULL;
05411             }
05412             p->whichwink++;
05413             /* Fall through */
05414          case SIG_FEATDMF:
05415          case SIG_E911:
05416          case SIG_FGC_CAMAMF:
05417          case SIG_FGC_CAMA:
05418          case SIG_FEATB:
05419          case SIG_SF_FEATDMF:
05420          case SIG_SF_FEATB:
05421             /* FGD MF *Must* wait for wink */
05422             if (!ast_strlen_zero(p->dop.dialstr)) {
05423                res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
05424                if (res < 0) {
05425                   ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
05426                   p->dop.dialstr[0] = '\0';
05427                   return NULL;
05428                } else 
05429                   ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
05430             }
05431             p->dop.dialstr[0] = '\0';
05432             break;
05433          default:
05434             ast_log(LOG_WARNING, "Don't know how to handle ring/off hoook for signalling %d\n", p->sig);
05435          }
05436          break;
05437       case DAHDI_EVENT_HOOKCOMPLETE:
05438          if (p->inalarm) break;
05439          if ((p->radio || (p->oprmode < 0))) break;
05440          switch (mysig) {
05441          case SIG_FXSLS:  /* only interesting for FXS */
05442          case SIG_FXSGS:
05443          case SIG_FXSKS:
05444          case SIG_EM:
05445          case SIG_EM_E1:
05446          case SIG_EMWINK:
05447          case SIG_FEATD:
05448          case SIG_SF:
05449          case SIG_SFWINK:
05450          case SIG_SF_FEATD:
05451             if (!ast_strlen_zero(p->dop.dialstr)) {
05452                res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
05453                if (res < 0) {
05454                   ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
05455                   p->dop.dialstr[0] = '\0';
05456                   return NULL;
05457                } else 
05458                   ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
05459             }
05460             p->dop.dialstr[0] = '\0';
05461             p->dop.op = DAHDI_DIAL_OP_REPLACE;
05462             break;
05463          case SIG_FEATDMF:
05464          case SIG_FEATDMF_TA:
05465          case SIG_E911:
05466          case SIG_FGC_CAMA:
05467          case SIG_FGC_CAMAMF:
05468          case SIG_FEATB:
05469          case SIG_SF_FEATDMF:
05470          case SIG_SF_FEATB:
05471             ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
05472             break;
05473          default:
05474             break;
05475          }
05476          break;
05477       case DAHDI_EVENT_POLARITY:
05478          /*
05479           * If we get a Polarity Switch event, check to see
05480           * if we should change the polarity state and
05481           * mark the channel as UP or if this is an indication
05482           * of remote end disconnect.
05483           */
05484          if (p->polarity == POLARITY_IDLE) {
05485             p->polarity = POLARITY_REV;
05486             if (p->answeronpolarityswitch &&
05487                 ((ast->_state == AST_STATE_DIALING) ||
05488                 (ast->_state == AST_STATE_RINGING))) {
05489                ast_debug(1, "Answering on polarity switch!\n");
05490                ast_setstate(p->owner, AST_STATE_UP);
05491                if (p->hanguponpolarityswitch) {
05492                   p->polaritydelaytv = ast_tvnow();
05493                }
05494             } else
05495                ast_debug(1, "Ignore switch to REVERSED Polarity on channel %d, state %d\n", p->channel, ast->_state);
05496 
05497          } 
05498          /* Removed else statement from here as it was preventing hangups from ever happening*/
05499          /* Added AST_STATE_RING in if statement below to deal with calling party hangups that take place when ringing */
05500          if (p->hanguponpolarityswitch &&
05501             (p->polarityonanswerdelay > 0) &&
05502                 (p->polarity == POLARITY_REV) &&
05503             ((ast->_state == AST_STATE_UP) || (ast->_state == AST_STATE_RING)) ) {
05504                                 /* Added log_debug information below to provide a better indication of what is going on */
05505             ast_debug(1, "Polarity Reversal event occured - DEBUG 1: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %d\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
05506          
05507             if (ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) > p->polarityonanswerdelay) {
05508                ast_debug(1, "Polarity Reversal detected and now Hanging up on channel %d\n", p->channel);
05509                ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
05510                p->polarity = POLARITY_IDLE;
05511             } else
05512                ast_debug(1, "Polarity Reversal detected but NOT hanging up (too close to answer event) on channel %d, state %d\n", p->channel, ast->_state);
05513 
05514          } else {
05515             p->polarity = POLARITY_IDLE;
05516             ast_debug(1, "Ignoring Polarity switch to IDLE on channel %d, state %d\n", p->channel, ast->_state);
05517          }
05518                         /* Added more log_debug information below to provide a better indication of what is going on */
05519          ast_debug(1, "Polarity Reversal event occured - DEBUG 2: channel %d, state %d, pol= %d, aonp= %d, honp= %d, pdelay= %d, tv= %d\n", p->channel, ast->_state, p->polarity, p->answeronpolarityswitch, p->hanguponpolarityswitch, p->polarityonanswerdelay, ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) );
05520          break;
05521       default:
05522          ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
05523    }
05524    return &p->subs[idx].f;
05525 }
05526 
05527 static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
05528 {
05529    struct dahdi_pvt *p = ast->tech_pvt;
05530    int res;
05531    int usedindex=-1;
05532    int idx;
05533    struct ast_frame *f;
05534 
05535 
05536    idx = dahdi_get_index(ast, p, 1);
05537    
05538    p->subs[idx].f.frametype = AST_FRAME_NULL;
05539    p->subs[idx].f.datalen = 0;
05540    p->subs[idx].f.samples = 0;
05541    p->subs[idx].f.mallocd = 0;
05542    p->subs[idx].f.offset = 0;
05543    p->subs[idx].f.subclass = 0;
05544    p->subs[idx].f.delivery = ast_tv(0,0);
05545    p->subs[idx].f.src = "dahdi_exception";
05546    p->subs[idx].f.data.ptr = NULL;
05547    
05548    
05549    if ((!p->owner) && (!(p->radio || (p->oprmode < 0)))) {
05550       /* If nobody owns us, absorb the event appropriately, otherwise
05551          we loop indefinitely.  This occurs when, during call waiting, the
05552          other end hangs up our channel so that it no longer exists, but we
05553          have neither FLASH'd nor ONHOOK'd to signify our desire to
05554          change to the other channel. */
05555       if (p->fake_event) {
05556          res = p->fake_event;
05557          p->fake_event = 0;
05558       } else
05559          res = dahdi_get_event(p->subs[SUB_REAL].dfd);
05560       /* Switch to real if there is one and this isn't something really silly... */
05561       if ((res != DAHDI_EVENT_RINGEROFF) && (res != DAHDI_EVENT_RINGERON) &&
05562          (res != DAHDI_EVENT_HOOKCOMPLETE)) {
05563          ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
05564          p->owner = p->subs[SUB_REAL].owner;
05565          if (p->owner && ast_bridged_channel(p->owner))
05566             ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
05567          p->subs[SUB_REAL].needunhold = 1;
05568       }
05569       switch (res) {
05570       case DAHDI_EVENT_ONHOOK:
05571          dahdi_disable_ec(p);
05572          if (p->owner) {
05573             ast_verb(3, "Channel %s still has call, ringing phone\n", p->owner->name);
05574             dahdi_ring_phone(p);
05575             p->callwaitingrepeat = 0;
05576             p->cidcwexpire = 0;
05577          } else
05578             ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
05579          update_conf(p);
05580          break;
05581       case DAHDI_EVENT_RINGOFFHOOK:
05582          dahdi_enable_ec(p);
05583          dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
05584          if (p->owner && (p->owner->_state == AST_STATE_RINGING)) {
05585             p->subs[SUB_REAL].needanswer = 1;
05586             p->dialing = 0;
05587          }
05588          break;
05589       case DAHDI_EVENT_HOOKCOMPLETE:
05590       case DAHDI_EVENT_RINGERON:
05591       case DAHDI_EVENT_RINGEROFF:
05592          /* Do nothing */
05593          break;
05594       case DAHDI_EVENT_WINKFLASH:
05595          p->flashtime = ast_tvnow();
05596          if (p->owner) {
05597             ast_verb(3, "Channel %d flashed to other channel %s\n", p->channel, p->owner->name);
05598             if (p->owner->_state != AST_STATE_UP) {
05599                /* Answer if necessary */
05600                usedindex = dahdi_get_index(p->owner, p, 0);
05601                if (usedindex > -1) {
05602                   p->subs[usedindex].needanswer = 1;
05603                }
05604                ast_setstate(p->owner, AST_STATE_UP);
05605             }
05606             p->callwaitingrepeat = 0;
05607             p->cidcwexpire = 0;
05608             if (ast_bridged_channel(p->owner))
05609                ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
05610             p->subs[SUB_REAL].needunhold = 1;
05611          } else
05612             ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
05613          update_conf(p);
05614          break;
05615       default:
05616          ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", event2str(res));
05617       }
05618       f = &p->subs[idx].f;
05619       return f;
05620    }
05621    if (!(p->radio || (p->oprmode < 0))) 
05622       ast_debug(1, "Exception on %d, channel %d\n", ast->fds[0],p->channel);
05623    /* If it's not us, return NULL immediately */
05624    if (ast != p->owner) {
05625       ast_log(LOG_WARNING, "We're %s, not %s\n", ast->name, p->owner->name);
05626       f = &p->subs[idx].f;
05627       return f;
05628    }
05629    f = dahdi_handle_event(ast);
05630    return f;
05631 }
05632 
05633 static struct ast_frame *dahdi_exception(struct ast_channel *ast)
05634 {
05635    struct dahdi_pvt *p = ast->tech_pvt;
05636    struct ast_frame *f;
05637    ast_mutex_lock(&p->lock);
05638    f = __dahdi_exception(ast);
05639    ast_mutex_unlock(&p->lock);
05640    return f;
05641 }
05642 
05643 static struct ast_frame  *dahdi_read(struct ast_channel *ast)
05644 {
05645    struct dahdi_pvt *p = ast->tech_pvt;
05646    int res;
05647    int idx;
05648    void *readbuf;
05649    struct ast_frame *f;
05650 
05651    while (ast_mutex_trylock(&p->lock)) {
05652       CHANNEL_DEADLOCK_AVOIDANCE(ast);
05653    }
05654 
05655    idx = dahdi_get_index(ast, p, 0);
05656    
05657    /* Hang up if we don't really exist */
05658    if (idx < 0)   {
05659       ast_log(LOG_WARNING, "We dont exist?\n");
05660       ast_mutex_unlock(&p->lock);
05661       return NULL;
05662    }
05663    
05664    if ((p->radio || (p->oprmode < 0)) && p->inalarm) return NULL;
05665 
05666    p->subs[idx].f.frametype = AST_FRAME_NULL;
05667    p->subs[idx].f.datalen = 0;
05668    p->subs[idx].f.samples = 0;
05669    p->subs[idx].f.mallocd = 0;
05670    p->subs[idx].f.offset = 0;
05671    p->subs[idx].f.subclass = 0;
05672    p->subs[idx].f.delivery = ast_tv(0,0);
05673    p->subs[idx].f.src = "dahdi_read";
05674    p->subs[idx].f.data.ptr = NULL;
05675    
05676    /* make sure it sends initial key state as first frame */
05677    if ((p->radio || (p->oprmode < 0)) && (!p->firstradio))
05678    {
05679       struct dahdi_params ps;
05680 
05681       memset(&ps, 0, sizeof(ps));
05682       ps.channo = p->channel;
05683       if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
05684          ast_mutex_unlock(&p->lock);
05685          return NULL;
05686       }
05687       p->firstradio = 1;
05688       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05689       if (ps.rxisoffhook)
05690       {
05691          p->subs[idx].f.subclass = AST_CONTROL_RADIO_KEY;
05692       }
05693       else
05694       {
05695          p->subs[idx].f.subclass = AST_CONTROL_RADIO_UNKEY;
05696       }
05697       ast_mutex_unlock(&p->lock);
05698       return &p->subs[idx].f;
05699    }
05700    if (p->ringt == 1) {
05701       ast_mutex_unlock(&p->lock);
05702       return NULL;
05703    }
05704    else if (p->ringt > 0) 
05705       p->ringt--;
05706 
05707    if (p->subs[idx].needringing) {
05708       /* Send ringing frame if requested */
05709       p->subs[idx].needringing = 0;
05710       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05711       p->subs[idx].f.subclass = AST_CONTROL_RINGING;
05712       ast_setstate(ast, AST_STATE_RINGING);
05713       ast_mutex_unlock(&p->lock);
05714       return &p->subs[idx].f;
05715    }
05716 
05717    if (p->subs[idx].needbusy) {
05718       /* Send busy frame if requested */
05719       p->subs[idx].needbusy = 0;
05720       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05721       p->subs[idx].f.subclass = AST_CONTROL_BUSY;
05722       ast_mutex_unlock(&p->lock);
05723       return &p->subs[idx].f;
05724    }
05725 
05726    if (p->subs[idx].needcongestion) {
05727       /* Send congestion frame if requested */
05728       p->subs[idx].needcongestion = 0;
05729       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05730       p->subs[idx].f.subclass = AST_CONTROL_CONGESTION;
05731       ast_mutex_unlock(&p->lock);
05732       return &p->subs[idx].f;
05733    }
05734 
05735    if (p->subs[idx].needcallerid) {
05736       ast_set_callerid(ast, S_OR(p->lastcid_num, NULL),
05737                      S_OR(p->lastcid_name, NULL),
05738                      S_OR(p->lastcid_num, NULL)
05739                      );
05740       p->subs[idx].needcallerid = 0;
05741    }
05742    
05743    if (p->subs[idx].needanswer) {
05744       /* Send answer frame if requested */
05745       p->subs[idx].needanswer = 0;
05746       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05747       p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
05748       ast_mutex_unlock(&p->lock);
05749       return &p->subs[idx].f;
05750    }  
05751    
05752    if (p->subs[idx].needflash) {
05753       /* Send answer frame if requested */
05754       p->subs[idx].needflash = 0;
05755       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05756       p->subs[idx].f.subclass = AST_CONTROL_FLASH;
05757       ast_mutex_unlock(&p->lock);
05758       return &p->subs[idx].f;
05759    }  
05760    
05761    if (p->subs[idx].needhold) {
05762       /* Send answer frame if requested */
05763       p->subs[idx].needhold = 0;
05764       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05765       p->subs[idx].f.subclass = AST_CONTROL_HOLD;
05766       ast_mutex_unlock(&p->lock);
05767       ast_debug(1, "Sending hold on '%s'\n", ast->name);
05768       return &p->subs[idx].f;
05769    }  
05770    
05771    if (p->subs[idx].needunhold) {
05772       /* Send answer frame if requested */
05773       p->subs[idx].needunhold = 0;
05774       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05775       p->subs[idx].f.subclass = AST_CONTROL_UNHOLD;
05776       ast_mutex_unlock(&p->lock);
05777       ast_debug(1, "Sending unhold on '%s'\n", ast->name);
05778       return &p->subs[idx].f;
05779    }  
05780    
05781    if (ast->rawreadformat == AST_FORMAT_SLINEAR) {
05782       if (!p->subs[idx].linear) {
05783          p->subs[idx].linear = 1;
05784          res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
05785          if (res) 
05786             ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to linear mode.\n", p->channel, idx);
05787       }
05788    } else if ((ast->rawreadformat == AST_FORMAT_ULAW) ||
05789          (ast->rawreadformat == AST_FORMAT_ALAW)) {
05790       if (p->subs[idx].linear) {
05791          p->subs[idx].linear = 0;
05792          res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
05793          if (res) 
05794             ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to companded mode.\n", p->channel, idx);
05795       }
05796    } else {
05797       ast_log(LOG_WARNING, "Don't know how to read frames in format %s\n", ast_getformatname(ast->rawreadformat));
05798       ast_mutex_unlock(&p->lock);
05799       return NULL;
05800    }
05801    readbuf = ((unsigned char *)p->subs[idx].buffer) + AST_FRIENDLY_OFFSET;
05802    CHECK_BLOCKING(ast);
05803    res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
05804    ast_clear_flag(ast, AST_FLAG_BLOCKING);
05805    /* Check for hangup */
05806    if (res < 0) {
05807       f = NULL;
05808       if (res == -1)  {
05809          if (errno == EAGAIN) {
05810             /* Return "NULL" frame if there is nobody there */
05811             ast_mutex_unlock(&p->lock);
05812             return &p->subs[idx].f;
05813          } else if (errno == ELAST) {
05814             f = __dahdi_exception(ast);
05815          } else
05816             ast_log(LOG_WARNING, "dahdi_rec: %s\n", strerror(errno));
05817       }
05818       ast_mutex_unlock(&p->lock);
05819       return f;
05820    }
05821    if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
05822       ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
05823       f = __dahdi_exception(ast);
05824       ast_mutex_unlock(&p->lock);
05825       return f;
05826    }
05827    if (p->tdd) { /* if in TDD mode, see if we receive that */
05828       int c;
05829 
05830       c = tdd_feed(p->tdd,readbuf,READ_SIZE);
05831       if (c < 0) {
05832          ast_debug(1,"tdd_feed failed\n");
05833          ast_mutex_unlock(&p->lock);
05834          return NULL;
05835       }
05836       if (c) { /* if a char to return */
05837          p->subs[idx].f.subclass = 0;
05838          p->subs[idx].f.frametype = AST_FRAME_TEXT;
05839          p->subs[idx].f.mallocd = 0;
05840          p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
05841          p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET;
05842          p->subs[idx].f.datalen = 1;
05843          *((char *) p->subs[idx].f.data.ptr) = c;
05844          ast_mutex_unlock(&p->lock);
05845          return &p->subs[idx].f;
05846       }
05847    }
05848    /* Ensure the CW timer decrements only on a single subchannel */
05849    if (p->callwaitingrepeat && dahdi_get_index(ast, p, 1) == SUB_REAL) {
05850       p->callwaitingrepeat--;
05851    }
05852    if (p->cidcwexpire)
05853       p->cidcwexpire--;
05854    /* Repeat callwaiting */
05855    if (p->callwaitingrepeat == 1) {
05856       p->callwaitrings++;
05857       dahdi_callwait(ast);
05858    }
05859    /* Expire CID/CW */
05860    if (p->cidcwexpire == 1) {
05861       ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
05862       restore_conference(p);
05863    }
05864    if (p->subs[idx].linear) {
05865       p->subs[idx].f.datalen = READ_SIZE * 2;
05866    } else 
05867       p->subs[idx].f.datalen = READ_SIZE;
05868 
05869    /* Handle CallerID Transmission */
05870    if ((p->owner == ast) && p->cidspill &&((ast->_state == AST_STATE_UP) || (ast->rings == p->cidrings))) {
05871       send_callerid(p);
05872    }
05873 
05874    p->subs[idx].f.frametype = AST_FRAME_VOICE;
05875    p->subs[idx].f.subclass = ast->rawreadformat;
05876    p->subs[idx].f.samples = READ_SIZE;
05877    p->subs[idx].f.mallocd = 0;
05878    p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
05879    p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET / sizeof(p->subs[idx].buffer[0]);
05880 #if 0
05881    ast_debug(1, "Read %d of voice on %s\n", p->subs[idx].f.datalen, ast->name);
05882 #endif   
05883    if (p->dialing || /* Transmitting something */
05884       (idx && (ast->_state != AST_STATE_UP)) || /* Three-way or callwait that isn't up */
05885       ((idx == SUB_CALLWAIT) && !p->subs[SUB_CALLWAIT].inthreeway) /* Inactive and non-confed call-wait */
05886       ) {
05887       /* Whoops, we're still dialing, or in a state where we shouldn't transmit....
05888          don't send anything */
05889       p->subs[idx].f.frametype = AST_FRAME_NULL;
05890       p->subs[idx].f.subclass = 0;
05891       p->subs[idx].f.samples = 0;
05892       p->subs[idx].f.mallocd = 0;
05893       p->subs[idx].f.offset = 0;
05894       p->subs[idx].f.data.ptr = NULL;
05895       p->subs[idx].f.datalen= 0;
05896    }
05897    if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect  || p->callprogress) && !idx) {
05898       /* Perform busy detection. etc on the dahdi line */
05899       int mute;
05900 
05901       f = ast_dsp_process(ast, p->dsp, &p->subs[idx].f);
05902 
05903       /* Check if DSP code thinks we should be muting this frame and mute the conference if so */
05904       mute = ast_dsp_was_muted(p->dsp);
05905       if (p->muting != mute) {
05906          p->muting = mute;
05907          dahdi_confmute(p, mute);
05908       }
05909 
05910       if (f) {
05911          if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_BUSY)) {
05912             if ((ast->_state == AST_STATE_UP) && !p->outgoing) {
05913                /* Treat this as a "hangup" instead of a "busy" on the assumption that
05914                   a busy  */
05915                f = NULL;
05916             }
05917          } else if (f->frametype == AST_FRAME_DTMF) {
05918 #ifdef HAVE_PRI
05919             if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri && 
05920                 ((!p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) ||
05921                  (p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)))) {
05922                /* Don't accept in-band DTMF when in overlap dial mode */
05923                f->frametype = AST_FRAME_NULL;
05924                f->subclass = 0;
05925             }
05926 #endif            
05927             /* DSP clears us of being pulse */
05928             p->pulsedial = 0;
05929          }
05930       }
05931    } else 
05932       f = &p->subs[idx].f; 
05933 
05934    if (f && (f->frametype == AST_FRAME_DTMF))
05935       dahdi_handle_dtmfup(ast, idx, &f);
05936 
05937    /* If we have a fake_event, trigger exception to handle it */
05938    if (p->fake_event)
05939       ast_set_flag(ast, AST_FLAG_EXCEPTION);
05940 
05941    ast_mutex_unlock(&p->lock);
05942    return f;
05943 }
05944 
05945 static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int idx, int linear)
05946 {
05947    int sent=0;
05948    int size;
05949    int res;
05950    int fd;
05951    fd = p->subs[idx].dfd;
05952    while (len) {
05953       size = len;
05954       if (size > (linear ? READ_SIZE * 2 : READ_SIZE))
05955          size = (linear ? READ_SIZE * 2 : READ_SIZE);
05956       res = write(fd, buf, size);
05957       if (res != size) {
05958          ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
05959          return sent;
05960       }
05961       len -= size;
05962       buf += size;
05963    }
05964    return sent;
05965 }
05966 
05967 static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
05968 {
05969    struct dahdi_pvt *p = ast->tech_pvt;
05970    int res;
05971    int idx;
05972    idx = dahdi_get_index(ast, p, 0);
05973    if (idx < 0) {
05974       ast_log(LOG_WARNING, "%s doesn't really exist?\n", ast->name);
05975       return -1;
05976    }
05977 
05978 #if 0
05979 #ifdef HAVE_PRI
05980    ast_mutex_lock(&p->lock);
05981    if (!p->proceeding && p->sig==SIG_PRI && p->pri && !p->outgoing) {
05982       if (p->pri->pri) {      
05983          if (!pri_grab(p, p->pri)) {
05984                pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
05985                pri_rel(p->pri);
05986          } else
05987                ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
05988       }
05989       p->proceeding=1;
05990    }
05991    ast_mutex_unlock(&p->lock);
05992 #endif
05993 #endif
05994    /* Write a frame of (presumably voice) data */
05995    if (frame->frametype != AST_FRAME_VOICE) {
05996       if (frame->frametype != AST_FRAME_IMAGE)
05997          ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
05998       return 0;
05999    }
06000    if ((frame->subclass != AST_FORMAT_SLINEAR) && 
06001        (frame->subclass != AST_FORMAT_ULAW) &&
06002        (frame->subclass != AST_FORMAT_ALAW)) {
06003       ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
06004       return -1;
06005    }
06006    if (p->dialing) {
06007       ast_debug(1, "Dropping frame since I'm still dialing on %s...\n",ast->name);
06008       return 0;
06009    }
06010    if (!p->owner) {
06011       ast_debug(1, "Dropping frame since there is no active owner on %s...\n",ast->name);
06012       return 0;
06013    }
06014    if (p->cidspill) {
06015       ast_debug(1, "Dropping frame since I've still got a callerid spill\n");
06016       return 0;
06017    }
06018    /* Return if it's not valid data */
06019    if (!frame->data.ptr || !frame->datalen)
06020       return 0;
06021 
06022    if (frame->subclass == AST_FORMAT_SLINEAR) {
06023       if (!p->subs[idx].linear) {
06024          p->subs[idx].linear = 1;
06025          res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
06026          if (res)
06027             ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
06028       }
06029       res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 1);
06030    } else {
06031       /* x-law already */
06032       if (p->subs[idx].linear) {
06033          p->subs[idx].linear = 0;
06034          res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
06035          if (res)
06036             ast_log(LOG_WARNING, "Unable to set companded mode on channel %d\n", p->channel);
06037       }
06038       res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 0);
06039    }
06040    if (res < 0) {
06041       ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
06042       return -1;
06043    } 
06044    return 0;
06045 }
06046 
06047 static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
06048 {
06049    struct dahdi_pvt *p = chan->tech_pvt;
06050    int res=-1;
06051    int idx;
06052    int func = DAHDI_FLASH;
06053    ast_mutex_lock(&p->lock);
06054    idx = dahdi_get_index(chan, p, 0);
06055    ast_debug(1, "Requested indication %d on channel %s\n", condition, chan->name);
06056    if (idx == SUB_REAL) {
06057       switch (condition) {
06058       case AST_CONTROL_BUSY:
06059 #ifdef HAVE_PRI
06060          if (p->priindication_oob && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))) {
06061             chan->hangupcause = AST_CAUSE_USER_BUSY;
06062             chan->_softhangup |= AST_SOFTHANGUP_DEV;
06063             res = 0;
06064          } else if (!p->progress && 
06065                ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
06066                && p->pri && !p->outgoing) {
06067             if (p->pri->pri) {      
06068                if (!pri_grab(p, p->pri)) {
06069                   pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
06070                   pri_rel(p->pri);
06071                }
06072                else
06073                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06074             }
06075             p->progress = 1;
06076             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY);
06077          } else
06078 #endif
06079             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY);
06080          break;
06081       case AST_CONTROL_RINGING:
06082 #ifdef HAVE_PRI
06083          if ((!p->alerting) && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) 
06084                && p->pri && !p->outgoing && (chan->_state != AST_STATE_UP)) {
06085             if (p->pri->pri) {      
06086                if (!pri_grab(p, p->pri)) {
06087                   pri_acknowledge(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
06088                   pri_rel(p->pri);
06089                }
06090                else
06091                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06092             }
06093             p->alerting = 1;
06094          }
06095 
06096 #endif
06097 #ifdef HAVE_SS7
06098          if ((!p->alerting) && (p->sig == SIG_SS7) && p->ss7 && !p->outgoing && (chan->_state != AST_STATE_UP)) {
06099             if (p->ss7->ss7) {
06100                ss7_grab(p, p->ss7);
06101                
06102                if ((isup_far(p->ss7->ss7, p->ss7call)) != -1)
06103                   p->rlt = 1;
06104                if (p->rlt != 1) /* No need to send CPG if call will be RELEASE */
06105                   isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_ALERTING);
06106                p->alerting = 1;
06107                ss7_rel(p->ss7);
06108             }
06109          }
06110 #endif
06111             
06112          res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_RINGTONE);
06113          
06114          if (chan->_state != AST_STATE_UP) {
06115             if ((chan->_state != AST_STATE_RING) ||
06116                ((p->sig != SIG_FXSKS) &&
06117              (p->sig != SIG_FXSLS) &&
06118              (p->sig != SIG_FXSGS)))
06119             ast_setstate(chan, AST_STATE_RINGING);
06120          }
06121          break;
06122       case AST_CONTROL_PROCEEDING:
06123          ast_debug(1,"Received AST_CONTROL_PROCEEDING on %s\n",chan->name);
06124 #ifdef HAVE_PRI
06125          if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
06126                && p->pri && !p->outgoing) {
06127             if (p->pri->pri) {      
06128                if (!pri_grab(p, p->pri)) {
06129                   pri_proceeding(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
06130                   pri_rel(p->pri);
06131                }
06132                else
06133                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06134             }
06135             p->proceeding = 1;
06136             p->dialing = 0;
06137          }
06138 #endif
06139 #ifdef HAVE_SS7
06140          /* This IF sends the FAR for an answered ALEG call */
06141          if (chan->_state == AST_STATE_UP && (p->rlt != 1) && (p->sig == SIG_SS7)){
06142             if ((isup_far(p->ss7->ss7, p->ss7call)) != -1)
06143                p->rlt = 1; 
06144          }
06145             
06146          if (!p->proceeding && p->sig == SIG_SS7 && p->ss7 && !p->outgoing) {
06147             if (p->ss7->ss7) {
06148                ss7_grab(p, p->ss7);
06149                isup_acm(p->ss7->ss7, p->ss7call);
06150                p->proceeding = 1;
06151                ss7_rel(p->ss7);
06152 
06153             }
06154          }
06155 #endif
06156          /* don't continue in ast_indicate */
06157          res = 0;
06158          break;
06159       case AST_CONTROL_PROGRESS:
06160          ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
06161 #ifdef HAVE_PRI
06162          p->digital = 0;   /* Digital-only calls isn't allows any inband progress messages */
06163          if (!p->progress && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
06164                && p->pri && !p->outgoing) {
06165             if (p->pri->pri) {      
06166                if (!pri_grab(p, p->pri)) {
06167                   pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
06168                   pri_rel(p->pri);
06169                }
06170                else
06171                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06172             }
06173             p->progress = 1;
06174          }
06175 #endif
06176 #ifdef HAVE_SS7
06177          if (!p->progress && p->sig==SIG_SS7 && p->ss7 && !p->outgoing) {
06178             if (p->ss7->ss7) {
06179                ss7_grab(p, p->ss7);
06180                isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_INBANDINFO);
06181                p->progress = 1;
06182                ss7_rel(p->ss7);
06183                /* enable echo canceler here on SS7 calls */
06184                dahdi_enable_ec(p);
06185 
06186             }
06187          }
06188 #endif
06189          /* don't continue in ast_indicate */
06190          res = 0;
06191          break;
06192       case AST_CONTROL_CONGESTION:
06193          chan->hangupcause = AST_CAUSE_CONGESTION;
06194 #ifdef HAVE_PRI
06195          if (p->priindication_oob && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))) {
06196             chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
06197             chan->_softhangup |= AST_SOFTHANGUP_DEV;
06198             res = 0;
06199          } else if (!p->progress && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) 
06200                && p->pri && !p->outgoing) {
06201             if (p->pri) {     
06202                if (!pri_grab(p, p->pri)) {
06203                   pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
06204                   pri_rel(p->pri);
06205                } else
06206                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06207             }
06208             p->progress = 1;
06209             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06210          } else
06211 #endif
06212             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06213          break;
06214       case AST_CONTROL_HOLD:
06215 #ifdef HAVE_PRI
06216          if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
06217             if (!pri_grab(p, p->pri)) {
06218                res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_HOLD);
06219                pri_rel(p->pri);
06220             } else
06221                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);       
06222          } else
06223 #endif
06224             ast_moh_start(chan, data, p->mohinterpret);
06225          break;
06226       case AST_CONTROL_UNHOLD:
06227 #ifdef HAVE_PRI
06228          if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
06229             if (!pri_grab(p, p->pri)) {
06230                res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_RETRIEVAL);
06231                pri_rel(p->pri);
06232             } else
06233                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);       
06234          } else
06235 #endif
06236             ast_moh_stop(chan);
06237          break;
06238       case AST_CONTROL_RADIO_KEY:
06239          if (p->radio) 
06240              res =  dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
06241          res = 0;
06242          break;
06243       case AST_CONTROL_RADIO_UNKEY:
06244          if (p->radio)
06245              res =  dahdi_set_hook(p->subs[idx].dfd, DAHDI_RINGOFF);
06246          res = 0;
06247          break;
06248       case AST_CONTROL_FLASH:
06249          /* flash hookswitch */
06250          if (ISTRUNK(p) && (p->sig != SIG_PRI)) {
06251             /* Clear out the dial buffer */
06252             p->dop.dialstr[0] = '\0';
06253             if ((ioctl(p->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
06254                ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n", 
06255                   chan->name, strerror(errno));
06256             } else
06257                res = 0;
06258          } else
06259             res = 0;
06260          break;
06261       case AST_CONTROL_SRCUPDATE:
06262          res = 0;
06263          break;
06264       case -1:
06265          res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06266          break;
06267       }
06268    } else
06269       res = 0;
06270    ast_mutex_unlock(&p->lock);
06271    return res;
06272 }
06273 
06274 static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, int transfercapability)
06275 {
06276    struct ast_channel *tmp;
06277    int deflaw;
06278    int res;
06279    int x,y;
06280    int features;
06281    struct ast_str *chan_name;
06282    struct ast_variable *v;
06283    struct dahdi_params ps;
06284    if (i->subs[idx].owner) {
06285       ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[idx]);
06286       return NULL;
06287    }
06288    y = 1;
06289    chan_name = ast_str_alloca(32);
06290    do {
06291 #ifdef HAVE_PRI
06292       if (i->bearer || (i->pri && (i->sig == SIG_FXSKS)))
06293          ast_str_set(&chan_name, 0, "%d:%d-%d", i->pri->trunkgroup, i->channel, y);
06294       else
06295 #endif
06296       if (i->channel == CHAN_PSEUDO)
06297          ast_str_set(&chan_name, 0, "pseudo-%ld", ast_random());
06298       else  
06299          ast_str_set(&chan_name, 0, "%d-%d", i->channel, y);
06300       for (x = 0; x < 3; x++) {
06301          if ((idx != x) && i->subs[x].owner && !strcasecmp(chan_name->str, i->subs[x].owner->name + 6))
06302             break;
06303       }
06304       y++;
06305    } while (x < 3);
06306    tmp = ast_channel_alloc(0, state, i->cid_num, i->cid_name, i->accountcode, i->exten, i->context, i->amaflags, "DAHDI/%s", chan_name->str);
06307    if (!tmp)
06308       return NULL;
06309    tmp->tech = &dahdi_tech;
06310    memset(&ps, 0, sizeof(ps));
06311    ps.channo = i->channel;
06312    res = ioctl(i->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps);
06313    if (res) {
06314       ast_log(LOG_WARNING, "Unable to get parameters, assuming MULAW: %s\n", strerror(errno));
06315       ps.curlaw = DAHDI_LAW_MULAW;
06316    }
06317    if (ps.curlaw == DAHDI_LAW_ALAW)
06318       deflaw = AST_FORMAT_ALAW;
06319    else
06320       deflaw = AST_FORMAT_ULAW;
06321    if (law) {
06322       if (law == DAHDI_LAW_ALAW)
06323          deflaw = AST_FORMAT_ALAW;
06324       else
06325          deflaw = AST_FORMAT_ULAW;
06326    }
06327    ast_channel_set_fd(tmp, 0, i->subs[idx].dfd);
06328    tmp->nativeformats = deflaw;
06329    /* Start out assuming ulaw since it's smaller :) */
06330    tmp->rawreadformat = deflaw;
06331    tmp->readformat = deflaw;
06332    tmp->rawwriteformat = deflaw;
06333    tmp->writeformat = deflaw;
06334    i->subs[idx].linear = 0;
06335    dahdi_setlinear(i->subs[idx].dfd, i->subs[idx].linear);
06336    features = 0;
06337    if (idx == SUB_REAL) {
06338       if (i->busydetect && CANBUSYDETECT(i))
06339          features |= DSP_FEATURE_BUSY_DETECT;
06340       if ((i->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(i))
06341          features |= DSP_FEATURE_CALL_PROGRESS;
06342       if ((!i->outgoing && (i->callprogress & CALLPROGRESS_FAX_INCOMING)) || 
06343           (i->outgoing && (i->callprogress & CALLPROGRESS_FAX_OUTGOING))) {
06344          features |= DSP_FEATURE_FAX_DETECT;
06345       }
06346       x = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
06347       if (ioctl(i->subs[idx].dfd, DAHDI_TONEDETECT, &x)) {
06348          i->hardwaredtmf = 0;
06349          features |= DSP_FEATURE_DIGIT_DETECT;
06350       } else if (NEED_MFDETECT(i)) {
06351          i->hardwaredtmf = 1;
06352          features |= DSP_FEATURE_DIGIT_DETECT;
06353       }
06354    }
06355    if (features) {
06356       if (i->dsp) {
06357          ast_debug(1, "Already have a dsp on %s?\n", tmp->name);
06358       } else {
06359          if (i->channel != CHAN_PSEUDO)
06360             i->dsp = ast_dsp_new();
06361          else
06362             i->dsp = NULL;
06363          if (i->dsp) {
06364             i->dsp_features = features;
06365 #if defined(HAVE_PRI) || defined(HAVE_SS7)
06366             /* We cannot do progress detection until receives PROGRESS message */
06367             if (i->outgoing && ((i->sig == SIG_PRI) || (i->sig == SIG_BRI) || (i->sig == SIG_BRI_PTMP) || (i->sig == SIG_SS7))) {
06368                /* Remember requested DSP features, don't treat
06369                   talking as ANSWER */
06370                i->dsp_features = features & ~DSP_PROGRESS_TALK;
06371                features = 0;
06372             }
06373 #endif
06374             ast_dsp_set_features(i->dsp, features);
06375             ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_DTMF | i->dtmfrelax);
06376             if (!ast_strlen_zero(progzone))
06377                ast_dsp_set_call_progress_zone(i->dsp, progzone);
06378             if (i->busydetect && CANBUSYDETECT(i)) {
06379                if(i->silencethreshold > 0)
06380                   ast_dsp_set_threshold(i->dsp, i->silencethreshold);
06381                ast_dsp_set_busy_count(i->dsp, i->busycount);
06382                if(i->busytonelength > 0)
06383                   ast_dsp_set_busy_pattern(i->dsp, i->busytonelength, i->busyquietlength, i->busyfuzziness);
06384                if((i->busytonelength == i->busyquietlength) && i->busycompare)
06385                   ast_dsp_set_busy_compare(i->dsp, i->busycompare);
06386             }
06387          }
06388       }
06389    }
06390       
06391    if (state == AST_STATE_RING)
06392       tmp->rings = 1;
06393    tmp->tech_pvt = i;
06394    if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
06395       /* Only FXO signalled stuff can be picked up */
06396       tmp->callgroup = i->callgroup;
06397       tmp->pickupgroup = i->pickupgroup;
06398    }
06399    if (!ast_strlen_zero(i->parkinglot))
06400       ast_string_field_set(tmp, parkinglot, i->parkinglot);
06401    if (!ast_strlen_zero(i->language))
06402       ast_string_field_set(tmp, language, i->language);
06403    if (!i->owner)
06404       i->owner = tmp;
06405    if (!ast_strlen_zero(i->accountcode))
06406       ast_string_field_set(tmp, accountcode, i->accountcode);
06407    if (i->amaflags)
06408       tmp->amaflags = i->amaflags;
06409    i->subs[idx].owner = tmp;
06410    ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
06411    ast_string_field_set(tmp, call_forward, i->call_forward);
06412    /* If we've been told "no ADSI" then enforce it */
06413    if (!i->adsi)
06414       tmp->adsicpe = AST_ADSI_UNAVAILABLE;
06415    if (!ast_strlen_zero(i->exten))
06416       ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
06417    if (!ast_strlen_zero(i->rdnis))
06418       tmp->cid.cid_rdnis = ast_strdup(i->rdnis);
06419    if (!ast_strlen_zero(i->dnid))
06420       tmp->cid.cid_dnid = ast_strdup(i->dnid);
06421 
06422    /* Don't use ast_set_callerid() here because it will
06423     * generate a needless NewCallerID event */
06424 #ifdef PRI_ANI
06425    if (!ast_strlen_zero(i->cid_ani))
06426       tmp->cid.cid_ani = ast_strdup(i->cid_ani);
06427    else  
06428       tmp->cid.cid_ani = ast_strdup(i->cid_num);
06429 #else
06430    tmp->cid.cid_ani = ast_strdup(i->cid_num);
06431 #endif
06432    tmp->cid.cid_pres = i->callingpres;
06433    tmp->cid.cid_ton = i->cid_ton;
06434    tmp->cid.cid_ani2 = i->cid_ani2;
06435 #if defined(HAVE_PRI) || defined(HAVE_SS7)
06436    tmp->transfercapability = transfercapability;
06437    pbx_builtin_setvar_helper(tmp, "TRANSFERCAPABILITY", ast_transfercapability2str(transfercapability));
06438    if (transfercapability & AST_TRANS_CAP_DIGITAL)
06439       i->digital = 1;
06440    /* Assume calls are not idle calls unless we're told differently */
06441    i->isidlecall = 0;
06442    i->alreadyhungup = 0;
06443 #endif
06444    /* clear the fake event in case we posted one before we had ast_channel */
06445    i->fake_event = 0;
06446    /* Assure there is no confmute on this channel */
06447    dahdi_confmute(i, 0);
06448    i->muting = 0;
06449    /* Configure the new channel jb */
06450    ast_jb_configure(tmp, &global_jbconf);
06451 
06452    ast_devstate_changed_literal(ast_state_chan2dev(state), tmp->name);
06453 
06454    for (v = i->vars ; v ; v = v->next)
06455                 pbx_builtin_setvar_helper(tmp, v->name, v->value);
06456 
06457    if (startpbx) {
06458       if (ast_pbx_start(tmp)) {
06459          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
06460          ast_hangup(tmp);
06461          i->owner = NULL;
06462          return NULL;
06463       }
06464    }
06465 
06466    ast_module_ref(ast_module_info->self);
06467    return tmp;
06468 }
06469 
06470 
06471 static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
06472 {
06473    char c;
06474 
06475    *str = 0; /* start with empty output buffer */
06476    for (;;)
06477    {
06478       /* Wait for the first digit (up to specified ms). */
06479       c = ast_waitfordigit(chan, ms);
06480       /* if timeout, hangup or error, return as such */
06481       if (c < 1)
06482          return c;
06483       *str++ = c;
06484       *str = 0;
06485       if (strchr(term, c))
06486          return 1;
06487    }
06488 }
06489 
06490 static int dahdi_wink(struct dahdi_pvt *p, int idx)
06491 {
06492    int j;
06493    dahdi_set_hook(p->subs[idx].dfd, DAHDI_WINK);
06494    for (;;)
06495    {
06496          /* set bits of interest */
06497       j = DAHDI_IOMUX_SIGEVENT;
06498           /* wait for some happening */
06499       if (ioctl(p->subs[idx].dfd,DAHDI_IOMUX,&j) == -1) return(-1);
06500          /* exit loop if we have it */
06501       if (j & DAHDI_IOMUX_SIGEVENT) break;
06502    }
06503      /* get the event info */
06504    if (ioctl(p->subs[idx].dfd,DAHDI_GETEVENT,&j) == -1) return(-1);
06505    return 0;
06506 }
06507 
06508 /*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
06509  * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
06510  * \param on 1 to enable, 0 to disable
06511  *
06512  * chan_dahdi has a DND (Do Not Disturb) mode for each dahdichan (physical 
06513  * DAHDI channel). Use this to enable or disable it.
06514  *
06515  * \bug the use of the word "channel" for those dahdichans is really confusing.
06516  */
06517 static void dahdi_dnd(struct dahdi_pvt *dahdichan, int on)
06518 {
06519    /* Do not disturb */
06520    dahdichan->dnd = on;
06521    ast_verb(3, "%s DND on channel %d\n", 
06522          on? "Enabled" : "Disabled",
06523          dahdichan->channel);
06524    manager_event(EVENT_FLAG_SYSTEM, "DNDState",
06525          "Channel: DAHDI/%d\r\n"
06526          "Status: %s\r\n", dahdichan->channel,
06527          on? "enabled" : "disabled");
06528 }
06529 
06530 static void *ss_thread(void *data)
06531 {
06532    struct ast_channel *chan = data;
06533    struct dahdi_pvt *p = chan->tech_pvt;
06534    char exten[AST_MAX_EXTENSION] = "";
06535    char exten2[AST_MAX_EXTENSION] = "";
06536    unsigned char buf[256];
06537    char dtmfcid[300];
06538    char dtmfbuf[300];
06539    struct callerid_state *cs = NULL;
06540    char *name = NULL, *number = NULL;
06541    int distMatches;
06542    int curRingData[3];
06543    int receivedRingT;
06544    int counter1;
06545    int counter;
06546    int samples = 0;
06547    struct ast_smdi_md_message *smdi_msg = NULL;
06548    int flags;
06549    int i;
06550    int timeout;
06551    int getforward = 0;
06552    char *s1, *s2;
06553    int len = 0;
06554    int res;
06555    int idx;
06556 
06557    ast_mutex_lock(&ss_thread_lock);
06558    ss_thread_count++;
06559    ast_mutex_unlock(&ss_thread_lock);
06560    /* in the bizarre case where the channel has become a zombie before we
06561       even get started here, abort safely
06562    */
06563    if (!p) {
06564       ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", chan->name);
06565       ast_hangup(chan);
06566       goto quit;
06567    }
06568    ast_verb(3, "Starting simple switch on '%s'\n", chan->name);
06569    idx = dahdi_get_index(chan, p, 1);
06570    if (idx < 0) {
06571       ast_log(LOG_WARNING, "Huh?\n");
06572       ast_hangup(chan);
06573       goto quit;
06574    }
06575    if (p->dsp)
06576       ast_dsp_digitreset(p->dsp);
06577    switch (p->sig) {
06578 #ifdef HAVE_PRI
06579    case SIG_PRI:
06580    case SIG_BRI:
06581    case SIG_BRI_PTMP:
06582       /* Now loop looking for an extension */
06583       ast_copy_string(exten, p->exten, sizeof(exten));
06584       len = strlen(exten);
06585       res = 0;
06586       while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
06587          if (len && !ast_ignore_pattern(chan->context, exten))
06588             tone_zone_play_tone(p->subs[idx].dfd, -1);
06589          else
06590             tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
06591          if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num))
06592             timeout = matchdigittimeout;
06593          else
06594             timeout = gendigittimeout;
06595          res = ast_waitfordigit(chan, timeout);
06596          if (res < 0) {
06597             ast_debug(1, "waitfordigit returned < 0...\n");
06598             ast_hangup(chan);
06599             goto quit;
06600          } else if (res) {
06601             exten[len++] = res;
06602             exten[len] = '\0';
06603          } else
06604             break;
06605       }
06606       /* if no extension was received ('unspecified') on overlap call, use the 's' extension */
06607       if (ast_strlen_zero(exten)) {
06608          ast_verb(3, "Going to extension s|1 because of empty extension received on overlap call\n");
06609          exten[0] = 's';
06610          exten[1] = '\0';
06611       }
06612       tone_zone_play_tone(p->subs[idx].dfd, -1);
06613       if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num)) {
06614          /* Start the real PBX */
06615          ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06616          if (p->dsp) ast_dsp_digitreset(p->dsp);
06617          dahdi_enable_ec(p);
06618          ast_setstate(chan, AST_STATE_RING);
06619          res = ast_pbx_run(chan);
06620          if (res) {
06621             ast_log(LOG_WARNING, "PBX exited non-zero!\n");
06622          }
06623       } else {
06624          ast_debug(1, "No such possible extension '%s' in context '%s'\n", exten, chan->context);
06625          chan->hangupcause = AST_CAUSE_UNALLOCATED;
06626          ast_hangup(chan);
06627          p->exten[0] = '\0';
06628          /* Since we send release complete here, we won't get one */
06629          p->call = NULL;
06630       }
06631       goto quit;
06632       break;
06633 #endif
06634    case SIG_FEATD:
06635    case SIG_FEATDMF:
06636    case SIG_FEATDMF_TA:
06637    case SIG_E911:
06638    case SIG_FGC_CAMAMF:
06639    case SIG_FEATB:
06640    case SIG_EMWINK:
06641    case SIG_SF_FEATD:
06642    case SIG_SF_FEATDMF:
06643    case SIG_SF_FEATB:
06644    case SIG_SFWINK:
06645       if (dahdi_wink(p, idx)) 
06646          goto quit;
06647       /* Fall through */
06648    case SIG_EM:
06649    case SIG_EM_E1:
06650    case SIG_SF:
06651    case SIG_FGC_CAMA:
06652       res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06653       if (p->dsp)
06654          ast_dsp_digitreset(p->dsp);
06655       /* set digit mode appropriately */
06656       if (p->dsp) {
06657          if (NEED_MFDETECT(p))
06658             ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax); 
06659          else 
06660             ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
06661       }
06662       memset(dtmfbuf, 0, sizeof(dtmfbuf));
06663       /* Wait for the first digit only if immediate=no */
06664       if (!p->immediate)
06665          /* Wait for the first digit (up to 5 seconds). */
06666          res = ast_waitfordigit(chan, 5000);
06667       else
06668          res = 0;
06669       if (res > 0) {
06670          /* save first char */
06671          dtmfbuf[0] = res;
06672          switch (p->sig) {
06673          case SIG_FEATD:
06674          case SIG_SF_FEATD:
06675             res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
06676             if (res > 0)
06677                res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
06678             if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06679             break;
06680          case SIG_FEATDMF_TA:
06681             res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
06682             if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06683             if (dahdi_wink(p, idx)) goto quit;
06684             dtmfbuf[0] = 0;
06685             /* Wait for the first digit (up to 5 seconds). */
06686             res = ast_waitfordigit(chan, 5000);
06687             if (res <= 0) break;
06688             dtmfbuf[0] = res;
06689             /* fall through intentionally */
06690          case SIG_FEATDMF:
06691          case SIG_E911:
06692          case SIG_FGC_CAMAMF:
06693          case SIG_SF_FEATDMF:
06694             res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
06695             /* if international caca, do it again to get real ANO */
06696             if ((p->sig == SIG_FEATDMF) && (dtmfbuf[1] != '0') && (strlen(dtmfbuf) != 14))
06697             {
06698                if (dahdi_wink(p, idx)) goto quit;
06699                dtmfbuf[0] = 0;
06700                /* Wait for the first digit (up to 5 seconds). */
06701                res = ast_waitfordigit(chan, 5000);
06702                if (res <= 0) break;
06703                dtmfbuf[0] = res;
06704                res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
06705             }
06706             if (res > 0) {
06707                /* if E911, take off hook */
06708                if (p->sig == SIG_E911)
06709                   dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
06710                res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "#", 3000);
06711             }
06712             if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06713             break;
06714          case SIG_FEATB:
06715          case SIG_SF_FEATB:
06716             res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
06717             if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06718             break;
06719          case SIG_EMWINK:
06720             /* if we received a '*', we are actually receiving Feature Group D
06721                dial syntax, so use that mode; otherwise, fall through to normal
06722                mode
06723             */
06724             if (res == '*') {
06725                res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
06726                if (res > 0)
06727                   res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
06728                if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06729                break;
06730             }
06731          default:
06732             /* If we got the first digit, get the rest */
06733             len = 1;
06734             dtmfbuf[len] = '\0';
06735             while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, dtmfbuf, 1, p->cid_num)) {
06736                if (ast_exists_extension(chan, chan->context, dtmfbuf, 1, p->cid_num)) {
06737                   timeout = matchdigittimeout;
06738                } else {
06739                   timeout = gendigittimeout;
06740                }
06741                res = ast_waitfordigit(chan, timeout);
06742                if (res < 0) {
06743                   ast_debug(1, "waitfordigit returned < 0...\n");
06744                   ast_hangup(chan);
06745                   goto quit;
06746                } else if (res) {
06747                   dtmfbuf[len++] = res;
06748                   dtmfbuf[len] = '\0';
06749                } else {
06750                   break;
06751                }
06752             }
06753             break;
06754          }
06755       }
06756       if (res == -1) {
06757          ast_log(LOG_WARNING, "getdtmf on channel %d: %s\n", p->channel, strerror(errno));
06758          ast_hangup(chan);
06759          goto quit;
06760       } else if (res < 0) {
06761          ast_debug(1, "Got hung up before digits finished\n");
06762          ast_hangup(chan);
06763          goto quit;
06764       }
06765 
06766       if (p->sig == SIG_FGC_CAMA) {
06767          char anibuf[100];
06768 
06769          if (ast_safe_sleep(chan,1000) == -1) {
06770                            ast_hangup(chan);
06771                            goto quit;
06772          }
06773                         dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
06774                         ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax);
06775                         res = my_getsigstr(chan, anibuf, "#", 10000);
06776                         if ((res > 0) && (strlen(anibuf) > 2)) {
06777             if (anibuf[strlen(anibuf) - 1] == '#')
06778                anibuf[strlen(anibuf) - 1] = 0;
06779             ast_set_callerid(chan, anibuf + 2, NULL, anibuf + 2);
06780          }
06781                         ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
06782       }
06783 
06784       ast_copy_string(exten, dtmfbuf, sizeof(exten));
06785       if (ast_strlen_zero(exten))
06786          ast_copy_string(exten, "s", sizeof(exten));
06787       if (p->sig == SIG_FEATD || p->sig == SIG_EMWINK) {
06788          /* Look for Feature Group D on all E&M Wink and Feature Group D trunks */
06789          if (exten[0] == '*') {
06790             char *stringp=NULL;
06791             ast_copy_string(exten2, exten, sizeof(exten2));
06792             /* Parse out extension and callerid */
06793             stringp=exten2 +1;
06794             s1 = strsep(&stringp, "*");
06795             s2 = strsep(&stringp, "*");
06796             if (s2) {
06797                if (!ast_strlen_zero(p->cid_num))
06798                   ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
06799                else
06800                   ast_set_callerid(chan, s1, NULL, s1);
06801                ast_copy_string(exten, s2, sizeof(exten));
06802             } else
06803                ast_copy_string(exten, s1, sizeof(exten));
06804          } else if (p->sig == SIG_FEATD)
06805             ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d.  Assuming E&M Wink instead\n", p->channel);
06806       }
06807       if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
06808          if (exten[0] == '*') {
06809             char *stringp=NULL;
06810             ast_copy_string(exten2, exten, sizeof(exten2));
06811             /* Parse out extension and callerid */
06812             stringp=exten2 +1;
06813             s1 = strsep(&stringp, "#");
06814             s2 = strsep(&stringp, "#");
06815             if (s2) {
06816                if (!ast_strlen_zero(p->cid_num))
06817                   ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
06818                else
06819                   if (*(s1 + 2))
06820                      ast_set_callerid(chan, s1 + 2, NULL, s1 + 2);
06821                ast_copy_string(exten, s2 + 1, sizeof(exten));
06822             } else
06823                ast_copy_string(exten, s1 + 2, sizeof(exten));
06824          } else
06825             ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d.  Assuming E&M Wink instead\n", p->channel);
06826       }
06827       if ((p->sig == SIG_E911) || (p->sig == SIG_FGC_CAMAMF)) {
06828          if (exten[0] == '*') {
06829             char *stringp=NULL;
06830             ast_copy_string(exten2, exten, sizeof(exten2));
06831             /* Parse out extension and callerid */
06832             stringp=exten2 +1;
06833             s1 = strsep(&stringp, "#");
06834             s2 = strsep(&stringp, "#");
06835             if (s2 && (*(s2 + 1) == '0')) {
06836                if (*(s2 + 2))
06837                   ast_set_callerid(chan, s2 + 2, NULL, s2 + 2);
06838             }
06839             if (s1)  ast_copy_string(exten, s1, sizeof(exten));
06840             else ast_copy_string(exten, "911", sizeof(exten));
06841          } else
06842             ast_log(LOG_WARNING, "Got a non-E911/FGC CAMA input on channel %d.  Assuming E&M Wink instead\n", p->channel);
06843       }
06844       if (p->sig == SIG_FEATB) {
06845          if (exten[0] == '*') {
06846             char *stringp=NULL;
06847             ast_copy_string(exten2, exten, sizeof(exten2));
06848             /* Parse out extension and callerid */
06849             stringp=exten2 +1;
06850             s1 = strsep(&stringp, "#");
06851             ast_copy_string(exten, exten2 + 1, sizeof(exten));
06852          } else
06853             ast_log(LOG_WARNING, "Got a non-Feature Group B input on channel %d.  Assuming E&M Wink instead\n", p->channel);
06854       }
06855       if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
06856          dahdi_wink(p, idx);
06857                         /* some switches require a minimum guard time between
06858                            the last FGD wink and something that answers
06859                            immediately. This ensures it */
06860                         if (ast_safe_sleep(chan,100)) goto quit;
06861       }
06862       dahdi_enable_ec(p);
06863       if (NEED_MFDETECT(p)) {
06864          if (p->dsp) {
06865             if (!p->hardwaredtmf)
06866                ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); 
06867             else {
06868                ast_dsp_free(p->dsp);
06869                p->dsp = NULL;
06870             }
06871          }
06872       }
06873 
06874       if (ast_exists_extension(chan, chan->context, exten, 1, chan->cid.cid_num)) {
06875          ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06876          if (p->dsp) ast_dsp_digitreset(p->dsp);
06877          res = ast_pbx_run(chan);
06878          if (res) {
06879             ast_log(LOG_WARNING, "PBX exited non-zero\n");
06880             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06881          }
06882          goto quit;
06883       } else {
06884          ast_verb(2, "Unknown extension '%s' in context '%s' requested\n", exten, chan->context);
06885          sleep(2);
06886          res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_INFO);
06887          if (res < 0)
06888             ast_log(LOG_WARNING, "Unable to start special tone on %d\n", p->channel);
06889          else
06890             sleep(1);
06891          res = ast_streamfile(chan, "ss-noservice", chan->language);
06892          if (res >= 0)
06893             ast_waitstream(chan, "");
06894          res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06895          ast_hangup(chan);
06896          goto quit;
06897       }
06898       break;
06899    case SIG_FXOLS:
06900    case SIG_FXOGS:
06901    case SIG_FXOKS:
06902       /* Read the first digit */
06903       timeout = firstdigittimeout;
06904       /* If starting a threeway call, never timeout on the first digit so someone
06905          can use flash-hook as a "hold" feature */
06906       if (p->subs[SUB_THREEWAY].owner) 
06907          timeout = 999999;
06908       while (len < AST_MAX_EXTENSION-1) {
06909          /* Read digit unless it's supposed to be immediate, in which case the
06910             only answer is 's' */
06911          if (p->immediate) 
06912             res = 's';
06913          else
06914             res = ast_waitfordigit(chan, timeout);
06915          timeout = 0;
06916          if (res < 0) {
06917             ast_debug(1, "waitfordigit returned < 0...\n");
06918             res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06919             ast_hangup(chan);
06920             goto quit;
06921          } else if (res)  {
06922             ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res, res, timeout);
06923             exten[len++]=res;
06924             exten[len] = '\0';
06925          }
06926          if (!ast_ignore_pattern(chan->context, exten))
06927             tone_zone_play_tone(p->subs[idx].dfd, -1);
06928          else
06929             tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
06930          if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num) && strcmp(exten, ast_parking_ext())) {
06931             if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
06932                if (getforward) {
06933                   /* Record this as the forwarding extension */
06934                   ast_copy_string(p->call_forward, exten, sizeof(p->call_forward)); 
06935                   ast_verb(3, "Setting call forward to '%s' on channel %d\n", p->call_forward, p->channel);
06936                   res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
06937                   if (res)
06938                      break;
06939                   usleep(500000);
06940                   res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06941                   sleep(1);
06942                   memset(exten, 0, sizeof(exten));
06943                   res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
06944                   len = 0;
06945                   getforward = 0;
06946                } else  {
06947                   res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06948                   ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06949                   if (!ast_strlen_zero(p->cid_num)) {
06950                      if (!p->hidecallerid)
06951                         ast_set_callerid(chan, p->cid_num, NULL, p->cid_num); 
06952                      else
06953                         ast_set_callerid(chan, NULL, NULL, p->cid_num); 
06954                   }
06955                   if (!ast_strlen_zero(p->cid_name)) {
06956                      if (!p->hidecallerid)
06957                         ast_set_callerid(chan, NULL, p->cid_name, NULL);
06958                   }
06959                   ast_setstate(chan, AST_STATE_RING);
06960                   dahdi_enable_ec(p);
06961                   res = ast_pbx_run(chan);
06962                   if (res) {
06963                      ast_log(LOG_WARNING, "PBX exited non-zero\n");
06964                      res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06965                   }
06966                   goto quit;
06967                }
06968             } else {
06969                /* It's a match, but they just typed a digit, and there is an ambiguous match,
06970                   so just set the timeout to matchdigittimeout and wait some more */
06971                timeout = matchdigittimeout;
06972             }
06973          } else if (res == 0) {
06974             ast_debug(1, "not enough digits (and no ambiguous match)...\n");
06975             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06976             dahdi_wait_event(p->subs[idx].dfd);
06977             ast_hangup(chan);
06978             goto quit;
06979          } else if (p->callwaiting && !strcmp(exten, "*70")) {
06980             ast_verb(3, "Disabling call waiting on %s\n", chan->name);
06981             /* Disable call waiting if enabled */
06982             p->callwaiting = 0;
06983             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
06984             if (res) {
06985                ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", 
06986                   chan->name, strerror(errno));
06987             }
06988             len = 0;
06989             ioctl(p->subs[idx].dfd,DAHDI_CONFDIAG,&len);
06990             memset(exten, 0, sizeof(exten));
06991             timeout = firstdigittimeout;
06992                
06993          } else if (!strcmp(exten,ast_pickup_ext())) {
06994             /* Scan all channels and see if there are any
06995              * ringing channels that have call groups
06996              * that equal this channels pickup group  
06997              */
06998             if (idx == SUB_REAL) {
06999                /* Switch us from Third call to Call Wait */
07000                if (p->subs[SUB_THREEWAY].owner) {
07001                   /* If you make a threeway call and the *8# a call, it should actually 
07002                      look like a callwait */
07003                   alloc_sub(p, SUB_CALLWAIT);   
07004                   swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
07005                   unalloc_sub(p, SUB_THREEWAY);
07006                }
07007                dahdi_enable_ec(p);
07008                if (ast_pickup_call(chan)) {
07009                   ast_debug(1, "No call pickup possible...\n");
07010                   res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07011                   dahdi_wait_event(p->subs[idx].dfd);
07012                }
07013                ast_hangup(chan);
07014                goto quit;
07015             } else {
07016                ast_log(LOG_WARNING, "Huh?  Got *8# on call not on real\n");
07017                ast_hangup(chan);
07018                goto quit;
07019             }
07020             
07021          } else if (!p->hidecallerid && !strcmp(exten, "*67")) {
07022             ast_verb(3, "Disabling Caller*ID on %s\n", chan->name);
07023             /* Disable Caller*ID if enabled */
07024             p->hidecallerid = 1;
07025             if (chan->cid.cid_num)
07026                ast_free(chan->cid.cid_num);
07027             chan->cid.cid_num = NULL;
07028             if (chan->cid.cid_name)
07029                ast_free(chan->cid.cid_name);
07030             chan->cid.cid_name = NULL;
07031             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07032             if (res) {
07033                ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", 
07034                   chan->name, strerror(errno));
07035             }
07036             len = 0;
07037             memset(exten, 0, sizeof(exten));
07038             timeout = firstdigittimeout;
07039          } else if (p->callreturn && !strcmp(exten, "*69")) {
07040             res = 0;
07041             if (!ast_strlen_zero(p->lastcid_num)) {
07042                res = ast_say_digit_str(chan, p->lastcid_num, "", chan->language);
07043             }
07044             if (!res)
07045                res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07046             break;
07047          } else if (!strcmp(exten, "*78")) {
07048             dahdi_dnd(p, 1);
07049             /* Do not disturb */
07050             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07051             getforward = 0;
07052             memset(exten, 0, sizeof(exten));
07053             len = 0;
07054          } else if (!strcmp(exten, "*79")) {
07055             dahdi_dnd(p, 0);
07056             /* Do not disturb */
07057             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07058             getforward = 0;
07059             memset(exten, 0, sizeof(exten));
07060             len = 0;
07061          } else if (p->cancallforward && !strcmp(exten, "*72")) {
07062             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07063             getforward = 1;
07064             memset(exten, 0, sizeof(exten));
07065             len = 0;
07066          } else if (p->cancallforward && !strcmp(exten, "*73")) {
07067             ast_verb(3, "Cancelling call forwarding on channel %d\n", p->channel);
07068             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07069             memset(p->call_forward, 0, sizeof(p->call_forward));
07070             getforward = 0;
07071             memset(exten, 0, sizeof(exten));
07072             len = 0;
07073          } else if ((p->transfer || p->canpark) && !strcmp(exten, ast_parking_ext()) && 
07074                   p->subs[SUB_THREEWAY].owner &&
07075                   ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
07076             /* This is a three way call, the main call being a real channel, 
07077                and we're parking the first call. */
07078             ast_masq_park_call(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), chan, 0, NULL);
07079             ast_verb(3, "Parking call to '%s'\n", chan->name);
07080             break;
07081          } else if (!ast_strlen_zero(p->lastcid_num) && !strcmp(exten, "*60")) {
07082             ast_verb(3, "Blacklisting number %s\n", p->lastcid_num);
07083             res = ast_db_put("blacklist", p->lastcid_num, "1");
07084             if (!res) {
07085                res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07086                memset(exten, 0, sizeof(exten));
07087                len = 0;
07088             }
07089          } else if (p->hidecallerid && !strcmp(exten, "*82")) {
07090             ast_verb(3, "Enabling Caller*ID on %s\n", chan->name);
07091             /* Enable Caller*ID if enabled */
07092             p->hidecallerid = 0;
07093             if (chan->cid.cid_num)
07094                ast_free(chan->cid.cid_num);
07095             chan->cid.cid_num = NULL;
07096             if (chan->cid.cid_name)
07097                ast_free(chan->cid.cid_name);
07098             chan->cid.cid_name = NULL;
07099             ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
07100             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07101             if (res) {
07102                ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", 
07103                   chan->name, strerror(errno));
07104             }
07105             len = 0;
07106             memset(exten, 0, sizeof(exten));
07107             timeout = firstdigittimeout;
07108          } else if (!strcmp(exten, "*0")) {
07109             struct ast_channel *nbridge = 
07110                p->subs[SUB_THREEWAY].owner;
07111             struct dahdi_pvt *pbridge = NULL;
07112               /* set up the private struct of the bridged one, if any */
07113             if (nbridge && ast_bridged_channel(nbridge)) 
07114                pbridge = ast_bridged_channel(nbridge)->tech_pvt;
07115             if (nbridge && pbridge && 
07116                 (nbridge->tech == &dahdi_tech) && 
07117                 (ast_bridged_channel(nbridge)->tech == &dahdi_tech) &&
07118                 ISTRUNK(pbridge)) {
07119                int func = DAHDI_FLASH;
07120                /* Clear out the dial buffer */
07121                p->dop.dialstr[0] = '\0';
07122                /* flash hookswitch */
07123                if ((ioctl(pbridge->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
07124                   ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n", 
07125                      nbridge->name, strerror(errno));
07126                }
07127                swap_subs(p, SUB_REAL, SUB_THREEWAY);
07128                unalloc_sub(p, SUB_THREEWAY);
07129                p->owner = p->subs[SUB_REAL].owner;
07130                if (ast_bridged_channel(p->subs[SUB_REAL].owner))
07131                   ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
07132                ast_hangup(chan);
07133                goto quit;
07134             } else {
07135                tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07136                dahdi_wait_event(p->subs[idx].dfd);
07137                tone_zone_play_tone(p->subs[idx].dfd, -1);
07138                swap_subs(p, SUB_REAL, SUB_THREEWAY);
07139                unalloc_sub(p, SUB_THREEWAY);
07140                p->owner = p->subs[SUB_REAL].owner;
07141                ast_hangup(chan);
07142                goto quit;
07143             }              
07144          } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) &&
07145                      ((exten[0] != '*') || (strlen(exten) > 2))) {
07146             ast_debug(1, "Can't match %s from '%s' in context %s\n", exten, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context);
07147             break;
07148          }
07149          if (!timeout)
07150             timeout = gendigittimeout;
07151          if (len && !ast_ignore_pattern(chan->context, exten))
07152             tone_zone_play_tone(p->subs[idx].dfd, -1);
07153       }
07154       break;
07155    case SIG_FXSLS:
07156    case SIG_FXSGS:
07157    case SIG_FXSKS:
07158 #ifdef HAVE_PRI
07159       if (p->pri) {
07160          /* This is a GR-303 trunk actually.  Wait for the first ring... */
07161          struct ast_frame *f;
07162          int res;
07163          time_t start;
07164 
07165          time(&start);
07166          ast_setstate(chan, AST_STATE_RING);
07167          while (time(NULL) < start + 3) {
07168             res = ast_waitfor(chan, 1000);
07169             if (res) {
07170                f = ast_read(chan);
07171                if (!f) {
07172                   ast_log(LOG_WARNING, "Whoa, hangup while waiting for first ring!\n");
07173                   ast_hangup(chan);
07174                   goto quit;
07175                } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RING)) {
07176                   res = 1;
07177                } else
07178                   res = 0;
07179                ast_frfree(f);
07180                if (res) {
07181                   ast_debug(1, "Got ring!\n");
07182                   res = 0;
07183                   break;
07184                }
07185             }
07186          }
07187       }
07188 #endif
07189       /* check for SMDI messages */
07190       if (p->use_smdi && p->smdi_iface) {
07191          smdi_msg = ast_smdi_md_message_wait(p->smdi_iface, SMDI_MD_WAIT_TIMEOUT);
07192 
07193          if (smdi_msg != NULL) {
07194             ast_copy_string(chan->exten, smdi_msg->fwd_st, sizeof(chan->exten));
07195 
07196             if (smdi_msg->type == 'B')
07197                pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "b");
07198             else if (smdi_msg->type == 'N')
07199                pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "u");
07200 
07201             ast_debug(1, "Recieved SMDI message on %s\n", chan->name);
07202          } else {
07203             ast_log(LOG_WARNING, "SMDI enabled but no SMDI message present\n");
07204          }
07205       }
07206 
07207       if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {
07208             number = smdi_msg->calling_st;
07209 
07210       /* If we want caller id, we're in a prering state due to a polarity reversal
07211        * and we're set to use a polarity reversal to trigger the start of caller id,
07212        * grab the caller id and wait for ringing to start... */
07213       } else if (p->use_callerid && (chan->_state == AST_STATE_PRERING && (p->cid_start == CID_START_POLARITY || p->cid_start == CID_START_POLARITY_IN))) {
07214          /* If set to use DTMF CID signalling, listen for DTMF */
07215          if (p->cid_signalling == CID_SIG_DTMF) {
07216             int k = 0;
07217             cs = NULL;
07218             ast_debug(1, "Receiving DTMF cid on "
07219                "channel %s\n", chan->name);
07220             dahdi_setlinear(p->subs[idx].dfd, 0);
07221             res = 2000;
07222             for (;;) {
07223                struct ast_frame *f;
07224                res = ast_waitfor(chan, res);
07225                if (res <= 0) {
07226                   ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
07227                      "Exiting simple switch\n");
07228                   ast_hangup(chan);
07229                   goto quit;
07230                } 
07231                f = ast_read(chan);
07232                if (!f)
07233                   break;
07234                if (f->frametype == AST_FRAME_DTMF) {
07235                   dtmfbuf[k++] = f->subclass;
07236                   ast_debug(1, "CID got digit '%c'\n", f->subclass);
07237                   res = 2000;
07238                }
07239                ast_frfree(f);
07240                if (chan->_state == AST_STATE_RING ||
07241                    chan->_state == AST_STATE_RINGING) 
07242                   break; /* Got ring */
07243             }
07244             dtmfbuf[k] = '\0';
07245             dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
07246             /* Got cid and ring. */
07247             ast_debug(1, "CID got string '%s'\n", dtmfbuf);
07248             callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
07249             ast_debug(1, "CID is '%s', flags %d\n", 
07250                dtmfcid, flags);
07251             /* If first byte is NULL, we have no cid */
07252             if (!ast_strlen_zero(dtmfcid)) 
07253                number = dtmfcid;
07254             else
07255                number = NULL;
07256          /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
07257          } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
07258             cs = callerid_new(p->cid_signalling);
07259             if (cs) {
07260                samples = 0;
07261 #if 1
07262                bump_gains(p);
07263 #endif
07264                /* Take out of linear mode for Caller*ID processing */
07265                dahdi_setlinear(p->subs[idx].dfd, 0);
07266                
07267                /* First we wait and listen for the Caller*ID */
07268                for (;;) {  
07269                   i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07270                   if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
07271                      ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07272                      callerid_free(cs);
07273                      ast_hangup(chan);
07274                      goto quit;
07275                   }
07276                   if (i & DAHDI_IOMUX_SIGEVENT) {
07277                      res = dahdi_get_event(p->subs[idx].dfd);
07278                      ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
07279 
07280                      if (p->cid_signalling == CID_SIG_V23_JP) {
07281                         if (res == DAHDI_EVENT_RINGBEGIN) {
07282                            res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
07283                            usleep(1);
07284                         }
07285                      } else {
07286                         res = 0;
07287                         break;
07288                      }
07289                   } else if (i & DAHDI_IOMUX_READ) {
07290                      res = read(p->subs[idx].dfd, buf, sizeof(buf));
07291                      if (res < 0) {
07292                         if (errno != ELAST) {
07293                            ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07294                            callerid_free(cs);
07295                            ast_hangup(chan);
07296                            goto quit;
07297                         }
07298                         break;
07299                      }
07300                      samples += res;
07301 
07302                      if  (p->cid_signalling == CID_SIG_V23_JP) {
07303                         res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
07304                      } else {
07305                         res = callerid_feed(cs, buf, res, AST_LAW(p));
07306                      }
07307 
07308                      if (res < 0) {
07309                         ast_log(LOG_WARNING, "CallerID feed failed on channel '%s'\n", chan->name);
07310                         break;
07311                      } else if (res)
07312                         break;
07313                      else if (samples > (8000 * 10))
07314                         break;
07315                   }
07316                }
07317                if (res == 1) {
07318                   callerid_get(cs, &name, &number, &flags);
07319                   ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
07320                }
07321 
07322                if (p->cid_signalling == CID_SIG_V23_JP) {
07323                   res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
07324                   usleep(1);
07325                   res = 4000;
07326                } else {
07327 
07328                   /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */ 
07329                   res = 2000;
07330                }
07331 
07332                for (;;) {
07333                   struct ast_frame *f;
07334                   res = ast_waitfor(chan, res);
07335                   if (res <= 0) {
07336                      ast_log(LOG_WARNING, "CID timed out waiting for ring. "
07337                         "Exiting simple switch\n");
07338                      ast_hangup(chan);
07339                      goto quit;
07340                   } 
07341                   if (!(f = ast_read(chan))) {
07342                      ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n");
07343                      ast_hangup(chan);
07344                      goto quit;
07345                   }
07346                   ast_frfree(f);
07347                   if (chan->_state == AST_STATE_RING ||
07348                       chan->_state == AST_STATE_RINGING) 
07349                      break; /* Got ring */
07350                }
07351    
07352                /* We must have a ring by now, so, if configured, lets try to listen for
07353                 * distinctive ringing */ 
07354                if (p->usedistinctiveringdetection) {
07355                   len = 0;
07356                   distMatches = 0;
07357                   /* Clear the current ring data array so we dont have old data in it. */
07358                   for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
07359                      curRingData[receivedRingT] = 0;
07360                   receivedRingT = 0;
07361                   counter = 0;
07362                   counter1 = 0;
07363                   /* Check to see if context is what it should be, if not set to be. */
07364                   if (strcmp(p->context,p->defcontext) != 0) {
07365                      ast_copy_string(p->context, p->defcontext, sizeof(p->context));
07366                      ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
07367                   }
07368       
07369                   for (;;) {  
07370                      i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07371                      if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
07372                         ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07373                         callerid_free(cs);
07374                         ast_hangup(chan);
07375                         goto quit;
07376                      }
07377                      if (i & DAHDI_IOMUX_SIGEVENT) {
07378                         res = dahdi_get_event(p->subs[idx].dfd);
07379                         ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
07380                         res = 0;
07381                         /* Let us detect distinctive ring */
07382       
07383                         curRingData[receivedRingT] = p->ringt;
07384       
07385                         if (p->ringt < p->ringt_base/2)
07386                            break;
07387                         /* Increment the ringT counter so we can match it against
07388                            values in chan_dahdi.conf for distinctive ring */
07389                         if (++receivedRingT == ARRAY_LEN(curRingData))
07390                            break;
07391                      } else if (i & DAHDI_IOMUX_READ) {
07392                         res = read(p->subs[idx].dfd, buf, sizeof(buf));
07393                         if (res < 0) {
07394                            if (errno != ELAST) {
07395                               ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07396                               callerid_free(cs);
07397                               ast_hangup(chan);
07398                               goto quit;
07399                            }
07400                            break;
07401                         }
07402                         if (p->ringt) 
07403                            p->ringt--;
07404                         if (p->ringt == 1) {
07405                            res = -1;
07406                            break;
07407                         }
07408                      }
07409                   }
07410                      /* this only shows up if you have n of the dring patterns filled in */
07411                   ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
07412                   for (counter = 0; counter < 3; counter++) {
07413                      /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
07414                      channel */
07415                      distMatches = 0;
07416                      for (counter1 = 0; counter1 < 3; counter1++) {
07417                         ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
07418                         if (p->drings.ringnum[counter].ring[counter1] == -1) {
07419                            ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
07420                            curRingData[counter1]);
07421                            distMatches++;
07422                         }
07423                         else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
07424                             curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
07425                            ast_verb(3, "Ring pattern matched in range: %d to %d\n",
07426                            (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
07427                            (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
07428                            distMatches++;
07429                         }
07430                      }
07431 
07432                      if (distMatches == 3) {
07433                         /* The ring matches, set the context to whatever is for distinctive ring.. */
07434                         ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context));
07435                         ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context));
07436                         ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
07437                         break;
07438                      }
07439                   }
07440                }
07441                /* Restore linear mode (if appropriate) for Caller*ID processing */
07442                dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
07443 #if 1
07444                restore_gains(p);
07445 #endif            
07446             } else
07447                ast_log(LOG_WARNING, "Unable to get caller ID space\n");       
07448          } else {
07449             ast_log(LOG_WARNING, "Channel %s in prering "
07450                "state, but I have nothing to do. "
07451                "Terminating simple switch, should be "
07452                "restarted by the actual ring.\n", 
07453                chan->name);
07454             ast_hangup(chan);
07455             goto quit;
07456          }
07457       } else if (p->use_callerid && p->cid_start == CID_START_RING) {
07458                         if (p->cid_signalling == CID_SIG_DTMF) {
07459                                 int k = 0;
07460                                 cs = NULL;
07461                                 dahdi_setlinear(p->subs[idx].dfd, 0);
07462                                 res = 2000;
07463                                 for (;;) {
07464                                         struct ast_frame *f;
07465                                         res = ast_waitfor(chan, res);
07466                                         if (res <= 0) {
07467                                                 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
07468                                                                 "Exiting simple switch\n");
07469                                                 ast_hangup(chan);
07470                                                 return NULL;
07471                                         }
07472                                         f = ast_read(chan);
07473                                         if (f->frametype == AST_FRAME_DTMF) {
07474                                                 dtmfbuf[k++] = f->subclass;
07475                                                 ast_log(LOG_DEBUG, "CID got digit '%c'\n", f->subclass);
07476                                                 res = 2000;
07477                                         }
07478                                         ast_frfree(f);
07479 
07480                                         if (p->ringt_base == p->ringt)
07481                                                 break;
07482 
07483                                 }
07484                                 dtmfbuf[k] = '\0';
07485                                 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
07486                                 /* Got cid and ring. */
07487                                 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
07488                                 ast_log(LOG_DEBUG, "CID is '%s', flags %d\n",
07489                                                 dtmfcid, flags);
07490                                 /* If first byte is NULL, we have no cid */
07491                                 if (!ast_strlen_zero(dtmfcid))
07492                                         number = dtmfcid;
07493                                 else
07494                                         number = NULL;
07495                                 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
07496                         } else {
07497          /* FSK Bell202 callerID */
07498          cs = callerid_new(p->cid_signalling);
07499          if (cs) {
07500 #if 1
07501             bump_gains(p);
07502 #endif            
07503             samples = 0;
07504             len = 0;
07505             distMatches = 0;
07506             /* Clear the current ring data array so we dont have old data in it. */
07507             for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
07508                curRingData[receivedRingT] = 0;
07509             receivedRingT = 0;
07510             counter = 0;
07511             counter1 = 0;
07512             /* Check to see if context is what it should be, if not set to be. */
07513             if (strcmp(p->context,p->defcontext) != 0) {
07514                ast_copy_string(p->context, p->defcontext, sizeof(p->context));
07515                ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
07516             }
07517 
07518             /* Take out of linear mode for Caller*ID processing */
07519             dahdi_setlinear(p->subs[idx].dfd, 0);
07520             for (;;) {  
07521                i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07522                if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
07523                   ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07524                   callerid_free(cs);
07525                   ast_hangup(chan);
07526                   goto quit;
07527                }
07528                if (i & DAHDI_IOMUX_SIGEVENT) {
07529                   res = dahdi_get_event(p->subs[idx].dfd);
07530                   ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
07531                   /* If we get a PR event, they hung up while processing calerid */
07532                   if ( res == DAHDI_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
07533                      ast_log(LOG_DEBUG, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
07534                      p->polarity = POLARITY_IDLE;
07535                      callerid_free(cs);
07536                      ast_hangup(chan);
07537                      goto quit;
07538                   }
07539                   res = 0;
07540                   /* Let us detect callerid when the telco uses distinctive ring */
07541 
07542                   curRingData[receivedRingT] = p->ringt;
07543 
07544                   if (p->ringt < p->ringt_base/2)
07545                      break;
07546                   /* Increment the ringT counter so we can match it against
07547                      values in chan_dahdi.conf for distinctive ring */
07548                   if (++receivedRingT == ARRAY_LEN(curRingData))
07549                      break;
07550                } else if (i & DAHDI_IOMUX_READ) {
07551                   res = read(p->subs[idx].dfd, buf, sizeof(buf));
07552                   if (res < 0) {
07553                      if (errno != ELAST) {
07554                         ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07555                         callerid_free(cs);
07556                         ast_hangup(chan);
07557                         goto quit;
07558                      }
07559                      break;
07560                   }
07561                   if (p->ringt) 
07562                      p->ringt--;
07563                   if (p->ringt == 1) {
07564                      res = -1;
07565                      break;
07566                   }
07567                   samples += res;
07568                   res = callerid_feed(cs, buf, res, AST_LAW(p));
07569                   if (res < 0) {
07570                      ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
07571                      break;
07572                   } else if (res)
07573                      break;
07574                   else if (samples > (8000 * 10))
07575                      break;
07576                }
07577             }
07578             if (res == 1) {
07579                callerid_get(cs, &name, &number, &flags);
07580                ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
07581             }
07582             if (distinctiveringaftercid == 1) {
07583                /* Clear the current ring data array so we dont have old data in it. */
07584                for (receivedRingT = 0; receivedRingT < 3; receivedRingT++) {
07585                   curRingData[receivedRingT] = 0;
07586                }
07587                receivedRingT = 0;
07588                ast_verb(3, "Detecting post-CID distinctive ring\n");
07589                for (;;) {
07590                   i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07591                   if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i)))    {
07592                      ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07593                      callerid_free(cs);
07594                      ast_hangup(chan);
07595                      goto quit;
07596                   }
07597                   if (i & DAHDI_IOMUX_SIGEVENT) {
07598                      res = dahdi_get_event(p->subs[idx].dfd);
07599                      ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
07600                      res = 0;
07601                      /* Let us detect callerid when the telco uses distinctive ring */
07602 
07603                      curRingData[receivedRingT] = p->ringt;
07604 
07605                      if (p->ringt < p->ringt_base/2)
07606                         break;
07607                      /* Increment the ringT counter so we can match it against
07608                         values in chan_dahdi.conf for distinctive ring */
07609                      if (++receivedRingT == ARRAY_LEN(curRingData))
07610                         break;
07611                   } else if (i & DAHDI_IOMUX_READ) {
07612                      res = read(p->subs[idx].dfd, buf, sizeof(buf));
07613                      if (res < 0) {
07614                         if (errno != ELAST) {
07615                            ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07616                            callerid_free(cs);
07617                            ast_hangup(chan);
07618                            goto quit;
07619                         }
07620                         break;
07621                      }
07622                   if (p->ringt)
07623                      p->ringt--;
07624                      if (p->ringt == 1) {
07625                         res = -1;
07626                         break;
07627                      }
07628                   }
07629                }
07630             }
07631             if (p->usedistinctiveringdetection) {
07632                   /* this only shows up if you have n of the dring patterns filled in */
07633                ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
07634 
07635                for (counter = 0; counter < 3; counter++) {
07636                   /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
07637                   channel */
07638                      /* this only shows up if you have n of the dring patterns filled in */
07639                   ast_verb(3, "Checking %d,%d,%d\n",
07640                         p->drings.ringnum[counter].ring[0],
07641                         p->drings.ringnum[counter].ring[1],
07642                         p->drings.ringnum[counter].ring[2]);
07643                   distMatches = 0;
07644                   for (counter1 = 0; counter1 < 3; counter1++) {
07645                      ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
07646                      if (p->drings.ringnum[counter].ring[counter1] == -1) {
07647                         ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
07648                         curRingData[counter1]);
07649                         distMatches++;
07650                      }
07651                      else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
07652                          curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
07653                         ast_verb(3, "Ring pattern matched in range: %d to %d\n",
07654                         (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
07655                         (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
07656                         distMatches++;
07657                      }
07658                   }
07659                   if (distMatches == 3) {
07660                      /* The ring matches, set the context to whatever is for distinctive ring.. */
07661                      ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context));
07662                      ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context));
07663                      ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
07664                      break;
07665                   }
07666                }
07667             }
07668             /* Restore linear mode (if appropriate) for Caller*ID processing */
07669             dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
07670 #if 1
07671             restore_gains(p);
07672 #endif            
07673             if (res < 0) {
07674                ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", chan->name);
07675             }
07676          } else
07677             ast_log(LOG_WARNING, "Unable to get caller ID space\n");
07678       }
07679       }
07680       else
07681          cs = NULL;
07682 
07683       if (number)
07684          ast_shrink_phone_number(number);
07685       ast_set_callerid(chan, number, name, number);
07686 
07687       if (smdi_msg)
07688          ASTOBJ_UNREF(smdi_msg, ast_smdi_md_message_destroy);
07689 
07690       if (cs)
07691          callerid_free(cs);
07692       /* If the CID had Message waiting payload, assume that this for MWI only and hangup the call */
07693       if (flags & CID_MSGWAITING) {
07694          ast_log(LOG_NOTICE, "MWI: Channel %d message waiting!\n", p->channel);
07695          notify_message(p->mailbox, 1);
07696          /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
07697          if (p->mwimonitor_rpas) {
07698             ast_hangup(chan);
07699             return NULL;
07700          }
07701       } else if (flags & CID_NOMSGWAITING) {
07702          ast_log(LOG_NOTICE, "MWI: Channel %d no message waiting!\n", p->channel);
07703          notify_message(p->mailbox, 0);
07704          /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
07705          if (p->mwimonitor_rpas) {
07706             ast_hangup(chan);
07707             return NULL;
07708          }
07709       }
07710 
07711       ast_setstate(chan, AST_STATE_RING);
07712       chan->rings = 1;
07713       p->ringt = p->ringt_base;
07714       res = ast_pbx_run(chan);
07715       if (res) {
07716          ast_hangup(chan);
07717          ast_log(LOG_WARNING, "PBX exited non-zero\n");
07718       }
07719       goto quit;
07720    default:
07721       ast_log(LOG_WARNING, "Don't know how to handle simple switch with signalling %s on channel %d\n", sig2str(p->sig), p->channel);
07722       res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07723       if (res < 0)
07724             ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
07725    }
07726    res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07727    if (res < 0)
07728          ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
07729    ast_hangup(chan);
07730 quit:
07731    ast_mutex_lock(&ss_thread_lock);
07732    ss_thread_count--;
07733    ast_cond_signal(&ss_thread_complete);
07734    ast_mutex_unlock(&ss_thread_lock);
07735    return NULL;
07736 }
07737 
07738 struct mwi_thread_data {
07739    struct dahdi_pvt *pvt;
07740    unsigned char buf[READ_SIZE];
07741    size_t len;
07742 };
07743 
07744 static int calc_energy(const unsigned char *buf, int len, int law)
07745 {
07746    int x;
07747    int sum = 0;
07748 
07749    if (!len)
07750       return 0;
07751 
07752    for (x = 0; x < len; x++)
07753       sum += abs(law == AST_FORMAT_ULAW ? AST_MULAW(buf[x]) : AST_ALAW(buf[x]));
07754 
07755    return sum / len;
07756 }
07757 
07758 static void *mwi_thread(void *data)
07759 {
07760    struct mwi_thread_data *mtd = data;
07761    struct callerid_state *cs;
07762    pthread_t threadid;
07763    int samples = 0;
07764    char *name, *number;
07765    int flags;
07766    int i, res;
07767    unsigned int spill_done = 0;
07768    int spill_result = -1;
07769    
07770    if (!(cs = callerid_new(mtd->pvt->cid_signalling))) {
07771       mtd->pvt->mwimonitoractive = 0;
07772 
07773       return NULL;
07774    }
07775    
07776    callerid_feed(cs, mtd->buf, mtd->len, AST_LAW(mtd->pvt));
07777 
07778    bump_gains(mtd->pvt);
07779 
07780    for (;;) {  
07781       i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07782       if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
07783          ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07784          goto quit;
07785       }
07786 
07787       if (i & DAHDI_IOMUX_SIGEVENT) {
07788          struct ast_channel *chan;
07789 
07790          /* If we get an event, screen out events that we do not act on.
07791           * Otherwise, cancel and go to the simple switch to let it deal with it.
07792           */
07793          res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
07794 
07795          switch (res) {
07796          case DAHDI_EVENT_NEONMWI_ACTIVE:
07797          case DAHDI_EVENT_NEONMWI_INACTIVE:
07798          case DAHDI_EVENT_NONE:
07799          case DAHDI_EVENT_BITSCHANGED:
07800             break;
07801          case DAHDI_EVENT_NOALARM:
07802             mtd->pvt->inalarm = 0;
07803             ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", mtd->pvt->channel);
07804             manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
07805                "Channel: %d\r\n", mtd->pvt->channel);
07806             break;
07807          case DAHDI_EVENT_ALARM:
07808             mtd->pvt->inalarm = 1;
07809             res = get_alarms(mtd->pvt);
07810             handle_alarms(mtd->pvt, res);
07811             break; /* What to do on channel alarm ???? -- fall thru intentionally?? */
07812          default:
07813             ast_log(LOG_NOTICE, "Got event %d (%s)...  Passing along to ss_thread\n", res, event2str(res));
07814             callerid_free(cs);
07815             
07816             restore_gains(mtd->pvt);
07817             mtd->pvt->ringt = mtd->pvt->ringt_base;
07818 
07819             if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, 0))) {
07820                if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
07821                   ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", mtd->pvt->channel);
07822                   res = tone_zone_play_tone(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
07823                   if (res < 0)
07824                      ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", mtd->pvt->channel);
07825                   ast_hangup(chan);
07826                   goto quit;
07827                }
07828                goto quit_no_clean;
07829 
07830             } else {
07831                ast_log(LOG_WARNING, "Could not create channel to handle call\n");
07832             }
07833          }
07834       } else if (i & DAHDI_IOMUX_READ) {
07835          if ((res = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
07836             if (errno != ELAST) {
07837                ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07838                goto quit;
07839             }
07840             break;
07841          }
07842          samples += res;
07843          if (!spill_done) {
07844             if ((spill_result = callerid_feed(cs, mtd->buf, res, AST_LAW(mtd->pvt))) < 0) {
07845                ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
07846                break;
07847             } else if (spill_result) {
07848                spill_done = 1;
07849             }
07850          } else {
07851             /* keep reading data until the energy level drops below the threshold
07852                so we don't get another 'trigger' on the remaining carrier signal
07853             */
07854             if (calc_energy(mtd->buf, res, AST_LAW(mtd->pvt)) <= mwilevel)
07855                break;
07856          }
07857          if (samples > (8000 * 4)) /*Termination case - time to give up*/
07858             break;
07859       }
07860    }
07861 
07862    if (spill_result == 1) {
07863       callerid_get(cs, &name, &number, &flags);
07864       if (flags & CID_MSGWAITING) {
07865          ast_log(LOG_NOTICE, "mwi: Have Messages on channel %d\n", mtd->pvt->channel);
07866          notify_message(mtd->pvt->mailbox, 1);
07867       } else if (flags & CID_NOMSGWAITING) {
07868          ast_log(LOG_NOTICE, "mwi: No Messages on channel %d\n", mtd->pvt->channel);
07869          notify_message(mtd->pvt->mailbox, 0);
07870       } else {
07871          ast_log(LOG_NOTICE, "mwi: Status unknown on channel %d\n", mtd->pvt->channel);
07872       }
07873    }
07874 
07875 
07876 quit:
07877    callerid_free(cs);
07878 
07879    restore_gains(mtd->pvt);
07880 
07881 quit_no_clean:
07882    mtd->pvt->mwimonitoractive = 0;
07883 
07884    ast_free(mtd);
07885 
07886    return NULL;
07887 }
07888 
07889 /* States for sending MWI message
07890  * First three states are required for send Ring Pulse Alert Signal 
07891  */
07892 enum mwisend_states {
07893    MWI_SEND_SA,
07894  MWI_SEND_SA_WAIT,
07895  MWI_SEND_PAUSE,
07896  MWI_SEND_SPILL,
07897  MWI_SEND_CLEANUP,
07898  MWI_SEND_DONE
07899 };
07900 
07901 static void *mwi_send_thread(void *data)
07902 {
07903    struct mwi_thread_data *mtd = data;
07904    struct timeval timeout_basis, suspend, now;
07905    int x, i, res;
07906    int num_read;
07907    enum mwisend_states mwi_send_state = MWI_SEND_SPILL; /*Assume FSK only */
07908 
07909    ast_mutex_lock(&mwi_thread_lock);
07910    mwi_thread_count++;
07911    ast_mutex_unlock(&mwi_thread_lock);
07912 
07913    /* Determine how this spill is to be sent */
07914    if(mwisend_rpas) {
07915       mwi_send_state = MWI_SEND_SA;
07916    }
07917 
07918    gettimeofday(&timeout_basis, NULL);
07919    
07920    mtd->pvt->cidspill = ast_calloc(1, MAX_CALLERID_SIZE);
07921    if (!mtd->pvt->cidspill) {
07922       mtd->pvt->mwisendactive = 0;
07923       ast_free(mtd);
07924       return NULL;
07925    }
07926    x = DAHDI_FLUSH_BOTH;
07927    res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
07928    x = 3000;
07929    ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x);
07930    mtd->pvt->cidlen = vmwi_generate(mtd->pvt->cidspill, has_voicemail(mtd->pvt), CID_MWI_TYPE_MDMF_FULL,
07931                             AST_LAW(mtd->pvt), mtd->pvt->cid_name, mtd->pvt->cid_num, 0);
07932    mtd->pvt->cidpos = 0;
07933 
07934    while (MWI_SEND_DONE != mwi_send_state) {
07935       num_read = 0;
07936       gettimeofday(&now, NULL);
07937       if ( 10 < (now.tv_sec - timeout_basis.tv_sec)) {
07938          ast_log(LOG_WARNING, "MWI Send TIMEOUT in state %d\n", mwi_send_state);
07939          goto quit;
07940       }
07941 
07942       i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07943       if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
07944          ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07945          goto quit;
07946       }
07947 
07948       if (i & DAHDI_IOMUX_SIGEVENT) {
07949          /* If we get an event, screen out events that we do not act on.
07950          * Otherwise, let handle_init_event determine what is needed
07951          */
07952          res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
07953          switch (res) {
07954             case DAHDI_EVENT_RINGEROFF:
07955                if(mwi_send_state == MWI_SEND_SA_WAIT) {
07956                   if (dahdi_set_hook(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
07957                      ast_log(LOG_WARNING, "Unable to finsh RP-AS: %s\n", strerror(errno));
07958                      goto quit;
07959                   }
07960                   mwi_send_state = MWI_SEND_PAUSE;
07961                   gettimeofday(&suspend, NULL);
07962                }
07963                break;
07964             case DAHDI_EVENT_RINGERON:
07965             case DAHDI_EVENT_HOOKCOMPLETE:
07966                break;
07967             default:
07968                /* Got to the default init event handler */
07969                if (0 < handle_init_event(mtd->pvt, res)) {
07970                   /* I've spawned a thread, get out */
07971                   goto quit;
07972                }
07973                break;
07974          }
07975       } else if (i & DAHDI_IOMUX_READ) {
07976          if ((num_read = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
07977             if (errno != ELAST) {
07978                ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07979                goto quit;
07980             }
07981             break;
07982          }
07983       }
07984       /* Perform mwi send action */
07985       switch ( mwi_send_state) {
07986          case MWI_SEND_SA:
07987             /* Send the Ring Pulse Signal Alert */
07988             res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &AS_RP_cadence);
07989             if (res) {
07990                ast_log(LOG_WARNING, "Unable to set RP-AS ring cadence: %s\n", strerror(errno));
07991                goto quit;
07992             }
07993             dahdi_set_hook(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_RING);
07994             mwi_send_state = MWI_SEND_SA_WAIT;
07995             break;
07996             case MWI_SEND_SA_WAIT:  /* do nothing until I get RINGEROFF event */
07997                break;
07998                case MWI_SEND_PAUSE:  /* Wait between alert and spill - min of 500 mS*/
07999                   gettimeofday(&now, NULL);
08000                   if ((int)(now.tv_sec - suspend.tv_sec) * 1000000 + (int)now.tv_usec - (int)suspend.tv_usec > 500000) {
08001                      mwi_send_state = MWI_SEND_SPILL;
08002                   }
08003                   break;
08004          case MWI_SEND_SPILL:
08005             /* We read some number of bytes.  Write an equal amount of data */
08006             if(0 < num_read) {
08007                if (num_read > mtd->pvt->cidlen - mtd->pvt->cidpos)
08008                   num_read = mtd->pvt->cidlen - mtd->pvt->cidpos;
08009                res = write(mtd->pvt->subs[SUB_REAL].dfd, mtd->pvt->cidspill + mtd->pvt->cidpos, num_read);
08010                if (res > 0) {
08011                   mtd->pvt->cidpos += res;
08012                   if (mtd->pvt->cidpos >= mtd->pvt->cidlen) {
08013                      ast_free(mtd->pvt->cidspill);
08014                      mtd->pvt->cidspill = NULL;
08015                      mtd->pvt->cidpos = 0;
08016                      mtd->pvt->cidlen = 0;
08017                      mwi_send_state = MWI_SEND_CLEANUP;
08018                   }
08019                } else {
08020                   ast_log(LOG_WARNING, "MWI Send Write failed: %s\n", strerror(errno));
08021                   goto quit;
08022                }
08023             }
08024             break;
08025          case MWI_SEND_CLEANUP:
08026             /* For now, do nothing */
08027             mwi_send_state = MWI_SEND_DONE;
08028             break;
08029          default:
08030             /* Should not get here, punt*/
08031             goto quit;
08032             break;
08033       }
08034    }
08035 
08036 quit:
08037    if(mtd->pvt->cidspill) {
08038       ast_free(mtd->pvt->cidspill);
08039       mtd->pvt->cidspill = NULL;
08040    }
08041    mtd->pvt->mwisendactive = 0;
08042    ast_free(mtd);
08043 
08044    ast_mutex_lock(&mwi_thread_lock);
08045    mwi_thread_count--;
08046    ast_cond_signal(&mwi_thread_complete);
08047    ast_mutex_unlock(&mwi_thread_lock);
08048 
08049    return NULL;
08050 }
08051 
08052 
08053 /* destroy a DAHDI channel, identified by its number */
08054 static int dahdi_destroy_channel_bynum(int channel)
08055 {
08056    struct dahdi_pvt *tmp = NULL;
08057    struct dahdi_pvt *prev = NULL;
08058 
08059    tmp = iflist;
08060    while (tmp) {
08061       if (tmp->channel == channel) {
08062          int x = DAHDI_FLASH;
08063          ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); /* important to create an event for dahdi_wait_event to register so that all ss_threads terminate */
08064          destroy_channel(prev, tmp, 1);
08065          ast_module_unref(ast_module_info->self);
08066          return RESULT_SUCCESS;
08067       }
08068       prev = tmp;
08069       tmp = tmp->next;
08070    }
08071    return RESULT_FAILURE;
08072 }
08073 
08074 /* returns < 0 = error, 0 event handled, >0 event handled and thread spawned */
08075 static int handle_init_event(struct dahdi_pvt *i, int event)
08076 {
08077    int res;
08078    int thread_spawned = 0;
08079    pthread_t threadid;
08080    struct ast_channel *chan;
08081 
08082    /* Handle an event on a given channel for the monitor thread. */
08083 
08084    switch (event) {
08085    case DAHDI_EVENT_NONE:
08086    case DAHDI_EVENT_BITSCHANGED:
08087       break;
08088    case DAHDI_EVENT_WINKFLASH:
08089    case DAHDI_EVENT_RINGOFFHOOK:
08090       if (i->inalarm) break;
08091       if (i->radio) break;
08092       /* Got a ring/answer.  What kind of channel are we? */
08093       switch (i->sig) {
08094       case SIG_FXOLS:
08095       case SIG_FXOGS:
08096       case SIG_FXOKS:
08097          res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
08098          if (res && (errno == EBUSY))
08099             break;
08100          if (i->cidspill) {
08101             /* Cancel VMWI spill */
08102             ast_free(i->cidspill);
08103             i->cidspill = NULL;
08104          }
08105          if (i->immediate) {
08106             dahdi_enable_ec(i);
08107             /* The channel is immediately up.  Start right away */
08108             res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
08109             chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, 0);
08110             if (!chan) {
08111                ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
08112                res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
08113                if (res < 0)
08114                   ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
08115             }
08116          } else {
08117             /* Check for callerid, digits, etc */
08118             chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, 0);
08119             if (chan) {
08120                if (has_voicemail(i))
08121                   res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
08122                else
08123                   res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
08124                if (res < 0) 
08125                   ast_log(LOG_WARNING, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i->channel);
08126                if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
08127                   ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
08128                   res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
08129                   if (res < 0)
08130                      ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
08131                   ast_hangup(chan);
08132                } else {
08133                   thread_spawned = 1;
08134                }
08135             } else
08136                ast_log(LOG_WARNING, "Unable to create channel\n");
08137          }
08138          break;
08139       case SIG_FXSLS:
08140       case SIG_FXSGS:
08141       case SIG_FXSKS:
08142             i->ringt = i->ringt_base;
08143             /* Fall through */
08144       case SIG_EMWINK:
08145       case SIG_FEATD:
08146       case SIG_FEATDMF:
08147       case SIG_FEATDMF_TA:
08148       case SIG_E911:
08149       case SIG_FGC_CAMA:
08150       case SIG_FGC_CAMAMF:
08151       case SIG_FEATB:
08152       case SIG_EM:
08153       case SIG_EM_E1:
08154       case SIG_SFWINK:
08155       case SIG_SF_FEATD:
08156       case SIG_SF_FEATDMF:
08157       case SIG_SF_FEATB:
08158       case SIG_SF:
08159          /* Check for callerid, digits, etc */
08160          if (i->cid_start == CID_START_POLARITY_IN) {
08161             chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0);
08162          } else {
08163             chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, 0);
08164          }
08165 
08166          if (!chan) {
08167             ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
08168          } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
08169             ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
08170             res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
08171             if (res < 0) {
08172                ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
08173             }
08174             ast_hangup(chan);
08175          } else  {
08176             thread_spawned = 1;
08177          }
08178          break;
08179       default:
08180          ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
08181          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
08182          if (res < 0)
08183                ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
08184          return -1;
08185       }
08186       break;
08187    case DAHDI_EVENT_NOALARM:
08188       i->inalarm = 0;
08189       ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel);
08190       manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
08191          "Channel: %d\r\n", i->channel);
08192       break;
08193    case DAHDI_EVENT_ALARM:
08194       i->inalarm = 1;
08195       res = get_alarms(i);
08196       handle_alarms(i, res);
08197       /* fall thru intentionally */
08198    case DAHDI_EVENT_ONHOOK:
08199       if (i->radio)
08200          break;
08201       /* Back on hook.  Hang up. */
08202       switch (i->sig) {
08203       case SIG_FXOLS:
08204       case SIG_FXOGS:
08205       case SIG_FEATD:
08206       case SIG_FEATDMF:
08207       case SIG_FEATDMF_TA:
08208       case SIG_E911:
08209       case SIG_FGC_CAMA:
08210       case SIG_FGC_CAMAMF:
08211       case SIG_FEATB:
08212       case SIG_EM:
08213       case SIG_EM_E1:
08214       case SIG_EMWINK:
08215       case SIG_SF_FEATD:
08216       case SIG_SF_FEATDMF:
08217       case SIG_SF_FEATB:
08218       case SIG_SF:
08219       case SIG_SFWINK:
08220       case SIG_FXSLS:
08221       case SIG_FXSGS:
08222       case SIG_FXSKS:
08223       case SIG_GR303FXSKS:
08224          dahdi_disable_ec(i);
08225          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
08226          dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
08227          break;
08228       case SIG_GR303FXOKS:
08229       case SIG_FXOKS:
08230          dahdi_disable_ec(i);
08231          /* Diddle the battery for the zhone */
08232 #ifdef ZHONE_HACK
08233          dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
08234          usleep(1);
08235 #endif         
08236          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
08237          dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
08238          break;
08239       case SIG_PRI:
08240       case SIG_SS7:
08241       case SIG_BRI:
08242       case SIG_BRI_PTMP:
08243          dahdi_disable_ec(i);
08244          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
08245          break;
08246       default:
08247          ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
08248          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
08249          return -1;
08250       }
08251       break;
08252    case DAHDI_EVENT_POLARITY:
08253       switch (i->sig) {
08254       case SIG_FXSLS:
08255       case SIG_FXSKS:
08256       case SIG_FXSGS:
08257          /* We have already got a PR before the channel was 
08258             created, but it wasn't handled. We need polarity 
08259             to be REV for remote hangup detection to work. 
08260             At least in Spain */
08261          if (i->hanguponpolarityswitch)
08262             i->polarity = POLARITY_REV;
08263          if (i->cid_start == CID_START_POLARITY || i->cid_start == CID_START_POLARITY_IN) {
08264             i->polarity = POLARITY_REV;
08265             ast_verb(2, "Starting post polarity "
08266                    "CID detection on channel %d\n",
08267                    i->channel);
08268             chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0);
08269             if (!chan) {
08270                ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
08271             } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
08272                ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
08273             } else {
08274                thread_spawned = 1;
08275             }
08276          }
08277          break;
08278       default:
08279          ast_log(LOG_WARNING, "handle_init_event detected "
08280             "polarity reversal on non-FXO (SIG_FXS) "
08281             "interface %d\n", i->channel);
08282       }
08283       break;
08284    case DAHDI_EVENT_REMOVED: /* destroy channel */
08285       ast_log(LOG_NOTICE, 
08286             "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n", 
08287             i->channel);
08288       dahdi_destroy_channel_bynum(i->channel);
08289       break;
08290    case DAHDI_EVENT_NEONMWI_ACTIVE:
08291       if (i->mwimonitor_neon) {
08292          notify_message(i->mailbox, 1);
08293          ast_log(LOG_NOTICE, "NEON MWI set for channel %d, mailbox %s \n", i->channel, i->mailbox);
08294       }
08295       break;
08296    case DAHDI_EVENT_NEONMWI_INACTIVE:
08297       if (i->mwimonitor_neon) {
08298          notify_message(i->mailbox, 0);
08299          ast_log(LOG_NOTICE, "NEON MWI cleared for channel %d, mailbox %s\n", i->channel, i->mailbox);
08300       }
08301       break;
08302    }
08303    return thread_spawned;
08304 }
08305 
08306 static void *do_monitor(void *data)
08307 {
08308    int count, res, res2, spoint, pollres=0;
08309    struct dahdi_pvt *i;
08310    struct dahdi_pvt *last = NULL;
08311    time_t thispass = 0, lastpass = 0;
08312    int found;
08313    char buf[1024];
08314    struct pollfd *pfds=NULL;
08315    int lastalloc = -1;
08316    /* This thread monitors all the frame relay interfaces which are not yet in use
08317       (and thus do not have a separate thread) indefinitely */
08318    /* From here on out, we die whenever asked */
08319 #if 0
08320    if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
08321       ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
08322       return NULL;
08323    }
08324    ast_debug(1, "Monitor starting...\n");
08325 #endif
08326    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
08327 
08328    for (;;) {
08329       /* Lock the interface list */
08330       ast_mutex_lock(&iflock);
08331       if (!pfds || (lastalloc != ifcount)) {
08332          if (pfds) {
08333             ast_free(pfds);
08334             pfds = NULL;
08335          }
08336          if (ifcount) {
08337             if (!(pfds = ast_calloc(1, ifcount * sizeof(*pfds)))) {
08338                ast_mutex_unlock(&iflock);
08339                return NULL;
08340             }
08341          }
08342          lastalloc = ifcount;
08343       }
08344       /* Build the stuff we're going to poll on, that is the socket of every
08345          dahdi_pvt that does not have an associated owner channel */
08346       count = 0;
08347       i = iflist;
08348       while (i) {
08349          if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio)) {
08350             if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive && !i->mwisendactive) {
08351                /* This needs to be watched, as it lacks an owner */
08352                pfds[count].fd = i->subs[SUB_REAL].dfd;
08353                pfds[count].events = POLLPRI;
08354                pfds[count].revents = 0;
08355                /* If we are monitoring for VMWI or sending CID, we need to
08356                   read from the channel as well */
08357                if (i->cidspill || i->mwimonitor_fsk)
08358                   pfds[count].events |= POLLIN;
08359                count++;
08360             }
08361          }
08362          i = i->next;
08363       }
08364       /* Okay, now that we know what to do, release the interface lock */
08365       ast_mutex_unlock(&iflock);
08366       
08367       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
08368       pthread_testcancel();
08369       /* Wait at least a second for something to happen */
08370       res = poll(pfds, count, 1000);
08371       pthread_testcancel();
08372       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
08373 
08374       /* Okay, poll has finished.  Let's see what happened.  */
08375       if (res < 0) {
08376          if ((errno != EAGAIN) && (errno != EINTR))
08377             ast_log(LOG_WARNING, "poll return %d: %s\n", res, strerror(errno));
08378          continue;
08379       }
08380       /* Alright, lock the interface list again, and let's look and see what has
08381          happened */
08382       ast_mutex_lock(&iflock);
08383       found = 0;
08384       spoint = 0;
08385       lastpass = thispass;
08386       thispass = time(NULL);
08387       i = iflist;
08388       while (i) {
08389          if (thispass != lastpass) {
08390             if (!found && ((i == last) || ((i == iflist) && !last))) {
08391                last = i;
08392                if (last) {
08393                   if (!last->mwisendactive &&    last->sig & __DAHDI_SIG_FXO) {
08394                      res = has_voicemail(last);
08395                      if (last->msgstate != res) {
08396 
08397                         /* This channel has a new voicemail state,
08398                         * initiate a thread to send an MWI message
08399                         */
08400                         pthread_attr_t attr;
08401                         pthread_t threadid;
08402                         struct mwi_thread_data *mtd;
08403                         res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_VMWI, &res);
08404                         if (res2) {
08405                            /* TODO: This message will ALWAYS be generated on some cards; any way to restrict it to those cards where it is interesting? */
08406                            ast_debug(3, "Unable to control message waiting led on channel %d: %s\n", last->channel, strerror(errno));
08407                         }
08408                         pthread_attr_init(&attr);
08409                         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
08410                         if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
08411                            last->msgstate = res;
08412                            mtd->pvt = last;
08413                            last->mwisendactive = 1;
08414                            if (ast_pthread_create_background(&threadid, &attr, mwi_send_thread, mtd)) {
08415                               ast_log(LOG_WARNING, "Unable to start mwi send thread on channel %d\n", last->channel);
08416                               ast_free(mtd);
08417                               last->mwisendactive = 0;
08418                            }
08419                         }
08420                         found ++;
08421                      }
08422                   }
08423                   last = last->next;
08424                }
08425             }
08426          }
08427          if ((i->subs[SUB_REAL].dfd > -1) && i->sig) {
08428             if (i->radio && !i->owner)
08429             {
08430                res = dahdi_get_event(i->subs[SUB_REAL].dfd);
08431                if (res)
08432                {
08433                   ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
08434                   /* Don't hold iflock while handling init events */
08435                   ast_mutex_unlock(&iflock);
08436                   handle_init_event(i, res);
08437                   ast_mutex_lock(&iflock);   
08438                }
08439                i = i->next;
08440                continue;
08441             }              
08442             pollres = ast_fdisset(pfds, i->subs[SUB_REAL].dfd, count, &spoint);
08443             if (pollres & POLLIN) {
08444                if (i->owner || i->subs[SUB_REAL].owner) {
08445 #ifdef HAVE_PRI
08446                   if (!i->pri)
08447 #endif                  
08448                      ast_log(LOG_WARNING, "Whoa....  I'm owned but found (%d) in read...\n", i->subs[SUB_REAL].dfd);
08449                   i = i->next;
08450                   continue;
08451                }
08452                if (!i->cidspill && !i->mwimonitor_fsk) {
08453                   ast_log(LOG_WARNING, "Whoa....  I'm reading but have no cidspill (%d)...\n", i->subs[SUB_REAL].dfd);
08454                   i = i->next;
08455                   continue;
08456                }
08457                res = read(i->subs[SUB_REAL].dfd, buf, sizeof(buf));
08458                if (res > 0) {
08459                   if (i->mwimonitor_fsk) {
08460                      if (calc_energy((unsigned char *) buf, res, AST_LAW(i)) > mwilevel) {
08461                         pthread_attr_t attr;
08462                         pthread_t threadid;
08463                         struct mwi_thread_data *mtd;
08464 
08465                         pthread_attr_init(&attr);
08466                         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
08467 
08468                         ast_log(LOG_DEBUG, "Maybe some MWI on port %d!\n", i->channel);
08469                         if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
08470                            mtd->pvt = i;
08471                            memcpy(mtd->buf, buf, res);
08472                            mtd->len = res;
08473                            if (ast_pthread_create_background(&threadid, &attr, mwi_thread, mtd)) {
08474                               ast_log(LOG_WARNING, "Unable to start mwi thread on channel %d\n", i->channel);
08475                               ast_free(mtd);
08476                            }
08477                            i->mwimonitoractive = 1;
08478                         }
08479                      }
08480                   }
08481                } else {
08482                   ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno));
08483                }
08484             }
08485             if (pollres & POLLPRI) {
08486                if (i->owner || i->subs[SUB_REAL].owner) {
08487 #ifdef HAVE_PRI
08488                   if (!i->pri)
08489 #endif                  
08490                      ast_log(LOG_WARNING, "Whoa....  I'm owned but found (%d)...\n", i->subs[SUB_REAL].dfd);
08491                   i = i->next;
08492                   continue;
08493                }
08494                res = dahdi_get_event(i->subs[SUB_REAL].dfd);
08495                ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
08496                /* Don't hold iflock while handling init events */
08497                ast_mutex_unlock(&iflock);
08498                handle_init_event(i, res);
08499                ast_mutex_lock(&iflock);   
08500             }
08501          }
08502          i=i->next;
08503       }
08504       ast_mutex_unlock(&iflock);
08505    }
08506    /* Never reached */
08507    return NULL;
08508    
08509 }
08510 
08511 static int restart_monitor(void)
08512 {
08513    /* If we're supposed to be stopped -- stay stopped */
08514    if (monitor_thread == AST_PTHREADT_STOP)
08515       return 0;
08516    ast_mutex_lock(&monlock);
08517    if (monitor_thread == pthread_self()) {
08518       ast_mutex_unlock(&monlock);
08519       ast_log(LOG_WARNING, "Cannot kill myself\n");
08520       return -1;
08521    }
08522    if (monitor_thread != AST_PTHREADT_NULL) {
08523       /* Wake up the thread */
08524       pthread_kill(monitor_thread, SIGURG);
08525    } else {
08526       /* Start a new monitor */
08527       if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
08528          ast_mutex_unlock(&monlock);
08529          ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
08530          return -1;
08531       }
08532    }
08533    ast_mutex_unlock(&monlock);
08534    return 0;
08535 }
08536 
08537 #ifdef HAVE_PRI
08538 static int pri_resolve_span(int *span, int channel, int offset, struct dahdi_spaninfo *si)
08539 {
08540    int x;
08541    int trunkgroup;
08542    /* Get appropriate trunk group if there is one */
08543    trunkgroup = pris[*span].mastertrunkgroup;
08544    if (trunkgroup) {
08545       /* Select a specific trunk group */
08546       for (x = 0; x < NUM_SPANS; x++) {
08547          if (pris[x].trunkgroup == trunkgroup) {
08548             *span = x;
08549             return 0;
08550          }
08551       }
08552       ast_log(LOG_WARNING, "Channel %d on span %d configured to use nonexistent trunk group %d\n", channel, *span, trunkgroup);
08553       *span = -1;
08554    } else {
08555       if (pris[*span].trunkgroup) {
08556          ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is trunk group %d (please use spanmap)\n", *span, pris[*span].trunkgroup);
08557          *span = -1;
08558       } else if (pris[*span].mastertrunkgroup) {
08559          ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is already part of trunk group %d\n", *span, pris[*span].mastertrunkgroup);
08560          *span = -1;
08561       } else {
08562          if (si->totalchans == 31) {
08563             /* E1 */
08564             pris[*span].dchannels[0] = 16 + offset;
08565          } else if (si->totalchans == 24) {
08566             /* T1 or J1 */
08567             pris[*span].dchannels[0] = 24 + offset;
08568          } else if (si->totalchans == 3) {
08569             /* BRI */
08570             pris[*span].dchannels[0] = 3 + offset;
08571          } else {
08572             ast_log(LOG_WARNING, "Unable to use span %d, since the D-channel cannot be located (unexpected span size of %d channels)\n", *span, si->totalchans);
08573             *span = -1;
08574             return 0;
08575          }
08576          pris[*span].dchanavail[0] |= DCHAN_PROVISIONED;
08577          pris[*span].offset = offset;
08578          pris[*span].span = *span + 1;
08579       }
08580    }
08581    return 0;
08582 }
08583 
08584 static int pri_create_trunkgroup(int trunkgroup, int *channels)
08585 {
08586    struct dahdi_spaninfo si;
08587    struct dahdi_params p;
08588    int fd;
08589    int span;
08590    int ospan=0;
08591    int x,y;
08592    for (x = 0; x < NUM_SPANS; x++) {
08593       if (pris[x].trunkgroup == trunkgroup) {
08594          ast_log(LOG_WARNING, "Trunk group %d already exists on span %d, Primary d-channel %d\n", trunkgroup, x + 1, pris[x].dchannels[0]);
08595          return -1;
08596       }
08597    }
08598    for (y = 0; y < NUM_DCHANS; y++) {
08599       if (!channels[y]) 
08600          break;
08601       memset(&si, 0, sizeof(si));
08602       memset(&p, 0, sizeof(p));
08603       fd = open("/dev/dahdi/channel", O_RDWR);
08604       if (fd < 0) {
08605          ast_log(LOG_WARNING, "Failed to open channel: %s\n", strerror(errno));
08606          return -1;
08607       }
08608       x = channels[y];
08609       if (ioctl(fd, DAHDI_SPECIFY, &x)) {
08610          ast_log(LOG_WARNING, "Failed to specify channel %d: %s\n", channels[y], strerror(errno));
08611          close(fd);
08612          return -1;
08613       }
08614       if (ioctl(fd, DAHDI_GET_PARAMS, &p)) {
08615          ast_log(LOG_WARNING, "Failed to get channel parameters for channel %d: %s\n", channels[y], strerror(errno));
08616          return -1;
08617       }
08618       if (ioctl(fd, DAHDI_SPANSTAT, &si)) {
08619          ast_log(LOG_WARNING, "Failed go get span information on channel %d (span %d): %s\n", channels[y], p.spanno, strerror(errno));
08620          close(fd);
08621          return -1;
08622       }
08623       span = p.spanno - 1;
08624       if (pris[span].trunkgroup) {
08625          ast_log(LOG_WARNING, "Span %d is already provisioned for trunk group %d\n", span + 1, pris[span].trunkgroup);
08626          close(fd);
08627          return -1;
08628       }
08629       if (pris[span].pvts[0]) {
08630          ast_log(LOG_WARNING, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span + 1);
08631          close(fd);
08632          return -1;
08633       }
08634       if (!y) {
08635          pris[span].trunkgroup = trunkgroup;
08636          pris[span].offset = channels[y] - p.chanpos;
08637          ospan = span;
08638       }
08639       pris[ospan].dchannels[y] = channels[y];
08640       pris[ospan].dchanavail[y] |= DCHAN_PROVISIONED;
08641       pris[span].span = span + 1;
08642       close(fd);
08643    }
08644    return 0;   
08645 }
08646 
08647 static int pri_create_spanmap(int span, int trunkgroup, int logicalspan)
08648 {
08649    if (pris[span].mastertrunkgroup) {
08650       ast_log(LOG_WARNING, "Span %d is already part of trunk group %d, cannot add to trunk group %d\n", span + 1, pris[span].mastertrunkgroup, trunkgroup);
08651       return -1;
08652    }
08653    pris[span].mastertrunkgroup = trunkgroup;
08654    pris[span].prilogicalspan = logicalspan;
08655    return 0;
08656 }
08657 
08658 #endif
08659 
08660 #ifdef HAVE_SS7
08661 
08662 static unsigned int parse_pointcode(const char *pcstring)
08663 {
08664    unsigned int code1, code2, code3;
08665    int numvals;
08666 
08667    numvals = sscanf(pcstring, "%d-%d-%d", &code1, &code2, &code3);
08668    if (numvals == 1)
08669       return code1;
08670    if (numvals == 3)
08671       return (code1 << 16) | (code2 << 8) | code3;
08672 
08673    return 0;
08674 }
08675 
08676 static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
08677 {
08678    if ((linkset < 0) || (linkset >= NUM_SPANS))
08679       return NULL;
08680    else
08681       return &linksets[linkset - 1];
08682 }
08683 #endif /* HAVE_SS7 */
08684 
08685 /* converts a DAHDI sigtype to signalling as can be configured from
08686  * chan_dahdi.conf.
08687  * While both have basically the same values, this will later be the
08688  * place to add filters and sanity checks
08689  */
08690 static int sigtype_to_signalling(int sigtype)
08691 {
08692         return sigtype;
08693 }
08694 
08695 static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, struct dahdi_pri *pri, int reloading)
08696 {
08697    /* Make a dahdi_pvt structure for this interface (or CRV if "pri" is specified) */
08698    struct dahdi_pvt *tmp = NULL, *tmp2,  *prev = NULL;
08699    char fn[80];
08700    struct dahdi_bufferinfo bi;
08701 
08702    int res;
08703    int span = 0;
08704    int here = 0;
08705    int x;
08706    struct dahdi_pvt **wlist;
08707    struct dahdi_pvt **wend;
08708    struct dahdi_params p;
08709 
08710    wlist = &iflist;
08711    wend = &ifend;
08712 
08713 #ifdef HAVE_PRI
08714    if (pri) {
08715       wlist = &pri->crvs;
08716       wend = &pri->crvend;
08717    }
08718 #endif
08719 
08720    tmp2 = *wlist;
08721    prev = NULL;
08722 
08723    while (tmp2) {
08724       if (!tmp2->destroy) {
08725          if (tmp2->channel == channel) {
08726             tmp = tmp2;
08727             here = 1;
08728             break;
08729          }
08730          if (tmp2->channel > channel) {
08731             break;
08732          }
08733       }
08734       prev = tmp2;
08735       tmp2 = tmp2->next;
08736    }
08737 
08738    if (!here && reloading != 1) {
08739       if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
08740          if (tmp)
08741             free(tmp);
08742          return NULL;
08743       }
08744       ast_mutex_init(&tmp->lock);
08745       ifcount++;
08746       for (x = 0; x < 3; x++)
08747          tmp->subs[x].dfd = -1;
08748       tmp->channel = channel;
08749    }
08750 
08751    if (tmp) {
08752       int chan_sig = conf->chan.sig;
08753       if (!here) {
08754          if ((channel != CHAN_PSEUDO) && !pri) {
08755             int count = 0;
08756             snprintf(fn, sizeof(fn), "%d", channel);
08757             /* Open non-blocking */
08758             tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
08759             while (tmp->subs[SUB_REAL].dfd < 0 && reloading == 2 && count < 1000) { /* the kernel may not call dahdi_release fast enough for the open flagbit to be cleared in time */
08760                usleep(1);
08761                tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
08762                count++;
08763             }
08764             /* Allocate a DAHDI structure */
08765             if (tmp->subs[SUB_REAL].dfd < 0) {
08766                ast_log(LOG_ERROR, "Unable to open channel %d: %s\nhere = %d, tmp->channel = %d, channel = %d\n", channel, strerror(errno), here, tmp->channel, channel);
08767                destroy_dahdi_pvt(&tmp);
08768                return NULL;
08769             }
08770             memset(&p, 0, sizeof(p));
08771             res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
08772             if (res < 0) {
08773                ast_log(LOG_ERROR, "Unable to get parameters: %s\n", strerror(errno));
08774                destroy_dahdi_pvt(&tmp);
08775                return NULL;
08776             }
08777             if (conf->is_sig_auto)
08778                chan_sig = sigtype_to_signalling(p.sigtype);
08779             if (p.sigtype != (chan_sig & 0x3ffff)) {
08780                ast_log(LOG_ERROR, "Signalling requested on channel %d is %s but line is in %s signalling\n", channel, sig2str(chan_sig), sig2str(p.sigtype));
08781                destroy_dahdi_pvt(&tmp);
08782                return NULL;
08783             }
08784             tmp->law = p.curlaw;
08785             tmp->span = p.spanno;
08786             span = p.spanno - 1;
08787          } else {
08788             if (channel == CHAN_PSEUDO)
08789                chan_sig = 0;
08790             else if ((chan_sig != SIG_FXOKS) && (chan_sig != SIG_FXSKS)) {
08791                ast_log(LOG_ERROR, "CRV's must use FXO/FXS Kewl Start (fxo_ks/fxs_ks) signalling only.\n");
08792                return NULL;
08793             }
08794          }
08795 #ifdef HAVE_SS7
08796          if (chan_sig == SIG_SS7) {
08797             struct dahdi_ss7 *ss7;
08798             int clear = 0;
08799             if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &clear)) {
08800                ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
08801                destroy_dahdi_pvt(&tmp);
08802                return NULL;
08803             }
08804 
08805             ss7 = ss7_resolve_linkset(cur_linkset);
08806             if (!ss7) {
08807                ast_log(LOG_ERROR, "Unable to find linkset %d\n", cur_linkset);
08808                destroy_dahdi_pvt(&tmp);
08809                return NULL;
08810             }
08811             if (cur_cicbeginswith < 0) {
08812                ast_log(LOG_ERROR, "Need to set cicbeginswith for the channels!\n");
08813                destroy_dahdi_pvt(&tmp);
08814                return NULL;
08815             }
08816 
08817             tmp->cic = cur_cicbeginswith++;
08818 
08819             /* DB: Add CIC's DPC information */
08820             tmp->dpc = cur_defaultdpc;
08821 
08822             tmp->ss7 = ss7;
08823             tmp->ss7call = NULL;
08824             ss7->pvts[ss7->numchans++] = tmp;
08825 
08826             ast_copy_string(linksets[span].internationalprefix, conf->ss7.internationalprefix, sizeof(linksets[span].internationalprefix));
08827             ast_copy_string(linksets[span].nationalprefix, conf->ss7.nationalprefix, sizeof(linksets[span].nationalprefix));
08828             ast_copy_string(linksets[span].subscriberprefix, conf->ss7.subscriberprefix, sizeof(linksets[span].subscriberprefix));
08829             ast_copy_string(linksets[span].unknownprefix, conf->ss7.unknownprefix, sizeof(linksets[span].unknownprefix));
08830 
08831             linksets[span].called_nai = conf->ss7.called_nai;
08832             linksets[span].calling_nai = conf->ss7.calling_nai;
08833          }
08834 #endif
08835 #ifdef HAVE_PRI
08836          if ((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP) || (chan_sig == SIG_GR303FXOKS) || (chan_sig == SIG_GR303FXSKS)) {
08837             int offset;
08838             int myswitchtype;
08839             int matchesdchan;
08840             int x,y;
08841             offset = 0;
08842             if (((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP)) 
08843                   && ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &offset)) {
08844                ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
08845                destroy_dahdi_pvt(&tmp);
08846                return NULL;
08847             }
08848             if (span >= NUM_SPANS) {
08849                ast_log(LOG_ERROR, "Channel %d does not lie on a span I know of (%d)\n", channel, span);
08850                destroy_dahdi_pvt(&tmp);
08851                return NULL;
08852             } else {
08853                struct dahdi_spaninfo si;
08854                si.spanno = 0;
08855                if (ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SPANSTAT,&si) == -1) {
08856                   ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno));
08857                   destroy_dahdi_pvt(&tmp);
08858                   return NULL;
08859                }
08860                /* Store the logical span first based upon the real span */
08861                tmp->logicalspan = pris[span].prilogicalspan;
08862                pri_resolve_span(&span, channel, (channel - p.chanpos), &si);
08863                if (span < 0) {
08864                   ast_log(LOG_WARNING, "Channel %d: Unable to find locate channel/trunk group!\n", channel);
08865                   destroy_dahdi_pvt(&tmp);
08866                   return NULL;
08867                }
08868                if ((chan_sig == SIG_PRI) ||
08869                      (chan_sig == SIG_BRI) ||
08870                      (chan_sig == SIG_BRI_PTMP))
08871                   myswitchtype = conf->pri.switchtype;
08872                else
08873                   myswitchtype = PRI_SWITCH_GR303_TMC;
08874                /* Make sure this isn't a d-channel */
08875                matchesdchan=0;
08876                for (x = 0; x < NUM_SPANS; x++) {
08877                   for (y = 0; y < NUM_DCHANS; y++) {
08878                      if (pris[x].dchannels[y] == tmp->channel) {
08879                         matchesdchan = 1;
08880                         break;
08881                      }
08882                   }
08883                }
08884                offset = p.chanpos;
08885                if (!matchesdchan) {
08886                   if (pris[span].nodetype && (pris[span].nodetype != conf->pri.nodetype)) {
08887                      ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].nodetype));
08888                      destroy_dahdi_pvt(&tmp);
08889                      return NULL;
08890                   }
08891                   if (pris[span].switchtype && (pris[span].switchtype != myswitchtype)) {
08892                      ast_log(LOG_ERROR, "Span %d is already a %s switch\n", span + 1, pri_switch2str(pris[span].switchtype));
08893                      destroy_dahdi_pvt(&tmp);
08894                      return NULL;
08895                   }
08896                   if ((pris[span].dialplan) && (pris[span].dialplan != conf->pri.dialplan)) {
08897                      ast_log(LOG_ERROR, "Span %d is already a %s dialing plan\n", span + 1, dialplan2str(pris[span].dialplan));
08898                      destroy_dahdi_pvt(&tmp);
08899                      return NULL;
08900                   }
08901                   if (!ast_strlen_zero(pris[span].idledial) && strcmp(pris[span].idledial, conf->pri.idledial)) {
08902                      ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, conf->pri.idledial);
08903                      destroy_dahdi_pvt(&tmp);
08904                      return NULL;
08905                   }
08906                   if (!ast_strlen_zero(pris[span].idleext) && strcmp(pris[span].idleext, conf->pri.idleext)) {
08907                      ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, conf->pri.idleext);
08908                      destroy_dahdi_pvt(&tmp);
08909                      return NULL;
08910                   }
08911                   if (pris[span].minunused && (pris[span].minunused != conf->pri.minunused)) {
08912                      ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, conf->pri.minunused);
08913                      destroy_dahdi_pvt(&tmp);
08914                      return NULL;
08915                   }
08916                   if (pris[span].minidle && (pris[span].minidle != conf->pri.minidle)) {
08917                      ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, conf->pri.minidle);
08918                      destroy_dahdi_pvt(&tmp);
08919                      return NULL;
08920                   }
08921                   if (pris[span].numchans >= MAX_CHANNELS) {
08922                      ast_log(LOG_ERROR, "Unable to add channel %d: Too many channels in trunk group %d!\n", channel,
08923                         pris[span].trunkgroup);
08924                      destroy_dahdi_pvt(&tmp);
08925                      return NULL;
08926                   }
08927 
08928                   pris[span].sig = chan_sig;
08929                   pris[span].nodetype = conf->pri.nodetype;
08930                   pris[span].switchtype = myswitchtype;
08931                   pris[span].nsf = conf->pri.nsf;
08932                   pris[span].dialplan = conf->pri.dialplan;
08933                   pris[span].localdialplan = conf->pri.localdialplan;
08934                   pris[span].pvts[pris[span].numchans++] = tmp;
08935                   pris[span].minunused = conf->pri.minunused;
08936                   pris[span].minidle = conf->pri.minidle;
08937                   pris[span].overlapdial = conf->pri.overlapdial;
08938 #ifdef HAVE_PRI_INBANDDISCONNECT
08939                   pris[span].inbanddisconnect = conf->pri.inbanddisconnect;
08940 #endif
08941                   pris[span].facilityenable = conf->pri.facilityenable;
08942                   ast_copy_string(pris[span].idledial, conf->pri.idledial, sizeof(pris[span].idledial));
08943                   ast_copy_string(pris[span].idleext, conf->pri.idleext, sizeof(pris[span].idleext));
08944                   ast_copy_string(pris[span].internationalprefix, conf->pri.internationalprefix, sizeof(pris[span].internationalprefix));
08945                   ast_copy_string(pris[span].nationalprefix, conf->pri.nationalprefix, sizeof(pris[span].nationalprefix));
08946                   ast_copy_string(pris[span].localprefix, conf->pri.localprefix, sizeof(pris[span].localprefix));
08947                   ast_copy_string(pris[span].privateprefix, conf->pri.privateprefix, sizeof(pris[span].privateprefix));
08948                   ast_copy_string(pris[span].unknownprefix, conf->pri.unknownprefix, sizeof(pris[span].unknownprefix));
08949                   pris[span].resetinterval = conf->pri.resetinterval;
08950                   
08951                   tmp->pri = &pris[span];
08952                   tmp->prioffset = offset;
08953                   tmp->call = NULL;
08954                } else {
08955                   ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", offset);
08956                   destroy_dahdi_pvt(&tmp);
08957                   return NULL;
08958                }
08959             }
08960          } else {
08961             tmp->prioffset = 0;
08962          }
08963 #endif
08964       } else {
08965          chan_sig = tmp->sig;
08966          if (tmp->subs[SUB_REAL].dfd > -1) {
08967             memset(&p, 0, sizeof(p));
08968             res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
08969          }
08970       }
08971       /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
08972       switch (chan_sig) {
08973       case SIG_FXSKS:
08974       case SIG_FXSLS:
08975       case SIG_EM:
08976       case SIG_EM_E1:
08977       case SIG_EMWINK:
08978       case SIG_FEATD:
08979       case SIG_FEATDMF:
08980       case SIG_FEATDMF_TA:
08981       case SIG_FEATB:
08982       case SIG_E911:
08983       case SIG_SF:
08984       case SIG_SFWINK:
08985       case SIG_FGC_CAMA:
08986       case SIG_FGC_CAMAMF:
08987       case SIG_SF_FEATD:
08988       case SIG_SF_FEATDMF:
08989       case SIG_SF_FEATB:
08990          p.starttime = 250;
08991          break;
08992       }
08993 
08994       if (tmp->radio) {
08995          /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
08996          p.channo = channel;
08997          p.rxwinktime = 1;
08998          p.rxflashtime = 1;
08999          p.starttime = 1;
09000          p.debouncetime = 5;
09001       }
09002       if (!tmp->radio) {
09003          p.channo = channel;
09004          /* Override timing settings based on config file */
09005          if (conf->timing.prewinktime >= 0)
09006             p.prewinktime = conf->timing.prewinktime;
09007          if (conf->timing.preflashtime >= 0)
09008             p.preflashtime = conf->timing.preflashtime;
09009          if (conf->timing.winktime >= 0)
09010             p.winktime = conf->timing.winktime;
09011          if (conf->timing.flashtime >= 0)
09012             p.flashtime = conf->timing.flashtime;
09013          if (conf->timing.starttime >= 0)
09014             p.starttime = conf->timing.starttime;
09015          if (conf->timing.rxwinktime >= 0)
09016             p.rxwinktime = conf->timing.rxwinktime;
09017          if (conf->timing.rxflashtime >= 0)
09018             p.rxflashtime = conf->timing.rxflashtime;
09019          if (conf->timing.debouncetime >= 0)
09020             p.debouncetime = conf->timing.debouncetime;
09021       }
09022 
09023       /* dont set parms on a pseudo-channel (or CRV) */
09024       if (tmp->subs[SUB_REAL].dfd >= 0)
09025       {
09026          res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_PARAMS, &p);
09027          if (res < 0) {
09028             ast_log(LOG_ERROR, "Unable to set parameters: %s\n", strerror(errno));
09029             destroy_dahdi_pvt(&tmp);
09030             return NULL;
09031          }
09032       }
09033 #if 1
09034       if (!here && (tmp->subs[SUB_REAL].dfd > -1)) {
09035          memset(&bi, 0, sizeof(bi));
09036          res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
09037          if (!res) {
09038             bi.txbufpolicy = conf->chan.buf_policy;
09039             bi.rxbufpolicy = conf->chan.buf_policy;
09040             bi.numbufs = conf->chan.buf_no;
09041             res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
09042             if (res < 0) {
09043                ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", channel, strerror(errno));
09044             }
09045          } else
09046             ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", channel, strerror(errno));
09047       }
09048 #endif
09049       tmp->immediate = conf->chan.immediate;
09050       tmp->transfertobusy = conf->chan.transfertobusy;
09051       if (chan_sig & __DAHDI_SIG_FXS) {
09052          tmp->mwimonitor_fsk = conf->chan.mwimonitor_fsk;
09053          tmp->mwimonitor_neon = conf->chan.mwimonitor_neon;
09054          tmp->mwimonitor_rpas = conf->chan.mwimonitor_rpas;
09055       }
09056       tmp->sig = chan_sig;
09057       tmp->outsigmod = conf->chan.outsigmod;
09058       tmp->ringt_base = ringt_base;
09059       tmp->firstradio = 0;
09060       if ((chan_sig == SIG_FXOKS) || (chan_sig == SIG_FXOLS) || (chan_sig == SIG_FXOGS))
09061          tmp->permcallwaiting = conf->chan.callwaiting;
09062       else
09063          tmp->permcallwaiting = 0;
09064       /* Flag to destroy the channel must be cleared on new mkif.  Part of changes for reload to work */
09065       tmp->destroy = 0;
09066       tmp->drings = conf->chan.drings;
09067 
09068       /* 10 is a nice default. */
09069       if (tmp->drings.ringnum[0].range == 0)
09070          tmp->drings.ringnum[0].range = 10;
09071       if (tmp->drings.ringnum[1].range == 0)
09072          tmp->drings.ringnum[1].range = 10;
09073       if (tmp->drings.ringnum[2].range == 0)
09074          tmp->drings.ringnum[2].range = 10;
09075 
09076       tmp->usedistinctiveringdetection = usedistinctiveringdetection;
09077       tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
09078       tmp->threewaycalling = conf->chan.threewaycalling;
09079       tmp->adsi = conf->chan.adsi;
09080       tmp->use_smdi = conf->chan.use_smdi;
09081       tmp->permhidecallerid = conf->chan.hidecallerid;
09082       tmp->callreturn = conf->chan.callreturn;
09083       tmp->echocancel = conf->chan.echocancel;
09084       tmp->echotraining = conf->chan.echotraining;
09085       tmp->pulse = conf->chan.pulse;
09086       if (tmp->echocancel.head.tap_length) {
09087          tmp->echocanbridged = conf->chan.echocanbridged;
09088       } else {
09089          if (conf->chan.echocanbridged)
09090             ast_log(LOG_NOTICE, "echocancelwhenbridged requires echocancel to be enabled; ignoring\n");
09091          tmp->echocanbridged = 0;
09092       }
09093       tmp->busydetect = conf->chan.busydetect;
09094       tmp->busycount = conf->chan.busycount;
09095       tmp->busycompare = conf->chan.busycompare;
09096       tmp->busytonelength = conf->chan.busytonelength;
09097       tmp->busyquietlength = conf->chan.busyquietlength;
09098       tmp->busyfuzziness = conf->chan.busyfuzziness;
09099       tmp->silencethreshold = conf->chan.silencethreshold;
09100       tmp->callprogress = conf->chan.callprogress;
09101       tmp->cancallforward = conf->chan.cancallforward;
09102       tmp->dtmfrelax = conf->chan.dtmfrelax;
09103       tmp->callwaiting = tmp->permcallwaiting;
09104       tmp->hidecallerid = tmp->permhidecallerid;
09105       tmp->channel = channel;
09106       tmp->stripmsd = conf->chan.stripmsd;
09107       tmp->use_callerid = conf->chan.use_callerid;
09108       tmp->cid_signalling = conf->chan.cid_signalling;
09109       tmp->cid_start = conf->chan.cid_start;
09110       tmp->dahditrcallerid = conf->chan.dahditrcallerid;
09111       tmp->restrictcid = conf->chan.restrictcid;
09112       tmp->use_callingpres = conf->chan.use_callingpres;
09113       tmp->priindication_oob = conf->chan.priindication_oob;
09114       tmp->priexclusive = conf->chan.priexclusive;
09115       if (tmp->usedistinctiveringdetection) {
09116          if (!tmp->use_callerid) {
09117             ast_log(LOG_NOTICE, "Distinctive Ring detect requires 'usecallerid' be on\n");
09118             tmp->use_callerid = 1;
09119          }
09120       }
09121 
09122       if (tmp->cid_signalling == CID_SIG_SMDI) {
09123          if (!tmp->use_smdi) {
09124             ast_log(LOG_WARNING, "SMDI callerid requires SMDI to be enabled, enabling...\n");
09125             tmp->use_smdi = 1;
09126          }
09127       }
09128       if (tmp->use_smdi) {
09129          tmp->smdi_iface = ast_smdi_interface_find(conf->smdi_port);
09130          if (!(tmp->smdi_iface)) {
09131             ast_log(LOG_ERROR, "Invalid SMDI port specfied, disabling SMDI support\n");
09132             tmp->use_smdi = 0;
09133          }
09134       }
09135 
09136       ast_copy_string(tmp->accountcode, conf->chan.accountcode, sizeof(tmp->accountcode));
09137       tmp->amaflags = conf->chan.amaflags;
09138       if (!here) {
09139          tmp->confno = -1;
09140          tmp->propconfno = -1;
09141       }
09142       tmp->canpark = conf->chan.canpark;
09143       tmp->transfer = conf->chan.transfer;
09144       ast_copy_string(tmp->defcontext,conf->chan.context,sizeof(tmp->defcontext));
09145       ast_copy_string(tmp->language, conf->chan.language, sizeof(tmp->language));
09146       ast_copy_string(tmp->mohinterpret, conf->chan.mohinterpret, sizeof(tmp->mohinterpret));
09147       ast_copy_string(tmp->mohsuggest, conf->chan.mohsuggest, sizeof(tmp->mohsuggest));
09148       ast_copy_string(tmp->context, conf->chan.context, sizeof(tmp->context));
09149       ast_copy_string(tmp->cid_num, conf->chan.cid_num, sizeof(tmp->cid_num));
09150       ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
09151       tmp->cid_ton = 0;
09152       ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name));
09153       ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
09154       if (channel != CHAN_PSEUDO && !ast_strlen_zero(tmp->mailbox)) {
09155          char *mailbox, *context;
09156          mailbox = context = ast_strdupa(tmp->mailbox);
09157          strsep(&context, "@");
09158          if (ast_strlen_zero(context))
09159             context = "default";
09160          tmp->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, NULL,
09161             AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
09162             AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
09163             AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
09164             AST_EVENT_IE_END);
09165       }
09166       tmp->msgstate = -1;
09167       tmp->group = conf->chan.group;
09168       tmp->callgroup = conf->chan.callgroup;
09169       tmp->pickupgroup= conf->chan.pickupgroup;
09170       if (conf->chan.vars) {
09171          tmp->vars = conf->chan.vars;
09172       }
09173       tmp->cid_rxgain = conf->chan.cid_rxgain;
09174       tmp->rxgain = conf->chan.rxgain;
09175       tmp->txgain = conf->chan.txgain;
09176       tmp->tonezone = conf->chan.tonezone;
09177       tmp->onhooktime = time(NULL);
09178       if (tmp->subs[SUB_REAL].dfd > -1) {
09179          set_actual_gain(tmp->subs[SUB_REAL].dfd, 0, tmp->rxgain, tmp->txgain, tmp->law);
09180          if (tmp->dsp)
09181             ast_dsp_set_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax);
09182          update_conf(tmp);
09183          if (!here) {
09184             if ((chan_sig != SIG_BRI) && (chan_sig != SIG_BRI_PTMP) && (chan_sig != SIG_PRI) && (chan_sig != SIG_SS7))
09185                /* Hang it up to be sure it's good */
09186                dahdi_set_hook(tmp->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
09187          }
09188          ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SETTONEZONE,&tmp->tonezone);
09189 #ifdef HAVE_PRI
09190          /* the dchannel is down so put the channel in alarm */
09191          if (tmp->pri && !pri_is_up(tmp->pri))
09192             tmp->inalarm = 1;
09193 #endif            
09194          if ((res = get_alarms(tmp)) != DAHDI_ALARM_NONE) {
09195             tmp->inalarm = 1;
09196             handle_alarms(tmp, res);
09197          }
09198       }
09199 
09200       tmp->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
09201       tmp->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
09202       tmp->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
09203       tmp->sendcalleridafter = conf->chan.sendcalleridafter;
09204       if (!here) {
09205          tmp->locallyblocked = tmp->remotelyblocked = 0;
09206          if ((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP) || (chan_sig == SIG_SS7))
09207             tmp->inservice = 0;
09208          else /* We default to in service on protocols that don't have a reset */
09209             tmp->inservice = 1;
09210       }
09211    }
09212    if (tmp && !here) {
09213       /* nothing on the iflist */
09214       if (!*wlist) {
09215          *wlist = tmp;
09216          tmp->prev = NULL;
09217          tmp->next = NULL;
09218          *wend = tmp;
09219       } else {
09220          /* at least one member on the iflist */
09221          struct dahdi_pvt *working = *wlist;
09222 
09223          /* check if we maybe have to put it on the begining */
09224          if (working->channel > tmp->channel) {
09225             tmp->next = *wlist;
09226             tmp->prev = NULL;
09227             (*wlist)->prev = tmp;
09228             *wlist = tmp;
09229          } else {
09230          /* go through all the members and put the member in the right place */
09231             while (working) {
09232                /* in the middle */
09233                if (working->next) {
09234                   if (working->channel < tmp->channel && working->next->channel > tmp->channel) {
09235                      tmp->next = working->next;
09236                      tmp->prev = working;
09237                      working->next->prev = tmp;
09238                      working->next = tmp;
09239                      break;
09240                   }
09241                } else {
09242                /* the last */
09243                   if (working->channel < tmp->channel) {
09244                      working->next = tmp;
09245                      tmp->next = NULL;
09246                      tmp->prev = working;
09247                      *wend = tmp;
09248                      break;
09249                   }
09250                }
09251                working = working->next;
09252             }
09253          }
09254       }
09255    }
09256    return tmp;
09257 }
09258 
09259 static inline int available(struct dahdi_pvt *p, int channelmatch, ast_group_t groupmatch, int *busy, int *channelmatched, int *groupmatched)
09260 {
09261    int res;
09262    struct dahdi_params par;
09263 
09264    /* First, check group matching */
09265    if (groupmatch) {
09266       if ((p->group & groupmatch) != groupmatch)
09267          return 0;
09268       *groupmatched = 1;
09269    }
09270    /* Check to see if we have a channel match */
09271    if (channelmatch != -1) {
09272       if (p->channel != channelmatch)
09273          return 0;
09274       *channelmatched = 1;
09275    }
09276    /* We're at least busy at this point */
09277    if (busy) {
09278       if ((p->sig == SIG_FXOKS) || (p->sig == SIG_FXOLS) || (p->sig == SIG_FXOGS))
09279          *busy = 1;
09280    }
09281    /* If do not disturb, definitely not */
09282    if (p->dnd)
09283       return 0;
09284    /* If guard time, definitely not */
09285    if (p->guardtime && (time(NULL) < p->guardtime)) 
09286       return 0;
09287 
09288    if (p->locallyblocked || p->remotelyblocked)
09289       return 0;
09290       
09291    /* If no owner definitely available */
09292    if (!p->owner) {
09293 #ifdef HAVE_PRI
09294       /* Trust PRI */
09295       if (p->pri) {
09296          if (p->resetting || p->call)
09297             return 0;
09298          else
09299             return 1;
09300       }
09301 #endif
09302 #ifdef HAVE_SS7
09303       /* Trust SS7 */
09304       if (p->ss7) {
09305          if (p->ss7call)
09306             return 0;
09307          else
09308             return 1;
09309       }
09310 #endif
09311       if (!(p->radio || (p->oprmode < 0)))
09312       {
09313          if (!p->sig || (p->sig == SIG_FXSLS))
09314             return 1;
09315          /* Check hook state */
09316          if (p->subs[SUB_REAL].dfd > -1) {
09317             memset(&par, 0, sizeof(par));
09318             res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
09319          } else {
09320             /* Assume not off hook on CVRS */
09321             res = 0;
09322             par.rxisoffhook = 0;
09323          }
09324          if (res) {
09325             ast_log(LOG_WARNING, "Unable to check hook state on channel %d: %s\n", p->channel, strerror(errno));
09326          } else if ((p->sig == SIG_FXSKS) || (p->sig == SIG_FXSGS)) {
09327             /* When "onhook" that means no battery on the line, and thus
09328               it is out of service..., if it's on a TDM card... If it's a channel
09329               bank, there is no telling... */
09330             if (par.rxbits > -1)
09331                return 1;
09332             if (par.rxisoffhook)
09333                return 1;
09334             else
09335                return 0;
09336          } else if (par.rxisoffhook) {
09337             ast_debug(1, "Channel %d off hook, can't use\n", p->channel);
09338             /* Not available when the other end is off hook */
09339 #ifdef DAHDI_CHECK_HOOKSTATE
09340             return 0;
09341 #else
09342             return 1;
09343 #endif
09344          }
09345       }
09346       return 1;
09347    }
09348 
09349    /* If it's not an FXO, forget about call wait */
09350    if ((p->sig != SIG_FXOKS) && (p->sig != SIG_FXOLS) && (p->sig != SIG_FXOGS)) 
09351       return 0;
09352 
09353    if (!p->callwaiting) {
09354       /* If they don't have call waiting enabled, then for sure they're unavailable at this point */
09355       return 0;
09356    }
09357 
09358    if (p->subs[SUB_CALLWAIT].dfd > -1) {
09359       /* If there is already a call waiting call, then we can't take a second one */
09360       return 0;
09361    }
09362    
09363    if ((p->owner->_state != AST_STATE_UP) &&
09364        ((p->owner->_state != AST_STATE_RINGING) || p->outgoing)) {
09365       /* If the current call is not up, then don't allow the call */
09366       return 0;
09367    }
09368    if ((p->subs[SUB_THREEWAY].owner) && (!p->subs[SUB_THREEWAY].inthreeway)) {
09369       /* Can't take a call wait when the three way calling hasn't been merged yet. */
09370       return 0;
09371    }
09372    /* We're cool */
09373    return 1;
09374 }
09375 
09376 static struct dahdi_pvt *chandup(struct dahdi_pvt *src)
09377 {
09378    struct dahdi_pvt *p;
09379    struct dahdi_bufferinfo bi;
09380    int res;
09381    
09382    if ((p = ast_malloc(sizeof(*p)))) {
09383       memcpy(p, src, sizeof(struct dahdi_pvt));
09384       ast_mutex_init(&p->lock);
09385       p->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
09386       /* Allocate a dahdi structure */
09387       if (p->subs[SUB_REAL].dfd < 0) {
09388          ast_log(LOG_ERROR, "Unable to dup channel: %s\n",  strerror(errno));
09389          destroy_dahdi_pvt(&p);
09390          return NULL;
09391       }
09392       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
09393       if (!res) {
09394          bi.txbufpolicy = src->buf_policy;
09395          bi.rxbufpolicy = src->buf_policy;
09396          bi.numbufs = src->buf_no;
09397          res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
09398          if (res < 0) {
09399             ast_log(LOG_WARNING, "Unable to set buffer policy on dup channel: %s\n", strerror(errno));
09400          }
09401       } else
09402          ast_log(LOG_WARNING, "Unable to check buffer policy on dup channel: %s\n", strerror(errno));
09403    }
09404    p->destroy = 1;
09405    p->next = iflist;
09406    p->prev = NULL;
09407    iflist = p;
09408    if (iflist->next)
09409       iflist->next->prev = p;
09410    return p;
09411 }
09412    
09413 
09414 #ifdef HAVE_PRI
09415 static int pri_find_empty_chan(struct dahdi_pri *pri, int backwards)
09416 {
09417    int x;
09418    if (backwards)
09419       x = pri->numchans;
09420    else
09421       x = 0;
09422    for (;;) {
09423       if (backwards && (x < 0))
09424          break;
09425       if (!backwards && (x >= pri->numchans))
09426          break;
09427       if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner) {
09428          ast_debug(1, "Found empty available channel %d/%d\n", 
09429             pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
09430          return x;
09431       }
09432       if (backwards)
09433          x--;
09434       else
09435          x++;
09436    }
09437    return -1;
09438 }
09439 #endif
09440 
09441 static struct ast_channel *dahdi_request(const char *type, int format, void *data, int *cause)
09442 {
09443    ast_group_t groupmatch = 0;
09444    int channelmatch = -1;
09445    int roundrobin = 0;
09446    int callwait = 0;
09447    int busy = 0;
09448    struct dahdi_pvt *p;
09449    struct ast_channel *tmp = NULL;
09450    char *dest=NULL;
09451    int x;
09452    char *s;
09453    char opt=0;
09454    int res=0, y=0;
09455    int backwards = 0;
09456 #ifdef HAVE_PRI
09457    int crv;
09458    int bearer = -1;
09459    int trunkgroup;
09460    struct dahdi_pri *pri=NULL;
09461 #endif   
09462    struct dahdi_pvt *exitpvt, *start, *end;
09463    ast_mutex_t *lock;
09464    int channelmatched = 0;
09465    int groupmatched = 0;
09466    
09467    /*
09468     * data is ---v
09469     * Dial(DAHDI/pseudo[/extension])
09470     * Dial(DAHDI/<channel#>[c|r<cadance#>|d][/extension])
09471     * Dial(DAHDI/<trunk_group#>:<crv#>[c|r<cadance#>|d][/extension])
09472     * Dial(DAHDI/(g|G|r|R)<group#(0-63)>[c|r<cadance#>|d][/extension])
09473     *
09474     * g - channel group allocation search forward
09475     * G - channel group allocation search backward
09476     * r - channel group allocation round robin search forward
09477     * R - channel group allocation round robin search backward
09478     *
09479     * c - Wait for DTMF digit to confirm answer
09480     * r<cadance#> - Set distintive ring cadance number
09481     * d - Force bearer capability for ISDN/SS7 call to digital.
09482     */
09483 
09484    /* Assume we're locking the iflock */
09485    lock = &iflock;
09486    start = iflist;
09487    end = ifend;
09488    if (data) {
09489       dest = ast_strdupa((char *)data);
09490    } else {
09491       ast_log(LOG_WARNING, "Channel requested with no data\n");
09492       return NULL;
09493    }
09494    if (toupper(dest[0]) == 'G' || toupper(dest[0])=='R') {
09495       /* Retrieve the group number */
09496       char *stringp;
09497 
09498       stringp = dest + 1;
09499       s = strsep(&stringp, "/");
09500       if ((res = sscanf(s, "%d%c%d", &x, &opt, &y)) < 1) {
09501          ast_log(LOG_WARNING, "Unable to determine group for data %s\n", (char *)data);
09502          return NULL;
09503       }
09504       groupmatch = ((ast_group_t) 1 << x);
09505       if (toupper(dest[0]) == 'G') {
09506          if (dest[0] == 'G') {
09507             backwards = 1;
09508             p = ifend;
09509          } else
09510             p = iflist;
09511       } else {
09512          if (dest[0] == 'R') {
09513             backwards = 1;
09514             p = round_robin[x]?round_robin[x]->prev:ifend;
09515             if (!p)
09516                p = ifend;
09517          } else {
09518             p = round_robin[x]?round_robin[x]->next:iflist;
09519             if (!p)
09520                p = iflist;
09521          }
09522          roundrobin = 1;
09523       }
09524    } else {
09525       char *stringp;
09526 
09527       stringp = dest;
09528       s = strsep(&stringp, "/");
09529       p = iflist;
09530       if (!strcasecmp(s, "pseudo")) {
09531          /* Special case for pseudo */
09532          x = CHAN_PSEUDO;
09533          channelmatch = x;
09534       } 
09535 #ifdef HAVE_PRI
09536       else if ((res = sscanf(s, "%d:%d%c%d", &trunkgroup, &crv, &opt, &y)) > 1) {
09537          if ((trunkgroup < 1) || (crv < 1)) {
09538             ast_log(LOG_WARNING, "Unable to determine trunk group and CRV for data %s\n", (char *)data);
09539             return NULL;
09540          }
09541          res--;
09542          for (x = 0; x < NUM_SPANS; x++) {
09543             if (pris[x].trunkgroup == trunkgroup) {
09544                pri = pris + x;
09545                lock = &pri->lock;
09546                start = pri->crvs;
09547                end = pri->crvend;
09548                break;
09549             }
09550          }
09551          if (!pri) {
09552             ast_log(LOG_WARNING, "Unable to find trunk group %d\n", trunkgroup);
09553             return NULL;
09554          }
09555          channelmatch = crv;
09556          p = pris[x].crvs;
09557       }
09558 #endif   
09559       else if ((res = sscanf(s, "%d%c%d", &x, &opt, &y)) < 1) {
09560          ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", (char *)data);
09561          return NULL;
09562       } else {
09563          channelmatch = x;
09564       }
09565    }
09566    /* Search for an unowned channel */
09567    ast_mutex_lock(lock);
09568    exitpvt = p;
09569    while (p && !tmp) {
09570       if (roundrobin)
09571          round_robin[x] = p;
09572 #if 0
09573       ast_verbose("name = %s, %d, %d, %d\n",p->owner ? p->owner->name : "<none>", p->channel, channelmatch, groupmatch);
09574 #endif
09575 
09576       if (p && available(p, channelmatch, groupmatch, &busy, &channelmatched, &groupmatched)) {
09577          ast_debug(1, "Using channel %d\n", p->channel);
09578          if (p->inalarm) 
09579             goto next;
09580 
09581          callwait = (p->owner != NULL);
09582 #ifdef HAVE_PRI
09583          if (pri && (p->subs[SUB_REAL].dfd < 0)) {
09584             if (p->sig != SIG_FXSKS) {
09585                /* Gotta find an actual channel to use for this
09586                   CRV if this isn't a callwait */
09587                bearer = pri_find_empty_chan(pri, 0);
09588                if (bearer < 0) {
09589                   ast_log(LOG_NOTICE, "Out of bearer channels on span %d for call to CRV %d:%d\n", pri->span, trunkgroup, crv);
09590                   p = NULL;
09591                   break;
09592                }
09593                pri_assign_bearer(p, pri, pri->pvts[bearer]);
09594             } else {
09595                if (alloc_sub(p, 0)) {
09596                   ast_log(LOG_NOTICE, "Failed to allocate place holder pseudo channel!\n");
09597                   p = NULL;
09598                   break;
09599                } else
09600                   ast_debug(1, "Allocated placeholder pseudo channel\n");
09601 
09602                p->pri = pri;
09603             }
09604          }
09605 #endif         
09606          if (p->channel == CHAN_PSEUDO) {
09607             p = chandup(p);
09608             if (!p) {
09609                break;
09610             }
09611          }
09612          if (p->owner) {
09613             if (alloc_sub(p, SUB_CALLWAIT)) {
09614                p = NULL;
09615                break;
09616             }
09617          }
09618          p->outgoing = 1;
09619          tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, 0);
09620 #ifdef HAVE_PRI
09621          if (p->bearer) {
09622             /* Log owner to bearer channel, too */
09623             p->bearer->owner = tmp;
09624          }
09625 #endif         
09626          /* Make special notes */
09627          if (res > 1) {
09628             if (opt == 'c') {
09629                /* Confirm answer */
09630                p->confirmanswer = 1;
09631             } else if (opt == 'r') {
09632                /* Distinctive ring */
09633                if (res < 3)
09634                   ast_log(LOG_WARNING, "Distinctive ring missing identifier in '%s'\n", (char *)data);
09635                else
09636                   p->distinctivering = y;
09637             } else if (opt == 'd') {
09638                /* If this is an ISDN call, make it digital */
09639                p->digital = 1;
09640                if (tmp)
09641                   tmp->transfercapability = AST_TRANS_CAP_DIGITAL;
09642             } else {
09643                ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", opt, (char *)data);
09644             }
09645          }
09646          /* Note if the call is a call waiting call */
09647          if (tmp && callwait)
09648             tmp->cdrflags |= AST_CDR_CALLWAIT;
09649          break;
09650       }
09651 next:
09652       if (backwards) {
09653          p = p->prev;
09654          if (!p)
09655             p = end;
09656       } else {
09657          p = p->next;
09658          if (!p)
09659             p = start;
09660       }
09661       /* stop when you roll to the one that we started from */
09662       if (p == exitpvt)
09663          break;
09664    }
09665    ast_mutex_unlock(lock);
09666    restart_monitor();
09667    if (callwait)
09668       *cause = AST_CAUSE_BUSY;
09669    else if (!tmp) {
09670       if (channelmatched) {
09671          if (busy)
09672             *cause = AST_CAUSE_BUSY;
09673       } else if (groupmatched) {
09674          *cause = AST_CAUSE_CONGESTION;
09675       }
09676    }
09677       
09678    return tmp;
09679 }
09680 
09681 #if defined(HAVE_PRI) || defined(HAVE_SS7)
09682 static int dahdi_setlaw(int dfd, int law)
09683 {
09684    return ioctl(dfd, DAHDI_SETLAW, &law);
09685 }
09686 #endif
09687 
09688 #ifdef HAVE_SS7
09689 
09690 static int ss7_find_cic(struct dahdi_ss7 *linkset, int cic, unsigned int dpc)
09691 {
09692    int i;
09693    int winner = -1;
09694    for (i = 0; i < linkset->numchans; i++) {
09695       if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && linkset->pvts[i]->cic == cic)) {
09696          winner = i;
09697          break;
09698       }
09699    }
09700    return winner;
09701 }
09702 
09703 static void ss7_handle_cqm(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc)
09704 {
09705    unsigned char status[32];
09706    struct dahdi_pvt *p = NULL;
09707    int i, offset;
09708 
09709    for (i = 0; i < linkset->numchans; i++) {
09710       if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
09711          p = linkset->pvts[i];
09712          offset = p->cic - startcic;
09713          status[offset] = 0;
09714          if (p->locallyblocked)
09715             status[offset] |= (1 << 0) | (1 << 4);
09716          if (p->remotelyblocked)
09717             status[offset] |= (1 << 1) | (1 << 5);
09718          if (p->ss7call) {
09719             if (p->outgoing)
09720                status[offset] |= (1 << 3);
09721             else
09722                status[offset] |= (1 << 2);
09723          } else
09724             status[offset] |= 0x3 << 2;
09725       }
09726    }
09727 
09728    if (p)
09729       isup_cqr(linkset->ss7, startcic, endcic, dpc, status);
09730    else
09731       ast_log(LOG_WARNING, "Could not find any equipped circuits within CQM CICs\n");
09732    
09733 }
09734 
09735 static inline void ss7_block_cics(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc, unsigned char state[], int block)
09736 {
09737    int i;
09738 
09739    for (i = 0; i < linkset->numchans; i++) {
09740       if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
09741          if (state) {
09742             if (state[i])
09743                linkset->pvts[i]->remotelyblocked = block;
09744          } else
09745             linkset->pvts[i]->remotelyblocked = block;
09746       }
09747    }
09748 }
09749 
09750 static void ss7_inservice(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc)
09751 {
09752    int i;
09753 
09754    for (i = 0; i < linkset->numchans; i++) {
09755       if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic))))
09756          linkset->pvts[i]->inservice = 1;
09757    }
09758 }
09759 
09760 static void ss7_reset_linkset(struct dahdi_ss7 *linkset)
09761 {
09762    int i, startcic = -1, endcic, dpc;
09763 
09764    if (linkset->numchans <= 0)
09765       return;
09766 
09767    startcic = linkset->pvts[0]->cic;
09768    /* DB: CIC's DPC fix */
09769    dpc = linkset->pvts[0]->dpc;
09770 
09771    for (i = 0; i < linkset->numchans; i++) {
09772       if (linkset->pvts[i+1] && linkset->pvts[i+1]->dpc == dpc && ((linkset->pvts[i+1]->cic - linkset->pvts[i]->cic) == 1) && (linkset->pvts[i]->cic - startcic < 31)) {
09773          continue;
09774       } else {
09775          endcic = linkset->pvts[i]->cic;
09776          ast_verbose("Resetting CICs %d to %d\n", startcic, endcic);
09777          isup_grs(linkset->ss7, startcic, endcic, dpc);
09778 
09779          /* DB: CIC's DPC fix */
09780          if (linkset->pvts[i+1]) {
09781             startcic = linkset->pvts[i+1]->cic;
09782             dpc = linkset->pvts[i+1]->dpc;
09783          }
09784       }
09785    }
09786 }
09787 
09788 static void dahdi_loopback(struct dahdi_pvt *p, int enable)
09789 {
09790    if (p->loopedback != enable) {
09791       if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_LOOPBACK, &enable)) {
09792          ast_log(LOG_WARNING, "Unable to set loopback on channel %d: %s\n", p->channel, strerror(errno));
09793          return;
09794       }
09795       p->loopedback = enable;
09796    }
09797 }
09798 
09799 /* XXX: This function is assumed to be called with the private channel lock and linkset lock held */
09800 static void ss7_start_call(struct dahdi_pvt *p, struct dahdi_ss7 *linkset)
09801 {
09802    struct ss7 *ss7 = linkset->ss7;
09803    int res;
09804    int law = 1;
09805    struct ast_channel *c;
09806    char tmp[256];
09807 
09808    if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law) == -1)
09809       ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, law, strerror(errno));
09810    
09811    if (linkset->type == SS7_ITU)
09812       law = DAHDI_LAW_ALAW;
09813    else
09814       law = DAHDI_LAW_MULAW;
09815 
09816    res = dahdi_setlaw(p->subs[SUB_REAL].dfd, law);
09817    if (res < 0) 
09818       ast_log(LOG_WARNING, "Unable to set law on channel %d\n", p->channel);
09819    
09820    if (!(linkset->flags & LINKSET_FLAG_EXPLICITACM)) {
09821       p->proceeding = 1;
09822       isup_acm(ss7, p->ss7call);
09823    }
09824 
09825    ast_mutex_unlock(&linkset->lock);
09826    c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, law, 0);
09827 
09828    if (!c) {
09829       ast_log(LOG_WARNING, "Unable to start PBX on CIC %d\n", p->cic);
09830       /* Holding this lock is assumed entering the function */
09831       ast_mutex_lock(&linkset->lock);
09832       return;
09833    } else
09834       ast_verb(3, "Accepting call to '%s' on CIC %d\n", p->exten, p->cic);
09835 
09836    dahdi_enable_ec(p);
09837 
09838    /* We only reference these variables in the context of the ss7_linkset function
09839     * when receiving either and IAM or a COT message.  Since they are only accessed
09840     * from this context, we should be safe to unlock around them */
09841 
09842    ast_mutex_unlock(&p->lock);
09843 
09844    if (!ast_strlen_zero(p->charge_number)) {
09845       pbx_builtin_setvar_helper(c, "SS7_CHARGE_NUMBER", p->charge_number);
09846       /* Clear this after we set it */
09847       p->charge_number[0] = 0;
09848    }
09849    if (!ast_strlen_zero(p->gen_add_number)) {
09850       pbx_builtin_setvar_helper(c, "SS7_GENERIC_ADDRESS", p->gen_add_number);
09851       /* Clear this after we set it */
09852       p->gen_add_number[0] = 0;
09853    }
09854    if (!ast_strlen_zero(p->jip_number)) {
09855       pbx_builtin_setvar_helper(c, "SS7_JIP", p->jip_number);
09856       /* Clear this after we set it */
09857       p->jip_number[0] = 0;
09858    }
09859    if (!ast_strlen_zero(p->gen_dig_number)) {
09860       pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGITS", p->gen_dig_number);
09861       /* Clear this after we set it */
09862       p->gen_dig_number[0] = 0;
09863    }
09864    if (!ast_strlen_zero(p->orig_called_num)) {
09865       pbx_builtin_setvar_helper(c, "SS7_ORIG_CALLED_NUM", p->orig_called_num);
09866       /* Clear this after we set it */
09867       p->orig_called_num[0] = 0;
09868    }
09869 
09870    snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_type);
09871    pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGTYPE", tmp);
09872    /* Clear this after we set it */
09873    p->gen_dig_type = 0;
09874 
09875    snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_scheme);
09876    pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGSCHEME", tmp);
09877    /* Clear this after we set it */
09878    p->gen_dig_scheme = 0;
09879 
09880    if (!ast_strlen_zero(p->lspi_ident)) {
09881       pbx_builtin_setvar_helper(c, "SS7_LSPI_IDENT", p->lspi_ident);
09882       /* Clear this after we set it */
09883       p->lspi_ident[0] = 0;
09884    }
09885 
09886    snprintf(tmp, sizeof(tmp), "%d", p->call_ref_ident);
09887    pbx_builtin_setvar_helper(c, "SS7_CALLREF_IDENT", tmp);
09888    /* Clear this after we set it */
09889    p->call_ref_ident = 0;
09890 
09891    snprintf(tmp, sizeof(tmp), "%d", p->call_ref_pc);
09892    pbx_builtin_setvar_helper(c, "SS7_CALLREF_PC", tmp);
09893    /* Clear this after we set it */
09894    p->call_ref_pc = 0;
09895 
09896    snprintf(tmp, sizeof(tmp), "%d", p->calling_party_cat);
09897    pbx_builtin_setvar_helper(c, "SS7_CALLING_PARTY_CATEGORY", tmp);
09898    /* Clear this after we set it */
09899    p->calling_party_cat = 0;
09900 
09901    if (!ast_strlen_zero(p->redirecting_num)) {
09902       pbx_builtin_setvar_helper(c, "SS7_REDIRECTING_NUMBER", p->redirecting_num);
09903       /* Clear this after we set it */
09904       p->redirecting_num[0] = 0;
09905    }
09906    if (!ast_strlen_zero(p->generic_name)) {
09907       pbx_builtin_setvar_helper(c, "SS7_GENERIC_NAME", p->generic_name);
09908       /* Clear this after we set it */
09909       p->generic_name[0] = 0;
09910    }
09911 
09912    ast_mutex_lock(&p->lock);
09913    ast_mutex_lock(&linkset->lock);
09914 }
09915 
09916 static void ss7_apply_plan_to_number(char *buf, size_t size, const struct dahdi_ss7 *ss7, const char *number, const unsigned nai)
09917 {
09918    if (ast_strlen_zero(number)) { /* make sure a number exists so prefix isn't placed on an empty string */
09919       if (size) {
09920          *buf = '\0';
09921       }
09922       return;
09923    }
09924    switch (nai) {
09925    case SS7_NAI_INTERNATIONAL:
09926       snprintf(buf, size, "%s%s", ss7->internationalprefix, number);
09927       break;
09928    case SS7_NAI_NATIONAL:
09929       snprintf(buf, size, "%s%s", ss7->nationalprefix, number);
09930       break;
09931    case SS7_NAI_SUBSCRIBER:
09932       snprintf(buf, size, "%s%s", ss7->subscriberprefix, number);
09933       break;
09934    case SS7_NAI_UNKNOWN:
09935       snprintf(buf, size, "%s%s", ss7->unknownprefix, number);
09936       break;
09937    default:
09938       snprintf(buf, size, "%s", number);
09939       break;
09940    }
09941 }
09942 static int ss7_pres_scr2cid_pres(char presentation_ind, char screening_ind)
09943 {
09944     return ((presentation_ind & 0x3) << 5) | (screening_ind & 0x3);
09945 }
09946 
09947 static void *ss7_linkset(void *data)
09948 {
09949    int res, i;
09950    struct timeval *next = NULL, tv;
09951    struct dahdi_ss7 *linkset = (struct dahdi_ss7 *) data;
09952    struct ss7 *ss7 = linkset->ss7;
09953    ss7_event *e = NULL;
09954    struct dahdi_pvt *p;
09955    int chanpos;
09956    struct pollfd pollers[NUM_DCHANS];
09957    int cic;
09958    unsigned int dpc;
09959    int nextms = 0;
09960 
09961    ss7_start(ss7);
09962 
09963    while(1) {
09964       ast_mutex_lock(&linkset->lock);
09965       if ((next = ss7_schedule_next(ss7))) {
09966          tv = ast_tvnow();
09967          tv.tv_sec = next->tv_sec - tv.tv_sec;
09968          tv.tv_usec = next->tv_usec - tv.tv_usec;
09969          if (tv.tv_usec < 0) {
09970             tv.tv_usec += 1000000;
09971             tv.tv_sec -= 1;
09972          }
09973          if (tv.tv_sec < 0) {
09974             tv.tv_sec = 0;
09975             tv.tv_usec = 0;
09976          }
09977          nextms = tv.tv_sec * 1000;
09978          nextms += tv.tv_usec / 1000;
09979       }
09980       ast_mutex_unlock(&linkset->lock);
09981 
09982       for (i = 0; i < linkset->numsigchans; i++) {
09983          pollers[i].fd = linkset->fds[i];
09984          pollers[i].events = ss7_pollflags(ss7, linkset->fds[i]);
09985          pollers[i].revents = 0;
09986       }
09987 
09988       res = poll(pollers, linkset->numsigchans, nextms);
09989       if ((res < 0) && (errno != EINTR)) {
09990          ast_log(LOG_ERROR, "poll(%s)\n", strerror(errno));
09991       } else if (!res) {
09992          ast_mutex_lock(&linkset->lock);
09993          ss7_schedule_run(ss7);
09994          ast_mutex_unlock(&linkset->lock);
09995          continue;
09996       }
09997 
09998       ast_mutex_lock(&linkset->lock);
09999       for (i = 0; i < linkset->numsigchans; i++) {
10000          if (pollers[i].revents & POLLPRI) {
10001             int x;
10002             if (ioctl(pollers[i].fd, DAHDI_GETEVENT, &x)) {
10003                ast_log(LOG_ERROR, "Error in exception retrieval!\n");
10004             }
10005             switch (x) {
10006             case DAHDI_EVENT_OVERRUN:
10007                ast_debug(1, "Overrun detected!\n");
10008                break;
10009             case DAHDI_EVENT_BADFCS:
10010                ast_debug(1, "Bad FCS\n");
10011                break;
10012             case DAHDI_EVENT_ABORT:
10013                ast_debug(1, "HDLC Abort\n");
10014                break;
10015             case DAHDI_EVENT_ALARM:
10016                ast_log(LOG_ERROR, "Alarm on link!\n");
10017                linkset->linkstate[i] |= (LINKSTATE_DOWN | LINKSTATE_INALARM);
10018                linkset->linkstate[i] &= ~LINKSTATE_UP;
10019                ss7_link_alarm(ss7, pollers[i].fd);
10020                break;
10021             case DAHDI_EVENT_NOALARM:
10022                ast_log(LOG_ERROR, "Alarm cleared on link\n");
10023                linkset->linkstate[i] &= ~(LINKSTATE_INALARM | LINKSTATE_DOWN);
10024                linkset->linkstate[i] |= LINKSTATE_STARTING;
10025                ss7_link_noalarm(ss7, pollers[i].fd);
10026                break;
10027             default:
10028                ast_log(LOG_ERROR, "Got exception %d!\n", x);
10029                break;
10030             }
10031          }
10032 
10033          if (pollers[i].revents & POLLIN) {
10034             ast_mutex_lock(&linkset->lock);
10035             res = ss7_read(ss7, pollers[i].fd);
10036             ast_mutex_unlock(&linkset->lock);
10037          }
10038 
10039          if (pollers[i].revents & POLLOUT) {
10040             ast_mutex_lock(&linkset->lock);
10041             res = ss7_write(ss7, pollers[i].fd);
10042             ast_mutex_unlock(&linkset->lock);
10043             if (res < 0) {
10044                ast_debug(1, "Error in write %s\n", strerror(errno));
10045             }
10046          }
10047       }
10048 
10049       while ((e = ss7_check_event(ss7))) {
10050          switch (e->e) {
10051          case SS7_EVENT_UP:
10052             if (linkset->state != LINKSET_STATE_UP) {
10053                ast_verbose("--- SS7 Up ---\n");
10054                ss7_reset_linkset(linkset);
10055             }
10056             linkset->state = LINKSET_STATE_UP;
10057             break;
10058          case SS7_EVENT_DOWN:
10059             ast_verbose("--- SS7 Down ---\n");
10060             linkset->state = LINKSET_STATE_DOWN;
10061             for (i = 0; i < linkset->numchans; i++) {
10062                struct dahdi_pvt *p = linkset->pvts[i];
10063                if (p)
10064                   p->inalarm = 1;
10065             }
10066             break;
10067          case MTP2_LINK_UP:
10068             ast_verbose("MTP2 link up (SLC %d)\n", e->gen.data);
10069             break;
10070          case MTP2_LINK_DOWN:
10071             ast_log(LOG_WARNING, "MTP2 link down (SLC %d)\n", e->gen.data);
10072             break;
10073          case ISUP_EVENT_CPG:
10074             chanpos = ss7_find_cic(linkset, e->cpg.cic, e->cpg.opc);
10075             if (chanpos < 0) {
10076                ast_log(LOG_WARNING, "CPG on unconfigured CIC %d\n", e->cpg.cic);
10077                break;
10078             }
10079             p = linkset->pvts[chanpos];
10080             ast_mutex_lock(&p->lock);
10081             switch (e->cpg.event) {
10082             case CPG_EVENT_ALERTING:
10083                p->alerting = 1;
10084                p->subs[SUB_REAL].needringing = 1;
10085                break;
10086             case CPG_EVENT_PROGRESS:
10087             case CPG_EVENT_INBANDINFO:
10088                {
10089                   struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, };
10090                   ast_debug(1, "Queuing frame PROGRESS on CIC %d\n", p->cic);
10091                   dahdi_queue_frame(p, &f, linkset);
10092                   p->progress = 1;
10093                   if (p->dsp && p->dsp_features) {
10094                           ast_dsp_set_features(p->dsp, p->dsp_features);
10095                           p->dsp_features = 0;
10096                   }
10097                }
10098                break;
10099             default:
10100                ast_debug(1, "Do not handle CPG with event type 0x%x\n", e->cpg.event);
10101             }
10102 
10103             ast_mutex_unlock(&p->lock);
10104             break;
10105          case ISUP_EVENT_RSC:
10106             ast_verbose("Resetting CIC %d\n", e->rsc.cic);
10107             chanpos = ss7_find_cic(linkset, e->rsc.cic, e->rsc.opc);
10108             if (chanpos < 0) {
10109                ast_log(LOG_WARNING, "RSC on unconfigured CIC %d\n", e->rsc.cic);
10110                break;
10111             }
10112             p = linkset->pvts[chanpos];
10113             ast_mutex_lock(&p->lock);
10114             p->inservice = 1;
10115             p->remotelyblocked = 0;
10116             dpc = p->dpc;
10117             isup_set_call_dpc(e->rsc.call, dpc);
10118             if (p->ss7call)
10119                p->ss7call = NULL;
10120             if (p->owner)
10121                p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
10122             ast_mutex_unlock(&p->lock);
10123             isup_rlc(ss7, e->rsc.call);
10124             break;
10125          case ISUP_EVENT_GRS:
10126             ast_debug(1, "Got Reset for CICs %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic);
10127             chanpos = ss7_find_cic(linkset, e->grs.startcic, e->grs.opc);
10128             if (chanpos < 0) {
10129                ast_log(LOG_WARNING, "GRS on unconfigured CIC %d\n", e->grs.startcic);
10130                break;
10131             }
10132             p = linkset->pvts[chanpos];
10133             isup_gra(ss7, e->grs.startcic, e->grs.endcic, e->grs.opc);
10134             ss7_block_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc, NULL, 0);
10135             break;
10136          case ISUP_EVENT_CQM:
10137             ast_debug(1, "Got Circuit group query message from CICs %d to %d\n", e->cqm.startcic, e->cqm.endcic);
10138             ss7_handle_cqm(linkset, e->cqm.startcic, e->cqm.endcic, e->cqm.opc);
10139             break;
10140          case ISUP_EVENT_GRA:
10141             ast_verbose("Got reset acknowledgement from CIC %d to %d.\n", e->gra.startcic, e->gra.endcic);
10142             ss7_inservice(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc);
10143             ss7_block_cics(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc, e->gra.status, 1);
10144             break;
10145          case ISUP_EVENT_IAM:
10146             ast_debug(1, "Got IAM for CIC %d and called number %s, calling number %s\n", e->iam.cic, e->iam.called_party_num, e->iam.calling_party_num);
10147             chanpos = ss7_find_cic(linkset, e->iam.cic, e->iam.opc);
10148             if (chanpos < 0) {
10149                ast_log(LOG_WARNING, "IAM on unconfigured CIC %d\n", e->iam.cic);
10150                isup_rel(ss7, e->iam.call, -1);
10151                break;
10152             }
10153             p = linkset->pvts[chanpos];
10154             ast_mutex_lock(&p->lock);
10155             if (p->owner) {
10156                if (p->ss7call == e->iam.call) {
10157                   ast_mutex_unlock(&p->lock);
10158                   ast_log(LOG_WARNING, "Duplicate IAM requested on CIC %d\n", e->iam.cic);
10159                   break;
10160                } else {
10161                   ast_mutex_unlock(&p->lock);
10162                   ast_log(LOG_WARNING, "Ring requested on CIC %d already in use!\n", e->iam.cic);
10163                   break;
10164                }
10165             }
10166 
10167             dpc = p->dpc;
10168             p->ss7call = e->iam.call;
10169             isup_set_call_dpc(p->ss7call, dpc);
10170 
10171             if ((p->use_callerid) && (!ast_strlen_zero(e->iam.calling_party_num))) {
10172                ss7_apply_plan_to_number(p->cid_num, sizeof(p->cid_num), linkset, e->iam.calling_party_num, e->iam.calling_nai);
10173                p->callingpres = ss7_pres_scr2cid_pres(e->iam.presentation_ind, e->iam.screening_ind);
10174             } else
10175                p->cid_num[0] = 0;
10176 
10177             if (p->immediate) {
10178                p->exten[0] = 's';
10179                p->exten[1] = '\0';
10180             } else if (!ast_strlen_zero(e->iam.called_party_num)) {
10181                char *st;
10182                ss7_apply_plan_to_number(p->exten, sizeof(p->exten), linkset, e->iam.called_party_num, e->iam.called_nai);
10183                st = strchr(p->exten, '#');
10184                if (st)
10185                   *st = '\0';
10186                } else
10187                   p->exten[0] = '\0';
10188 
10189             p->cid_ani[0] = '\0';
10190             if ((p->use_callerid) && (!ast_strlen_zero(e->iam.generic_name)))
10191                ast_copy_string(p->cid_name, e->iam.generic_name, sizeof(p->cid_name));
10192             else
10193                p->cid_name[0] = '\0';
10194             
10195             p->cid_ani2 = e->iam.oli_ani2;
10196             p->cid_ton = 0;
10197             ast_copy_string(p->charge_number, e->iam.charge_number, sizeof(p->charge_number));
10198             ast_copy_string(p->gen_add_number, e->iam.gen_add_number, sizeof(p->gen_add_number));
10199             p->gen_add_type = e->iam.gen_add_type;
10200             p->gen_add_nai = e->iam.gen_add_nai;
10201             p->gen_add_pres_ind = e->iam.gen_add_pres_ind;
10202             p->gen_add_num_plan = e->iam.gen_add_num_plan;
10203             ast_copy_string(p->gen_dig_number, e->iam.gen_dig_number, sizeof(p->gen_dig_number));
10204             p->gen_dig_type = e->iam.gen_dig_type;
10205             p->gen_dig_scheme = e->iam.gen_dig_scheme;
10206             ast_copy_string(p->jip_number, e->iam.jip_number, sizeof(p->jip_number));
10207             ast_copy_string(p->orig_called_num, e->iam.orig_called_num, sizeof(p->orig_called_num));
10208             ast_copy_string(p->redirecting_num, e->iam.redirecting_num, sizeof(p->redirecting_num));
10209             ast_copy_string(p->generic_name, e->iam.generic_name, sizeof(p->generic_name));
10210             p->calling_party_cat = e->iam.calling_party_cat;
10211                
10212             /* Set DNID */
10213             if (!ast_strlen_zero(e->iam.called_party_num))
10214                ss7_apply_plan_to_number(p->dnid, sizeof(p->dnid), linkset, e->iam.called_party_num, e->iam.called_nai);
10215             
10216             if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
10217 
10218                if (e->iam.cot_check_required) {
10219                   dahdi_loopback(p, 1);
10220                } else
10221                   ss7_start_call(p, linkset);
10222             } else {
10223                ast_debug(1, "Call on CIC for unconfigured extension %s\n", p->exten);
10224                p->alreadyhungup = 1;
10225                isup_rel(ss7, e->iam.call, AST_CAUSE_UNALLOCATED);
10226             }
10227             ast_mutex_unlock(&p->lock);
10228             break;
10229          case ISUP_EVENT_COT:
10230             chanpos = ss7_find_cic(linkset, e->cot.cic, e->cot.opc);
10231             if (chanpos < 0) {
10232                ast_log(LOG_WARNING, "COT on unconfigured CIC %d\n", e->cot.cic);
10233                isup_rel(ss7, e->cot.call, -1);
10234                break;
10235             }
10236             p = linkset->pvts[chanpos];
10237 
10238             ast_mutex_lock(&p->lock);
10239 
10240             if (p->loopedback) {
10241                dahdi_loopback(p, 0);
10242                ss7_start_call(p, linkset);
10243             }
10244 
10245             ast_mutex_unlock(&p->lock);
10246 
10247             break;
10248          case ISUP_EVENT_CCR:
10249             ast_debug(1, "Got CCR request on CIC %d\n", e->ccr.cic);
10250             chanpos = ss7_find_cic(linkset, e->ccr.cic, e->ccr.opc);
10251             if (chanpos < 0) {
10252                ast_log(LOG_WARNING, "CCR on unconfigured CIC %d\n", e->ccr.cic);
10253                break;
10254             }
10255 
10256             p = linkset->pvts[chanpos];
10257 
10258             ast_mutex_lock(&p->lock);
10259             dahdi_loopback(p, 1);
10260             ast_mutex_unlock(&p->lock);
10261 
10262             isup_lpa(linkset->ss7, e->ccr.cic, p->dpc);
10263             break;
10264          case ISUP_EVENT_CVT:
10265             ast_debug(1, "Got CVT request on CIC %d\n", e->cvt.cic);
10266             chanpos = ss7_find_cic(linkset, e->cvt.cic, e->cvt.opc);
10267             if (chanpos < 0) {
10268                ast_log(LOG_WARNING, "CVT on unconfigured CIC %d\n", e->cvt.cic);
10269                break;
10270             }
10271             
10272             p = linkset->pvts[chanpos];
10273             
10274             ast_mutex_lock(&p->lock);
10275             dahdi_loopback(p, 1);
10276             ast_mutex_unlock(&p->lock);
10277             
10278             isup_cvr(linkset->ss7, e->cvt.cic, p->dpc);
10279             break;
10280          case ISUP_EVENT_REL:
10281             chanpos = ss7_find_cic(linkset, e->rel.cic, e->rel.opc);
10282             if (chanpos < 0) {
10283                ast_log(LOG_WARNING, "REL on unconfigured CIC %d\n", e->rel.cic);
10284                break;
10285             }
10286             p = linkset->pvts[chanpos];
10287             ast_mutex_lock(&p->lock);
10288             if (p->owner) {
10289                p->owner->hangupcause = e->rel.cause;
10290                p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
10291             } else if (!p->restartpending)
10292                ast_log(LOG_WARNING, "REL on channel (CIC %d) without owner!\n", p->cic);
10293 
10294             /* End the loopback if we have one */
10295             dahdi_loopback(p, 0);
10296 
10297             isup_rlc(ss7, e->rel.call);
10298             p->ss7call = NULL;
10299 
10300             ast_mutex_unlock(&p->lock);
10301             break;
10302          case ISUP_EVENT_ACM:
10303             chanpos = ss7_find_cic(linkset, e->acm.cic, e->acm.opc);
10304             if (chanpos < 0) {
10305                ast_log(LOG_WARNING, "ACM on unconfigured CIC %d\n", e->acm.cic);
10306                isup_rel(ss7, e->acm.call, -1);
10307                break;
10308             } else {
10309                struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
10310 
10311                p = linkset->pvts[chanpos];
10312 
10313                ast_debug(1, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
10314                
10315                if (e->acm.call_ref_ident > 0) {
10316                   p->rlt = 1; /* Setting it but not using it here*/
10317                }
10318 
10319                ast_mutex_lock(&p->lock);
10320                dahdi_queue_frame(p, &f, linkset);
10321                p->proceeding = 1;
10322                /* Send alerting if subscriber is free */
10323                if (e->acm.called_party_status_ind == 1) {
10324                   p->alerting = 1;
10325                   p->subs[SUB_REAL].needringing = 1;
10326                }
10327                ast_mutex_unlock(&p->lock);
10328             }
10329             break;
10330          case ISUP_EVENT_CGB:
10331             chanpos = ss7_find_cic(linkset, e->cgb.startcic, e->cgb.opc);
10332             if (chanpos < 0) {
10333                ast_log(LOG_WARNING, "CGB on unconfigured CIC %d\n", e->cgb.startcic);
10334                break;
10335             }
10336             p = linkset->pvts[chanpos];
10337             ss7_block_cics(linkset, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, 1);
10338             isup_cgba(linkset->ss7, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, e->cgb.type);
10339             break;
10340          case ISUP_EVENT_CGU:
10341             chanpos = ss7_find_cic(linkset, e->cgu.startcic, e->cgu.opc);
10342             if (chanpos < 0) {
10343                ast_log(LOG_WARNING, "CGU on unconfigured CIC %d\n", e->cgu.startcic);
10344                break;
10345             }
10346             p = linkset->pvts[chanpos];
10347             ss7_block_cics(linkset, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, 0);
10348             isup_cgua(linkset->ss7, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, e->cgu.type);
10349             break;
10350          case ISUP_EVENT_UCIC:
10351             chanpos = ss7_find_cic(linkset, e->ucic.cic, e->ucic.opc);
10352             if (chanpos < 0) {
10353                ast_log(LOG_WARNING, "UCIC on unconfigured CIC %d\n", e->ucic.cic);
10354                break;
10355             }
10356             p = linkset->pvts[chanpos];
10357             ast_debug(1, "Unequiped Circuit Id Code on CIC %d\n", e->ucic.cic);
10358             ast_mutex_lock(&p->lock);
10359             p->remotelyblocked = 1;
10360             p->inservice = 0;
10361             ast_mutex_unlock(&p->lock);         //doesn't require a SS7 acknowledgement
10362             break;
10363          case ISUP_EVENT_BLO:
10364             chanpos = ss7_find_cic(linkset, e->blo.cic, e->blo.opc);
10365             if (chanpos < 0) {
10366                ast_log(LOG_WARNING, "BLO on unconfigured CIC %d\n", e->blo.cic);
10367                break;
10368             }
10369             p = linkset->pvts[chanpos];
10370             ast_debug(1, "Blocking CIC %d\n", e->blo.cic);
10371             ast_mutex_lock(&p->lock);
10372             p->remotelyblocked = 1;
10373             ast_mutex_unlock(&p->lock);
10374             isup_bla(linkset->ss7, e->blo.cic, p->dpc);
10375             break;
10376          case ISUP_EVENT_BLA:
10377             chanpos = ss7_find_cic(linkset, e->bla.cic, e->bla.opc);
10378             if (chanpos < 0) {
10379                ast_log(LOG_WARNING, "BLA on unconfigured CIC %d\n", e->bla.cic);
10380                break;
10381             }
10382             ast_debug(1, "Blocking CIC %d\n", e->bla.cic);
10383             p = linkset->pvts[chanpos];
10384             ast_mutex_lock(&p->lock);
10385             p->locallyblocked = 1;
10386             ast_mutex_unlock(&p->lock);
10387             break;
10388          case ISUP_EVENT_UBL:
10389             chanpos = ss7_find_cic(linkset, e->ubl.cic, e->ubl.opc);
10390             if (chanpos < 0) {
10391                ast_log(LOG_WARNING, "UBL on unconfigured CIC %d\n", e->ubl.cic);
10392                break;
10393             }
10394             p = linkset->pvts[chanpos];
10395             ast_debug(1, "Unblocking CIC %d\n", e->ubl.cic);
10396             ast_mutex_lock(&p->lock);
10397             p->remotelyblocked = 0;
10398             ast_mutex_unlock(&p->lock);
10399             isup_uba(linkset->ss7, e->ubl.cic, p->dpc);
10400             break;
10401          case ISUP_EVENT_UBA:
10402             chanpos = ss7_find_cic(linkset, e->uba.cic, e->uba.opc);
10403             if (chanpos < 0) {
10404                ast_log(LOG_WARNING, "UBA on unconfigured CIC %d\n", e->uba.cic);
10405                break;
10406             }
10407             p = linkset->pvts[chanpos];
10408             ast_debug(1, "Unblocking CIC %d\n", e->uba.cic);
10409             ast_mutex_lock(&p->lock);
10410             p->locallyblocked = 0;
10411             ast_mutex_unlock(&p->lock);
10412             break;
10413          case ISUP_EVENT_CON:
10414          case ISUP_EVENT_ANM:
10415             if (e->e == ISUP_EVENT_CON)
10416                cic = e->con.cic;
10417             else
10418                cic = e->anm.cic;
10419 
10420             chanpos = ss7_find_cic(linkset, cic, (e->e == ISUP_EVENT_ANM) ? e->anm.opc : e->con.opc);
10421             if (chanpos < 0) {
10422                ast_log(LOG_WARNING, "ANM/CON on unconfigured CIC %d\n", cic);
10423                isup_rel(ss7, (e->e == ISUP_EVENT_ANM) ? e->anm.call : e->con.call, -1);
10424                break;
10425             } else {
10426                p = linkset->pvts[chanpos];
10427                ast_mutex_lock(&p->lock);
10428                p->subs[SUB_REAL].needanswer = 1;
10429                if (p->dsp && p->dsp_features) {
10430                        ast_dsp_set_features(p->dsp, p->dsp_features);
10431                        p->dsp_features = 0;
10432                }
10433                dahdi_enable_ec(p);
10434                ast_mutex_unlock(&p->lock);
10435             }
10436             break;
10437          case ISUP_EVENT_RLC:
10438             chanpos = ss7_find_cic(linkset, e->rlc.cic, e->rlc.opc);
10439             if (chanpos < 0) {
10440                ast_log(LOG_WARNING, "RLC on unconfigured CIC %d\n", e->rlc.cic);
10441                break;
10442             } else {
10443                p = linkset->pvts[chanpos];
10444                ast_mutex_lock(&p->lock);
10445                if (p->alreadyhungup)
10446                   p->ss7call = NULL;
10447                else
10448                   ast_log(LOG_NOTICE, "Received RLC out and we haven't sent REL.  Ignoring.\n");
10449                ast_mutex_unlock(&p->lock);
10450                }
10451                break;
10452          case ISUP_EVENT_FAA:
10453             chanpos = ss7_find_cic(linkset, e->faa.cic, e->faa.opc);
10454             if (chanpos < 0) {
10455                ast_log(LOG_WARNING, "FAA on unconfigured CIC %d\n", e->faa.cic);
10456                break;
10457             } else {
10458                p = linkset->pvts[chanpos];
10459                ast_debug(1, "FAA received on CIC %d\n", e->faa.cic);
10460                ast_mutex_lock(&p->lock);
10461                if (p->alreadyhungup){
10462                   p->ss7call = NULL;
10463                   ast_log(LOG_NOTICE, "Received FAA and we haven't sent FAR.  Ignoring.\n");
10464                }
10465                ast_mutex_unlock(&p->lock);
10466             }
10467             break;
10468          default:
10469             ast_debug(1, "Unknown event %s\n", ss7_event2str(e->e));
10470             break;
10471          }
10472       }
10473       ast_mutex_unlock(&linkset->lock);
10474    }
10475 
10476    return 0;
10477 }
10478 
10479 static void dahdi_ss7_message(struct ss7 *ss7, char *s)
10480 {
10481 #if 0
10482    int i;
10483 
10484    for (i = 0; i < NUM_SPANS; i++)
10485       if (linksets[i].ss7 == ss7)
10486          break;
10487 
10488    ast_verbose("[%d] %s", i+1, s);
10489 #else
10490    ast_verbose("%s", s);
10491 #endif
10492 }
10493 
10494 static void dahdi_ss7_error(struct ss7 *ss7, char *s)
10495 {
10496 #if 0
10497    int i;
10498 
10499    for (i = 0; i < NUM_SPANS; i++)
10500       if (linksets[i].ss7 == ss7)
10501          break;
10502 
10503 #else
10504    ast_log(LOG_ERROR, "%s", s);
10505 #endif
10506 }
10507 
10508 #endif /* HAVE_SS7 */
10509 
10510 #ifdef HAVE_PRI
10511 static struct dahdi_pvt *pri_find_crv(struct dahdi_pri *pri, int crv)
10512 {
10513    struct dahdi_pvt *p;
10514    p = pri->crvs;
10515    while (p) {
10516       if (p->channel == crv)
10517          return p;
10518       p = p->next;
10519    }
10520    return NULL;
10521 }
10522 
10523 
10524 static int pri_find_principle(struct dahdi_pri *pri, int channel)
10525 {
10526    int x;
10527    int span = PRI_SPAN(channel);
10528    int spanfd;
10529    struct dahdi_params param;
10530    int principle = -1;
10531    int explicit = PRI_EXPLICIT(channel);
10532    channel = PRI_CHANNEL(channel);
10533 
10534    if (!explicit) {
10535       spanfd = pri_active_dchan_fd(pri);
10536       memset(&param, 0, sizeof(param));
10537       if (ioctl(spanfd, DAHDI_GET_PARAMS, &param))
10538          return -1;
10539       span = pris[param.spanno - 1].prilogicalspan;
10540    }
10541 
10542    for (x = 0; x < pri->numchans; x++) {
10543       if (pri->pvts[x] && (pri->pvts[x]->prioffset == channel) && (pri->pvts[x]->logicalspan == span)) {
10544          principle = x;
10545          break;
10546       }
10547    }
10548    
10549    return principle;
10550 }
10551 
10552 static int pri_fixup_principle(struct dahdi_pri *pri, int principle, q931_call *c)
10553 {
10554    int x;
10555    struct dahdi_pvt *crv;
10556    if (!c) {
10557       if (principle < 0)
10558          return -1;
10559       return principle;
10560    }
10561    if ((principle > -1) && 
10562       (principle < pri->numchans) && 
10563       (pri->pvts[principle]) && 
10564       (pri->pvts[principle]->call == c))
10565       return principle;
10566    /* First, check for other bearers */
10567    for (x = 0; x < pri->numchans; x++) {
10568       if (!pri->pvts[x])
10569          continue;
10570       if (pri->pvts[x]->call == c) {
10571          /* Found our call */
10572          if (principle != x) {
10573             struct dahdi_pvt *new = pri->pvts[principle], *old = pri->pvts[x];
10574 
10575             ast_verb(3, "Moving call from channel %d to channel %d\n",
10576                 old->channel, new->channel);
10577             if (new->owner) {
10578                ast_log(LOG_WARNING, "Can't fix up channel from %d to %d because %d is already in use\n",
10579                   old->channel, new->channel, new->channel);
10580                return -1;
10581             }
10582             /* Fix it all up now */
10583             new->owner = old->owner;
10584             old->owner = NULL;
10585             if (new->owner) {
10586                ast_string_field_build(new->owner, name, 
10587                             "DAHDI/%d:%d-%d", pri->trunkgroup,
10588                             new->channel, 1);
10589                new->owner->tech_pvt = new;
10590                ast_channel_set_fd(new->owner, 0, new->subs[SUB_REAL].dfd);
10591                new->subs[SUB_REAL].owner = old->subs[SUB_REAL].owner;
10592                old->subs[SUB_REAL].owner = NULL;
10593             } else
10594                ast_log(LOG_WARNING, "Whoa, there's no  owner, and we're having to fix up channel %d to channel %d\n", old->channel, new->channel);
10595             new->call = old->call;
10596             old->call = NULL;
10597 
10598             /* Copy any DSP that may be present */
10599             new->dsp = old->dsp;
10600             new->dsp_features = old->dsp_features;
10601             old->dsp = NULL;
10602             old->dsp_features = 0;
10603          }
10604          return principle;
10605       }
10606    }
10607    /* Now check for a CRV with no bearer */
10608    crv = pri->crvs;
10609    while (crv) {
10610       if (crv->call == c) {
10611          /* This is our match...  Perform some basic checks */
10612          if (crv->bearer)
10613             ast_log(LOG_WARNING, "Trying to fix up call which already has a bearer which isn't the one we think it is\n");
10614          else if (pri->pvts[principle]->owner) 
10615             ast_log(LOG_WARNING, "Tring to fix up a call to a bearer which already has an owner!\n");
10616          else {
10617             /* Looks good.  Drop the pseudo channel now, clear up the assignment, and
10618                wakeup the potential sleeper */
10619             dahdi_close_sub(crv, SUB_REAL);
10620             pri->pvts[principle]->call = crv->call;
10621             pri_assign_bearer(crv, pri, pri->pvts[principle]);
10622             ast_debug(1, "Assigning bearer %d/%d to CRV %d:%d\n",
10623                pri->pvts[principle]->logicalspan, pri->pvts[principle]->prioffset,
10624                pri->trunkgroup, crv->channel);
10625             wakeup_sub(crv, SUB_REAL, pri);
10626          }
10627          return principle;
10628       }
10629       crv = crv->next;
10630    }
10631    ast_log(LOG_WARNING, "Call specified, but not found?\n");
10632    return -1;
10633 }
10634 
10635 static void *do_idle_thread(void *vchan)
10636 {
10637    struct ast_channel *chan = vchan;
10638    struct dahdi_pvt *pvt = chan->tech_pvt;
10639    struct ast_frame *f;
10640    char ex[80];
10641    /* Wait up to 30 seconds for an answer */
10642    int newms, ms = 30000;
10643    ast_verb(3, "Initiating idle call on channel %s\n", chan->name);
10644    snprintf(ex, sizeof(ex), "%d/%s", pvt->channel, pvt->pri->idledial);
10645    if (ast_call(chan, ex, 0)) {
10646       ast_log(LOG_WARNING, "Idle dial failed on '%s' to '%s'\n", chan->name, ex);
10647       ast_hangup(chan);
10648       return NULL;
10649    }
10650    while ((newms = ast_waitfor(chan, ms)) > 0) {
10651       f = ast_read(chan);
10652       if (!f) {
10653          /* Got hangup */
10654          break;
10655       }
10656       if (f->frametype == AST_FRAME_CONTROL) {
10657          switch (f->subclass) {
10658          case AST_CONTROL_ANSWER:
10659             /* Launch the PBX */
10660             ast_copy_string(chan->exten, pvt->pri->idleext, sizeof(chan->exten));
10661             ast_copy_string(chan->context, pvt->pri->idlecontext, sizeof(chan->context));
10662             chan->priority = 1;
10663             ast_verb(4, "Idle channel '%s' answered, sending to %s@%s\n", chan->name, chan->exten, chan->context);
10664             ast_pbx_run(chan);
10665             /* It's already hungup, return immediately */
10666             return NULL;
10667          case AST_CONTROL_BUSY:
10668             ast_verb(4, "Idle channel '%s' busy, waiting...\n", chan->name);
10669             break;
10670          case AST_CONTROL_CONGESTION:
10671             ast_verb(4, "Idle channel '%s' congested, waiting...\n", chan->name);
10672             break;
10673          };
10674       }
10675       ast_frfree(f);
10676       ms = newms;
10677    }
10678    /* Hangup the channel since nothing happend */
10679    ast_hangup(chan);
10680    return NULL;
10681 }
10682 
10683 #ifndef PRI_RESTART
10684 #error "Upgrade your libpri"
10685 #endif
10686 static void dahdi_pri_message(struct pri *pri, char *s)
10687 {
10688    int x, y;
10689    int dchan = -1, span = -1;
10690    int dchancount = 0;
10691 
10692    if (pri) {
10693       for (x = 0; x < NUM_SPANS; x++) {
10694          for (y = 0; y < NUM_DCHANS; y++) {
10695             if (pris[x].dchans[y])
10696                dchancount++;
10697 
10698             if (pris[x].dchans[y] == pri)
10699                dchan = y;
10700          }
10701          if (dchan >= 0) {
10702             span = x;
10703             break;
10704          }
10705          dchancount = 0;
10706       }
10707       if (dchancount > 1 && (span > -1))
10708          ast_verbose("[Span %d D-Channel %d]%s", span, dchan, s);
10709       else
10710          ast_verbose("%s", s);
10711    } else
10712       ast_verbose("%s", s);
10713 
10714    ast_mutex_lock(&pridebugfdlock);
10715 
10716    if (pridebugfd >= 0) {
10717       if (write(pridebugfd, s, strlen(s)) < 0) {
10718          ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
10719       }
10720    }
10721 
10722    ast_mutex_unlock(&pridebugfdlock);
10723 }
10724 
10725 static void dahdi_pri_error(struct pri *pri, char *s)
10726 {
10727    int x, y;
10728    int dchan = -1, span = -1;
10729    int dchancount = 0;
10730 
10731    if (pri) {
10732       for (x = 0; x < NUM_SPANS; x++) {
10733          for (y = 0; y < NUM_DCHANS; y++) {
10734             if (pris[x].dchans[y])
10735                dchancount++;
10736 
10737             if (pris[x].dchans[y] == pri)
10738                dchan = y;
10739          }
10740          if (dchan >= 0) {
10741             span = x;
10742             break;
10743          }
10744          dchancount = 0;
10745       }
10746       if ((dchancount > 1) && (span > -1))
10747          ast_log(LOG_ERROR, "[Span %d D-Channel %d] PRI: %s", span, dchan, s);
10748       else
10749          ast_log(LOG_ERROR, "%s", s);
10750    } else
10751       ast_log(LOG_ERROR, "%s", s);
10752 
10753    ast_mutex_lock(&pridebugfdlock);
10754 
10755    if (pridebugfd >= 0) {
10756       if (write(pridebugfd, s, strlen(s)) < 0) {
10757          ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
10758       }
10759    }
10760 
10761    ast_mutex_unlock(&pridebugfdlock);
10762 }
10763 
10764 static int pri_check_restart(struct dahdi_pri *pri)
10765 {
10766    do {
10767       pri->resetpos++;
10768    } while ((pri->resetpos < pri->numchans) &&
10769        (!pri->pvts[pri->resetpos] ||
10770         pri->pvts[pri->resetpos]->call ||
10771         pri->pvts[pri->resetpos]->resetting));
10772    if (pri->resetpos < pri->numchans) {
10773       /* Mark the channel as resetting and restart it */
10774       pri->pvts[pri->resetpos]->resetting = 1;
10775       pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[pri->resetpos]));
10776    } else {
10777       pri->resetting = 0;
10778       time(&pri->lastreset);
10779    }
10780    return 0;
10781 }
10782 
10783 static int pri_hangup_all(struct dahdi_pvt *p, struct dahdi_pri *pri)
10784 {
10785    int x;
10786    int redo;
10787    ast_mutex_unlock(&pri->lock);
10788    ast_mutex_lock(&p->lock);
10789    do {
10790       redo = 0;
10791       for (x = 0; x < 3; x++) {
10792          while (p->subs[x].owner && ast_channel_trylock(p->subs[x].owner)) {
10793             redo++;
10794             DEADLOCK_AVOIDANCE(&p->lock);
10795          }
10796          if (p->subs[x].owner) {
10797             ast_queue_hangup_with_cause(p->subs[x].owner, AST_CAUSE_PRE_EMPTED);
10798             ast_channel_unlock(p->subs[x].owner);
10799          }
10800       }
10801    } while (redo);
10802    ast_mutex_unlock(&p->lock);
10803    ast_mutex_lock(&pri->lock);
10804    return 0;
10805 }
10806 
10807 static char * redirectingreason2str(int redirectingreason)
10808 {
10809    switch (redirectingreason) {
10810    case 0:
10811       return "UNKNOWN";
10812    case 1:
10813       return "BUSY";
10814    case 2:
10815       return "NO_REPLY";
10816    case 0xF:
10817       return "UNCONDITIONAL";
10818    default:
10819       return "NOREDIRECT";
10820    }
10821 }
10822 
10823 static void apply_plan_to_number(char *buf, size_t size, const struct dahdi_pri *pri, const char *number, const int plan)
10824 {
10825    if (pri->dialplan == -2) { /* autodetect the TON but leave the number untouched */
10826       snprintf(buf, size, "%s", number);
10827       return;
10828    }
10829    if (ast_strlen_zero(number)) { /* make sure a number exists so prefix isn't placed on an empty string */
10830       if (size) {
10831          *buf = '\0';
10832       }
10833       return;
10834    }
10835    switch (plan) {
10836    case PRI_INTERNATIONAL_ISDN:     /* Q.931 dialplan == 0x11 international dialplan => prepend international prefix digits */
10837       snprintf(buf, size, "%s%s", pri->internationalprefix, number);
10838       break;
10839    case PRI_NATIONAL_ISDN:       /* Q.931 dialplan == 0x21 national dialplan => prepend national prefix digits */
10840       snprintf(buf, size, "%s%s", pri->nationalprefix, number);
10841       break;
10842    case PRI_LOCAL_ISDN:       /* Q.931 dialplan == 0x41 local dialplan => prepend local prefix digits */
10843       snprintf(buf, size, "%s%s", pri->localprefix, number);
10844       break;
10845    case PRI_PRIVATE:       /* Q.931 dialplan == 0x49 private dialplan => prepend private prefix digits */
10846       snprintf(buf, size, "%s%s", pri->privateprefix, number);
10847       break;
10848    case PRI_UNKNOWN:       /* Q.931 dialplan == 0x00 unknown dialplan => prepend unknown prefix digits */
10849       snprintf(buf, size, "%s%s", pri->unknownprefix, number);
10850       break;
10851    default:          /* other Q.931 dialplan => don't twiddle with callingnum */
10852       snprintf(buf, size, "%s", number);
10853       break;
10854    }
10855 }
10856 
10857 
10858 static void *pri_dchannel(void *vpri)
10859 {
10860    struct dahdi_pri *pri = vpri;
10861    pri_event *e;
10862    struct pollfd fds[NUM_DCHANS];
10863    int res;
10864    int chanpos = 0;
10865    int x;
10866    int haveidles;
10867    int activeidles;
10868    int nextidle = -1;
10869    struct ast_channel *c;
10870    struct timeval tv, lowest, *next;
10871    struct timeval lastidle = ast_tvnow();
10872    int doidling=0;
10873    char *cc;
10874    char idlen[80];
10875    struct ast_channel *idle;
10876    pthread_t p;
10877    time_t t;
10878    int i, which=-1;
10879    int numdchans;
10880    int cause=0;
10881    struct dahdi_pvt *crv;
10882    pthread_t threadid;
10883    char ani2str[6];
10884    char plancallingnum[256];
10885    char plancallingani[256];
10886    char calledtonstr[10];
10887    
10888    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
10889 
10890    gettimeofday(&lastidle, NULL);
10891    if (!ast_strlen_zero(pri->idledial) && !ast_strlen_zero(pri->idleext)) {
10892       /* Need to do idle dialing, check to be sure though */
10893       cc = strchr(pri->idleext, '@');
10894       if (cc) {
10895          *cc = '\0';
10896          cc++;
10897          ast_copy_string(pri->idlecontext, cc, sizeof(pri->idlecontext));
10898 #if 0
10899          /* Extensions may not be loaded yet */
10900          if (!ast_exists_extension(NULL, pri->idlecontext, pri->idleext, 1, NULL))
10901             ast_log(LOG_WARNING, "Extension '%s @ %s' does not exist\n", pri->idleext, pri->idlecontext);
10902          else
10903 #endif
10904             doidling = 1;
10905       } else
10906          ast_log(LOG_WARNING, "Idle dial string '%s' lacks '@context'\n", pri->idleext);
10907    }
10908    for (;;) {
10909       for (i = 0; i < NUM_DCHANS; i++) {
10910          if (!pri->dchannels[i])
10911             break;
10912          fds[i].fd = pri->fds[i];
10913          fds[i].events = POLLIN | POLLPRI;
10914          fds[i].revents = 0;
10915       }
10916       numdchans = i;
10917       time(&t);
10918       ast_mutex_lock(&pri->lock);
10919       if (pri->switchtype != PRI_SWITCH_GR303_TMC && (pri->resetinterval > 0)) {
10920          if (pri->resetting && pri_is_up(pri)) {
10921             if (pri->resetpos < 0)
10922                pri_check_restart(pri);
10923          } else {
10924             if (!pri->resetting  && (t - pri->lastreset) >= pri->resetinterval) {
10925                pri->resetting = 1;
10926                pri->resetpos = -1;
10927             }
10928          }
10929       }
10930       /* Look for any idle channels if appropriate */
10931       if (doidling && pri_is_up(pri)) {
10932          nextidle = -1;
10933          haveidles = 0;
10934          activeidles = 0;
10935          for (x = pri->numchans; x >= 0; x--) {
10936             if (pri->pvts[x] && !pri->pvts[x]->owner && 
10937                 !pri->pvts[x]->call) {
10938                if (haveidles < pri->minunused) {
10939                   haveidles++;
10940                } else if (!pri->pvts[x]->resetting) {
10941                   nextidle = x;
10942                   break;
10943                }
10944             } else if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall)
10945                activeidles++;
10946          }
10947          if (nextidle > -1) {
10948             if (ast_tvdiff_ms(ast_tvnow(), lastidle) > 1000) {
10949                /* Don't create a new idle call more than once per second */
10950                snprintf(idlen, sizeof(idlen), "%d/%s", pri->pvts[nextidle]->channel, pri->idledial);
10951                idle = dahdi_request("DAHDI", AST_FORMAT_ULAW, idlen, &cause);
10952                if (idle) {
10953                   pri->pvts[nextidle]->isidlecall = 1;
10954                   if (ast_pthread_create_background(&p, NULL, do_idle_thread, idle)) {
10955                      ast_log(LOG_WARNING, "Unable to start new thread for idle channel '%s'\n", idle->name);
10956                      dahdi_hangup(idle);
10957                   }
10958                } else
10959                   ast_log(LOG_WARNING, "Unable to request channel 'DAHDI/%s' for idle call\n", idlen);
10960                lastidle = ast_tvnow();
10961             }
10962          } else if ((haveidles < pri->minunused) &&
10963                (activeidles > pri->minidle)) {
10964             /* Mark something for hangup if there is something 
10965                that can be hungup */
10966             for (x = pri->numchans; x >= 0; x--) {
10967                /* find a candidate channel */
10968                if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall) {
10969                   pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
10970                   haveidles++;
10971                   /* Stop if we have enough idle channels or
10972                     can't spare any more active idle ones */
10973                   if ((haveidles >= pri->minunused) ||
10974                       (activeidles <= pri->minidle))
10975                      break;
10976                } 
10977             }
10978          }
10979       }
10980       /* Start with reasonable max */
10981       lowest = ast_tv(60, 0);
10982       for (i = 0; i < NUM_DCHANS; i++) {
10983          /* Find lowest available d-channel */
10984          if (!pri->dchannels[i])
10985             break;
10986          if ((next = pri_schedule_next(pri->dchans[i]))) {
10987             /* We need relative time here */
10988             tv = ast_tvsub(*next, ast_tvnow());
10989             if (tv.tv_sec < 0) {
10990                tv = ast_tv(0,0);
10991             }
10992             if (doidling || pri->resetting) {
10993                if (tv.tv_sec > 1) {
10994                   tv = ast_tv(1, 0);
10995                }
10996             } else {
10997                if (tv.tv_sec > 60) {
10998                   tv = ast_tv(60, 0);
10999                }
11000             }
11001          } else if (doidling || pri->resetting) {
11002             /* Make sure we stop at least once per second if we're
11003                monitoring idle channels */
11004             tv = ast_tv(1,0);
11005          } else {
11006             /* Don't poll for more than 60 seconds */
11007             tv = ast_tv(60, 0);
11008          }
11009          if (!i || ast_tvcmp(tv, lowest) < 0) {
11010             lowest = tv;
11011          }
11012       }
11013       ast_mutex_unlock(&pri->lock);
11014 
11015       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
11016       pthread_testcancel();
11017       e = NULL;
11018       res = poll(fds, numdchans, lowest.tv_sec * 1000 + lowest.tv_usec / 1000);
11019       pthread_testcancel();
11020       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
11021 
11022       ast_mutex_lock(&pri->lock);
11023       if (!res) {
11024          for (which = 0; which < NUM_DCHANS; which++) {
11025             if (!pri->dchans[which])
11026                break;
11027             /* Just a timeout, run the scheduler */
11028             e = pri_schedule_run(pri->dchans[which]);
11029             if (e)
11030                break;
11031          }
11032       } else if (res > -1) {
11033          for (which = 0; which < NUM_DCHANS; which++) {
11034             if (!pri->dchans[which])
11035                break;
11036             if (fds[which].revents & POLLPRI) {
11037                /* Check for an event */
11038                x = 0;
11039                res = ioctl(pri->fds[which], DAHDI_GETEVENT, &x);
11040                if (x) {
11041                   ast_log(LOG_NOTICE, "PRI got event: %s (%d) on %s D-channel of span %d\n", event2str(x), x, pri_order(which), pri->span);
11042                   manager_event(EVENT_FLAG_SYSTEM, "PRIEvent",
11043                      "PRIEvent: %s\r\n"
11044                      "PRIEventCode: %d\r\n"
11045                      "D-channel: %s\r\n"
11046                      "Span: %d\r\n",
11047                      event2str(x),
11048                      x,
11049                      pri_order(which),
11050                      pri->span
11051                      );
11052                }
11053                /* Keep track of alarm state */  
11054                if (x == DAHDI_EVENT_ALARM) {
11055                   pri->dchanavail[which] &= ~(DCHAN_NOTINALARM | DCHAN_UP);
11056                   pri_find_dchan(pri);
11057                } else if (x == DAHDI_EVENT_NOALARM) {
11058                   pri->dchanavail[which] |= DCHAN_NOTINALARM;
11059                   pri_restart(pri->dchans[which]);
11060                }
11061             
11062                ast_debug(1, "Got event %s (%d) on D-channel for span %d\n", event2str(x), x, pri->span);
11063             } else if (fds[which].revents & POLLIN) {
11064                e = pri_check_event(pri->dchans[which]);
11065             }
11066             if (e)
11067                break;
11068          }
11069       } else if (errno != EINTR)
11070          ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
11071 
11072       if (e) {
11073          if (pri->debug)
11074             pri_dump_event(pri->dchans[which], e);
11075 
11076          if (e->e != PRI_EVENT_DCHAN_DOWN) {
11077             if (!(pri->dchanavail[which] & DCHAN_UP)) {
11078                ast_verb(2, "%s D-Channel on span %d up\n", pri_order(which), pri->span);
11079             }
11080             pri->dchanavail[which] |= DCHAN_UP;
11081          } else {
11082             if (pri->dchanavail[which] & DCHAN_UP) {
11083                ast_verb(2, "%s D-Channel on span %d down\n", pri_order(which), pri->span);
11084             }
11085             pri->dchanavail[which] &= ~DCHAN_UP;
11086          }
11087 
11088          if ((e->e != PRI_EVENT_DCHAN_UP) && (e->e != PRI_EVENT_DCHAN_DOWN) && (pri->pri != pri->dchans[which]))
11089             /* Must be an NFAS group that has the secondary dchan active */
11090             pri->pri = pri->dchans[which];
11091 
11092          switch (e->e) {
11093          case PRI_EVENT_DCHAN_UP:
11094             if (!pri->pri) pri_find_dchan(pri);
11095 
11096             /* Note presense of D-channel */
11097             time(&pri->lastreset);
11098 
11099             /* Restart in 5 seconds */
11100             if (pri->resetinterval > -1) {
11101                pri->lastreset -= pri->resetinterval;
11102                pri->lastreset += 5;
11103             }
11104             pri->resetting = 0;
11105             /* Take the channels from inalarm condition */
11106             for (i = 0; i < pri->numchans; i++)
11107                if (pri->pvts[i]) {
11108                   pri->pvts[i]->inalarm = 0;
11109                }
11110             break;
11111          case PRI_EVENT_DCHAN_DOWN:
11112             pri_find_dchan(pri);
11113             if (!pri_is_up(pri)) {
11114                pri->resetting = 0;
11115                /* Hangup active channels and put them in alarm mode */
11116                for (i = 0; i < pri->numchans; i++) {
11117                   struct dahdi_pvt *p = pri->pvts[i];
11118                   if (p) {
11119                      if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
11120                         /* T309 is not enabled : hangup calls when alarm occurs */
11121                         if (p->call) {
11122                            if (p->pri && p->pri->pri) {
11123                               pri_hangup(p->pri->pri, p->call, -1);
11124                               pri_destroycall(p->pri->pri, p->call);
11125                               p->call = NULL;
11126                            } else
11127                               ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
11128                         }
11129                         if (p->realcall) {
11130                            pri_hangup_all(p->realcall, pri);
11131                         } else if (p->owner)
11132                            p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11133                      }
11134                      p->inalarm = 1;
11135                   }
11136                }
11137             }
11138             break;
11139          case PRI_EVENT_RESTART:
11140             if (e->restart.channel > -1) {
11141                chanpos = pri_find_principle(pri, e->restart.channel);
11142                if (chanpos < 0)
11143                   ast_log(LOG_WARNING, "Restart requested on odd/unavailable channel number %d/%d on span %d\n", 
11144                      PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
11145                else {
11146                   ast_verb(3, "B-channel %d/%d restarted on span %d\n",
11147                         PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
11148                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11149                   if (pri->pvts[chanpos]->call) {
11150                      pri_destroycall(pri->pri, pri->pvts[chanpos]->call);
11151                      pri->pvts[chanpos]->call = NULL;
11152                   }
11153                   /* Force soft hangup if appropriate */
11154                   if (pri->pvts[chanpos]->realcall) 
11155                      pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11156                   else if (pri->pvts[chanpos]->owner)
11157                      pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11158                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11159                }
11160             } else {
11161                ast_verb(3, "Restart on requested on entire span %d\n", pri->span);
11162                for (x = 0; x < pri->numchans; x++)
11163                   if (pri->pvts[x]) {
11164                      ast_mutex_lock(&pri->pvts[x]->lock);
11165                      if (pri->pvts[x]->call) {
11166                         pri_destroycall(pri->pri, pri->pvts[x]->call);
11167                         pri->pvts[x]->call = NULL;
11168                      }
11169                      if (pri->pvts[chanpos]->realcall) 
11170                         pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11171                      else if (pri->pvts[x]->owner)
11172                         pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11173                      ast_mutex_unlock(&pri->pvts[x]->lock);
11174                   }
11175             }
11176             break;
11177          case PRI_EVENT_KEYPAD_DIGIT:
11178             chanpos = pri_find_principle(pri, e->digit.channel);
11179             if (chanpos < 0) {
11180                ast_log(LOG_WARNING, "KEYPAD_DIGITs received on unconfigured channel %d/%d span %d\n", 
11181                   PRI_SPAN(e->digit.channel), PRI_CHANNEL(e->digit.channel), pri->span);
11182             } else {
11183                chanpos = pri_fixup_principle(pri, chanpos, e->digit.call);
11184                if (chanpos > -1) {
11185                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11186                   /* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
11187                   if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->digit.call && pri->pvts[chanpos]->owner) {
11188                      /* how to do that */
11189                      int digitlen = strlen(e->digit.digits);
11190                      char digit;
11191                      int i;               
11192                      for (i = 0; i < digitlen; i++) { 
11193                         digit = e->digit.digits[i];
11194                         {
11195                            struct ast_frame f = { AST_FRAME_DTMF, digit, };
11196                            dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11197                         }
11198                      }
11199                   }
11200                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11201                }
11202             }
11203             break;
11204             
11205          case PRI_EVENT_INFO_RECEIVED:
11206             chanpos = pri_find_principle(pri, e->ring.channel);
11207             if (chanpos < 0) {
11208                ast_log(LOG_WARNING, "INFO received on unconfigured channel %d/%d span %d\n", 
11209                   PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
11210             } else {
11211                chanpos = pri_fixup_principle(pri, chanpos, e->ring.call);
11212                if (chanpos > -1) {
11213                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11214                   /* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
11215                   if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) {
11216                      /* how to do that */
11217                      int digitlen = strlen(e->ring.callednum);
11218                      char digit;
11219                      int i;               
11220                      for (i = 0; i < digitlen; i++) { 
11221                         digit = e->ring.callednum[i];
11222                         {
11223                            struct ast_frame f = { AST_FRAME_DTMF, digit, };
11224                            dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11225                         }
11226                      }
11227                   }
11228                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11229                }
11230             }
11231             break;
11232          case PRI_EVENT_RING:
11233             crv = NULL;
11234             if (e->ring.channel == -1)
11235                chanpos = pri_find_empty_chan(pri, 1);
11236             else
11237                chanpos = pri_find_principle(pri, e->ring.channel);
11238             /* if no channel specified find one empty */
11239             if (chanpos < 0) {
11240                ast_log(LOG_WARNING, "Ring requested on unconfigured channel %d/%d span %d\n", 
11241                   PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
11242             } else {
11243                ast_mutex_lock(&pri->pvts[chanpos]->lock);
11244                if (pri->pvts[chanpos]->owner) {
11245                   if (pri->pvts[chanpos]->call == e->ring.call) {
11246                      ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n", 
11247                         PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
11248                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11249                      break;
11250                   } else {
11251                      /* This is where we handle initial glare */
11252                      ast_debug(1, "Ring requested on channel %d/%d already in use or previously requested on span %d.  Attempting to renegotiate channel.\n", 
11253                      PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
11254                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11255                      chanpos = -1;
11256                   }
11257                }
11258                if (chanpos > -1)
11259                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11260             }
11261             if ((chanpos < 0) && (e->ring.flexible))
11262                chanpos = pri_find_empty_chan(pri, 1);
11263             if (chanpos > -1) {
11264                ast_mutex_lock(&pri->pvts[chanpos]->lock);
11265                if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
11266                   /* Should be safe to lock CRV AFAIK while bearer is still locked */
11267                   crv = pri_find_crv(pri, pri_get_crv(pri->pri, e->ring.call, NULL));
11268                   if (crv)
11269                      ast_mutex_lock(&crv->lock);
11270                   if (!crv || crv->owner) {
11271                      pri->pvts[chanpos]->call = NULL;
11272                      if (crv) {
11273                         if (crv->owner)
11274                            crv->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11275                         ast_log(LOG_WARNING, "Call received for busy CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
11276                      } else
11277                         ast_log(LOG_NOTICE, "Call received for unconfigured CRV %d on span %d\n", pri_get_crv(pri->pri, e->ring.call, NULL), pri->span);
11278                      pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INVALID_CALL_REFERENCE);
11279                      if (crv)
11280                         ast_mutex_unlock(&crv->lock);
11281                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11282                      break;
11283                   }
11284                }
11285                pri->pvts[chanpos]->call = e->ring.call;
11286                apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
11287                if (pri->pvts[chanpos]->use_callerid) {
11288                   ast_shrink_phone_number(plancallingnum);
11289                   ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum, sizeof(pri->pvts[chanpos]->cid_num));
11290 #ifdef PRI_ANI
11291                   if (!ast_strlen_zero(e->ring.callingani)) {
11292                      apply_plan_to_number(plancallingani, sizeof(plancallingani), pri, e->ring.callingani, e->ring.callingplanani);
11293                      ast_shrink_phone_number(plancallingani);
11294                      ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani, sizeof(pri->pvts[chanpos]->cid_ani));
11295                   } else {
11296                      pri->pvts[chanpos]->cid_ani[0] = '\0';
11297                   }
11298 #endif
11299                   ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname, sizeof(pri->pvts[chanpos]->cid_name));
11300                   pri->pvts[chanpos]->cid_ton = e->ring.callingplan; /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
11301                } else {
11302                   pri->pvts[chanpos]->cid_num[0] = '\0';
11303                   pri->pvts[chanpos]->cid_ani[0] = '\0';
11304                   pri->pvts[chanpos]->cid_name[0] = '\0';
11305                   pri->pvts[chanpos]->cid_ton = 0;
11306                }
11307                apply_plan_to_number(pri->pvts[chanpos]->rdnis, sizeof(pri->pvts[chanpos]->rdnis), pri,
11308                           e->ring.redirectingnum, e->ring.callingplanrdnis);
11309                /* If immediate=yes go to s|1 */
11310                if (pri->pvts[chanpos]->immediate) {
11311                   ast_verb(3, "Going to extension s|1 because of immediate=yes\n");
11312                   pri->pvts[chanpos]->exten[0] = 's';
11313                   pri->pvts[chanpos]->exten[1] = '\0';
11314                }
11315                /* Get called number */
11316                else if (!ast_strlen_zero(e->ring.callednum)) {
11317                   ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
11318                   ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
11319                } else if (pri->overlapdial)
11320                   pri->pvts[chanpos]->exten[0] = '\0';
11321                else {
11322                   /* Some PRI circuits are set up to send _no_ digits.  Handle them as 's'. */
11323                   pri->pvts[chanpos]->exten[0] = 's';
11324                   pri->pvts[chanpos]->exten[1] = '\0';
11325                }
11326                /* Set DNID on all incoming calls -- even immediate */
11327                if (!ast_strlen_zero(e->ring.callednum))
11328                   ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
11329                /* No number yet, but received "sending complete"? */
11330                if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
11331                   ast_verb(3, "Going to extension s|1 because of Complete received\n");
11332                   pri->pvts[chanpos]->exten[0] = 's';
11333                   pri->pvts[chanpos]->exten[1] = '\0';
11334                }
11335                /* Make sure extension exists (or in overlap dial mode, can exist) */
11336                if (((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
11337                   ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
11338                   /* Setup law */
11339                   int law;
11340                   if (pri->switchtype != PRI_SWITCH_GR303_TMC) {
11341                      /* Set to audio mode at this point */
11342                      law = 1;
11343                      if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law) == -1)
11344                         ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", pri->pvts[chanpos]->channel, law, strerror(errno));
11345                   }
11346                   if (e->ring.layer1 == PRI_LAYER_1_ALAW)
11347                      law = DAHDI_LAW_ALAW;
11348                   else
11349                      law = DAHDI_LAW_MULAW;
11350                   res = dahdi_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].dfd, law);
11351                   if (res < 0) 
11352                      ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvts[chanpos]->channel);
11353                   res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].dfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
11354                   if (res < 0)
11355                      ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[chanpos]->channel);
11356                   if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
11357                      /* Just announce proceeding */
11358                      pri->pvts[chanpos]->proceeding = 1;
11359                      pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
11360                   } else {
11361                      if (pri->switchtype != PRI_SWITCH_GR303_TMC) 
11362                         pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
11363                      else
11364                         pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
11365                   }
11366                   /* Get the use_callingpres state */
11367                   pri->pvts[chanpos]->callingpres = e->ring.callingpres;
11368                
11369                   /* Start PBX */
11370                   if (!e->ring.complete && (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
11371                      /* Release the PRI lock while we create the channel */
11372                      ast_mutex_unlock(&pri->lock);
11373                      if (crv) {
11374                         /* Set bearer and such */
11375                         pri_assign_bearer(crv, pri, pri->pvts[chanpos]);
11376                         c = dahdi_new(crv, AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
11377                         pri->pvts[chanpos]->owner = &inuse;
11378                         ast_debug(1, "Started up crv %d:%d on bearer channel %d\n", pri->trunkgroup, crv->channel, crv->bearer->channel);
11379                      } else {
11380                         c = dahdi_new(pri->pvts[chanpos], AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
11381                      }
11382 
11383                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11384 
11385                      if (!ast_strlen_zero(e->ring.callingsubaddr)) {
11386                         pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
11387                      }
11388                      if (e->ring.ani2 >= 0) {
11389                         snprintf(ani2str, 5, "%.2d", e->ring.ani2);
11390                         pbx_builtin_setvar_helper(c, "ANI2", ani2str);
11391                         pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
11392                      }
11393 
11394 #ifdef SUPPORT_USERUSER
11395                      if (!ast_strlen_zero(e->ring.useruserinfo)) {
11396                         pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
11397                      }
11398 #endif
11399 
11400                      snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
11401                      pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
11402                      if (e->ring.redirectingreason >= 0)
11403                         pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
11404                   
11405                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11406                      ast_mutex_lock(&pri->lock);
11407                      if (c && !ast_pthread_create_detached(&threadid, NULL, ss_thread, c)) {
11408                         ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
11409                               plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
11410                               pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
11411                      } else {
11412                         ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n", 
11413                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
11414                         if (c)
11415                            ast_hangup(c);
11416                         else {
11417                            pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
11418                            pri->pvts[chanpos]->call = NULL;
11419                         }
11420                      }
11421                   } else  {
11422                      ast_mutex_unlock(&pri->lock);
11423                      /* Release PRI lock while we create the channel */
11424                      c = dahdi_new(pri->pvts[chanpos], AST_STATE_RING, 1, SUB_REAL, law, e->ring.ctype);
11425                      if (c) {
11426                         char calledtonstr[10];
11427 
11428                         ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11429 
11430                         if (e->ring.ani2 >= 0) {
11431                            snprintf(ani2str, 5, "%d", e->ring.ani2);
11432                            pbx_builtin_setvar_helper(c, "ANI2", ani2str);
11433                            pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
11434                         }
11435 
11436 #ifdef SUPPORT_USERUSER
11437                         if (!ast_strlen_zero(e->ring.useruserinfo)) {
11438                            pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
11439                         }
11440 #endif
11441 
11442                         if (e->ring.redirectingreason >= 0)
11443                            pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
11444                      
11445                         snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
11446                         pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
11447 
11448                         ast_mutex_lock(&pri->pvts[chanpos]->lock);
11449                         ast_mutex_lock(&pri->lock);
11450 
11451                         ast_verb(3, "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
11452                               plancallingnum, pri->pvts[chanpos]->exten, 
11453                               pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
11454 
11455                         dahdi_enable_ec(pri->pvts[chanpos]);
11456                      } else {
11457 
11458                         ast_mutex_lock(&pri->lock);
11459 
11460                         ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n", 
11461                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
11462                         pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
11463                         pri->pvts[chanpos]->call = NULL;
11464                      }
11465                   }
11466                } else {
11467                   ast_verb(3, "Extension '%s' in context '%s' from '%s' does not exist.  Rejecting call on channel %d/%d, span %d\n",
11468                         pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context, pri->pvts[chanpos]->cid_num, pri->pvts[chanpos]->logicalspan, 
11469                            pri->pvts[chanpos]->prioffset, pri->span);
11470                   pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
11471                   pri->pvts[chanpos]->call = NULL;
11472                   pri->pvts[chanpos]->exten[0] = '\0';
11473                }
11474                if (crv)
11475                   ast_mutex_unlock(&crv->lock);
11476                ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11477             } else {
11478                if (e->ring.flexible)
11479                   pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
11480                else
11481                   pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
11482             }
11483             break;
11484          case PRI_EVENT_RINGING:
11485             chanpos = pri_find_principle(pri, e->ringing.channel);
11486             if (chanpos < 0) {
11487                ast_log(LOG_WARNING, "Ringing requested on unconfigured channel %d/%d span %d\n", 
11488                   PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
11489             } else {
11490                chanpos = pri_fixup_principle(pri, chanpos, e->ringing.call);
11491                if (chanpos < 0) {
11492                   ast_log(LOG_WARNING, "Ringing requested on channel %d/%d not in use on span %d\n", 
11493                      PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
11494                } else {
11495                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11496                   if (ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) {
11497                      dahdi_enable_ec(pri->pvts[chanpos]);
11498                      pri->pvts[chanpos]->subs[SUB_REAL].needringing = 1;
11499                      pri->pvts[chanpos]->alerting = 1;
11500                   } else
11501                      ast_debug(1, "Deferring ringing notification because of extra digits to dial...\n");
11502 
11503 #ifdef PRI_PROGRESS_MASK
11504                   if (e->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE) {
11505 #else
11506                   if (e->ringing.progress == 8) {
11507 #endif
11508                      /* Now we can do call progress detection */
11509                      if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11510                         /* RINGING detection isn't required because we got ALERTING signal */
11511                         ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features & ~DSP_PROGRESS_RINGING);
11512                         pri->pvts[chanpos]->dsp_features = 0;
11513                      }
11514                   }
11515 
11516 #ifdef SUPPORT_USERUSER
11517                   if (!ast_strlen_zero(e->ringing.useruserinfo)) {
11518                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11519                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11520                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->ringing.useruserinfo);
11521                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11522                   }
11523 #endif
11524 
11525                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11526                }
11527             }
11528             break;
11529          case PRI_EVENT_PROGRESS:
11530             /* Get chan value if e->e is not PRI_EVNT_RINGING */
11531             chanpos = pri_find_principle(pri, e->proceeding.channel);
11532             if (chanpos > -1) {
11533 #ifdef PRI_PROGRESS_MASK
11534                if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)) {
11535 #else
11536                if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progress == 8)) {
11537 #endif
11538                   struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, };
11539 
11540                   if (e->proceeding.cause > -1) {
11541                      ast_verb(3, "PROGRESS with cause code %d received\n", e->proceeding.cause);
11542 
11543                      /* Work around broken, out of spec USER_BUSY cause in a progress message */
11544                      if (e->proceeding.cause == AST_CAUSE_USER_BUSY) {
11545                         if (pri->pvts[chanpos]->owner) {
11546                            ast_verb(3, "PROGRESS with 'user busy' received, signalling AST_CONTROL_BUSY instead of AST_CONTROL_PROGRESS\n");
11547 
11548                            pri->pvts[chanpos]->owner->hangupcause = e->proceeding.cause;
11549                            f.subclass = AST_CONTROL_BUSY;
11550                         }
11551                      }
11552                   }
11553                   
11554                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11555                   ast_debug(1, "Queuing frame from PRI_EVENT_PROGRESS on channel %d/%d span %d\n",
11556                      pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
11557                   dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11558 #ifdef PRI_PROGRESS_MASK
11559                   if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
11560 #else
11561                   if (e->proceeding.progress == 8) {
11562 #endif
11563                      /* Now we can do call progress detection */
11564                      if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11565                         ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
11566                         pri->pvts[chanpos]->dsp_features = 0;
11567                      }
11568                      /* Bring voice path up */
11569                      f.subclass = AST_CONTROL_PROGRESS;
11570                      dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11571                   }
11572                   pri->pvts[chanpos]->progress = 1;
11573                   pri->pvts[chanpos]->dialing = 0;
11574                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11575                }
11576             }
11577             break;
11578          case PRI_EVENT_PROCEEDING:
11579             chanpos = pri_find_principle(pri, e->proceeding.channel);
11580             if (chanpos > -1) {
11581                if (!pri->pvts[chanpos]->proceeding) {
11582                   struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
11583                   
11584                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11585                   ast_debug(1, "Queuing frame from PRI_EVENT_PROCEEDING on channel %d/%d span %d\n",
11586                      pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
11587                   dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11588 #ifdef PRI_PROGRESS_MASK
11589                   if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
11590 #else
11591                   if (e->proceeding.progress == 8) {
11592 #endif
11593                      /* Now we can do call progress detection */
11594                      if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11595                         ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
11596                         pri->pvts[chanpos]->dsp_features = 0;
11597                      }
11598                      /* Bring voice path up */
11599                      f.subclass = AST_CONTROL_PROGRESS;
11600                      dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11601                   }
11602                   pri->pvts[chanpos]->proceeding = 1;
11603                   pri->pvts[chanpos]->dialing = 0;
11604                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11605                }
11606             }
11607             break;
11608          case PRI_EVENT_FACNAME:
11609             chanpos = pri_find_principle(pri, e->facname.channel);
11610             if (chanpos < 0) {
11611                ast_log(LOG_WARNING, "Facility Name requested on unconfigured channel %d/%d span %d\n", 
11612                   PRI_SPAN(e->facname.channel), PRI_CHANNEL(e->facname.channel), pri->span);
11613             } else {
11614                chanpos = pri_fixup_principle(pri, chanpos, e->facname.call);
11615                if (chanpos < 0) {
11616                   ast_log(LOG_WARNING, "Facility Name requested on channel %d/%d not in use on span %d\n", 
11617                      PRI_SPAN(e->facname.channel), PRI_CHANNEL(e->facname.channel), pri->span);
11618                } else {
11619                   /* Re-use *69 field for PRI */
11620                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11621                   ast_copy_string(pri->pvts[chanpos]->lastcid_num, e->facname.callingnum, sizeof(pri->pvts[chanpos]->lastcid_num));
11622                   ast_copy_string(pri->pvts[chanpos]->lastcid_name, e->facname.callingname, sizeof(pri->pvts[chanpos]->lastcid_name));
11623                   pri->pvts[chanpos]->subs[SUB_REAL].needcallerid =1;
11624                   dahdi_enable_ec(pri->pvts[chanpos]);
11625                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11626                }
11627             }
11628             break;            
11629          case PRI_EVENT_ANSWER:
11630             chanpos = pri_find_principle(pri, e->answer.channel);
11631             if (chanpos < 0) {
11632                ast_log(LOG_WARNING, "Answer on unconfigured channel %d/%d span %d\n", 
11633                   PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
11634             } else {
11635                chanpos = pri_fixup_principle(pri, chanpos, e->answer.call);
11636                if (chanpos < 0) {
11637                   ast_log(LOG_WARNING, "Answer requested on channel %d/%d not in use on span %d\n", 
11638                      PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
11639                } else {
11640                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11641                   /* Now we can do call progress detection */
11642 
11643                   /* We changed this so it turns on the DSP no matter what... progress or no progress.
11644                    * By this time, we need DTMF detection and other features that were previously disabled
11645                    * -- Matt F */
11646                   if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11647                      ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
11648                      pri->pvts[chanpos]->dsp_features = 0;
11649                   }
11650                   if (pri->pvts[chanpos]->realcall && (pri->pvts[chanpos]->realcall->sig == SIG_FXSKS)) {
11651                      ast_debug(1, "Starting up GR-303 trunk now that we got CONNECT...\n");
11652                      x = DAHDI_START;
11653                      res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
11654                      if (res < 0) {
11655                         if (errno != EINPROGRESS) {
11656                            ast_log(LOG_WARNING, "Unable to start channel: %s\n", strerror(errno));
11657                         }
11658                      }
11659                   } else if (!ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) {
11660                      pri->pvts[chanpos]->dialing = 1;
11661                      /* Send any "w" waited stuff */
11662                      res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_DIAL, &pri->pvts[chanpos]->dop);
11663                      if (res < 0) {
11664                         ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", pri->pvts[chanpos]->channel, strerror(errno));
11665                         pri->pvts[chanpos]->dop.dialstr[0] = '\0';
11666                      } else
11667                         ast_debug(1, "Sent deferred digit string: %s\n", pri->pvts[chanpos]->dop.dialstr);
11668 
11669                      pri->pvts[chanpos]->dop.dialstr[0] = '\0';
11670                   } else if (pri->pvts[chanpos]->confirmanswer) {
11671                      ast_debug(1, "Waiting on answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel);
11672                   } else {
11673                      pri->pvts[chanpos]->subs[SUB_REAL].needanswer =1;
11674                      /* Enable echo cancellation if it's not on already */
11675                      dahdi_enable_ec(pri->pvts[chanpos]);
11676                   }
11677 
11678 #ifdef SUPPORT_USERUSER
11679                   if (!ast_strlen_zero(e->answer.useruserinfo)) {
11680                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11681                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11682                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->answer.useruserinfo);
11683                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11684                   }
11685 #endif
11686 
11687                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11688                }
11689             }
11690             break;            
11691          case PRI_EVENT_HANGUP:
11692             chanpos = pri_find_principle(pri, e->hangup.channel);
11693             if (chanpos < 0) {
11694                ast_log(LOG_WARNING, "Hangup requested on unconfigured channel %d/%d span %d\n", 
11695                   PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11696             } else {
11697                chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
11698                if (chanpos > -1) {
11699                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11700                   if (!pri->pvts[chanpos]->alreadyhungup) {
11701                      /* we're calling here dahdi_hangup so once we get there we need to clear p->call after calling pri_hangup */
11702                      pri->pvts[chanpos]->alreadyhungup = 1;
11703                      if (pri->pvts[chanpos]->realcall) 
11704                         pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11705                      else if (pri->pvts[chanpos]->owner) {
11706                         /* Queue a BUSY instead of a hangup if our cause is appropriate */
11707                         pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
11708                         if (pri->pvts[chanpos]->owner->_state == AST_STATE_UP)
11709                            pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11710                         else {
11711                            switch (e->hangup.cause) {
11712                            case PRI_CAUSE_USER_BUSY:
11713                               pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
11714                               break;
11715                            case PRI_CAUSE_CALL_REJECTED:
11716                            case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
11717                            case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
11718                            case PRI_CAUSE_SWITCH_CONGESTION:
11719                            case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
11720                            case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
11721                               pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
11722                               break;
11723                            default:
11724                               pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11725                            }
11726                         }
11727                      }
11728                      ast_verb(3, "Channel %d/%d, span %d got hangup, cause %d\n",
11729                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, e->hangup.cause);
11730                   } else {
11731                      pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
11732                      pri->pvts[chanpos]->call = NULL;
11733                   }
11734                   if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
11735                      ast_verb(3, "Forcing restart of channel %d/%d on span %d since channel reported in use\n",
11736                            PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11737                      pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
11738                      pri->pvts[chanpos]->resetting = 1;
11739                   }
11740                   if (e->hangup.aoc_units > -1)
11741                      ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
11742                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
11743 
11744 #ifdef SUPPORT_USERUSER
11745                   if (pri->pvts[chanpos]->owner && !ast_strlen_zero(e->hangup.useruserinfo)) {
11746                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11747                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11748                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
11749                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11750                   }
11751 #endif
11752 
11753                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11754                } else {
11755                   ast_log(LOG_WARNING, "Hangup on bad channel %d/%d on span %d\n", 
11756                      PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11757                }
11758             } 
11759             break;
11760 #ifndef PRI_EVENT_HANGUP_REQ
11761 #error please update libpri
11762 #endif
11763          case PRI_EVENT_HANGUP_REQ:
11764             chanpos = pri_find_principle(pri, e->hangup.channel);
11765             if (chanpos < 0) {
11766                ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n", 
11767                   PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11768             } else {
11769                chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
11770                if (chanpos > -1) {
11771                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11772                   if (pri->pvts[chanpos]->realcall) 
11773                      pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11774                   else if (pri->pvts[chanpos]->owner) {
11775                      pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
11776                      if (pri->pvts[chanpos]->owner->_state == AST_STATE_UP)
11777                         pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11778                      else {
11779                         switch (e->hangup.cause) {
11780                            case PRI_CAUSE_USER_BUSY:
11781                               pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
11782                               break;
11783                            case PRI_CAUSE_CALL_REJECTED:
11784                            case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
11785                            case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
11786                            case PRI_CAUSE_SWITCH_CONGESTION:
11787                            case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
11788                            case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
11789                               pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
11790                               break;
11791                            default:
11792                               pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11793                         }
11794                      }
11795                      ast_verb(3, "Channel %d/%d, span %d got hangup request, cause %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span, e->hangup.cause);
11796                      if (e->hangup.aoc_units > -1)
11797                         ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
11798                               pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
11799                   } else {
11800                      pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
11801                      pri->pvts[chanpos]->call = NULL;
11802                   }
11803                   if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
11804                      ast_verb(3, "Forcing restart of channel %d/%d span %d since channel reported in use\n",
11805                            PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11806                      pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
11807                      pri->pvts[chanpos]->resetting = 1;
11808                   }
11809 
11810 #ifdef SUPPORT_USERUSER
11811                   if (!ast_strlen_zero(e->hangup.useruserinfo)) {
11812                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11813                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11814                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
11815                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11816                   }
11817 #endif
11818 
11819                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11820                } else {
11821                   ast_log(LOG_WARNING, "Hangup REQ on bad channel %d/%d on span %d\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11822                }
11823             } 
11824             break;
11825          case PRI_EVENT_HANGUP_ACK:
11826             chanpos = pri_find_principle(pri, e->hangup.channel);
11827             if (chanpos < 0) {
11828                ast_log(LOG_WARNING, "Hangup ACK requested on unconfigured channel number %d/%d span %d\n", 
11829                   PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11830             } else {
11831                chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
11832                if (chanpos > -1) {
11833                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11834                   pri->pvts[chanpos]->call = NULL;
11835                   pri->pvts[chanpos]->resetting = 0;
11836                   if (pri->pvts[chanpos]->owner) {
11837                      ast_verb(3, "Channel %d/%d, span %d got hangup ACK\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11838                   }
11839 
11840 #ifdef SUPPORT_USERUSER
11841                   if (!ast_strlen_zero(e->hangup.useruserinfo)) {
11842                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11843                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11844                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
11845                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11846                   }
11847 #endif
11848 
11849                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11850                }
11851             }
11852             break;
11853          case PRI_EVENT_CONFIG_ERR:
11854             ast_log(LOG_WARNING, "PRI Error on span %d: %s\n", pri->trunkgroup, e->err.err);
11855             break;
11856          case PRI_EVENT_RESTART_ACK:
11857             chanpos = pri_find_principle(pri, e->restartack.channel);
11858             if (chanpos < 0) {
11859                /* Sometime switches (e.g. I421 / British Telecom) don't give us the
11860                   channel number, so we have to figure it out...  This must be why
11861                   everybody resets exactly a channel at a time. */
11862                for (x = 0; x < pri->numchans; x++) {
11863                   if (pri->pvts[x] && pri->pvts[x]->resetting) {
11864                      chanpos = x;
11865                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11866                      ast_debug(1, "Assuming restart ack is really for channel %d/%d span %d\n", pri->pvts[chanpos]->logicalspan, 
11867                         pri->pvts[chanpos]->prioffset, pri->span);
11868                      if (pri->pvts[chanpos]->realcall) 
11869                         pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11870                      else if (pri->pvts[chanpos]->owner) {
11871                         ast_log(LOG_WARNING, "Got restart ack on channel %d/%d with owner on span %d\n", pri->pvts[chanpos]->logicalspan, 
11872                            pri->pvts[chanpos]->prioffset, pri->span);
11873                         pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11874                      }
11875                      pri->pvts[chanpos]->resetting = 0;
11876                      ast_verb(3, "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
11877                            pri->pvts[chanpos]->prioffset, pri->span);
11878                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11879                      if (pri->resetting)
11880                         pri_check_restart(pri);
11881                      break;
11882                   }
11883                }
11884                if (chanpos < 0) {
11885                   ast_log(LOG_WARNING, "Restart ACK requested on strange channel %d/%d span %d\n", 
11886                      PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
11887                }
11888             } else {
11889                if (pri->pvts[chanpos]) {
11890                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11891                   if (pri->pvts[chanpos]->realcall) 
11892                      pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11893                   else if (pri->pvts[chanpos]->owner) {
11894                      ast_log(LOG_WARNING, "Got restart ack on channel %d/%d span %d with owner\n",
11895                         PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
11896                      pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11897                   }
11898                   pri->pvts[chanpos]->resetting = 0;
11899                   pri->pvts[chanpos]->inservice = 1;
11900                   ast_verb(3, "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
11901                            pri->pvts[chanpos]->prioffset, pri->span);
11902                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11903                   if (pri->resetting)
11904                      pri_check_restart(pri);
11905                }
11906             }
11907             break;
11908          case PRI_EVENT_SETUP_ACK:
11909             chanpos = pri_find_principle(pri, e->setup_ack.channel);
11910             if (chanpos < 0) {
11911                ast_log(LOG_WARNING, "Received SETUP_ACKNOWLEDGE on unconfigured channel %d/%d span %d\n", 
11912                   PRI_SPAN(e->setup_ack.channel), PRI_CHANNEL(e->setup_ack.channel), pri->span);
11913             } else {
11914                chanpos = pri_fixup_principle(pri, chanpos, e->setup_ack.call);
11915                if (chanpos > -1) {
11916                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11917                   pri->pvts[chanpos]->setup_ack = 1;
11918                   /* Send any queued digits */
11919                   for (x = 0;x < strlen(pri->pvts[chanpos]->dialdest); x++) {
11920                      ast_debug(1, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]);
11921                      pri_information(pri->pri, pri->pvts[chanpos]->call, 
11922                         pri->pvts[chanpos]->dialdest[x]);
11923                   }
11924                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11925                } else
11926                   ast_log(LOG_WARNING, "Unable to move channel %d!\n", e->setup_ack.channel);
11927             }
11928             break;
11929          case PRI_EVENT_NOTIFY:
11930             chanpos = pri_find_principle(pri, e->notify.channel);
11931             if (chanpos < 0) {
11932                ast_log(LOG_WARNING, "Received NOTIFY on unconfigured channel %d/%d span %d\n",
11933                   PRI_SPAN(e->notify.channel), PRI_CHANNEL(e->notify.channel), pri->span);
11934             } else {
11935                struct ast_frame f = { AST_FRAME_CONTROL, };
11936                ast_mutex_lock(&pri->pvts[chanpos]->lock);
11937                switch (e->notify.info) {
11938                case PRI_NOTIFY_REMOTE_HOLD:
11939                   f.subclass = AST_CONTROL_HOLD;
11940                   dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11941                   break;
11942                case PRI_NOTIFY_REMOTE_RETRIEVAL:
11943                   f.subclass = AST_CONTROL_UNHOLD;
11944                   dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11945                   break;
11946                }
11947                ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11948             }
11949             break;
11950          default:
11951             ast_debug(1, "Event: %d\n", e->e);
11952          }
11953       }  
11954       ast_mutex_unlock(&pri->lock);
11955    }
11956    /* Never reached */
11957    return NULL;
11958 }
11959 
11960 static int start_pri(struct dahdi_pri *pri)
11961 {
11962    int res, x;
11963    struct dahdi_params p;
11964    struct dahdi_bufferinfo bi;
11965    struct dahdi_spaninfo si;
11966    int i;
11967    
11968    for (i = 0; i < NUM_DCHANS; i++) {
11969       if (!pri->dchannels[i])
11970          break;
11971       pri->fds[i] = open("/dev/dahdi/channel", O_RDWR);
11972       x = pri->dchannels[i];
11973       if ((pri->fds[i] < 0) || (ioctl(pri->fds[i],DAHDI_SPECIFY,&x) == -1)) {
11974          ast_log(LOG_ERROR, "Unable to open D-channel %d (%s)\n", x, strerror(errno));
11975          return -1;
11976       }
11977       memset(&p, 0, sizeof(p));
11978       res = ioctl(pri->fds[i], DAHDI_GET_PARAMS, &p);
11979       if (res) {
11980          dahdi_close_pri_fd(pri, i);
11981          ast_log(LOG_ERROR, "Unable to get parameters for D-channel %d (%s)\n", x, strerror(errno));
11982          return -1;
11983       }
11984       if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC)) {
11985          dahdi_close_pri_fd(pri, i);
11986          ast_log(LOG_ERROR, "D-channel %d is not in HDLC/FCS mode.\n", x);
11987          return -1;
11988       }
11989       memset(&si, 0, sizeof(si));
11990       res = ioctl(pri->fds[i], DAHDI_SPANSTAT, &si);
11991       if (res) {
11992          dahdi_close_pri_fd(pri, i);
11993          ast_log(LOG_ERROR, "Unable to get span state for D-channel %d (%s)\n", x, strerror(errno));
11994       }
11995       if (!si.alarms)
11996          pri->dchanavail[i] |= DCHAN_NOTINALARM;
11997       else
11998          pri->dchanavail[i] &= ~DCHAN_NOTINALARM;
11999       memset(&bi, 0, sizeof(bi));
12000       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
12001       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
12002       bi.numbufs = 32;
12003       bi.bufsize = 1024;
12004       if (ioctl(pri->fds[i], DAHDI_SET_BUFINFO, &bi)) {
12005          ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", x, strerror(errno));
12006          dahdi_close_pri_fd(pri, i);
12007          return -1;
12008       }
12009       switch (pri->sig) {
12010          case SIG_BRI:
12011             pri->dchans[i] = pri_new_bri(pri->fds[i], 1, pri->nodetype, pri->switchtype);
12012             break;
12013          case SIG_BRI_PTMP:
12014             pri->dchans[i] = pri_new_bri(pri->fds[i], 0, pri->nodetype, pri->switchtype);
12015             break;
12016          default:
12017             pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype);
12018       }
12019       /* Force overlap dial if we're doing GR-303! */
12020       if (pri->switchtype == PRI_SWITCH_GR303_TMC)
12021          pri->overlapdial |= DAHDI_OVERLAPDIAL_BOTH;
12022       pri_set_overlapdial(pri->dchans[i],(pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)?1:0);
12023 #ifdef HAVE_PRI_INBANDDISCONNECT
12024       pri_set_inbanddisconnect(pri->dchans[i], pri->inbanddisconnect);
12025 #endif
12026       /* Enslave to master if appropriate */
12027       if (i)
12028          pri_enslave(pri->dchans[0], pri->dchans[i]);
12029       if (!pri->dchans[i]) {
12030          dahdi_close_pri_fd(pri, i);
12031          ast_log(LOG_ERROR, "Unable to create PRI structure\n");
12032          return -1;
12033       }
12034       pri_set_debug(pri->dchans[i], DEFAULT_PRI_DEBUG);
12035       pri_set_nsf(pri->dchans[i], pri->nsf);
12036 #ifdef PRI_GETSET_TIMERS
12037       for (x = 0; x < PRI_MAX_TIMERS; x++) {
12038          if (pritimers[x] != 0)
12039             pri_set_timer(pri->dchans[i], x, pritimers[x]);
12040       }
12041 #endif
12042    }
12043    /* Assume primary is the one we use */
12044    pri->pri = pri->dchans[0];
12045    pri->resetpos = -1;
12046    if (ast_pthread_create_background(&pri->master, NULL, pri_dchannel, pri)) {
12047       for (i = 0; i < NUM_DCHANS; i++) {
12048          if (!pri->dchannels[i])
12049             break;
12050          dahdi_close_pri_fd(pri, i);
12051       }
12052       ast_log(LOG_ERROR, "Unable to spawn D-channel: %s\n", strerror(errno));
12053       return -1;
12054    }
12055    return 0;
12056 }
12057 
12058 static char *complete_span_helper(const char *line, const char *word, int pos, int state, int rpos)
12059 {
12060    int which, span;
12061    char *ret = NULL;
12062 
12063    if (pos != rpos)
12064       return ret;
12065 
12066    for (which = span = 0; span < NUM_SPANS; span++) {
12067       if (pris[span].pri && ++which > state) {
12068          if (asprintf(&ret, "%d", span + 1) < 0) { /* user indexes start from 1 */
12069             ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
12070          }
12071          break;
12072       }
12073    }
12074    return ret;
12075 }
12076 
12077 static char *complete_span_4(const char *line, const char *word, int pos, int state)
12078 {
12079    return complete_span_helper(line,word,pos,state,3);
12080 }
12081 
12082 static char *complete_span_5(const char *line, const char *word, int pos, int state)
12083 {
12084    return complete_span_helper(line,word,pos,state,4);
12085 }
12086 
12087 static char *handle_pri_unset_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12088 {
12089    switch (cmd) {
12090    case CLI_INIT:
12091       e->command = "pri unset debug file";
12092       e->usage = "Usage: pri unset debug file\n"
12093             "       Stop sending debug output to the previously \n"
12094                  "       specified file\n";
12095       return NULL;
12096    case CLI_GENERATE:
12097       return NULL;   
12098    }
12099    /* Assume it is unset */
12100    ast_mutex_lock(&pridebugfdlock);
12101    close(pridebugfd);
12102    pridebugfd = -1;
12103    ast_cli(a->fd, "PRI debug output to file disabled\n");
12104    ast_mutex_unlock(&pridebugfdlock);
12105    return CLI_SUCCESS;
12106 }
12107 
12108 static char *handle_pri_set_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12109 {
12110    int myfd;
12111    switch (cmd) {
12112    case CLI_INIT:
12113       e->command = "pri set debug file";
12114       e->usage = "Usage: pri set debug file [output-file]\n"
12115             "       Sends PRI debug output to the specified output file\n";
12116       return NULL;
12117    case CLI_GENERATE:
12118       return NULL;   
12119    }
12120    if (a->argc < 5)
12121       return CLI_SHOWUSAGE;
12122 
12123    if (ast_strlen_zero(a->argv[4]))
12124       return CLI_SHOWUSAGE;
12125 
12126    myfd = open(a->argv[4], O_CREAT|O_WRONLY, AST_FILE_MODE);
12127    if (myfd < 0) {
12128       ast_cli(a->fd, "Unable to open '%s' for writing\n", a->argv[4]);
12129       return CLI_SUCCESS;
12130    }
12131 
12132    ast_mutex_lock(&pridebugfdlock);
12133 
12134    if (pridebugfd >= 0)
12135       close(pridebugfd);
12136 
12137    pridebugfd = myfd;
12138    ast_copy_string(pridebugfilename,a->argv[4],sizeof(pridebugfilename));
12139    ast_mutex_unlock(&pridebugfdlock);
12140    ast_cli(a->fd, "PRI debug output will be sent to '%s'\n", a->argv[4]);
12141    return CLI_SUCCESS;
12142 }
12143 
12144 static char *handle_pri_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12145 {
12146    int span;
12147    int x;
12148    switch (cmd) {
12149    case CLI_INIT: 
12150       e->command = "pri debug span";
12151       e->usage = 
12152          "Usage: pri debug span <span>\n"
12153          "       Enables debugging on a given PRI span\n";
12154       return NULL;
12155    case CLI_GENERATE:   
12156       return complete_span_4(a->line, a->word, a->pos, a->n);
12157    }
12158    if (a->argc < 4) {
12159       return CLI_SHOWUSAGE;
12160    }
12161    span = atoi(a->argv[3]);
12162    if ((span < 1) || (span > NUM_SPANS)) {
12163       ast_cli(a->fd, "Invalid span %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
12164       return CLI_SUCCESS;
12165    }
12166    if (!pris[span-1].pri) {
12167       ast_cli(a->fd, "No PRI running on span %d\n", span);
12168       return CLI_SUCCESS;
12169    }
12170    for (x = 0; x < NUM_DCHANS; x++) {
12171       if (pris[span-1].dchans[x])
12172          pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU |
12173                                                PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE |
12174                                                PRI_DEBUG_Q921_STATE);
12175    }
12176    ast_cli(a->fd, "Enabled debugging on span %d\n", span);
12177    return CLI_SUCCESS;
12178 }
12179 
12180 
12181 
12182 static char *handle_pri_no_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12183 {
12184    int span;
12185    int x;
12186    switch (cmd) {
12187    case CLI_INIT:
12188       e->command = "pri no debug span";
12189       e->usage = 
12190          "Usage: pri no debug span <span>\n"
12191          "       Disables debugging on a given PRI span\n";
12192       return NULL;
12193    case CLI_GENERATE:
12194       return complete_span_5(a->line, a->word, a->pos, a->n);
12195    }
12196    if (a->argc < 5)
12197       return CLI_SHOWUSAGE;
12198 
12199    span = atoi(a->argv[4]);
12200    if ((span < 1) || (span > NUM_SPANS)) {
12201       ast_cli(a->fd, "Invalid span %s.  Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
12202       return CLI_SUCCESS;
12203    }
12204    if (!pris[span-1].pri) {
12205       ast_cli(a->fd, "No PRI running on span %d\n", span);
12206       return CLI_SUCCESS;
12207    }
12208    for (x = 0; x < NUM_DCHANS; x++) {
12209       if (pris[span-1].dchans[x])
12210          pri_set_debug(pris[span-1].dchans[x], 0);
12211    }
12212    ast_cli(a->fd, "Disabled debugging on span %d\n", span);
12213    return CLI_SUCCESS;
12214 }
12215 
12216 static char *handle_pri_really_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12217 {
12218    int span;
12219    int x;
12220    switch (cmd) {
12221    case CLI_INIT:
12222       e->command = "pri intensive debug span";
12223       e->usage = 
12224          "Usage: pri intensive debug span <span>\n"
12225          "       Enables debugging down to the Q.921 level\n";
12226       return NULL;
12227    case CLI_GENERATE:
12228       return complete_span_5(a->line, a->word, a->pos, a->n);
12229    }
12230 
12231    if (a->argc < 5)
12232       return CLI_SHOWUSAGE;
12233    span = atoi(a->argv[4]);
12234    if ((span < 1) || (span > NUM_SPANS)) {
12235       ast_cli(a->fd, "Invalid span %s.  Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
12236       return CLI_SUCCESS;
12237    }
12238    if (!pris[span-1].pri) {
12239       ast_cli(a->fd, "No PRI running on span %d\n", span);
12240       return CLI_SUCCESS;
12241    }
12242    for (x = 0; x < NUM_DCHANS; x++) {
12243       if (pris[span-1].dchans[x])
12244          pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU |
12245                                                PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE |
12246                                                PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_STATE);
12247    }
12248    ast_cli(a->fd, "Enabled EXTENSIVE debugging on span %d\n", span);
12249    return CLI_SUCCESS;
12250 }
12251 
12252 static void build_status(char *s, size_t len, int status, int active)
12253 {
12254    if (!s || len < 1) {
12255       return;
12256    }
12257    s[0] = '\0';
12258    if (status & DCHAN_PROVISIONED)
12259       strncat(s, "Provisioned, ", len - strlen(s) - 1);
12260    if (!(status & DCHAN_NOTINALARM))
12261       strncat(s, "In Alarm, ", len - strlen(s) - 1);
12262    if (status & DCHAN_UP)
12263       strncat(s, "Up", len - strlen(s) - 1);
12264    else
12265       strncat(s, "Down", len - strlen(s) - 1);
12266    if (active)
12267       strncat(s, ", Active", len - strlen(s) - 1);
12268    else
12269       strncat(s, ", Standby", len - strlen(s) - 1);
12270    s[len - 1] = '\0';
12271 }
12272 
12273 static char *handle_pri_show_spans(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12274 {
12275    int span;
12276    int x;
12277    char status[256];
12278 
12279    switch (cmd) {
12280    case CLI_INIT:
12281       e->command = "pri show spans";
12282       e->usage = 
12283          "Usage: pri show spans\n"
12284          "       Displays PRI Information\n";
12285       return NULL;
12286    case CLI_GENERATE:
12287       return NULL;   
12288    }
12289 
12290    if (a->argc != 3)
12291       return CLI_SHOWUSAGE;
12292 
12293    for (span = 0; span < NUM_SPANS; span++) {
12294       if (pris[span].pri) {
12295          for (x = 0; x < NUM_DCHANS; x++) {
12296             if (pris[span].dchannels[x]) {
12297                build_status(status, sizeof(status), pris[span].dchanavail[x], pris[span].dchans[x] == pris[span].pri);
12298                ast_cli(a->fd, "PRI span %d/%d: %s\n", span + 1, x, status);
12299             }
12300          }
12301       }
12302    }
12303    return CLI_SUCCESS;
12304 }
12305 
12306 static char *handle_pri_show_span(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12307 {
12308    int span;
12309    int x;
12310    char status[256];
12311    switch (cmd) {
12312    case CLI_INIT: 
12313       e->command = "pri show span";
12314       e->usage = 
12315          "Usage: pri show span <span>\n"
12316          "       Displays PRI Information on a given PRI span\n";
12317       return NULL;
12318    case CLI_GENERATE:
12319       return complete_span_4(a->line, a->word, a->pos, a->n);
12320    }
12321 
12322    if (a->argc < 4)
12323       return CLI_SHOWUSAGE;
12324    span = atoi(a->argv[3]);
12325    if ((span < 1) || (span > NUM_SPANS)) {
12326       ast_cli(a->fd, "Invalid span '%s'.  Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS);
12327       return CLI_SUCCESS;
12328    }
12329    if (!pris[span-1].pri) {
12330       ast_cli(a->fd, "No PRI running on span %d\n", span);
12331       return CLI_SUCCESS;
12332    }
12333    for (x = 0; x < NUM_DCHANS; x++) {
12334       if (pris[span-1].dchannels[x]) {
12335 #ifdef PRI_DUMP_INFO_STR
12336          char *info_str = NULL;
12337 #endif
12338          ast_cli(a->fd, "%s D-channel: %d\n", pri_order(x), pris[span-1].dchannels[x]);
12339          build_status(status, sizeof(status), pris[span-1].dchanavail[x], pris[span-1].dchans[x] == pris[span-1].pri);
12340          ast_cli(a->fd, "Status: %s\n", status);
12341 #ifdef PRI_DUMP_INFO_STR
12342          info_str = pri_dump_info_str(pris[span-1].pri);
12343          if (info_str) {
12344             ast_cli(a->fd, "%s", info_str);
12345             ast_free(info_str);
12346          }
12347 #else
12348          pri_dump_info(pris[span-1].pri);
12349 #endif
12350          ast_cli(a->fd, "Overlap Recv: %s\n\n", (pris[span-1].overlapdial & DAHDI_OVERLAPDIAL_INCOMING)?"Yes":"No");
12351       }
12352    }
12353    return CLI_SUCCESS;
12354 }
12355 
12356 static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12357 {
12358    int x;
12359    int span;
12360    int count=0;
12361    int debug=0;
12362 
12363    switch (cmd) {
12364    case CLI_INIT: 
12365       e->command = "pri show debug";
12366       e->usage = 
12367          "Usage: pri show debug\n"
12368          "  Show the debug state of pri spans\n";
12369       return NULL;
12370    case CLI_GENERATE:
12371       return NULL;   
12372    }
12373 
12374    for (span = 0; span < NUM_SPANS; span++) {
12375            if (pris[span].pri) {
12376          for (x = 0; x < NUM_DCHANS; x++) {
12377             debug = 0;
12378                if (pris[span].dchans[x]) {
12379                   debug = pri_get_debug(pris[span].dchans[x]);
12380                ast_cli(a->fd, "Span %d: Debug: %s\tIntense: %s\n", span+1, (debug&PRI_DEBUG_Q931_STATE)? "Yes" : "No" ,(debug&PRI_DEBUG_Q921_RAW)? "Yes" : "No" );
12381                count++;
12382             }
12383          }
12384       }
12385 
12386    }
12387    ast_mutex_lock(&pridebugfdlock);
12388    if (pridebugfd >= 0) 
12389       ast_cli(a->fd, "Logging PRI debug to file %s\n", pridebugfilename);
12390    ast_mutex_unlock(&pridebugfdlock);
12391        
12392    if (!count) 
12393       ast_cli(a->fd, "No debug set or no PRI running\n");
12394    return CLI_SUCCESS;
12395 }
12396 
12397 static char *handle_pri_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12398 {
12399    switch (cmd) {
12400    case CLI_INIT:
12401       e->command = "pri show version";
12402       e->usage = 
12403          "Usage: pri show version\n"
12404          "Show libpri version information\n";
12405       return NULL;
12406    case CLI_GENERATE:
12407       return NULL;
12408    }
12409 
12410    ast_cli(a->fd, "libpri version: %s\n", pri_get_version());
12411 
12412    return CLI_SUCCESS;
12413 }
12414 
12415 static struct ast_cli_entry dahdi_pri_cli[] = {
12416    AST_CLI_DEFINE(handle_pri_debug, "Enables PRI debugging on a span"),
12417    AST_CLI_DEFINE(handle_pri_no_debug, "Disables PRI debugging on a span"),
12418    AST_CLI_DEFINE(handle_pri_really_debug, "Enables REALLY INTENSE PRI debugging"),
12419    AST_CLI_DEFINE(handle_pri_show_spans, "Displays PRI Information"),
12420    AST_CLI_DEFINE(handle_pri_show_span, "Displays PRI Information"),
12421    AST_CLI_DEFINE(handle_pri_show_debug, "Displays current PRI debug settings"),
12422    AST_CLI_DEFINE(handle_pri_set_debug_file, "Sends PRI debug output to the specified file"),
12423    AST_CLI_DEFINE(handle_pri_unset_debug_file, "Ends PRI debug output to file"),
12424    AST_CLI_DEFINE(handle_pri_version, "Displays libpri version"),
12425 };
12426 
12427 #endif /* HAVE_PRI */
12428 
12429 static char *dahdi_destroy_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12430 {
12431    int channel;
12432    int ret;
12433    switch (cmd) {
12434    case CLI_INIT:
12435       e->command = "dahdi destroy channel";
12436       e->usage = 
12437          "Usage: dahdi destroy channel <chan num>\n"
12438          "  DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.  Immediately removes a given channel, whether it is in use or not\n";
12439       return NULL;
12440    case CLI_GENERATE:
12441       return NULL;   
12442    }
12443    if (a->argc != 4)
12444       return CLI_SHOWUSAGE;
12445    
12446    channel = atoi(a->argv[3]);
12447    ret = dahdi_destroy_channel_bynum(channel);
12448    return ( RESULT_SUCCESS == ret ) ? CLI_SUCCESS : CLI_FAILURE;
12449 }
12450 
12451 static void dahdi_softhangup_all(void)
12452 {
12453    struct dahdi_pvt *p;
12454 retry:
12455    ast_mutex_lock(&iflock);
12456     for (p = iflist; p; p = p->next) {
12457       ast_mutex_lock(&p->lock);
12458         if (p->owner && !p->restartpending) {
12459          if (ast_channel_trylock(p->owner)) {
12460             if (option_debug > 2)
12461                ast_verbose("Avoiding deadlock\n");
12462             /* Avoid deadlock since you're not supposed to lock iflock or pvt before a channel */
12463             ast_mutex_unlock(&p->lock);
12464             ast_mutex_unlock(&iflock);
12465             goto retry;
12466          }
12467          if (option_debug > 2)
12468             ast_verbose("Softhanging up on %s\n", p->owner->name);
12469          ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_EXPLICIT);
12470          p->restartpending = 1;
12471          num_restart_pending++;
12472          ast_channel_unlock(p->owner);
12473       }
12474       ast_mutex_unlock(&p->lock);
12475     }
12476    ast_mutex_unlock(&iflock);
12477 }
12478 
12479 static int setup_dahdi(int reload);
12480 static int dahdi_restart(void)
12481 {
12482 #if defined(HAVE_PRI) || defined(HAVE_SS7)
12483    int i, j;
12484 #endif
12485    int cancel_code;
12486    struct dahdi_pvt *p;
12487 
12488    ast_mutex_lock(&restart_lock);
12489 
12490    ast_verb(1, "Destroying channels and reloading DAHDI configuration.\n");
12491    dahdi_softhangup_all();
12492    ast_verb(4, "Initial softhangup of all DAHDI channels complete.\n");
12493 
12494 #if defined(HAVE_PRI)
12495    for (i = 0; i < NUM_SPANS; i++) {
12496       if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL)) {
12497          cancel_code = pthread_cancel(pris[i].master);
12498          pthread_kill(pris[i].master, SIGURG);
12499          ast_debug(4, "Waiting to join thread of span %d with pid=%p, cancel_code=%d\n", i, (void *) pris[i].master, cancel_code);
12500          pthread_join(pris[i].master, NULL);
12501          ast_debug(4, "Joined thread of span %d\n", i);
12502       }
12503    }
12504 #endif
12505 
12506 #if defined(HAVE_SS7)
12507    for (i = 0; i < NUM_SPANS; i++) {
12508       if (linksets[i].master && (linksets[i].master != AST_PTHREADT_NULL)) {
12509          cancel_code = pthread_cancel(linksets[i].master);
12510          pthread_kill(linksets[i].master, SIGURG);
12511          ast_debug(4, "Waiting to join thread of span %d with pid=%p, cancel_code=%d\n", i, (void *) linksets[i].master, cancel_code);
12512          pthread_join(linksets[i].master, NULL);
12513          ast_debug(4, "Joined thread of span %d\n", i);
12514       }
12515     }
12516 #endif
12517 
12518    ast_mutex_lock(&monlock);
12519    if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
12520       cancel_code = pthread_cancel(monitor_thread);
12521       pthread_kill(monitor_thread, SIGURG);
12522       ast_debug(4, "Waiting to join monitor thread with pid=%p, cancel_code=%d\n", (void *) monitor_thread, cancel_code);
12523       pthread_join(monitor_thread, NULL);
12524       ast_debug(4, "Joined monitor thread\n");
12525    }
12526    monitor_thread = AST_PTHREADT_NULL; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
12527 
12528    ast_mutex_lock(&mwi_thread_lock);
12529    while (mwi_thread_count > 0) {
12530       ast_debug(3, "Waiting on %d mwi_send_thread(s) to finish\n", mwi_thread_count);
12531       ast_cond_wait(&mwi_thread_complete, &mwi_thread_lock);
12532    }
12533    ast_mutex_unlock(&mwi_thread_lock);
12534    ast_mutex_lock(&ss_thread_lock);
12535    while (ss_thread_count > 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
12536       int x = DAHDI_FLASH;
12537       ast_debug(3, "Waiting on %d ss_thread(s) to finish\n", ss_thread_count);
12538 
12539       for (p = iflist; p; p = p->next) {
12540          if (p->owner)
12541             ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x); /* important to create an event for dahdi_wait_event to register so that all ss_threads terminate */      
12542          }
12543          ast_cond_wait(&ss_thread_complete, &ss_thread_lock);
12544       }
12545 
12546    /* ensure any created channels before monitor threads were stopped are hungup */
12547    dahdi_softhangup_all();
12548    ast_verb(4, "Final softhangup of all DAHDI channels complete.\n");
12549    destroy_all_channels();
12550    ast_debug(1, "Channels destroyed. Now re-reading config. %d active channels remaining.\n", ast_active_channels());
12551 
12552    ast_mutex_unlock(&monlock);
12553 
12554 #ifdef HAVE_PRI
12555    for (i = 0; i < NUM_SPANS; i++) {
12556       for (j = 0; j < NUM_DCHANS; j++)
12557          dahdi_close_pri_fd(&(pris[i]), j);
12558    }
12559 
12560    memset(pris, 0, sizeof(pris));
12561    for (i = 0; i < NUM_SPANS; i++) {
12562       ast_mutex_init(&pris[i].lock);
12563       pris[i].offset = -1;
12564       pris[i].master = AST_PTHREADT_NULL;
12565       for (j = 0; j < NUM_DCHANS; j++)
12566          pris[i].fds[j] = -1;
12567       }
12568    pri_set_error(dahdi_pri_error);
12569    pri_set_message(dahdi_pri_message);
12570 #endif
12571 #ifdef HAVE_SS7
12572    for (i = 0; i < NUM_SPANS; i++) {
12573       for (j = 0; j < NUM_DCHANS; j++)
12574          dahdi_close_ss7_fd(&(linksets[i]), j);
12575    }
12576 
12577    memset(linksets, 0, sizeof(linksets));
12578    for (i = 0; i < NUM_SPANS; i++) {
12579       ast_mutex_init(&linksets[i].lock);
12580       linksets[i].master = AST_PTHREADT_NULL;
12581       for (j = 0; j < NUM_DCHANS; j++)
12582          linksets[i].fds[j] = -1;
12583    }
12584    ss7_set_error(dahdi_ss7_error);
12585    ss7_set_message(dahdi_ss7_message);
12586 #endif
12587 
12588    if (setup_dahdi(2) != 0) {
12589       ast_log(LOG_WARNING, "Reload channels from dahdi config failed!\n");
12590       ast_mutex_unlock(&ss_thread_lock);
12591       return 1;
12592    }
12593    ast_mutex_unlock(&ss_thread_lock);
12594    ast_mutex_unlock(&restart_lock);
12595    return 0;
12596 }
12597 
12598 static char *dahdi_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12599 {
12600    switch (cmd) {
12601    case CLI_INIT:
12602       e->command = "dahdi restart";
12603       e->usage = 
12604          "Usage: dahdi restart\n"
12605          "  Restarts the DAHDI channels: destroys them all and then\n"
12606          "  re-reads them from chan_dahdi.conf.\n"
12607          "  Note that this will STOP any running CALL on DAHDI channels.\n"
12608          "";
12609       return NULL;
12610    case CLI_GENERATE:
12611       return NULL;
12612    }
12613    if (a->argc != 2)
12614       return CLI_SHOWUSAGE;
12615 
12616    if (dahdi_restart() != 0)
12617       return CLI_FAILURE;
12618    return CLI_SUCCESS;
12619 }
12620 
12621 static int action_dahdirestart(struct mansession *s, const struct message *m)
12622 {
12623    if (dahdi_restart() != 0) {
12624       astman_send_error(s, m, "Failed rereading DAHDI configuration");
12625       return 1;
12626    }
12627    astman_send_ack(s, m, "DAHDIRestart: Success");
12628    return 0;
12629 }
12630 
12631 static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12632 {
12633 #define FORMAT "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
12634 #define FORMAT2 "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
12635    unsigned int targetnum = 0;
12636    int filtertype = 0;
12637    struct dahdi_pvt *tmp = NULL;
12638    char tmps[20] = "";
12639    char statestr[20] = "";
12640    char blockstr[20] = "";
12641    ast_mutex_t *lock;
12642    struct dahdi_pvt *start;
12643 #ifdef HAVE_PRI
12644    int trunkgroup;
12645    struct dahdi_pri *pri = NULL;
12646    int x;
12647 #endif
12648    switch (cmd) {
12649    case CLI_INIT:
12650       e->command = "dahdi show channels [trunkgroup|group|context]";
12651       e->usage = 
12652          "Usage: dahdi show channels [ trunkgroup <trunkgroup> | group <group> | context <context> ]\n"
12653          "  Shows a list of available channels with optional filtering\n"
12654          "  <group> must be a number between 0 and 63\n";
12655       return NULL;
12656    case CLI_GENERATE:
12657       return NULL;   
12658    }
12659 
12660    lock = &iflock;
12661    start = iflist;
12662 
12663    /* syntax: dahdi show channels [ group <group> | context <context> | trunkgroup <trunkgroup> ] */
12664 
12665    if (!((a->argc == 3) || (a->argc == 5)))
12666       return CLI_SHOWUSAGE;
12667 
12668    if (a->argc == 5) {
12669 #ifdef HAVE_PRI
12670       if (!strcasecmp(a->argv[3], "trunkgroup")) {
12671          /* this option requires no special handling, so leave filtertype to zero */
12672          if ((trunkgroup = atoi(a->argv[4])) < 1)
12673             return CLI_SHOWUSAGE;
12674          for (x = 0; x < NUM_SPANS; x++) {
12675             if (pris[x].trunkgroup == trunkgroup) {
12676                pri = pris + x;
12677                break;
12678             }
12679          }
12680          if (pri) {
12681             start = pri->crvs;
12682             lock = &pri->lock;
12683          } else {
12684             ast_cli(a->fd, "No such trunk group %d\n", trunkgroup);
12685             return CLI_FAILURE;
12686          }
12687       } else
12688 #endif   
12689       if (!strcasecmp(a->argv[3], "group")) {
12690          targetnum = atoi(a->argv[4]);
12691          if ((targetnum < 0) || (targetnum > 63))
12692             return CLI_SHOWUSAGE;
12693          targetnum = 1 << targetnum;
12694          filtertype = 1;
12695       } else if (!strcasecmp(a->argv[3], "context")) {
12696          filtertype = 2;
12697       }
12698    }
12699 
12700    ast_mutex_lock(lock);
12701 #ifdef HAVE_PRI
12702    ast_cli(a->fd, FORMAT2, pri ? "CRV" : "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State");
12703 #else
12704    ast_cli(a->fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State");
12705 #endif   
12706    
12707    tmp = start;
12708    while (tmp) {
12709       if (filtertype) {
12710          switch(filtertype) {
12711          case 1: /* dahdi show channels group <group> */
12712             if (tmp->group != targetnum) {
12713                tmp = tmp->next;
12714                continue;
12715             }
12716             break;
12717          case 2: /* dahdi show channels context <context> */
12718             if (strcasecmp(tmp->context, a->argv[4])) {
12719                tmp = tmp->next;
12720                continue;
12721             }
12722             break;
12723          default:
12724             ;
12725          }
12726       }
12727       if (tmp->channel > 0) {
12728          snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
12729       } else
12730          ast_copy_string(tmps, "pseudo", sizeof(tmps));
12731 
12732       if (tmp->locallyblocked)
12733          blockstr[0] = 'L';
12734       else
12735          blockstr[0] = ' ';
12736 
12737       if (tmp->remotelyblocked)
12738          blockstr[1] = 'R';
12739       else
12740          blockstr[1] = ' ';
12741 
12742       blockstr[2] = '\0';
12743 
12744       snprintf(statestr, sizeof(statestr), "%s", "In Service");
12745 
12746       ast_cli(a->fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, statestr);
12747       tmp = tmp->next;
12748    }
12749    ast_mutex_unlock(lock);
12750    return CLI_SUCCESS;
12751 #undef FORMAT
12752 #undef FORMAT2
12753 }
12754 
12755 static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12756 {
12757    int channel;
12758    struct dahdi_pvt *tmp = NULL;
12759    struct dahdi_confinfo ci;
12760    struct dahdi_params ps;
12761    int x;
12762    ast_mutex_t *lock;
12763    struct dahdi_pvt *start;
12764 #ifdef HAVE_PRI
12765    char *c;
12766    int trunkgroup;
12767    struct dahdi_pri *pri=NULL;
12768 #endif
12769    switch (cmd) {
12770    case CLI_INIT:
12771       e->command = "dahdi show channel";
12772       e->usage = 
12773          "Usage: dahdi show channel <chan num>\n"
12774          "  Detailed information about a given channel\n";
12775       return NULL;
12776    case CLI_GENERATE:
12777       return NULL;   
12778    }
12779 
12780    lock = &iflock;
12781    start = iflist;
12782 
12783    if (a->argc != 4)
12784       return CLI_SHOWUSAGE;
12785 #ifdef HAVE_PRI
12786    if ((c = strchr(a->argv[3], ':'))) {
12787       if (sscanf(a->argv[3], "%d:%d", &trunkgroup, &channel) != 2)
12788          return CLI_SHOWUSAGE;
12789       if ((trunkgroup < 1) || (channel < 1))
12790          return CLI_SHOWUSAGE;
12791       for (x = 0; x < NUM_SPANS; x++) {
12792          if (pris[x].trunkgroup == trunkgroup) {
12793             pri = pris + x;
12794             break;
12795          }
12796       }
12797       if (pri) {
12798          start = pri->crvs;
12799          lock = &pri->lock;
12800       } else {
12801          ast_cli(a->fd, "No such trunk group %d\n", trunkgroup);
12802          return CLI_FAILURE;
12803       }
12804    } else
12805 #endif
12806       channel = atoi(a->argv[3]);
12807 
12808    ast_mutex_lock(lock);
12809    tmp = start;
12810    while (tmp) {
12811       if (tmp->channel == channel) {
12812 #ifdef HAVE_PRI
12813          if (pri) 
12814             ast_cli(a->fd, "Trunk/CRV: %d/%d\n", trunkgroup, tmp->channel);
12815          else
12816 #endif         
12817          ast_cli(a->fd, "Channel: %d\n", tmp->channel);
12818          ast_cli(a->fd, "File Descriptor: %d\n", tmp->subs[SUB_REAL].dfd);
12819          ast_cli(a->fd, "Span: %d\n", tmp->span);
12820          ast_cli(a->fd, "Extension: %s\n", tmp->exten);
12821          ast_cli(a->fd, "Dialing: %s\n", tmp->dialing ? "yes" : "no");
12822          ast_cli(a->fd, "Context: %s\n", tmp->context);
12823          ast_cli(a->fd, "Caller ID: %s\n", tmp->cid_num);
12824          ast_cli(a->fd, "Calling TON: %d\n", tmp->cid_ton);
12825          ast_cli(a->fd, "Caller ID name: %s\n", tmp->cid_name);
12826          ast_cli(a->fd, "Mailbox: %s\n", S_OR(tmp->mailbox, "none"));
12827          if (tmp->vars) {
12828             struct ast_variable *v;
12829             ast_cli(a->fd, "Variables:\n");
12830             for (v = tmp->vars ; v ; v = v->next)
12831                ast_cli(a->fd, "       %s = %s\n", v->name, v->value);
12832          }
12833          ast_cli(a->fd, "Destroy: %d\n", tmp->destroy);
12834          ast_cli(a->fd, "InAlarm: %d\n", tmp->inalarm);
12835          ast_cli(a->fd, "Signalling Type: %s\n", sig2str(tmp->sig));
12836          ast_cli(a->fd, "Radio: %d\n", tmp->radio);
12837          ast_cli(a->fd, "Owner: %s\n", tmp->owner ? tmp->owner->name : "<None>");
12838          ast_cli(a->fd, "Real: %s%s%s\n", tmp->subs[SUB_REAL].owner ? tmp->subs[SUB_REAL].owner->name : "<None>", tmp->subs[SUB_REAL].inthreeway ? " (Confed)" : "", tmp->subs[SUB_REAL].linear ? " (Linear)" : "");
12839          ast_cli(a->fd, "Callwait: %s%s%s\n", tmp->subs[SUB_CALLWAIT].owner ? tmp->subs[SUB_CALLWAIT].owner->name : "<None>", tmp->subs[SUB_CALLWAIT].inthreeway ? " (Confed)" : "", tmp->subs[SUB_CALLWAIT].linear ? " (Linear)" : "");
12840          ast_cli(a->fd, "Threeway: %s%s%s\n", tmp->subs[SUB_THREEWAY].owner ? tmp->subs[SUB_THREEWAY].owner->name : "<None>", tmp->subs[SUB_THREEWAY].inthreeway ? " (Confed)" : "", tmp->subs[SUB_THREEWAY].linear ? " (Linear)" : "");
12841          ast_cli(a->fd, "Confno: %d\n", tmp->confno);
12842          ast_cli(a->fd, "Propagated Conference: %d\n", tmp->propconfno);
12843          ast_cli(a->fd, "Real in conference: %d\n", tmp->inconference);
12844          ast_cli(a->fd, "DSP: %s\n", tmp->dsp ? "yes" : "no");
12845          ast_cli(a->fd, "Busy Detection: %s\n", tmp->busydetect ? "yes" : "no");
12846          if (tmp->busydetect) {
12847 #if defined(BUSYDETECT_TONEONLY)
12848             ast_cli(a->fd, "    Busy Detector Helper: BUSYDETECT_TONEONLY\n");
12849 #elif defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
12850             ast_cli(a->fd, "    Busy Detector Helper: BUSYDETECT_COMPARE_TONE_AND_SILENCE\n");
12851 #endif
12852 #ifdef BUSYDETECT_DEBUG
12853             ast_cli(a->fd, "    Busy Detector Debug: Enabled\n");
12854 #endif
12855             ast_cli(a->fd, "    Busy Count: %d\n", tmp->busycount);
12856             ast_cli(a->fd, "    Busy Pattern: %d,%d\n", tmp->busytonelength, tmp->busyquietlength);
12857          }
12858          ast_cli(a->fd, "TDD: %s\n", tmp->tdd ? "yes" : "no");
12859          ast_cli(a->fd, "Relax DTMF: %s\n", tmp->dtmfrelax ? "yes" : "no");
12860          ast_cli(a->fd, "Dialing/CallwaitCAS: %d/%d\n", tmp->dialing, tmp->callwaitcas);
12861          ast_cli(a->fd, "Default law: %s\n", tmp->law == DAHDI_LAW_MULAW ? "ulaw" : tmp->law == DAHDI_LAW_ALAW ? "alaw" : "unknown");
12862          ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
12863          ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
12864          ast_cli(a->fd, "DND: %s\n", tmp->dnd ? "yes" : "no");
12865          ast_cli(a->fd, "Echo Cancellation:\n");
12866 
12867          if (tmp->echocancel.head.tap_length) {
12868             ast_cli(a->fd, "\t%d taps\n", tmp->echocancel.head.tap_length);
12869             for (x = 0; x < tmp->echocancel.head.param_count; x++) {
12870                ast_cli(a->fd, "\t\t%s: %ud\n", tmp->echocancel.params[x].name, tmp->echocancel.params[x].value);
12871             }
12872             ast_cli(a->fd, "\t%scurrently %s\n", tmp->echocanbridged ? "" : "(unless TDM bridged) ", tmp->echocanon ? "ON" : "OFF");
12873          } else {
12874             ast_cli(a->fd, "\tnone\n");
12875          }
12876          if (tmp->master)
12877             ast_cli(a->fd, "Master Channel: %d\n", tmp->master->channel);
12878          for (x = 0; x < MAX_SLAVES; x++) {
12879             if (tmp->slaves[x])
12880                ast_cli(a->fd, "Slave Channel: %d\n", tmp->slaves[x]->channel);
12881          }
12882 #ifdef HAVE_SS7
12883          if (tmp->ss7) {
12884             ast_cli(a->fd, "CIC: %d\n", tmp->cic);
12885          }
12886 #endif
12887 #ifdef HAVE_PRI
12888          if (tmp->pri) {
12889             ast_cli(a->fd, "PRI Flags: ");
12890             if (tmp->resetting)
12891                ast_cli(a->fd, "Resetting ");
12892             if (tmp->call)
12893                ast_cli(a->fd, "Call ");
12894             if (tmp->bearer)
12895                ast_cli(a->fd, "Bearer ");
12896             ast_cli(a->fd, "\n");
12897             if (tmp->logicalspan) 
12898                ast_cli(a->fd, "PRI Logical Span: %d\n", tmp->logicalspan);
12899             else
12900                ast_cli(a->fd, "PRI Logical Span: Implicit\n");
12901          }
12902             
12903 #endif
12904          memset(&ci, 0, sizeof(ci));
12905          ps.channo = tmp->channel;
12906          if (tmp->subs[SUB_REAL].dfd > -1) {
12907             memset(&ci, 0, sizeof(ci));
12908             if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
12909                ast_cli(a->fd, "Actual Confinfo: Num/%d, Mode/0x%04x\n", ci.confno, ci.confmode);
12910             }
12911             if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONFMUTE, &x)) {
12912                ast_cli(a->fd, "Actual Confmute: %s\n", x ? "Yes" : "No");
12913             }
12914             memset(&ps, 0, sizeof(ps));
12915             if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
12916                ast_log(LOG_WARNING, "Failed to get parameters on channel %d: %s\n", tmp->channel, strerror(errno));
12917             } else {
12918                ast_cli(a->fd, "Hookstate (FXS only): %s\n", ps.rxisoffhook ? "Offhook" : "Onhook");
12919             }
12920          }
12921          if (ISTRUNK(tmp)) {
12922             ast_cli(a->fd, "Call Progress: %s\n", tmp->callprogress ? "yes" : "no");  
12923             if (!ast_strlen_zero(progzone))
12924                ast_cli(a->fd, "Progress Zone: %s\n", progzone);
12925             ast_cli(a->fd, "Busy Detect: %s\n", tmp->busydetect ? "yes" : "no");  
12926             if(tmp->busydetect) {
12927                ast_cli(a->fd, "Busy Count: %d\n", tmp->busycount);
12928                if(tmp->busytonelength > 0) {
12929                   ast_cli(a->fd, "Busy Pattern:\n");
12930                   ast_cli(a->fd, " -- Tone Length: %6d ms\n", tmp->busytonelength);
12931                   if (tmp->busyquietlength > 0) 
12932                      ast_cli(a->fd, " -- Quiet Length: %6d ms\n", tmp->busyquietlength);
12933                   else 
12934                      ast_cli(a->fd, " -- Detect Tone Only\n");
12935                   if(tmp->busyfuzziness > 0)
12936                      ast_cli(a->fd, "Busy Pattern Fuziness: %d\n", tmp->busyfuzziness);
12937                }
12938             }
12939          }
12940          ast_mutex_unlock(lock);
12941          return CLI_SUCCESS;
12942       }
12943       tmp = tmp->next;
12944    }
12945    
12946    ast_cli(a->fd, "Unable to find given channel %d\n", channel);
12947    ast_mutex_unlock(lock);
12948    return CLI_FAILURE;
12949 }
12950 
12951 static char *handle_dahdi_show_cadences(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12952 {
12953    int i, j;
12954    switch (cmd) {
12955    case CLI_INIT:
12956       e->command = "dahdi show cadences";
12957       e->usage = 
12958          "Usage: dahdi show cadences\n"
12959          "       Shows all cadences currently defined\n";
12960       return NULL;
12961    case CLI_GENERATE:
12962       return NULL;   
12963    }
12964    for (i = 0; i < num_cadence; i++) {
12965       char output[1024];
12966       char tmp[16], tmp2[64];
12967       snprintf(tmp, sizeof(tmp), "r%d: ", i + 1);
12968       term_color(output, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(output));
12969 
12970       for (j = 0; j < 16; j++) {
12971          if (cadences[i].ringcadence[j] == 0)
12972             break;
12973          snprintf(tmp, sizeof(tmp), "%d", cadences[i].ringcadence[j]);
12974          if (cidrings[i] * 2 - 1 == j)
12975             term_color(tmp2, tmp, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp2) - 1);
12976          else
12977             term_color(tmp2, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(tmp2) - 1);
12978          if (j != 0)
12979             strncat(output, ",", sizeof(output) - strlen(output) - 1);
12980          strncat(output, tmp2, sizeof(output) - strlen(output) - 1);
12981       }
12982       ast_cli(a->fd,"%s\n",output);
12983    }
12984    return CLI_SUCCESS;
12985 }
12986 
12987 /* Based on irqmiss.c */
12988 static char *dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) 
12989 {
12990    #define FORMAT "%-40.40s %-7.7s %-6d %-6d %-6d %-3.3s %-4.4s %-8.8s %s\n"
12991    #define FORMAT2 "%-40.40s %-7.7s %-6.6s %-6.6s %-6.6s %-3.3s %-4.4s %-8.8s %s\n"
12992    int span;
12993    int res;
12994    char alarmstr[50];
12995 
12996    int ctl;
12997    struct dahdi_spaninfo s;
12998 
12999    switch (cmd) {
13000    case CLI_INIT:
13001       e->command = "dahdi show status";
13002       e->usage = 
13003          "Usage: dahdi show status\n"
13004          "       Shows a list of DAHDI cards with status\n";
13005       return NULL;
13006    case CLI_GENERATE:
13007       return NULL;   
13008    }
13009    ctl = open("/dev/dahdi/ctl", O_RDWR);
13010    if (ctl < 0) {
13011       ast_cli(a->fd, "No DAHDI found. Unable to open /dev/dahdi/ctl: %s\n", strerror(errno));
13012       return CLI_FAILURE;
13013    }
13014    ast_cli(a->fd, FORMAT2, "Description", "Alarms", "IRQ", "bpviol", "CRC4", "Framing", "Coding", "Options", "LBO");
13015 
13016    for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
13017       s.spanno = span;
13018       res = ioctl(ctl, DAHDI_SPANSTAT, &s);
13019       if (res) {
13020          continue;
13021       }
13022       alarmstr[0] = '\0';
13023       if (s.alarms > 0) {
13024          if (s.alarms & DAHDI_ALARM_BLUE)
13025             strcat(alarmstr, "BLU/");
13026          if (s.alarms & DAHDI_ALARM_YELLOW)
13027             strcat(alarmstr, "YEL/");
13028          if (s.alarms & DAHDI_ALARM_RED)
13029             strcat(alarmstr, "RED/");
13030          if (s.alarms & DAHDI_ALARM_LOOPBACK)
13031             strcat(alarmstr, "LB/");
13032          if (s.alarms & DAHDI_ALARM_RECOVER)
13033             strcat(alarmstr, "REC/");
13034          if (s.alarms & DAHDI_ALARM_NOTOPEN)
13035             strcat(alarmstr, "NOP/");
13036          if (!strlen(alarmstr))
13037             strcat(alarmstr, "UUU/");
13038          if (strlen(alarmstr)) {
13039             /* Strip trailing / */
13040             alarmstr[strlen(alarmstr) - 1] = '\0';
13041          }
13042       } else {
13043          if (s.numchans)
13044             strcpy(alarmstr, "OK");
13045          else
13046             strcpy(alarmstr, "UNCONFIGURED");
13047       }
13048 
13049       ast_cli(a->fd, FORMAT, s.desc, alarmstr, s.irqmisses, s.bpvcount, s.crc4count
13050             , s.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
13051               s.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
13052               s.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
13053               "CAS"
13054             , s.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
13055               s.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
13056               s.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
13057               "Unk"
13058             , s.lineconfig & DAHDI_CONFIG_CRC4 ?
13059               s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" : "YEL"
13060             , lbostr[s.lbo]
13061          );
13062    }
13063    close(ctl);
13064 
13065    return CLI_SUCCESS;
13066 #undef FORMAT
13067 #undef FORMAT2
13068 }
13069 
13070 static char *dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13071 {
13072    int pseudo_fd = -1;
13073    struct dahdi_versioninfo vi;
13074 
13075    switch (cmd) {
13076    case CLI_INIT:
13077       e->command = "dahdi show version";
13078       e->usage = 
13079          "Usage: dahdi show version\n"
13080          "       Shows the DAHDI version in use\n";
13081       return NULL;
13082    case CLI_GENERATE:
13083       return NULL;
13084    }
13085    if ((pseudo_fd = open("/dev/dahdi/ctl", O_RDONLY)) < 0) {
13086       ast_cli(a->fd, "Failed to open control file to get version.\n");
13087       return CLI_SUCCESS;
13088    }
13089 
13090    strcpy(vi.version, "Unknown");
13091    strcpy(vi.echo_canceller, "Unknown");
13092 
13093    if (ioctl(pseudo_fd, DAHDI_GETVERSION, &vi))
13094       ast_cli(a->fd, "Failed to get DAHDI version: %s\n", strerror(errno));
13095    else
13096       ast_cli(a->fd, "DAHDI Version: %s Echo Canceller: %s\n", vi.version, vi.echo_canceller);
13097 
13098    close(pseudo_fd);
13099 
13100    return CLI_SUCCESS;
13101 }
13102 
13103 static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13104 {
13105    int channel;
13106    int gain;
13107    int tx;
13108    struct dahdi_hwgain hwgain;
13109    struct dahdi_pvt *tmp = NULL;
13110 
13111    switch (cmd) {
13112    case CLI_INIT:
13113       e->command = "dahdi set hwgain";
13114       e->usage = 
13115          "Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
13116          "  Sets the hardware gain on a a given channel, overriding the\n"
13117          "   value provided at module loadtime, whether the channel is in\n"
13118          "   use or not.  Changes take effect immediately.\n"
13119          "   <rx|tx> which direction do you want to change (relative to our module)\n"
13120          "   <chan num> is the channel number relative to the device\n"
13121          "   <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
13122       return NULL;
13123    case CLI_GENERATE:
13124       return NULL;   
13125    }
13126 
13127    if (a->argc != 6)
13128       return CLI_SHOWUSAGE;
13129    
13130    if (!strcasecmp("rx", a->argv[3]))
13131       tx = 0; /* rx */
13132    else if (!strcasecmp("tx", a->argv[3]))
13133       tx = 1; /* tx */
13134    else
13135       return CLI_SHOWUSAGE;
13136 
13137    channel = atoi(a->argv[4]);
13138    gain = atof(a->argv[5])*10.0;
13139 
13140    ast_mutex_lock(&iflock);
13141 
13142    for (tmp = iflist; tmp; tmp = tmp->next) {
13143 
13144       if (tmp->channel != channel)
13145          continue;
13146 
13147       if (tmp->subs[SUB_REAL].dfd == -1)
13148          break;
13149 
13150       hwgain.newgain = gain;
13151       hwgain.tx = tx;
13152       if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_HWGAIN, &hwgain) < 0) {
13153          ast_cli(a->fd, "Unable to set the hardware gain for channel %d: %s\n", channel, strerror(errno));
13154          ast_mutex_unlock(&iflock);
13155          return CLI_FAILURE;
13156       }
13157       ast_cli(a->fd, "hardware %s gain set to %d (%.1f dB) on channel %d\n",
13158          tx ? "tx" : "rx", gain, (float)gain/10.0, channel);
13159       break;
13160    }
13161 
13162    ast_mutex_unlock(&iflock);
13163 
13164    if (tmp)
13165       return CLI_SUCCESS;
13166 
13167    ast_cli(a->fd, "Unable to find given channel %d\n", channel);
13168    return CLI_FAILURE;
13169 
13170 }
13171 
13172 static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13173 {
13174    int channel;
13175    float gain;
13176    int tx;
13177    int res;
13178    ast_mutex_t *lock;
13179    struct dahdi_pvt *tmp = NULL;
13180 
13181    switch (cmd) {
13182    case CLI_INIT:
13183       e->command = "dahdi set swgain";
13184       e->usage = 
13185          "Usage: dahdi set swgain <rx|tx> <chan#> <gain>\n"
13186          "  Sets the software gain on a a given channel, overriding the\n"
13187          "   value provided at module loadtime, whether the channel is in\n"
13188          "   use or not.  Changes take effect immediately.\n"
13189          "   <rx|tx> which direction do you want to change (relative to our module)\n"
13190          "   <chan num> is the channel number relative to the device\n"
13191          "   <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
13192       return NULL;
13193    case CLI_GENERATE:
13194       return NULL;   
13195    }
13196 
13197    lock = &iflock;
13198 
13199    if (a->argc != 6)
13200       return CLI_SHOWUSAGE;
13201    
13202    if (!strcasecmp("rx", a->argv[3]))
13203       tx = 0; /* rx */
13204    else if (!strcasecmp("tx", a->argv[3]))
13205       tx = 1; /* tx */
13206    else
13207       return CLI_SHOWUSAGE;
13208 
13209    channel = atoi(a->argv[4]);
13210    gain = atof(a->argv[5]);
13211 
13212    ast_mutex_lock(lock);
13213    for (tmp = iflist; tmp; tmp = tmp->next) {
13214 
13215       if (tmp->channel != channel)
13216          continue;
13217 
13218       if (tmp->subs[SUB_REAL].dfd == -1)
13219          break;
13220 
13221       if (tx)
13222          res = set_actual_txgain(tmp->subs[SUB_REAL].dfd, channel, gain, tmp->law);
13223       else
13224          res = set_actual_rxgain(tmp->subs[SUB_REAL].dfd, channel, gain, tmp->law);
13225 
13226       if (res) {
13227          ast_cli(a->fd, "Unable to set the software gain for channel %d\n", channel);
13228          ast_mutex_unlock(lock);
13229          return CLI_FAILURE;
13230       }
13231 
13232       ast_cli(a->fd, "software %s gain set to %.1f on channel %d\n",
13233          tx ? "tx" : "rx", gain, channel);
13234       break;
13235    }
13236    ast_mutex_unlock(lock);
13237 
13238    if (tmp)
13239       return CLI_SUCCESS;
13240 
13241    ast_cli(a->fd, "Unable to find given channel %d\n", channel);
13242    return CLI_FAILURE;
13243 
13244 }
13245 
13246 static char *dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13247 {
13248    int channel;
13249    int on;
13250    struct dahdi_pvt *dahdi_chan = NULL;
13251 
13252    switch (cmd) {
13253    case CLI_INIT:
13254       e->command = "dahdi set dnd";
13255       e->usage = 
13256          "Usage: dahdi set dnd <chan#> <on|off>\n"
13257          "  Sets/resets DND (Do Not Disturb) mode on a channel.\n"
13258          "  Changes take effect immediately.\n"
13259          "  <chan num> is the channel number\n"
13260          "  <on|off> Enable or disable DND mode?\n"
13261          ;
13262       return NULL;
13263    case CLI_GENERATE:
13264       return NULL;   
13265    }
13266 
13267    if (a->argc != 5)
13268       return CLI_SHOWUSAGE;
13269 
13270    if ((channel = atoi(a->argv[3])) <= 0) {
13271       ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
13272       return CLI_SHOWUSAGE;
13273    }
13274    
13275    if (ast_true(a->argv[4]))
13276       on = 1;
13277    else if (ast_false(a->argv[4]))
13278       on = 0;
13279    else {
13280       ast_cli(a->fd, "Expected 'on' or 'off', got '%s'\n", a->argv[4]);
13281       return CLI_SHOWUSAGE;
13282    }
13283 
13284    ast_mutex_lock(&iflock);
13285    for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
13286       if (dahdi_chan->channel != channel)
13287          continue;
13288 
13289       /* Found the channel. Actually set it */
13290       dahdi_dnd(dahdi_chan, on);
13291       break;
13292    }
13293    ast_mutex_unlock(&iflock);
13294 
13295    if (!dahdi_chan) {
13296       ast_cli(a->fd, "Unable to find given channel %d\n", channel);
13297       return CLI_FAILURE;
13298    }
13299 
13300    return CLI_SUCCESS;
13301 }
13302 
13303 static struct ast_cli_entry dahdi_cli[] = {
13304    AST_CLI_DEFINE(handle_dahdi_show_cadences, "List cadences"),
13305    AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
13306    AST_CLI_DEFINE(dahdi_show_channel, "Show information on a channel"),
13307    AST_CLI_DEFINE(dahdi_destroy_channel, "Destroy a channel"),
13308    AST_CLI_DEFINE(dahdi_restart_cmd, "Fully restart DAHDI channels"),
13309    AST_CLI_DEFINE(dahdi_show_status, "Show all DAHDI cards status"),
13310    AST_CLI_DEFINE(dahdi_show_version, "Show the DAHDI version in use"),
13311    AST_CLI_DEFINE(dahdi_set_hwgain, "Set hardware gain on a channel"),
13312    AST_CLI_DEFINE(dahdi_set_swgain, "Set software gain on a channel"),
13313    AST_CLI_DEFINE(dahdi_set_dnd, "Sets/resets DND (Do Not Disturb) mode on a channel"),
13314 };
13315 
13316 #define TRANSFER  0
13317 #define HANGUP    1
13318 
13319 static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
13320 {
13321    if (p) {
13322       switch (mode) {
13323          case TRANSFER:
13324             p->fake_event = DAHDI_EVENT_WINKFLASH;
13325             break;
13326          case HANGUP:
13327             p->fake_event = DAHDI_EVENT_ONHOOK;
13328             break;
13329          default:
13330             ast_log(LOG_WARNING, "I don't know how to handle transfer event with this: %d on channel %s\n",mode, p->owner->name);   
13331       }
13332    }
13333    return 0;
13334 }
13335 static struct dahdi_pvt *find_channel(int channel)
13336 {
13337    struct dahdi_pvt *p = iflist;
13338    while (p) {
13339       if (p->channel == channel) {
13340          break;
13341       }
13342       p = p->next;
13343    }
13344    return p;
13345 }
13346 
13347 static int action_dahdidndon(struct mansession *s, const struct message *m)
13348 {
13349    struct dahdi_pvt *p = NULL;
13350    const char *channel = astman_get_header(m, "DAHDIChannel");
13351 
13352    if (ast_strlen_zero(channel)) {
13353       astman_send_error(s, m, "No channel specified");
13354       return 0;
13355    }
13356    p = find_channel(atoi(channel));
13357    if (!p) {
13358       astman_send_error(s, m, "No such channel");
13359       return 0;
13360    }
13361    p->dnd = 1;
13362    astman_send_ack(s, m, "DND Enabled");
13363    return 0;
13364 }
13365 
13366 static int action_dahdidndoff(struct mansession *s, const struct message *m)
13367 {
13368    struct dahdi_pvt *p = NULL;
13369    const char *channel = astman_get_header(m, "DAHDIChannel");
13370 
13371    if (ast_strlen_zero(channel)) {
13372       astman_send_error(s, m, "No channel specified");
13373       return 0;
13374    }
13375    p = find_channel(atoi(channel));
13376    if (!p) {
13377       astman_send_error(s, m, "No such channel");
13378       return 0;
13379    }
13380    p->dnd = 0;
13381    astman_send_ack(s, m, "DND Disabled");
13382    return 0;
13383 }
13384 
13385 static int action_transfer(struct mansession *s, const struct message *m)
13386 {
13387    struct dahdi_pvt *p = NULL;
13388    const char *channel = astman_get_header(m, "DAHDIChannel");
13389 
13390    if (ast_strlen_zero(channel)) {
13391       astman_send_error(s, m, "No channel specified");
13392       return 0;
13393    }
13394    p = find_channel(atoi(channel));
13395    if (!p) {
13396       astman_send_error(s, m, "No such channel");
13397       return 0;
13398    }
13399    dahdi_fake_event(p,TRANSFER);
13400    astman_send_ack(s, m, "DAHDITransfer");
13401    return 0;
13402 }
13403 
13404 static int action_transferhangup(struct mansession *s, const struct message *m)
13405 {
13406    struct dahdi_pvt *p = NULL;
13407    const char *channel = astman_get_header(m, "DAHDIChannel");
13408 
13409    if (ast_strlen_zero(channel)) {
13410       astman_send_error(s, m, "No channel specified");
13411       return 0;
13412    }
13413    p = find_channel(atoi(channel));
13414    if (!p) {
13415       astman_send_error(s, m, "No such channel");
13416       return 0;
13417    }
13418    dahdi_fake_event(p,HANGUP);
13419    astman_send_ack(s, m, "DAHDIHangup");
13420    return 0;
13421 }
13422 
13423 static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
13424 {
13425    struct dahdi_pvt *p = NULL;
13426    const char *channel = astman_get_header(m, "DAHDIChannel");
13427    const char *number = astman_get_header(m, "Number");
13428    int i;
13429 
13430    if (ast_strlen_zero(channel)) {
13431       astman_send_error(s, m, "No channel specified");
13432       return 0;
13433    }
13434    if (ast_strlen_zero(number)) {
13435       astman_send_error(s, m, "No number specified");
13436       return 0;
13437    }
13438    p = find_channel(atoi(channel));
13439    if (!p) {
13440       astman_send_error(s, m, "No such channel");
13441       return 0;
13442    }
13443    if (!p->owner) {
13444       astman_send_error(s, m, "Channel does not have it's owner");
13445       return 0;
13446    }
13447    for (i = 0; i < strlen(number); i++) {
13448       struct ast_frame f = { AST_FRAME_DTMF, number[i] };
13449       dahdi_queue_frame(p, &f, NULL); 
13450    }
13451    astman_send_ack(s, m, "DAHDIDialOffhook");
13452    return 0;
13453 }
13454 
13455 static int action_dahdishowchannels(struct mansession *s, const struct message *m)
13456 {
13457    struct dahdi_pvt *tmp = NULL;
13458    const char *id = astman_get_header(m, "ActionID");
13459    const char *dahdichannel = astman_get_header(m, "DAHDIChannel");
13460    char idText[256] = "";
13461    int channels = 0;
13462    int dahdichanquery = -1;
13463    if (!ast_strlen_zero(dahdichannel)) {
13464       dahdichanquery = atoi(dahdichannel);
13465    }
13466 
13467    astman_send_ack(s, m, "DAHDI channel status will follow");
13468    if (!ast_strlen_zero(id))
13469       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
13470 
13471    ast_mutex_lock(&iflock);
13472    
13473    tmp = iflist;
13474    while (tmp) {
13475       if (tmp->channel > 0) {
13476          int alm = get_alarms(tmp);
13477 
13478          /* If a specific channel is queried for, only deliver status for that channel */
13479          if (dahdichanquery > 0 && tmp->channel != dahdichanquery)
13480             continue;
13481 
13482          channels++;
13483          if (tmp->owner) {
13484             /* Add data if we have a current call */
13485             astman_append(s,
13486                "Event: DAHDIShowChannels\r\n"
13487                "DAHDIChannel: %d\r\n"
13488                "Channel: %s\r\n"
13489                "Uniqueid: %s\r\n"
13490                "AccountCode: %s\r\n"
13491                "Signalling: %s\r\n"
13492                "SignallingCode: %d\r\n"
13493                "Context: %s\r\n"
13494                "DND: %s\r\n"
13495                "Alarm: %s\r\n"
13496                "%s"
13497                "\r\n",
13498                tmp->channel, 
13499                tmp->owner->name,
13500                tmp->owner->uniqueid,
13501                tmp->owner->accountcode,
13502                sig2str(tmp->sig), 
13503                tmp->sig,
13504                tmp->context, 
13505                tmp->dnd ? "Enabled" : "Disabled",
13506                alarm2str(alm), idText);
13507          } else {
13508             astman_append(s,
13509                "Event: DAHDIShowChannels\r\n"
13510                "DAHDIChannel: %d\r\n"
13511                "Signalling: %s\r\n"
13512                "SignallingCode: %d\r\n"
13513                "Context: %s\r\n"
13514                "DND: %s\r\n"
13515                "Alarm: %s\r\n"
13516                "%s"
13517                "\r\n",
13518                tmp->channel, sig2str(tmp->sig), tmp->sig, 
13519                tmp->context, 
13520                tmp->dnd ? "Enabled" : "Disabled",
13521                alarm2str(alm), idText);
13522          }
13523       } 
13524 
13525       tmp = tmp->next;
13526    }
13527 
13528    ast_mutex_unlock(&iflock);
13529    
13530    astman_append(s, 
13531       "Event: DAHDIShowChannelsComplete\r\n"
13532       "%s"
13533       "Items: %d\r\n"
13534       "\r\n", 
13535       idText,
13536       channels);
13537    return 0;
13538 }
13539 
13540 #ifdef HAVE_SS7
13541 static int linkset_addsigchan(int sigchan)
13542 {
13543    struct dahdi_ss7 *link;
13544    int res;
13545    int curfd;
13546    struct dahdi_params p;
13547    struct dahdi_bufferinfo bi;
13548    struct dahdi_spaninfo si;
13549 
13550 
13551    link = ss7_resolve_linkset(cur_linkset);
13552    if (!link) {
13553       ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
13554       return -1;
13555    }
13556 
13557    if (cur_ss7type < 0) {
13558       ast_log(LOG_ERROR, "Unspecified or invalid ss7type\n");
13559       return -1;
13560    }
13561 
13562    if (!link->ss7)
13563       link->ss7 = ss7_new(cur_ss7type);
13564 
13565    if (!link->ss7) {
13566       ast_log(LOG_ERROR, "Can't create new SS7!\n");
13567       return -1;
13568    }
13569 
13570    link->type = cur_ss7type;
13571 
13572    if (cur_pointcode < 0) {
13573       ast_log(LOG_ERROR, "Unspecified pointcode!\n");
13574       return -1;
13575    } else
13576       ss7_set_pc(link->ss7, cur_pointcode);
13577 
13578    if (sigchan < 0) {
13579       ast_log(LOG_ERROR, "Invalid sigchan!\n");
13580       return -1;
13581    } else {
13582       if (link->numsigchans >= NUM_DCHANS) {
13583          ast_log(LOG_ERROR, "Too many sigchans on linkset %d\n", cur_linkset);
13584          return -1;
13585       }
13586       curfd = link->numsigchans;
13587 
13588       link->fds[curfd] = open("/dev/dahdi/channel", O_RDWR, 0600);
13589       if ((link->fds[curfd] < 0) || (ioctl(link->fds[curfd],DAHDI_SPECIFY,&sigchan) == -1)) {
13590          ast_log(LOG_ERROR, "Unable to open SS7 sigchan %d (%s)\n", sigchan, strerror(errno));
13591          return -1;
13592       }
13593       memset(&p, 0, sizeof(p));
13594       res = ioctl(link->fds[curfd], DAHDI_GET_PARAMS, &p);
13595       if (res) {
13596          dahdi_close_ss7_fd(link, curfd);
13597          ast_log(LOG_ERROR, "Unable to get parameters for sigchan %d (%s)\n", sigchan, strerror(errno));
13598          return -1;
13599       }
13600       if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC) && (p.sigtype != DAHDI_SIG_MTP2)) {
13601          dahdi_close_ss7_fd(link, curfd);
13602          ast_log(LOG_ERROR, "sigchan %d is not in HDLC/FCS mode.\n", sigchan);
13603          return -1;
13604       }
13605 
13606       memset(&bi, 0, sizeof(bi));
13607       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
13608       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
13609       bi.numbufs = 32;
13610       bi.bufsize = 512;
13611 
13612       if (ioctl(link->fds[curfd], DAHDI_SET_BUFINFO, &bi)) {
13613          ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", sigchan, strerror(errno));
13614          dahdi_close_ss7_fd(link, curfd);
13615          return -1;
13616       }
13617 
13618       if (p.sigtype == DAHDI_SIG_MTP2)
13619          ss7_add_link(link->ss7, SS7_TRANSPORT_DAHDIMTP2, link->fds[curfd]);
13620       else
13621          ss7_add_link(link->ss7, SS7_TRANSPORT_DAHDIDCHAN, link->fds[curfd]);
13622 
13623       link->numsigchans++;
13624 
13625       memset(&si, 0, sizeof(si));
13626       res = ioctl(link->fds[curfd], DAHDI_SPANSTAT, &si);
13627       if (res) {
13628          dahdi_close_ss7_fd(link, curfd);
13629          ast_log(LOG_ERROR, "Unable to get span state for sigchan %d (%s)\n", sigchan, strerror(errno));
13630       }
13631 
13632       if (!si.alarms) {
13633          link->linkstate[curfd] = LINKSTATE_DOWN;
13634          ss7_link_noalarm(link->ss7, link->fds[curfd]);
13635       } else {
13636          link->linkstate[curfd] = LINKSTATE_DOWN | LINKSTATE_INALARM;
13637          ss7_link_alarm(link->ss7, link->fds[curfd]);
13638       }
13639    }
13640 
13641    if (cur_adjpointcode < 0) {
13642       ast_log(LOG_ERROR, "Unspecified adjpointcode!\n");
13643       return -1;
13644    } else {
13645       ss7_set_adjpc(link->ss7, link->fds[curfd], cur_adjpointcode);
13646    }
13647 
13648    if (cur_defaultdpc < 0) {
13649       ast_log(LOG_ERROR, "Unspecified defaultdpc!\n");
13650       return -1;
13651    }
13652 
13653    if (cur_networkindicator < 0) {
13654       ast_log(LOG_ERROR, "Invalid networkindicator!\n");
13655       return -1;
13656    } else
13657       ss7_set_network_ind(link->ss7, cur_networkindicator);
13658 
13659    return 0;
13660 }
13661 
13662 static char *handle_ss7_no_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13663 {
13664    int span;
13665    switch (cmd) {
13666    case CLI_INIT:
13667       e->command = "ss7 no debug linkset";
13668       e->usage = 
13669          "Usage: ss7 no debug linkset <span>\n"
13670          "       Disables debugging on a given SS7 linkset\n";
13671       return NULL;
13672    case CLI_GENERATE:
13673       return NULL;
13674    }
13675    if (a->argc < 5)
13676       return CLI_SHOWUSAGE;
13677    span = atoi(a->argv[4]);
13678    if ((span < 1) || (span > NUM_SPANS)) {
13679       ast_cli(a->fd, "Invalid linkset %s.  Should be a number from %d to %d\n", a->argv[4], 1, NUM_SPANS);
13680       return CLI_SUCCESS;
13681    }
13682    if (!linksets[span-1].ss7) {
13683       ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
13684       return CLI_SUCCESS;
13685    }
13686    if (linksets[span-1].ss7)
13687       ss7_set_debug(linksets[span-1].ss7, 0);
13688 
13689    ast_cli(a->fd, "Disabled debugging on linkset %d\n", span);
13690    return CLI_SUCCESS;
13691 }
13692 
13693 static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13694 {
13695    int span;
13696    switch (cmd) {
13697    case CLI_INIT:
13698       e->command = "ss7 debug linkset";
13699       e->usage = 
13700          "Usage: ss7 debug linkset <linkset>\n"
13701          "       Enables debugging on a given SS7 linkset\n";
13702       return NULL;
13703    case CLI_GENERATE:
13704       return NULL;
13705    }
13706    if (a->argc < 4)
13707       return CLI_SHOWUSAGE;
13708    span = atoi(a->argv[3]);
13709    if ((span < 1) || (span > NUM_SPANS)) {
13710       ast_cli(a->fd, "Invalid linkset %s.  Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS);
13711       return CLI_SUCCESS;
13712    }
13713    if (!linksets[span-1].ss7) {
13714       ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
13715       return CLI_SUCCESS;
13716    }
13717    if (linksets[span-1].ss7)
13718       ss7_set_debug(linksets[span-1].ss7, SS7_DEBUG_MTP2 | SS7_DEBUG_MTP3 | SS7_DEBUG_ISUP);
13719 
13720    ast_cli(a->fd, "Enabled debugging on linkset %d\n", span);
13721    return CLI_SUCCESS;
13722 }
13723 
13724 static char *handle_ss7_block_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13725 {
13726    int linkset, cic;
13727    int blocked = -1, i;
13728    switch (cmd) {
13729    case CLI_INIT:
13730       e->command = "ss7 block cic";
13731       e->usage = 
13732          "Usage: ss7 block cic <linkset> <CIC>\n"
13733          "       Sends a remote blocking request for the given CIC on the specified linkset\n";
13734       return NULL;
13735    case CLI_GENERATE:
13736       return NULL;
13737    }
13738    if (a->argc == 5)
13739       linkset = atoi(a->argv[3]);
13740    else
13741       return CLI_SHOWUSAGE;
13742 
13743    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13744       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13745       return CLI_SUCCESS;
13746    }
13747 
13748    if (!linksets[linkset-1].ss7) {
13749       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13750       return CLI_SUCCESS;
13751    }
13752 
13753    cic = atoi(a->argv[4]);
13754 
13755    if (cic < 1) {
13756       ast_cli(a->fd, "Invalid CIC specified!\n");
13757       return CLI_SUCCESS;
13758    }
13759 
13760    for (i = 0; i < linksets[linkset-1].numchans; i++) {
13761       if (linksets[linkset-1].pvts[i]->cic == cic) {
13762          blocked = linksets[linkset-1].pvts[i]->locallyblocked;
13763          if (!blocked) {
13764             ast_mutex_lock(&linksets[linkset-1].lock);
13765             isup_blo(linksets[linkset-1].ss7, cic, linksets[linkset-1].pvts[i]->dpc);
13766             ast_mutex_unlock(&linksets[linkset-1].lock);
13767          }
13768       }
13769    }
13770 
13771    if (blocked < 0) {
13772       ast_cli(a->fd, "Invalid CIC specified!\n");
13773       return CLI_SUCCESS;
13774    }
13775 
13776    if (!blocked)
13777       ast_cli(a->fd, "Sent blocking request for linkset %d on CIC %d\n", linkset, cic);
13778    else
13779       ast_cli(a->fd, "CIC %d already locally blocked\n", cic);
13780 
13781    /* Break poll on the linkset so it sends our messages */
13782    pthread_kill(linksets[linkset-1].master, SIGURG);
13783 
13784    return CLI_SUCCESS;
13785 }
13786 
13787 static char *handle_ss7_block_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13788 {
13789    int linkset;
13790    int i;
13791    switch (cmd) {
13792    case CLI_INIT:
13793       e->command = "ss7 block linkset";
13794       e->usage = 
13795          "Usage: ss7 block linkset <linkset number>\n"
13796          "       Sends a remote blocking request for all CICs on the given linkset\n";
13797       return NULL;
13798    case CLI_GENERATE:
13799       return NULL;
13800    }
13801    if (a->argc == 4)
13802       linkset = atoi(a->argv[3]);
13803    else
13804       return CLI_SHOWUSAGE;
13805 
13806    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13807       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13808       return CLI_SUCCESS;
13809    }
13810 
13811    if (!linksets[linkset-1].ss7) {
13812       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13813       return CLI_SUCCESS;
13814    }
13815 
13816    for (i = 0; i < linksets[linkset-1].numchans; i++) {
13817       ast_cli(a->fd, "Sending remote blocking request on CIC %d\n", linksets[linkset-1].pvts[i]->cic);
13818       ast_mutex_lock(&linksets[linkset-1].lock);
13819       isup_blo(linksets[linkset-1].ss7, linksets[linkset-1].pvts[i]->cic, linksets[linkset-1].pvts[i]->dpc);
13820       ast_mutex_unlock(&linksets[linkset-1].lock);
13821    }
13822 
13823    /* Break poll on the linkset so it sends our messages */
13824    pthread_kill(linksets[linkset-1].master, SIGURG);
13825 
13826    return CLI_SUCCESS;
13827 }
13828 
13829 static char *handle_ss7_unblock_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13830 {
13831    int linkset, cic;
13832    int i, blocked = -1;
13833    switch (cmd) {
13834    case CLI_INIT:
13835       e->command = "ss7 unblock cic";
13836       e->usage = 
13837          "Usage: ss7 unblock cic <linkset> <CIC>\n"
13838          "       Sends a remote unblocking request for the given CIC on the specified linkset\n";
13839       return NULL;
13840    case CLI_GENERATE:
13841       return NULL;
13842    }
13843 
13844    if (a->argc == 5)
13845       linkset = atoi(a->argv[3]);
13846    else
13847       return CLI_SHOWUSAGE;
13848 
13849    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13850       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13851       return CLI_SUCCESS;
13852    }
13853 
13854    if (!linksets[linkset-1].ss7) {
13855       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13856       return CLI_SUCCESS;
13857    }
13858 
13859    cic = atoi(a->argv[4]);
13860 
13861    if (cic < 1) {
13862       ast_cli(a->fd, "Invalid CIC specified!\n");
13863       return CLI_SUCCESS;
13864    }
13865 
13866    for (i = 0; i < linksets[linkset-1].numchans; i++) {
13867       if (linksets[linkset-1].pvts[i]->cic == cic) {
13868          blocked = linksets[linkset-1].pvts[i]->locallyblocked;
13869          if (blocked) {
13870             ast_mutex_lock(&linksets[linkset-1].lock);
13871             isup_ubl(linksets[linkset-1].ss7, cic, linksets[linkset-1].pvts[i]->dpc);
13872             ast_mutex_unlock(&linksets[linkset-1].lock);
13873          }
13874       }
13875    }
13876 
13877    if (blocked > 0)
13878       ast_cli(a->fd, "Sent unblocking request for linkset %d on CIC %d\n", linkset, cic);
13879 
13880    /* Break poll on the linkset so it sends our messages */
13881    pthread_kill(linksets[linkset-1].master, SIGURG);
13882 
13883    return CLI_SUCCESS;
13884 }
13885 
13886 static char *handle_ss7_unblock_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13887 {
13888    int linkset;
13889    int i;
13890    switch (cmd) {
13891    case CLI_INIT:
13892       e->command = "ss7 unblock linkset";
13893       e->usage = 
13894          "Usage: ss7 unblock linkset <linkset number>\n"
13895          "       Sends a remote unblocking request for all CICs on the specified linkset\n";
13896       return NULL;
13897    case CLI_GENERATE:
13898       return NULL;
13899    }
13900 
13901    if (a->argc == 4)
13902       linkset = atoi(a->argv[3]);
13903    else
13904       return CLI_SHOWUSAGE;
13905 
13906    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13907       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13908       return CLI_SUCCESS;
13909    }
13910 
13911    if (!linksets[linkset-1].ss7) {
13912       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13913       return CLI_SUCCESS;
13914    }
13915 
13916    for (i = 0; i < linksets[linkset-1].numchans; i++) {
13917       ast_cli(a->fd, "Sending remote unblock request on CIC %d\n", linksets[linkset-1].pvts[i]->cic);
13918       ast_mutex_lock(&linksets[linkset-1].lock);
13919       isup_ubl(linksets[linkset-1].ss7, linksets[linkset-1].pvts[i]->cic, linksets[linkset-1].pvts[i]->dpc);
13920       ast_mutex_unlock(&linksets[linkset-1].lock);
13921    }
13922 
13923    /* Break poll on the linkset so it sends our messages */
13924    pthread_kill(linksets[linkset-1].master, SIGURG);
13925 
13926    return CLI_SUCCESS;
13927 }
13928 
13929 static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13930 {
13931    int linkset;
13932    struct dahdi_ss7 *ss7;
13933    switch (cmd) {
13934    case CLI_INIT:
13935       e->command = "ss7 show linkset";
13936       e->usage = 
13937          "Usage: ss7 show linkset <span>\n"
13938          "       Shows the status of an SS7 linkset.\n";
13939       return NULL;
13940    case CLI_GENERATE:
13941       return NULL;
13942    }
13943 
13944    if (a->argc < 4)
13945       return CLI_SHOWUSAGE;
13946    linkset = atoi(a->argv[3]);
13947    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13948       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13949       return CLI_SUCCESS;
13950    }
13951    if (!linksets[linkset-1].ss7) {
13952       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13953       return CLI_SUCCESS;
13954    }
13955    if (linksets[linkset-1].ss7)
13956       ss7 = &linksets[linkset-1];
13957 
13958    ast_cli(a->fd, "SS7 linkset %d status: %s\n", linkset, (ss7->state == LINKSET_STATE_UP) ? "Up" : "Down");
13959 
13960    return CLI_SUCCESS;
13961 }
13962 
13963 static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13964 {
13965    switch (cmd) {
13966    case CLI_INIT:
13967       e->command = "ss7 show version";
13968       e->usage = 
13969          "Usage: ss7 show version\n"
13970          "  Show the libss7 version\n";
13971       return NULL;
13972    case CLI_GENERATE:
13973       return NULL;
13974    }
13975 
13976    ast_cli(a->fd, "libss7 version: %s\n", ss7_get_version());
13977 
13978    return CLI_SUCCESS;
13979 }
13980 
13981 static struct ast_cli_entry dahdi_ss7_cli[] = {
13982    AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"), 
13983    AST_CLI_DEFINE(handle_ss7_no_debug, "Disables SS7 debugging on a linkset"), 
13984    AST_CLI_DEFINE(handle_ss7_block_cic, "Blocks the given CIC"),
13985    AST_CLI_DEFINE(handle_ss7_unblock_cic, "Unblocks the given CIC"),
13986    AST_CLI_DEFINE(handle_ss7_block_linkset, "Blocks all CICs on a linkset"),
13987    AST_CLI_DEFINE(handle_ss7_unblock_linkset, "Unblocks all CICs on a linkset"),
13988    AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"),
13989    AST_CLI_DEFINE(handle_ss7_version, "Displays libss7 version"),
13990 };
13991 #endif /* HAVE_SS7 */
13992 
13993 static int __unload_module(void)
13994 {
13995    struct dahdi_pvt *p;
13996 #if defined(HAVE_PRI) || defined(HAVE_SS7)
13997    int i, j;
13998 #endif
13999 
14000 #ifdef HAVE_PRI
14001    for (i = 0; i < NUM_SPANS; i++) {
14002       if (pris[i].master != AST_PTHREADT_NULL) 
14003          pthread_cancel(pris[i].master);
14004    }
14005    ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
14006    ast_unregister_application(dahdi_send_keypad_facility_app);
14007 #endif
14008 #if defined(HAVE_SS7)
14009    for (i = 0; i < NUM_SPANS; i++) {
14010       if (linksets[i].master != AST_PTHREADT_NULL)
14011          pthread_cancel(linksets[i].master);
14012       }
14013    ast_cli_unregister_multiple(dahdi_ss7_cli, sizeof(dahdi_ss7_cli) / sizeof(struct ast_cli_entry));
14014 #endif
14015 
14016    ast_cli_unregister_multiple(dahdi_cli, sizeof(dahdi_cli) / sizeof(struct ast_cli_entry));
14017    ast_manager_unregister( "DAHDIDialOffhook" );
14018    ast_manager_unregister( "DAHDIHangup" );
14019    ast_manager_unregister( "DAHDITransfer" );
14020    ast_manager_unregister( "DAHDIDNDoff" );
14021    ast_manager_unregister( "DAHDIDNDon" );
14022    ast_manager_unregister("DAHDIShowChannels");
14023    ast_manager_unregister("DAHDIRestart");
14024    ast_channel_unregister(&dahdi_tech);
14025    ast_mutex_lock(&iflock);
14026    /* Hangup all interfaces if they have an owner */
14027    p = iflist;
14028    while (p) {
14029       if (p->owner)
14030          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
14031       p = p->next;
14032    }
14033    ast_mutex_unlock(&iflock);
14034    ast_mutex_lock(&monlock);
14035    if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
14036       pthread_cancel(monitor_thread);
14037       pthread_kill(monitor_thread, SIGURG);
14038       pthread_join(monitor_thread, NULL);
14039    }
14040    monitor_thread = AST_PTHREADT_STOP;
14041    ast_mutex_unlock(&monlock);
14042 
14043    destroy_all_channels();
14044 
14045 #if defined(HAVE_PRI)
14046    for (i = 0; i < NUM_SPANS; i++) {
14047       if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL))
14048          pthread_join(pris[i].master, NULL);
14049       for (j = 0; j < NUM_DCHANS; j++) {
14050          dahdi_close_pri_fd(&(pris[i]), j);
14051       }
14052    }
14053 #endif
14054 
14055 #if defined(HAVE_SS7)
14056    for (i = 0; i < NUM_SPANS; i++) {
14057       if (linksets[i].master && (linksets[i].master != AST_PTHREADT_NULL))
14058          pthread_join(linksets[i].master, NULL);
14059       for (j = 0; j < NUM_DCHANS; j++) {
14060          dahdi_close_ss7_fd(&(linksets[i]), j);
14061       }
14062    }
14063 #endif
14064 
14065    ast_cond_destroy(&mwi_thread_complete);
14066    ast_cond_destroy(&ss_thread_complete);
14067    return 0;
14068 }
14069 
14070 static int unload_module(void)
14071 {
14072 #if defined(HAVE_PRI) || defined(HAVE_SS7)
14073    int y;
14074 #endif
14075 #ifdef HAVE_PRI
14076    for (y = 0; y < NUM_SPANS; y++)
14077       ast_mutex_destroy(&pris[y].lock);
14078 #endif
14079 #ifdef HAVE_SS7
14080    for (y = 0; y < NUM_SPANS; y++)
14081       ast_mutex_destroy(&linksets[y].lock);
14082 #endif /* HAVE_SS7 */
14083    return __unload_module();
14084 }
14085 
14086 static int build_channels(struct dahdi_chan_conf *conf, int iscrv, const char *value, int reload, int lineno, int *found_pseudo)
14087 {
14088    char *c, *chan;
14089    int x, start, finish;
14090    struct dahdi_pvt *tmp;
14091 #ifdef HAVE_PRI
14092    struct dahdi_pri *pri;
14093    int trunkgroup, y;
14094 #endif
14095    
14096    if ((reload == 0) && (conf->chan.sig < 0) && !conf->is_sig_auto) {
14097       ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n");
14098       return -1;
14099    }
14100 
14101    c = ast_strdupa(value);
14102 
14103 #ifdef HAVE_PRI
14104    pri = NULL;
14105    if (iscrv) {
14106       if (sscanf(c, "%d:%n", &trunkgroup, &y) != 1) {
14107          ast_log(LOG_WARNING, "CRV must begin with trunkgroup followed by a colon at line %d.\n", lineno);
14108          return -1;
14109       }
14110       if (trunkgroup < 1) {
14111          ast_log(LOG_WARNING, "CRV trunk group must be a positive number at line %d.\n", lineno);
14112          return -1;
14113       }
14114       c += y;
14115       for (y = 0; y < NUM_SPANS; y++) {
14116          if (pris[y].trunkgroup == trunkgroup) {
14117             pri = pris + y;
14118             break;
14119          }
14120       }
14121       if (!pri) {
14122          ast_log(LOG_WARNING, "No such trunk group %d at CRV declaration at line %d.\n", trunkgroup, lineno);
14123          return -1;
14124       }
14125    }
14126 #endif         
14127 
14128    while ((chan = strsep(&c, ","))) {
14129       if (sscanf(chan, "%d-%d", &start, &finish) == 2) {
14130          /* Range */
14131       } else if (sscanf(chan, "%d", &start)) {
14132          /* Just one */
14133          finish = start;
14134       } else if (!strcasecmp(chan, "pseudo")) {
14135          finish = start = CHAN_PSEUDO;
14136          if (found_pseudo)
14137             *found_pseudo = 1;
14138       } else {
14139          ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
14140          return -1;
14141       }
14142       if (finish < start) {
14143          ast_log(LOG_WARNING, "Sillyness: %d < %d\n", start, finish);
14144          x = finish;
14145          finish = start;
14146          start = x;
14147       }
14148 
14149       for (x = start; x <= finish; x++) {
14150 #ifdef HAVE_PRI
14151          tmp = mkintf(x, conf, pri, reload);
14152 #else       
14153          tmp = mkintf(x, conf, NULL, reload);
14154 #endif         
14155 
14156          if (tmp) {
14157 #ifdef HAVE_PRI
14158                if (pri)
14159                ast_verb(3, "%s CRV %d:%d, %s signalling\n", reload ? "Reconfigured" : "Registered", trunkgroup, x, sig2str(tmp->sig));
14160                else
14161 #endif
14162                ast_verb(3, "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig));
14163          } else {
14164             ast_log(LOG_ERROR, "Unable to %s channel '%s'\n",
14165                (reload == 1) ? "reconfigure" : "register", value);
14166             return -1;
14167          }
14168       }
14169    }
14170 
14171    return 0;
14172 }
14173 
14174 /** The length of the parameters list of 'dahdichan'. 
14175  * \todo Move definition of MAX_CHANLIST_LEN to a proper place. */
14176 #define MAX_CHANLIST_LEN 80
14177 
14178 static void process_echocancel(struct dahdi_chan_conf *confp, const char *data, unsigned int line)
14179 {
14180    char *parse = ast_strdupa(data);
14181    char *params[DAHDI_MAX_ECHOCANPARAMS + 1];
14182    unsigned int param_count;
14183    unsigned int x;
14184 
14185    if (!(param_count = ast_app_separate_args(parse, ',', params, ARRAY_LEN(params))))
14186       return;
14187 
14188    memset(&confp->chan.echocancel, 0, sizeof(confp->chan.echocancel));
14189 
14190    /* first parameter is tap length, process it here */
14191 
14192    x = ast_strlen_zero(params[0]) ? 0 : atoi(params[0]);
14193    
14194    if ((x == 32) || (x == 64) || (x == 128) || (x == 256) || (x == 512) || (x == 1024))
14195       confp->chan.echocancel.head.tap_length = x;
14196    else if ((confp->chan.echocancel.head.tap_length = ast_true(params[0])))
14197       confp->chan.echocancel.head.tap_length = 128;
14198 
14199    /* now process any remaining parameters */
14200 
14201    for (x = 1; x < param_count; x++) {
14202       struct {
14203          char *name;
14204          char *value;
14205       } param;
14206 
14207       if (ast_app_separate_args(params[x], '=', (char **) &param, 2) < 1) {
14208          ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %d: '%s'\n", line, params[x]);
14209          continue;
14210       }
14211 
14212       if (ast_strlen_zero(param.name) || (strlen(param.name) > sizeof(confp->chan.echocancel.params[0].name)-1)) {
14213          ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %d: '%s'\n", line, param.name);
14214          continue;
14215       }
14216 
14217       strcpy(confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].name, param.name);
14218 
14219       if (param.value) {
14220          if (sscanf(param.value, "%d", &confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].value) != 1) {
14221             ast_log(LOG_WARNING, "Invalid echocancel parameter value supplied at line %d: '%s'\n", line, param.value);
14222             continue;
14223          }
14224       }
14225       confp->chan.echocancel.head.param_count++;
14226    }
14227 }
14228 
14229 /*! process_dahdi() - ignore keyword 'channel' and similar */
14230 #define PROC_DAHDI_OPT_NOCHAN  (1 << 0) 
14231 /*! process_dahdi() - No warnings on non-existing cofiguration keywords */
14232 #define PROC_DAHDI_OPT_NOWARN  (1 << 1) 
14233 
14234 static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
14235 {
14236    struct dahdi_pvt *tmp;
14237    int y;
14238    int found_pseudo = 0;
14239    char dahdichan[MAX_CHANLIST_LEN] = {};
14240 
14241    for (; v; v = v->next) {
14242       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
14243          continue;
14244 
14245       /* must have parkinglot in confp before build_channels is called */
14246       if (!strcasecmp(v->name, "parkinglot")) {
14247          ast_copy_string(confp->chan.parkinglot, v->value, sizeof(confp->chan.parkinglot));
14248       }
14249 
14250       /* Create the interface list */
14251       if (!strcasecmp(v->name, "channel")
14252 #ifdef HAVE_PRI
14253           || !strcasecmp(v->name, "crv")
14254 #endif         
14255          ) {
14256          int iscrv;
14257          if (options & PROC_DAHDI_OPT_NOCHAN) {
14258             ast_log(LOG_WARNING, "Channel '%s' ignored.\n", v->value);
14259             continue;
14260          }
14261          iscrv = !strcasecmp(v->name, "crv");
14262          if (build_channels(confp, iscrv, v->value, reload, v->lineno, &found_pseudo))
14263                return -1;
14264          ast_log(LOG_DEBUG, "Channel '%s' configured.\n", v->value);
14265       } else if (!strcasecmp(v->name, "buffers")) {
14266          int res;
14267          char policy[21] = "";
14268 
14269          res = sscanf(v->value, "%d,%20s", &confp->chan.buf_no, policy);
14270          if (res != 2) {
14271             ast_log(LOG_WARNING, "Parsing buffers option data failed, using defaults.\n");
14272             confp->chan.buf_no = numbufs;
14273             continue;
14274          }
14275          if (confp->chan.buf_no < 0)
14276             confp->chan.buf_no = numbufs;
14277          if (!strcasecmp(policy, "full")) {
14278             confp->chan.buf_policy = DAHDI_POLICY_WHEN_FULL;
14279          } else if (!strcasecmp(policy, "immediate")) {
14280             confp->chan.buf_policy = DAHDI_POLICY_IMMEDIATE;
14281          } else {
14282             ast_log(LOG_WARNING, "Invalid policy name given (%s).\n", policy);
14283          }
14284       } else if (!strcasecmp(v->name, "dahdichan")) {
14285          ast_copy_string(dahdichan, v->value, sizeof(dahdichan));
14286       } else if (!strcasecmp(v->name, "usedistinctiveringdetection")) {
14287          usedistinctiveringdetection = ast_true(v->value);
14288       } else if (!strcasecmp(v->name, "distinctiveringaftercid")) {
14289          distinctiveringaftercid = ast_true(v->value);
14290       } else if (!strcasecmp(v->name, "dring1context")) {
14291          ast_copy_string(confp->chan.drings.ringContext[0].contextData,v->value,sizeof(confp->chan.drings.ringContext[0].contextData));
14292       } else if (!strcasecmp(v->name, "dring2context")) {
14293          ast_copy_string(confp->chan.drings.ringContext[1].contextData,v->value,sizeof(confp->chan.drings.ringContext[1].contextData));
14294       } else if (!strcasecmp(v->name, "dring3context")) {
14295          ast_copy_string(confp->chan.drings.ringContext[2].contextData,v->value,sizeof(confp->chan.drings.ringContext[2].contextData));
14296       } else if (!strcasecmp(v->name, "dring1range")) {
14297          confp->chan.drings.ringnum[0].range = atoi(v->value);
14298       } else if (!strcasecmp(v->name, "dring2range")) {
14299          confp->chan.drings.ringnum[1].range = atoi(v->value);
14300       } else if (!strcasecmp(v->name, "dring3range")) {
14301          confp->chan.drings.ringnum[2].range = atoi(v->value);
14302       } else if (!strcasecmp(v->name, "dring1")) {
14303          sscanf(v->value, "%d,%d,%d", &confp->chan.drings.ringnum[0].ring[0], &confp->chan.drings.ringnum[0].ring[1], &confp->chan.drings.ringnum[0].ring[2]);
14304       } else if (!strcasecmp(v->name, "dring2")) {
14305          sscanf(v->value,"%d,%d,%d", &confp->chan.drings.ringnum[1].ring[0], &confp->chan.drings.ringnum[1].ring[1], &confp->chan.drings.ringnum[1].ring[2]);
14306       } else if (!strcasecmp(v->name, "dring3")) {
14307          sscanf(v->value, "%d,%d,%d", &confp->chan.drings.ringnum[2].ring[0], &confp->chan.drings.ringnum[2].ring[1], &confp->chan.drings.ringnum[2].ring[2]);
14308       } else if (!strcasecmp(v->name, "usecallerid")) {
14309          confp->chan.use_callerid = ast_true(v->value);
14310       } else if (!strcasecmp(v->name, "cidsignalling")) {
14311          if (!strcasecmp(v->value, "bell"))
14312             confp->chan.cid_signalling = CID_SIG_BELL;
14313          else if (!strcasecmp(v->value, "v23"))
14314             confp->chan.cid_signalling = CID_SIG_V23;
14315          else if (!strcasecmp(v->value, "dtmf"))
14316             confp->chan.cid_signalling = CID_SIG_DTMF;
14317          else if (!strcasecmp(v->value, "smdi"))
14318             confp->chan.cid_signalling = CID_SIG_SMDI;
14319          else if (!strcasecmp(v->value, "v23_jp"))
14320             confp->chan.cid_signalling = CID_SIG_V23_JP;
14321          else if (ast_true(v->value))
14322             confp->chan.cid_signalling = CID_SIG_BELL;
14323       } else if (!strcasecmp(v->name, "cidstart")) {
14324          if (!strcasecmp(v->value, "ring"))
14325             confp->chan.cid_start = CID_START_RING;
14326          else if (!strcasecmp(v->value, "polarity_in"))
14327             confp->chan.cid_start = CID_START_POLARITY_IN;
14328          else if (!strcasecmp(v->value, "polarity"))
14329             confp->chan.cid_start = CID_START_POLARITY;
14330          else if (ast_true(v->value))
14331             confp->chan.cid_start = CID_START_RING;
14332       } else if (!strcasecmp(v->name, "threewaycalling")) {
14333          confp->chan.threewaycalling = ast_true(v->value);
14334       } else if (!strcasecmp(v->name, "cancallforward")) {
14335          confp->chan.cancallforward = ast_true(v->value);
14336       } else if (!strcasecmp(v->name, "relaxdtmf")) {
14337          if (ast_true(v->value)) 
14338             confp->chan.dtmfrelax = DSP_DIGITMODE_RELAXDTMF;
14339          else
14340             confp->chan.dtmfrelax = 0;
14341       } else if (!strcasecmp(v->name, "mailbox")) {
14342          ast_copy_string(confp->chan.mailbox, v->value, sizeof(confp->chan.mailbox));
14343       } else if (!strcasecmp(v->name, "hasvoicemail")) {
14344          if (ast_true(v->value) && ast_strlen_zero(confp->chan.mailbox)) {
14345             ast_copy_string(confp->chan.mailbox, cat, sizeof(confp->chan.mailbox));
14346          }
14347       } else if (!strcasecmp(v->name, "adsi")) {
14348          confp->chan.adsi = ast_true(v->value);
14349       } else if (!strcasecmp(v->name, "usesmdi")) {
14350          confp->chan.use_smdi = ast_true(v->value);
14351       } else if (!strcasecmp(v->name, "smdiport")) {
14352          ast_copy_string(confp->smdi_port, v->value, sizeof(confp->smdi_port));
14353       } else if (!strcasecmp(v->name, "transfer")) {
14354          confp->chan.transfer = ast_true(v->value);
14355       } else if (!strcasecmp(v->name, "canpark")) {
14356          confp->chan.canpark = ast_true(v->value);
14357       } else if (!strcasecmp(v->name, "echocancelwhenbridged")) {
14358          confp->chan.echocanbridged = ast_true(v->value);
14359       } else if (!strcasecmp(v->name, "busydetect")) {
14360          confp->chan.busydetect = ast_true(v->value);
14361       } else if (!strcasecmp(v->name, "busycount")) {
14362          confp->chan.busycount = atoi(v->value);
14363       } else if (!strcasecmp(v->name, "silencethreshold")) {
14364          confp->chan.silencethreshold = atoi(v->value);
14365       } else if (!strcasecmp(v->name, "busycompare")) {
14366          confp->chan.busycompare = ast_true(v->value);
14367       } else if (!strcasecmp(v->name, "busypattern")) {
14368          if (sscanf(v->value, "%d,%d", &confp->chan.busytonelength, &confp->chan.busyquietlength) != 2) {
14369             ast_log(LOG_ERROR, "busypattern= expects busypattern=tonelength,quietlength at line %d.\n", v->lineno);
14370          }
14371          int count = sscanf(v->value, "%d,%d", &confp->chan.busytonelength, &confp->chan.busyquietlength);
14372          if (count == 1)
14373             confp->chan.busyquietlength = 0;
14374          else if (count < 1)
14375             ast_log(LOG_ERROR, "busypattern= expects busypattern=tonelength[,quietlength] at line %d.\n", v->lineno);
14376       } else if (!strcasecmp(v->name, "busyfuzziness")) {
14377          confp->chan.busyfuzziness = atoi(v->value);
14378       } else if (!strcasecmp(v->name, "callprogress")) {
14379          confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS;
14380          if (ast_true(v->value))
14381             confp->chan.callprogress |= CALLPROGRESS_PROGRESS;
14382       } else if (!strcasecmp(v->name, "faxdetect")) {
14383          confp->chan.callprogress &= ~CALLPROGRESS_FAX;
14384          if (!strcasecmp(v->value, "incoming")) {
14385             confp->chan.callprogress |= CALLPROGRESS_FAX_INCOMING;
14386          } else if (!strcasecmp(v->value, "outgoing")) {
14387             confp->chan.callprogress |= CALLPROGRESS_FAX_OUTGOING;
14388          } else if (!strcasecmp(v->value, "both") || ast_true(v->value))
14389             confp->chan.callprogress |= CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING;
14390       } else if (!strcasecmp(v->name, "echocancel")) {
14391          process_echocancel(confp, v->value, v->lineno);
14392       } else if (!strcasecmp(v->name, "echotraining")) {
14393          if (sscanf(v->value, "%d", &y) == 1) {
14394             if ((y < 10) || (y > 4000)) {
14395                ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 4000 ms at line %d.\n", v->lineno);             
14396             } else {
14397                confp->chan.echotraining = y;
14398             }
14399          } else if (ast_true(v->value)) {
14400             confp->chan.echotraining = 400;
14401          } else
14402             confp->chan.echotraining = 0;
14403       } else if (!strcasecmp(v->name, "hidecallerid")) {
14404          confp->chan.hidecallerid = ast_true(v->value);
14405       } else if (!strcasecmp(v->name, "hidecalleridname")) {
14406          confp->chan.hidecalleridname = ast_true(v->value);
14407       } else if (!strcasecmp(v->name, "pulsedial")) {
14408          confp->chan.pulse = ast_true(v->value);
14409       } else if (!strcasecmp(v->name, "callreturn")) {
14410          confp->chan.callreturn = ast_true(v->value);
14411       } else if (!strcasecmp(v->name, "callwaiting")) {
14412          confp->chan.callwaiting = ast_true(v->value);
14413       } else if (!strcasecmp(v->name, "callwaitingcallerid")) {
14414          confp->chan.callwaitingcallerid = ast_true(v->value);
14415       } else if (!strcasecmp(v->name, "context")) {
14416          ast_copy_string(confp->chan.context, v->value, sizeof(confp->chan.context));
14417       } else if (!strcasecmp(v->name, "language")) {
14418          ast_copy_string(confp->chan.language, v->value, sizeof(confp->chan.language));
14419       } else if (!strcasecmp(v->name, "progzone")) {
14420          ast_copy_string(progzone, v->value, sizeof(progzone));
14421       } else if (!strcasecmp(v->name, "mohinterpret") 
14422          ||!strcasecmp(v->name, "musiconhold") || !strcasecmp(v->name, "musicclass")) {
14423          ast_copy_string(confp->chan.mohinterpret, v->value, sizeof(confp->chan.mohinterpret));
14424       } else if (!strcasecmp(v->name, "mohsuggest")) {
14425          ast_copy_string(confp->chan.mohsuggest, v->value, sizeof(confp->chan.mohsuggest));
14426       } else if (!strcasecmp(v->name, "parkinglot")) {
14427          ast_copy_string(parkinglot, v->value, sizeof(parkinglot));
14428       } else if (!strcasecmp(v->name, "stripmsd")) {
14429          ast_log(LOG_NOTICE, "Configuration option \"%s\" has been deprecated. Please use dialplan instead\n", v->name);
14430          confp->chan.stripmsd = atoi(v->value);
14431       } else if (!strcasecmp(v->name, "jitterbuffers")) {
14432          numbufs = atoi(v->value);
14433       } else if (!strcasecmp(v->name, "group")) {
14434          confp->chan.group = ast_get_group(v->value);
14435       } else if (!strcasecmp(v->name, "callgroup")) {
14436          if (!strcasecmp(v->value, "none"))
14437             confp->chan.callgroup = 0;
14438          else
14439             confp->chan.callgroup = ast_get_group(v->value);
14440       } else if (!strcasecmp(v->name, "pickupgroup")) {
14441          if (!strcasecmp(v->value, "none"))
14442             confp->chan.pickupgroup = 0;
14443          else
14444             confp->chan.pickupgroup = ast_get_group(v->value);
14445       } else if (!strcasecmp(v->name, "setvar")) {
14446          char *varname = ast_strdupa(v->value), *varval = NULL;
14447          struct ast_variable *tmpvar;
14448          if (varname && (varval = strchr(varname, '='))) {
14449             *varval++ = '\0';
14450             if ((tmpvar = ast_variable_new(varname, varval, ""))) {
14451                tmpvar->next = confp->chan.vars;
14452                confp->chan.vars = tmpvar;
14453             }
14454          }
14455       } else if (!strcasecmp(v->name, "immediate")) {
14456          confp->chan.immediate = ast_true(v->value);
14457       } else if (!strcasecmp(v->name, "transfertobusy")) {
14458          confp->chan.transfertobusy = ast_true(v->value);
14459       } else if (!strcasecmp(v->name, "mwimonitor")) {
14460          confp->chan.mwimonitor_neon = 0;
14461          confp->chan.mwimonitor_fsk  = 0;
14462          confp->chan.mwimonitor_rpas = 0;
14463          if (strcasestr(v->value, "fsk")) {
14464             confp->chan.mwimonitor_fsk = 1;
14465          }
14466          if (strcasestr(v->value, "rpas")) {
14467             confp->chan.mwimonitor_rpas = 1;
14468          }
14469          if (strcasestr(v->value, "neon")) {
14470             confp->chan.mwimonitor_neon = 1;
14471          }
14472          /* If set to true or yes, assume that simple fsk is desired */
14473          if (ast_true(v->value)) {
14474             confp->chan.mwimonitor_fsk = 1;
14475          } 
14476       } else if (!strcasecmp(v->name, "cid_rxgain")) {
14477          if (sscanf(v->value, "%f", &confp->chan.cid_rxgain) != 1) {
14478             ast_log(LOG_WARNING, "Invalid cid_rxgain: %s at line %d.\n", v->value, v->lineno);
14479          }
14480       } else if (!strcasecmp(v->name, "rxgain")) {
14481          if (sscanf(v->value, "%f", &confp->chan.rxgain) != 1) {
14482             ast_log(LOG_WARNING, "Invalid rxgain: %s at line %d.\n", v->value, v->lineno);
14483          }
14484       } else if (!strcasecmp(v->name, "txgain")) {
14485          if (sscanf(v->value, "%f", &confp->chan.txgain) != 1) {
14486             ast_log(LOG_WARNING, "Invalid txgain: %s at line %d.\n", v->value, v->lineno);
14487          }
14488       } else if (!strcasecmp(v->name, "tonezone")) {
14489          if (sscanf(v->value, "%d", &confp->chan.tonezone) != 1) {
14490             ast_log(LOG_WARNING, "Invalid tonezone: %s at line %d.\n", v->value, v->lineno);
14491          }
14492       } else if (!strcasecmp(v->name, "callerid")) {
14493          if (!strcasecmp(v->value, "asreceived")) {
14494             confp->chan.cid_num[0] = '\0';
14495             confp->chan.cid_name[0] = '\0';
14496          } else {
14497             ast_callerid_split(v->value, confp->chan.cid_name, sizeof(confp->chan.cid_name), confp->chan.cid_num, sizeof(confp->chan.cid_num));
14498          } 
14499       } else if (!strcasecmp(v->name, "fullname")) {
14500          ast_copy_string(confp->chan.cid_name, v->value, sizeof(confp->chan.cid_name));
14501       } else if (!strcasecmp(v->name, "cid_number")) {
14502          ast_copy_string(confp->chan.cid_num, v->value, sizeof(confp->chan.cid_num));
14503       } else if (!strcasecmp(v->name, "useincomingcalleridondahditransfer")) {
14504          confp->chan.dahditrcallerid = ast_true(v->value);
14505       } else if (!strcasecmp(v->name, "restrictcid")) {
14506          confp->chan.restrictcid = ast_true(v->value);
14507       } else if (!strcasecmp(v->name, "usecallingpres")) {
14508          confp->chan.use_callingpres = ast_true(v->value);
14509       } else if (!strcasecmp(v->name, "accountcode")) {
14510          ast_copy_string(confp->chan.accountcode, v->value, sizeof(confp->chan.accountcode));
14511       } else if (!strcasecmp(v->name, "amaflags")) {
14512          y = ast_cdr_amaflags2int(v->value);
14513          if (y < 0) 
14514             ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d.\n", v->value, v->lineno);
14515          else
14516             confp->chan.amaflags = y;
14517       } else if (!strcasecmp(v->name, "polarityonanswerdelay")) {
14518          confp->chan.polarityonanswerdelay = atoi(v->value);
14519       } else if (!strcasecmp(v->name, "answeronpolarityswitch")) {
14520          confp->chan.answeronpolarityswitch = ast_true(v->value);
14521       } else if (!strcasecmp(v->name, "hanguponpolarityswitch")) {
14522          confp->chan.hanguponpolarityswitch = ast_true(v->value);
14523       } else if (!strcasecmp(v->name, "sendcalleridafter")) {
14524          confp->chan.sendcalleridafter = atoi(v->value);
14525       } else if (!strcasecmp(v->name, "mwimonitornotify")) {
14526          ast_copy_string(mwimonitornotify, v->value, sizeof(mwimonitornotify));
14527       } else if (!strcasecmp(v->name, "mwisendtype")) {
14528          if (!strcasecmp(v->value, "rpas")) { /* Ring Pulse Alert Signal */
14529             mwisend_rpas = 1;
14530          } else {
14531             mwisend_rpas = 0;
14532          }
14533       } else if (reload != 1) {
14534           if (!strcasecmp(v->name, "signalling") || !strcasecmp(v->name, "signaling")) {
14535             int orig_radio = confp->chan.radio;
14536             int orig_outsigmod = confp->chan.outsigmod;
14537             int orig_auto = confp->is_sig_auto;
14538 
14539             confp->chan.radio = 0;
14540             confp->chan.outsigmod = -1;
14541             confp->is_sig_auto = 0;
14542             if (!strcasecmp(v->value, "em")) {
14543                confp->chan.sig = SIG_EM;
14544             } else if (!strcasecmp(v->value, "em_e1")) {
14545                confp->chan.sig = SIG_EM_E1;
14546             } else if (!strcasecmp(v->value, "em_w")) {
14547                confp->chan.sig = SIG_EMWINK;
14548             } else if (!strcasecmp(v->value, "fxs_ls")) {
14549                confp->chan.sig = SIG_FXSLS;
14550             } else if (!strcasecmp(v->value, "fxs_gs")) {
14551                confp->chan.sig = SIG_FXSGS;
14552             } else if (!strcasecmp(v->value, "fxs_ks")) {
14553                confp->chan.sig = SIG_FXSKS;
14554             } else if (!strcasecmp(v->value, "fxo_ls")) {
14555                confp->chan.sig = SIG_FXOLS;
14556             } else if (!strcasecmp(v->value, "fxo_gs")) {
14557                confp->chan.sig = SIG_FXOGS;
14558             } else if (!strcasecmp(v->value, "fxo_ks")) {
14559                confp->chan.sig = SIG_FXOKS;
14560             } else if (!strcasecmp(v->value, "fxs_rx")) {
14561                confp->chan.sig = SIG_FXSKS;
14562                confp->chan.radio = 1;
14563             } else if (!strcasecmp(v->value, "fxo_rx")) {
14564                confp->chan.sig = SIG_FXOLS;
14565                confp->chan.radio = 1;
14566             } else if (!strcasecmp(v->value, "fxs_tx")) {
14567                confp->chan.sig = SIG_FXSLS;
14568                confp->chan.radio = 1;
14569             } else if (!strcasecmp(v->value, "fxo_tx")) {
14570                confp->chan.sig = SIG_FXOGS;
14571                confp->chan.radio = 1;
14572             } else if (!strcasecmp(v->value, "em_rx")) {
14573                confp->chan.sig = SIG_EM;
14574                confp->chan.radio = 1;
14575             } else if (!strcasecmp(v->value, "em_tx")) {
14576                confp->chan.sig = SIG_EM;
14577                confp->chan.radio = 1;
14578             } else if (!strcasecmp(v->value, "em_rxtx")) {
14579                confp->chan.sig = SIG_EM;
14580                confp->chan.radio = 2;
14581             } else if (!strcasecmp(v->value, "em_txrx")) {
14582                confp->chan.sig = SIG_EM;
14583                confp->chan.radio = 2;
14584             } else if (!strcasecmp(v->value, "sf")) {
14585                confp->chan.sig = SIG_SF;
14586             } else if (!strcasecmp(v->value, "sf_w")) {
14587                confp->chan.sig = SIG_SFWINK;
14588             } else if (!strcasecmp(v->value, "sf_featd")) {
14589                confp->chan.sig = SIG_FEATD;
14590             } else if (!strcasecmp(v->value, "sf_featdmf")) {
14591                confp->chan.sig = SIG_FEATDMF;
14592             } else if (!strcasecmp(v->value, "sf_featb")) {
14593                confp->chan.sig = SIG_SF_FEATB;
14594             } else if (!strcasecmp(v->value, "sf")) {
14595                confp->chan.sig = SIG_SF;
14596             } else if (!strcasecmp(v->value, "sf_rx")) {
14597                confp->chan.sig = SIG_SF;
14598                confp->chan.radio = 1;
14599             } else if (!strcasecmp(v->value, "sf_tx")) {
14600                confp->chan.sig = SIG_SF;
14601                confp->chan.radio = 1;
14602             } else if (!strcasecmp(v->value, "sf_rxtx")) {
14603                confp->chan.sig = SIG_SF;
14604                confp->chan.radio = 2;
14605             } else if (!strcasecmp(v->value, "sf_txrx")) {
14606                confp->chan.sig = SIG_SF;
14607                confp->chan.radio = 2;
14608             } else if (!strcasecmp(v->value, "featd")) {
14609                confp->chan.sig = SIG_FEATD;
14610             } else if (!strcasecmp(v->value, "featdmf")) {
14611                confp->chan.sig = SIG_FEATDMF;
14612             } else if (!strcasecmp(v->value, "featdmf_ta")) {
14613                confp->chan.sig = SIG_FEATDMF_TA;
14614             } else if (!strcasecmp(v->value, "e911")) {
14615                confp->chan.sig = SIG_E911;
14616             } else if (!strcasecmp(v->value, "fgccama")) {
14617                confp->chan.sig = SIG_FGC_CAMA;
14618             } else if (!strcasecmp(v->value, "fgccamamf")) {
14619                confp->chan.sig = SIG_FGC_CAMAMF;
14620             } else if (!strcasecmp(v->value, "featb")) {
14621                confp->chan.sig = SIG_FEATB;
14622 #ifdef HAVE_PRI
14623             } else if (!strcasecmp(v->value, "pri_net")) {
14624                confp->chan.sig = SIG_PRI;
14625                confp->pri.nodetype = PRI_NETWORK;
14626             } else if (!strcasecmp(v->value, "pri_cpe")) {
14627                confp->chan.sig = SIG_PRI;
14628                confp->pri.nodetype = PRI_CPE;
14629             } else if (!strcasecmp(v->value, "bri_cpe")) {
14630                confp->chan.sig = SIG_BRI;
14631                confp->pri.nodetype = PRI_CPE;
14632             } else if (!strcasecmp(v->value, "bri_net")) {
14633                confp->chan.sig = SIG_BRI;
14634                confp->pri.nodetype = PRI_NETWORK;
14635             } else if (!strcasecmp(v->value, "bri_cpe_ptmp")) {
14636                confp->chan.sig = SIG_BRI_PTMP;
14637                confp->pri.nodetype = PRI_CPE;
14638             } else if (!strcasecmp(v->value, "bri_net_ptmp")) {
14639                ast_log(LOG_WARNING, "How cool would it be if someone implemented this mode!  For now, sucks for you. (line %d)\n", v->lineno);
14640             } else if (!strcasecmp(v->value, "gr303fxoks_net")) {
14641                confp->chan.sig = SIG_GR303FXOKS;
14642                confp->pri.nodetype = PRI_NETWORK;
14643             } else if (!strcasecmp(v->value, "gr303fxsks_cpe")) {
14644                confp->chan.sig = SIG_GR303FXSKS;
14645                confp->pri.nodetype = PRI_CPE;
14646 #endif
14647 #ifdef HAVE_SS7
14648             } else if (!strcasecmp(v->value, "ss7")) {
14649                confp->chan.sig = SIG_SS7;
14650 #endif
14651             } else if (!strcasecmp(v->value, "auto")) {
14652                confp->is_sig_auto = 1;
14653             } else {
14654                confp->chan.outsigmod = orig_outsigmod;
14655                confp->chan.radio = orig_radio;
14656                confp->is_sig_auto = orig_auto;
14657                ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
14658             }
14659           } else if (!strcasecmp(v->name, "outsignalling") || !strcasecmp(v->name, "outsignaling")) {
14660             if (!strcasecmp(v->value, "em")) {
14661                confp->chan.outsigmod = SIG_EM;
14662             } else if (!strcasecmp(v->value, "em_e1")) {
14663                confp->chan.outsigmod = SIG_EM_E1;
14664             } else if (!strcasecmp(v->value, "em_w")) {
14665                confp->chan.outsigmod = SIG_EMWINK;
14666             } else if (!strcasecmp(v->value, "sf")) {
14667                confp->chan.outsigmod = SIG_SF;
14668             } else if (!strcasecmp(v->value, "sf_w")) {
14669                confp->chan.outsigmod = SIG_SFWINK;
14670             } else if (!strcasecmp(v->value, "sf_featd")) {
14671                confp->chan.outsigmod = SIG_FEATD;
14672             } else if (!strcasecmp(v->value, "sf_featdmf")) {
14673                confp->chan.outsigmod = SIG_FEATDMF;
14674             } else if (!strcasecmp(v->value, "sf_featb")) {
14675                confp->chan.outsigmod = SIG_SF_FEATB;
14676             } else if (!strcasecmp(v->value, "sf")) {
14677                confp->chan.outsigmod = SIG_SF;
14678             } else if (!strcasecmp(v->value, "featd")) {
14679                confp->chan.outsigmod = SIG_FEATD;
14680             } else if (!strcasecmp(v->value, "featdmf")) {
14681                confp->chan.outsigmod = SIG_FEATDMF;
14682             } else if (!strcasecmp(v->value, "featdmf_ta")) {
14683                confp->chan.outsigmod = SIG_FEATDMF_TA;
14684             } else if (!strcasecmp(v->value, "e911")) {
14685                confp->chan.outsigmod = SIG_E911;
14686             } else if (!strcasecmp(v->value, "fgccama")) {
14687                confp->chan.outsigmod = SIG_FGC_CAMA;
14688             } else if (!strcasecmp(v->value, "fgccamamf")) {
14689                confp->chan.outsigmod = SIG_FGC_CAMAMF;
14690             } else if (!strcasecmp(v->value, "featb")) {
14691                confp->chan.outsigmod = SIG_FEATB;
14692             } else {
14693                ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
14694             }
14695 #ifdef HAVE_PRI
14696          } else if (!strcasecmp(v->name, "pridialplan")) {
14697             if (!strcasecmp(v->value, "national")) {
14698                confp->pri.dialplan = PRI_NATIONAL_ISDN + 1;
14699             } else if (!strcasecmp(v->value, "unknown")) {
14700                confp->pri.dialplan = PRI_UNKNOWN + 1;
14701             } else if (!strcasecmp(v->value, "private")) {
14702                confp->pri.dialplan = PRI_PRIVATE + 1;
14703             } else if (!strcasecmp(v->value, "international")) {
14704                confp->pri.dialplan = PRI_INTERNATIONAL_ISDN + 1;
14705             } else if (!strcasecmp(v->value, "local")) {
14706                confp->pri.dialplan = PRI_LOCAL_ISDN + 1;
14707             } else if (!strcasecmp(v->value, "dynamic")) {
14708                confp->pri.dialplan = -1;
14709             } else if (!strcasecmp(v->value, "redundant")) {
14710                confp->pri.dialplan = -2;
14711             } else {
14712                ast_log(LOG_WARNING, "Unknown PRI dialplan '%s' at line %d.\n", v->value, v->lineno);
14713             }
14714          } else if (!strcasecmp(v->name, "prilocaldialplan")) {
14715             if (!strcasecmp(v->value, "national")) {
14716                confp->pri.localdialplan = PRI_NATIONAL_ISDN + 1;
14717             } else if (!strcasecmp(v->value, "unknown")) {
14718                confp->pri.localdialplan = PRI_UNKNOWN + 1;
14719             } else if (!strcasecmp(v->value, "private")) {
14720                confp->pri.localdialplan = PRI_PRIVATE + 1;
14721             } else if (!strcasecmp(v->value, "international")) {
14722                confp->pri.localdialplan = PRI_INTERNATIONAL_ISDN + 1;
14723             } else if (!strcasecmp(v->value, "local")) {
14724                confp->pri.localdialplan = PRI_LOCAL_ISDN + 1;
14725             } else if (!strcasecmp(v->value, "dynamic")) {
14726                confp->pri.localdialplan = -1;
14727             } else if (!strcasecmp(v->value, "redundant")) {
14728                confp->pri.localdialplan = -2;
14729             } else {
14730                ast_log(LOG_WARNING, "Unknown PRI localdialplan '%s' at line %d.\n", v->value, v->lineno);
14731             }
14732          } else if (!strcasecmp(v->name, "switchtype")) {
14733             if (!strcasecmp(v->value, "national")) 
14734                confp->pri.switchtype = PRI_SWITCH_NI2;
14735             else if (!strcasecmp(v->value, "ni1"))
14736                confp->pri.switchtype = PRI_SWITCH_NI1;
14737             else if (!strcasecmp(v->value, "dms100"))
14738                confp->pri.switchtype = PRI_SWITCH_DMS100;
14739             else if (!strcasecmp(v->value, "4ess"))
14740                confp->pri.switchtype = PRI_SWITCH_ATT4ESS;
14741             else if (!strcasecmp(v->value, "5ess"))
14742                confp->pri.switchtype = PRI_SWITCH_LUCENT5E;
14743             else if (!strcasecmp(v->value, "euroisdn"))
14744                confp->pri.switchtype = PRI_SWITCH_EUROISDN_E1;
14745             else if (!strcasecmp(v->value, "qsig"))
14746                confp->pri.switchtype = PRI_SWITCH_QSIG;
14747             else {
14748                ast_log(LOG_ERROR, "Unknown switchtype '%s' at line %d.\n", v->value, v->lineno);
14749                return -1;
14750             }
14751          } else if (!strcasecmp(v->name, "nsf")) {
14752             if (!strcasecmp(v->value, "sdn"))
14753                confp->pri.nsf = PRI_NSF_SDN;
14754             else if (!strcasecmp(v->value, "megacom"))
14755                confp->pri.nsf = PRI_NSF_MEGACOM;
14756             else if (!strcasecmp(v->value, "tollfreemegacom"))
14757                confp->pri.nsf = PRI_NSF_TOLL_FREE_MEGACOM;           
14758             else if (!strcasecmp(v->value, "accunet"))
14759                confp->pri.nsf = PRI_NSF_ACCUNET;
14760             else if (!strcasecmp(v->value, "none"))
14761                confp->pri.nsf = PRI_NSF_NONE;
14762             else {
14763                ast_log(LOG_WARNING, "Unknown network-specific facility '%s' at line %d.\n", v->value, v->lineno);
14764                confp->pri.nsf = PRI_NSF_NONE;
14765             }
14766          } else if (!strcasecmp(v->name, "priindication")) {
14767             if (!strcasecmp(v->value, "outofband"))
14768                confp->chan.priindication_oob = 1;
14769             else if (!strcasecmp(v->value, "inband"))
14770                confp->chan.priindication_oob = 0;
14771             else
14772                ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d.\n",
14773                   v->value, v->lineno);
14774          } else if (!strcasecmp(v->name, "priexclusive")) {
14775             confp->chan.priexclusive = ast_true(v->value);
14776          } else if (!strcasecmp(v->name, "internationalprefix")) {
14777             ast_copy_string(confp->pri.internationalprefix, v->value, sizeof(confp->pri.internationalprefix));
14778          } else if (!strcasecmp(v->name, "nationalprefix")) {
14779             ast_copy_string(confp->pri.nationalprefix, v->value, sizeof(confp->pri.nationalprefix));
14780          } else if (!strcasecmp(v->name, "localprefix")) {
14781             ast_copy_string(confp->pri.localprefix, v->value, sizeof(confp->pri.localprefix));
14782          } else if (!strcasecmp(v->name, "privateprefix")) {
14783             ast_copy_string(confp->pri.privateprefix, v->value, sizeof(confp->pri.privateprefix));
14784          } else if (!strcasecmp(v->name, "unknownprefix")) {
14785             ast_copy_string(confp->pri.unknownprefix, v->value, sizeof(confp->pri.unknownprefix));
14786          } else if (!strcasecmp(v->name, "resetinterval")) {
14787             if (!strcasecmp(v->value, "never"))
14788                confp->pri.resetinterval = -1;
14789             else if (atoi(v->value) >= 60)
14790                confp->pri.resetinterval = atoi(v->value);
14791             else
14792                ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
14793                   v->value, v->lineno);
14794          } else if (!strcasecmp(v->name, "minunused")) {
14795             confp->pri.minunused = atoi(v->value);
14796          } else if (!strcasecmp(v->name, "minidle")) {
14797             confp->pri.minidle = atoi(v->value); 
14798          } else if (!strcasecmp(v->name, "idleext")) {
14799             ast_copy_string(confp->pri.idleext, v->value, sizeof(confp->pri.idleext));
14800          } else if (!strcasecmp(v->name, "idledial")) {
14801             ast_copy_string(confp->pri.idledial, v->value, sizeof(confp->pri.idledial));
14802          } else if (!strcasecmp(v->name, "overlapdial")) {
14803             if (ast_true(v->value)) {
14804                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
14805             } else if (!strcasecmp(v->value, "incoming")) {
14806                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_INCOMING;
14807             } else if (!strcasecmp(v->value, "outgoing")) {
14808                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_OUTGOING;
14809             } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) {
14810                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
14811             } else {
14812                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_NONE;
14813             }
14814 #ifdef HAVE_PRI_INBANDDISCONNECT
14815          } else if (!strcasecmp(v->name, "inbanddisconnect")) {
14816             confp->pri.inbanddisconnect = ast_true(v->value);
14817 #endif
14818          } else if (!strcasecmp(v->name, "pritimer")) {
14819 #ifdef PRI_GETSET_TIMERS
14820             char tmp[20], *timerc, *c = tmp;
14821             int timer, timeridx;
14822             ast_copy_string(tmp, v->value, sizeof(tmp));
14823             timerc = strsep(&c, ",");
14824             if (timerc) {
14825                timer = atoi(c);
14826                if (!timer)
14827                   ast_log(LOG_WARNING, "'%s' is not a valid value for an ISDN timer at line %d.\n", timerc, v->lineno);
14828                else {
14829                   if ((timeridx = pri_timer2idx(timerc)) >= 0)
14830                      pritimers[timeridx] = timer;
14831                   else
14832                      ast_log(LOG_WARNING, "'%s' is not a valid ISDN timer at line %d.\n", timerc, v->lineno);
14833                }
14834             } else
14835                ast_log(LOG_WARNING, "'%s' is not a valid ISDN timer configuration string at line %d.\n", v->value, v->lineno);
14836 
14837          } else if (!strcasecmp(v->name, "facilityenable")) {
14838             confp->pri.facilityenable = ast_true(v->value);
14839 #endif /* PRI_GETSET_TIMERS */
14840 #endif /* HAVE_PRI */
14841 #ifdef HAVE_SS7
14842          } else if (!strcasecmp(v->name, "ss7type")) {
14843             if (!strcasecmp(v->value, "itu")) {
14844                cur_ss7type = SS7_ITU;
14845             } else if (!strcasecmp(v->value, "ansi")) {
14846                cur_ss7type = SS7_ANSI;
14847             } else
14848                ast_log(LOG_WARNING, "'%s' is an unknown ss7 switch type at line %d.!\n", v->value, v->lineno);
14849          } else if (!strcasecmp(v->name, "linkset")) {
14850             cur_linkset = atoi(v->value);
14851          } else if (!strcasecmp(v->name, "pointcode")) {
14852             cur_pointcode = parse_pointcode(v->value);
14853          } else if (!strcasecmp(v->name, "adjpointcode")) {
14854             cur_adjpointcode = parse_pointcode(v->value);
14855          } else if (!strcasecmp(v->name, "defaultdpc")) {
14856             cur_defaultdpc = parse_pointcode(v->value);
14857          } else if (!strcasecmp(v->name, "cicbeginswith")) {
14858             cur_cicbeginswith = atoi(v->value);
14859          } else if (!strcasecmp(v->name, "networkindicator")) {
14860             if (!strcasecmp(v->value, "national"))
14861                cur_networkindicator = SS7_NI_NAT;
14862             else if (!strcasecmp(v->value, "national_spare"))
14863                cur_networkindicator = SS7_NI_NAT_SPARE;
14864             else if (!strcasecmp(v->value, "international"))
14865                cur_networkindicator = SS7_NI_INT;
14866             else if (!strcasecmp(v->value, "international_spare"))
14867                cur_networkindicator = SS7_NI_INT_SPARE;
14868             else
14869                cur_networkindicator = -1;
14870          } else if (!strcasecmp(v->name, "ss7_internationalprefix")) {
14871             ast_copy_string(confp->ss7.internationalprefix, v->value, sizeof(confp->ss7.internationalprefix));
14872          } else if (!strcasecmp(v->name, "ss7_nationalprefix")) {
14873             ast_copy_string(confp->ss7.nationalprefix, v->value, sizeof(confp->ss7.nationalprefix));
14874          } else if (!strcasecmp(v->name, "ss7_subscriberprefix")) {
14875             ast_copy_string(confp->ss7.subscriberprefix, v->value, sizeof(confp->ss7.subscriberprefix));
14876          } else if (!strcasecmp(v->name, "ss7_unknownprefix")) {
14877             ast_copy_string(confp->ss7.unknownprefix, v->value, sizeof(confp->ss7.unknownprefix));
14878          } else if (!strcasecmp(v->name, "ss7_called_nai")) {
14879             if (!strcasecmp(v->value, "national")) {
14880                confp->ss7.called_nai = SS7_NAI_NATIONAL;
14881             } else if (!strcasecmp(v->value, "international")) {
14882                confp->ss7.called_nai = SS7_NAI_INTERNATIONAL;
14883             } else if (!strcasecmp(v->value, "subscriber")) {
14884                confp->ss7.called_nai = SS7_NAI_SUBSCRIBER;
14885             } else if (!strcasecmp(v->value, "dynamic")) {
14886                confp->ss7.called_nai = SS7_NAI_DYNAMIC;
14887             } else {
14888                ast_log(LOG_WARNING, "Unknown SS7 called_nai '%s' at line %d.\n", v->value, v->lineno);
14889             }
14890          } else if (!strcasecmp(v->name, "ss7_calling_nai")) {
14891             if (!strcasecmp(v->value, "national")) {
14892                confp->ss7.calling_nai = SS7_NAI_NATIONAL;
14893             } else if (!strcasecmp(v->value, "international")) {
14894                confp->ss7.calling_nai = SS7_NAI_INTERNATIONAL;
14895             } else if (!strcasecmp(v->value, "subscriber")) {
14896                confp->ss7.calling_nai = SS7_NAI_SUBSCRIBER;
14897             } else if (!strcasecmp(v->value, "dynamic")) {
14898                confp->ss7.calling_nai = SS7_NAI_DYNAMIC;
14899             } else {
14900                ast_log(LOG_WARNING, "Unknown SS7 calling_nai '%s' at line %d.\n", v->value, v->lineno);
14901             }
14902          } else if (!strcasecmp(v->name, "sigchan")) {
14903             int sigchan, res;
14904             sigchan = atoi(v->value);
14905             res = linkset_addsigchan(sigchan);
14906             if (res < 0)
14907                return -1;
14908 
14909          } else if (!strcasecmp(v->name, "ss7_explicitacm")) {
14910             struct dahdi_ss7 *link;
14911             link = ss7_resolve_linkset(cur_linkset);
14912             if (!link) {
14913                ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
14914                return -1;
14915             }
14916             if (ast_true(v->value))
14917                link->flags |= LINKSET_FLAG_EXPLICITACM;
14918 
14919 #endif /* HAVE_SS7 */
14920          } else if (!strcasecmp(v->name, "cadence")) {
14921             /* setup to scan our argument */
14922             int element_count, c[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
14923             int i;
14924             struct dahdi_ring_cadence new_cadence;
14925             int cid_location = -1;
14926             int firstcadencepos = 0;
14927             char original_args[80];
14928             int cadence_is_ok = 1;
14929 
14930             ast_copy_string(original_args, v->value, sizeof(original_args));
14931             /* 16 cadences allowed (8 pairs) */
14932             element_count = sscanf(v->value, "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d", &c[0], &c[1], &c[2], &c[3], &c[4], &c[5], &c[6], &c[7], &c[8], &c[9], &c[10], &c[11], &c[12], &c[13], &c[14], &c[15]);
14933    
14934             /* Cadence must be even (on/off) */
14935             if (element_count % 2 == 1) {
14936                ast_log(LOG_ERROR, "Must be a silence duration for each ring duration: %s at line %d.\n", original_args, v->lineno);
14937                cadence_is_ok = 0;
14938             }
14939    
14940             /* Ring cadences cannot be negative */
14941             for (i = 0; i < element_count; i++) {
14942                if (c[i] == 0) {
14943                   ast_log(LOG_ERROR, "Ring or silence duration cannot be zero: %s at line %d.\n", original_args, v->lineno);
14944                   cadence_is_ok = 0;
14945                   break;
14946                } else if (c[i] < 0) {
14947                   if (i % 2 == 1) {
14948                      /* Silence duration, negative possibly okay */
14949                      if (cid_location == -1) {
14950                         cid_location = i;
14951                         c[i] *= -1;
14952                      } else {
14953                         ast_log(LOG_ERROR, "CID location specified twice: %s at line %d.\n", original_args, v->lineno);
14954                         cadence_is_ok = 0;
14955                         break;
14956                      }
14957                   } else {
14958                      if (firstcadencepos == 0) {
14959                         firstcadencepos = i; /* only recorded to avoid duplicate specification */
14960                                  /* duration will be passed negative to the DAHDI driver */
14961                      } else {
14962                          ast_log(LOG_ERROR, "First cadence position specified twice: %s at line %d.\n", original_args, v->lineno);
14963                         cadence_is_ok = 0;
14964                         break;
14965                      }
14966                   }
14967                }
14968             }
14969    
14970             /* Substitute our scanned cadence */
14971             for (i = 0; i < 16; i++) {
14972                new_cadence.ringcadence[i] = c[i];
14973             }
14974    
14975             if (cadence_is_ok) {
14976                /* ---we scanned it without getting annoyed; now some sanity checks--- */
14977                if (element_count < 2) {
14978                   ast_log(LOG_ERROR, "Minimum cadence is ring,pause: %s at line %d.\n", original_args, v->lineno);
14979                } else {
14980                   if (cid_location == -1) {
14981                      /* user didn't say; default to first pause */
14982                      cid_location = 1;
14983                   } else {
14984                      /* convert element_index to cidrings value */
14985                      cid_location = (cid_location + 1) / 2;
14986                   }
14987                   /* ---we like their cadence; try to install it--- */
14988                   if (!user_has_defined_cadences++)
14989                      /* this is the first user-defined cadence; clear the default user cadences */
14990                      num_cadence = 0;
14991                   if ((num_cadence+1) >= NUM_CADENCE_MAX)
14992                      ast_log(LOG_ERROR, "Already %d cadences; can't add another: %s at line %d.\n", NUM_CADENCE_MAX, original_args, v->lineno);
14993                   else {
14994                      cadences[num_cadence] = new_cadence;
14995                      cidrings[num_cadence++] = cid_location;
14996                      ast_verb(3, "cadence 'r%d' added: %s\n",num_cadence,original_args);
14997                   }
14998                }
14999             }
15000          } else if (!strcasecmp(v->name, "ringtimeout")) {
15001             ringt_base = (atoi(v->value) * 8) / READ_SIZE;
15002          } else if (!strcasecmp(v->name, "prewink")) {
15003             confp->timing.prewinktime = atoi(v->value);
15004          } else if (!strcasecmp(v->name, "preflash")) {
15005             confp->timing.preflashtime = atoi(v->value);
15006          } else if (!strcasecmp(v->name, "wink")) {
15007             confp->timing.winktime = atoi(v->value);
15008          } else if (!strcasecmp(v->name, "flash")) {
15009             confp->timing.flashtime = atoi(v->value);
15010          } else if (!strcasecmp(v->name, "start")) {
15011             confp->timing.starttime = atoi(v->value);
15012          } else if (!strcasecmp(v->name, "rxwink")) {
15013             confp->timing.rxwinktime = atoi(v->value);
15014          } else if (!strcasecmp(v->name, "rxflash")) {
15015             confp->timing.rxflashtime = atoi(v->value);
15016          } else if (!strcasecmp(v->name, "debounce")) {
15017             confp->timing.debouncetime = atoi(v->value);
15018          } else if (!strcasecmp(v->name, "toneduration")) {
15019             int toneduration;
15020             int ctlfd;
15021             int res;
15022             struct dahdi_dialparams dps;
15023 
15024             ctlfd = open("/dev/dahdi/ctl", O_RDWR);
15025             if (ctlfd == -1) {
15026                ast_log(LOG_ERROR, "Unable to open /dev/dahdi/ctl to set toneduration at line %d.\n", v->lineno);
15027                return -1;
15028             }
15029 
15030             toneduration = atoi(v->value);
15031             if (toneduration > -1) {
15032                memset(&dps, 0, sizeof(dps));
15033 
15034                dps.dtmf_tonelen = dps.mfv1_tonelen = toneduration;
15035                res = ioctl(ctlfd, DAHDI_SET_DIALPARAMS, &dps);
15036                if (res < 0) {
15037                   ast_log(LOG_ERROR, "Invalid tone duration: %d ms at line %d: %s\n", toneduration, v->lineno, strerror(errno));
15038                   return -1;
15039                }
15040             }
15041             close(ctlfd);
15042          } else if (!strcasecmp(v->name, "defaultcic")) {
15043             ast_copy_string(defaultcic, v->value, sizeof(defaultcic));
15044          } else if (!strcasecmp(v->name, "defaultozz")) {
15045             ast_copy_string(defaultozz, v->value, sizeof(defaultozz));
15046          } else if (!strcasecmp(v->name, "mwilevel")) {
15047             mwilevel = atoi(v->value);
15048          }
15049       } else if (!(options & PROC_DAHDI_OPT_NOWARN) )
15050          ast_log(LOG_WARNING, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
15051    }
15052    if (dahdichan[0]) { 
15053       /* The user has set 'dahdichan' */
15054       /*< \todo pass proper line number instead of 0 */
15055       if (build_channels(confp, 0, dahdichan, reload, 0, &found_pseudo)) {
15056          return -1;
15057       }
15058    }
15059    /*< \todo why check for the pseudo in the per-channel section.
15060     * Any actual use for manual setup of the pseudo channel? */
15061    if (!found_pseudo && reload == 0) {
15062       /* use the default configuration for a channel, so
15063          that any settings from real configured channels
15064          don't "leak" into the pseudo channel config
15065       */
15066       struct dahdi_chan_conf conf = dahdi_chan_conf_default();
15067 
15068       tmp = mkintf(CHAN_PSEUDO, &conf, NULL, reload);
15069 
15070       if (tmp) {
15071          ast_verb(3, "Automatically generated pseudo channel\n");
15072       } else {
15073          ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
15074       }
15075    }
15076    return 0;
15077 }
15078       
15079 static int setup_dahdi(int reload)
15080 {
15081    struct ast_config *cfg, *ucfg;
15082    struct ast_variable *v;
15083    struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
15084    struct dahdi_chan_conf conf;
15085    struct ast_flags config_flags = { reload == 1 ? CONFIG_FLAG_FILEUNCHANGED : 0 };
15086    const char *cat;
15087    int res;
15088 
15089 #ifdef HAVE_PRI
15090    char *c;
15091    int spanno;
15092    int i;
15093    int logicalspan;
15094    int trunkgroup;
15095    int dchannels[NUM_DCHANS];
15096 #endif
15097 
15098    cfg = ast_config_load(config, config_flags);
15099 
15100    /* Error if we have no config file */
15101    if (!cfg) {
15102       ast_log(LOG_ERROR, "Unable to load config %s\n", config);
15103       return 0;
15104    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
15105       ucfg = ast_config_load("users.conf", config_flags);
15106       if (ucfg == CONFIG_STATUS_FILEUNCHANGED)
15107          return 0;
15108       ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
15109       cfg = ast_config_load(config, config_flags);
15110    } else {
15111       ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
15112       ucfg = ast_config_load("users.conf", config_flags);
15113    }
15114 
15115    /* It's a little silly to lock it, but we mind as well just to be sure */
15116    ast_mutex_lock(&iflock);
15117 #ifdef HAVE_PRI
15118    if (reload != 1) {
15119       /* Process trunkgroups first */
15120       v = ast_variable_browse(cfg, "trunkgroups");
15121       while (v) {
15122          if (!strcasecmp(v->name, "trunkgroup")) {
15123             trunkgroup = atoi(v->value);
15124             if (trunkgroup > 0) {
15125                if ((c = strchr(v->value, ','))) {
15126                   i = 0;
15127                   memset(dchannels, 0, sizeof(dchannels));
15128                   while (c && (i < NUM_DCHANS)) {
15129                      dchannels[i] = atoi(c + 1);
15130                      if (dchannels[i] < 0) {
15131                         ast_log(LOG_WARNING, "D-channel for trunk group %d must be a postiive number at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
15132                      } else
15133                         i++;
15134                      c = strchr(c + 1, ',');
15135                   }
15136                   if (i) {
15137                      if (pri_create_trunkgroup(trunkgroup, dchannels)) {
15138                         ast_log(LOG_WARNING, "Unable to create trunk group %d with Primary D-channel %d at line %d of chan_dahdi.conf\n", trunkgroup, dchannels[0], v->lineno);
15139                   } else
15140                         ast_verb(2, "Created trunk group %d with Primary D-channel %d and %d backup%s\n", trunkgroup, dchannels[0], i - 1, (i == 1) ? "" : "s");
15141                   } else
15142                      ast_log(LOG_WARNING, "Trunk group %d lacks any valid D-channels at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
15143                } else
15144                   ast_log(LOG_WARNING, "Trunk group %d lacks a primary D-channel at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
15145             } else
15146                ast_log(LOG_WARNING, "Trunk group identifier must be a positive integer at line %d of chan_dahdi.conf\n", v->lineno);
15147          } else if (!strcasecmp(v->name, "spanmap")) {
15148             spanno = atoi(v->value);
15149             if (spanno > 0) {
15150                if ((c = strchr(v->value, ','))) {
15151                   trunkgroup = atoi(c + 1);
15152                   if (trunkgroup > 0) {
15153                      if ((c = strchr(c + 1, ','))) 
15154                         logicalspan = atoi(c + 1);
15155                      else
15156                         logicalspan = 0;
15157                      if (logicalspan >= 0) {
15158                         if (pri_create_spanmap(spanno - 1, trunkgroup, logicalspan)) {
15159                            ast_log(LOG_WARNING, "Failed to map span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
15160                      } else
15161                            ast_verb(2, "Mapped span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
15162                      } else
15163                         ast_log(LOG_WARNING, "Logical span must be a postive number, or '0' (for unspecified) at line %d of chan_dahdi.conf\n", v->lineno);
15164                   } else
15165                      ast_log(LOG_WARNING, "Trunk group must be a postive number at line %d of chan_dahdi.conf\n", v->lineno);
15166                } else
15167                   ast_log(LOG_WARNING, "Missing trunk group for span map at line %d of chan_dahdi.conf\n", v->lineno);
15168             } else
15169                ast_log(LOG_WARNING, "Span number must be a postive integer at line %d of chan_dahdi.conf\n", v->lineno);
15170          } else {
15171             ast_log(LOG_NOTICE, "Ignoring unknown keyword '%s' in trunkgroups\n", v->name);
15172          }
15173          v = v->next;
15174       }
15175    }
15176 #endif
15177    
15178    /* Copy the default jb config over global_jbconf */
15179    memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
15180 
15181    mwimonitornotify[0] = '\0';
15182 
15183    v = ast_variable_browse(cfg, "channels");
15184    if ((res = process_dahdi(&base_conf, "", v, reload, 0))) {
15185       ast_mutex_unlock(&iflock);
15186       ast_config_destroy(cfg);
15187       if (ucfg) {
15188          ast_config_destroy(ucfg);
15189       }
15190       return res;
15191    }
15192 
15193    /* Now get configuration from all normal sections in chan_dahdi.conf: */
15194    for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
15195       /* [channels] and [trunkgroups] are used. Let's also reserve
15196        * [globals] and [general] for future use
15197        */
15198       if (!strcasecmp(cat, "general") || 
15199           !strcasecmp(cat, "trunkgroups") ||
15200           !strcasecmp(cat, "globals") ||
15201           !strcasecmp(cat, "channels")) {
15202          continue;
15203       }
15204 
15205       memcpy(&conf, &base_conf, sizeof(conf));
15206 
15207       if ((res = process_dahdi(&conf, cat, ast_variable_browse(cfg, cat), reload, PROC_DAHDI_OPT_NOCHAN))) {
15208          ast_mutex_unlock(&iflock);
15209          ast_config_destroy(cfg);
15210          if (ucfg) {
15211             ast_config_destroy(cfg);
15212          }
15213          return res;
15214       }
15215    }
15216 
15217    ast_config_destroy(cfg);
15218 
15219    if (ucfg) {
15220       const char *chans;
15221 
15222       process_dahdi(&base_conf, "", ast_variable_browse(ucfg, "general"), 1, 0);
15223 
15224       for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
15225          if (!strcasecmp(cat, "general")) {
15226             continue;
15227          }
15228 
15229          chans = ast_variable_retrieve(ucfg, cat, "dahdichan");
15230 
15231          if (ast_strlen_zero(chans)) {
15232             continue;
15233          }
15234 
15235          memcpy(&conf, &base_conf, sizeof(conf));
15236 
15237          if ((res = process_dahdi(&conf, cat, ast_variable_browse(ucfg, cat), reload, PROC_DAHDI_OPT_NOCHAN | PROC_DAHDI_OPT_NOWARN))) {
15238             ast_config_destroy(ucfg);
15239             ast_mutex_unlock(&iflock);
15240             return res;
15241          }
15242       }
15243       ast_config_destroy(ucfg);
15244    }
15245    ast_mutex_unlock(&iflock);
15246 
15247 #ifdef HAVE_PRI
15248    if (reload != 1) {
15249       int x;
15250       for (x = 0; x < NUM_SPANS; x++) {
15251          if (pris[x].pvts[0]) {
15252             if (start_pri(pris + x)) {
15253                ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
15254                return -1;
15255             } else
15256                ast_verb(2, "Starting D-Channel on span %d\n", x + 1);
15257          }
15258       }
15259    }
15260 #endif
15261 #ifdef HAVE_SS7
15262    if (reload != 1) {
15263       int x;
15264       for (x = 0; x < NUM_SPANS; x++) {
15265          if (linksets[x].ss7) {
15266             if (ast_pthread_create(&linksets[x].master, NULL, ss7_linkset, &linksets[x])) {
15267                ast_log(LOG_ERROR, "Unable to start SS7 linkset on span %d\n", x + 1);
15268                return -1;
15269             } else
15270                ast_verb(2, "Starting SS7 linkset on span %d\n", x + 1);
15271          }
15272       }
15273    }
15274 #endif
15275    /* And start the monitor for the first time */
15276    restart_monitor();
15277    return 0;
15278 }
15279 
15280 static int load_module(void)
15281 {
15282    int res;
15283 #if defined(HAVE_PRI) || defined(HAVE_SS7)
15284    int y, i;
15285 #endif
15286 
15287 #ifdef HAVE_PRI
15288    memset(pris, 0, sizeof(pris));
15289    for (y = 0; y < NUM_SPANS; y++) {
15290       ast_mutex_init(&pris[y].lock);
15291       pris[y].offset = -1;
15292       pris[y].master = AST_PTHREADT_NULL;
15293       for (i = 0; i < NUM_DCHANS; i++)
15294          pris[y].fds[i] = -1;
15295    }
15296    pri_set_error(dahdi_pri_error);
15297    pri_set_message(dahdi_pri_message);
15298    ast_register_application(dahdi_send_keypad_facility_app, dahdi_send_keypad_facility_exec,
15299          dahdi_send_keypad_facility_synopsis, dahdi_send_keypad_facility_descrip);
15300 #endif
15301 #ifdef HAVE_SS7
15302    memset(linksets, 0, sizeof(linksets));
15303    for (y = 0; y < NUM_SPANS; y++) {
15304       ast_mutex_init(&linksets[y].lock);
15305       linksets[y].master = AST_PTHREADT_NULL;
15306       for (i = 0; i < NUM_DCHANS; i++)
15307          linksets[y].fds[i] = -1;
15308    }
15309    ss7_set_error(dahdi_ss7_error);
15310    ss7_set_message(dahdi_ss7_message);
15311 #endif /* HAVE_SS7 */
15312    res = setup_dahdi(0);
15313    /* Make sure we can register our DAHDI channel type */
15314    if (res)
15315       return AST_MODULE_LOAD_DECLINE;
15316    if (ast_channel_register(&dahdi_tech)) {
15317       ast_log(LOG_ERROR, "Unable to register channel class 'DAHDI'\n");
15318       __unload_module();
15319       return AST_MODULE_LOAD_FAILURE;
15320    }
15321 #ifdef HAVE_PRI
15322    ast_string_field_init(&inuse, 16);
15323    ast_string_field_set(&inuse, name, "GR-303InUse");
15324    ast_cli_register_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
15325 #endif   
15326 #ifdef HAVE_SS7
15327    ast_cli_register_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
15328 #endif
15329 
15330    ast_cli_register_multiple(dahdi_cli, ARRAY_LEN(dahdi_cli));
15331    
15332    memset(round_robin, 0, sizeof(round_robin));
15333    ast_manager_register( "DAHDITransfer", 0, action_transfer, "Transfer DAHDI Channel" );
15334    ast_manager_register( "DAHDIHangup", 0, action_transferhangup, "Hangup DAHDI Channel" );
15335    ast_manager_register( "DAHDIDialOffhook", 0, action_dahdidialoffhook, "Dial over DAHDI channel while offhook" );
15336    ast_manager_register( "DAHDIDNDon", 0, action_dahdidndon, "Toggle DAHDI channel Do Not Disturb status ON" );
15337    ast_manager_register( "DAHDIDNDoff", 0, action_dahdidndoff, "Toggle DAHDI channel Do Not Disturb status OFF" );
15338    ast_manager_register("DAHDIShowChannels", 0, action_dahdishowchannels, "Show status DAHDI channels");
15339    ast_manager_register("DAHDIRestart", 0, action_dahdirestart, "Fully Restart DAHDI channels (terminates calls)");
15340 
15341    ast_cond_init(&mwi_thread_complete, NULL);
15342    ast_cond_init(&ss_thread_complete, NULL);
15343 
15344    return res;
15345 }
15346 
15347 static int dahdi_sendtext(struct ast_channel *c, const char *text)
15348 {
15349 #define  END_SILENCE_LEN 400
15350 #define  HEADER_MS 50
15351 #define  TRAILER_MS 5
15352 #define  HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
15353 #define  ASCII_BYTES_PER_CHAR 80
15354 
15355    unsigned char *buf,*mybuf;
15356    struct dahdi_pvt *p = c->tech_pvt;
15357    struct pollfd fds[1];
15358    int size,res,fd,len,x;
15359    int bytes=0;
15360    /* Initial carrier (imaginary) */
15361    float cr = 1.0;
15362    float ci = 0.0;
15363    float scont = 0.0;
15364    int idx;
15365 
15366    idx = dahdi_get_index(c, p, 0);
15367    if (idx < 0) {
15368       ast_log(LOG_WARNING, "Huh?  I don't exist?\n");
15369       return -1;
15370    }
15371    if (!text[0]) return(0); /* if nothing to send, dont */
15372    if ((!p->tdd) && (!p->mate)) return(0);  /* if not in TDD mode, just return */
15373    if (p->mate) 
15374       buf = ast_malloc(((strlen(text) + 1) * ASCII_BYTES_PER_CHAR) + END_SILENCE_LEN + HEADER_LEN);
15375    else
15376       buf = ast_malloc(((strlen(text) + 1) * TDD_BYTES_PER_CHAR) + END_SILENCE_LEN);
15377    if (!buf)
15378       return -1;
15379    mybuf = buf;
15380    if (p->mate) {
15381       int codec = AST_LAW(p);
15382       for (x = 0; x < HEADER_MS; x++) {   /* 50 ms of Mark */
15383          PUT_CLID_MARKMS;
15384       }
15385       /* Put actual message */
15386       for (x = 0; text[x]; x++) {
15387          PUT_CLID(text[x]);
15388       }
15389       for (x = 0; x < TRAILER_MS; x++) {  /* 5 ms of Mark */
15390          PUT_CLID_MARKMS;
15391       }
15392       len = bytes;
15393       buf = mybuf;
15394    } else {
15395       len = tdd_generate(p->tdd, buf, text);
15396       if (len < 1) {
15397          ast_log(LOG_ERROR, "TDD generate (len %d) failed!!\n", (int)strlen(text));
15398          ast_free(mybuf);
15399          return -1;
15400       }
15401    }
15402    memset(buf + len, 0x7f, END_SILENCE_LEN);
15403    len += END_SILENCE_LEN;
15404    fd = p->subs[idx].dfd;
15405    while (len) {
15406       if (ast_check_hangup(c)) {
15407          ast_free(mybuf);
15408          return -1;
15409       }
15410       size = len;
15411       if (size > READ_SIZE)
15412          size = READ_SIZE;
15413       fds[0].fd = fd;
15414       fds[0].events = POLLOUT | POLLPRI;
15415       fds[0].revents = 0;
15416       res = poll(fds, 1, -1);
15417       if (!res) {
15418          ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
15419          continue;
15420       }
15421         /* if got exception */
15422       if (fds[0].revents & POLLPRI) {
15423          ast_free(mybuf);
15424          return -1;
15425       }
15426       if (!(fds[0].revents & POLLOUT)) {
15427          ast_debug(1, "write fd not ready on channel %d\n", p->channel);
15428          continue;
15429       }
15430       res = write(fd, buf, size);
15431       if (res != size) {
15432          if (res == -1) {
15433             ast_free(mybuf);
15434             return -1;
15435          }
15436          ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
15437          break;
15438       }
15439       len -= size;
15440       buf += size;
15441    }
15442    ast_free(mybuf);
15443    return(0);
15444 }
15445 
15446 
15447 static int reload(void)
15448 {
15449    int res = 0;
15450 
15451    res = setup_dahdi(1);
15452    if (res) {
15453       ast_log(LOG_WARNING, "Reload of chan_dahdi.so is unsuccessful!\n");
15454       return -1;
15455    }
15456    return 0;
15457 }
15458 
15459 /* This is a workaround so that menuselect displays a proper description
15460  * AST_MODULE_INFO(, , "DAHDI Telephony"
15461  */
15462 
15463 #ifdef HAVE_PRI
15464 #ifdef HAVE_SS7
15465 #define tdesc "DAHDI Telephony w/PRI & SS7"
15466 #else
15467 #define tdesc "DAHDI Telephony w/PRI"
15468 #endif
15469 #else
15470 #ifdef HAVE_SS7
15471 #define tdesc "DAHDI Telephony w/SS7"
15472 #else
15473 #define tdesc "DAHDI Telephony"
15474 #endif
15475 #endif
15476 
15477 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
15478       .load = load_module,
15479       .unload = unload_module,
15480       .reload = reload,
15481           );
15482 
15483 

Generated on Fri Jun 19 12:09:34 2009 for Asterisk - the Open Source PBX by  doxygen 1.4.7