Thu Apr 8 01:20:54 2010

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: 250483 $")
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    .target_extra = -1,
00125 };
00126 static struct ast_jb_conf global_jbconf;
00127 
00128 /* define this to send PRI user-user information elements */
00129 #undef SUPPORT_USERUSER
00130 
00131 /*! 
00132  * \note Define ZHONE_HACK to cause us to go off hook and then back on hook when
00133  * the user hangs up to reset the state machine so ring works properly.
00134  * This is used to be able to support kewlstart by putting the zhone in
00135  * groundstart mode since their forward disconnect supervision is entirely
00136  * broken even though their documentation says it isn't and their support
00137  * is entirely unwilling to provide any assistance with their channel banks
00138  * even though their web site says they support their products for life.
00139  */
00140 /* #define ZHONE_HACK */
00141 
00142 /*! \note
00143  * Define if you want to check the hook state for an FXO (FXS signalled) interface
00144  * before dialing on it.  Certain FXO interfaces always think they're out of
00145  * service with this method however.
00146  */
00147 /* #define DAHDI_CHECK_HOOKSTATE */
00148 
00149 /*! \brief Typically, how many rings before we should send Caller*ID */
00150 #define DEFAULT_CIDRINGS 1
00151 
00152 #define CHANNEL_PSEUDO -12
00153 
00154 #define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? AST_FORMAT_ALAW : AST_FORMAT_ULAW)
00155 
00156 
00157 /*! \brief Signaling types that need to use MF detection should be placed in this macro */
00158 #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)) 
00159 
00160 static const char tdesc[] = "DAHDI Telephony Driver"
00161 #ifdef HAVE_PRI
00162                " w/PRI"
00163 #endif
00164 #ifdef HAVE_SS7
00165           " w/SS7"
00166 #endif
00167 ;
00168 
00169 static const char config[] = "chan_dahdi.conf";
00170 
00171 #define SIG_EM    DAHDI_SIG_EM
00172 #define SIG_EMWINK   (0x0100000 | DAHDI_SIG_EM)
00173 #define SIG_FEATD (0x0200000 | DAHDI_SIG_EM)
00174 #define  SIG_FEATDMF (0x0400000 | DAHDI_SIG_EM)
00175 #define  SIG_FEATB   (0x0800000 | DAHDI_SIG_EM)
00176 #define  SIG_E911 (0x1000000 | DAHDI_SIG_EM)
00177 #define  SIG_FEATDMF_TA (0x2000000 | DAHDI_SIG_EM)
00178 #define  SIG_FGC_CAMA   (0x4000000 | DAHDI_SIG_EM)
00179 #define  SIG_FGC_CAMAMF (0x8000000 | DAHDI_SIG_EM)
00180 #define SIG_FXSLS DAHDI_SIG_FXSLS
00181 #define SIG_FXSGS DAHDI_SIG_FXSGS
00182 #define SIG_FXSKS DAHDI_SIG_FXSKS
00183 #define SIG_FXOLS DAHDI_SIG_FXOLS
00184 #define SIG_FXOGS DAHDI_SIG_FXOGS
00185 #define SIG_FXOKS DAHDI_SIG_FXOKS
00186 #define SIG_PRI      DAHDI_SIG_CLEAR
00187 #define SIG_BRI      (0x2000000 | DAHDI_SIG_CLEAR)
00188 #define SIG_BRI_PTMP (0X4000000 | DAHDI_SIG_CLEAR)
00189 #define SIG_SS7      (0x1000000 | DAHDI_SIG_CLEAR)
00190 #define  SIG_SF      DAHDI_SIG_SF
00191 #define SIG_SFWINK   (0x0100000 | DAHDI_SIG_SF)
00192 #define SIG_SF_FEATD (0x0200000 | DAHDI_SIG_SF)
00193 #define  SIG_SF_FEATDMF (0x0400000 | DAHDI_SIG_SF)
00194 #define  SIG_SF_FEATB   (0x0800000 | DAHDI_SIG_SF)
00195 #define SIG_EM_E1 DAHDI_SIG_EM_E1
00196 #define SIG_GR303FXOKS  (0x0100000 | DAHDI_SIG_FXOKS)
00197 #define SIG_GR303FXSKS  (0x0100000 | DAHDI_SIG_FXSKS)
00198 
00199 #ifdef LOTS_OF_SPANS
00200 #define NUM_SPANS DAHDI_MAX_SPANS
00201 #else
00202 #define NUM_SPANS       32
00203 #endif
00204 #define NUM_DCHANS      4  /*!< No more than 4 d-channels */
00205 #define MAX_CHANNELS 672      /*!< No more than a DS3 per trunk group */
00206 
00207 #define CHAN_PSEUDO  -2
00208 
00209 #define DCHAN_PROVISIONED (1 << 0)
00210 #define DCHAN_NOTINALARM  (1 << 1)
00211 #define DCHAN_UP          (1 << 2)
00212 
00213 #define DCHAN_AVAILABLE (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP)
00214 
00215 /* Overlap dialing option types */
00216 #define DAHDI_OVERLAPDIAL_NONE 0
00217 #define DAHDI_OVERLAPDIAL_OUTGOING 1
00218 #define DAHDI_OVERLAPDIAL_INCOMING 2
00219 #define DAHDI_OVERLAPDIAL_BOTH (DAHDI_OVERLAPDIAL_INCOMING|DAHDI_OVERLAPDIAL_OUTGOING)
00220 
00221 
00222 #define CALLPROGRESS_PROGRESS    1
00223 #define CALLPROGRESS_FAX_OUTGOING   2
00224 #define CALLPROGRESS_FAX_INCOMING   4
00225 #define CALLPROGRESS_FAX      (CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
00226 
00227 static char defaultcic[64] = "";
00228 static char defaultozz[64] = "";
00229 
00230 static char parkinglot[AST_MAX_EXTENSION] = "";    /*!< Default parking lot for this channel */
00231 
00232 /*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */
00233 static char mwimonitornotify[PATH_MAX] = "";
00234 static int  mwisend_rpas = 0;
00235 
00236 static char progzone[10] = "";
00237 
00238 static int usedistinctiveringdetection = 0;
00239 static int distinctiveringaftercid = 0;
00240 
00241 static int numbufs = 4;
00242 
00243 static int mwilevel = 512;
00244 
00245 #ifdef HAVE_PRI
00246 static struct ast_channel inuse;
00247 #ifdef PRI_GETSET_TIMERS
00248 static int pritimers[PRI_MAX_TIMERS];
00249 #endif
00250 static int pridebugfd = -1;
00251 static char pridebugfilename[1024] = "";
00252 #endif
00253 
00254 /*! \brief Wait up to 16 seconds for first digit (FXO logic) */
00255 static int firstdigittimeout = 16000;
00256 
00257 /*! \brief How long to wait for following digits (FXO logic) */
00258 static int gendigittimeout = 8000;
00259 
00260 /*! \brief How long to wait for an extra digit, if there is an ambiguous match */
00261 static int matchdigittimeout = 3000;
00262 
00263 /*! \brief Protect the interface list (of dahdi_pvt's) */
00264 AST_MUTEX_DEFINE_STATIC(iflock);
00265 
00266 
00267 static int ifcount = 0;
00268 
00269 #ifdef HAVE_PRI
00270 AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
00271 #endif
00272 
00273 /*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
00274    when it's doing something critical. */
00275 AST_MUTEX_DEFINE_STATIC(monlock);
00276 
00277 /*! \brief This is the thread for the monitor which checks for input on the channels
00278    which are not currently in use. */
00279 static pthread_t monitor_thread = AST_PTHREADT_NULL;
00280 static ast_cond_t mwi_thread_complete;
00281 static ast_cond_t ss_thread_complete;
00282 AST_MUTEX_DEFINE_STATIC(mwi_thread_lock);
00283 AST_MUTEX_DEFINE_STATIC(ss_thread_lock);
00284 AST_MUTEX_DEFINE_STATIC(restart_lock);
00285 static int mwi_thread_count = 0;
00286 static int ss_thread_count = 0;
00287 static int num_restart_pending = 0;
00288 
00289 static int restart_monitor(void);
00290 
00291 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);
00292 
00293 static int dahdi_sendtext(struct ast_channel *c, const char *text);
00294 
00295 static void mwi_event_cb(const struct ast_event *event, void *userdata)
00296 {
00297    /* This module does not handle MWI in an event-based manner.  However, it
00298     * subscribes to MWI for each mailbox that is configured so that the core
00299     * knows that we care about it.  Then, chan_dahdi will get the MWI from the
00300     * event cache instead of checking the mailbox directly. */
00301 }
00302 
00303 /*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
00304 static inline int dahdi_get_event(int fd)
00305 {
00306    int j;
00307    if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
00308       return -1;
00309    return j;
00310 }
00311 
00312 /*! \brief Avoid the silly dahdi_waitevent which ignores a bunch of events */
00313 static inline int dahdi_wait_event(int fd)
00314 {
00315    int i, j = 0;
00316    i = DAHDI_IOMUX_SIGEVENT;
00317    if (ioctl(fd, DAHDI_IOMUX, &i) == -1)
00318       return -1;
00319    if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
00320       return -1;
00321    return j;
00322 }
00323 
00324 /*! Chunk size to read -- we use 20ms chunks to make things happy. */
00325 #define READ_SIZE 160
00326 
00327 #define MASK_AVAIL      (1 << 0) /*!< Channel available for PRI use */
00328 #define MASK_INUSE      (1 << 1) /*!< Channel currently in use */
00329 
00330 #define CALLWAITING_SILENT_SAMPLES  ( (300 * 8) / READ_SIZE) /*!< 300 ms */
00331 #define CALLWAITING_REPEAT_SAMPLES  ( (10000 * 8) / READ_SIZE) /*!< 10,000 ms */
00332 #define CIDCW_EXPIRE_SAMPLES     ( (500 * 8) / READ_SIZE) /*!< 500 ms */
00333 #define MIN_MS_SINCE_FLASH       ( (2000) )  /*!< 2000 ms */
00334 #define DEFAULT_RINGT            ( (8000 * 8) / READ_SIZE) /*!< 8,000 ms */
00335 
00336 struct dahdi_pvt;
00337 
00338 /*!
00339  * \brief Configured ring timeout base.
00340  * \note Value computed from "ringtimeout" read in from chan_dahdi.conf if it exists.
00341  */
00342 static int ringt_base = DEFAULT_RINGT;
00343 
00344 #ifdef HAVE_SS7
00345 
00346 #define LINKSTATE_INALARM  (1 << 0)
00347 #define LINKSTATE_STARTING (1 << 1)
00348 #define LINKSTATE_UP    (1 << 2)
00349 #define LINKSTATE_DOWN     (1 << 3)
00350 
00351 #define SS7_NAI_DYNAMIC    -1
00352 
00353 #define LINKSET_FLAG_EXPLICITACM (1 << 0)
00354 
00355 struct dahdi_ss7 {
00356    pthread_t master;                /*!< Thread of master */
00357    ast_mutex_t lock;
00358    int fds[NUM_DCHANS];
00359    int numsigchans;
00360    int linkstate[NUM_DCHANS];
00361    int numchans;
00362    int type;
00363    enum {
00364       LINKSET_STATE_DOWN = 0,
00365       LINKSET_STATE_UP
00366    } state;
00367    char called_nai;                 /*!< Called Nature of Address Indicator */
00368    char calling_nai;                /*!< Calling Nature of Address Indicator */
00369    char internationalprefix[10];             /*!< country access code ('00' for european dialplans) */
00370    char nationalprefix[10];               /*!< area access code ('0' for european dialplans) */
00371    char subscriberprefix[20];             /*!< area access code + area code ('0'+area code for european dialplans) */
00372    char unknownprefix[20];                /*!< for unknown dialplans */
00373    struct ss7 *ss7;
00374    struct dahdi_pvt *pvts[MAX_CHANNELS];           /*!< Member channel pvt structs */
00375    int flags;                    /*!< Linkset flags */
00376 };
00377 
00378 static struct dahdi_ss7 linksets[NUM_SPANS];
00379 
00380 static int cur_ss7type = -1;
00381 static int cur_linkset = -1;
00382 static int cur_pointcode = -1;
00383 static int cur_cicbeginswith = -1;
00384 static int cur_adjpointcode = -1;
00385 static int cur_networkindicator = -1;
00386 static int cur_defaultdpc = -1;
00387 #endif /* HAVE_SS7 */
00388 
00389 #ifdef HAVE_PRI
00390 
00391 #define PVT_TO_CHANNEL(p) (((p)->prioffset) | ((p)->logicalspan << 8) | (p->pri->mastertrunkgroup ? 0x10000 : 0))
00392 #define PRI_CHANNEL(p) ((p) & 0xff)
00393 #define PRI_SPAN(p) (((p) >> 8) & 0xff)
00394 #define PRI_EXPLICIT(p) (((p) >> 16) & 0x01)
00395 
00396 struct dahdi_pri {
00397    pthread_t master;                /*!< Thread of master */
00398    ast_mutex_t lock;                /*!< Mutex */
00399    char idleext[AST_MAX_EXTENSION];          /*!< Where to idle extra calls */
00400    char idlecontext[AST_MAX_CONTEXT];           /*!< What context to use for idle */
00401    char idledial[AST_MAX_EXTENSION];            /*!< What to dial before dumping */
00402    int minunused;                   /*!< Min # of channels to keep empty */
00403    int minidle;                     /*!< Min # of "idling" calls to keep active */
00404    int nodetype;                    /*!< Node type */
00405    int switchtype;                     /*!< Type of switch to emulate */
00406    int nsf;                   /*!< Network-Specific Facilities */
00407    int dialplan;                    /*!< Dialing plan */
00408    int localdialplan;                  /*!< Local dialing plan */
00409    char internationalprefix[10];             /*!< country access code ('00' for european dialplans) */
00410    char nationalprefix[10];               /*!< area access code ('0' for european dialplans) */
00411    char localprefix[20];                  /*!< area access code + area code ('0'+area code for european dialplans) */
00412    char privateprefix[20];                /*!< for private dialplans */
00413    char unknownprefix[20];                /*!< for unknown dialplans */
00414    int dchannels[NUM_DCHANS];             /*!< What channel are the dchannels on */
00415    int trunkgroup;                     /*!< What our trunkgroup is */
00416    int mastertrunkgroup;                  /*!< What trunk group is our master */
00417    int prilogicalspan;                 /*!< Logical span number within trunk group */
00418    int numchans;                    /*!< Num of channels we represent */
00419    int overlapdial;                 /*!< In overlap dialing mode */
00420    int facilityenable;                 /*!< Enable facility IEs */
00421    struct pri *dchans[NUM_DCHANS];              /*!< Actual d-channels */
00422    int dchanavail[NUM_DCHANS];               /*!< Whether each channel is available */
00423    struct pri *pri;                 /*!< Currently active D-channel */
00424    /*! \brief TRUE if to dump PRI event info (Tested but never set) */
00425    int debug;
00426    int fds[NUM_DCHANS];                /*!< FD's for d-channels */
00427    /*! \brief Value set but not used */
00428    int offset;
00429    /*! \brief Span number put into user output messages */
00430    int span;
00431    /*! \brief TRUE if span is being reset/restarted */
00432    int resetting;
00433    /*! \brief Current position during a reset (-1 if not started) */
00434    int resetpos;
00435 #ifdef HAVE_PRI_INBANDDISCONNECT
00436    unsigned int inbanddisconnect:1;          /*!< Should we support inband audio after receiving DISCONNECT? */
00437 #endif
00438    time_t lastreset;                /*!< time when unused channels were last reset */
00439    long resetinterval;                 /*!< Interval (in seconds) for resetting unused channels */
00440    /*! \brief ISDN signalling type (SIG_PRI, SIG_BRI, SIG_BRI_PTMP, etc...) */
00441    int sig;
00442    struct dahdi_pvt *pvts[MAX_CHANNELS];           /*!< Member channel pvt structs */
00443    struct dahdi_pvt *crvs;                /*!< Member CRV structs */
00444    struct dahdi_pvt *crvend;                 /*!< Pointer to end of CRV structs */
00445 };
00446 
00447 
00448 static struct dahdi_pri pris[NUM_SPANS];
00449 
00450 #if 0
00451 #define DEFAULT_PRI_DEBUG (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE)
00452 #else
00453 #define DEFAULT_PRI_DEBUG 0
00454 #endif
00455 
00456 static inline void pri_rel(struct dahdi_pri *pri)
00457 {
00458    ast_mutex_unlock(&pri->lock);
00459 }
00460 
00461 #else
00462 /*! Shut up the compiler */
00463 struct dahdi_pri;
00464 #endif
00465 
00466 #define SUB_REAL  0        /*!< Active call */
00467 #define SUB_CALLWAIT 1        /*!< Call-Waiting call on hold */
00468 #define SUB_THREEWAY 2        /*!< Three-way call */
00469 
00470 /* Polarity states */
00471 #define POLARITY_IDLE   0
00472 #define POLARITY_REV    1
00473 
00474 
00475 struct distRingData {
00476    int ring[3];
00477    int range;
00478 };
00479 struct ringContextData {
00480    char contextData[AST_MAX_CONTEXT];
00481 };
00482 struct dahdi_distRings {
00483    struct distRingData ringnum[3];
00484    struct ringContextData ringContext[3];
00485 };
00486 
00487 static char *subnames[] = {
00488    "Real",
00489    "Callwait",
00490    "Threeway"
00491 };
00492 
00493 struct dahdi_subchannel {
00494    int dfd;
00495    struct ast_channel *owner;
00496    int chan;
00497    short buffer[AST_FRIENDLY_OFFSET/2 + READ_SIZE];
00498    struct ast_frame f;     /*!< One frame for each channel.  How did this ever work before? */
00499    unsigned int needringing:1;
00500    unsigned int needbusy:1;
00501    unsigned int needcongestion:1;
00502    unsigned int needcallerid:1;
00503    unsigned int needanswer:1;
00504    unsigned int needflash:1;
00505    unsigned int needhold:1;
00506    unsigned int needunhold:1;
00507    unsigned int linear:1;
00508    unsigned int inthreeway:1;
00509    struct dahdi_confinfo curconf;
00510 };
00511 
00512 #define CONF_USER_REAL     (1 << 0)
00513 #define CONF_USER_THIRDCALL   (1 << 1)
00514 
00515 #define MAX_SLAVES   4
00516 
00517 static struct dahdi_pvt {
00518    ast_mutex_t lock;
00519    struct ast_channel *owner;       /*!< Our current active owner (if applicable) */
00520                      /*!< Up to three channels can be associated with this call */
00521       
00522    struct dahdi_subchannel sub_unused;    /*!< Just a safety precaution */
00523    struct dahdi_subchannel subs[3];       /*!< Sub-channels */
00524    struct dahdi_confinfo saveconf;        /*!< Saved conference info */
00525 
00526    struct dahdi_pvt *slaves[MAX_SLAVES];     /*!< Slave to us (follows our conferencing) */
00527    struct dahdi_pvt *master;           /*!< Master to us (we follow their conferencing) */
00528    int inconference;          /*!< If our real should be in the conference */
00529    
00530    int buf_no;             /*!< Number of buffers */
00531    int buf_policy;            /*!< Buffer policy */
00532    int sig;             /*!< Signalling style */
00533    /*!
00534     * \brief Nonzero if the signaling type is sent over a radio.
00535     * \note Set to a couple of nonzero values but it is only tested like a boolean.
00536     */
00537    int radio;
00538    int outsigmod;             /*!< Outbound Signalling style (modifier) */
00539    int oprmode;               /*!< "Operator Services" mode */
00540    struct dahdi_pvt *oprpeer;          /*!< "Operator Services" peer tech_pvt ptr */
00541    /*! \brief Amount of gain to increase during caller id */
00542    float cid_rxgain;
00543    /*! \brief Rx gain set by chan_dahdi.conf */
00544    float rxgain;
00545    /*! \brief Tx gain set by chan_dahdi.conf */
00546    float txgain;
00547    int tonezone;              /*!< tone zone for this chan, or -1 for default */
00548    struct dahdi_pvt *next;          /*!< Next channel in list */
00549    struct dahdi_pvt *prev;          /*!< Prev channel in list */
00550 
00551    /* flags */
00552 
00553    /*!
00554     * \brief TRUE if ADSI (Analog Display Services Interface) available
00555     * \note Set from the "adsi" value read in from chan_dahdi.conf
00556     */
00557    unsigned int adsi:1;
00558    /*!
00559     * \brief TRUE if we can use a polarity reversal to mark when an outgoing
00560     * call is answered by the remote party.
00561     * \note Set from the "answeronpolarityswitch" value read in from chan_dahdi.conf
00562     */
00563    unsigned int answeronpolarityswitch:1;
00564    /*!
00565     * \brief TRUE if busy detection is enabled.
00566     * (Listens for the beep-beep busy pattern.)
00567     * \note Set from the "busydetect" value read in from chan_dahdi.conf
00568     */
00569    unsigned int busydetect:1;
00570    /*!
00571     * \brief TRUE if call return is enabled.
00572     * (*69, if your dialplan doesn't catch this first)
00573     * \note Set from the "callreturn" value read in from chan_dahdi.conf
00574     */
00575    unsigned int callreturn:1;
00576    /*!
00577     * \brief TRUE if busy extensions will hear the call-waiting tone
00578     * and can use hook-flash to switch between callers.
00579     * \note Can be disabled by dialing *70.
00580     * \note Initialized with the "callwaiting" value read in from chan_dahdi.conf
00581     */
00582    unsigned int callwaiting:1;
00583    /*!
00584     * \brief TRUE if send caller ID for Call Waiting
00585     * \note Set from the "callwaitingcallerid" value read in from chan_dahdi.conf
00586     */
00587    unsigned int callwaitingcallerid:1;
00588    /*!
00589     * \brief TRUE if support for call forwarding enabled.
00590     * Dial *72 to enable call forwarding.
00591     * Dial *73 to disable call forwarding.
00592     * \note Set from the "cancallforward" value read in from chan_dahdi.conf
00593     */
00594    unsigned int cancallforward:1;
00595    /*!
00596     * \brief TRUE if support for call parking is enabled.
00597     * \note Set from the "canpark" value read in from chan_dahdi.conf
00598     */
00599    unsigned int canpark:1;
00600    /*! \brief TRUE if to wait for a DTMF digit to confirm answer */
00601    unsigned int confirmanswer:1;
00602    /*!
00603     * \brief TRUE if the channel is to be destroyed on hangup.
00604     * (Used by pseudo channels.)
00605     */
00606    unsigned int destroy:1;
00607    unsigned int didtdd:1;           /*!< flag to say its done it once */
00608    /*! \brief TRUE if analog type line dialed no digits in Dial() */
00609    unsigned int dialednone:1;
00610    /*! \brief TRUE if in the process of dialing digits or sending something. */
00611    unsigned int dialing:1;
00612    /*! \brief TRUE if the transfer capability of the call is digital. */
00613    unsigned int digital:1;
00614    /*! \brief TRUE if Do-Not-Disturb is enabled. */
00615    unsigned int dnd:1;
00616    /*! \brief XXX BOOLEAN Purpose??? */
00617    unsigned int echobreak:1;
00618    /*!
00619     * \brief TRUE if echo cancellation enabled when bridged.
00620     * \note Initialized with the "echocancelwhenbridged" value read in from chan_dahdi.conf
00621     * \note Disabled if the echo canceller is not setup.
00622     */
00623    unsigned int echocanbridged:1;
00624    /*! \brief TRUE if echo cancellation is turned on. */
00625    unsigned int echocanon:1;
00626    /*! \brief TRUE if a fax tone has already been handled. */
00627    unsigned int faxhandled:1;
00628    /*! \brief TRUE if over a radio and dahdi_read() has been called. */
00629    unsigned int firstradio:1;
00630    /*!
00631     * \brief TRUE if the call will be considered "hung up" on a polarity reversal.
00632     * \note Set from the "hanguponpolarityswitch" value read in from chan_dahdi.conf
00633     */
00634    unsigned int hanguponpolarityswitch:1;
00635    /*! \brief TRUE if DTMF detection needs to be done by hardware. */
00636    unsigned int hardwaredtmf:1;
00637    /*!
00638     * \brief TRUE if the outgoing caller ID is blocked/hidden.
00639     * \note Caller ID can be disabled by dialing *67.
00640     * \note Caller ID can be enabled by dialing *82.
00641     * \note Initialized with the "hidecallerid" value read in from chan_dahdi.conf
00642     */
00643    unsigned int hidecallerid:1;
00644    /*!
00645     * \brief TRUE if hide just the name not the number for legacy PBX use.
00646     * \note Only applies to PRI channels.
00647     * \note Set from the "hidecalleridname" value read in from chan_dahdi.conf
00648     */
00649    unsigned int hidecalleridname:1;
00650    /*! \brief TRUE if DTMF detection is disabled. */
00651    unsigned int ignoredtmf:1;
00652    /*!
00653     * \brief TRUE if the channel should be answered immediately
00654     * without attempting to gather any digits.
00655     * \note Set from the "immediate" value read in from chan_dahdi.conf
00656     */
00657    unsigned int immediate:1;
00658    /*! \brief TRUE if in an alarm condition. */
00659    unsigned int inalarm:1;
00660    /*! \brief TRUE if TDD in MATE mode */
00661    unsigned int mate:1;
00662    /*! \brief TRUE if we originated the call leg. */
00663    unsigned int outgoing:1;
00664    /* unsigned int overlapdial:1;         unused and potentially confusing */
00665    /*!
00666     * \brief TRUE if busy extensions will hear the call-waiting tone
00667     * and can use hook-flash to switch between callers.
00668     * \note Set from the "callwaiting" value read in from chan_dahdi.conf
00669     */
00670    unsigned int permcallwaiting:1;
00671    /*!
00672     * \brief TRUE if the outgoing caller ID is blocked/restricted/hidden.
00673     * \note Set from the "hidecallerid" value read in from chan_dahdi.conf
00674     */
00675    unsigned int permhidecallerid:1;
00676    /*!
00677     * \brief TRUE if PRI congestion/busy indications are sent out-of-band.
00678     * \note Set from the "priindication" value read in from chan_dahdi.conf
00679     */
00680    unsigned int priindication_oob:1;
00681    /*!
00682     * \brief TRUE if PRI B channels are always exclusively selected.
00683     * \note Set from the "priexclusive" value read in from chan_dahdi.conf
00684     */
00685    unsigned int priexclusive:1;
00686    /*!
00687     * \brief TRUE if we will pulse dial.
00688     * \note Set from the "pulsedial" value read in from chan_dahdi.conf
00689     */
00690    unsigned int pulse:1;
00691    /*! \brief TRUE if a pulsed digit was detected. (Pulse dial phone detected) */
00692    unsigned int pulsedial:1;
00693    unsigned int restartpending:1;      /*!< flag to ensure counted only once for restart */
00694    /*!
00695     * \brief TRUE if caller ID is restricted.
00696     * \note Set but not used.  Should be deleted.  Redundant with permhidecallerid.
00697     * \note Set from the "restrictcid" value read in from chan_dahdi.conf
00698     */
00699    unsigned int restrictcid:1;
00700    /*!
00701     * \brief TRUE if three way calling is enabled
00702     * \note Set from the "threewaycalling" value read in from chan_dahdi.conf
00703     */
00704    unsigned int threewaycalling:1;
00705    /*!
00706     * \brief TRUE if call transfer is enabled
00707     * \note For FXS ports (either direct analog or over T1/E1):
00708     *   Support flash-hook call transfer
00709     * \note For digital ports using ISDN PRI protocols:
00710     *   Support switch-side transfer (called 2BCT, RLT or other names)
00711     * \note Set from the "transfer" value read in from chan_dahdi.conf
00712     */
00713    unsigned int transfer:1;
00714    /*!
00715     * \brief TRUE if caller ID is used on this channel.
00716     * \note PRI and SS7 spans will save caller ID from the networking peer.
00717     * \note FXS ports will generate the caller ID spill.
00718     * \note FXO ports will listen for the caller ID spill.
00719     * \note Set from the "usecallerid" value read in from chan_dahdi.conf
00720     */
00721    unsigned int use_callerid:1;
00722    /*!
00723     * \brief TRUE if we will use the calling presentation setting
00724     * from the Asterisk channel for outgoing calls.
00725     * \note Only applies to PRI and SS7 channels.
00726     * \note Set from the "usecallingpres" value read in from chan_dahdi.conf
00727     */
00728    unsigned int use_callingpres:1;
00729    /*!
00730     * \brief TRUE if distinctive rings are to be detected.
00731     * \note For FXO lines
00732     * \note Set indirectly from the "usedistinctiveringdetection" value read in from chan_dahdi.conf
00733     */
00734    unsigned int usedistinctiveringdetection:1;
00735    /*!
00736     * \brief TRUE if we should use the callerid from incoming call on dahdi transfer.
00737     * \note Set from the "useincomingcalleridondahditransfer" value read in from chan_dahdi.conf
00738     */
00739    unsigned int dahditrcallerid:1;
00740    /*!
00741     * \brief TRUE if allowed to flash-transfer to busy channels.
00742     * \note Set from the "transfertobusy" value read in from chan_dahdi.conf
00743     */
00744    unsigned int transfertobusy:1;
00745    /*!
00746     * \brief TRUE if the FXO port monitors for neon type MWI indications from the other end.
00747     * \note Set if the "mwimonitor" value read in contains "neon" from chan_dahdi.conf
00748     */
00749    unsigned int mwimonitor_neon:1;
00750    /*!
00751     * \brief TRUE if the FXO port monitors for fsk type MWI indications from the other end.
00752     * \note Set if the "mwimonitor" value read in contains "fsk" from chan_dahdi.conf
00753     */
00754    unsigned int mwimonitor_fsk:1;
00755    /*!
00756     * \brief TRUE if the FXO port monitors for rpas precursor to fsk MWI indications from the other end.
00757     * \note RPAS - Ring Pulse Alert Signal
00758     * \note Set if the "mwimonitor" value read in contains "rpas" from chan_dahdi.conf
00759     */
00760    unsigned int mwimonitor_rpas:1;
00761    /*! \brief TRUE if an MWI monitor thread is currently active */
00762    unsigned int mwimonitoractive:1;
00763    /*! \brief TRUE if a MWI message sending thread is active */
00764    unsigned int mwisendactive:1;
00765    /*!
00766     * \brief TRUE if channel is out of reset and ready
00767     * \note Set but not used.
00768     */
00769    unsigned int inservice:1;
00770    /*!
00771     * \brief TRUE if the channel is locally blocked.
00772     * \note Applies to SS7 channels.
00773     */
00774    unsigned int locallyblocked:1;
00775    /*!
00776     * \brief TRUE if the channel is remotely blocked.
00777     * \note Applies to SS7 channels.
00778     */
00779    unsigned int remotelyblocked:1;
00780 #if defined(HAVE_PRI) || defined(HAVE_SS7)
00781    /*!
00782     * \brief XXX BOOLEAN Purpose???
00783     * \note Applies to SS7 channels.
00784     */
00785    unsigned int rlt:1;
00786    /*! \brief TRUE if channel is alerting/ringing */
00787    unsigned int alerting:1;
00788    /*! \brief TRUE if the call has already gone/hungup */
00789    unsigned int alreadyhungup:1;
00790    /*!
00791     * \brief TRUE if this is an idle call
00792     * \note Applies to PRI channels.
00793     */
00794    unsigned int isidlecall:1;
00795    /*!
00796     * \brief TRUE if call is in a proceeding state.
00797     * The call has started working its way through the network.
00798     */
00799    unsigned int proceeding:1;
00800    /*! \brief TRUE if the call has seen progress through the network. */
00801    unsigned int progress:1;
00802    /*!
00803     * \brief TRUE if this channel is being reset/restarted
00804     * \note Applies to PRI channels.
00805     */
00806    unsigned int resetting:1;
00807    /*!
00808     * \brief TRUE if this channel has received a SETUP_ACKNOWLEDGE
00809     * \note Applies to PRI channels.
00810     */
00811    unsigned int setup_ack:1;
00812 #endif
00813    /*!
00814     * \brief TRUE if SMDI (Simplified Message Desk Interface) is enabled
00815     * \note Set from the "usesmdi" value read in from chan_dahdi.conf
00816     */
00817    unsigned int use_smdi:1;
00818    /*! \brief The serial port to listen for SMDI data on */
00819    struct ast_smdi_interface *smdi_iface;
00820 
00821    /*! \brief Distinctive Ring data */
00822    struct dahdi_distRings drings;
00823 
00824    /*!
00825     * \brief The configured context for incoming calls.
00826     * \note The "context" string read in from chan_dahdi.conf
00827     */
00828    char context[AST_MAX_CONTEXT];
00829    /*!
00830     * \brief Saved context string.
00831     */
00832    char defcontext[AST_MAX_CONTEXT];
00833    /*! \brief Extension to use in the dialplan. */
00834    char exten[AST_MAX_EXTENSION];
00835    /*!
00836     * \brief Language configured for calls.
00837     * \note The "language" string read in from chan_dahdi.conf
00838     */
00839    char language[MAX_LANGUAGE];
00840    /*!
00841     * \brief The configured music-on-hold class to use for calls.
00842     * \note The "musicclass" or "mohinterpret" or "musiconhold" string read in from chan_dahdi.conf
00843     */
00844    char mohinterpret[MAX_MUSICCLASS];
00845    /*!
00846     * \brief Suggested music-on-hold class for peer channel to use for calls.
00847     * \note The "mohsuggest" string read in from chan_dahdi.conf
00848     */
00849    char mohsuggest[MAX_MUSICCLASS];
00850    char parkinglot[AST_MAX_EXTENSION]; /*!< Parking lot for this channel */
00851 #if defined(PRI_ANI) || defined(HAVE_SS7)
00852    /*! \brief Automatic Number Identification number (Alternate PRI caller ID number) */
00853    char cid_ani[AST_MAX_EXTENSION];
00854 #endif
00855    /*! \brief Automatic Number Identification code from PRI */
00856    int cid_ani2;
00857    /*! \brief Caller ID number from an incoming call. */
00858    char cid_num[AST_MAX_EXTENSION];
00859    /*! \brief Caller ID Q.931 TON/NPI field values.  Set by PRI. Zero otherwise. */
00860    int cid_ton;
00861    /*! \brief Caller ID name from an incoming call. */
00862    char cid_name[AST_MAX_EXTENSION];
00863    /*! \brief Last Caller ID number from an incoming call. */
00864    char lastcid_num[AST_MAX_EXTENSION];
00865    /*! \brief Last Caller ID name from an incoming call. */
00866    char lastcid_name[AST_MAX_EXTENSION];
00867    char *origcid_num;            /*!< malloced original callerid */
00868    char *origcid_name;           /*!< malloced original callerid */
00869    /*! \brief Call waiting number. */
00870    char callwait_num[AST_MAX_EXTENSION];
00871    /*! \brief Call waiting name. */
00872    char callwait_name[AST_MAX_EXTENSION];
00873    /*! \brief Redirecting Directory Number Information Service (RDNIS) number */
00874    char rdnis[AST_MAX_EXTENSION];
00875    /*! \brief Dialed Number Identifier */
00876    char dnid[AST_MAX_EXTENSION];
00877    /*!
00878     * \brief Bitmapped groups this belongs to.
00879     * \note The "group" bitmapped group string read in from chan_dahdi.conf
00880     */
00881    ast_group_t group;
00882    /*! \brief Active PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW */
00883    int law;
00884    int confno;             /*!< Our conference */
00885    int confusers;             /*!< Who is using our conference */
00886    int propconfno;               /*!< Propagated conference number */
00887    /*!
00888     * \brief Bitmapped call groups this belongs to.
00889     * \note The "callgroup" bitmapped group string read in from chan_dahdi.conf
00890     */
00891    ast_group_t callgroup;
00892    /*!
00893     * \brief Bitmapped pickup groups this belongs to.
00894     * \note The "pickupgroup" bitmapped group string read in from chan_dahdi.conf
00895     */
00896    ast_group_t pickupgroup;
00897    /*!
00898     * \brief Channel variable list with associated values to set when a channel is created.
00899     * \note The "setvar" strings read in from chan_dahdi.conf
00900     */
00901    struct ast_variable *vars;
00902    int channel;               /*!< Channel Number or CRV */
00903    int span;               /*!< Span number */
00904    time_t guardtime;          /*!< Must wait this much time before using for new call */
00905    int cid_signalling;           /*!< CID signalling type bell202 or v23 */
00906    int cid_start;             /*!< CID start indicator, polarity or ring */
00907    int callingpres;           /*!< The value of callling presentation that we're going to use when placing a PRI call */
00908    int callwaitingrepeat;           /*!< How many samples to wait before repeating call waiting */
00909    int cidcwexpire;           /*!< When to expire our muting for CID/CW */
00910    /*! \brief Analog caller ID waveform sample buffer */
00911    unsigned char *cidspill;
00912    /*! \brief Position in the cidspill buffer to send out next. */
00913    int cidpos;
00914    /*! \brief Length of the cidspill buffer containing samples. */
00915    int cidlen;
00916    /*! \brief Ring timeout timer?? */
00917    int ringt;
00918    /*!
00919     * \brief Ring timeout base.
00920     * \note Value computed indirectly from "ringtimeout" read in from chan_dahdi.conf
00921     */
00922    int ringt_base;
00923    /*!
00924     * \brief Number of most significant digits/characters to strip from the dialed number.
00925     * \note Feature is deprecated.  Use dialplan logic.
00926     * \note The characters are stripped before the PRI TON/NPI prefix
00927     * characters are processed.
00928     */
00929    int stripmsd;
00930    /*! \brief BOOLEAN. XXX Meaning what?? */
00931    int callwaitcas;
00932    /*! \brief Number of call waiting rings. */
00933    int callwaitrings;
00934    /*! \brief Echo cancel parameters. */
00935    struct {
00936       struct dahdi_echocanparams head;
00937       struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS];
00938    } echocancel;
00939    /*!
00940     * \brief Echo training time. 0 = disabled
00941     * \note Set from the "echotraining" value read in from chan_dahdi.conf
00942     */
00943    int echotraining;
00944    /*! \brief Filled with 'w'.  XXX Purpose?? */
00945    char echorest[20];
00946    /*!
00947     * \brief Number of times to see "busy" tone before hanging up.
00948     * \note Set from the "busycount" value read in from chan_dahdi.conf
00949     */
00950    int busycount;
00951    /*!
00952     * \brief Length of "busy" tone on time.
00953     * \note Set from the "busypattern" value read in from chan_dahdi.conf
00954     */
00955    int busy_tonelength;
00956    /*!
00957     * \brief Length of "busy" tone off time.
00958     * \note Set from the "busypattern" value read in from chan_dahdi.conf
00959     */
00960    int busy_quietlength;
00961    /*!
00962     * \brief Bitmapped call progress detection flags. CALLPROGRESS_xxx values.
00963     * \note Bits set from the "callprogress" and "faxdetect" values read in from chan_dahdi.conf
00964     */
00965    int callprogress;
00966    struct timeval flashtime;        /*!< Last flash-hook time */
00967    /*! \brief Opaque DSP configuration structure. */
00968    struct ast_dsp *dsp;
00969    //int cref;             /*!< Call reference number (Not used) */
00970    /*! \brief DAHDI dial operation command struct for ioctl() call. */
00971    struct dahdi_dialoperation dop;
00972    int whichwink;             /*!< SIG_FEATDMF_TA Which wink are we on? */
00973    /*! \brief Second part of SIG_FEATDMF_TA wink operation. */
00974    char finaldial[64];
00975    char accountcode[AST_MAX_ACCOUNT_CODE];      /*!< Account code */
00976    int amaflags;              /*!< AMA Flags */
00977    struct tdd_state *tdd;           /*!< TDD flag */
00978    /*! \brief Accumulated call forwarding number. */
00979    char call_forward[AST_MAX_EXTENSION];
00980    /*!
00981     * \brief Voice mailbox location.
00982     * \note Set from the "mailbox" string read in from chan_dahdi.conf
00983     */
00984    char mailbox[AST_MAX_EXTENSION];
00985    /*! \brief Opaque event subscription parameters for message waiting indication support. */
00986    struct ast_event_sub *mwi_event_sub;
00987    /*! \brief Delayed dialing for E911.  Overlap digits for ISDN. */
00988    char dialdest[256];
00989    /*! \brief Time the interface went on-hook. */
00990    int onhooktime;
00991    /*! \brief -1 = unknown, 0 = no messages, 1 = new messages available */
00992    int msgstate;
00993    int distinctivering;          /*!< Which distinctivering to use */
00994    int cidrings;              /*!< Which ring to deliver CID on */
00995    int dtmfrelax;             /*!< whether to run in relaxed DTMF mode */
00996    /*! \brief Holding place for event injected from outside normal operation. */
00997    int fake_event;
00998    /*!
00999     * \brief Minimal time period (ms) between the answer polarity
01000     * switch and hangup polarity switch.
01001     */
01002    int polarityonanswerdelay;
01003    /*! \brief Start delay time if polarityonanswerdelay is nonzero. */
01004    struct timeval polaritydelaytv;
01005    /*!
01006     * \brief Send caller ID after this many rings.
01007     * \note Set from the "sendcalleridafter" value read in from chan_dahdi.conf
01008     */
01009    int sendcalleridafter;
01010 #ifdef HAVE_PRI
01011    /*! \brief DAHDI PRI control parameters */
01012    struct dahdi_pri *pri;
01013    /*! \brief XXX Purpose??? */
01014    struct dahdi_pvt *bearer;
01015    /*! \brief XXX Purpose??? */
01016    struct dahdi_pvt *realcall;
01017    /*! \brief Opaque libpri call control structure */
01018    q931_call *call;
01019    /*! \brief Channel number in span. */
01020    int prioffset;
01021    /*! \brief Logical span number within trunk group */
01022    int logicalspan;
01023 #endif   
01024    /*! \brief Current line interface polarity. POLARITY_IDLE, POLARITY_REV */
01025    int polarity;
01026    /*! \brief DSP feature flags: DSP_FEATURE_xxx */
01027    int dsp_features;
01028 #ifdef HAVE_SS7
01029    /*! \brief SS7 control parameters */
01030    struct dahdi_ss7 *ss7;
01031    /*! \brief Opaque libss7 call control structure */
01032    struct isup_call *ss7call;
01033    char charge_number[50];
01034    char gen_add_number[50];
01035    char gen_dig_number[50];
01036    char orig_called_num[50];
01037    char redirecting_num[50];
01038    char generic_name[50];
01039    unsigned char gen_add_num_plan;
01040    unsigned char gen_add_nai;
01041    unsigned char gen_add_pres_ind;
01042    unsigned char gen_add_type;
01043    unsigned char gen_dig_type;
01044    unsigned char gen_dig_scheme;
01045    char jip_number[50];
01046    unsigned char lspi_type;
01047    unsigned char lspi_scheme;
01048    unsigned char lspi_context;
01049    char lspi_ident[50];
01050    unsigned int call_ref_ident;
01051    unsigned int call_ref_pc;
01052    unsigned char calling_party_cat;
01053    int transcap;
01054    int cic;                   /*!< CIC associated with channel */
01055    unsigned int dpc;                /*!< CIC's DPC */
01056    unsigned int loopedback:1;
01057 #endif
01058    /*! \brief DTMF digit in progress.  0 when no digit in progress. */
01059    char begindigit;
01060    /*! \brief TRUE if confrence is muted. */
01061    int muting;
01062 } *iflist = NULL, *ifend = NULL;
01063 
01064 /*! \brief Channel configuration from chan_dahdi.conf .
01065  * This struct is used for parsing the [channels] section of chan_dahdi.conf.
01066  * Generally there is a field here for every possible configuration item.
01067  *
01068  * The state of fields is saved along the parsing and whenever a 'channel'
01069  * statement is reached, the current dahdi_chan_conf is used to configure the 
01070  * channel (struct dahdi_pvt)
01071  *
01072  * \see dahdi_chan_init for the default values.
01073  */
01074 struct dahdi_chan_conf {
01075    struct dahdi_pvt chan;
01076 #ifdef HAVE_PRI
01077    struct dahdi_pri pri;
01078 #endif
01079 
01080 #ifdef HAVE_SS7
01081    struct dahdi_ss7 ss7;
01082 #endif
01083    struct dahdi_params timing;
01084    int is_sig_auto; /*!< Use channel signalling from DAHDI? */
01085 
01086    /*!
01087     * \brief The serial port to listen for SMDI data on
01088     * \note Set from the "smdiport" string read in from chan_dahdi.conf
01089     */
01090    char smdi_port[SMDI_MAX_FILENAME_LEN];
01091 };
01092 
01093 /*! returns a new dahdi_chan_conf with default values (by-value) */
01094 static struct dahdi_chan_conf dahdi_chan_conf_default(void) {
01095    /* recall that if a field is not included here it is initialized
01096     * to 0 or equivalent
01097     */
01098    struct dahdi_chan_conf conf = {
01099 #ifdef HAVE_PRI
01100       .pri = {
01101          .nsf = PRI_NSF_NONE,
01102          .switchtype = PRI_SWITCH_NI2,
01103          .dialplan = PRI_UNKNOWN + 1,
01104          .localdialplan = PRI_NATIONAL_ISDN + 1,
01105          .nodetype = PRI_CPE,
01106 
01107          .minunused = 2,
01108          .idleext = "",
01109          .idledial = "",
01110          .internationalprefix = "",
01111          .nationalprefix = "",
01112          .localprefix = "",
01113          .privateprefix = "",
01114          .unknownprefix = "",
01115          .resetinterval = -1,
01116       },
01117 #endif
01118 #ifdef HAVE_SS7
01119       .ss7 = {
01120          .called_nai = SS7_NAI_NATIONAL,
01121          .calling_nai = SS7_NAI_NATIONAL,
01122          .internationalprefix = "",
01123          .nationalprefix = "",
01124          .subscriberprefix = "",
01125          .unknownprefix = ""
01126       },
01127 #endif
01128       .chan = {
01129          .context = "default",
01130          .cid_num = "",
01131          .cid_name = "",
01132          .mohinterpret = "default",
01133          .mohsuggest = "",
01134          .parkinglot = "",
01135          .transfertobusy = 1,
01136 
01137          .cid_signalling = CID_SIG_BELL,
01138          .cid_start = CID_START_RING,
01139          .dahditrcallerid = 0,
01140          .use_callerid = 1,
01141          .sig = -1,
01142          .outsigmod = -1,
01143 
01144          .cid_rxgain = +5.0,
01145 
01146          .tonezone = -1,
01147 
01148          .echocancel.head.tap_length = 1,
01149 
01150          .busycount = 3,
01151 
01152          .accountcode = "",
01153 
01154          .mailbox = "",
01155 
01156 
01157          .polarityonanswerdelay = 600,
01158 
01159          .sendcalleridafter = DEFAULT_CIDRINGS,
01160       
01161          .buf_policy = DAHDI_POLICY_IMMEDIATE,
01162          .buf_no = numbufs
01163       },
01164       .timing = {
01165          .prewinktime = -1,
01166          .preflashtime = -1,
01167          .winktime = -1,
01168          .flashtime = -1,
01169          .starttime = -1,
01170          .rxwinktime = -1,
01171          .rxflashtime = -1,
01172          .debouncetime = -1
01173       },
01174       .is_sig_auto = 1,
01175       .smdi_port = "/dev/ttyS0",
01176    };
01177 
01178    return conf;
01179 }
01180 
01181 
01182 static struct ast_channel *dahdi_request(const char *type, int format, void *data, int *cause);
01183 static int dahdi_digit_begin(struct ast_channel *ast, char digit);
01184 static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
01185 static int dahdi_sendtext(struct ast_channel *c, const char *text);
01186 static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout);
01187 static int dahdi_hangup(struct ast_channel *ast);
01188 static int dahdi_answer(struct ast_channel *ast);
01189 static struct ast_frame *dahdi_read(struct ast_channel *ast);
01190 static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame);
01191 static struct ast_frame *dahdi_exception(struct ast_channel *ast);
01192 static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
01193 static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
01194 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
01195 static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
01196 static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event);
01197 
01198 static const struct ast_channel_tech dahdi_tech = {
01199    .type = "DAHDI",
01200    .description = tdesc,
01201    .capabilities = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW,
01202    .requester = dahdi_request,
01203    .send_digit_begin = dahdi_digit_begin,
01204    .send_digit_end = dahdi_digit_end,
01205    .send_text = dahdi_sendtext,
01206    .call = dahdi_call,
01207    .hangup = dahdi_hangup,
01208    .answer = dahdi_answer,
01209    .read = dahdi_read,
01210    .write = dahdi_write,
01211    .bridge = dahdi_bridge,
01212    .exception = dahdi_exception,
01213    .indicate = dahdi_indicate,
01214    .fixup = dahdi_fixup,
01215    .setoption = dahdi_setoption,
01216    .func_channel_read = dahdi_func_read,
01217 };
01218 
01219 #ifdef HAVE_PRI
01220 #define GET_CHANNEL(p) ((p)->bearer ? (p)->bearer->channel : p->channel)
01221 #else
01222 #define GET_CHANNEL(p) ((p)->channel)
01223 #endif
01224 
01225 struct dahdi_pvt *round_robin[32];
01226 
01227 #ifdef HAVE_PRI
01228 static inline int pri_grab(struct dahdi_pvt *pvt, struct dahdi_pri *pri)
01229 {
01230    int res;
01231    /* Grab the lock first */
01232    do {
01233       res = ast_mutex_trylock(&pri->lock);
01234       if (res) {
01235          DEADLOCK_AVOIDANCE(&pvt->lock);
01236       }
01237    } while (res);
01238    /* Then break the poll */
01239    if (pri->master != AST_PTHREADT_NULL)
01240       pthread_kill(pri->master, SIGURG);
01241    return 0;
01242 }
01243 #endif
01244 
01245 #ifdef HAVE_SS7
01246 static inline void ss7_rel(struct dahdi_ss7 *ss7)
01247 {
01248    ast_mutex_unlock(&ss7->lock);
01249 }
01250 
01251 static inline int ss7_grab(struct dahdi_pvt *pvt, struct dahdi_ss7 *pri)
01252 {
01253    int res;
01254    /* Grab the lock first */
01255    do {
01256       res = ast_mutex_trylock(&pri->lock);
01257       if (res) {
01258          DEADLOCK_AVOIDANCE(&pvt->lock);
01259       }
01260    } while (res);
01261    /* Then break the poll */
01262    if (pri->master != AST_PTHREADT_NULL)
01263       pthread_kill(pri->master, SIGURG);
01264    return 0;
01265 }
01266 #endif
01267 #define NUM_CADENCE_MAX 25
01268 static int num_cadence = 4;
01269 static int user_has_defined_cadences = 0;
01270 
01271 static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
01272    { { 125, 125, 2000, 4000 } },       /*!< Quick chirp followed by normal ring */
01273    { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
01274    { { 125, 125, 125, 125, 125, 4000 } }, /*!< Three short bursts */
01275    { { 1000, 500, 2500, 5000 } },   /*!< Long ring */
01276 };
01277 
01278 /*! \brief cidrings says in which pause to transmit the cid information, where the first pause
01279  * is 1, the second pause is 2 and so on.
01280  */
01281 
01282 static int cidrings[NUM_CADENCE_MAX] = {
01283    2,                            /*!< Right after first long ring */
01284    4,                            /*!< Right after long part */
01285    3,                            /*!< After third chirp */
01286    2,                            /*!< Second spell */
01287 };
01288 
01289 /* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
01290 static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}};
01291 
01292 #define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
01293          (p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
01294 
01295 #define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
01296 #define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
01297 
01298 static int dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok)
01299 {
01300    int res;
01301    if (p->subs[SUB_REAL].owner == ast)
01302       res = 0;
01303    else if (p->subs[SUB_CALLWAIT].owner == ast)
01304       res = 1;
01305    else if (p->subs[SUB_THREEWAY].owner == ast)
01306       res = 2;
01307    else {
01308       res = -1;
01309       if (!nullok)
01310          ast_log(LOG_WARNING, "Unable to get index, and nullok is not asserted\n");
01311    }
01312    return res;
01313 }
01314 
01315 #ifdef HAVE_PRI
01316 static void wakeup_sub(struct dahdi_pvt *p, int a, struct dahdi_pri *pri)
01317 #else
01318 static void wakeup_sub(struct dahdi_pvt *p, int a, void *pri)
01319 #endif
01320 {
01321 #ifdef HAVE_PRI
01322    if (pri)
01323       ast_mutex_unlock(&pri->lock);
01324 #endif         
01325    for (;;) {
01326       if (p->subs[a].owner) {
01327          if (ast_channel_trylock(p->subs[a].owner)) {
01328             DEADLOCK_AVOIDANCE(&p->lock);
01329          } else {
01330             ast_queue_frame(p->subs[a].owner, &ast_null_frame);
01331             ast_channel_unlock(p->subs[a].owner);
01332             break;
01333          }
01334       } else
01335          break;
01336    }
01337 #ifdef HAVE_PRI
01338    if (pri)
01339       ast_mutex_lock(&pri->lock);
01340 #endif         
01341 }
01342 
01343 static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f, void *data)
01344 {
01345 #ifdef HAVE_PRI
01346    struct dahdi_pri *pri = (struct dahdi_pri*) data;
01347 #endif
01348 #ifdef HAVE_SS7
01349    struct dahdi_ss7 *ss7 = (struct dahdi_ss7*) data;
01350 #endif
01351    /* We must unlock the PRI to avoid the possibility of a deadlock */
01352 #if defined(HAVE_PRI) || defined(HAVE_SS7)
01353    if (data) {
01354       switch (p->sig) {
01355 #ifdef HAVE_PRI
01356       case SIG_BRI:
01357       case SIG_BRI_PTMP:
01358       case SIG_PRI:
01359          ast_mutex_unlock(&pri->lock);
01360          break;
01361 #endif
01362 #ifdef HAVE_SS7
01363       case SIG_SS7:
01364          ast_mutex_unlock(&ss7->lock);
01365          break;
01366 #endif
01367       default:
01368          break;
01369       }
01370    }
01371 #endif      
01372    for (;;) {
01373       if (p->owner) {
01374          if (ast_channel_trylock(p->owner)) {
01375             DEADLOCK_AVOIDANCE(&p->lock);
01376          } else {
01377             ast_queue_frame(p->owner, f);
01378             ast_channel_unlock(p->owner);
01379             break;
01380          }
01381       } else
01382          break;
01383    }
01384 #if defined(HAVE_PRI) || defined(HAVE_SS7)
01385    if (data) {
01386       switch (p->sig) {
01387 #ifdef HAVE_PRI
01388       case SIG_BRI:
01389       case SIG_BRI_PTMP:
01390       case SIG_PRI:
01391          ast_mutex_lock(&pri->lock);
01392          break;
01393 #endif
01394 #ifdef HAVE_SS7
01395       case SIG_SS7:
01396          ast_mutex_lock(&ss7->lock);
01397          break;
01398 #endif
01399       default:
01400          break;
01401       }
01402    }
01403 
01404 #endif      
01405 }
01406 
01407 static int restore_gains(struct dahdi_pvt *p);
01408 
01409 static void swap_subs(struct dahdi_pvt *p, int a, int b)
01410 {
01411    int tchan;
01412    int tinthreeway;
01413    struct ast_channel *towner;
01414 
01415    ast_debug(1, "Swapping %d and %d\n", a, b);
01416 
01417    tchan = p->subs[a].chan;
01418    towner = p->subs[a].owner;
01419    tinthreeway = p->subs[a].inthreeway;
01420 
01421    p->subs[a].chan = p->subs[b].chan;
01422    p->subs[a].owner = p->subs[b].owner;
01423    p->subs[a].inthreeway = p->subs[b].inthreeway;
01424 
01425    p->subs[b].chan = tchan;
01426    p->subs[b].owner = towner;
01427    p->subs[b].inthreeway = tinthreeway;
01428 
01429    if (p->subs[a].owner) 
01430       ast_channel_set_fd(p->subs[a].owner, 0, p->subs[a].dfd);
01431    if (p->subs[b].owner) 
01432       ast_channel_set_fd(p->subs[b].owner, 0, p->subs[b].dfd);
01433    wakeup_sub(p, a, NULL);
01434    wakeup_sub(p, b, NULL);
01435 }
01436 
01437 static int dahdi_open(char *fn)
01438 {
01439    int fd;
01440    int isnum;
01441    int chan = 0;
01442    int bs;
01443    int x;
01444    isnum = 1;
01445    for (x = 0; x < strlen(fn); x++) {
01446       if (!isdigit(fn[x])) {
01447          isnum = 0;
01448          break;
01449       }
01450    }
01451    if (isnum) {
01452       chan = atoi(fn);
01453       if (chan < 1) {
01454          ast_log(LOG_WARNING, "Invalid channel number '%s'\n", fn);
01455          return -1;
01456       }
01457       fn = "/dev/dahdi/channel";
01458    }
01459    fd = open(fn, O_RDWR | O_NONBLOCK);
01460    if (fd < 0) {
01461       ast_log(LOG_WARNING, "Unable to open '%s': %s\n", fn, strerror(errno));
01462       return -1;
01463    }
01464    if (chan) {
01465       if (ioctl(fd, DAHDI_SPECIFY, &chan)) {
01466          x = errno;
01467          close(fd);
01468          errno = x;
01469          ast_log(LOG_WARNING, "Unable to specify channel %d: %s\n", chan, strerror(errno));
01470          return -1;
01471       }
01472    }
01473    bs = READ_SIZE;
01474    if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &bs) == -1) {
01475       ast_log(LOG_WARNING, "Unable to set blocksize '%d': %s\n", bs,  strerror(errno));
01476       x = errno;
01477       close(fd);
01478       errno = x;
01479       return -1;
01480    }
01481    return fd;
01482 }
01483 
01484 static void dahdi_close(int fd)
01485 {
01486    if (fd > 0)
01487       close(fd);
01488 }
01489 
01490 static void dahdi_close_sub(struct dahdi_pvt *chan_pvt, int sub_num)
01491 {
01492    dahdi_close(chan_pvt->subs[sub_num].dfd);
01493    chan_pvt->subs[sub_num].dfd = -1;
01494 }
01495 
01496 #ifdef HAVE_PRI
01497 static void dahdi_close_pri_fd(struct dahdi_pri *pri, int fd_num)
01498 {
01499    dahdi_close(pri->fds[fd_num]);
01500    pri->fds[fd_num] = -1;
01501 }
01502 #endif
01503 
01504 #ifdef HAVE_SS7
01505 static void dahdi_close_ss7_fd(struct dahdi_ss7 *ss7, int fd_num)
01506 {
01507    dahdi_close(ss7->fds[fd_num]);
01508    ss7->fds[fd_num] = -1;
01509 }
01510 #endif
01511 
01512 static int dahdi_setlinear(int dfd, int linear)
01513 {
01514    int res;
01515    res = ioctl(dfd, DAHDI_SETLINEAR, &linear);
01516    if (res)
01517       return res;
01518    return 0;
01519 }
01520 
01521 
01522 static int alloc_sub(struct dahdi_pvt *p, int x)
01523 {
01524    struct dahdi_bufferinfo bi;
01525    int res;
01526    if (p->subs[x].dfd >= 0) {
01527       ast_log(LOG_WARNING, "%s subchannel of %d already in use\n", subnames[x], p->channel);
01528       return -1;
01529    }
01530 
01531    p->subs[x].dfd = dahdi_open("/dev/dahdi/pseudo");
01532    if (p->subs[x].dfd <= -1) {
01533       ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
01534       return -1;
01535    }
01536 
01537    res = ioctl(p->subs[x].dfd, DAHDI_GET_BUFINFO, &bi);
01538    if (!res) {
01539       bi.txbufpolicy = p->buf_policy;
01540       bi.rxbufpolicy = p->buf_policy;
01541       bi.numbufs = p->buf_no;
01542       res = ioctl(p->subs[x].dfd, DAHDI_SET_BUFINFO, &bi);
01543       if (res < 0) {
01544          ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", x, strerror(errno));
01545       }
01546    } else 
01547       ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", x, strerror(errno));
01548 
01549    if (ioctl(p->subs[x].dfd, DAHDI_CHANNO, &p->subs[x].chan) == 1) {
01550       ast_log(LOG_WARNING, "Unable to get channel number for pseudo channel on FD %d: %s\n", p->subs[x].dfd, strerror(errno));
01551       dahdi_close_sub(p, x);
01552       p->subs[x].dfd = -1;
01553       return -1;
01554    }
01555    ast_debug(1, "Allocated %s subchannel on FD %d channel %d\n", subnames[x], p->subs[x].dfd, p->subs[x].chan);
01556    return 0;
01557 }
01558 
01559 static int unalloc_sub(struct dahdi_pvt *p, int x)
01560 {
01561    if (!x) {
01562       ast_log(LOG_WARNING, "Trying to unalloc the real channel %d?!?\n", p->channel);
01563       return -1;
01564    }
01565    ast_debug(1, "Released sub %d of channel %d\n", x, p->channel);
01566    dahdi_close_sub(p, x);
01567    p->subs[x].linear = 0;
01568    p->subs[x].chan = 0;
01569    p->subs[x].owner = NULL;
01570    p->subs[x].inthreeway = 0;
01571    p->polarity = POLARITY_IDLE;
01572    memset(&p->subs[x].curconf, 0, sizeof(p->subs[x].curconf));
01573    return 0;
01574 }
01575 
01576 static int digit_to_dtmfindex(char digit)
01577 {
01578    if (isdigit(digit))
01579       return DAHDI_TONE_DTMF_BASE + (digit - '0');
01580    else if (digit >= 'A' && digit <= 'D')
01581       return DAHDI_TONE_DTMF_A + (digit - 'A');
01582    else if (digit >= 'a' && digit <= 'd')
01583       return DAHDI_TONE_DTMF_A + (digit - 'a');
01584    else if (digit == '*')
01585       return DAHDI_TONE_DTMF_s;
01586    else if (digit == '#')
01587       return DAHDI_TONE_DTMF_p;
01588    else
01589       return -1;
01590 }
01591 
01592 static int dahdi_digit_begin(struct ast_channel *chan, char digit)
01593 {
01594    struct dahdi_pvt *pvt;
01595    int idx;
01596    int dtmf = -1;
01597    
01598    pvt = chan->tech_pvt;
01599 
01600    ast_mutex_lock(&pvt->lock);
01601 
01602    idx = dahdi_get_index(chan, pvt, 0);
01603 
01604    if ((idx != SUB_REAL) || !pvt->owner)
01605       goto out;
01606 
01607 #ifdef HAVE_PRI
01608    if (((pvt->sig == SIG_PRI) || (pvt->sig == SIG_BRI) || (pvt->sig == SIG_BRI_PTMP)) 
01609          && (chan->_state == AST_STATE_DIALING) && !pvt->proceeding) {
01610       if (pvt->setup_ack) {
01611          if (!pri_grab(pvt, pvt->pri)) {
01612             pri_information(pvt->pri->pri, pvt->call, digit);
01613             pri_rel(pvt->pri);
01614          } else
01615             ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", pvt->span);
01616       } else if (strlen(pvt->dialdest) < sizeof(pvt->dialdest) - 1) {
01617          int res;
01618          ast_debug(1, "Queueing digit '%c' since setup_ack not yet received\n", digit);
01619          res = strlen(pvt->dialdest);
01620          pvt->dialdest[res++] = digit;
01621          pvt->dialdest[res] = '\0';
01622       }
01623       goto out;
01624    }
01625 #endif
01626    if ((dtmf = digit_to_dtmfindex(digit)) == -1)
01627       goto out;
01628 
01629    if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &dtmf)) {
01630       int res;
01631       struct dahdi_dialoperation zo = {
01632          .op = DAHDI_DIAL_OP_APPEND,
01633       };
01634 
01635       zo.dialstr[0] = 'T';
01636       zo.dialstr[1] = digit;
01637       zo.dialstr[2] = '\0';
01638       if ((res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo)))
01639          ast_log(LOG_WARNING, "Couldn't dial digit %c: %s\n", digit, strerror(errno));
01640       else
01641          pvt->dialing = 1;
01642    } else {
01643       ast_debug(1, "Started VLDTMF digit '%c'\n", digit);
01644       pvt->dialing = 1;
01645       pvt->begindigit = digit;
01646    }
01647 
01648 out:
01649    ast_mutex_unlock(&pvt->lock);
01650 
01651    return 0;
01652 }
01653 
01654 static int dahdi_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
01655 {
01656    struct dahdi_pvt *pvt;
01657    int res = 0;
01658    int idx;
01659    int x;
01660    
01661    pvt = chan->tech_pvt;
01662 
01663    ast_mutex_lock(&pvt->lock);
01664    
01665    idx = dahdi_get_index(chan, pvt, 0);
01666 
01667    if ((idx != SUB_REAL) || !pvt->owner || pvt->pulse)
01668       goto out;
01669 
01670 #ifdef HAVE_PRI
01671    /* This means that the digit was already sent via PRI signalling */
01672    if (((pvt->sig == SIG_PRI) || (pvt->sig == SIG_BRI) || (pvt->sig == SIG_BRI_PTMP))
01673          && !pvt->begindigit)
01674       goto out;
01675 #endif
01676 
01677    if (pvt->begindigit) {
01678       x = -1;
01679       ast_debug(1, "Ending VLDTMF digit '%c'\n", digit);
01680       res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &x);
01681       pvt->dialing = 0;
01682       pvt->begindigit = 0;
01683    }
01684 
01685 out:
01686    ast_mutex_unlock(&pvt->lock);
01687 
01688    return res;
01689 }
01690 
01691 static char *events[] = {
01692    "No event",
01693    "On hook",
01694    "Ring/Answered",
01695    "Wink/Flash",
01696    "Alarm",
01697    "No more alarm",
01698    "HDLC Abort",
01699    "HDLC Overrun",
01700    "HDLC Bad FCS",
01701    "Dial Complete",
01702    "Ringer On",
01703    "Ringer Off",
01704    "Hook Transition Complete",
01705    "Bits Changed",
01706    "Pulse Start",
01707    "Timer Expired",
01708    "Timer Ping",
01709    "Polarity Reversal",
01710    "Ring Begin",
01711 };
01712 
01713 static struct {
01714    int alarm;
01715    char *name;
01716 } alarms[] = {
01717    { DAHDI_ALARM_RED, "Red Alarm" },
01718    { DAHDI_ALARM_YELLOW, "Yellow Alarm" },
01719    { DAHDI_ALARM_BLUE, "Blue Alarm" },
01720    { DAHDI_ALARM_RECOVER, "Recovering" },
01721    { DAHDI_ALARM_LOOPBACK, "Loopback" },
01722    { DAHDI_ALARM_NOTOPEN, "Not Open" },
01723    { DAHDI_ALARM_NONE, "None" },
01724 };
01725 
01726 static char *alarm2str(int alm)
01727 {
01728    int x;
01729    for (x = 0; x < ARRAY_LEN(alarms); x++) {
01730       if (alarms[x].alarm & alm)
01731          return alarms[x].name;
01732    }
01733    return alm ? "Unknown Alarm" : "No Alarm";
01734 }
01735 
01736 static char *event2str(int event)
01737 {
01738    static char buf[256];
01739    if ((event < (ARRAY_LEN(events))) && (event > -1))
01740       return events[event];
01741    sprintf(buf, "Event %d", event); /* safe */
01742    return buf;
01743 }
01744 
01745 #ifdef HAVE_PRI
01746 static char *dialplan2str(int dialplan)
01747 {
01748    if (dialplan == -1 || dialplan == -2) {
01749       return("Dynamically set dialplan in ISDN");
01750    }
01751    return (pri_plan2str(dialplan));
01752 }
01753 #endif
01754 
01755 static char *dahdi_sig2str(int sig)
01756 {
01757    static char buf[256];
01758    switch (sig) {
01759    case SIG_EM:
01760       return "E & M Immediate";
01761    case SIG_EMWINK:
01762       return "E & M Wink";
01763    case SIG_EM_E1:
01764       return "E & M E1";
01765    case SIG_FEATD:
01766       return "Feature Group D (DTMF)";
01767    case SIG_FEATDMF:
01768       return "Feature Group D (MF)";
01769    case SIG_FEATDMF_TA:
01770       return "Feature Groud D (MF) Tandem Access";
01771    case SIG_FEATB:
01772       return "Feature Group B (MF)";
01773    case SIG_E911:
01774       return "E911 (MF)";
01775    case SIG_FGC_CAMA:
01776       return "FGC/CAMA (Dialpulse)";
01777    case SIG_FGC_CAMAMF:
01778       return "FGC/CAMA (MF)";
01779    case SIG_FXSLS:
01780       return "FXS Loopstart";
01781    case SIG_FXSGS:
01782       return "FXS Groundstart";
01783    case SIG_FXSKS:
01784       return "FXS Kewlstart";
01785    case SIG_FXOLS:
01786       return "FXO Loopstart";
01787    case SIG_FXOGS:
01788       return "FXO Groundstart";
01789    case SIG_FXOKS:
01790       return "FXO Kewlstart";
01791    case SIG_PRI:
01792       return "ISDN PRI";
01793    case SIG_BRI:
01794       return "ISDN BRI Point to Point";
01795    case SIG_BRI_PTMP:
01796       return "ISDN BRI Point to MultiPoint";
01797    case SIG_SS7:
01798       return "SS7";
01799    case SIG_SF:
01800       return "SF (Tone) Immediate";
01801    case SIG_SFWINK:
01802       return "SF (Tone) Wink";
01803    case SIG_SF_FEATD:
01804       return "SF (Tone) with Feature Group D (DTMF)";
01805    case SIG_SF_FEATDMF:
01806       return "SF (Tone) with Feature Group D (MF)";
01807    case SIG_SF_FEATB:
01808       return "SF (Tone) with Feature Group B (MF)";
01809    case SIG_GR303FXOKS:
01810       return "GR-303 with FXOKS";
01811    case SIG_GR303FXSKS:
01812       return "GR-303 with FXSKS";
01813    case 0:
01814       return "Pseudo";
01815    default:
01816       snprintf(buf, sizeof(buf), "Unknown signalling %d", sig);
01817       return buf;
01818    }
01819 }
01820 
01821 #define sig2str dahdi_sig2str
01822 
01823 static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx, int slavechannel)
01824 {
01825    /* If the conference already exists, and we're already in it
01826       don't bother doing anything */
01827    struct dahdi_confinfo zi;
01828    
01829    memset(&zi, 0, sizeof(zi));
01830    zi.chan = 0;
01831 
01832    if (slavechannel > 0) {
01833       /* If we have only one slave, do a digital mon */
01834       zi.confmode = DAHDI_CONF_DIGITALMON;
01835       zi.confno = slavechannel;
01836    } else {
01837       if (!idx) {
01838          /* Real-side and pseudo-side both participate in conference */
01839          zi.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER |
01840             DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
01841       } else
01842          zi.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
01843       zi.confno = p->confno;
01844    }
01845    if ((zi.confno == c->curconf.confno) && (zi.confmode == c->curconf.confmode))
01846       return 0;
01847    if (c->dfd < 0)
01848       return 0;
01849    if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
01850       ast_log(LOG_WARNING, "Failed to add %d to conference %d/%d: %s\n", c->dfd, zi.confmode, zi.confno, strerror(errno));
01851       return -1;
01852    }
01853    if (slavechannel < 1) {
01854       p->confno = zi.confno;
01855    }
01856    memcpy(&c->curconf, &zi, sizeof(c->curconf));
01857    ast_debug(1, "Added %d to conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
01858    return 0;
01859 }
01860 
01861 static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c)
01862 {
01863    /* If they're listening to our channel, they're ours */  
01864    if ((p->channel == c->curconf.confno) && (c->curconf.confmode == DAHDI_CONF_DIGITALMON))
01865       return 1;
01866    /* If they're a talker on our (allocated) conference, they're ours */
01867    if ((p->confno > 0) && (p->confno == c->curconf.confno) && (c->curconf.confmode & DAHDI_CONF_TALKER))
01868       return 1;
01869    return 0;
01870 }
01871 
01872 static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx)
01873 {
01874    struct dahdi_confinfo zi;
01875    if (/* Can't delete if there's no dfd */
01876       (c->dfd < 0) ||
01877       /* Don't delete from the conference if it's not our conference */
01878       !isourconf(p, c)
01879       /* Don't delete if we don't think it's conferenced at all (implied) */
01880       ) return 0;
01881    memset(&zi, 0, sizeof(zi));
01882    if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
01883       ast_log(LOG_WARNING, "Failed to drop %d from conference %d/%d: %s\n", c->dfd, c->curconf.confmode, c->curconf.confno, strerror(errno));
01884       return -1;
01885    }
01886    ast_debug(1, "Removed %d from conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
01887    memcpy(&c->curconf, &zi, sizeof(c->curconf));
01888    return 0;
01889 }
01890 
01891 static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out)
01892 {
01893    int x;
01894    int useslavenative;
01895    struct dahdi_pvt *slave = NULL;
01896    /* Start out optimistic */
01897    useslavenative = 1;
01898    /* Update conference state in a stateless fashion */
01899    for (x = 0; x < 3; x++) {
01900       /* Any three-way calling makes slave native mode *definitely* out
01901          of the question */
01902       if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway)
01903          useslavenative = 0;
01904    }
01905    /* If we don't have any 3-way calls, check to see if we have
01906       precisely one slave */
01907    if (useslavenative) {
01908       for (x = 0; x < MAX_SLAVES; x++) {
01909          if (p->slaves[x]) {
01910             if (slave) {
01911                /* Whoops already have a slave!  No 
01912                   slave native and stop right away */
01913                slave = NULL;
01914                useslavenative = 0;
01915                break;
01916             } else {
01917                /* We have one slave so far */
01918                slave = p->slaves[x];
01919             }
01920          }
01921       }
01922    }
01923    /* If no slave, slave native definitely out */
01924    if (!slave)
01925       useslavenative = 0;
01926    else if (slave->law != p->law) {
01927       useslavenative = 0;
01928       slave = NULL;
01929    }
01930    if (out)
01931       *out = slave;
01932    return useslavenative;
01933 }
01934 
01935 static int reset_conf(struct dahdi_pvt *p)
01936 {
01937    p->confno = -1;
01938    memset(&p->subs[SUB_REAL].curconf, 0, sizeof(p->subs[SUB_REAL].curconf));
01939    if (p->subs[SUB_REAL].dfd > -1) {
01940       struct dahdi_confinfo zi;
01941 
01942       memset(&zi, 0, sizeof(zi));
01943       if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &zi))
01944          ast_log(LOG_WARNING, "Failed to reset conferencing on channel %d: %s\n", p->channel, strerror(errno));
01945    }
01946    return 0;
01947 }
01948 
01949 static int update_conf(struct dahdi_pvt *p)
01950 {
01951    int needconf = 0;
01952    int x;
01953    int useslavenative;
01954    struct dahdi_pvt *slave = NULL;
01955 
01956    useslavenative = isslavenative(p, &slave);
01957    /* Start with the obvious, general stuff */
01958    for (x = 0; x < 3; x++) {
01959       /* Look for three way calls */
01960       if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway) {
01961          conf_add(p, &p->subs[x], x, 0);
01962          needconf++;
01963       } else {
01964          conf_del(p, &p->subs[x], x);
01965       }
01966    }
01967    /* If we have a slave, add him to our conference now. or DAX
01968       if this is slave native */
01969    for (x = 0; x < MAX_SLAVES; x++) {
01970       if (p->slaves[x]) {
01971          if (useslavenative)
01972             conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
01973          else {
01974             conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
01975             needconf++;
01976          }
01977       }
01978    }
01979    /* If we're supposed to be in there, do so now */
01980    if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
01981       if (useslavenative)
01982          conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
01983       else {
01984          conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
01985          needconf++;
01986       }
01987    }
01988    /* If we have a master, add ourselves to his conference */
01989    if (p->master) {
01990       if (isslavenative(p->master, NULL)) {
01991          conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p->master));
01992       } else {
01993          conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
01994       }
01995    }
01996    if (!needconf) {
01997       /* Nobody is left (or should be left) in our conference.
01998          Kill it. */
01999       p->confno = -1;
02000    }
02001    ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
02002    return 0;
02003 }
02004 
02005 static void dahdi_enable_ec(struct dahdi_pvt *p)
02006 {
02007    int x;
02008    int res;
02009    if (!p)
02010       return;
02011    if (p->echocanon) {
02012       ast_debug(1, "Echo cancellation already on\n");
02013       return;
02014    }
02015    if (p->digital) {
02016       ast_debug(1, "Echo cancellation isn't required on digital connection\n");
02017       return;
02018    }
02019    if (p->echocancel.head.tap_length) {
02020       if ((p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP) || (p->sig == SIG_PRI) || (p->sig == SIG_SS7)) {
02021          x = 1;
02022          res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x);
02023          if (res)
02024             ast_log(LOG_WARNING, "Unable to enable audio mode on channel %d (%s)\n", p->channel, strerror(errno));
02025       }
02026       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &p->echocancel);
02027       if (res)  {
02028          ast_log(LOG_WARNING, "Unable to enable echo cancellation on channel %d (%s)\n", p->channel, strerror(errno));
02029       } else {
02030          p->echocanon = 1;
02031          ast_debug(1, "Enabled echo cancellation on channel %d\n", p->channel);
02032       }
02033    } else
02034       ast_debug(1, "No echo cancellation requested\n");
02035 }
02036 
02037 static void dahdi_train_ec(struct dahdi_pvt *p)
02038 {
02039    int x;
02040    int res;
02041    
02042    if (p && p->echocanon && p->echotraining) {
02043       x = p->echotraining;
02044       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOTRAIN, &x);
02045       if (res)
02046          ast_log(LOG_WARNING, "Unable to request echo training on channel %d: %s\n", p->channel, strerror(errno));
02047       else
02048          ast_debug(1, "Engaged echo training on channel %d\n", p->channel);
02049    } else {
02050       ast_debug(1, "No echo training requested\n");
02051    }
02052 }
02053 
02054 static void dahdi_disable_ec(struct dahdi_pvt *p)
02055 {
02056    int res;
02057 
02058    if (p->echocanon) {
02059       struct dahdi_echocanparams ecp = { .tap_length = 0 };
02060 
02061       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &ecp);
02062 
02063       if (res)
02064          ast_log(LOG_WARNING, "Unable to disable echo cancellation on channel %d: %s\n", p->channel, strerror(errno));
02065       else
02066          ast_debug(1, "Disabled echo cancellation on channel %d\n", p->channel);
02067    }
02068 
02069    p->echocanon = 0;
02070 }
02071 
02072 static void fill_txgain(struct dahdi_gains *g, float gain, int law)
02073 {
02074    int j;
02075    int k;
02076    float linear_gain = pow(10.0, gain / 20.0);
02077 
02078    switch (law) {
02079    case DAHDI_LAW_ALAW:
02080       for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
02081          if (gain) {
02082             k = (int) (((float) AST_ALAW(j)) * linear_gain);
02083             if (k > 32767) k = 32767;
02084             if (k < -32767) k = -32767;
02085             g->txgain[j] = AST_LIN2A(k);
02086          } else {
02087             g->txgain[j] = j;
02088          }
02089       }
02090       break;
02091    case DAHDI_LAW_MULAW:
02092       for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
02093          if (gain) {
02094             k = (int) (((float) AST_MULAW(j)) * linear_gain);
02095             if (k > 32767) k = 32767;
02096             if (k < -32767) k = -32767;
02097             g->txgain[j] = AST_LIN2MU(k);
02098          } else {
02099             g->txgain[j] = j;
02100          }
02101       }
02102       break;
02103    }
02104 }
02105 
02106 static void fill_rxgain(struct dahdi_gains *g, float gain, int law)
02107 {
02108    int j;
02109    int k;
02110    float linear_gain = pow(10.0, gain / 20.0);
02111 
02112    switch (law) {
02113    case DAHDI_LAW_ALAW:
02114       for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
02115          if (gain) {
02116             k = (int) (((float) AST_ALAW(j)) * linear_gain);
02117             if (k > 32767) k = 32767;
02118             if (k < -32767) k = -32767;
02119             g->rxgain[j] = AST_LIN2A(k);
02120          } else {
02121             g->rxgain[j] = j;
02122          }
02123       }
02124       break;
02125    case DAHDI_LAW_MULAW:
02126       for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
02127          if (gain) {
02128             k = (int) (((float) AST_MULAW(j)) * linear_gain);
02129             if (k > 32767) k = 32767;
02130             if (k < -32767) k = -32767;
02131             g->rxgain[j] = AST_LIN2MU(k);
02132          } else {
02133             g->rxgain[j] = j;
02134          }
02135       }
02136       break;
02137    }
02138 }
02139 
02140 static int set_actual_txgain(int fd, int chan, float gain, int law)
02141 {
02142    struct dahdi_gains g;
02143    int res;
02144 
02145    memset(&g, 0, sizeof(g));
02146    g.chan = chan;
02147    res = ioctl(fd, DAHDI_GETGAINS, &g);
02148    if (res) {
02149       ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
02150       return res;
02151    }
02152 
02153    fill_txgain(&g, gain, law);
02154 
02155    return ioctl(fd, DAHDI_SETGAINS, &g);
02156 }
02157 
02158 static int set_actual_rxgain(int fd, int chan, float gain, int law)
02159 {
02160    struct dahdi_gains g;
02161    int res;
02162 
02163    memset(&g, 0, sizeof(g));
02164    g.chan = chan;
02165    res = ioctl(fd, DAHDI_GETGAINS, &g);
02166    if (res) {
02167       ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
02168       return res;
02169    }
02170 
02171    fill_rxgain(&g, gain, law);
02172 
02173    return ioctl(fd, DAHDI_SETGAINS, &g);
02174 }
02175 
02176 static int set_actual_gain(int fd, int chan, float rxgain, float txgain, int law)
02177 {
02178    return set_actual_txgain(fd, chan, txgain, law) | set_actual_rxgain(fd, chan, rxgain, law);
02179 }
02180 
02181 static int bump_gains(struct dahdi_pvt *p)
02182 {
02183    int res;
02184 
02185    /* Bump receive gain by value stored in cid_rxgain */
02186    res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain + p->cid_rxgain, p->txgain, p->law);
02187    if (res) {
02188       ast_log(LOG_WARNING, "Unable to bump gain: %s\n", strerror(errno));
02189       return -1;
02190    }
02191 
02192    return 0;
02193 }
02194 
02195 static int restore_gains(struct dahdi_pvt *p)
02196 {
02197    int res;
02198 
02199    res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law);
02200    if (res) {
02201       ast_log(LOG_WARNING, "Unable to restore gains: %s\n", strerror(errno));
02202       return -1;
02203    }
02204 
02205    return 0;
02206 }
02207 
02208 static inline int dahdi_set_hook(int fd, int hs)
02209 {
02210    int x, res;
02211 
02212    x = hs;
02213    res = ioctl(fd, DAHDI_HOOK, &x);
02214 
02215    if (res < 0) {
02216       if (errno == EINPROGRESS)
02217          return 0;
02218       ast_log(LOG_WARNING, "DAHDI hook failed returned %d (trying %d): %s\n", res, hs, strerror(errno));
02219       /* will expectedly fail if phone is off hook during operation, such as during a restart */
02220    }
02221 
02222    return res;
02223 }
02224 
02225 static inline int dahdi_confmute(struct dahdi_pvt *p, int muted)
02226 {
02227    int x, y, res;
02228    x = muted;
02229    if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
02230       y = 1;
02231       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &y);
02232       if (res)
02233          ast_log(LOG_WARNING, "Unable to set audio mode on %d: %s\n", p->channel, strerror(errno));
02234    }
02235    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_CONFMUTE, &x);
02236    if (res < 0)
02237       ast_log(LOG_WARNING, "DAHDI confmute(%d) failed on channel %d: %s\n", muted, p->channel, strerror(errno));
02238    return res;
02239 }
02240 
02241 static int save_conference(struct dahdi_pvt *p)
02242 {
02243    struct dahdi_confinfo c;
02244    int res;
02245    if (p->saveconf.confmode) {
02246       ast_log(LOG_WARNING, "Can't save conference -- already in use\n");
02247       return -1;
02248    }
02249    p->saveconf.chan = 0;
02250    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &p->saveconf);
02251    if (res) {
02252       ast_log(LOG_WARNING, "Unable to get conference info: %s\n", strerror(errno));
02253       p->saveconf.confmode = 0;
02254       return -1;
02255    }
02256    memset(&c, 0, sizeof(c));
02257    c.confmode = DAHDI_CONF_NORMAL;
02258    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &c);
02259    if (res) {
02260       ast_log(LOG_WARNING, "Unable to set conference info: %s\n", strerror(errno));
02261       return -1;
02262    }
02263    ast_debug(1, "Disabled conferencing\n");
02264    return 0;
02265 }
02266 
02267 /*!
02268  * \brief Send MWI state change
02269  *
02270  * \arg mailbox_full This is the mailbox associated with the FXO line that the
02271  *      MWI state has changed on.
02272  * \arg thereornot This argument should simply be set to 1 or 0, to indicate
02273  *      whether there are messages waiting or not.
02274  *
02275  *  \return nothing
02276  *
02277  * This function does two things:
02278  *
02279  * 1) It generates an internal Asterisk event notifying any other module that
02280  *    cares about MWI that the state of a mailbox has changed.
02281  *
02282  * 2) It runs the script specified by the mwimonitornotify option to allow
02283  *    some custom handling of the state change.
02284  */
02285 static void notify_message(char *mailbox_full, int thereornot)
02286 {
02287    char s[sizeof(mwimonitornotify) + 80];
02288    struct ast_event *event;
02289    char *mailbox, *context;
02290 
02291    /* Strip off @default */
02292    context = mailbox = ast_strdupa(mailbox_full);
02293    strsep(&context, "@");
02294    if (ast_strlen_zero(context))
02295       context = "default";
02296 
02297    if (!(event = ast_event_new(AST_EVENT_MWI,
02298          AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
02299          AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
02300          AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
02301          AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
02302          AST_EVENT_IE_END))) {
02303       return;
02304    }
02305 
02306    ast_event_queue_and_cache(event);
02307 
02308    if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(mwimonitornotify)) {
02309       snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
02310       ast_safe_system(s);
02311    }
02312 }
02313 
02314 static int restore_conference(struct dahdi_pvt *p)
02315 {
02316    int res;
02317    if (p->saveconf.confmode) {
02318       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &p->saveconf);
02319       p->saveconf.confmode = 0;
02320       if (res) {
02321          ast_log(LOG_WARNING, "Unable to restore conference info: %s\n", strerror(errno));
02322          return -1;
02323       }
02324    }
02325    ast_debug(1, "Restored conferencing\n");
02326    return 0;
02327 }
02328 
02329 static int send_callerid(struct dahdi_pvt *p);
02330 
02331 static int send_cwcidspill(struct dahdi_pvt *p)
02332 {
02333    p->callwaitcas = 0;
02334    p->cidcwexpire = 0;
02335    if (!(p->cidspill = ast_malloc(MAX_CALLERID_SIZE)))
02336       return -1;
02337    p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, p->callwait_name, p->callwait_num, AST_LAW(p));
02338    /* Make sure we account for the end */
02339    p->cidlen += READ_SIZE * 4;
02340    p->cidpos = 0;
02341    send_callerid(p);
02342    ast_verb(3, "CPE supports Call Waiting Caller*ID.  Sending '%s/%s'\n", p->callwait_name, p->callwait_num);
02343    return 0;
02344 }
02345 
02346 static int has_voicemail(struct dahdi_pvt *p)
02347 {
02348    int new_msgs;
02349    struct ast_event *event;
02350    char *mailbox, *context;
02351 
02352    mailbox = context = ast_strdupa(p->mailbox);
02353    strsep(&context, "@");
02354    if (ast_strlen_zero(context))
02355       context = "default";
02356 
02357    event = ast_event_get_cached(AST_EVENT_MWI,
02358       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
02359       AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
02360       AST_EVENT_IE_END);
02361 
02362    if (event) {
02363       new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
02364       ast_event_destroy(event);
02365    } else
02366       new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
02367 
02368    return new_msgs;
02369 }
02370 
02371 static int send_callerid(struct dahdi_pvt *p)
02372 {
02373    /* Assumes spill in p->cidspill, p->cidlen in length and we're p->cidpos into it */
02374    int res;
02375    /* Take out of linear mode if necessary */
02376    if (p->subs[SUB_REAL].linear) {
02377       p->subs[SUB_REAL].linear = 0;
02378       dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
02379    }
02380    while (p->cidpos < p->cidlen) {
02381       res = write(p->subs[SUB_REAL].dfd, p->cidspill + p->cidpos, p->cidlen - p->cidpos);
02382       if (res < 0) {
02383          if (errno == EAGAIN)
02384             return 0;
02385          else {
02386             ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
02387             return -1;
02388          }
02389       }
02390       if (!res)
02391          return 0;
02392       p->cidpos += res;
02393    }
02394    ast_free(p->cidspill);
02395    p->cidspill = NULL;
02396    if (p->callwaitcas) {
02397       /* Wait for CID/CW to expire */
02398       p->cidcwexpire = CIDCW_EXPIRE_SAMPLES;
02399    } else
02400       restore_conference(p);
02401    return 0;
02402 }
02403 
02404 static int dahdi_callwait(struct ast_channel *ast)
02405 {
02406    struct dahdi_pvt *p = ast->tech_pvt;
02407    p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES;
02408    if (p->cidspill) {
02409       ast_log(LOG_WARNING, "Spill already exists?!?\n");
02410       ast_free(p->cidspill);
02411    }
02412    if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
02413       return -1;
02414    save_conference(p);
02415    /* Silence */
02416    memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
02417    if (!p->callwaitrings && p->callwaitingcallerid) {
02418       ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
02419       p->callwaitcas = 1;
02420       p->cidlen = 2400 + 680 + READ_SIZE * 4;
02421    } else {
02422       ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
02423       p->callwaitcas = 0;
02424       p->cidlen = 2400 + READ_SIZE * 4;
02425    }
02426    p->cidpos = 0;
02427    send_callerid(p);
02428    
02429    return 0;
02430 }
02431 
02432 #ifdef HAVE_SS7
02433 static unsigned char cid_pres2ss7pres(int cid_pres)
02434 {
02435     return (cid_pres >> 5) & 0x03;
02436 }
02437 
02438 static unsigned char cid_pres2ss7screen(int cid_pres)
02439 {
02440    return cid_pres & 0x03;
02441 }
02442 #endif
02443 
02444 static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
02445 {
02446    struct dahdi_pvt *p = ast->tech_pvt;
02447    int x, res, idx,mysig;
02448    char *c, *n, *l;
02449 #ifdef HAVE_PRI
02450    char *s = NULL;
02451 #endif
02452    char dest[256]; /* must be same length as p->dialdest */
02453    ast_mutex_lock(&p->lock);
02454    ast_copy_string(dest, rdest, sizeof(dest));
02455    ast_copy_string(p->dialdest, rdest, sizeof(p->dialdest));
02456    if ((ast->_state == AST_STATE_BUSY)) {
02457       p->subs[SUB_REAL].needbusy = 1;
02458       ast_mutex_unlock(&p->lock);
02459       return 0;
02460    }
02461    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
02462       ast_log(LOG_WARNING, "dahdi_call called on %s, neither down nor reserved\n", ast->name);
02463       ast_mutex_unlock(&p->lock);
02464       return -1;
02465    }
02466    p->dialednone = 0;
02467    if ((p->radio || (p->oprmode < 0)))  /* if a radio channel, up immediately */
02468    {
02469       /* Special pseudo -- automatically up */
02470       ast_setstate(ast, AST_STATE_UP); 
02471       ast_mutex_unlock(&p->lock);
02472       return 0;
02473    }
02474    x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE;
02475    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
02476    if (res)
02477       ast_log(LOG_WARNING, "Unable to flush input on channel %d: %s\n", p->channel, strerror(errno));
02478    p->outgoing = 1;
02479 
02480    if (IS_DIGITAL(ast->transfercapability)){
02481       set_actual_gain(p->subs[SUB_REAL].dfd, 0, 0, 0, p->law);
02482    } else {
02483       set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law);
02484    }  
02485 
02486    mysig = p->sig;
02487    if (p->outsigmod > -1)
02488       mysig = p->outsigmod;
02489 
02490    switch (mysig) {
02491    case SIG_FXOLS:
02492    case SIG_FXOGS:
02493    case SIG_FXOKS:
02494       if (p->owner == ast) {
02495          /* Normal ring, on hook */
02496          
02497          /* Don't send audio while on hook, until the call is answered */
02498          p->dialing = 1;
02499          if (p->use_callerid) {
02500             /* Generate the Caller-ID spill if desired */
02501             if (p->cidspill) {
02502                ast_log(LOG_WARNING, "cidspill already exists??\n");
02503                ast_free(p->cidspill);
02504             }
02505             p->callwaitcas = 0;
02506             if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) {
02507                p->cidlen = ast_callerid_generate(p->cidspill, ast->cid.cid_name, ast->cid.cid_num, AST_LAW(p));
02508                p->cidpos = 0;
02509                send_callerid(p);
02510             }
02511          }
02512          /* Choose proper cadence */
02513          if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
02514             if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
02515                ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast->name, strerror(errno));
02516             p->cidrings = cidrings[p->distinctivering - 1];
02517          } else {
02518             if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
02519                ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast->name, strerror(errno));
02520             p->cidrings = p->sendcalleridafter;
02521          }
02522 
02523          /* nick@dccinc.com 4/3/03 mods to allow for deferred dialing */
02524          c = strchr(dest, '/');
02525          if (c)
02526             c++;
02527          if (c && (strlen(c) < p->stripmsd)) {
02528             ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
02529             c = NULL;
02530          }
02531          if (c) {
02532             p->dop.op = DAHDI_DIAL_OP_REPLACE;
02533             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "Tw%s", c);
02534             ast_debug(1, "FXO: setup deferred dialstring: %s\n", c);
02535          } else {
02536             p->dop.dialstr[0] = '\0';
02537          }
02538          x = DAHDI_RING;
02539          if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x) && (errno != EINPROGRESS)) {
02540             ast_log(LOG_WARNING, "Unable to ring phone: %s\n", strerror(errno));
02541             ast_mutex_unlock(&p->lock);
02542             return -1;
02543          }
02544          p->dialing = 1;
02545       } else {
02546          /* Call waiting call */
02547          p->callwaitrings = 0;
02548          if (ast->cid.cid_num)
02549             ast_copy_string(p->callwait_num, ast->cid.cid_num, sizeof(p->callwait_num));
02550          else
02551             p->callwait_num[0] = '\0';
02552          if (ast->cid.cid_name)
02553             ast_copy_string(p->callwait_name, ast->cid.cid_name, sizeof(p->callwait_name));
02554          else
02555             p->callwait_name[0] = '\0';
02556          /* Call waiting tone instead */
02557          if (dahdi_callwait(ast)) {
02558             ast_mutex_unlock(&p->lock);
02559             return -1;
02560          }
02561          /* Make ring-back */
02562          if (tone_zone_play_tone(p->subs[SUB_CALLWAIT].dfd, DAHDI_TONE_RINGTONE))
02563             ast_log(LOG_WARNING, "Unable to generate call-wait ring-back on channel %s\n", ast->name);
02564             
02565       }
02566       n = ast->cid.cid_name;
02567       l = ast->cid.cid_num;
02568       if (l)
02569          ast_copy_string(p->lastcid_num, l, sizeof(p->lastcid_num));
02570       else
02571          p->lastcid_num[0] = '\0';
02572       if (n)
02573          ast_copy_string(p->lastcid_name, n, sizeof(p->lastcid_name));
02574       else
02575          p->lastcid_name[0] = '\0';
02576       ast_setstate(ast, AST_STATE_RINGING);
02577       idx = dahdi_get_index(ast, p, 0);
02578       if (idx > -1) {
02579          p->subs[idx].needringing = 1;
02580       }
02581       break;
02582    case SIG_FXSLS:
02583    case SIG_FXSGS:
02584    case SIG_FXSKS:
02585       if (p->answeronpolarityswitch || p->hanguponpolarityswitch) {
02586          ast_debug(1, "Ignore possible polarity reversal on line seizure\n");
02587          p->polaritydelaytv = ast_tvnow();
02588       }
02589       /* fall through */
02590    case SIG_EMWINK:
02591    case SIG_EM:
02592    case SIG_EM_E1:
02593    case SIG_FEATD:
02594    case SIG_FEATDMF:
02595    case SIG_E911:
02596    case SIG_FGC_CAMA:
02597    case SIG_FGC_CAMAMF:
02598    case SIG_FEATB:
02599    case SIG_SFWINK:
02600    case SIG_SF:
02601    case SIG_SF_FEATD:
02602    case SIG_SF_FEATDMF:
02603    case SIG_FEATDMF_TA:
02604    case SIG_SF_FEATB:
02605       c = strchr(dest, '/');
02606       if (c)
02607          c++;
02608       else
02609          c = "";
02610       if (strlen(c) < p->stripmsd) {
02611          ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
02612          ast_mutex_unlock(&p->lock);
02613          return -1;
02614       }
02615 #ifdef HAVE_PRI
02616       /* Start the trunk, if not GR-303 */
02617       if (!p->pri) {
02618 #endif
02619          x = DAHDI_START;
02620          res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
02621          if (res < 0) {
02622             if (errno != EINPROGRESS) {
02623                ast_log(LOG_WARNING, "Unable to start channel: %s\n", strerror(errno));
02624                ast_mutex_unlock(&p->lock);
02625                return -1;
02626             }
02627          }
02628 #ifdef HAVE_PRI
02629       }
02630 #endif
02631       ast_debug(1, "Dialing '%s'\n", c);
02632       p->dop.op = DAHDI_DIAL_OP_REPLACE;
02633 
02634       c += p->stripmsd;
02635 
02636       switch (mysig) {
02637       case SIG_FEATD:
02638          l = ast->cid.cid_num;
02639          if (l) 
02640             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T*%s*%s*", l, c);
02641          else
02642             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T**%s*", c);
02643          break;
02644       case SIG_FEATDMF:
02645          l = ast->cid.cid_num;
02646          if (l) 
02647             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*00%s#*%s#", l, c);
02648          else
02649             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*02#*%s#", c);
02650          break;
02651       case SIG_FEATDMF_TA:
02652       {
02653          const char *cic, *ozz;
02654 
02655          /* If you have to go through a Tandem Access point you need to use this */
02656          ozz = pbx_builtin_getvar_helper(p->owner, "FEATDMF_OZZ");
02657          if (!ozz)
02658             ozz = defaultozz;
02659          cic = pbx_builtin_getvar_helper(p->owner, "FEATDMF_CIC");
02660          if (!cic)
02661             cic = defaultcic;
02662          if (!ozz || !cic) {
02663             ast_log(LOG_WARNING, "Unable to dial channel of type feature group D MF tandem access without CIC or OZZ set\n");
02664             ast_mutex_unlock(&p->lock);
02665             return -1;
02666          }
02667          snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s%s#", ozz, cic);
02668          snprintf(p->finaldial, sizeof(p->finaldial), "M*%s#", c);
02669          p->whichwink = 0;
02670       }
02671          break;
02672       case SIG_E911:
02673          ast_copy_string(p->dop.dialstr, "M*911#", sizeof(p->dop.dialstr));
02674          break;
02675       case SIG_FGC_CAMA:
02676          snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%s", c);
02677          break;
02678       case SIG_FGC_CAMAMF:
02679       case SIG_FEATB:
02680          snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s#", c);
02681          break;
02682       default:
02683          if (p->pulse)
02684             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%sw", c);
02685          else
02686             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T%sw", c);
02687          break;
02688       }
02689 
02690       if (p->echotraining && (strlen(p->dop.dialstr) > 4)) {
02691          memset(p->echorest, 'w', sizeof(p->echorest) - 1);
02692          strcpy(p->echorest + (p->echotraining / 400) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
02693          p->echorest[sizeof(p->echorest) - 1] = '\0';
02694          p->echobreak = 1;
02695          p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
02696       } else
02697          p->echobreak = 0;
02698       if (!res) {
02699          if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
02700             int saveerr = errno;
02701 
02702             x = DAHDI_ONHOOK;
02703             ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
02704             ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
02705             ast_mutex_unlock(&p->lock);
02706             return -1;
02707          }
02708       } else
02709          ast_debug(1, "Deferring dialing...\n");
02710 
02711       p->dialing = 1;
02712       if (ast_strlen_zero(c))
02713          p->dialednone = 1;
02714       ast_setstate(ast, AST_STATE_DIALING);
02715       break;
02716    case 0:
02717       /* Special pseudo -- automatically up*/
02718       ast_setstate(ast, AST_STATE_UP);
02719       break;      
02720    case SIG_PRI:
02721    case SIG_BRI:
02722    case SIG_BRI_PTMP:
02723    case SIG_SS7:
02724       /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
02725       p->dialdest[0] = '\0';
02726       p->dialing = 1;
02727       break;
02728    default:
02729       ast_debug(1, "not yet implemented\n");
02730       ast_mutex_unlock(&p->lock);
02731       return -1;
02732    }
02733 #ifdef HAVE_SS7
02734    if (p->ss7) {
02735       char ss7_called_nai;
02736       int called_nai_strip;
02737       char ss7_calling_nai;
02738       int calling_nai_strip;
02739       const char *charge_str = NULL;
02740       const char *gen_address = NULL;
02741       const char *gen_digits = NULL;
02742       const char *gen_dig_type = NULL;
02743       const char *gen_dig_scheme = NULL;
02744       const char *gen_name = NULL;
02745       const char *jip_digits = NULL;
02746       const char *lspi_ident = NULL;
02747       const char *rlt_flag = NULL;
02748       const char *call_ref_id = NULL;
02749       const char *call_ref_pc = NULL;
02750       const char *send_far = NULL;
02751 
02752       c = strchr(dest, '/');
02753       if (c) {
02754          c++;
02755       } else {
02756          c = "";
02757       }
02758       if (strlen(c) < p->stripmsd) {
02759          ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
02760          ast_mutex_unlock(&p->lock);
02761          return -1;
02762       }
02763 
02764       if (!p->hidecallerid) {
02765          l = ast->cid.cid_num;
02766       } else {
02767          l = NULL;
02768       }
02769 
02770       if (ss7_grab(p, p->ss7)) {
02771          ast_log(LOG_WARNING, "Failed to grab SS7!\n");
02772          ast_mutex_unlock(&p->lock);
02773          return -1;
02774       }
02775       p->digital = IS_DIGITAL(ast->transfercapability);
02776       p->ss7call = isup_new_call(p->ss7->ss7);
02777 
02778       if (!p->ss7call) {
02779          ss7_rel(p->ss7);
02780          ast_mutex_unlock(&p->lock);
02781          ast_log(LOG_ERROR, "Unable to allocate new SS7 call!\n");
02782          return -1;
02783       }
02784 
02785       called_nai_strip = 0;
02786       ss7_called_nai = p->ss7->called_nai;
02787       if (ss7_called_nai == SS7_NAI_DYNAMIC) { /* compute dynamically */
02788          if (strncmp(c + p->stripmsd, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
02789             called_nai_strip = strlen(p->ss7->internationalprefix);
02790             ss7_called_nai = SS7_NAI_INTERNATIONAL;
02791          } else if (strncmp(c + p->stripmsd, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
02792             called_nai_strip = strlen(p->ss7->nationalprefix);
02793             ss7_called_nai = SS7_NAI_NATIONAL;
02794          } else {
02795             ss7_called_nai = SS7_NAI_SUBSCRIBER;
02796          }
02797       }
02798       isup_set_called(p->ss7call, c + p->stripmsd + called_nai_strip, ss7_called_nai, p->ss7->ss7);
02799 
02800       calling_nai_strip = 0;
02801       ss7_calling_nai = p->ss7->calling_nai;
02802       if ((l != NULL) && (ss7_calling_nai == SS7_NAI_DYNAMIC)) { /* compute dynamically */
02803          if (strncmp(l, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
02804             calling_nai_strip = strlen(p->ss7->internationalprefix);
02805             ss7_calling_nai = SS7_NAI_INTERNATIONAL;
02806          } else if (strncmp(l, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
02807             calling_nai_strip = strlen(p->ss7->nationalprefix);
02808             ss7_calling_nai = SS7_NAI_NATIONAL;
02809          } else {
02810             ss7_calling_nai = SS7_NAI_SUBSCRIBER;
02811          }
02812       }
02813       isup_set_calling(p->ss7call, l ? (l + calling_nai_strip) : NULL, ss7_calling_nai,
02814          p->use_callingpres ? cid_pres2ss7pres(ast->cid.cid_pres) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED),
02815          p->use_callingpres ? cid_pres2ss7screen(ast->cid.cid_pres) : SS7_SCREENING_USER_PROVIDED );
02816 
02817       isup_set_oli(p->ss7call, ast->cid.cid_ani2);
02818       isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc);
02819 
02820       ast_channel_lock(ast);
02821       /* Set the charge number if it is set */
02822       charge_str = pbx_builtin_getvar_helper(ast, "SS7_CHARGE_NUMBER");
02823       if (charge_str)
02824          isup_set_charge(p->ss7call, charge_str, SS7_ANI_CALLING_PARTY_SUB_NUMBER, 0x10);
02825       
02826       gen_address = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_ADDRESS");
02827       if (gen_address)
02828          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 */
02829       
02830       gen_digits = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGITS");
02831       gen_dig_type = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGTYPE");
02832       gen_dig_scheme = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGSCHEME");
02833       if (gen_digits)
02834          isup_set_gen_digits(p->ss7call, gen_digits, atoi(gen_dig_type), atoi(gen_dig_scheme)); 
02835       
02836       gen_name = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_NAME");
02837       if (gen_name)
02838          isup_set_generic_name(p->ss7call, gen_name, GEN_NAME_TYPE_CALLING_NAME, GEN_NAME_AVAIL_AVAILABLE, GEN_NAME_PRES_ALLOWED);
02839 
02840       jip_digits = pbx_builtin_getvar_helper(ast, "SS7_JIP");
02841       if (jip_digits)
02842          isup_set_jip_digits(p->ss7call, jip_digits);
02843       
02844       lspi_ident = pbx_builtin_getvar_helper(ast, "SS7_LSPI_IDENT");
02845       if (lspi_ident)
02846          isup_set_lspi(p->ss7call, lspi_ident, 0x18, 0x7, 0x00); 
02847       
02848       rlt_flag = pbx_builtin_getvar_helper(ast, "SS7_RLT_ON");
02849       if ((rlt_flag) && ((strncmp("NO", rlt_flag, strlen(rlt_flag))) != 0 )) {
02850          isup_set_lspi(p->ss7call, rlt_flag, 0x18, 0x7, 0x00); /* Setting for Nortel DMS-250/500 */
02851       }
02852       
02853       call_ref_id = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_IDENT");
02854       call_ref_pc = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_PC");
02855       if (call_ref_id && call_ref_pc) {
02856          isup_set_callref(p->ss7call, atoi(call_ref_id),
02857                 call_ref_pc ? atoi(call_ref_pc) : 0);
02858       }
02859       
02860       send_far = pbx_builtin_getvar_helper(ast, "SS7_SEND_FAR");
02861       if ((send_far) && ((strncmp("NO", send_far, strlen(send_far))) != 0 ))
02862          (isup_far(p->ss7->ss7, p->ss7call));
02863       
02864       ast_channel_unlock(ast);
02865 
02866       isup_iam(p->ss7->ss7, p->ss7call);
02867       ast_setstate(ast, AST_STATE_DIALING);
02868       ss7_rel(p->ss7);
02869    }
02870 #endif /* HAVE_SS7 */
02871 #ifdef HAVE_PRI
02872    if (p->pri) {
02873       struct pri_sr *sr;
02874 #ifdef SUPPORT_USERUSER
02875       const char *useruser;
02876 #endif
02877       int pridialplan;
02878       int dp_strip;
02879       int prilocaldialplan;
02880       int ldp_strip;
02881       int exclusive;
02882       const char *rr_str;
02883       int redirect_reason;
02884 
02885       c = strchr(dest, '/');
02886       if (c) {
02887          c++;
02888       } else {
02889          c = "";
02890       }
02891 
02892       l = NULL;
02893       n = NULL;
02894       if (!p->hidecallerid) {
02895          l = ast->cid.cid_num;
02896          if (!p->hidecalleridname) {
02897             n = ast->cid.cid_name;
02898          }
02899       }
02900 
02901       if (strlen(c) < p->stripmsd) {
02902          ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
02903          ast_mutex_unlock(&p->lock);
02904          return -1;
02905       }
02906       if (mysig != SIG_FXSKS) {
02907          p->dop.op = DAHDI_DIAL_OP_REPLACE;
02908          s = strchr(c + p->stripmsd, 'w');
02909          if (s) {
02910             if (strlen(s) > 1)
02911                snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T%s", s);
02912             else
02913                p->dop.dialstr[0] = '\0';
02914             *s = '\0';
02915          } else {
02916             p->dop.dialstr[0] = '\0';
02917          }
02918       }
02919       if (pri_grab(p, p->pri)) {
02920          ast_log(LOG_WARNING, "Failed to grab PRI!\n");
02921          ast_mutex_unlock(&p->lock);
02922          return -1;
02923       }
02924       if (!(p->call = pri_new_call(p->pri->pri))) {
02925          ast_log(LOG_WARNING, "Unable to create call on channel %d\n", p->channel);
02926          pri_rel(p->pri);
02927          ast_mutex_unlock(&p->lock);
02928          return -1;
02929       }
02930       if (!(sr = pri_sr_new())) {
02931          ast_log(LOG_WARNING, "Failed to allocate setup request channel %d\n", p->channel);
02932          pri_rel(p->pri);
02933          ast_mutex_unlock(&p->lock);
02934       }
02935       if (p->bearer || (mysig == SIG_FXSKS)) {
02936          if (p->bearer) {
02937             ast_debug(1, "Oooh, I have a bearer on %d (%d:%d)\n", PVT_TO_CHANNEL(p->bearer), p->bearer->logicalspan, p->bearer->channel);
02938             p->bearer->call = p->call;
02939          } else
02940             ast_debug(1, "I'm being setup with no bearer right now...\n");
02941 
02942          pri_set_crv(p->pri->pri, p->call, p->channel, 0);
02943       }
02944       p->digital = IS_DIGITAL(ast->transfercapability);
02945 
02946       /* Should the picked channel be used exclusively? */
02947       if (p->priexclusive || p->pri->nodetype == PRI_NETWORK) {
02948          exclusive = 1;
02949       } else {
02950          exclusive = 0;
02951       }
02952       
02953       pri_sr_set_channel(sr, p->bearer ? PVT_TO_CHANNEL(p->bearer) : PVT_TO_CHANNEL(p), exclusive, 1);
02954       pri_sr_set_bearer(sr, p->digital ? PRI_TRANS_CAP_DIGITAL : ast->transfercapability, 
02955                (p->digital ? -1 : 
02956                   ((p->law == DAHDI_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW)));
02957       if (p->pri->facilityenable)
02958          pri_facility_enable(p->pri->pri);
02959 
02960       ast_verb(3, "Requested transfer capability: 0x%.2x - %s\n", ast->transfercapability, ast_transfercapability2str(ast->transfercapability));
02961       dp_strip = 0;
02962       pridialplan = p->pri->dialplan - 1;
02963       if (pridialplan == -2 || pridialplan == -3) { /* compute dynamically */
02964          if (strncmp(c + p->stripmsd, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
02965             if (pridialplan == -2) {
02966                dp_strip = strlen(p->pri->internationalprefix);
02967             }
02968             pridialplan = PRI_INTERNATIONAL_ISDN;
02969          } else if (strncmp(c + p->stripmsd, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
02970             if (pridialplan == -2) {
02971                dp_strip = strlen(p->pri->nationalprefix);
02972             }
02973             pridialplan = PRI_NATIONAL_ISDN;
02974          } else {
02975             pridialplan = PRI_LOCAL_ISDN;
02976          }
02977       }
02978       while (c[p->stripmsd] > '9' && c[p->stripmsd] != '*' && c[p->stripmsd] != '#') {
02979          switch (c[p->stripmsd]) {
02980          case 'U':
02981             pridialplan = (PRI_TON_UNKNOWN << 4) | (pridialplan & 0xf);
02982             break;
02983          case 'I':
02984             pridialplan = (PRI_TON_INTERNATIONAL << 4) | (pridialplan & 0xf);
02985             break;
02986          case 'N':
02987             pridialplan = (PRI_TON_NATIONAL << 4) | (pridialplan & 0xf);
02988             break;
02989          case 'L':
02990             pridialplan = (PRI_TON_NET_SPECIFIC << 4) | (pridialplan & 0xf);
02991             break;
02992          case 'S':
02993             pridialplan = (PRI_TON_SUBSCRIBER << 4) | (pridialplan & 0xf);
02994             break;
02995          case 'V':
02996             pridialplan = (PRI_TON_ABBREVIATED << 4) | (pridialplan & 0xf);
02997             break;
02998          case 'R':
02999             pridialplan = (PRI_TON_RESERVED << 4) | (pridialplan & 0xf);
03000             break;
03001          case 'u':
03002             pridialplan = PRI_NPI_UNKNOWN | (pridialplan & 0xf0);
03003             break;
03004          case 'e':
03005             pridialplan = PRI_NPI_E163_E164 | (pridialplan & 0xf0);
03006             break;
03007          case 'x':
03008             pridialplan = PRI_NPI_X121 | (pridialplan & 0xf0);
03009             break;
03010          case 'f':
03011             pridialplan = PRI_NPI_F69 | (pridialplan & 0xf0);
03012             break;
03013          case 'n':
03014             pridialplan = PRI_NPI_NATIONAL | (pridialplan & 0xf0);
03015             break;
03016          case 'p':
03017             pridialplan = PRI_NPI_PRIVATE | (pridialplan & 0xf0);
03018             break;
03019          case 'r':
03020             pridialplan = PRI_NPI_RESERVED | (pridialplan & 0xf0);
03021             break;
03022          default:
03023             if (isalpha(c[p->stripmsd])) {
03024                ast_log(LOG_WARNING, "Unrecognized pridialplan %s modifier: %c\n",
03025                   c[p->stripmsd] > 'Z' ? "NPI" : "TON", c[p->stripmsd]);
03026             }
03027             break;
03028          }
03029          c++;
03030       }
03031       pri_sr_set_called(sr, c + p->stripmsd + dp_strip, pridialplan, s ? 1 : 0);
03032 
03033       ldp_strip = 0;
03034       prilocaldialplan = p->pri->localdialplan - 1;
03035       if ((l != NULL) && (prilocaldialplan == -2 || prilocaldialplan == -3)) { /* compute dynamically */
03036          if (strncmp(l, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
03037             if (prilocaldialplan == -2) {
03038                ldp_strip = strlen(p->pri->internationalprefix);
03039             }
03040             prilocaldialplan = PRI_INTERNATIONAL_ISDN;
03041          } else if (strncmp(l, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
03042             if (prilocaldialplan == -2) {
03043                ldp_strip = strlen(p->pri->nationalprefix);
03044             }
03045             prilocaldialplan = PRI_NATIONAL_ISDN;
03046          } else {
03047             prilocaldialplan = PRI_LOCAL_ISDN;
03048          }
03049       }
03050       if (l != NULL) {
03051          while (*l > '9' && *l != '*' && *l != '#') {
03052             switch (*l) {
03053             case 'U':
03054                prilocaldialplan = (PRI_TON_UNKNOWN << 4) | (prilocaldialplan & 0xf);
03055                break;
03056             case 'I':
03057                prilocaldialplan = (PRI_TON_INTERNATIONAL << 4) | (prilocaldialplan & 0xf);
03058                break;
03059             case 'N':
03060                prilocaldialplan = (PRI_TON_NATIONAL << 4) | (prilocaldialplan & 0xf);
03061                break;
03062             case 'L':
03063                prilocaldialplan = (PRI_TON_NET_SPECIFIC << 4) | (prilocaldialplan & 0xf);
03064                break;
03065             case 'S':
03066                prilocaldialplan = (PRI_TON_SUBSCRIBER << 4) | (prilocaldialplan & 0xf);
03067                break;
03068             case 'V':
03069                prilocaldialplan = (PRI_TON_ABBREVIATED << 4) | (prilocaldialplan & 0xf);
03070                break;
03071             case 'R':
03072                prilocaldialplan = (PRI_TON_RESERVED << 4) | (prilocaldialplan & 0xf);
03073                break;
03074             case 'u':
03075                prilocaldialplan = PRI_NPI_UNKNOWN | (prilocaldialplan & 0xf0);
03076                break;
03077             case 'e':
03078                prilocaldialplan = PRI_NPI_E163_E164 | (prilocaldialplan & 0xf0);
03079                break;
03080             case 'x':
03081                prilocaldialplan = PRI_NPI_X121 | (prilocaldialplan & 0xf0);
03082                break;
03083             case 'f':
03084                prilocaldialplan = PRI_NPI_F69 | (prilocaldialplan & 0xf0);
03085                break;
03086             case 'n':
03087                prilocaldialplan = PRI_NPI_NATIONAL | (prilocaldialplan & 0xf0);
03088                break;
03089             case 'p':
03090                prilocaldialplan = PRI_NPI_PRIVATE | (prilocaldialplan & 0xf0);
03091                break;
03092             case 'r':
03093                prilocaldialplan = PRI_NPI_RESERVED | (prilocaldialplan & 0xf0);
03094                break;
03095             default:
03096                if (isalpha(*l)) {
03097                   ast_log(LOG_WARNING,
03098                      "Unrecognized prilocaldialplan %s modifier: %c\n",
03099                      *l > 'Z' ? "NPI" : "TON", *l);
03100                }
03101                break;
03102             }
03103             l++;
03104          }
03105       }
03106       pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan,
03107          p->use_callingpres ? ast->cid.cid_pres : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE));
03108       if ((rr_str = pbx_builtin_getvar_helper(ast, "PRIREDIRECTREASON"))) {
03109          if (!strcasecmp(rr_str, "UNKNOWN"))
03110             redirect_reason = 0;
03111          else if (!strcasecmp(rr_str, "BUSY"))
03112             redirect_reason = 1;
03113          else if (!strcasecmp(rr_str, "NO_REPLY") || !strcasecmp(rr_str, "NOANSWER"))
03114          /* the NOANSWER is to match diversion-reason from chan_sip, (which never reads PRIREDIRECTREASON) */
03115             redirect_reason = 2;
03116          else if (!strcasecmp(rr_str, "UNCONDITIONAL"))
03117             redirect_reason = 15;
03118          else
03119             redirect_reason = PRI_REDIR_UNCONDITIONAL;
03120       } else
03121          redirect_reason = PRI_REDIR_UNCONDITIONAL;
03122       pri_sr_set_redirecting(sr, ast->cid.cid_rdnis, p->pri->localdialplan - 1, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, redirect_reason);
03123 
03124 #ifdef SUPPORT_USERUSER
03125       /* User-user info */
03126       useruser = pbx_builtin_getvar_helper(p->owner, "USERUSERINFO");
03127 
03128       if (useruser)
03129          pri_sr_set_useruser(sr, useruser);
03130 #endif
03131 
03132       if (pri_setup(p->pri->pri, p->call, sr)) {
03133          ast_log(LOG_WARNING, "Unable to setup call to %s (using %s)\n", 
03134             c + p->stripmsd + dp_strip, dialplan2str(p->pri->dialplan));
03135          pri_rel(p->pri);
03136          ast_mutex_unlock(&p->lock);
03137          pri_sr_free(sr);
03138          return -1;
03139       }
03140       pri_sr_free(sr);
03141       ast_setstate(ast, AST_STATE_DIALING);
03142       pri_rel(p->pri);
03143    }
03144 #endif      
03145    ast_mutex_unlock(&p->lock);
03146    return 0;
03147 }
03148 
03149 static void destroy_dahdi_pvt(struct dahdi_pvt **pvt)
03150 {
03151    struct dahdi_pvt *p = *pvt;
03152    /* Remove channel from the list */
03153    if (p->prev)
03154       p->prev->next = p->next;
03155    if (p->next)
03156       p->next->prev = p->prev;
03157    if (p->use_smdi)
03158       ast_smdi_interface_unref(p->smdi_iface);
03159    if (p->mwi_event_sub)
03160       ast_event_unsubscribe(p->mwi_event_sub);
03161    if (p->vars) {
03162       ast_variables_destroy(p->vars);
03163    }
03164    ast_mutex_destroy(&p->lock);
03165    dahdi_close_sub(p, SUB_REAL);
03166    if (p->owner)
03167       p->owner->tech_pvt = NULL;
03168    free(p);
03169    *pvt = NULL;
03170 }
03171 
03172 static int destroy_channel(struct dahdi_pvt *prev, struct dahdi_pvt *cur, int now)
03173 {
03174    int owned = 0;
03175    int i = 0;
03176 
03177    if (!now) {
03178       if (cur->owner) {
03179          owned = 1;
03180       }
03181 
03182       for (i = 0; i < 3; i++) {
03183          if (cur->subs[i].owner) {
03184             owned = 1;
03185          }
03186       }
03187       if (!owned) {
03188          if (prev) {
03189             prev->next = cur->next;
03190             if (prev->next)
03191                prev->next->prev = prev;
03192             else
03193                ifend = prev;
03194          } else {
03195             iflist = cur->next;
03196             if (iflist)
03197                iflist->prev = NULL;
03198             else
03199                ifend = NULL;
03200          }
03201          destroy_dahdi_pvt(&cur);
03202       }
03203    } else {
03204       if (prev) {
03205          prev->next = cur->next;
03206          if (prev->next)
03207             prev->next->prev = prev;
03208          else
03209             ifend = prev;
03210       } else {
03211          iflist = cur->next;
03212          if (iflist)
03213             iflist->prev = NULL;
03214          else
03215             ifend = NULL;
03216       }
03217       destroy_dahdi_pvt(&cur);
03218    }
03219    return 0;
03220 }
03221 
03222 static void destroy_all_channels(void)
03223 {
03224    int x;
03225    struct dahdi_pvt *p, *pl;
03226 
03227    while (num_restart_pending) {
03228       usleep(1);
03229    }
03230 
03231    ast_mutex_lock(&iflock);
03232    /* Destroy all the interfaces and free their memory */
03233    p = iflist;
03234    while (p) {
03235       /* Free any callerid */
03236       if (p->cidspill)
03237          ast_free(p->cidspill);
03238       pl = p;
03239       p = p->next;
03240       x = pl->channel;
03241       /* Free associated memory */
03242       if (pl)
03243          destroy_dahdi_pvt(&pl);
03244       if (option_verbose > 2) 
03245          ast_verbose(VERBOSE_PREFIX_2 "Unregistered channel %d\n", x);
03246    }
03247    iflist = NULL;
03248    ifcount = 0;
03249    ast_mutex_unlock(&iflock);
03250 }
03251 
03252 #ifdef HAVE_PRI
03253 static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility";
03254 
03255 static char *dahdi_send_keypad_facility_synopsis = "Send digits out of band over a PRI";
03256 
03257 static char *dahdi_send_keypad_facility_descrip = 
03258 "  DAHDISendKeypadFacility(): This application will send the given string of digits in a Keypad Facility\n"
03259 "  IE over the current channel.\n";
03260 
03261 static int dahdi_send_keypad_facility_exec(struct ast_channel *chan, void *data)
03262 {
03263    /* Data will be our digit string */
03264    struct dahdi_pvt *p;
03265    char *digits = (char *) data;
03266 
03267    if (ast_strlen_zero(digits)) {
03268       ast_debug(1, "No digit string sent to application!\n");
03269       return -1;
03270    }
03271 
03272    p = (struct dahdi_pvt *)chan->tech_pvt;
03273 
03274    if (!p) {
03275       ast_debug(1, "Unable to find technology private\n");
03276       return -1;
03277    }
03278 
03279    ast_mutex_lock(&p->lock);
03280 
03281    if (!p->pri || !p->call) {
03282       ast_debug(1, "Unable to find pri or call on channel!\n");
03283       ast_mutex_unlock(&p->lock);
03284       return -1;
03285    }
03286 
03287    if (!pri_grab(p, p->pri)) {
03288       pri_keypad_facility(p->pri->pri, p->call, digits);
03289       pri_rel(p->pri);
03290    } else {
03291       ast_debug(1, "Unable to grab pri to send keypad facility!\n");
03292       ast_mutex_unlock(&p->lock);
03293       return -1;
03294    }
03295 
03296    ast_mutex_unlock(&p->lock);
03297 
03298    return 0;
03299 }
03300 
03301 static int pri_is_up(struct dahdi_pri *pri)
03302 {
03303    int x;
03304    for (x = 0; x < NUM_DCHANS; x++) {
03305       if (pri->dchanavail[x] == DCHAN_AVAILABLE)
03306          return 1;
03307    }
03308    return 0;
03309 }
03310 
03311 static int pri_assign_bearer(struct dahdi_pvt *crv, struct dahdi_pri *pri, struct dahdi_pvt *bearer)
03312 {
03313    bearer->owner = &inuse;
03314    bearer->realcall = crv;
03315    crv->subs[SUB_REAL].dfd = bearer->subs[SUB_REAL].dfd;
03316    if (crv->subs[SUB_REAL].owner)
03317       ast_channel_set_fd(crv->subs[SUB_REAL].owner, 0, crv->subs[SUB_REAL].dfd);
03318    crv->bearer = bearer;
03319    crv->call = bearer->call;
03320    crv->pri = pri;
03321    return 0;
03322 }
03323 
03324 static char *pri_order(int level)
03325 {
03326    switch (level) {
03327    case 0:
03328       return "Primary";
03329    case 1:
03330       return "Secondary";
03331    case 2:
03332       return "Tertiary";
03333    case 3:
03334       return "Quaternary";
03335    default:
03336       return "<Unknown>";
03337    }     
03338 }
03339 
03340 /* Returns fd of the active dchan */
03341 static int pri_active_dchan_fd(struct dahdi_pri *pri)
03342 {
03343    int x = -1;
03344 
03345    for (x = 0; x < NUM_DCHANS; x++) {
03346       if ((pri->dchans[x] == pri->pri))
03347          break;
03348    }
03349 
03350    return pri->fds[x];
03351 }
03352 
03353 static int pri_find_dchan(struct dahdi_pri *pri)
03354 {
03355    int oldslot = -1;
03356    struct pri *old;
03357    int newslot = -1;
03358    int x;
03359    old = pri->pri;
03360    for (x = 0; x < NUM_DCHANS; x++) {
03361       if ((pri->dchanavail[x] == DCHAN_AVAILABLE) && (newslot < 0))
03362          newslot = x;
03363       if (pri->dchans[x] == old) {
03364          oldslot = x;
03365       }
03366    }
03367    if (newslot < 0) {
03368       newslot = 0;
03369       ast_log(LOG_WARNING, "No D-channels available!  Using Primary channel %d as D-channel anyway!\n",
03370          pri->dchannels[newslot]);
03371    }
03372    if (old && (oldslot != newslot))
03373       ast_log(LOG_NOTICE, "Switching from from d-channel %d to channel %d!\n",
03374          pri->dchannels[oldslot], pri->dchannels[newslot]);
03375    pri->pri = pri->dchans[newslot];
03376    return 0;
03377 }
03378 #endif
03379 
03380 static int dahdi_hangup(struct ast_channel *ast)
03381 {
03382    int res;
03383    int idx,x, law;
03384    /*static int restore_gains(struct dahdi_pvt *p);*/
03385    struct dahdi_pvt *p = ast->tech_pvt;
03386    struct dahdi_pvt *tmp = NULL;
03387    struct dahdi_pvt *prev = NULL;
03388    struct dahdi_params par;
03389 
03390    ast_debug(1, "dahdi_hangup(%s)\n", ast->name);
03391    if (!ast->tech_pvt) {
03392       ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
03393       return 0;
03394    }
03395    
03396    ast_mutex_lock(&p->lock);
03397    
03398    idx = dahdi_get_index(ast, p, 1);
03399 
03400    if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
03401       x = 1;
03402       ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
03403       p->cid_num[0] = '\0';
03404       p->cid_name[0] = '\0';
03405    }
03406 
03407    x = 0;
03408    dahdi_confmute(p, 0);
03409    p->muting = 0;
03410    restore_gains(p);
03411    if (p->origcid_num) {
03412       ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num));
03413       ast_free(p->origcid_num);
03414       p->origcid_num = NULL;
03415    }  
03416    if (p->origcid_name) {
03417       ast_copy_string(p->cid_name, p->origcid_name, sizeof(p->cid_name));
03418       ast_free(p->origcid_name);
03419       p->origcid_name = NULL;
03420    }  
03421    if (p->dsp)
03422       ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
03423    p->exten[0] = '\0';
03424 
03425    ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
03426       p->channel, idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
03427    p->ignoredtmf = 0;
03428    
03429    if (idx > -1) {
03430       /* Real channel, do some fixup */
03431       p->subs[idx].owner = NULL;
03432       p->subs[idx].needanswer = 0;
03433       p->subs[idx].needflash = 0;
03434       p->subs[idx].needringing = 0;
03435       p->subs[idx].needbusy = 0;
03436       p->subs[idx].needcongestion = 0;
03437       p->subs[idx].linear = 0;
03438       p->subs[idx].needcallerid = 0;
03439       p->polarity = POLARITY_IDLE;
03440       dahdi_setlinear(p->subs[idx].dfd, 0);
03441       if (idx == SUB_REAL) {
03442          if ((p->subs[SUB_CALLWAIT].dfd > -1) && (p->subs[SUB_THREEWAY].dfd > -1)) {
03443             ast_debug(1, "Normal call hung up with both three way call and a call waiting call in place?\n");
03444             if (p->subs[SUB_CALLWAIT].inthreeway) {
03445                /* We had flipped over to answer a callwait and now it's gone */
03446                ast_debug(1, "We were flipped over to the callwait, moving back and unowning.\n");
03447                /* Move to the call-wait, but un-own us until they flip back. */
03448                swap_subs(p, SUB_CALLWAIT, SUB_REAL);
03449                unalloc_sub(p, SUB_CALLWAIT);
03450                p->owner = NULL;
03451             } else {
03452                /* The three way hung up, but we still have a call wait */
03453                ast_debug(1, "We were in the threeway and have a callwait still.  Ditching the threeway.\n");
03454                swap_subs(p, SUB_THREEWAY, SUB_REAL);
03455                unalloc_sub(p, SUB_THREEWAY);
03456                if (p->subs[SUB_REAL].inthreeway) {
03457                   /* This was part of a three way call.  Immediately make way for
03458                      another call */
03459                   ast_debug(1, "Call was complete, setting owner to former third call\n");
03460                   p->owner = p->subs[SUB_REAL].owner;
03461                } else {
03462                   /* This call hasn't been completed yet...  Set owner to NULL */
03463                   ast_debug(1, "Call was incomplete, setting owner to NULL\n");
03464                   p->owner = NULL;
03465                }
03466                p->subs[SUB_REAL].inthreeway = 0;
03467             }
03468          } else if (p->subs[SUB_CALLWAIT].dfd > -1) {
03469             /* Move to the call-wait and switch back to them. */
03470             swap_subs(p, SUB_CALLWAIT, SUB_REAL);
03471             unalloc_sub(p, SUB_CALLWAIT);
03472             p->owner = p->subs[SUB_REAL].owner;
03473             if (p->owner->_state != AST_STATE_UP)
03474                p->subs[SUB_REAL].needanswer = 1;
03475             if (ast_bridged_channel(p->subs[SUB_REAL].owner))
03476                ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
03477          } else if (p->subs[SUB_THREEWAY].dfd > -1) {
03478             swap_subs(p, SUB_THREEWAY, SUB_REAL);
03479             unalloc_sub(p, SUB_THREEWAY);
03480             if (p->subs[SUB_REAL].inthreeway) {
03481                /* This was part of a three way call.  Immediately make way for
03482                   another call */
03483                ast_debug(1, "Call was complete, setting owner to former third call\n");
03484                p->owner = p->subs[SUB_REAL].owner;
03485             } else {
03486                /* This call hasn't been completed yet...  Set owner to NULL */
03487                ast_debug(1, "Call was incomplete, setting owner to NULL\n");
03488                p->owner = NULL;
03489             }
03490             p->subs[SUB_REAL].inthreeway = 0;
03491          }
03492       } else if (idx == SUB_CALLWAIT) {
03493          /* Ditch the holding callwait call, and immediately make it availabe */
03494          if (p->subs[SUB_CALLWAIT].inthreeway) {
03495             /* This is actually part of a three way, placed on hold.  Place the third part
03496                on music on hold now */
03497             if (p->subs[SUB_THREEWAY].owner && ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
03498                ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD, 
03499                   S_OR(p->mohsuggest, NULL),
03500                   !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
03501             }
03502             p->subs[SUB_THREEWAY].inthreeway = 0;
03503             /* Make it the call wait now */
03504             swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
03505             unalloc_sub(p, SUB_THREEWAY);
03506          } else
03507             unalloc_sub(p, SUB_CALLWAIT);
03508       } else if (idx == SUB_THREEWAY) {
03509          if (p->subs[SUB_CALLWAIT].inthreeway) {
03510             /* The other party of the three way call is currently in a call-wait state.
03511                Start music on hold for them, and take the main guy out of the third call */
03512             if (p->subs[SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
03513                ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD, 
03514                   S_OR(p->mohsuggest, NULL),
03515                   !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
03516             }
03517             p->subs[SUB_CALLWAIT].inthreeway = 0;
03518          }
03519          p->subs[SUB_REAL].inthreeway = 0;
03520          /* If this was part of a three way call index, let us make
03521             another three way call */
03522          unalloc_sub(p, SUB_THREEWAY);
03523       } else {
03524          /* This wasn't any sort of call, but how are we an index? */
03525          ast_log(LOG_WARNING, "Index found but not any type of call?\n");
03526       }
03527    }
03528 
03529    if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
03530       p->owner = NULL;
03531       p->ringt = 0;
03532       p->distinctivering = 0;
03533       p->confirmanswer = 0;
03534       p->cidrings = 1;
03535       p->outgoing = 0;
03536       p->digital = 0;
03537       p->faxhandled = 0;
03538       p->pulsedial = 0;
03539       p->onhooktime = time(NULL);
03540 #if defined(HAVE_PRI) || defined(HAVE_SS7)
03541       p->proceeding = 0;
03542       p->dialing = 0;
03543       p->progress = 0;
03544       p->alerting = 0;
03545       p->setup_ack = 0;
03546       p->rlt = 0;
03547 #endif      
03548       if (p->dsp) {
03549          ast_dsp_free(p->dsp);
03550          p->dsp = NULL;
03551       }
03552 
03553       law = DAHDI_LAW_DEFAULT;
03554       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
03555       if (res < 0) 
03556          ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
03557       /* Perform low level hangup if no owner left */
03558 #ifdef HAVE_SS7
03559       if (p->ss7) {
03560          if (p->ss7call) {
03561             if (!ss7_grab(p, p->ss7)) {
03562                if (!p->alreadyhungup) {
03563                   const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
03564                   int icause = ast->hangupcause ? ast->hangupcause : -1;
03565 
03566                   if (cause) {
03567                      if (atoi(cause))
03568                         icause = atoi(cause);
03569                   }
03570                   isup_rel(p->ss7->ss7, p->ss7call, icause);
03571                   ss7_rel(p->ss7);
03572                   p->alreadyhungup = 1;
03573                } else
03574                   ast_log(LOG_WARNING, "Trying to hangup twice!\n");
03575             } else {
03576                ast_log(LOG_WARNING, "Unable to grab SS7 on CIC %d\n", p->cic);
03577                res = -1;
03578             }
03579          }
03580       }
03581 #endif
03582 #ifdef HAVE_PRI
03583       if (p->pri) {
03584 #ifdef SUPPORT_USERUSER
03585          const char *useruser = pbx_builtin_getvar_helper(ast,"USERUSERINFO");
03586 #endif
03587 
03588          /* Make sure we have a call (or REALLY have a call in the case of a PRI) */
03589          if (p->call && (!p->bearer || (p->bearer->call == p->call))) {
03590             if (!pri_grab(p, p->pri)) {
03591                if (p->alreadyhungup) {
03592                   ast_debug(1, "Already hungup...  Calling hangup once, and clearing call\n");
03593 
03594 #ifdef SUPPORT_USERUSER
03595                   pri_call_set_useruser(p->call, useruser);
03596 #endif
03597 
03598                   pri_hangup(p->pri->pri, p->call, -1);
03599                   p->call = NULL;
03600                   if (p->bearer) 
03601                      p->bearer->call = NULL;
03602                } else {
03603                   const char *cause = pbx_builtin_getvar_helper(ast,"PRI_CAUSE");
03604                   int icause = ast->hangupcause ? ast->hangupcause : -1;
03605                   ast_debug(1, "Not yet hungup...  Calling hangup once with icause, and clearing call\n");
03606 
03607 #ifdef SUPPORT_USERUSER
03608                   pri_call_set_useruser(p->call, useruser);
03609 #endif
03610 
03611                   p->alreadyhungup = 1;
03612                   if (p->bearer)
03613                      p->bearer->alreadyhungup = 1;
03614                   if (cause) {
03615                      if (atoi(cause))
03616                         icause = atoi(cause);
03617                   }
03618                   pri_hangup(p->pri->pri, p->call, icause);
03619                }
03620                if (res < 0) 
03621                   ast_log(LOG_WARNING, "pri_disconnect failed\n");
03622                pri_rel(p->pri);        
03623             } else {
03624                ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
03625                res = -1;
03626             }
03627          } else {
03628             if (p->bearer)
03629                ast_debug(1, "Bearer call is %p, while ours is still %p\n", p->bearer->call, p->call);
03630             p->call = NULL;
03631             res = 0;
03632          }
03633       }
03634 #endif
03635       if (p->sig && ((p->sig != SIG_PRI) && (p->sig != SIG_SS7) && (p->sig != SIG_BRI) && (p->sig != SIG_BRI_PTMP)))
03636          res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
03637       if (res < 0) {
03638          ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
03639       }
03640       switch (p->sig) {
03641       case SIG_FXOGS:
03642       case SIG_FXOLS:
03643       case SIG_FXOKS:
03644          memset(&par, 0, sizeof(par));
03645          res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
03646          if (!res) {
03647 #if 0
03648             ast_debug(1, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
03649 #endif
03650             /* If they're off hook, try playing congestion */
03651             if ((par.rxisoffhook) && (!(p->radio || (p->oprmode < 0))))
03652                tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
03653             else
03654                tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
03655          }
03656          break;
03657       case SIG_FXSGS:
03658       case SIG_FXSLS:
03659       case SIG_FXSKS:
03660          /* Make sure we're not made available for at least two seconds assuming
03661             we were actually used for an inbound or outbound call. */
03662          if (ast->_state != AST_STATE_RESERVED) {
03663             time(&p->guardtime);
03664             p->guardtime += 2;
03665          }
03666          break;
03667       default:
03668          tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
03669       }
03670       if (p->cidspill)
03671          ast_free(p->cidspill);
03672       if (p->sig)
03673          dahdi_disable_ec(p);
03674       x = 0;
03675       ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
03676       ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
03677       p->didtdd = 0;
03678       p->cidspill = NULL;
03679       p->callwaitcas = 0;
03680       p->callwaiting = p->permcallwaiting;
03681       p->hidecallerid = p->permhidecallerid;
03682       p->dialing = 0;
03683       p->rdnis[0] = '\0';
03684       update_conf(p);
03685       reset_conf(p);
03686       /* Restore data mode */
03687       if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
03688          x = 0;
03689          ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
03690       }
03691 #ifdef HAVE_PRI
03692       if (p->bearer) {
03693          ast_debug(1, "Freeing up bearer channel %d\n", p->bearer->channel);
03694          /* Free up the bearer channel as well, and
03695             don't use its file descriptor anymore */
03696          update_conf(p->bearer);
03697          reset_conf(p->bearer);
03698          p->bearer->owner = NULL;
03699          p->bearer->realcall = NULL;
03700          p->bearer = NULL;
03701          p->subs[SUB_REAL].dfd = -1;
03702          p->pri = NULL;
03703       }
03704 #endif
03705       if (num_restart_pending == 0)
03706          restart_monitor();
03707    }
03708 
03709    p->callwaitingrepeat = 0;
03710    p->cidcwexpire = 0;
03711    p->oprmode = 0;
03712    ast->tech_pvt = NULL;
03713    ast_mutex_unlock(&p->lock);
03714    ast_module_unref(ast_module_info->self);
03715    ast_verb(3, "Hungup '%s'\n", ast->name);
03716 
03717    ast_mutex_lock(&iflock);
03718 
03719    if (p->restartpending) {
03720       num_restart_pending--;
03721    }
03722 
03723    tmp = iflist;
03724    prev = NULL;
03725    if (p->destroy) {
03726       while (tmp) {
03727          if (tmp == p) {
03728             destroy_channel(prev, tmp, 0);
03729             break;
03730          } else {
03731             prev = tmp;
03732             tmp = tmp->next;
03733          }
03734       }
03735    }
03736    ast_mutex_unlock(&iflock);
03737    return 0;
03738 }
03739 
03740 static int dahdi_answer(struct ast_channel *ast)
03741 {
03742    struct dahdi_pvt *p = ast->tech_pvt;
03743    int res = 0;
03744    int idx;
03745    int oldstate = ast->_state;
03746    ast_setstate(ast, AST_STATE_UP);
03747    ast_mutex_lock(&p->lock);
03748    idx = dahdi_get_index(ast, p, 0);
03749    if (idx < 0)
03750       idx = SUB_REAL;
03751    /* nothing to do if a radio channel */
03752    if ((p->radio || (p->oprmode < 0))) {
03753       ast_mutex_unlock(&p->lock);
03754       return 0;
03755    }
03756    switch (p->sig) {
03757    case SIG_FXSLS:
03758    case SIG_FXSGS:
03759    case SIG_FXSKS:
03760       p->ringt = 0;
03761       /* Fall through */
03762    case SIG_EM:
03763    case SIG_EM_E1:
03764    case SIG_EMWINK:
03765    case SIG_FEATD:
03766    case SIG_FEATDMF:
03767    case SIG_FEATDMF_TA:
03768    case SIG_E911:
03769    case SIG_FGC_CAMA:
03770    case SIG_FGC_CAMAMF:
03771    case SIG_FEATB:
03772    case SIG_SF:
03773    case SIG_SFWINK:
03774    case SIG_SF_FEATD:
03775    case SIG_SF_FEATDMF:
03776    case SIG_SF_FEATB:
03777    case SIG_FXOLS:
03778    case SIG_FXOGS:
03779    case SIG_FXOKS:
03780       /* Pick up the line */
03781       ast_debug(1, "Took %s off hook\n", ast->name);
03782       if (p->hanguponpolarityswitch) {
03783          p->polaritydelaytv = ast_tvnow();
03784       }
03785       res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
03786       tone_zone_play_tone(p->subs[idx].dfd, -1);
03787       p->dialing = 0;
03788       if ((idx == SUB_REAL) && p->subs[SUB_THREEWAY].inthreeway) {
03789          if (oldstate == AST_STATE_RINGING) {
03790             ast_debug(1, "Finally swapping real and threeway\n");
03791             tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, -1);
03792             swap_subs(p, SUB_THREEWAY, SUB_REAL);
03793             p->owner = p->subs[SUB_REAL].owner;
03794          }
03795       }
03796       if (p->sig & __DAHDI_SIG_FXS) {
03797          dahdi_enable_ec(p);
03798          dahdi_train_ec(p);
03799       }
03800       break;
03801 #ifdef HAVE_PRI
03802    case SIG_BRI:
03803    case SIG_BRI_PTMP:
03804    case SIG_PRI:
03805       /* Send a pri acknowledge */
03806       if (!pri_grab(p, p->pri)) {
03807          p->proceeding = 1;
03808          p->dialing = 0;
03809          res = pri_answer(p->pri->pri, p->call, 0, !p->digital);
03810          pri_rel(p->pri);
03811       } else {
03812          ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
03813          res = -1;
03814       }
03815       break;
03816 #endif
03817 #ifdef HAVE_SS7
03818    case SIG_SS7:
03819       if (!ss7_grab(p, p->ss7)) {
03820          p->proceeding = 1;
03821          res = isup_anm(p->ss7->ss7, p->ss7call);
03822          ss7_rel(p->ss7);
03823       } else {
03824          ast_log(LOG_WARNING, "Unable to grab SS7 on span %d\n", p->span);
03825          res = -1;
03826       }
03827       break;
03828 #endif
03829    case 0:
03830       ast_mutex_unlock(&p->lock);
03831       return 0;
03832    default:
03833       ast_log(LOG_WARNING, "Don't know how to answer signalling %d (channel %d)\n", p->sig, p->channel);
03834       res = -1;
03835    }
03836    ast_mutex_unlock(&p->lock);
03837    return res;
03838 }
03839 
03840 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
03841 {
03842    char *cp;
03843    signed char *scp;
03844    int x;
03845    int idx;
03846    struct dahdi_pvt *p = chan->tech_pvt, *pp;
03847    struct oprmode *oprmode;
03848    
03849 
03850    /* all supported options require data */
03851    if (!data || (datalen < 1)) {
03852       errno = EINVAL;
03853       return -1;
03854    }
03855 
03856    switch (option) {
03857    case AST_OPTION_TXGAIN:
03858       scp = (signed char *) data;
03859       idx = dahdi_get_index(chan, p, 0);
03860       if (idx < 0) {
03861          ast_log(LOG_WARNING, "No index in TXGAIN?\n");
03862          return -1;
03863       }
03864       ast_debug(1, "Setting actual tx gain on %s to %f\n", chan->name, p->txgain + (float) *scp);
03865       return set_actual_txgain(p->subs[idx].dfd, 0, p->txgain + (float) *scp, p->law);
03866    case AST_OPTION_RXGAIN:
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 RXGAIN?\n");
03871          return -1;
03872       }
03873       ast_debug(1, "Setting actual rx gain on %s to %f\n", chan->name, p->rxgain + (float) *scp);
03874       return set_actual_rxgain(p->subs[idx].dfd, 0, p->rxgain + (float) *scp, p->law);
03875    case AST_OPTION_TONE_VERIFY:
03876       if (!p->dsp)
03877          break;
03878       cp = (char *) data;
03879       switch (*cp) {
03880       case 1:
03881          ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",chan->name);
03882          ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | p->dtmfrelax);  /* set mute mode if desired */
03883          break;
03884       case 2:
03885          ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",chan->name);
03886          ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX | p->dtmfrelax);  /* set mute mode if desired */
03887          break;
03888       default:
03889          ast_debug(1, "Set option TONE VERIFY, mode: OFF(0) on %s\n",chan->name);
03890          ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);  /* set mute mode if desired */
03891          break;
03892       }
03893       break;
03894    case AST_OPTION_TDD:
03895       /* turn on or off TDD */
03896       cp = (char *) data;
03897       p->mate = 0;
03898       if (!*cp) { /* turn it off */
03899          ast_debug(1, "Set option TDD MODE, value: OFF(0) on %s\n",chan->name);
03900          if (p->tdd)
03901             tdd_free(p->tdd);
03902          p->tdd = 0;
03903          break;
03904       }
03905       ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
03906          (*cp == 2) ? "MATE" : "ON", (int) *cp, chan->name);
03907       dahdi_disable_ec(p);
03908       /* otherwise, turn it on */
03909       if (!p->didtdd) { /* if havent done it yet */
03910          unsigned char mybuf[41000];/*! \todo XXX This is an abuse of the stack!! */
03911          unsigned char *buf;
03912          int size, res, fd, len;
03913          struct pollfd fds[1];
03914 
03915          buf = mybuf;
03916          memset(buf, 0x7f, sizeof(mybuf)); /* set to silence */
03917          ast_tdd_gen_ecdisa(buf + 16000, 16000);  /* put in tone */
03918          len = 40000;
03919          idx = dahdi_get_index(chan, p, 0);
03920          if (idx < 0) {
03921             ast_log(LOG_WARNING, "No index in TDD?\n");
03922             return -1;
03923          }
03924          fd = p->subs[idx].dfd;
03925          while (len) {
03926             if (ast_check_hangup(chan))
03927                return -1;
03928             size = len;
03929             if (size > READ_SIZE)
03930                size = READ_SIZE;
03931             fds[0].fd = fd;
03932             fds[0].events = POLLPRI | POLLOUT;
03933             fds[0].revents = 0;
03934             res = poll(fds, 1, -1);
03935             if (!res) {
03936                ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
03937                continue;
03938             }
03939             /* if got exception */
03940             if (fds[0].revents & POLLPRI)
03941                return -1;
03942             if (!(fds[0].revents & POLLOUT)) {
03943                ast_debug(1, "write fd not ready on channel %d\n", p->channel);
03944                continue;
03945             }
03946             res = write(fd, buf, size);
03947             if (res != size) {
03948                if (res == -1) return -1;
03949                ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
03950                break;
03951             }
03952             len -= size;
03953             buf += size;
03954          }
03955          p->didtdd = 1; /* set to have done it now */    
03956       }
03957       if (*cp == 2) { /* Mate mode */
03958          if (p->tdd)
03959             tdd_free(p->tdd);
03960          p->tdd = 0;
03961          p->mate = 1;
03962          break;
03963       }     
03964       if (!p->tdd) { /* if we dont have one yet */
03965          p->tdd = tdd_new(); /* allocate one */
03966       }     
03967       break;
03968    case AST_OPTION_RELAXDTMF:  /* Relax DTMF decoding (or not) */
03969       if (!p->dsp)
03970          break;
03971       cp = (char *) data;
03972       ast_debug(1, "Set option RELAX DTMF, value: %s(%d) on %s\n",
03973          *cp ? "ON" : "OFF", (int) *cp, chan->name);
03974       ast_dsp_set_digitmode(p->dsp, ((*cp) ? DSP_DIGITMODE_RELAXDTMF : DSP_DIGITMODE_DTMF) | p->dtmfrelax);
03975       break;
03976    case AST_OPTION_AUDIO_MODE:  /* Set AUDIO mode (or not) */
03977       cp = (char *) data;
03978       if (!*cp) {    
03979          ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", chan->name);
03980          x = 0;
03981          dahdi_disable_ec(p);
03982       } else {    
03983          ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", chan->name);
03984          x = 1;
03985       }
03986       if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x) == -1)
03987          ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, x, strerror(errno));
03988       break;
03989    case AST_OPTION_OPRMODE:  /* Operator services mode */
03990       oprmode = (struct oprmode *) data;
03991       pp = oprmode->peer->tech_pvt;
03992       p->oprmode = pp->oprmode = 0;
03993       /* setup peers */
03994       p->oprpeer = pp;
03995       pp->oprpeer = p;
03996       /* setup modes, if any */
03997       if (oprmode->mode) 
03998       {
03999          pp->oprmode = oprmode->mode;
04000          p->oprmode = -oprmode->mode;
04001       }
04002       ast_debug(1, "Set Operator Services mode, value: %d on %s/%s\n",
04003          oprmode->mode, chan->name,oprmode->peer->name);
04004       break;
04005    case AST_OPTION_ECHOCAN:
04006       cp = (char *) data;
04007       if (*cp) {
04008          ast_debug(1, "Enabling echo cancelation on %s\n", chan->name);
04009          dahdi_enable_ec(p);
04010       } else {
04011          ast_debug(1, "Disabling echo cancelation on %s\n", chan->name);
04012          dahdi_disable_ec(p);
04013       }
04014       break;
04015    }
04016    errno = 0;
04017 
04018    return 0;
04019 }
04020 
04021 static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
04022 {
04023    struct dahdi_pvt *p = chan->tech_pvt;
04024    
04025    if (!strcasecmp(data, "rxgain")) {
04026       ast_mutex_lock(&p->lock);
04027       snprintf(buf, len, "%f", p->rxgain);
04028       ast_mutex_unlock(&p->lock);   
04029    } else if (!strcasecmp(data, "txgain")) {
04030       ast_mutex_lock(&p->lock);
04031       snprintf(buf, len, "%f", p->txgain);
04032       ast_mutex_unlock(&p->lock);   
04033    } else {
04034       ast_copy_string(buf, "", len);
04035    }
04036    return 0;
04037 }
04038 
04039 
04040 static void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
04041 {
04042    /* Unlink a specific slave or all slaves/masters from a given master */
04043    int x;
04044    int hasslaves;
04045    if (!master)
04046       return;
04047    if (needlock) {
04048       ast_mutex_lock(&master->lock);
04049       if (slave) {
04050          while (ast_mutex_trylock(&slave->lock)) {
04051             DEADLOCK_AVOIDANCE(&master->lock);
04052          }
04053       }
04054    }
04055    hasslaves = 0;
04056    for (x = 0; x < MAX_SLAVES; x++) {
04057       if (master->slaves[x]) {
04058          if (!slave || (master->slaves[x] == slave)) {
04059             /* Take slave out of the conference */
04060             ast_debug(1, "Unlinking slave %d from %d\n", master->slaves[x]->channel, master->channel);
04061             conf_del(master, &master->slaves[x]->subs[SUB_REAL], SUB_REAL);
04062             conf_del(master->slaves[x], &master->subs[SUB_REAL], SUB_REAL);
04063             master->slaves[x]->master = NULL;
04064             master->slaves[x] = NULL;
04065          } else
04066             hasslaves = 1;
04067       }
04068       if (!hasslaves)
04069          master->inconference = 0;
04070    }
04071    if (!slave) {
04072       if (master->master) {
04073          /* Take master out of the conference */
04074          conf_del(master->master, &master->subs[SUB_REAL], SUB_REAL);
04075          conf_del(master, &master->master->subs[SUB_REAL], SUB_REAL);
04076          hasslaves = 0;
04077          for (x = 0; x < MAX_SLAVES; x++) {
04078             if (master->master->slaves[x] == master)
04079                master->master->slaves[x] = NULL;
04080             else if (master->master->slaves[x])
04081                hasslaves = 1;
04082          }
04083          if (!hasslaves)
04084             master->master->inconference = 0;
04085       }
04086       master->master = NULL;
04087    }
04088    update_conf(master);
04089    if (needlock) {
04090       if (slave)
04091          ast_mutex_unlock(&slave->lock);
04092       ast_mutex_unlock(&master->lock);
04093    }
04094 }
04095 
04096 static void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master) {
04097    int x;
04098    if (!slave || !master) {
04099       ast_log(LOG_WARNING, "Tried to link to/from NULL??\n");
04100       return;
04101    }
04102    for (x = 0; x < MAX_SLAVES; x++) {
04103       if (!master->slaves[x]) {
04104          master->slaves[x] = slave;
04105          break;
04106       }
04107    }
04108    if (x >= MAX_SLAVES) {
04109       ast_log(LOG_WARNING, "Replacing slave %d with new slave, %d\n", master->slaves[MAX_SLAVES - 1]->channel, slave->channel);
04110       master->slaves[MAX_SLAVES - 1] = slave;
04111    }
04112    if (slave->master) 
04113       ast_log(LOG_WARNING, "Replacing master %d with new master, %d\n", slave->master->channel, master->channel);
04114    slave->master = master;
04115    
04116    ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
04117 }
04118 
04119 static void disable_dtmf_detect(struct dahdi_pvt *p)
04120 {
04121    int val;
04122 
04123    p->ignoredtmf = 1;
04124 
04125    val = 0;
04126    ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
04127 
04128    if (!p->hardwaredtmf && p->dsp) {
04129       p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
04130       ast_dsp_set_features(p->dsp, p->dsp_features);
04131    }
04132 }
04133 
04134 static void enable_dtmf_detect(struct dahdi_pvt *p)
04135 {
04136    int val;
04137 
04138    if (p->channel == CHAN_PSEUDO)
04139       return;
04140 
04141    p->ignoredtmf = 0;
04142 
04143    val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
04144    ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
04145 
04146    if (!p->hardwaredtmf && p->dsp) {
04147       p->dsp_features |= DSP_FEATURE_DIGIT_DETECT;
04148       ast_dsp_set_features(p->dsp, p->dsp_features);
04149    }
04150 }
04151 
04152 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)
04153 {
04154    struct ast_channel *who;
04155    struct dahdi_pvt *p0, *p1, *op0, *op1;
04156    struct dahdi_pvt *master = NULL, *slave = NULL;
04157    struct ast_frame *f;
04158    int inconf = 0;
04159    int nothingok = 1;
04160    int ofd0, ofd1;
04161    int oi0, oi1, i0 = -1, i1 = -1, t0, t1;
04162    int os0 = -1, os1 = -1;
04163    int priority = 0;
04164    struct ast_channel *oc0, *oc1;
04165    enum ast_bridge_result res;
04166 
04167 #ifdef PRI_2BCT
04168    int triedtopribridge = 0;
04169    q931_call *q931c0 = NULL, *q931c1 = NULL;
04170 #endif
04171 
04172    /* For now, don't attempt to native bridge if either channel needs DTMF detection.
04173       There is code below to handle it properly until DTMF is actually seen,
04174       but due to currently unresolved issues it's ignored...
04175    */
04176 
04177    if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
04178       return AST_BRIDGE_FAILED_NOWARN;
04179 
04180    ast_channel_lock(c0);
04181    while (ast_channel_trylock(c1)) {
04182       CHANNEL_DEADLOCK_AVOIDANCE(c0);
04183    }
04184 
04185    p0 = c0->tech_pvt;
04186    p1 = c1->tech_pvt;
04187    /* cant do pseudo-channels here */
04188    if (!p0 || (!p0->sig) || !p1 || (!p1->sig)) {
04189       ast_channel_unlock(c0);
04190       ast_channel_unlock(c1);
04191       return AST_BRIDGE_FAILED_NOWARN;
04192    }
04193 
04194    oi0 = dahdi_get_index(c0, p0, 0);
04195    oi1 = dahdi_get_index(c1, p1, 0);
04196    if ((oi0 < 0) || (oi1 < 0)) {
04197       ast_channel_unlock(c0);
04198       ast_channel_unlock(c1);
04199       return AST_BRIDGE_FAILED;
04200    }
04201 
04202    op0 = p0 = c0->tech_pvt;
04203    op1 = p1 = c1->tech_pvt;
04204    ofd0 = c0->fds[0];
04205    ofd1 = c1->fds[0];
04206    oc0 = p0->owner;
04207    oc1 = p1->owner;
04208 
04209    if (ast_mutex_trylock(&p0->lock)) {
04210       /* Don't block, due to potential for deadlock */
04211       ast_channel_unlock(c0);
04212       ast_channel_unlock(c1);
04213       ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
04214       return AST_BRIDGE_RETRY;
04215    }
04216    if (ast_mutex_trylock(&p1->lock)) {
04217       /* Don't block, due to potential for deadlock */
04218       ast_mutex_unlock(&p0->lock);
04219       ast_channel_unlock(c0);
04220       ast_channel_unlock(c1);
04221       ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
04222       return AST_BRIDGE_RETRY;
04223    }
04224 
04225    if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
04226       if (p0->owner && p1->owner) {
04227          /* If we don't have a call-wait in a 3-way, and we aren't in a 3-way, we can be master */
04228          if (!p0->subs[SUB_CALLWAIT].inthreeway && !p1->subs[SUB_REAL].inthreeway) {
04229             master = p0;
04230             slave = p1;
04231             inconf = 1;
04232          } else if (!p1->subs[SUB_CALLWAIT].inthreeway && !p0->subs[SUB_REAL].inthreeway) {
04233             master = p1;
04234             slave = p0;
04235             inconf = 1;
04236          } else {
04237             ast_log(LOG_WARNING, "Huh?  Both calls are callwaits or 3-ways?  That's clever...?\n");
04238             ast_log(LOG_WARNING, "p0: chan %d/%d/CW%d/3W%d, p1: chan %d/%d/CW%d/3W%d\n",
04239                p0->channel,
04240                oi0, (p0->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
04241                p0->subs[SUB_REAL].inthreeway, p0->channel,
04242                oi0, (p1->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
04243                p1->subs[SUB_REAL].inthreeway);
04244          }
04245          nothingok = 0;
04246       }
04247    } else if ((oi0 == SUB_REAL) && (oi1 == SUB_THREEWAY)) {
04248       if (p1->subs[SUB_THREEWAY].inthreeway) {
04249          master = p1;
04250          slave = p0;
04251          nothingok = 0;
04252       }
04253    } else if ((oi0 == SUB_THREEWAY) && (oi1 == SUB_REAL)) {
04254       if (p0->subs[SUB_THREEWAY].inthreeway) {
04255          master = p0;
04256          slave = p1;
04257          nothingok = 0;
04258       }
04259    } else if ((oi0 == SUB_REAL) && (oi1 == SUB_CALLWAIT)) {
04260       /* We have a real and a call wait.  If we're in a three way call, put us in it, otherwise, 
04261          don't put us in anything */
04262       if (p1->subs[SUB_CALLWAIT].inthreeway) {
04263          master = p1;
04264          slave = p0;
04265          nothingok = 0;
04266       }
04267    } else if ((oi0 == SUB_CALLWAIT) && (oi1 == SUB_REAL)) {
04268       /* Same as previous */
04269       if (p0->subs[SUB_CALLWAIT].inthreeway) {
04270          master = p0;
04271          slave = p1;
04272          nothingok = 0;
04273       }
04274    }
04275    ast_debug(1, "master: %d, slave: %d, nothingok: %d\n",
04276       master ? master->channel : 0, slave ? slave->channel : 0, nothingok);
04277    if (master && slave) {
04278       /* Stop any tones, or play ringtone as appropriate.  If they're bridged
04279          in an active threeway call with a channel that is ringing, we should
04280          indicate ringing. */
04281       if ((oi1 == SUB_THREEWAY) && 
04282           p1->subs[SUB_THREEWAY].inthreeway && 
04283           p1->subs[SUB_REAL].owner && 
04284           p1->subs[SUB_REAL].inthreeway && 
04285           (p1->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
04286          ast_debug(1, "Playing ringback on %s since %s is in a ringing three-way\n", c0->name, c1->name);
04287          tone_zone_play_tone(p0->subs[oi0].dfd, DAHDI_TONE_RINGTONE);
04288          os1 = p1->subs[SUB_REAL].owner->_state;
04289       } else {
04290          ast_debug(1, "Stopping tones on %d/%d talking to %d/%d\n", p0->channel, oi0, p1->channel, oi1);
04291          tone_zone_play_tone(p0->subs[oi0].dfd, -1);
04292       }
04293       if ((oi0 == SUB_THREEWAY) && 
04294           p0->subs[SUB_THREEWAY].inthreeway && 
04295           p0->subs[SUB_REAL].owner && 
04296           p0->subs[SUB_REAL].inthreeway && 
04297           (p0->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
04298          ast_debug(1, "Playing ringback on %s since %s is in a ringing three-way\n", c1->name, c0->name);
04299          tone_zone_play_tone(p1->subs[oi1].dfd, DAHDI_TONE_RINGTONE);
04300          os0 = p0->subs[SUB_REAL].owner->_state;
04301       } else {
04302          ast_debug(1, "Stopping tones on %d/%d talking to %d/%d\n", p1->channel, oi1, p0->channel, oi0);
04303          tone_zone_play_tone(p1->subs[oi0].dfd, -1);
04304       }
04305       if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
04306          if (!p0->echocanbridged || !p1->echocanbridged) {
04307             /* Disable echo cancellation if appropriate */
04308             dahdi_disable_ec(p0);
04309             dahdi_disable_ec(p1);
04310          }
04311       }
04312       dahdi_link(slave, master);
04313       master->inconference = inconf;
04314    } else if (!nothingok)
04315       ast_log(LOG_WARNING, "Can't link %d/%s with %d/%s\n", p0->channel, subnames[oi0], p1->channel, subnames[oi1]);
04316 
04317    update_conf(p0);
04318    update_conf(p1);
04319    t0 = p0->subs[SUB_REAL].inthreeway;
04320    t1 = p1->subs[SUB_REAL].inthreeway;
04321 
04322    ast_mutex_unlock(&p0->lock);
04323    ast_mutex_unlock(&p1->lock);
04324 
04325    ast_channel_unlock(c0);
04326    ast_channel_unlock(c1);
04327 
04328    /* Native bridge failed */
04329    if ((!master || !slave) && !nothingok) {
04330       dahdi_enable_ec(p0);
04331       dahdi_enable_ec(p1);
04332       return AST_BRIDGE_FAILED;
04333    }
04334    
04335    ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);
04336 
04337    if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
04338       disable_dtmf_detect(op0);
04339 
04340    if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
04341       disable_dtmf_detect(op1);
04342 
04343    for (;;) {
04344       struct ast_channel *c0_priority[2] = {c0, c1};
04345       struct ast_channel *c1_priority[2] = {c1, c0};
04346 
04347       /* Here's our main loop...  Start by locking things, looking for private parts, 
04348          and then balking if anything is wrong */
04349       
04350       ast_channel_lock(c0);
04351       while (ast_channel_trylock(c1)) {
04352          CHANNEL_DEADLOCK_AVOIDANCE(c0);
04353       }
04354 
04355       p0 = c0->tech_pvt;
04356       p1 = c1->tech_pvt;
04357 
04358       if (op0 == p0)
04359          i0 = dahdi_get_index(c0, p0, 1);
04360       if (op1 == p1)
04361          i1 = dahdi_get_index(c1, p1, 1);
04362 
04363       ast_channel_unlock(c0);
04364       ast_channel_unlock(c1);
04365 
04366       if (!timeoutms || 
04367           (op0 != p0) ||
04368           (op1 != p1) || 
04369           (ofd0 != c0->fds[0]) || 
04370           (ofd1 != c1->fds[0]) ||
04371           (p0->subs[SUB_REAL].owner && (os0 > -1) && (os0 != p0->subs[SUB_REAL].owner->_state)) || 
04372           (p1->subs[SUB_REAL].owner && (os1 > -1) && (os1 != p1->subs[SUB_REAL].owner->_state)) || 
04373           (oc0 != p0->owner) || 
04374           (oc1 != p1->owner) ||
04375           (t0 != p0->subs[SUB_REAL].inthreeway) ||
04376           (t1 != p1->subs[SUB_REAL].inthreeway) ||
04377           (oi0 != i0) ||
04378           (oi1 != i1)) {
04379          ast_debug(1, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n",
04380             op0->channel, oi0, op1->channel, oi1);
04381          res = AST_BRIDGE_RETRY;
04382          goto return_from_bridge;
04383       }
04384 
04385 #ifdef PRI_2BCT
04386       q931c0 = p0->call;
04387       q931c1 = p1->call;
04388       if (p0->transfer && p1->transfer 
04389           && q931c0 && q931c1 
04390           && !triedtopribridge) {
04391          pri_channel_bridge(q931c0, q931c1);
04392          triedtopribridge = 1;
04393       }
04394 #endif
04395 
04396       who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &timeoutms);
04397       if (!who) {
04398          ast_debug(1, "Ooh, empty read...\n");
04399          continue;
04400       }
04401       f = ast_read(who);
04402       if (!f || (f->frametype == AST_FRAME_CONTROL)) {
04403          *fo = f;
04404          *rc = who;
04405          res = AST_BRIDGE_COMPLETE;
04406          goto return_from_bridge;
04407       }
04408       if (f->frametype == AST_FRAME_DTMF) {
04409          if ((who == c0) && p0->pulsedial) {
04410             ast_write(c1, f);
04411          } else if ((who == c1) && p1->pulsedial) {
04412             ast_write(c0, f);
04413          } else {
04414             *fo = f;
04415             *rc = who;
04416             res = AST_BRIDGE_COMPLETE;
04417             goto return_from_bridge;
04418          }
04419       }
04420       ast_frfree(f);
04421       
04422       /* Swap who gets priority */
04423       priority = !priority;
04424    }
04425 
04426 return_from_bridge:
04427    if (op0 == p0)
04428       dahdi_enable_ec(p0);
04429 
04430    if (op1 == p1)
04431       dahdi_enable_ec(p1);
04432 
04433    if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
04434       enable_dtmf_detect(op0);
04435 
04436    if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
04437       enable_dtmf_detect(op1);
04438 
04439    dahdi_unlink(slave, master, 1);
04440 
04441    return res;
04442 }
04443 
04444 static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
04445 {
04446    struct dahdi_pvt *p = newchan->tech_pvt;
04447    int x;
04448    ast_mutex_lock(&p->lock);
04449    ast_debug(1, "New owner for channel %d is %s\n", p->channel, newchan->name);
04450    if (p->owner == oldchan) {
04451       p->owner = newchan;
04452    }
04453    for (x = 0; x < 3; x++)
04454       if (p->subs[x].owner == oldchan) {
04455          if (!x)
04456             dahdi_unlink(NULL, p, 0);
04457          p->subs[x].owner = newchan;
04458       }
04459    if (newchan->_state == AST_STATE_RINGING) 
04460       dahdi_indicate(newchan, AST_CONTROL_RINGING, NULL, 0);
04461    update_conf(p);
04462    ast_mutex_unlock(&p->lock);
04463    return 0;
04464 }
04465 
04466 static int dahdi_ring_phone(struct dahdi_pvt *p)
04467 {
04468    int x;
04469    int res;
04470    /* Make sure our transmit state is on hook */
04471    x = 0;
04472    x = DAHDI_ONHOOK;
04473    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
04474    do {
04475       x = DAHDI_RING;
04476       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
04477       if (res) {
04478          switch (errno) {
04479          case EBUSY:
04480          case EINTR:
04481             /* Wait just in case */
04482             usleep(10000);
04483             continue;
04484          case EINPROGRESS:
04485             res = 0;
04486             break;
04487          default:
04488             ast_log(LOG_WARNING, "Couldn't ring the phone: %s\n", strerror(errno));
04489             res = 0;
04490          }
04491       }
04492    } while (res);
04493    return res;
04494 }
04495 
04496 static void *ss_thread(void *data);
04497 
04498 static struct ast_channel *dahdi_new(struct dahdi_pvt *, int, int, int, int, int);
04499 
04500 static int attempt_transfer(struct dahdi_pvt *p)
04501 {
04502    /* In order to transfer, we need at least one of the channels to
04503       actually be in a call bridge.  We can't conference two applications
04504       together (but then, why would we want to?) */
04505    if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
04506       /* The three-way person we're about to transfer to could still be in MOH, so
04507          stop if now if appropriate */
04508       if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner))
04509          ast_queue_control(p->subs[SUB_THREEWAY].owner, AST_CONTROL_UNHOLD);
04510       if (p->subs[SUB_REAL].owner->_state == AST_STATE_RINGING) {
04511          ast_indicate(ast_bridged_channel(p->subs[SUB_REAL].owner), AST_CONTROL_RINGING);
04512       }
04513       if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RING) {
04514          tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
04515       }
04516        if (ast_channel_masquerade(p->subs[SUB_THREEWAY].owner, ast_bridged_channel(p->subs[SUB_REAL].owner))) {
04517          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
04518                ast_bridged_channel(p->subs[SUB_REAL].owner)->name, p->subs[SUB_THREEWAY].owner->name);
04519          return -1;
04520       }
04521       /* Orphan the channel after releasing the lock */
04522       ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04523       unalloc_sub(p, SUB_THREEWAY);
04524    } else if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
04525       ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
04526       if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RINGING) {
04527          ast_indicate(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), AST_CONTROL_RINGING);
04528       }
04529       if (p->subs[SUB_REAL].owner->_state == AST_STATE_RING) {
04530          tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
04531       }
04532       if (ast_channel_masquerade(p->subs[SUB_REAL].owner, ast_bridged_channel(p->subs[SUB_THREEWAY].owner))) {
04533          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
04534                ast_bridged_channel(p->subs[SUB_THREEWAY].owner)->name, p->subs[SUB_REAL].owner->name);
04535          return -1;
04536       }
04537       /* Three-way is now the REAL */
04538       swap_subs(p, SUB_THREEWAY, SUB_REAL);
04539       ast_channel_unlock(p->subs[SUB_REAL].owner);
04540       unalloc_sub(p, SUB_THREEWAY);
04541       /* Tell the caller not to hangup */
04542       return 1;
04543    } else {
04544       ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
04545          p->subs[SUB_REAL].owner->name, p->subs[SUB_THREEWAY].owner->name);
04546       p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
04547       return -1;
04548    }
04549    return 0;
04550 }
04551 
04552 static int check_for_conference(struct dahdi_pvt *p)
04553 {
04554    struct dahdi_confinfo ci;
04555    /* Fine if we already have a master, etc */
04556    if (p->master || (p->confno > -1))
04557       return 0;
04558    memset(&ci, 0, sizeof(ci));
04559    if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
04560       ast_log(LOG_WARNING, "Failed to get conference info on channel %d: %s\n", p->channel, strerror(errno));
04561       return 0;
04562    }
04563    /* If we have no master and don't have a confno, then 
04564       if we're in a conference, it's probably a MeetMe room or
04565       some such, so don't let us 3-way out! */
04566    if ((p->subs[SUB_REAL].curconf.confno != ci.confno) || (p->subs[SUB_REAL].curconf.confmode != ci.confmode)) {
04567       ast_verb(3, "Avoiding 3-way call when in an external conference\n");
04568       return 1;
04569    }
04570    return 0;
04571 }
04572 
04573 /*! Checks channel for alarms
04574  * \param p a channel to check for alarms.
04575  * \returns the alarms on the span to which the channel belongs, or alarms on
04576  *          the channel if no span alarms.
04577  */
04578 static int get_alarms(struct dahdi_pvt *p)
04579 {
04580    int res;
04581    struct dahdi_spaninfo zi;
04582    struct dahdi_params params;
04583 
04584    memset(&zi, 0, sizeof(zi));
04585    zi.spanno = p->span;
04586 
04587    if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SPANSTAT, &zi)) >= 0) {
04588       if (zi.alarms != DAHDI_ALARM_NONE)
04589          return zi.alarms;
04590    } else {
04591       ast_log(LOG_WARNING, "Unable to determine alarm on channel %d: %s\n", p->channel, strerror(errno));
04592       return 0;
04593    }
04594 
04595    /* No alarms on the span. Check for channel alarms. */
04596    memset(&params, 0, sizeof(params));
04597    if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &params)) >= 0)
04598       return params.chan_alarms;
04599 
04600    ast_log(LOG_WARNING, "Unable to determine alarm on channel %d\n", p->channel);
04601 
04602    return DAHDI_ALARM_NONE;
04603 }
04604 
04605 static void dahdi_handle_dtmfup(struct ast_channel *ast, int idx, struct ast_frame **dest)
04606 {
04607    struct dahdi_pvt *p = ast->tech_pvt;
04608    struct ast_frame *f = *dest;
04609 
04610    ast_debug(1, "DTMF digit: %c on %s\n", f->subclass, ast->name);
04611 
04612    if (p->confirmanswer) {
04613       ast_debug(1, "Confirm answer on %s!\n", ast->name);
04614       /* Upon receiving a DTMF digit, consider this an answer confirmation instead
04615          of a DTMF digit */
04616       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04617       p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
04618       *dest = &p->subs[idx].f;
04619       /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
04620       p->confirmanswer = 0;
04621    } else if (p->callwaitcas) {
04622       if ((f->subclass == 'A') || (f->subclass == 'D')) {
04623          ast_debug(1, "Got some DTMF, but it's for the CAS\n");
04624          if (p->cidspill)
04625             ast_free(p->cidspill);
04626          send_cwcidspill(p);
04627       }
04628       p->callwaitcas = 0;
04629       p->subs[idx].f.frametype = AST_FRAME_NULL;
04630       p->subs[idx].f.subclass = 0;
04631       *dest = &p->subs[idx].f;
04632    } else if (f->subclass == 'f') {
04633       /* Fax tone -- Handle and return NULL */
04634       if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
04635          p->faxhandled = 1;
04636          if (strcmp(ast->exten, "fax")) {
04637             const char *target_context = S_OR(ast->macrocontext, ast->context);
04638 
04639             /* We need to unlock 'ast' here because ast_exists_extension has the
04640              * potential to start autoservice on the channel. Such action is prone
04641              * to deadlock.
04642              */
04643             ast_mutex_unlock(&p->lock);
04644             ast_channel_unlock(ast);
04645             if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
04646                ast_channel_lock(ast);
04647                ast_mutex_lock(&p->lock);
04648                ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
04649                /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
04650                pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
04651                if (ast_async_goto(ast, target_context, "fax", 1))
04652                   ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
04653             } else {
04654                ast_channel_lock(ast);
04655                ast_mutex_lock(&p->lock);
04656                ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
04657             }
04658          } else {
04659             ast_debug(1, "Already in a fax extension, not redirecting\n");
04660          }
04661       } else {
04662          ast_debug(1, "Fax already handled\n");
04663       }
04664       dahdi_confmute(p, 0);
04665       p->subs[idx].f.frametype = AST_FRAME_NULL;
04666       p->subs[idx].f.subclass = 0;
04667       *dest = &p->subs[idx].f;
04668    }
04669 }
04670          
04671 static void handle_alarms(struct dahdi_pvt *p, int alms)
04672 {
04673    const char *alarm_str = alarm2str(alms);
04674 
04675    ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
04676    manager_event(EVENT_FLAG_SYSTEM, "Alarm",
04677             "Alarm: %s\r\n"
04678             "Channel: %d\r\n",
04679             alarm_str, p->channel);
04680 }
04681 
04682 static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
04683 {
04684    int res, x;
04685    int idx, mysig;
04686    char *c;
04687    struct dahdi_pvt *p = ast->tech_pvt;
04688    pthread_t threadid;
04689    struct ast_channel *chan;
04690    struct ast_frame *f;
04691 
04692    idx = dahdi_get_index(ast, p, 0);
04693    mysig = p->sig;
04694    if (p->outsigmod > -1)
04695       mysig = p->outsigmod;
04696    p->subs[idx].f.frametype = AST_FRAME_NULL;
04697    p->subs[idx].f.subclass = 0;
04698    p->subs[idx].f.datalen = 0;
04699    p->subs[idx].f.samples = 0;
04700    p->subs[idx].f.mallocd = 0;
04701    p->subs[idx].f.offset = 0;
04702    p->subs[idx].f.src = "dahdi_handle_event";
04703    p->subs[idx].f.data.ptr = NULL;
04704    f = &p->subs[idx].f;
04705 
04706    if (idx < 0)
04707       return &p->subs[idx].f;
04708    if (p->fake_event) {
04709       res = p->fake_event;
04710       p->fake_event = 0;
04711    } else
04712       res = dahdi_get_event(p->subs[idx].dfd);
04713 
04714    ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, idx);
04715 
04716    if (res & (DAHDI_EVENT_PULSEDIGIT | DAHDI_EVENT_DTMFUP)) {
04717       p->pulsedial =  (res & DAHDI_EVENT_PULSEDIGIT) ? 1 : 0;
04718       ast_debug(1, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
04719 #ifdef HAVE_PRI
04720       if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
04721          /* absorb event */
04722       } else {
04723 #endif
04724          dahdi_confmute(p, 0);
04725          p->subs[idx].f.frametype = AST_FRAME_DTMF_END;
04726          p->subs[idx].f.subclass = res & 0xff;
04727 #ifdef HAVE_PRI
04728       }
04729 #endif
04730       dahdi_handle_dtmfup(ast, idx, &f);
04731       return f;
04732    }
04733 
04734    if (res & DAHDI_EVENT_DTMFDOWN) {
04735       ast_debug(1, "DTMF Down '%c'\n", res & 0xff);
04736       /* Mute conference */
04737       dahdi_confmute(p, 1);
04738       p->subs[idx].f.frametype = AST_FRAME_DTMF_BEGIN;
04739       p->subs[idx].f.subclass = res & 0xff;
04740       return &p->subs[idx].f;
04741    }
04742 
04743    switch (res) {
04744       case DAHDI_EVENT_EC_DISABLED:
04745          ast_verb(3, "Channel %d echo canceler disabled due to CED detection\n", p->channel);
04746          p->echocanon = 0;
04747          break;
04748       case DAHDI_EVENT_BITSCHANGED:
04749          ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig));
04750       case DAHDI_EVENT_PULSE_START:
04751          /* Stop tone if there's a pulse start and the PBX isn't started */
04752          if (!ast->pbx)
04753             tone_zone_play_tone(p->subs[idx].dfd, -1);
04754          break;   
04755       case DAHDI_EVENT_DIALCOMPLETE:
04756          if (p->inalarm) break;
04757          if ((p->radio || (p->oprmode < 0))) break;
04758          if (ioctl(p->subs[idx].dfd,DAHDI_DIALING,&x) == -1) {
04759             ast_log(LOG_DEBUG, "DAHDI_DIALING ioctl failed on %s: %s\n",ast->name, strerror(errno));
04760             return NULL;
04761          }
04762          if (!x) { /* if not still dialing in driver */
04763             dahdi_enable_ec(p);
04764             if (p->echobreak) {
04765                dahdi_train_ec(p);
04766                ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
04767                p->dop.op = DAHDI_DIAL_OP_REPLACE;
04768                res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
04769                p->echobreak = 0;
04770             } else {
04771                p->dialing = 0;
04772                if ((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) {
04773                   /* if thru with dialing after offhook */
04774                   if (ast->_state == AST_STATE_DIALING_OFFHOOK) {
04775                      ast_setstate(ast, AST_STATE_UP);
04776                      p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04777                      p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
04778                      break;
04779                   } else { /* if to state wait for offhook to dial rest */
04780                      /* we now wait for off hook */
04781                      ast_setstate(ast,AST_STATE_DIALING_OFFHOOK);
04782                   }
04783                }
04784                if (ast->_state == AST_STATE_DIALING) {
04785                   if ((p->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
04786                      ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n");
04787                   } 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)))) {
04788                      ast_setstate(ast, AST_STATE_RINGING);
04789                   } else if (!p->answeronpolarityswitch) {
04790                      ast_setstate(ast, AST_STATE_UP);
04791                      p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04792                      p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
04793                      /* If aops=0 and hops=1, this is necessary */
04794                      p->polarity = POLARITY_REV;
04795                   } else {
04796                      /* Start clean, so we can catch the change to REV polarity when party answers */
04797                      p->polarity = POLARITY_IDLE;
04798                   }
04799                }
04800             }
04801          }
04802          break;
04803       case DAHDI_EVENT_ALARM:
04804 #ifdef HAVE_PRI
04805          if ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
04806             if (!p->pri || !p->pri->pri || (pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0)) {
04807                /* T309 is not enabled : hangup calls when alarm occurs */
04808                if (p->call) {
04809                   if (p->pri && p->pri->pri) {
04810                      if (!pri_grab(p, p->pri)) {
04811                         pri_hangup(p->pri->pri, p->call, -1);
04812                         pri_destroycall(p->pri->pri, p->call);
04813                         p->call = NULL;
04814                         pri_rel(p->pri);
04815                      } else
04816                         ast_log(LOG_WARNING, "Failed to grab PRI!\n");
04817                   } else
04818                      ast_log(LOG_WARNING, "The PRI Call has not been destroyed\n");
04819                }
04820                if (p->owner)
04821                   p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
04822             }
04823          }
04824          if (p->bearer)
04825             p->bearer->inalarm = 1;
04826          else
04827 #endif
04828          p->inalarm = 1;
04829          res = get_alarms(p);
04830          handle_alarms(p, res);
04831 #ifdef HAVE_PRI
04832          if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
04833             /* fall through intentionally */
04834          } else {
04835             break;
04836          }
04837 #endif
04838 #ifdef HAVE_SS7
04839          if (p->sig == SIG_SS7)
04840             break;
04841 #endif
04842       case DAHDI_EVENT_ONHOOK:
04843          if (p->radio) {
04844             p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04845             p->subs[idx].f.subclass = AST_CONTROL_RADIO_UNKEY;
04846             break;
04847          }
04848          if (p->oprmode < 0)
04849          {
04850             if (p->oprmode != -1) break;
04851             if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
04852             {
04853                /* Make sure it starts ringing */
04854                dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
04855                dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RING);
04856                save_conference(p->oprpeer);
04857                tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
04858             }
04859             break;
04860          }
04861          switch (p->sig) {
04862          case SIG_FXOLS:
04863          case SIG_FXOGS:
04864          case SIG_FXOKS:
04865             p->onhooktime = time(NULL);
04866             p->msgstate = -1;
04867             /* Check for some special conditions regarding call waiting */
04868             if (idx == SUB_REAL) {
04869                /* The normal line was hung up */
04870                if (p->subs[SUB_CALLWAIT].owner) {
04871                   /* There's a call waiting call, so ring the phone, but make it unowned in the mean time */
04872                   swap_subs(p, SUB_CALLWAIT, SUB_REAL);
04873                   ast_verb(3, "Channel %d still has (callwait) call, ringing phone\n", p->channel);
04874                   unalloc_sub(p, SUB_CALLWAIT); 
04875 #if 0
04876                   p->subs[idx].needanswer = 0;
04877                   p->subs[idx].needringing = 0;
04878 #endif                  
04879                   p->callwaitingrepeat = 0;
04880                   p->cidcwexpire = 0;
04881                   p->owner = NULL;
04882                   /* Don't start streaming audio yet if the incoming call isn't up yet */
04883                   if (p->subs[SUB_REAL].owner->_state != AST_STATE_UP)
04884                      p->dialing = 1;
04885                   dahdi_ring_phone(p);
04886                } else if (p->subs[SUB_THREEWAY].owner) {
04887                   unsigned int mssinceflash;
04888                   /* Here we have to retain the lock on both the main channel, the 3-way channel, and
04889                      the private structure -- not especially easy or clean */
04890                   while (p->subs[SUB_THREEWAY].owner && ast_channel_trylock(p->subs[SUB_THREEWAY].owner)) {
04891                      /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
04892                      DLA_UNLOCK(&p->lock);
04893                      CHANNEL_DEADLOCK_AVOIDANCE(ast);
04894                      /* We can grab ast and p in that order, without worry.  We should make sure
04895                         nothing seriously bad has happened though like some sort of bizarre double
04896                         masquerade! */
04897                      DLA_LOCK(&p->lock);
04898                      if (p->owner != ast) {
04899                         ast_log(LOG_WARNING, "This isn't good...\n");
04900                         return NULL;
04901                      }
04902                   }
04903                   if (!p->subs[SUB_THREEWAY].owner) {
04904                      ast_log(LOG_NOTICE, "Whoa, threeway disappeared kinda randomly.\n");
04905                      return NULL;
04906                   }
04907                   mssinceflash = ast_tvdiff_ms(ast_tvnow(), p->flashtime);
04908                   ast_debug(1, "Last flash was %d ms ago\n", mssinceflash);
04909                   if (mssinceflash < MIN_MS_SINCE_FLASH) {
04910                      /* It hasn't been long enough since the last flashook.  This is probably a bounce on 
04911                         hanging up.  Hangup both channels now */
04912                      if (p->subs[SUB_THREEWAY].owner)
04913                         ast_queue_hangup_with_cause(p->subs[SUB_THREEWAY].owner, AST_CAUSE_NO_ANSWER);
04914                      p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
04915                      ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
04916                      ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04917                   } else if ((ast->pbx) || (ast->_state == AST_STATE_UP)) {
04918                      if (p->transfer) {
04919                         /* In any case this isn't a threeway call anymore */
04920                         p->subs[SUB_REAL].inthreeway = 0;
04921                         p->subs[SUB_THREEWAY].inthreeway = 0;
04922                         /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
04923                         if (!p->transfertobusy && ast->_state == AST_STATE_BUSY) {
04924                            ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04925                            /* Swap subs and dis-own channel */
04926                            swap_subs(p, SUB_THREEWAY, SUB_REAL);
04927                            p->owner = NULL;
04928                            /* Ring the phone */
04929                            dahdi_ring_phone(p);
04930                         } else {
04931                            if ((res = attempt_transfer(p)) < 0) {
04932                               p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
04933                               if (p->subs[SUB_THREEWAY].owner)
04934                                  ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04935                            } else if (res) {
04936                               /* Don't actually hang up at this point */
04937                               if (p->subs[SUB_THREEWAY].owner)
04938                                  ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04939                               break;
04940                            }
04941                         }
04942                      } else {
04943                         p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
04944                         if (p->subs[SUB_THREEWAY].owner)
04945                            ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04946                      }
04947                   } else {
04948                      ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04949                      /* Swap subs and dis-own channel */
04950                      swap_subs(p, SUB_THREEWAY, SUB_REAL);
04951                      p->owner = NULL;
04952                      /* Ring the phone */
04953                      dahdi_ring_phone(p);
04954                   }
04955                }
04956             } else {
04957                ast_log(LOG_WARNING, "Got a hangup and my index is %d?\n", idx);
04958             }
04959             /* Fall through */
04960          default:
04961             dahdi_disable_ec(p);
04962             return NULL;
04963          }
04964          break;
04965       case DAHDI_EVENT_RINGOFFHOOK:
04966          if (p->inalarm) break;
04967          if (p->oprmode < 0)
04968          {
04969             if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
04970             {
04971                /* Make sure it stops ringing */
04972                dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
04973                tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, -1);
04974                restore_conference(p->oprpeer);
04975             }
04976             break;
04977          }
04978          if (p->radio)
04979          {
04980             p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04981             p->subs[idx].f.subclass = AST_CONTROL_RADIO_KEY;
04982             break;
04983          }
04984          /* for E911, its supposed to wait for offhook then dial
04985             the second half of the dial string */
04986          if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast->_state == AST_STATE_DIALING_OFFHOOK)) {
04987             c = strchr(p->dialdest, '/');
04988             if (c)
04989                c++;
04990             else
04991                c = p->dialdest;
04992             if (*c) snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
04993             else ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
04994             if (strlen(p->dop.dialstr) > 4) {
04995                memset(p->echorest, 'w', sizeof(p->echorest) - 1);
04996                strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
04997                p->echorest[sizeof(p->echorest) - 1] = '\0';
04998                p->echobreak = 1;
04999                p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
05000             } else
05001                p->echobreak = 0;
05002             if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
05003                int saveerr = errno;
05004 
05005                x = DAHDI_ONHOOK;
05006                ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
05007                ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
05008                return NULL;
05009                }
05010             p->dialing = 1;
05011             return &p->subs[idx].f;
05012          }
05013          switch (p->sig) {
05014          case SIG_FXOLS:
05015          case SIG_FXOGS:
05016          case SIG_FXOKS:
05017             switch (ast->_state) {
05018             case AST_STATE_RINGING:
05019                dahdi_enable_ec(p);
05020                dahdi_train_ec(p);
05021                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05022                p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
05023                /* Make sure it stops ringing */
05024                dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
05025                ast_debug(1, "channel %d answered\n", p->channel);
05026                if (p->cidspill) {
05027                   /* Cancel any running CallerID spill */
05028                   ast_free(p->cidspill);
05029                   p->cidspill = NULL;
05030                }
05031                p->dialing = 0;
05032                p->callwaitcas = 0;
05033                if (p->confirmanswer) {
05034                   /* Ignore answer if "confirm answer" is enabled */
05035                   p->subs[idx].f.frametype = AST_FRAME_NULL;
05036                   p->subs[idx].f.subclass = 0;
05037                } else if (!ast_strlen_zero(p->dop.dialstr)) {
05038                   /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
05039                   res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
05040                   if (res < 0) {
05041                      ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
05042                      p->dop.dialstr[0] = '\0';
05043                      return NULL;
05044                   } else {
05045                      ast_debug(1, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
05046                      p->subs[idx].f.frametype = AST_FRAME_NULL;
05047                      p->subs[idx].f.subclass = 0;
05048                      p->dialing = 1;
05049                   }
05050                   p->dop.dialstr[0] = '\0';
05051                   ast_setstate(ast, AST_STATE_DIALING);
05052                } else
05053                   ast_setstate(ast, AST_STATE_UP);
05054                return &p->subs[idx].f;
05055             case AST_STATE_DOWN:
05056                ast_setstate(ast, AST_STATE_RING);
05057                ast->rings = 1;
05058                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05059                p->subs[idx].f.subclass = AST_CONTROL_OFFHOOK;
05060                ast_debug(1, "channel %d picked up\n", p->channel);
05061                return &p->subs[idx].f;
05062             case AST_STATE_UP:
05063                /* Make sure it stops ringing */
05064                dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
05065                /* Okay -- probably call waiting*/
05066                if (ast_bridged_channel(p->owner))
05067                   ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
05068                p->subs[idx].needunhold = 1;
05069                break;
05070             case AST_STATE_RESERVED:
05071                /* Start up dialtone */
05072                if (has_voicemail(p))
05073                   res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
05074                else
05075                   res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
05076                break;
05077             default:
05078                ast_log(LOG_WARNING, "FXO phone off hook in weird state %d??\n", ast->_state);
05079             }
05080             break;
05081          case SIG_FXSLS:
05082          case SIG_FXSGS:
05083          case SIG_FXSKS:
05084             if (ast->_state == AST_STATE_RING) {
05085                p->ringt = p->ringt_base;
05086             }
05087 
05088             /* If we get a ring then we cannot be in 
05089              * reversed polarity. So we reset to idle */
05090             ast_debug(1, "Setting IDLE polarity due "
05091                "to ring. Old polarity was %d\n", 
05092                p->polarity);
05093             p->polarity = POLARITY_IDLE;
05094 
05095             /* Fall through */
05096          case SIG_EM:
05097          case SIG_EM_E1:
05098          case SIG_EMWINK:
05099          case SIG_FEATD:
05100          case SIG_FEATDMF:
05101          case SIG_FEATDMF_TA:
05102          case SIG_E911:
05103          case SIG_FGC_CAMA:
05104          case SIG_FGC_CAMAMF:
05105          case SIG_FEATB:
05106          case SIG_SF:
05107          case SIG_SFWINK:
05108          case SIG_SF_FEATD:
05109          case SIG_SF_FEATDMF:
05110          case SIG_SF_FEATB:
05111             if (ast->_state == AST_STATE_PRERING)
05112                ast_setstate(ast, AST_STATE_RING);
05113             if ((ast->_state == AST_STATE_DOWN) || (ast->_state == AST_STATE_RING)) {
05114                ast_debug(1, "Ring detected\n");
05115                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05116                p->subs[idx].f.subclass = AST_CONTROL_RING;
05117             } else if (p->outgoing && ((ast->_state == AST_STATE_RINGING) || (ast->_state == AST_STATE_DIALING))) {
05118                ast_debug(1, "Line answered\n");
05119                if (p->confirmanswer) {
05120                   p->subs[idx].f.frametype = AST_FRAME_NULL;
05121                   p->subs[idx].f.subclass = 0;
05122                } else {
05123                   p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05124                   p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
05125                   ast_setstate(ast, AST_STATE_UP);
05126                }
05127             } else if (ast->_state != AST_STATE_RING)
05128                ast_log(LOG_WARNING, "Ring/Off-hook in strange state %d on channel %d\n", ast->_state, p->channel);
05129             break;
05130          default:
05131             ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
05132          }
05133          break;
05134       case DAHDI_EVENT_RINGBEGIN:
05135          switch (p->sig) {
05136          case SIG_FXSLS:
05137          case SIG_FXSGS:
05138          case SIG_FXSKS:
05139             if (ast->_state == AST_STATE_RING) {
05140                p->ringt = p->ringt_base;
05141             }
05142             break;
05143          }
05144          break;
05145       case DAHDI_EVENT_RINGEROFF:
05146          if (p->inalarm) break;
05147          if ((p->radio || (p->oprmode < 0))) break;
05148          ast->rings++;
05149          if ((ast->rings > p->cidrings) && (p->cidspill)) {
05150             ast_log(LOG_WARNING, "Didn't finish Caller-ID spill.  Cancelling.\n");
05151             ast_free(p->cidspill);
05152             p->cidspill = NULL;
05153             p->callwaitcas = 0;
05154          }
05155          p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05156          p->subs[idx].f.subclass = AST_CONTROL_RINGING;
05157          break;
05158       case DAHDI_EVENT_RINGERON:
05159          break;
05160       case DAHDI_EVENT_NOALARM:
05161          p->inalarm = 0;
05162 #ifdef HAVE_PRI
05163          /* Extremely unlikely but just in case */
05164          if (p->bearer)
05165             p->bearer->inalarm = 0;
05166 #endif            
05167          ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
05168          manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
05169                         "Channel: %d\r\n", p->channel);
05170          break;
05171       case DAHDI_EVENT_WINKFLASH:
05172          if (p->inalarm) break;
05173          if (p->radio) break;
05174          if (p->oprmode < 0) break;
05175          if (p->oprmode > 1)
05176          {
05177             struct dahdi_params par;
05178 
05179             memset(&par, 0, sizeof(par));
05180             if (ioctl(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par) != -1)
05181             {
05182                if (!par.rxisoffhook)
05183                {
05184                   /* Make sure it stops ringing */
05185                   dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
05186                   dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RING);
05187                   save_conference(p);
05188                   tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
05189                }
05190             }
05191             break;
05192          }
05193          /* Remember last time we got a flash-hook */
05194          p->flashtime = ast_tvnow();
05195          switch (mysig) {
05196          case SIG_FXOLS:
05197          case SIG_FXOGS:
05198          case SIG_FXOKS:
05199             ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
05200                idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
05201             p->callwaitcas = 0;
05202 
05203             if (idx != SUB_REAL) {
05204                ast_log(LOG_WARNING, "Got flash hook with index %d on channel %d?!?\n", idx, p->channel);
05205                goto winkflashdone;
05206             }
05207             
05208             if (p->subs[SUB_CALLWAIT].owner) {
05209                /* Swap to call-wait */
05210                swap_subs(p, SUB_REAL, SUB_CALLWAIT);
05211                tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
05212                p->owner = p->subs[SUB_REAL].owner;
05213                ast_debug(1, "Making %s the new owner\n", p->owner->name);
05214                if (p->owner->_state == AST_STATE_RINGING) {
05215                   ast_setstate(p->owner, AST_STATE_UP);
05216                   p->subs[SUB_REAL].needanswer = 1;
05217                }
05218                p->callwaitingrepeat = 0;
05219                p->cidcwexpire = 0;
05220                /* Start music on hold if appropriate */
05221                if (!p->subs[SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
05222                   ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
05223                      S_OR(p->mohsuggest, NULL),
05224                      !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
05225                }
05226                p->subs[SUB_CALLWAIT].needhold = 1;
05227                if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
05228                   ast_queue_control_data(p->subs[SUB_REAL].owner, AST_CONTROL_HOLD,
05229                      S_OR(p->mohsuggest, NULL),
05230                      !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
05231                }
05232                p->subs[SUB_REAL].needunhold = 1;
05233             } else if (!p->subs[SUB_THREEWAY].owner) {
05234                if (!p->threewaycalling) {
05235                   /* Just send a flash if no 3-way calling */
05236                   p->subs[SUB_REAL].needflash = 1;
05237                   goto winkflashdone;
05238                } else if (!check_for_conference(p)) {
05239                   char cid_num[256];
05240                   char cid_name[256];
05241 
05242                   cid_num[0] = 0;
05243                   cid_name[0] = 0;
05244                   if (p->dahditrcallerid && p->owner) {
05245                      if (p->owner->cid.cid_num)
05246                         ast_copy_string(cid_num, p->owner->cid.cid_num, sizeof(cid_num));
05247                      if (p->owner->cid.cid_name)
05248                         ast_copy_string(cid_name, p->owner->cid.cid_name, sizeof(cid_name));
05249                   }
05250                   /* XXX This section needs much more error checking!!! XXX */
05251                   /* Start a 3-way call if feasible */
05252                   if (!((ast->pbx) ||
05253                         (ast->_state == AST_STATE_UP) ||
05254                         (ast->_state == AST_STATE_RING))) {
05255                      ast_debug(1, "Flash when call not up or ringing\n");
05256                      goto winkflashdone;
05257                   }
05258                   if (alloc_sub(p, SUB_THREEWAY)) {
05259                      ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
05260                      goto winkflashdone;
05261                   }
05262                   /* Make new channel */
05263                   chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, 0);
05264                   if (p->dahditrcallerid) {
05265                      if (!p->origcid_num)
05266                         p->origcid_num = ast_strdup(p->cid_num);
05267                      if (!p->origcid_name)
05268                         p->origcid_name = ast_strdup(p->cid_name);
05269                      ast_copy_string(p->cid_num, cid_num, sizeof(p->cid_num));
05270                      ast_copy_string(p->cid_name, cid_name, sizeof(p->cid_name));
05271                   }
05272                   /* Swap things around between the three-way and real call */
05273                   swap_subs(p, SUB_THREEWAY, SUB_REAL);
05274                   /* Disable echo canceller for better dialing */
05275                   dahdi_disable_ec(p);
05276                   res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
05277                   if (res)
05278                      ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
05279                   p->owner = chan;
05280                   if (!chan) {
05281                      ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", p->channel);
05282                   } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
05283                      ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
05284                      res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
05285                      dahdi_enable_ec(p);
05286                      ast_hangup(chan);
05287                   } else {
05288                      struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner);
05289                      int way3bridge = 0, cdr3way = 0;
05290                      
05291                      if (!other) {
05292                         other = ast_bridged_channel(p->subs[SUB_REAL].owner);
05293                      } else
05294                         way3bridge = 1;
05295                      
05296                      if (p->subs[SUB_THREEWAY].owner->cdr)
05297                         cdr3way = 1;
05298                      
05299                      ast_verb(3, "Started three way call on channel %d\n", p->channel);
05300 
05301                      /* Start music on hold if appropriate */
05302                      if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
05303                         ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
05304                            S_OR(p->mohsuggest, NULL),
05305                            !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
05306                      }
05307                      p->subs[SUB_THREEWAY].needhold = 1;
05308                   }
05309                }
05310             } else {
05311                /* Already have a 3 way call */
05312                if (p->subs[SUB_THREEWAY].inthreeway) {
05313                   /* Call is already up, drop the last person */
05314                   ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
05315                   /* If the primary call isn't answered yet, use it */
05316                   if ((p->subs[SUB_REAL].owner->_state != AST_STATE_UP) && (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_UP)) {
05317                      /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
05318                      swap_subs(p, SUB_THREEWAY, SUB_REAL);
05319                      p->owner = p->subs[SUB_REAL].owner;
05320                   }
05321                   /* Drop the last call and stop the conference */
05322                   ast_verb(3, "Dropping three-way call on %s\n", p->subs[SUB_THREEWAY].owner->name);
05323                   p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
05324                   p->subs[SUB_REAL].inthreeway = 0;
05325                   p->subs[SUB_THREEWAY].inthreeway = 0;
05326                } else {
05327                   /* Lets see what we're up to */
05328                   if (((ast->pbx) || (ast->_state == AST_STATE_UP)) && 
05329                       (p->transfertobusy || (ast->_state != AST_STATE_BUSY))) {
05330                      int otherindex = SUB_THREEWAY;
05331                      struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner);
05332                      int way3bridge = 0, cdr3way = 0;
05333                      
05334                      if (!other) {
05335                         other = ast_bridged_channel(p->subs[SUB_REAL].owner);
05336                      } else
05337                         way3bridge = 1;
05338                      
05339                      if (p->subs[SUB_THREEWAY].owner->cdr)
05340                         cdr3way = 1;
05341 
05342                      ast_verb(3, "Building conference on call on %s and %s\n", p->subs[SUB_THREEWAY].owner->name, p->subs[SUB_REAL].owner->name);
05343                      /* Put them in the threeway, and flip */
05344                      p->subs[SUB_THREEWAY].inthreeway = 1;
05345                      p->subs[SUB_REAL].inthreeway = 1;
05346                      if (ast->_state == AST_STATE_UP) {
05347                         swap_subs(p, SUB_THREEWAY, SUB_REAL);
05348                         otherindex = SUB_REAL;
05349                      }
05350                      if (p->subs[otherindex].owner && ast_bridged_channel(p->subs[otherindex].owner))
05351                         ast_queue_control(p->subs[otherindex].owner, AST_CONTROL_UNHOLD);
05352                      p->subs[otherindex].needunhold = 1;
05353                      p->owner = p->subs[SUB_REAL].owner;
05354                      if (ast->_state == AST_STATE_RINGING) {
05355                         ast_debug(1, "Enabling ringtone on real and threeway\n");
05356                         res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
05357                         res = tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
05358                      }
05359                   } else {
05360                      ast_verb(3, "Dumping incomplete call on on %s\n", p->subs[SUB_THREEWAY].owner->name);
05361                      swap_subs(p, SUB_THREEWAY, SUB_REAL);
05362                      p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
05363                      p->owner = p->subs[SUB_REAL].owner;
05364                      if (p->subs[SUB_REAL].owner && ast_bridged_channel(p->subs[SUB_REAL].owner))
05365                         ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
05366                      p->subs[SUB_REAL].needunhold = 1;
05367                      dahdi_enable_ec(p);
05368                   }
05369                      
05370                }
05371             }
05372          winkflashdone:              
05373             update_conf(p);
05374             break;
05375          case SIG_EM:
05376          case SIG_EM_E1:
05377          case SIG_FEATD:
05378          case SIG_SF:
05379          case SIG_SFWINK:
05380          case SIG_SF_FEATD:
05381          case SIG_FXSLS:
05382          case SIG_FXSGS:
05383             if (option_debug) {
05384                if (p->dialing)
05385                   ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
05386                else
05387                   ast_debug(1, "Got wink in weird state %d on channel %d\n", ast->_state, p->channel);
05388             }
05389             break;
05390          case SIG_FEATDMF_TA:
05391             switch (p->whichwink) {
05392             case 0:
05393                ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
05394                snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
05395                break;
05396             case 1:
05397                ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
05398                break;
05399             case 2:
05400                ast_log(LOG_WARNING, "Received unexpected wink on channel of type SIG_FEATDMF_TA\n");
05401                return NULL;
05402             }
05403             p->whichwink++;
05404             /* Fall through */
05405          case SIG_FEATDMF:
05406          case SIG_E911:
05407          case SIG_FGC_CAMAMF:
05408          case SIG_FGC_CAMA:
05409          case SIG_FEATB:
05410          case SIG_SF_FEATDMF:
05411          case SIG_SF_FEATB:
05412          case SIG_EMWINK:
05413             /* FGD MF and EMWINK *Must* wait for wink */
05414             if (!ast_strlen_zero(p->dop.dialstr)) {
05415                res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
05416                if (res < 0) {
05417                   ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
05418                   p->dop.dialstr[0] = '\0';
05419                   return NULL;
05420                } else 
05421                   ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
05422             }
05423             p->dop.dialstr[0] = '\0';
05424             break;
05425          default:
05426             ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
05427          }
05428          break;
05429       case DAHDI_EVENT_HOOKCOMPLETE:
05430          if (p->inalarm) break;
05431          if ((p->radio || (p->oprmode < 0))) break;
05432          switch (mysig) {
05433          case SIG_FXSLS:  /* only interesting for FXS */
05434          case SIG_FXSGS:
05435          case SIG_FXSKS:
05436          case SIG_EM:
05437          case SIG_EM_E1:
05438          case SIG_EMWINK:
05439          case SIG_FEATD:
05440          case SIG_SF:
05441          case SIG_SFWINK:
05442          case SIG_SF_FEATD:
05443             if (!ast_strlen_zero(p->dop.dialstr)) {
05444                res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
05445                if (res < 0) {
05446                   ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
05447                   p->dop.dialstr[0] = '\0';
05448                   return NULL;
05449                } else 
05450                   ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
05451             }
05452             p->dop.dialstr[0] = '\0';
05453             p->dop.op = DAHDI_DIAL_OP_REPLACE;
05454             break;
05455          case SIG_FEATDMF:
05456          case SIG_FEATDMF_TA:
05457          case SIG_E911:
05458          case SIG_FGC_CAMA:
05459          case SIG_FGC_CAMAMF:
05460          case SIG_FEATB:
05461          case SIG_SF_FEATDMF:
05462          case SIG_SF_FEATB:
05463             ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
05464             break;
05465          default:
05466             break;
05467          }
05468          break;
05469       case DAHDI_EVENT_POLARITY:
05470          /*
05471           * If we get a Polarity Switch event, this could be
05472           * due to line seizure, remote end connect or remote end disconnect.
05473           *
05474           * Check to see if we should change the polarity state and
05475           * mark the channel as UP or if this is an indication
05476           * of remote end disconnect.
05477           */
05478 
05479          if (p->polarityonanswerdelay > 0) {
05480             /* check if event is not too soon after OffHook or Answer */
05481                if (ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) > p->polarityonanswerdelay) {
05482                switch (ast->_state) {
05483                case AST_STATE_DIALING:       /*!< Digits (or equivalent) have been dialed */
05484                case AST_STATE_RINGING:       /*!< Remote end is ringing */
05485                   if (p->answeronpolarityswitch) {
05486                      ast_debug(1, "Answering on polarity switch! channel %d\n", p->channel);
05487                      ast_setstate(p->owner, AST_STATE_UP);
05488                      p->polarity = POLARITY_REV;
05489                      if (p->hanguponpolarityswitch) {
05490                         p->polaritydelaytv = ast_tvnow();
05491                      }
05492                   } else {
05493                      ast_debug(1, "Ignore Answer on polarity switch, channel %d\n", p->channel);
05494                   }
05495                   break;
05496                case AST_STATE_UP:         /*!< Line is up */
05497                case AST_STATE_RING:       /*!< Line is ringing */
05498                   if (p->hanguponpolarityswitch) {
05499                      ast_debug(1, "HangingUp on polarity switch! channel %d\n", p->channel);
05500                      ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
05501                      p->polarity = POLARITY_IDLE;
05502                   } else {
05503                      ast_debug(1, "Ignore Hangup on polarity switch, channel %d\n", p->channel);
05504                   }
05505                   break;
05506 
05507                case AST_STATE_DOWN:       /*!< Channel is down and available */
05508                case AST_STATE_RESERVED:      /*!< Channel is down, but reserved */
05509                case AST_STATE_OFFHOOK:       /*!< Channel is off hook */
05510                case AST_STATE_BUSY:       /*!< Line is busy */
05511                case AST_STATE_DIALING_OFFHOOK:     /*!< Digits (or equivalent) have been dialed while offhook */
05512                case AST_STATE_PRERING:       /*!< Channel has detected an incoming call and is waiting for ring */
05513                default:
05514                   if (p->answeronpolarityswitch || p->hanguponpolarityswitch) {
05515                      ast_debug(1, "Ignoring Polarity switch on channel %d, state %d\n", p->channel, ast->_state);
05516                   }
05517 
05518                }
05519 
05520             } else {
05521                /* event is too soon after OffHook or Answer */
05522                switch (ast->_state) {
05523                case AST_STATE_DIALING:       /*!< Digits (or equivalent) have been dialed */
05524                case AST_STATE_RINGING:       /*!< Remote end is ringing */
05525                   if (p->answeronpolarityswitch) {
05526                      ast_debug(1, "Polarity switch detected but NOT answering (too close to OffHook event) on channel %d, state %d\n", p->channel, ast->_state);
05527                   }
05528                   break;
05529 
05530                case AST_STATE_UP:         /*!< Line is up */
05531                case AST_STATE_RING:       /*!< Line is ringing */
05532                   if (p->hanguponpolarityswitch) {
05533                      ast_debug(1, "Polarity switch detected but NOT hanging up (too close to Answer event) on channel %d, state %d\n", p->channel, ast->_state);
05534                   }
05535                   break;
05536 
05537                default: 
05538                   if (p->answeronpolarityswitch || p->hanguponpolarityswitch) {
05539                      ast_debug(1, "Polarity switch detected (too close to previous event) on channel %d, state %d\n", p->channel, ast->_state);
05540                   }
05541                }
05542             }
05543          }
05544                         /* Added more log_debug information below to provide a better indication of what is going on */
05545          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) );
05546          break;
05547       default:
05548          ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
05549    }
05550    return &p->subs[idx].f;
05551 }
05552 
05553 static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
05554 {
05555    struct dahdi_pvt *p = ast->tech_pvt;
05556    int res;
05557    int usedindex=-1;
05558    int idx;
05559    struct ast_frame *f;
05560 
05561 
05562    idx = dahdi_get_index(ast, p, 1);
05563    
05564    p->subs[idx].f.frametype = AST_FRAME_NULL;
05565    p->subs[idx].f.datalen = 0;
05566    p->subs[idx].f.samples = 0;
05567    p->subs[idx].f.mallocd = 0;
05568    p->subs[idx].f.offset = 0;
05569    p->subs[idx].f.subclass = 0;
05570    p->subs[idx].f.delivery = ast_tv(0,0);
05571    p->subs[idx].f.src = "dahdi_exception";
05572    p->subs[idx].f.data.ptr = NULL;
05573    
05574    
05575    if ((!p->owner) && (!(p->radio || (p->oprmode < 0)))) {
05576       /* If nobody owns us, absorb the event appropriately, otherwise
05577          we loop indefinitely.  This occurs when, during call waiting, the
05578          other end hangs up our channel so that it no longer exists, but we
05579          have neither FLASH'd nor ONHOOK'd to signify our desire to
05580          change to the other channel. */
05581       if (p->fake_event) {
05582          res = p->fake_event;
05583          p->fake_event = 0;
05584       } else
05585          res = dahdi_get_event(p->subs[SUB_REAL].dfd);
05586       /* Switch to real if there is one and this isn't something really silly... */
05587       if ((res != DAHDI_EVENT_RINGEROFF) && (res != DAHDI_EVENT_RINGERON) &&
05588          (res != DAHDI_EVENT_HOOKCOMPLETE)) {
05589          ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
05590          p->owner = p->subs[SUB_REAL].owner;
05591          if (p->owner && ast_bridged_channel(p->owner))
05592             ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
05593          p->subs[SUB_REAL].needunhold = 1;
05594       }
05595       switch (res) {
05596       case DAHDI_EVENT_ONHOOK:
05597          dahdi_disable_ec(p);
05598          if (p->owner) {
05599             ast_verb(3, "Channel %s still has call, ringing phone\n", p->owner->name);
05600             dahdi_ring_phone(p);
05601             p->callwaitingrepeat = 0;
05602             p->cidcwexpire = 0;
05603          } else
05604             ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
05605          update_conf(p);
05606          break;
05607       case DAHDI_EVENT_RINGOFFHOOK:
05608          dahdi_enable_ec(p);
05609          dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
05610          if (p->owner && (p->owner->_state == AST_STATE_RINGING)) {
05611             p->subs[SUB_REAL].needanswer = 1;
05612             p->dialing = 0;
05613          }
05614          break;
05615       case DAHDI_EVENT_HOOKCOMPLETE:
05616       case DAHDI_EVENT_RINGERON:
05617       case DAHDI_EVENT_RINGEROFF:
05618          /* Do nothing */
05619          break;
05620       case DAHDI_EVENT_WINKFLASH:
05621          p->flashtime = ast_tvnow();
05622          if (p->owner) {
05623             ast_verb(3, "Channel %d flashed to other channel %s\n", p->channel, p->owner->name);
05624             if (p->owner->_state != AST_STATE_UP) {
05625                /* Answer if necessary */
05626                usedindex = dahdi_get_index(p->owner, p, 0);
05627                if (usedindex > -1) {
05628                   p->subs[usedindex].needanswer = 1;
05629                }
05630                ast_setstate(p->owner, AST_STATE_UP);
05631             }
05632             p->callwaitingrepeat = 0;
05633             p->cidcwexpire = 0;
05634             if (ast_bridged_channel(p->owner))
05635                ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
05636             p->subs[SUB_REAL].needunhold = 1;
05637          } else
05638             ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
05639          update_conf(p);
05640          break;
05641       default:
05642          ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", event2str(res));
05643       }
05644       f = &p->subs[idx].f;
05645       return f;
05646    }
05647    if (!(p->radio || (p->oprmode < 0))) 
05648       ast_debug(1, "Exception on %d, channel %d\n", ast->fds[0],p->channel);
05649    /* If it's not us, return NULL immediately */
05650    if (ast != p->owner) {
05651       ast_log(LOG_WARNING, "We're %s, not %s\n", ast->name, p->owner->name);
05652       f = &p->subs[idx].f;
05653       return f;
05654    }
05655    f = dahdi_handle_event(ast);
05656    return f;
05657 }
05658 
05659 static struct ast_frame *dahdi_exception(struct ast_channel *ast)
05660 {
05661    struct dahdi_pvt *p = ast->tech_pvt;
05662    struct ast_frame *f;
05663    ast_mutex_lock(&p->lock);
05664    f = __dahdi_exception(ast);
05665    ast_mutex_unlock(&p->lock);
05666    return f;
05667 }
05668 
05669 static struct ast_frame  *dahdi_read(struct ast_channel *ast)
05670 {
05671    struct dahdi_pvt *p = ast->tech_pvt;
05672    int res;
05673    int idx;
05674    void *readbuf;
05675    struct ast_frame *f;
05676 
05677    while (ast_mutex_trylock(&p->lock)) {
05678       CHANNEL_DEADLOCK_AVOIDANCE(ast);
05679    }
05680 
05681    idx = dahdi_get_index(ast, p, 0);
05682    
05683    /* Hang up if we don't really exist */
05684    if (idx < 0)   {
05685       ast_log(LOG_WARNING, "We dont exist?\n");
05686       ast_mutex_unlock(&p->lock);
05687       return NULL;
05688    }
05689    
05690    if ((p->radio || (p->oprmode < 0)) && p->inalarm) {
05691       ast_mutex_unlock(&p->lock);
05692       return NULL;
05693    }
05694 
05695    p->subs[idx].f.frametype = AST_FRAME_NULL;
05696    p->subs[idx].f.datalen = 0;
05697    p->subs[idx].f.samples = 0;
05698    p->subs[idx].f.mallocd = 0;
05699    p->subs[idx].f.offset = 0;
05700    p->subs[idx].f.subclass = 0;
05701    p->subs[idx].f.delivery = ast_tv(0,0);
05702    p->subs[idx].f.src = "dahdi_read";
05703    p->subs[idx].f.data.ptr = NULL;
05704    
05705    /* make sure it sends initial key state as first frame */
05706    if ((p->radio || (p->oprmode < 0)) && (!p->firstradio))
05707    {
05708       struct dahdi_params ps;
05709 
05710       memset(&ps, 0, sizeof(ps));
05711       ps.channo = p->channel;
05712       if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
05713          ast_mutex_unlock(&p->lock);
05714          return NULL;
05715       }
05716       p->firstradio = 1;
05717       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05718       if (ps.rxisoffhook)
05719       {
05720          p->subs[idx].f.subclass = AST_CONTROL_RADIO_KEY;
05721       }
05722       else
05723       {
05724          p->subs[idx].f.subclass = AST_CONTROL_RADIO_UNKEY;
05725       }
05726       ast_mutex_unlock(&p->lock);
05727       return &p->subs[idx].f;
05728    }
05729    if (p->ringt == 1) {
05730       ast_mutex_unlock(&p->lock);
05731       return NULL;
05732    }
05733    else if (p->ringt > 0) 
05734       p->ringt--;
05735 
05736    if (p->subs[idx].needringing) {
05737       /* Send ringing frame if requested */
05738       p->subs[idx].needringing = 0;
05739       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05740       p->subs[idx].f.subclass = AST_CONTROL_RINGING;
05741       ast_setstate(ast, AST_STATE_RINGING);
05742       ast_mutex_unlock(&p->lock);
05743       return &p->subs[idx].f;
05744    }
05745 
05746    if (p->subs[idx].needbusy) {
05747       /* Send busy frame if requested */
05748       p->subs[idx].needbusy = 0;
05749       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05750       p->subs[idx].f.subclass = AST_CONTROL_BUSY;
05751       ast_mutex_unlock(&p->lock);
05752       return &p->subs[idx].f;
05753    }
05754 
05755    if (p->subs[idx].needcongestion) {
05756       /* Send congestion frame if requested */
05757       p->subs[idx].needcongestion = 0;
05758       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05759       p->subs[idx].f.subclass = AST_CONTROL_CONGESTION;
05760       ast_mutex_unlock(&p->lock);
05761       return &p->subs[idx].f;
05762    }
05763 
05764    if (p->subs[idx].needcallerid) {
05765       ast_set_callerid(ast, S_OR(p->lastcid_num, NULL),
05766                      S_OR(p->lastcid_name, NULL),
05767                      S_OR(p->lastcid_num, NULL)
05768                      );
05769       p->subs[idx].needcallerid = 0;
05770    }
05771    
05772    if (p->subs[idx].needanswer) {
05773       /* Send answer frame if requested */
05774       p->subs[idx].needanswer = 0;
05775       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05776       p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
05777       ast_mutex_unlock(&p->lock);
05778       return &p->subs[idx].f;
05779    }  
05780    
05781    if (p->subs[idx].needflash) {
05782       /* Send answer frame if requested */
05783       p->subs[idx].needflash = 0;
05784       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05785       p->subs[idx].f.subclass = AST_CONTROL_FLASH;
05786       ast_mutex_unlock(&p->lock);
05787       return &p->subs[idx].f;
05788    }  
05789    
05790    if (p->subs[idx].needhold) {
05791       /* Send answer frame if requested */
05792       p->subs[idx].needhold = 0;
05793       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05794       p->subs[idx].f.subclass = AST_CONTROL_HOLD;
05795       ast_mutex_unlock(&p->lock);
05796       ast_debug(1, "Sending hold on '%s'\n", ast->name);
05797       return &p->subs[idx].f;
05798    }  
05799    
05800    if (p->subs[idx].needunhold) {
05801       /* Send answer frame if requested */
05802       p->subs[idx].needunhold = 0;
05803       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05804       p->subs[idx].f.subclass = AST_CONTROL_UNHOLD;
05805       ast_mutex_unlock(&p->lock);
05806       ast_debug(1, "Sending unhold on '%s'\n", ast->name);
05807       return &p->subs[idx].f;
05808    }  
05809    
05810    if (ast->rawreadformat == AST_FORMAT_SLINEAR) {
05811       if (!p->subs[idx].linear) {
05812          p->subs[idx].linear = 1;
05813          res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
05814          if (res) 
05815             ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to linear mode.\n", p->channel, idx);
05816       }
05817    } else if ((ast->rawreadformat == AST_FORMAT_ULAW) ||
05818          (ast->rawreadformat == AST_FORMAT_ALAW)) {
05819       if (p->subs[idx].linear) {
05820          p->subs[idx].linear = 0;
05821          res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
05822          if (res) 
05823             ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to companded mode.\n", p->channel, idx);
05824       }
05825    } else {
05826       ast_log(LOG_WARNING, "Don't know how to read frames in format %s\n", ast_getformatname(ast->rawreadformat));
05827       ast_mutex_unlock(&p->lock);
05828       return NULL;
05829    }
05830    readbuf = ((unsigned char *)p->subs[idx].buffer) + AST_FRIENDLY_OFFSET;
05831    CHECK_BLOCKING(ast);
05832    res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
05833    ast_clear_flag(ast, AST_FLAG_BLOCKING);
05834    /* Check for hangup */
05835    if (res < 0) {
05836       f = NULL;
05837       if (res == -1)  {
05838          if (errno == EAGAIN) {
05839             /* Return "NULL" frame if there is nobody there */
05840             ast_mutex_unlock(&p->lock);
05841             return &p->subs[idx].f;
05842          } else if (errno == ELAST) {
05843             f = __dahdi_exception(ast);
05844          } else
05845             ast_log(LOG_WARNING, "dahdi_rec: %s\n", strerror(errno));
05846       }
05847       ast_mutex_unlock(&p->lock);
05848       return f;
05849    }
05850    if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
05851       ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
05852       f = __dahdi_exception(ast);
05853       ast_mutex_unlock(&p->lock);
05854       return f;
05855    }
05856    if (p->tdd) { /* if in TDD mode, see if we receive that */
05857       int c;
05858 
05859       c = tdd_feed(p->tdd,readbuf,READ_SIZE);
05860       if (c < 0) {
05861          ast_debug(1,"tdd_feed failed\n");
05862          ast_mutex_unlock(&p->lock);
05863          return NULL;
05864       }
05865       if (c) { /* if a char to return */
05866          p->subs[idx].f.subclass = 0;
05867          p->subs[idx].f.frametype = AST_FRAME_TEXT;
05868          p->subs[idx].f.mallocd = 0;
05869          p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
05870          p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET;
05871          p->subs[idx].f.datalen = 1;
05872          *((char *) p->subs[idx].f.data.ptr) = c;
05873          ast_mutex_unlock(&p->lock);
05874          return &p->subs[idx].f;
05875       }
05876    }
05877    /* Ensure the CW timer decrements only on a single subchannel */
05878    if (p->callwaitingrepeat && dahdi_get_index(ast, p, 1) == SUB_REAL) {
05879       p->callwaitingrepeat--;
05880    }
05881    if (p->cidcwexpire)
05882       p->cidcwexpire--;
05883    /* Repeat callwaiting */
05884    if (p->callwaitingrepeat == 1) {
05885       p->callwaitrings++;
05886       dahdi_callwait(ast);
05887    }
05888    /* Expire CID/CW */
05889    if (p->cidcwexpire == 1) {
05890       ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
05891       restore_conference(p);
05892    }
05893    if (p->subs[idx].linear) {
05894       p->subs[idx].f.datalen = READ_SIZE * 2;
05895    } else 
05896       p->subs[idx].f.datalen = READ_SIZE;
05897 
05898    /* Handle CallerID Transmission */
05899    if ((p->owner == ast) && p->cidspill &&((ast->_state == AST_STATE_UP) || (ast->rings == p->cidrings))) {
05900       send_callerid(p);
05901    }
05902 
05903    p->subs[idx].f.frametype = AST_FRAME_VOICE;
05904    p->subs[idx].f.subclass = ast->rawreadformat;
05905    p->subs[idx].f.samples = READ_SIZE;
05906    p->subs[idx].f.mallocd = 0;
05907    p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
05908    p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET / sizeof(p->subs[idx].buffer[0]);
05909 #if 0
05910    ast_debug(1, "Read %d of voice on %s\n", p->subs[idx].f.datalen, ast->name);
05911 #endif   
05912    if (p->dialing || /* Transmitting something */
05913       (idx && (ast->_state != AST_STATE_UP)) || /* Three-way or callwait that isn't up */
05914       ((idx == SUB_CALLWAIT) && !p->subs[SUB_CALLWAIT].inthreeway) /* Inactive and non-confed call-wait */
05915       ) {
05916       /* Whoops, we're still dialing, or in a state where we shouldn't transmit....
05917          don't send anything */
05918       p->subs[idx].f.frametype = AST_FRAME_NULL;
05919       p->subs[idx].f.subclass = 0;
05920       p->subs[idx].f.samples = 0;
05921       p->subs[idx].f.mallocd = 0;
05922       p->subs[idx].f.offset = 0;
05923       p->subs[idx].f.data.ptr = NULL;
05924       p->subs[idx].f.datalen= 0;
05925    }
05926    if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect  || p->callprogress) && !idx) {
05927       /* Perform busy detection. etc on the dahdi line */
05928       int mute;
05929 
05930       f = ast_dsp_process(ast, p->dsp, &p->subs[idx].f);
05931 
05932       /* Check if DSP code thinks we should be muting this frame and mute the conference if so */
05933       mute = ast_dsp_was_muted(p->dsp);
05934       if (p->muting != mute) {
05935          p->muting = mute;
05936          dahdi_confmute(p, mute);
05937       }
05938 
05939       if (f) {
05940          if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_BUSY)) {
05941             if ((ast->_state == AST_STATE_UP) && !p->outgoing) {
05942                /* Treat this as a "hangup" instead of a "busy" on the assumption that
05943                   a busy  */
05944                f = NULL;
05945             }
05946          } else if (f->frametype == AST_FRAME_DTMF) {
05947 #ifdef HAVE_PRI
05948             if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri && 
05949                 ((!p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) ||
05950                  (p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)))) {
05951                /* Don't accept in-band DTMF when in overlap dial mode */
05952                f->frametype = AST_FRAME_NULL;
05953                f->subclass = 0;
05954             }
05955 #endif            
05956             /* DSP clears us of being pulse */
05957             p->pulsedial = 0;
05958          }
05959       }
05960    } else 
05961       f = &p->subs[idx].f; 
05962 
05963    if (f && (f->frametype == AST_FRAME_DTMF))
05964       dahdi_handle_dtmfup(ast, idx, &f);
05965 
05966    /* If we have a fake_event, trigger exception to handle it */
05967    if (p->fake_event)
05968       ast_set_flag(ast, AST_FLAG_EXCEPTION);
05969 
05970    ast_mutex_unlock(&p->lock);
05971    return f;
05972 }
05973 
05974 static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int idx, int linear)
05975 {
05976    int sent=0;
05977    int size;
05978    int res;
05979    int fd;
05980    fd = p->subs[idx].dfd;
05981    while (len) {
05982       size = len;
05983       if (size > (linear ? READ_SIZE * 2 : READ_SIZE))
05984          size = (linear ? READ_SIZE * 2 : READ_SIZE);
05985       res = write(fd, buf, size);
05986       if (res != size) {
05987          ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
05988          return sent;
05989       }
05990       len -= size;
05991       buf += size;
05992    }
05993    return sent;
05994 }
05995 
05996 static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
05997 {
05998    struct dahdi_pvt *p = ast->tech_pvt;
05999    int res;
06000    int idx;
06001    idx = dahdi_get_index(ast, p, 0);
06002    if (idx < 0) {
06003       ast_log(LOG_WARNING, "%s doesn't really exist?\n", ast->name);
06004       return -1;
06005    }
06006 
06007 #if 0
06008 #ifdef HAVE_PRI
06009    ast_mutex_lock(&p->lock);
06010    if (!p->proceeding && p->sig==SIG_PRI && p->pri && !p->outgoing) {
06011       if (p->pri->pri) {      
06012          if (!pri_grab(p, p->pri)) {
06013                pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
06014                pri_rel(p->pri);
06015          } else
06016                ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06017       }
06018       p->proceeding=1;
06019    }
06020    ast_mutex_unlock(&p->lock);
06021 #endif
06022 #endif
06023    /* Write a frame of (presumably voice) data */
06024    if (frame->frametype != AST_FRAME_VOICE) {
06025       if (frame->frametype != AST_FRAME_IMAGE)
06026          ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
06027       return 0;
06028    }
06029    if ((frame->subclass != AST_FORMAT_SLINEAR) && 
06030        (frame->subclass != AST_FORMAT_ULAW) &&
06031        (frame->subclass != AST_FORMAT_ALAW)) {
06032       ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
06033       return -1;
06034    }
06035    if (p->dialing) {
06036       ast_debug(1, "Dropping frame since I'm still dialing on %s...\n",ast->name);
06037       return 0;
06038    }
06039    if (!p->owner) {
06040       ast_debug(1, "Dropping frame since there is no active owner on %s...\n",ast->name);
06041       return 0;
06042    }
06043    if (p->cidspill) {
06044       ast_debug(1, "Dropping frame since I've still got a callerid spill\n");
06045       return 0;
06046    }
06047    /* Return if it's not valid data */
06048    if (!frame->data.ptr || !frame->datalen)
06049       return 0;
06050 
06051    if (frame->subclass == AST_FORMAT_SLINEAR) {
06052       if (!p->subs[idx].linear) {
06053          p->subs[idx].linear = 1;
06054          res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
06055          if (res)
06056             ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
06057       }
06058       res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 1);
06059    } else {
06060       /* x-law already */
06061       if (p->subs[idx].linear) {
06062          p->subs[idx].linear = 0;
06063          res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
06064          if (res)
06065             ast_log(LOG_WARNING, "Unable to set companded mode on channel %d\n", p->channel);
06066       }
06067       res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 0);
06068    }
06069    if (res < 0) {
06070       ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
06071       return -1;
06072    } 
06073    return 0;
06074 }
06075 
06076 static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
06077 {
06078    struct dahdi_pvt *p = chan->tech_pvt;
06079    int res=-1;
06080    int idx;
06081    int func = DAHDI_FLASH;
06082    ast_mutex_lock(&p->lock);
06083    idx = dahdi_get_index(chan, p, 0);
06084    ast_debug(1, "Requested indication %d on channel %s\n", condition, chan->name);
06085    if (idx == SUB_REAL) {
06086       switch (condition) {
06087       case AST_CONTROL_BUSY:
06088 #ifdef HAVE_PRI
06089          if (p->priindication_oob && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))) {
06090             chan->hangupcause = AST_CAUSE_USER_BUSY;
06091             chan->_softhangup |= AST_SOFTHANGUP_DEV;
06092             res = 0;
06093          } else if (!p->progress && 
06094                ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
06095                && p->pri && !p->outgoing) {
06096             if (p->pri->pri) {      
06097                if (!pri_grab(p, p->pri)) {
06098                   pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
06099                   pri_rel(p->pri);
06100                }
06101                else
06102                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06103             }
06104             p->progress = 1;
06105             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY);
06106          } else
06107 #endif
06108             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY);
06109          break;
06110       case AST_CONTROL_RINGING:
06111 #ifdef HAVE_PRI
06112          if ((!p->alerting) && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) 
06113                && p->pri && !p->outgoing && (chan->_state != AST_STATE_UP)) {
06114             if (p->pri->pri) {      
06115                if (!pri_grab(p, p->pri)) {
06116                   pri_acknowledge(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
06117                   pri_rel(p->pri);
06118                }
06119                else
06120                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06121             }
06122             p->alerting = 1;
06123          }
06124 
06125 #endif
06126 #ifdef HAVE_SS7
06127          if ((!p->alerting) && (p->sig == SIG_SS7) && p->ss7 && !p->outgoing && (chan->_state != AST_STATE_UP)) {
06128             if (p->ss7->ss7) {
06129                ss7_grab(p, p->ss7);
06130                
06131                if ((isup_far(p->ss7->ss7, p->ss7call)) != -1)
06132                   p->rlt = 1;
06133                if (p->rlt != 1) /* No need to send CPG if call will be RELEASE */
06134                   isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_ALERTING);
06135                p->alerting = 1;
06136                ss7_rel(p->ss7);
06137             }
06138          }
06139 #endif
06140             
06141          res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_RINGTONE);
06142          
06143          if (chan->_state != AST_STATE_UP) {
06144             if ((chan->_state != AST_STATE_RING) ||
06145                ((p->sig != SIG_FXSKS) &&
06146              (p->sig != SIG_FXSLS) &&
06147              (p->sig != SIG_FXSGS)))
06148             ast_setstate(chan, AST_STATE_RINGING);
06149          }
06150          break;
06151       case AST_CONTROL_PROCEEDING:
06152          ast_debug(1,"Received AST_CONTROL_PROCEEDING on %s\n",chan->name);
06153 #ifdef HAVE_PRI
06154          if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
06155                && p->pri && !p->outgoing) {
06156             if (p->pri->pri) {      
06157                if (!pri_grab(p, p->pri)) {
06158                   pri_proceeding(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
06159                   pri_rel(p->pri);
06160                }
06161                else
06162                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06163             }
06164             p->proceeding = 1;
06165             p->dialing = 0;
06166          }
06167 #endif
06168 #ifdef HAVE_SS7
06169          /* This IF sends the FAR for an answered ALEG call */
06170          if (chan->_state == AST_STATE_UP && (p->rlt != 1) && (p->sig == SIG_SS7)){
06171             if ((isup_far(p->ss7->ss7, p->ss7call)) != -1)
06172                p->rlt = 1; 
06173          }
06174             
06175          if (!p->proceeding && p->sig == SIG_SS7 && p->ss7 && !p->outgoing) {
06176             if (p->ss7->ss7) {
06177                ss7_grab(p, p->ss7);
06178                isup_acm(p->ss7->ss7, p->ss7call);
06179                p->proceeding = 1;
06180                ss7_rel(p->ss7);
06181 
06182             }
06183          }
06184 #endif
06185          /* don't continue in ast_indicate */
06186          res = 0;
06187          break;
06188       case AST_CONTROL_PROGRESS:
06189          ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
06190 #ifdef HAVE_PRI
06191          p->digital = 0;   /* Digital-only calls isn't allows any inband progress messages */
06192          if (!p->progress && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
06193                && p->pri && !p->outgoing) {
06194             if (p->pri->pri) {      
06195                if (!pri_grab(p, p->pri)) {
06196                   pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
06197                   pri_rel(p->pri);
06198                }
06199                else
06200                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06201             }
06202             p->progress = 1;
06203          }
06204 #endif
06205 #ifdef HAVE_SS7
06206          if (!p->progress && p->sig==SIG_SS7 && p->ss7 && !p->outgoing) {
06207             if (p->ss7->ss7) {
06208                ss7_grab(p, p->ss7);
06209                isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_INBANDINFO);
06210                p->progress = 1;
06211                ss7_rel(p->ss7);
06212                /* enable echo canceler here on SS7 calls */
06213                dahdi_enable_ec(p);
06214 
06215             }
06216          }
06217 #endif
06218          /* don't continue in ast_indicate */
06219          res = 0;
06220          break;
06221       case AST_CONTROL_CONGESTION:
06222          chan->hangupcause = AST_CAUSE_CONGESTION;
06223 #ifdef HAVE_PRI
06224          if (p->priindication_oob && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))) {
06225             chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
06226             chan->_softhangup |= AST_SOFTHANGUP_DEV;
06227             res = 0;
06228          } else if (!p->progress && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) 
06229                && p->pri && !p->outgoing) {
06230             if (p->pri) {     
06231                if (!pri_grab(p, p->pri)) {
06232                   pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
06233                   pri_rel(p->pri);
06234                } else
06235                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06236             }
06237             p->progress = 1;
06238             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06239          } else
06240 #endif
06241             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06242          break;
06243       case AST_CONTROL_HOLD:
06244 #ifdef HAVE_PRI
06245          if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
06246             if (!pri_grab(p, p->pri)) {
06247                res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_HOLD);
06248                pri_rel(p->pri);
06249             } else
06250                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);       
06251          } else
06252 #endif
06253             ast_moh_start(chan, data, p->mohinterpret);
06254          break;
06255       case AST_CONTROL_UNHOLD:
06256 #ifdef HAVE_PRI
06257          if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
06258             if (!pri_grab(p, p->pri)) {
06259                res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_RETRIEVAL);
06260                pri_rel(p->pri);
06261             } else
06262                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);       
06263          } else
06264 #endif
06265             ast_moh_stop(chan);
06266          break;
06267       case AST_CONTROL_RADIO_KEY:
06268          if (p->radio) 
06269              res =  dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
06270          res = 0;
06271          break;
06272       case AST_CONTROL_RADIO_UNKEY:
06273          if (p->radio)
06274              res =  dahdi_set_hook(p->subs[idx].dfd, DAHDI_RINGOFF);
06275          res = 0;
06276          break;
06277       case AST_CONTROL_FLASH:
06278          /* flash hookswitch */
06279          if (ISTRUNK(p) && (p->sig != SIG_PRI)) {
06280             /* Clear out the dial buffer */
06281             p->dop.dialstr[0] = '\0';
06282             if ((ioctl(p->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
06283                ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n", 
06284                   chan->name, strerror(errno));
06285             } else
06286                res = 0;
06287          } else
06288             res = 0;
06289          break;
06290       case AST_CONTROL_SRCUPDATE:
06291          res = 0;
06292          break;
06293       case -1:
06294          res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06295          break;
06296       }
06297    } else
06298       res = 0;
06299    ast_mutex_unlock(&p->lock);
06300    return res;
06301 }
06302 
06303 static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, int transfercapability)
06304 {
06305    struct ast_channel *tmp;
06306    int deflaw;
06307    int res;
06308    int x,y;
06309    int features;
06310    struct ast_str *chan_name;
06311    struct ast_variable *v;
06312    struct dahdi_params ps;
06313    if (i->subs[idx].owner) {
06314       ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[idx]);
06315       return NULL;
06316    }
06317    y = 1;
06318    chan_name = ast_str_alloca(32);
06319    do {
06320 #ifdef HAVE_PRI
06321       if (i->bearer || (i->pri && (i->sig == SIG_FXSKS)))
06322          ast_str_set(&chan_name, 0, "%d:%d-%d", i->pri->trunkgroup, i->channel, y);
06323       else
06324 #endif
06325       if (i->channel == CHAN_PSEUDO)
06326          ast_str_set(&chan_name, 0, "pseudo-%ld", ast_random());
06327       else  
06328          ast_str_set(&chan_name, 0, "%d-%d", i->channel, y);
06329       for (x = 0; x < 3; x++) {
06330          if ((idx != x) && i->subs[x].owner && !strcasecmp(chan_name->str, i->subs[x].owner->name + 6))
06331             break;
06332       }
06333       y++;
06334    } while (x < 3);
06335    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);
06336    if (!tmp)
06337       return NULL;
06338    tmp->tech = &dahdi_tech;
06339    memset(&ps, 0, sizeof(ps));
06340    ps.channo = i->channel;
06341    res = ioctl(i->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps);
06342    if (res) {
06343       ast_log(LOG_WARNING, "Unable to get parameters, assuming MULAW: %s\n", strerror(errno));
06344       ps.curlaw = DAHDI_LAW_MULAW;
06345    }
06346    if (ps.curlaw == DAHDI_LAW_ALAW)
06347       deflaw = AST_FORMAT_ALAW;
06348    else
06349       deflaw = AST_FORMAT_ULAW;
06350    if (law) {
06351       if (law == DAHDI_LAW_ALAW)
06352          deflaw = AST_FORMAT_ALAW;
06353       else
06354          deflaw = AST_FORMAT_ULAW;
06355    }
06356    ast_channel_set_fd(tmp, 0, i->subs[idx].dfd);
06357    tmp->nativeformats = deflaw;
06358    /* Start out assuming ulaw since it's smaller :) */
06359    tmp->rawreadformat = deflaw;
06360    tmp->readformat = deflaw;
06361    tmp->rawwriteformat = deflaw;
06362    tmp->writeformat = deflaw;
06363    i->subs[idx].linear = 0;
06364    dahdi_setlinear(i->subs[idx].dfd, i->subs[idx].linear);
06365    features = 0;
06366    if (idx == SUB_REAL) {
06367       if (i->busydetect && CANBUSYDETECT(i))
06368          features |= DSP_FEATURE_BUSY_DETECT;
06369       if ((i->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(i))
06370          features |= DSP_FEATURE_CALL_PROGRESS;
06371       if ((!i->outgoing && (i->callprogress & CALLPROGRESS_FAX_INCOMING)) || 
06372           (i->outgoing && (i->callprogress & CALLPROGRESS_FAX_OUTGOING))) {
06373          features |= DSP_FEATURE_FAX_DETECT;
06374       }
06375       x = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
06376       if (ioctl(i->subs[idx].dfd, DAHDI_TONEDETECT, &x)) {
06377          i->hardwaredtmf = 0;
06378          features |= DSP_FEATURE_DIGIT_DETECT;
06379       } else if (NEED_MFDETECT(i)) {
06380          i->hardwaredtmf = 1;
06381          features |= DSP_FEATURE_DIGIT_DETECT;
06382       }
06383    }
06384    if (features) {
06385       if (i->dsp) {
06386          ast_debug(1, "Already have a dsp on %s?\n", tmp->name);
06387       } else {
06388          if (i->channel != CHAN_PSEUDO)
06389             i->dsp = ast_dsp_new();
06390          else
06391             i->dsp = NULL;
06392          if (i->dsp) {
06393             i->dsp_features = features;
06394 #if defined(HAVE_PRI) || defined(HAVE_SS7)
06395             /* We cannot do progress detection until receives PROGRESS message */
06396             if (i->outgoing && ((i->sig == SIG_PRI) || (i->sig == SIG_BRI) || (i->sig == SIG_BRI_PTMP) || (i->sig == SIG_SS7))) {
06397                /* Remember requested DSP features, don't treat
06398                   talking as ANSWER */
06399                i->dsp_features = features & ~DSP_PROGRESS_TALK;
06400                features = 0;
06401             }
06402 #endif
06403             ast_dsp_set_features(i->dsp, features);
06404             ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_DTMF | i->dtmfrelax);
06405             if (!ast_strlen_zero(progzone))
06406                ast_dsp_set_call_progress_zone(i->dsp, progzone);
06407             if (i->busydetect && CANBUSYDETECT(i)) {
06408                ast_dsp_set_busy_count(i->dsp, i->busycount);
06409                ast_dsp_set_busy_pattern(i->dsp, i->busy_tonelength, i->busy_quietlength);
06410             }
06411          }
06412       }
06413    }
06414       
06415    if (state == AST_STATE_RING)
06416       tmp->rings = 1;
06417    tmp->tech_pvt = i;
06418    if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
06419       /* Only FXO signalled stuff can be picked up */
06420       tmp->callgroup = i->callgroup;
06421       tmp->pickupgroup = i->pickupgroup;
06422    }
06423    if (!ast_strlen_zero(i->parkinglot))
06424       ast_string_field_set(tmp, parkinglot, i->parkinglot);
06425    if (!ast_strlen_zero(i->language))
06426       ast_string_field_set(tmp, language, i->language);
06427    if (!i->owner)
06428       i->owner = tmp;
06429    if (!ast_strlen_zero(i->accountcode))
06430       ast_string_field_set(tmp, accountcode, i->accountcode);
06431    if (i->amaflags)
06432       tmp->amaflags = i->amaflags;
06433    i->subs[idx].owner = tmp;
06434    ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
06435    ast_string_field_set(tmp, call_forward, i->call_forward);
06436    /* If we've been told "no ADSI" then enforce it */
06437    if (!i->adsi)
06438       tmp->adsicpe = AST_ADSI_UNAVAILABLE;
06439    if (!ast_strlen_zero(i->exten))
06440       ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
06441    if (!ast_strlen_zero(i->rdnis))
06442       tmp->cid.cid_rdnis = ast_strdup(i->rdnis);
06443    if (!ast_strlen_zero(i->dnid))
06444       tmp->cid.cid_dnid = ast_strdup(i->dnid);
06445 
06446    /* Don't use ast_set_callerid() here because it will
06447     * generate a needless NewCallerID event */
06448 #ifdef PRI_ANI
06449    if (!ast_strlen_zero(i->cid_ani))
06450       tmp->cid.cid_ani = ast_strdup(i->cid_ani);
06451    else  
06452       tmp->cid.cid_ani = ast_strdup(i->cid_num);
06453 #else
06454    tmp->cid.cid_ani = ast_strdup(i->cid_num);
06455 #endif
06456    tmp->cid.cid_pres = i->callingpres;
06457    tmp->cid.cid_ton = i->cid_ton;
06458    tmp->cid.cid_ani2 = i->cid_ani2;
06459 #if defined(HAVE_PRI) || defined(HAVE_SS7)
06460    tmp->transfercapability = transfercapability;
06461    pbx_builtin_setvar_helper(tmp, "TRANSFERCAPABILITY", ast_transfercapability2str(transfercapability));
06462    if (transfercapability & AST_TRANS_CAP_DIGITAL)
06463       i->digital = 1;
06464    /* Assume calls are not idle calls unless we're told differently */
06465    i->isidlecall = 0;
06466    i->alreadyhungup = 0;
06467 #endif
06468    /* clear the fake event in case we posted one before we had ast_channel */
06469    i->fake_event = 0;
06470    /* Assure there is no confmute on this channel */
06471    dahdi_confmute(i, 0);
06472    i->muting = 0;
06473    /* Configure the new channel jb */
06474    ast_jb_configure(tmp, &global_jbconf);
06475 
06476    ast_devstate_changed_literal(ast_state_chan2dev(state), tmp->name);
06477 
06478    for (v = i->vars ; v ; v = v->next)
06479                 pbx_builtin_setvar_helper(tmp, v->name, v->value);
06480 
06481    if (startpbx) {
06482       if (ast_pbx_start(tmp)) {
06483          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
06484          ast_hangup(tmp);
06485          i->owner = NULL;
06486          return NULL;
06487       }
06488    }
06489 
06490    ast_module_ref(ast_module_info->self);
06491    return tmp;
06492 }
06493 
06494 
06495 static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
06496 {
06497    char c;
06498 
06499    *str = 0; /* start with empty output buffer */
06500    for (;;)
06501    {
06502       /* Wait for the first digit (up to specified ms). */
06503       c = ast_waitfordigit(chan, ms);
06504       /* if timeout, hangup or error, return as such */
06505       if (c < 1)
06506          return c;
06507       *str++ = c;
06508       *str = 0;
06509       if (strchr(term, c))
06510          return 1;
06511    }
06512 }
06513 
06514 static int dahdi_wink(struct dahdi_pvt *p, int idx)
06515 {
06516    int j;
06517    dahdi_set_hook(p->subs[idx].dfd, DAHDI_WINK);
06518    for (;;)
06519    {
06520          /* set bits of interest */
06521       j = DAHDI_IOMUX_SIGEVENT;
06522           /* wait for some happening */
06523       if (ioctl(p->subs[idx].dfd,DAHDI_IOMUX,&j) == -1) return(-1);
06524          /* exit loop if we have it */
06525       if (j & DAHDI_IOMUX_SIGEVENT) break;
06526    }
06527      /* get the event info */
06528    if (ioctl(p->subs[idx].dfd,DAHDI_GETEVENT,&j) == -1) return(-1);
06529    return 0;
06530 }
06531 
06532 /*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
06533  * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
06534  * \param on 1 to enable, 0 to disable
06535  *
06536  * chan_dahdi has a DND (Do Not Disturb) mode for each dahdichan (physical 
06537  * DAHDI channel). Use this to enable or disable it.
06538  *
06539  * \bug the use of the word "channel" for those dahdichans is really confusing.
06540  */
06541 static void dahdi_dnd(struct dahdi_pvt *dahdichan, int on)
06542 {
06543    /* Do not disturb */
06544    dahdichan->dnd = on;
06545    ast_verb(3, "%s DND on channel %d\n", 
06546          on? "Enabled" : "Disabled",
06547          dahdichan->channel);
06548    manager_event(EVENT_FLAG_SYSTEM, "DNDState",
06549          "Channel: DAHDI/%d\r\n"
06550          "Status: %s\r\n", dahdichan->channel,
06551          on? "enabled" : "disabled");
06552 }
06553 
06554 static void *ss_thread(void *data)
06555 {
06556    struct ast_channel *chan = data;
06557    struct dahdi_pvt *p = chan->tech_pvt;
06558    char exten[AST_MAX_EXTENSION] = "";
06559    char exten2[AST_MAX_EXTENSION] = "";
06560    unsigned char buf[256];
06561    char dtmfcid[300];
06562    char dtmfbuf[300];
06563    struct callerid_state *cs = NULL;
06564    char *name = NULL, *number = NULL;
06565    int distMatches;
06566    int curRingData[3];
06567    int receivedRingT;
06568    int counter1;
06569    int counter;
06570    int samples = 0;
06571    struct ast_smdi_md_message *smdi_msg = NULL;
06572    int flags = 0;
06573    int i;
06574    int timeout;
06575    int getforward = 0;
06576    char *s1, *s2;
06577    int len = 0;
06578    int res;
06579    int idx;
06580 
06581    ast_mutex_lock(&ss_thread_lock);
06582    ss_thread_count++;
06583    ast_mutex_unlock(&ss_thread_lock);
06584    /* in the bizarre case where the channel has become a zombie before we
06585       even get started here, abort safely
06586    */
06587    if (!p) {
06588       ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", chan->name);
06589       ast_hangup(chan);
06590       goto quit;
06591    }
06592    ast_verb(3, "Starting simple switch on '%s'\n", chan->name);
06593    idx = dahdi_get_index(chan, p, 1);
06594    if (idx < 0) {
06595       ast_log(LOG_WARNING, "Huh?\n");
06596       ast_hangup(chan);
06597       goto quit;
06598    }
06599    if (p->dsp)
06600       ast_dsp_digitreset(p->dsp);
06601    switch (p->sig) {
06602 #ifdef HAVE_PRI
06603    case SIG_PRI:
06604    case SIG_BRI:
06605    case SIG_BRI_PTMP:
06606       /* Now loop looking for an extension */
06607       ast_copy_string(exten, p->exten, sizeof(exten));
06608       len = strlen(exten);
06609       res = 0;
06610       while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
06611          if (len && !ast_ignore_pattern(chan->context, exten))
06612             tone_zone_play_tone(p->subs[idx].dfd, -1);
06613          else
06614             tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
06615          if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num))
06616             timeout = matchdigittimeout;
06617          else
06618             timeout = gendigittimeout;
06619          res = ast_waitfordigit(chan, timeout);
06620          if (res < 0) {
06621             ast_debug(1, "waitfordigit returned < 0...\n");
06622             ast_hangup(chan);
06623             goto quit;
06624          } else if (res) {
06625             exten[len++] = res;
06626             exten[len] = '\0';
06627          } else
06628             break;
06629       }
06630       /* if no extension was received ('unspecified') on overlap call, use the 's' extension */
06631       if (ast_strlen_zero(exten)) {
06632          ast_verb(3, "Going to extension s|1 because of empty extension received on overlap call\n");
06633          exten[0] = 's';
06634          exten[1] = '\0';
06635       }
06636       tone_zone_play_tone(p->subs[idx].dfd, -1);
06637       if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num)) {
06638          /* Start the real PBX */
06639          ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06640          if (p->dsp) {
06641             ast_dsp_digitreset(p->dsp);
06642          }
06643          if (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) {
06644             if (p->pri->pri) {      
06645                if (!pri_grab(p, p->pri)) {
06646                   pri_proceeding(p->pri->pri, p->call, PVT_TO_CHANNEL(p), 0);
06647                   p->proceeding = 1;
06648                   pri_rel(p->pri);
06649                } else {
06650                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06651                }
06652             }
06653          }
06654          dahdi_enable_ec(p);
06655          ast_setstate(chan, AST_STATE_RING);
06656          res = ast_pbx_run(chan);
06657          if (res) {
06658             ast_log(LOG_WARNING, "PBX exited non-zero!\n");
06659          }
06660       } else {
06661          ast_debug(1, "No such possible extension '%s' in context '%s'\n", exten, chan->context);
06662          chan->hangupcause = AST_CAUSE_UNALLOCATED;
06663          ast_hangup(chan);
06664          p->exten[0] = '\0';
06665          /* Since we send release complete here, we won't get one */
06666          p->call = NULL;
06667       }
06668       goto quit;
06669       break;
06670 #endif
06671    case SIG_FEATD:
06672    case SIG_FEATDMF:
06673    case SIG_FEATDMF_TA:
06674    case SIG_E911:
06675    case SIG_FGC_CAMAMF:
06676    case SIG_FEATB:
06677    case SIG_EMWINK:
06678    case SIG_SF_FEATD:
06679    case SIG_SF_FEATDMF:
06680    case SIG_SF_FEATB:
06681    case SIG_SFWINK:
06682       if (dahdi_wink(p, idx)) 
06683          goto quit;
06684       /* Fall through */
06685    case SIG_EM:
06686    case SIG_EM_E1:
06687    case SIG_SF:
06688    case SIG_FGC_CAMA:
06689       res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06690       if (p->dsp)
06691          ast_dsp_digitreset(p->dsp);
06692       /* set digit mode appropriately */
06693       if (p->dsp) {
06694          if (NEED_MFDETECT(p))
06695             ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax); 
06696          else 
06697             ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
06698       }
06699       memset(dtmfbuf, 0, sizeof(dtmfbuf));
06700       /* Wait for the first digit only if immediate=no */
06701       if (!p->immediate)
06702          /* Wait for the first digit (up to 5 seconds). */
06703          res = ast_waitfordigit(chan, 5000);
06704       else
06705          res = 0;
06706       if (res > 0) {
06707          /* save first char */
06708          dtmfbuf[0] = res;
06709          switch (p->sig) {
06710          case SIG_FEATD:
06711          case SIG_SF_FEATD:
06712             res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
06713             if (res > 0)
06714                res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
06715             if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06716             break;
06717          case SIG_FEATDMF_TA:
06718             res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
06719             if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06720             if (dahdi_wink(p, idx)) goto quit;
06721             dtmfbuf[0] = 0;
06722             /* Wait for the first digit (up to 5 seconds). */
06723             res = ast_waitfordigit(chan, 5000);
06724             if (res <= 0) break;
06725             dtmfbuf[0] = res;
06726             /* fall through intentionally */
06727          case SIG_FEATDMF:
06728          case SIG_E911:
06729          case SIG_FGC_CAMAMF:
06730          case SIG_SF_FEATDMF:
06731             res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
06732             /* if international caca, do it again to get real ANO */
06733             if ((p->sig == SIG_FEATDMF) && (dtmfbuf[1] != '0') && (strlen(dtmfbuf) != 14))
06734             {
06735                if (dahdi_wink(p, idx)) goto quit;
06736                dtmfbuf[0] = 0;
06737                /* Wait for the first digit (up to 5 seconds). */
06738                res = ast_waitfordigit(chan, 5000);
06739                if (res <= 0) break;
06740                dtmfbuf[0] = res;
06741                res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
06742             }
06743             if (res > 0) {
06744                /* if E911, take off hook */
06745                if (p->sig == SIG_E911)
06746                   dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
06747                res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "#", 3000);
06748             }
06749             if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06750             break;
06751          case SIG_FEATB:
06752          case SIG_SF_FEATB:
06753             res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
06754             if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06755             break;
06756          case SIG_EMWINK:
06757             /* if we received a '*', we are actually receiving Feature Group D
06758                dial syntax, so use that mode; otherwise, fall through to normal
06759                mode
06760             */
06761             if (res == '*') {
06762                res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
06763                if (res > 0)
06764                   res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
06765                if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06766                break;
06767             }
06768          default:
06769             /* If we got the first digit, get the rest */
06770             len = 1;
06771             dtmfbuf[len] = '\0';
06772             while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, dtmfbuf, 1, p->cid_num)) {
06773                if (ast_exists_extension(chan, chan->context, dtmfbuf, 1, p->cid_num)) {
06774                   timeout = matchdigittimeout;
06775                } else {
06776                   timeout = gendigittimeout;
06777                }
06778                res = ast_waitfordigit(chan, timeout);
06779                if (res < 0) {
06780                   ast_debug(1, "waitfordigit returned < 0...\n");
06781                   ast_hangup(chan);
06782                   goto quit;
06783                } else if (res) {
06784                   dtmfbuf[len++] = res;
06785                   dtmfbuf[len] = '\0';
06786                } else {
06787                   break;
06788                }
06789             }
06790             break;
06791          }
06792       }
06793       if (res == -1) {
06794          ast_log(LOG_WARNING, "getdtmf on channel %d: %s\n", p->channel, strerror(errno));
06795          ast_hangup(chan);
06796          goto quit;
06797       } else if (res < 0) {
06798          ast_debug(1, "Got hung up before digits finished\n");
06799          ast_hangup(chan);
06800          goto quit;
06801       }
06802 
06803       if (p->sig == SIG_FGC_CAMA) {
06804          char anibuf[100];
06805 
06806          if (ast_safe_sleep(chan,1000) == -1) {
06807                            ast_hangup(chan);
06808                            goto quit;
06809          }
06810                         dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
06811                         ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax);
06812                         res = my_getsigstr(chan, anibuf, "#", 10000);
06813                         if ((res > 0) && (strlen(anibuf) > 2)) {
06814             if (anibuf[strlen(anibuf) - 1] == '#')
06815                anibuf[strlen(anibuf) - 1] = 0;
06816             ast_set_callerid(chan, anibuf + 2, NULL, anibuf + 2);
06817          }
06818                         ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
06819       }
06820 
06821       ast_copy_string(exten, dtmfbuf, sizeof(exten));
06822       if (ast_strlen_zero(exten))
06823          ast_copy_string(exten, "s", sizeof(exten));
06824       if (p->sig == SIG_FEATD || p->sig == SIG_EMWINK) {
06825          /* Look for Feature Group D on all E&M Wink and Feature Group D trunks */
06826          if (exten[0] == '*') {
06827             char *stringp=NULL;
06828             ast_copy_string(exten2, exten, sizeof(exten2));
06829             /* Parse out extension and callerid */
06830             stringp=exten2 +1;
06831             s1 = strsep(&stringp, "*");
06832             s2 = strsep(&stringp, "*");
06833             if (s2) {
06834                if (!ast_strlen_zero(p->cid_num))
06835                   ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
06836                else
06837                   ast_set_callerid(chan, s1, NULL, s1);
06838                ast_copy_string(exten, s2, sizeof(exten));
06839             } else
06840                ast_copy_string(exten, s1, sizeof(exten));
06841          } else if (p->sig == SIG_FEATD)
06842             ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d.  Assuming E&M Wink instead\n", p->channel);
06843       }
06844       if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
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             s2 = strsep(&stringp, "#");
06852             if (s2) {
06853                if (!ast_strlen_zero(p->cid_num))
06854                   ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
06855                else
06856                   if (*(s1 + 2))
06857                      ast_set_callerid(chan, s1 + 2, NULL, s1 + 2);
06858                ast_copy_string(exten, s2 + 1, sizeof(exten));
06859             } else
06860                ast_copy_string(exten, s1 + 2, sizeof(exten));
06861          } else
06862             ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d.  Assuming E&M Wink instead\n", p->channel);
06863       }
06864       if ((p->sig == SIG_E911) || (p->sig == SIG_FGC_CAMAMF)) {
06865          if (exten[0] == '*') {
06866             char *stringp=NULL;
06867             ast_copy_string(exten2, exten, sizeof(exten2));
06868             /* Parse out extension and callerid */
06869             stringp=exten2 +1;
06870             s1 = strsep(&stringp, "#");
06871             s2 = strsep(&stringp, "#");
06872             if (s2 && (*(s2 + 1) == '0')) {
06873                if (*(s2 + 2))
06874                   ast_set_callerid(chan, s2 + 2, NULL, s2 + 2);
06875             }
06876             if (s1)  ast_copy_string(exten, s1, sizeof(exten));
06877             else ast_copy_string(exten, "911", sizeof(exten));
06878          } else
06879             ast_log(LOG_WARNING, "Got a non-E911/FGC CAMA input on channel %d.  Assuming E&M Wink instead\n", p->channel);
06880       }
06881       if (p->sig == SIG_FEATB) {
06882          if (exten[0] == '*') {
06883             char *stringp=NULL;
06884             ast_copy_string(exten2, exten, sizeof(exten2));
06885             /* Parse out extension and callerid */
06886             stringp=exten2 +1;
06887             s1 = strsep(&stringp, "#");
06888             ast_copy_string(exten, exten2 + 1, sizeof(exten));
06889          } else
06890             ast_log(LOG_WARNING, "Got a non-Feature Group B input on channel %d.  Assuming E&M Wink instead\n", p->channel);
06891       }
06892       if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
06893          dahdi_wink(p, idx);
06894                         /* some switches require a minimum guard time between
06895                            the last FGD wink and something that answers
06896                            immediately. This ensures it */
06897                         if (ast_safe_sleep(chan,100)) goto quit;
06898       }
06899       dahdi_enable_ec(p);
06900       if (NEED_MFDETECT(p)) {
06901          if (p->dsp) {
06902             if (!p->hardwaredtmf)
06903                ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); 
06904             else {
06905                ast_dsp_free(p->dsp);
06906                p->dsp = NULL;
06907             }
06908          }
06909       }
06910 
06911       if (ast_exists_extension(chan, chan->context, exten, 1, chan->cid.cid_num)) {
06912          ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06913          if (p->dsp) ast_dsp_digitreset(p->dsp);
06914          res = ast_pbx_run(chan);
06915          if (res) {
06916             ast_log(LOG_WARNING, "PBX exited non-zero\n");
06917             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06918          }
06919          goto quit;
06920       } else {
06921          ast_verb(2, "Unknown extension '%s' in context '%s' requested\n", exten, chan->context);
06922          sleep(2);
06923          res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_INFO);
06924          if (res < 0)
06925             ast_log(LOG_WARNING, "Unable to start special tone on %d\n", p->channel);
06926          else
06927             sleep(1);
06928          res = ast_streamfile(chan, "ss-noservice", chan->language);
06929          if (res >= 0)
06930             ast_waitstream(chan, "");
06931          res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06932          ast_hangup(chan);
06933          goto quit;
06934       }
06935       break;
06936    case SIG_FXOLS:
06937    case SIG_FXOGS:
06938    case SIG_FXOKS:
06939       /* Read the first digit */
06940       timeout = firstdigittimeout;
06941       /* If starting a threeway call, never timeout on the first digit so someone
06942          can use flash-hook as a "hold" feature */
06943       if (p->subs[SUB_THREEWAY].owner) 
06944          timeout = 999999;
06945       while (len < AST_MAX_EXTENSION-1) {
06946          /* Read digit unless it's supposed to be immediate, in which case the
06947             only answer is 's' */
06948          if (p->immediate) 
06949             res = 's';
06950          else
06951             res = ast_waitfordigit(chan, timeout);
06952          timeout = 0;
06953          if (res < 0) {
06954             ast_debug(1, "waitfordigit returned < 0...\n");
06955             res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06956             ast_hangup(chan);
06957             goto quit;
06958          } else if (res)  {
06959             ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res, res, timeout);
06960             exten[len++]=res;
06961             exten[len] = '\0';
06962          }
06963          if (!ast_ignore_pattern(chan->context, exten))
06964             tone_zone_play_tone(p->subs[idx].dfd, -1);
06965          else
06966             tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
06967          if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num) && strcmp(exten, ast_parking_ext())) {
06968             if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
06969                if (getforward) {
06970                   /* Record this as the forwarding extension */
06971                   ast_copy_string(p->call_forward, exten, sizeof(p->call_forward)); 
06972                   ast_verb(3, "Setting call forward to '%s' on channel %d\n", p->call_forward, p->channel);
06973                   res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
06974                   if (res)
06975                      break;
06976                   usleep(500000);
06977                   res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06978                   sleep(1);
06979                   memset(exten, 0, sizeof(exten));
06980                   res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
06981                   len = 0;
06982                   getforward = 0;
06983                } else  {
06984                   res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06985                   ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06986                   if (!ast_strlen_zero(p->cid_num)) {
06987                      if (!p->hidecallerid)
06988                         ast_set_callerid(chan, p->cid_num, NULL, p->cid_num); 
06989                      else
06990                         ast_set_callerid(chan, NULL, NULL, p->cid_num); 
06991                   }
06992                   if (!ast_strlen_zero(p->cid_name)) {
06993                      if (!p->hidecallerid)
06994                         ast_set_callerid(chan, NULL, p->cid_name, NULL);
06995                   }
06996                   ast_setstate(chan, AST_STATE_RING);
06997                   dahdi_enable_ec(p);
06998                   res = ast_pbx_run(chan);
06999                   if (res) {
07000                      ast_log(LOG_WARNING, "PBX exited non-zero\n");
07001                      res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07002                   }
07003                   goto quit;
07004                }
07005             } else {
07006                /* It's a match, but they just typed a digit, and there is an ambiguous match,
07007                   so just set the timeout to matchdigittimeout and wait some more */
07008                timeout = matchdigittimeout;
07009             }
07010          } else if (res == 0) {
07011             ast_debug(1, "not enough digits (and no ambiguous match)...\n");
07012             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07013             dahdi_wait_event(p->subs[idx].dfd);
07014             ast_hangup(chan);
07015             goto quit;
07016          } else if (p->callwaiting && !strcmp(exten, "*70")) {
07017             ast_verb(3, "Disabling call waiting on %s\n", chan->name);
07018             /* Disable call waiting if enabled */
07019             p->callwaiting = 0;
07020             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07021             if (res) {
07022                ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", 
07023                   chan->name, strerror(errno));
07024             }
07025             len = 0;
07026             ioctl(p->subs[idx].dfd,DAHDI_CONFDIAG,&len);
07027             memset(exten, 0, sizeof(exten));
07028             timeout = firstdigittimeout;
07029                
07030          } else if (!strcmp(exten,ast_pickup_ext())) {
07031             /* Scan all channels and see if there are any
07032              * ringing channels that have call groups
07033              * that equal this channels pickup group  
07034              */
07035             if (idx == SUB_REAL) {
07036                /* Switch us from Third call to Call Wait */
07037                if (p->subs[SUB_THREEWAY].owner) {
07038                   /* If you make a threeway call and the *8# a call, it should actually 
07039                      look like a callwait */
07040                   alloc_sub(p, SUB_CALLWAIT);   
07041                   swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
07042                   unalloc_sub(p, SUB_THREEWAY);
07043                }
07044                dahdi_enable_ec(p);
07045                if (ast_pickup_call(chan)) {
07046                   ast_debug(1, "No call pickup possible...\n");
07047                   res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07048                   dahdi_wait_event(p->subs[idx].dfd);
07049                }
07050                ast_hangup(chan);
07051                goto quit;
07052             } else {
07053                ast_log(LOG_WARNING, "Huh?  Got *8# on call not on real\n");
07054                ast_hangup(chan);
07055                goto quit;
07056             }
07057             
07058          } else if (!p->hidecallerid && !strcmp(exten, "*67")) {
07059             ast_verb(3, "Disabling Caller*ID on %s\n", chan->name);
07060             /* Disable Caller*ID if enabled */
07061             p->hidecallerid = 1;
07062             if (chan->cid.cid_num)
07063                ast_free(chan->cid.cid_num);
07064             chan->cid.cid_num = NULL;
07065             if (chan->cid.cid_name)
07066                ast_free(chan->cid.cid_name);
07067             chan->cid.cid_name = NULL;
07068             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07069             if (res) {
07070                ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", 
07071                   chan->name, strerror(errno));
07072             }
07073             len = 0;
07074             memset(exten, 0, sizeof(exten));
07075             timeout = firstdigittimeout;
07076          } else if (p->callreturn && !strcmp(exten, "*69")) {
07077             res = 0;
07078             if (!ast_strlen_zero(p->lastcid_num)) {
07079                res = ast_say_digit_str(chan, p->lastcid_num, "", chan->language);
07080             }
07081             if (!res)
07082                res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07083             break;
07084          } else if (!strcmp(exten, "*78")) {
07085             dahdi_dnd(p, 1);
07086             /* Do not disturb */
07087             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07088             getforward = 0;
07089             memset(exten, 0, sizeof(exten));
07090             len = 0;
07091          } else if (!strcmp(exten, "*79")) {
07092             dahdi_dnd(p, 0);
07093             /* Do not disturb */
07094             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07095             getforward = 0;
07096             memset(exten, 0, sizeof(exten));
07097             len = 0;
07098          } else if (p->cancallforward && !strcmp(exten, "*72")) {
07099             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07100             getforward = 1;
07101             memset(exten, 0, sizeof(exten));
07102             len = 0;
07103          } else if (p->cancallforward && !strcmp(exten, "*73")) {
07104             ast_verb(3, "Cancelling call forwarding on channel %d\n", p->channel);
07105             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07106             memset(p->call_forward, 0, sizeof(p->call_forward));
07107             getforward = 0;
07108             memset(exten, 0, sizeof(exten));
07109             len = 0;
07110          } else if ((p->transfer || p->canpark) && !strcmp(exten, ast_parking_ext()) && 
07111                   p->subs[SUB_THREEWAY].owner &&
07112                   ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
07113             /* This is a three way call, the main call being a real channel, 
07114                and we're parking the first call. */
07115             ast_masq_park_call(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), chan, 0, NULL);
07116             ast_verb(3, "Parking call to '%s'\n", chan->name);
07117             break;
07118          } else if (!ast_strlen_zero(p->lastcid_num) && !strcmp(exten, "*60")) {
07119             ast_verb(3, "Blacklisting number %s\n", p->lastcid_num);
07120             res = ast_db_put("blacklist", p->lastcid_num, "1");
07121             if (!res) {
07122                res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07123                memset(exten, 0, sizeof(exten));
07124                len = 0;
07125             }
07126          } else if (p->hidecallerid && !strcmp(exten, "*82")) {
07127             ast_verb(3, "Enabling Caller*ID on %s\n", chan->name);
07128             /* Enable Caller*ID if enabled */
07129             p->hidecallerid = 0;
07130             if (chan->cid.cid_num)
07131                ast_free(chan->cid.cid_num);
07132             chan->cid.cid_num = NULL;
07133             if (chan->cid.cid_name)
07134                ast_free(chan->cid.cid_name);
07135             chan->cid.cid_name = NULL;
07136             ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
07137             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07138             if (res) {
07139                ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", 
07140                   chan->name, strerror(errno));
07141             }
07142             len = 0;
07143             memset(exten, 0, sizeof(exten));
07144             timeout = firstdigittimeout;
07145          } else if (!strcmp(exten, "*0")) {
07146             struct ast_channel *nbridge = 
07147                p->subs[SUB_THREEWAY].owner;
07148             struct dahdi_pvt *pbridge = NULL;
07149               /* set up the private struct of the bridged one, if any */
07150             if (nbridge && ast_bridged_channel(nbridge)) 
07151                pbridge = ast_bridged_channel(nbridge)->tech_pvt;
07152             if (nbridge && pbridge && 
07153                 (nbridge->tech == &dahdi_tech) && 
07154                 (ast_bridged_channel(nbridge)->tech == &dahdi_tech) &&
07155                 ISTRUNK(pbridge)) {
07156                int func = DAHDI_FLASH;
07157                /* Clear out the dial buffer */
07158                p->dop.dialstr[0] = '\0';
07159                /* flash hookswitch */
07160                if ((ioctl(pbridge->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
07161                   ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n", 
07162                      nbridge->name, strerror(errno));
07163                }
07164                swap_subs(p, SUB_REAL, SUB_THREEWAY);
07165                unalloc_sub(p, SUB_THREEWAY);
07166                p->owner = p->subs[SUB_REAL].owner;
07167                if (ast_bridged_channel(p->subs[SUB_REAL].owner))
07168                   ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
07169                ast_hangup(chan);
07170                goto quit;
07171             } else {
07172                tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07173                dahdi_wait_event(p->subs[idx].dfd);
07174                tone_zone_play_tone(p->subs[idx].dfd, -1);
07175                swap_subs(p, SUB_REAL, SUB_THREEWAY);
07176                unalloc_sub(p, SUB_THREEWAY);
07177                p->owner = p->subs[SUB_REAL].owner;
07178                ast_hangup(chan);
07179                goto quit;
07180             }              
07181          } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) &&
07182                      ((exten[0] != '*') || (strlen(exten) > 2))) {
07183             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);
07184             break;
07185          }
07186          if (!timeout)
07187             timeout = gendigittimeout;
07188          if (len && !ast_ignore_pattern(chan->context, exten))
07189             tone_zone_play_tone(p->subs[idx].dfd, -1);
07190       }
07191       break;
07192    case SIG_FXSLS:
07193    case SIG_FXSGS:
07194    case SIG_FXSKS:
07195 #ifdef HAVE_PRI
07196       if (p->pri) {
07197          /* This is a GR-303 trunk actually.  Wait for the first ring... */
07198          struct ast_frame *f;
07199          int res;
07200          time_t start;
07201 
07202          time(&start);
07203          ast_setstate(chan, AST_STATE_RING);
07204          while (time(NULL) < start + 3) {
07205             res = ast_waitfor(chan, 1000);
07206             if (res) {
07207                f = ast_read(chan);
07208                if (!f) {
07209                   ast_log(LOG_WARNING, "Whoa, hangup while waiting for first ring!\n");
07210                   ast_hangup(chan);
07211                   goto quit;
07212                } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RING)) {
07213                   res = 1;
07214                } else
07215                   res = 0;
07216                ast_frfree(f);
07217                if (res) {
07218                   ast_debug(1, "Got ring!\n");
07219                   res = 0;
07220                   break;
07221                }
07222             }
07223          }
07224       }
07225 #endif
07226       /* check for SMDI messages */
07227       if (p->use_smdi && p->smdi_iface) {
07228          smdi_msg = ast_smdi_md_message_wait(p->smdi_iface, SMDI_MD_WAIT_TIMEOUT);
07229 
07230          if (smdi_msg != NULL) {
07231             ast_copy_string(chan->exten, smdi_msg->fwd_st, sizeof(chan->exten));
07232 
07233             if (smdi_msg->type == 'B')
07234                pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "b");
07235             else if (smdi_msg->type == 'N')
07236                pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "u");
07237 
07238             ast_debug(1, "Received SMDI message on %s\n", chan->name);
07239          } else {
07240             ast_log(LOG_WARNING, "SMDI enabled but no SMDI message present\n");
07241          }
07242       }
07243 
07244       if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {
07245             number = smdi_msg->calling_st;
07246 
07247       /* If we want caller id, we're in a prering state due to a polarity reversal
07248        * and we're set to use a polarity reversal to trigger the start of caller id,
07249        * grab the caller id and wait for ringing to start... */
07250       } else if (p->use_callerid && (chan->_state == AST_STATE_PRERING && (p->cid_start == CID_START_POLARITY || p->cid_start == CID_START_POLARITY_IN))) {
07251          /* If set to use DTMF CID signalling, listen for DTMF */
07252          if (p->cid_signalling == CID_SIG_DTMF) {
07253             int k = 0;
07254             cs = NULL;
07255             ast_debug(1, "Receiving DTMF cid on "
07256                "channel %s\n", chan->name);
07257             dahdi_setlinear(p->subs[idx].dfd, 0);
07258             res = 2000;
07259             for (;;) {
07260                struct ast_frame *f;
07261                res = ast_waitfor(chan, res);
07262                if (res <= 0) {
07263                   ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
07264                      "Exiting simple switch\n");
07265                   ast_hangup(chan);
07266                   goto quit;
07267                } 
07268                f = ast_read(chan);
07269                if (!f)
07270                   break;
07271                if (f->frametype == AST_FRAME_DTMF) {
07272                   dtmfbuf[k++] = f->subclass;
07273                   ast_debug(1, "CID got digit '%c'\n", f->subclass);
07274                   res = 2000;
07275                }
07276                ast_frfree(f);
07277                if (chan->_state == AST_STATE_RING ||
07278                    chan->_state == AST_STATE_RINGING) 
07279                   break; /* Got ring */
07280             }
07281             dtmfbuf[k] = '\0';
07282             dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
07283             /* Got cid and ring. */
07284             ast_debug(1, "CID got string '%s'\n", dtmfbuf);
07285             callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
07286             ast_debug(1, "CID is '%s', flags %d\n", 
07287                dtmfcid, flags);
07288             /* If first byte is NULL, we have no cid */
07289             if (!ast_strlen_zero(dtmfcid)) 
07290                number = dtmfcid;
07291             else
07292                number = NULL;
07293          /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
07294          } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
07295             cs = callerid_new(p->cid_signalling);
07296             if (cs) {
07297                samples = 0;
07298 #if 1
07299                bump_gains(p);
07300 #endif
07301                /* Take out of linear mode for Caller*ID processing */
07302                dahdi_setlinear(p->subs[idx].dfd, 0);
07303                
07304                /* First we wait and listen for the Caller*ID */
07305                for (;;) {  
07306                   i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07307                   if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
07308                      ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07309                      callerid_free(cs);
07310                      ast_hangup(chan);
07311                      goto quit;
07312                   }
07313                   if (i & DAHDI_IOMUX_SIGEVENT) {
07314                      res = dahdi_get_event(p->subs[idx].dfd);
07315                      ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
07316                      if (res == DAHDI_EVENT_NOALARM) {
07317                         p->inalarm = 0;
07318                      }
07319 
07320                      if (p->cid_signalling == CID_SIG_V23_JP) {
07321                         if (res == DAHDI_EVENT_RINGBEGIN) {
07322                            res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
07323                            usleep(1);
07324                         }
07325                      } else {
07326                         res = 0;
07327                         break;
07328                      }
07329                   } else if (i & DAHDI_IOMUX_READ) {
07330                      res = read(p->subs[idx].dfd, buf, sizeof(buf));
07331                      if (res < 0) {
07332                         if (errno != ELAST) {
07333                            ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07334                            callerid_free(cs);
07335                            ast_hangup(chan);
07336                            goto quit;
07337                         }
07338                         break;
07339                      }
07340                      samples += res;
07341 
07342                      if  (p->cid_signalling == CID_SIG_V23_JP) {
07343                         res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
07344                      } else {
07345                         res = callerid_feed(cs, buf, res, AST_LAW(p));
07346                      }
07347 
07348                      if (res < 0) {
07349                         ast_log(LOG_WARNING, "CallerID feed failed on channel '%s'\n", chan->name);
07350                         break;
07351                      } else if (res)
07352                         break;
07353                      else if (samples > (8000 * 10))
07354                         break;
07355                   }
07356                }
07357                if (res == 1) {
07358                   callerid_get(cs, &name, &number, &flags);
07359                   ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
07360                }
07361 
07362                if (p->cid_signalling == CID_SIG_V23_JP) {
07363                   res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
07364                   usleep(1);
07365                   res = 4000;
07366                } else {
07367 
07368                   /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */ 
07369                   res = 2000;
07370                }
07371 
07372                for (;;) {
07373                   struct ast_frame *f;
07374                   res = ast_waitfor(chan, res);
07375                   if (res <= 0) {
07376                      ast_log(LOG_WARNING, "CID timed out waiting for ring. "
07377                         "Exiting simple switch\n");
07378                      ast_hangup(chan);
07379                      goto quit;
07380                   } 
07381                   if (!(f = ast_read(chan))) {
07382                      ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n");
07383                      ast_hangup(chan);
07384                      goto quit;
07385                   }
07386                   ast_frfree(f);
07387                   if (chan->_state == AST_STATE_RING ||
07388                       chan->_state == AST_STATE_RINGING) 
07389                      break; /* Got ring */
07390                }
07391    
07392                /* We must have a ring by now, so, if configured, lets try to listen for
07393                 * distinctive ringing */ 
07394                if (p->usedistinctiveringdetection) {
07395                   len = 0;
07396                   distMatches = 0;
07397                   /* Clear the current ring data array so we dont have old data in it. */
07398                   for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
07399                      curRingData[receivedRingT] = 0;
07400                   receivedRingT = 0;
07401                   counter = 0;
07402                   counter1 = 0;
07403                   /* Check to see if context is what it should be, if not set to be. */
07404                   if (strcmp(p->context,p->defcontext) != 0) {
07405                      ast_copy_string(p->context, p->defcontext, sizeof(p->context));
07406                      ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
07407                   }
07408       
07409                   for (;;) {  
07410                      i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07411                      if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
07412                         ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07413                         callerid_free(cs);
07414                         ast_hangup(chan);
07415                         goto quit;
07416                      }
07417                      if (i & DAHDI_IOMUX_SIGEVENT) {
07418                         res = dahdi_get_event(p->subs[idx].dfd);
07419                         ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
07420                         if (res == DAHDI_EVENT_NOALARM) {
07421                            p->inalarm = 0;
07422                         }
07423                         res = 0;
07424                         /* Let us detect distinctive ring */
07425       
07426                         curRingData[receivedRingT] = p->ringt;
07427       
07428                         if (p->ringt < p->ringt_base/2)
07429                            break;
07430                         /* Increment the ringT counter so we can match it against
07431                            values in chan_dahdi.conf for distinctive ring */
07432                         if (++receivedRingT == ARRAY_LEN(curRingData))
07433                            break;
07434                      } else if (i & DAHDI_IOMUX_READ) {
07435                         res = read(p->subs[idx].dfd, buf, sizeof(buf));
07436                         if (res < 0) {
07437                            if (errno != ELAST) {
07438                               ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07439                               callerid_free(cs);
07440                               ast_hangup(chan);
07441                               goto quit;
07442                            }
07443                            break;
07444                         }
07445                         if (p->ringt) 
07446                            p->ringt--;
07447                         if (p->ringt == 1) {
07448                            res = -1;
07449                            break;
07450                         }
07451                      }
07452                   }
07453                      /* this only shows up if you have n of the dring patterns filled in */
07454                   ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
07455                   for (counter = 0; counter < 3; counter++) {
07456                      /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
07457                      channel */
07458                      distMatches = 0;
07459                      for (counter1 = 0; counter1 < 3; counter1++) {
07460                         ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
07461                         if (p->drings.ringnum[counter].ring[counter1] == -1) {
07462                            ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
07463                            curRingData[counter1]);
07464                            distMatches++;
07465                         }
07466                         else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
07467                             curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
07468                            ast_verb(3, "Ring pattern matched in range: %d to %d\n",
07469                            (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
07470                            (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
07471                            distMatches++;
07472                         }
07473                      }
07474 
07475                      if (distMatches == 3) {
07476                         /* The ring matches, set the context to whatever is for distinctive ring.. */
07477                         ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context));
07478                         ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context));
07479                         ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
07480                         break;
07481                      }
07482                   }
07483                }
07484                /* Restore linear mode (if appropriate) for Caller*ID processing */
07485                dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
07486 #if 1
07487                restore_gains(p);
07488 #endif            
07489             } else
07490                ast_log(LOG_WARNING, "Unable to get caller ID space\n");       
07491          } else {
07492             ast_log(LOG_WARNING, "Channel %s in prering "
07493                "state, but I have nothing to do. "
07494                "Terminating simple switch, should be "
07495                "restarted by the actual ring.\n", 
07496                chan->name);
07497             ast_hangup(chan);
07498             goto quit;
07499          }
07500       } else if (p->use_callerid && p->cid_start == CID_START_RING) {
07501                         if (p->cid_signalling == CID_SIG_DTMF) {
07502                                 int k = 0;
07503                                 cs = NULL;
07504                                 dahdi_setlinear(p->subs[idx].dfd, 0);
07505                                 res = 2000;
07506                                 for (;;) {
07507                                         struct ast_frame *f;
07508                                         res = ast_waitfor(chan, res);
07509                                         if (res <= 0) {
07510                                                 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
07511                                                                 "Exiting simple switch\n");
07512                                                 ast_hangup(chan);
07513                                                 return NULL;
07514                                         }
07515                                         f = ast_read(chan);
07516                                         if (f->frametype == AST_FRAME_DTMF) {
07517                                                 dtmfbuf[k++] = f->subclass;
07518                                                 ast_log(LOG_DEBUG, "CID got digit '%c'\n", f->subclass);
07519                                                 res = 2000;
07520                                         }
07521                                         ast_frfree(f);
07522 
07523                                         if (p->ringt_base == p->ringt)
07524                                                 break;
07525 
07526                                 }
07527                                 dtmfbuf[k] = '\0';
07528                                 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
07529                                 /* Got cid and ring. */
07530                                 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
07531                                 ast_log(LOG_DEBUG, "CID is '%s', flags %d\n",
07532                                                 dtmfcid, flags);
07533                                 /* If first byte is NULL, we have no cid */
07534                                 if (!ast_strlen_zero(dtmfcid))
07535                                         number = dtmfcid;
07536                                 else
07537                                         number = NULL;
07538                                 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
07539                         } else {
07540          /* FSK Bell202 callerID */
07541          cs = callerid_new(p->cid_signalling);
07542          if (cs) {
07543 #if 1
07544             bump_gains(p);
07545 #endif            
07546             samples = 0;
07547             len = 0;
07548             distMatches = 0;
07549             /* Clear the current ring data array so we dont have old data in it. */
07550             for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
07551                curRingData[receivedRingT] = 0;
07552             receivedRingT = 0;
07553             counter = 0;
07554             counter1 = 0;
07555             /* Check to see if context is what it should be, if not set to be. */
07556             if (strcmp(p->context,p->defcontext) != 0) {
07557                ast_copy_string(p->context, p->defcontext, sizeof(p->context));
07558                ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
07559             }
07560 
07561             /* Take out of linear mode for Caller*ID processing */
07562             dahdi_setlinear(p->subs[idx].dfd, 0);
07563             for (;;) {  
07564                i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07565                if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
07566                   ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07567                   callerid_free(cs);
07568                   ast_hangup(chan);
07569                   goto quit;
07570                }
07571                if (i & DAHDI_IOMUX_SIGEVENT) {
07572                   res = dahdi_get_event(p->subs[idx].dfd);
07573                   ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
07574                   if (res == DAHDI_EVENT_NOALARM) {
07575                      p->inalarm = 0;
07576                   }
07577                   /* If we get a PR event, they hung up while processing calerid */
07578                   if ( res == DAHDI_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
07579                      ast_log(LOG_DEBUG, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
07580                      p->polarity = POLARITY_IDLE;
07581                      callerid_free(cs);
07582                      ast_hangup(chan);
07583                      goto quit;
07584                   }
07585                   res = 0;
07586                   /* Let us detect callerid when the telco uses distinctive ring */
07587 
07588                   curRingData[receivedRingT] = p->ringt;
07589 
07590                   if (p->ringt < p->ringt_base/2)
07591                      break;
07592                   /* Increment the ringT counter so we can match it against
07593                      values in chan_dahdi.conf for distinctive ring */
07594                   if (++receivedRingT == ARRAY_LEN(curRingData))
07595                      break;
07596                } else if (i & DAHDI_IOMUX_READ) {
07597                   res = read(p->subs[idx].dfd, buf, sizeof(buf));
07598                   if (res < 0) {
07599                      if (errno != ELAST) {
07600                         ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07601                         callerid_free(cs);
07602                         ast_hangup(chan);
07603                         goto quit;
07604                      }
07605                      break;
07606                   }
07607                   if (p->ringt) 
07608                      p->ringt--;
07609                   if (p->ringt == 1) {
07610                      res = -1;
07611                      break;
07612                   }
07613                   samples += res;
07614                   res = callerid_feed(cs, buf, res, AST_LAW(p));
07615                   if (res < 0) {
07616                      ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
07617                      break;
07618                   } else if (res)
07619                      break;
07620                   else if (samples > (8000 * 10))
07621                      break;
07622                }
07623             }
07624             if (res == 1) {
07625                callerid_get(cs, &name, &number, &flags);
07626                ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
07627             }
07628             if (distinctiveringaftercid == 1) {
07629                /* Clear the current ring data array so we dont have old data in it. */
07630                for (receivedRingT = 0; receivedRingT < 3; receivedRingT++) {
07631                   curRingData[receivedRingT] = 0;
07632                }
07633                receivedRingT = 0;
07634                ast_verb(3, "Detecting post-CID distinctive ring\n");
07635                for (;;) {
07636                   i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07637                   if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i)))    {
07638                      ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07639                      callerid_free(cs);
07640                      ast_hangup(chan);
07641                      goto quit;
07642                   }
07643                   if (i & DAHDI_IOMUX_SIGEVENT) {
07644                      res = dahdi_get_event(p->subs[idx].dfd);
07645                      ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
07646                      if (res == DAHDI_EVENT_NOALARM) {
07647                         p->inalarm = 0;
07648                      }
07649                      res = 0;
07650                      /* Let us detect callerid when the telco uses distinctive ring */
07651 
07652                      curRingData[receivedRingT] = p->ringt;
07653 
07654                      if (p->ringt < p->ringt_base/2)
07655                         break;
07656                      /* Increment the ringT counter so we can match it against
07657                         values in chan_dahdi.conf for distinctive ring */
07658                      if (++receivedRingT == ARRAY_LEN(curRingData))
07659                         break;
07660                   } else if (i & DAHDI_IOMUX_READ) {
07661                      res = read(p->subs[idx].dfd, buf, sizeof(buf));
07662                      if (res < 0) {
07663                         if (errno != ELAST) {
07664                            ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07665                            callerid_free(cs);
07666                            ast_hangup(chan);
07667                            goto quit;
07668                         }
07669                         break;
07670                      }
07671                   if (p->ringt)
07672                      p->ringt--;
07673                      if (p->ringt == 1) {
07674                         res = -1;
07675                         break;
07676                      }
07677                   }
07678                }
07679             }
07680             if (p->usedistinctiveringdetection) {
07681                   /* this only shows up if you have n of the dring patterns filled in */
07682                ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
07683 
07684                for (counter = 0; counter < 3; counter++) {
07685                   /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
07686                   channel */
07687                      /* this only shows up if you have n of the dring patterns filled in */
07688                   ast_verb(3, "Checking %d,%d,%d\n",
07689                         p->drings.ringnum[counter].ring[0],
07690                         p->drings.ringnum[counter].ring[1],
07691                         p->drings.ringnum[counter].ring[2]);
07692                   distMatches = 0;
07693                   for (counter1 = 0; counter1 < 3; counter1++) {
07694                      ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
07695                      if (p->drings.ringnum[counter].ring[counter1] == -1) {
07696                         ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
07697                         curRingData[counter1]);
07698                         distMatches++;
07699                      }
07700                      else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
07701                          curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
07702                         ast_verb(3, "Ring pattern matched in range: %d to %d\n",
07703                         (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
07704                         (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
07705                         distMatches++;
07706                      }
07707                   }
07708                   if (distMatches == 3) {
07709                      /* The ring matches, set the context to whatever is for distinctive ring.. */
07710                      ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context));
07711                      ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context));
07712                      ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
07713                      break;
07714                   }
07715                }
07716             }
07717             /* Restore linear mode (if appropriate) for Caller*ID processing */
07718             dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
07719 #if 1
07720             restore_gains(p);
07721 #endif            
07722             if (res < 0) {
07723                ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", chan->name);
07724             }
07725          } else
07726             ast_log(LOG_WARNING, "Unable to get caller ID space\n");
07727       }
07728       }
07729       else
07730          cs = NULL;
07731 
07732       if (number)
07733          ast_shrink_phone_number(number);
07734       ast_set_callerid(chan, number, name, number);
07735 
07736       if (smdi_msg)
07737          ASTOBJ_UNREF(smdi_msg, ast_smdi_md_message_destroy);
07738 
07739       if (cs)
07740          callerid_free(cs);
07741       /* If the CID had Message waiting payload, assume that this for MWI only and hangup the call */
07742       if (flags & CID_MSGWAITING) {
07743          ast_log(LOG_NOTICE, "MWI: Channel %d message waiting!\n", p->channel);
07744          notify_message(p->mailbox, 1);
07745          /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
07746          if (p->mwimonitor_rpas) {
07747             ast_hangup(chan);
07748             return NULL;
07749          }
07750       } else if (flags & CID_NOMSGWAITING) {
07751          ast_log(LOG_NOTICE, "MWI: Channel %d no message waiting!\n", p->channel);
07752          notify_message(p->mailbox, 0);
07753          /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
07754          if (p->mwimonitor_rpas) {
07755             ast_hangup(chan);
07756             return NULL;
07757          }
07758       }
07759 
07760       ast_setstate(chan, AST_STATE_RING);
07761       chan->rings = 1;
07762       p->ringt = p->ringt_base;
07763       res = ast_pbx_run(chan);
07764       if (res) {
07765          ast_hangup(chan);
07766          ast_log(LOG_WARNING, "PBX exited non-zero\n");
07767       }
07768       goto quit;
07769    default:
07770       ast_log(LOG_WARNING, "Don't know how to handle simple switch with signalling %s on channel %d\n", sig2str(p->sig), p->channel);
07771       res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07772       if (res < 0)
07773             ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
07774    }
07775    res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07776    if (res < 0)
07777          ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
07778    ast_hangup(chan);
07779 quit:
07780    ast_mutex_lock(&ss_thread_lock);
07781    ss_thread_count--;
07782    ast_cond_signal(&ss_thread_complete);
07783    ast_mutex_unlock(&ss_thread_lock);
07784    return NULL;
07785 }
07786 
07787 struct mwi_thread_data {
07788    struct dahdi_pvt *pvt;
07789    unsigned char buf[READ_SIZE];
07790    size_t len;
07791 };
07792 
07793 static int calc_energy(const unsigned char *buf, int len, int law)
07794 {
07795    int x;
07796    int sum = 0;
07797 
07798    if (!len)
07799       return 0;
07800 
07801    for (x = 0; x < len; x++)
07802       sum += abs(law == AST_FORMAT_ULAW ? AST_MULAW(buf[x]) : AST_ALAW(buf[x]));
07803 
07804    return sum / len;
07805 }
07806 
07807 static void *mwi_thread(void *data)
07808 {
07809    struct mwi_thread_data *mtd = data;
07810    struct callerid_state *cs;
07811    pthread_t threadid;
07812    int samples = 0;
07813    char *name, *number;
07814    int flags;
07815    int i, res;
07816    unsigned int spill_done = 0;
07817    int spill_result = -1;
07818    
07819    if (!(cs = callerid_new(mtd->pvt->cid_signalling))) {
07820       mtd->pvt->mwimonitoractive = 0;
07821 
07822       return NULL;
07823    }
07824    
07825    callerid_feed(cs, mtd->buf, mtd->len, AST_LAW(mtd->pvt));
07826 
07827    bump_gains(mtd->pvt);
07828 
07829    for (;;) {  
07830       i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07831       if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
07832          ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07833          goto quit;
07834       }
07835 
07836       if (i & DAHDI_IOMUX_SIGEVENT) {
07837          struct ast_channel *chan;
07838 
07839          /* If we get an event, screen out events that we do not act on.
07840           * Otherwise, cancel and go to the simple switch to let it deal with it.
07841           */
07842          res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
07843 
07844          switch (res) {
07845          case DAHDI_EVENT_NEONMWI_ACTIVE:
07846          case DAHDI_EVENT_NEONMWI_INACTIVE:
07847          case DAHDI_EVENT_NONE:
07848          case DAHDI_EVENT_BITSCHANGED:
07849             break;
07850          case DAHDI_EVENT_NOALARM:
07851             mtd->pvt->inalarm = 0;
07852             ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", mtd->pvt->channel);
07853             manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
07854                "Channel: %d\r\n", mtd->pvt->channel);
07855             break;
07856          case DAHDI_EVENT_ALARM:
07857             mtd->pvt->inalarm = 1;
07858             res = get_alarms(mtd->pvt);
07859             handle_alarms(mtd->pvt, res);
07860             break; /* What to do on channel alarm ???? -- fall thru intentionally?? */
07861          default:
07862             ast_log(LOG_NOTICE, "Got event %d (%s)...  Passing along to ss_thread\n", res, event2str(res));
07863             callerid_free(cs);
07864             
07865             restore_gains(mtd->pvt);
07866             mtd->pvt->ringt = mtd->pvt->ringt_base;
07867 
07868             if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, 0))) {
07869                if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
07870                   ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", mtd->pvt->channel);
07871                   res = tone_zone_play_tone(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
07872                   if (res < 0)
07873                      ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", mtd->pvt->channel);
07874                   ast_hangup(chan);
07875                   goto quit;
07876                }
07877                goto quit_no_clean;
07878 
07879             } else {
07880                ast_log(LOG_WARNING, "Could not create channel to handle call\n");
07881             }
07882          }
07883       } else if (i & DAHDI_IOMUX_READ) {
07884          if ((res = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
07885             if (errno != ELAST) {
07886                ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07887                goto quit;
07888             }
07889             break;
07890          }
07891          samples += res;
07892          if (!spill_done) {
07893             if ((spill_result = callerid_feed(cs, mtd->buf, res, AST_LAW(mtd->pvt))) < 0) {
07894                ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
07895                break;
07896             } else if (spill_result) {
07897                spill_done = 1;
07898             }
07899          } else {
07900             /* keep reading data until the energy level drops below the threshold
07901                so we don't get another 'trigger' on the remaining carrier signal
07902             */
07903             if (calc_energy(mtd->buf, res, AST_LAW(mtd->pvt)) <= mwilevel)
07904                break;
07905          }
07906          if (samples > (8000 * 4)) /*Termination case - time to give up*/
07907             break;
07908       }
07909    }
07910 
07911    if (spill_result == 1) {
07912       callerid_get(cs, &name, &number, &flags);
07913       if (flags & CID_MSGWAITING) {
07914          ast_log(LOG_NOTICE, "mwi: Have Messages on channel %d\n", mtd->pvt->channel);
07915          notify_message(mtd->pvt->mailbox, 1);
07916       } else if (flags & CID_NOMSGWAITING) {
07917          ast_log(LOG_NOTICE, "mwi: No Messages on channel %d\n", mtd->pvt->channel);
07918          notify_message(mtd->pvt->mailbox, 0);
07919       } else {
07920          ast_log(LOG_NOTICE, "mwi: Status unknown on channel %d\n", mtd->pvt->channel);
07921       }
07922    }
07923 
07924 
07925 quit:
07926    callerid_free(cs);
07927 
07928    restore_gains(mtd->pvt);
07929 
07930 quit_no_clean:
07931    mtd->pvt->mwimonitoractive = 0;
07932 
07933    ast_free(mtd);
07934 
07935    return NULL;
07936 }
07937 
07938 /* States for sending MWI message
07939  * First three states are required for send Ring Pulse Alert Signal 
07940  */
07941 enum mwisend_states {
07942    MWI_SEND_SA,
07943  MWI_SEND_SA_WAIT,
07944  MWI_SEND_PAUSE,
07945  MWI_SEND_SPILL,
07946  MWI_SEND_CLEANUP,
07947  MWI_SEND_DONE
07948 };
07949 
07950 static void *mwi_send_thread(void *data)
07951 {
07952    struct mwi_thread_data *mtd = data;
07953    struct timeval timeout_basis, suspend, now;
07954    int x, i, res;
07955    int num_read;
07956    enum mwisend_states mwi_send_state = MWI_SEND_SPILL; /*Assume FSK only */
07957 
07958    ast_mutex_lock(&mwi_thread_lock);
07959    mwi_thread_count++;
07960    ast_mutex_unlock(&mwi_thread_lock);
07961 
07962    /* Determine how this spill is to be sent */
07963    if(mwisend_rpas) {
07964       mwi_send_state = MWI_SEND_SA;
07965    }
07966 
07967    gettimeofday(&timeout_basis, NULL);
07968    
07969    mtd->pvt->cidspill = ast_calloc(1, MAX_CALLERID_SIZE);
07970    if (!mtd->pvt->cidspill) {
07971       mtd->pvt->mwisendactive = 0;
07972       ast_free(mtd);
07973       return NULL;
07974    }
07975    x = DAHDI_FLUSH_BOTH;
07976    res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
07977    x = 3000;
07978    ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x);
07979    mtd->pvt->cidlen = vmwi_generate(mtd->pvt->cidspill, has_voicemail(mtd->pvt), CID_MWI_TYPE_MDMF_FULL,
07980                             AST_LAW(mtd->pvt), mtd->pvt->cid_name, mtd->pvt->cid_num, 0);
07981    mtd->pvt->cidpos = 0;
07982 
07983    while (MWI_SEND_DONE != mwi_send_state) {
07984       num_read = 0;
07985       gettimeofday(&now, NULL);
07986       if ( 10 < (now.tv_sec - timeout_basis.tv_sec)) {
07987          ast_log(LOG_WARNING, "MWI Send TIMEOUT in state %d\n", mwi_send_state);
07988          goto quit;
07989       }
07990 
07991       i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07992       if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
07993          ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07994          goto quit;
07995       }
07996 
07997       if (i & DAHDI_IOMUX_SIGEVENT) {
07998          /* If we get an event, screen out events that we do not act on.
07999          * Otherwise, let handle_init_event determine what is needed
08000          */
08001          res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
08002          switch (res) {
08003             case DAHDI_EVENT_RINGEROFF:
08004                if(mwi_send_state == MWI_SEND_SA_WAIT) {
08005                   if (dahdi_set_hook(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
08006                      ast_log(LOG_WARNING, "Unable to finsh RP-AS: %s\n", strerror(errno));
08007                      goto quit;
08008                   }
08009                   mwi_send_state = MWI_SEND_PAUSE;
08010                   gettimeofday(&suspend, NULL);
08011                }
08012                break;
08013             case DAHDI_EVENT_RINGERON:
08014             case DAHDI_EVENT_HOOKCOMPLETE:
08015                break;
08016             default:
08017                /* Got to the default init event handler */
08018                if (0 < handle_init_event(mtd->pvt, res)) {
08019                   /* I've spawned a thread, get out */
08020                   goto quit;
08021                }
08022                break;
08023          }
08024       } else if (i & DAHDI_IOMUX_READ) {
08025          if ((num_read = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
08026             if (errno != ELAST) {
08027                ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
08028                goto quit;
08029             }
08030             break;
08031          }
08032       }
08033       /* Perform mwi send action */
08034       switch ( mwi_send_state) {
08035          case MWI_SEND_SA:
08036             /* Send the Ring Pulse Signal Alert */
08037             res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &AS_RP_cadence);
08038             if (res) {
08039                ast_log(LOG_WARNING, "Unable to set RP-AS ring cadence: %s\n", strerror(errno));
08040                goto quit;
08041             }
08042             dahdi_set_hook(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_RING);
08043             mwi_send_state = MWI_SEND_SA_WAIT;
08044             break;
08045             case MWI_SEND_SA_WAIT:  /* do nothing until I get RINGEROFF event */
08046                break;
08047                case MWI_SEND_PAUSE:  /* Wait between alert and spill - min of 500 mS*/
08048                   gettimeofday(&now, NULL);
08049                   if ((int)(now.tv_sec - suspend.tv_sec) * 1000000 + (int)now.tv_usec - (int)suspend.tv_usec > 500000) {
08050                      mwi_send_state = MWI_SEND_SPILL;
08051                   }
08052                   break;
08053          case MWI_SEND_SPILL:
08054             /* We read some number of bytes.  Write an equal amount of data */
08055             if(0 < num_read) {
08056                if (num_read > mtd->pvt->cidlen - mtd->pvt->cidpos)
08057                   num_read = mtd->pvt->cidlen - mtd->pvt->cidpos;
08058                res = write(mtd->pvt->subs[SUB_REAL].dfd, mtd->pvt->cidspill + mtd->pvt->cidpos, num_read);
08059                if (res > 0) {
08060                   mtd->pvt->cidpos += res;
08061                   if (mtd->pvt->cidpos >= mtd->pvt->cidlen) {
08062                      ast_free(mtd->pvt->cidspill);
08063                      mtd->pvt->cidspill = NULL;
08064                      mtd->pvt->cidpos = 0;
08065                      mtd->pvt->cidlen = 0;
08066                      mwi_send_state = MWI_SEND_CLEANUP;
08067                   }
08068                } else {
08069                   ast_log(LOG_WARNING, "MWI Send Write failed: %s\n", strerror(errno));
08070                   goto quit;
08071                }
08072             }
08073             break;
08074          case MWI_SEND_CLEANUP:
08075             /* For now, do nothing */
08076             mwi_send_state = MWI_SEND_DONE;
08077             break;
08078          default:
08079             /* Should not get here, punt*/
08080             goto quit;
08081             break;
08082       }
08083    }
08084 
08085 quit:
08086    if(mtd->pvt->cidspill) {
08087       ast_free(mtd->pvt->cidspill);
08088       mtd->pvt->cidspill = NULL;
08089    }
08090    mtd->pvt->mwisendactive = 0;
08091    ast_free(mtd);
08092 
08093    ast_mutex_lock(&mwi_thread_lock);
08094    mwi_thread_count--;
08095    ast_cond_signal(&mwi_thread_complete);
08096    ast_mutex_unlock(&mwi_thread_lock);
08097 
08098    return NULL;
08099 }
08100 
08101 
08102 /* destroy a DAHDI channel, identified by its number */
08103 static int dahdi_destroy_channel_bynum(int channel)
08104 {
08105    struct dahdi_pvt *tmp = NULL;
08106    struct dahdi_pvt *prev = NULL;
08107 
08108    tmp = iflist;
08109    while (tmp) {
08110       if (tmp->channel == channel) {
08111          int x = DAHDI_FLASH;
08112          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 */
08113          destroy_channel(prev, tmp, 1);
08114          ast_module_unref(ast_module_info->self);
08115          return RESULT_SUCCESS;
08116       }
08117       prev = tmp;
08118       tmp = tmp->next;
08119    }
08120    return RESULT_FAILURE;
08121 }
08122 
08123 static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
08124 {
08125    int res;
08126    pthread_t threadid;
08127    struct ast_channel *chan;
08128 
08129    /* Handle an event on a given channel for the monitor thread. */
08130 
08131    switch (event) {
08132    case DAHDI_EVENT_NONE:
08133    case DAHDI_EVENT_BITSCHANGED:
08134       break;
08135    case DAHDI_EVENT_WINKFLASH:
08136    case DAHDI_EVENT_RINGOFFHOOK:
08137       if (i->inalarm) break;
08138       if (i->radio) break;
08139       /* Got a ring/answer.  What kind of channel are we? */
08140       switch (i->sig) {
08141       case SIG_FXOLS:
08142       case SIG_FXOGS:
08143       case SIG_FXOKS:
08144          res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
08145          if (res && (errno == EBUSY))
08146             break;
08147          if (i->cidspill) {
08148             /* Cancel VMWI spill */
08149             ast_free(i->cidspill);
08150             i->cidspill = NULL;
08151          }
08152          if (i->immediate) {
08153             dahdi_enable_ec(i);
08154             /* The channel is immediately up.  Start right away */
08155             res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
08156             chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, 0);
08157             if (!chan) {
08158                ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
08159                res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
08160                if (res < 0)
08161                   ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
08162             }
08163          } else {
08164             /* Check for callerid, digits, etc */
08165             chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, 0);
08166             if (chan) {
08167                if (has_voicemail(i))
08168                   res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
08169                else
08170                   res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
08171                if (res < 0) 
08172                   ast_log(LOG_WARNING, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i->channel);
08173                if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
08174                   ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
08175                   res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
08176                   if (res < 0)
08177                      ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
08178                   ast_hangup(chan);
08179                }
08180             } else
08181                ast_log(LOG_WARNING, "Unable to create channel\n");
08182          }
08183          break;
08184       case SIG_FXSLS:
08185       case SIG_FXSGS:
08186       case SIG_FXSKS:
08187             i->ringt = i->ringt_base;
08188             /* Fall through */
08189       case SIG_EMWINK:
08190       case SIG_FEATD:
08191       case SIG_FEATDMF:
08192       case SIG_FEATDMF_TA:
08193       case SIG_E911:
08194       case SIG_FGC_CAMA:
08195       case SIG_FGC_CAMAMF:
08196       case SIG_FEATB:
08197       case SIG_EM:
08198       case SIG_EM_E1:
08199       case SIG_SFWINK:
08200       case SIG_SF_FEATD:
08201       case SIG_SF_FEATDMF:
08202       case SIG_SF_FEATB:
08203       case SIG_SF:
08204          /* Check for callerid, digits, etc */
08205          if (i->cid_start == CID_START_POLARITY_IN) {
08206             chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0);
08207          } else {
08208             chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, 0);
08209          }
08210 
08211          if (!chan) {
08212             ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
08213          } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
08214             ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
08215             res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
08216             if (res < 0) {
08217                ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
08218             }
08219             ast_hangup(chan);
08220          }
08221          break;
08222       default:
08223          ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
08224          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
08225          if (res < 0)
08226                ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
08227          return NULL;
08228       }
08229       break;
08230    case DAHDI_EVENT_NOALARM:
08231       i->inalarm = 0;
08232       ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel);
08233       manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
08234          "Channel: %d\r\n", i->channel);
08235       break;
08236    case DAHDI_EVENT_ALARM:
08237       i->inalarm = 1;
08238       res = get_alarms(i);
08239       handle_alarms(i, res);
08240       /* fall thru intentionally */
08241    case DAHDI_EVENT_ONHOOK:
08242       if (i->radio)
08243          break;
08244       /* Back on hook.  Hang up. */
08245       switch (i->sig) {
08246       case SIG_FXOLS:
08247       case SIG_FXOGS:
08248       case SIG_FEATD:
08249       case SIG_FEATDMF:
08250       case SIG_FEATDMF_TA:
08251       case SIG_E911:
08252       case SIG_FGC_CAMA:
08253       case SIG_FGC_CAMAMF:
08254       case SIG_FEATB:
08255       case SIG_EM:
08256       case SIG_EM_E1:
08257       case SIG_EMWINK:
08258       case SIG_SF_FEATD:
08259       case SIG_SF_FEATDMF:
08260       case SIG_SF_FEATB:
08261       case SIG_SF:
08262       case SIG_SFWINK:
08263       case SIG_FXSLS:
08264       case SIG_FXSGS:
08265       case SIG_FXSKS:
08266       case SIG_GR303FXSKS:
08267          dahdi_disable_ec(i);
08268          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
08269          dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
08270          break;
08271       case SIG_GR303FXOKS:
08272       case SIG_FXOKS:
08273          dahdi_disable_ec(i);
08274          /* Diddle the battery for the zhone */
08275 #ifdef ZHONE_HACK
08276          dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
08277          usleep(1);
08278 #endif         
08279          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
08280          dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
08281          break;
08282       case SIG_PRI:
08283       case SIG_SS7:
08284       case SIG_BRI:
08285       case SIG_BRI_PTMP:
08286          dahdi_disable_ec(i);
08287          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
08288          break;
08289       default:
08290          ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
08291          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
08292          return NULL;
08293       }
08294       break;
08295    case DAHDI_EVENT_POLARITY:
08296       switch (i->sig) {
08297       case SIG_FXSLS:
08298       case SIG_FXSKS:
08299       case SIG_FXSGS:
08300          /* We have already got a PR before the channel was 
08301             created, but it wasn't handled. We need polarity 
08302             to be REV for remote hangup detection to work. 
08303             At least in Spain */
08304          if (i->hanguponpolarityswitch)
08305             i->polarity = POLARITY_REV;
08306          if (i->cid_start == CID_START_POLARITY || i->cid_start == CID_START_POLARITY_IN) {
08307             i->polarity = POLARITY_REV;
08308             ast_verb(2, "Starting post polarity "
08309                    "CID detection on channel %d\n",
08310                    i->channel);
08311             chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0);
08312             if (!chan) {
08313                ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
08314             } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
08315                ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
08316             }
08317          }
08318          break;
08319       default:
08320          ast_log(LOG_WARNING, "handle_init_event detected "
08321             "polarity reversal on non-FXO (SIG_FXS) "
08322             "interface %d\n", i->channel);
08323       }
08324       break;
08325    case DAHDI_EVENT_REMOVED: /* destroy channel, will actually do so in do_monitor */
08326       ast_log(LOG_NOTICE, 
08327             "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n", 
08328             i->channel);
08329       return i;
08330    case DAHDI_EVENT_NEONMWI_ACTIVE:
08331       if (i->mwimonitor_neon) {
08332          notify_message(i->mailbox, 1);
08333          ast_log(LOG_NOTICE, "NEON MWI set for channel %d, mailbox %s \n", i->channel, i->mailbox);
08334       }
08335       break;
08336    case DAHDI_EVENT_NEONMWI_INACTIVE:
08337       if (i->mwimonitor_neon) {
08338          notify_message(i->mailbox, 0);
08339          ast_log(LOG_NOTICE, "NEON MWI cleared for channel %d, mailbox %s\n", i->channel, i->mailbox);
08340       }
08341       break;
08342    }
08343    return NULL;
08344 }
08345 
08346 static void *do_monitor(void *data)
08347 {
08348    int count, res, res2, spoint, pollres=0;
08349    struct dahdi_pvt *i;
08350    struct dahdi_pvt *last = NULL;
08351    struct dahdi_pvt *doomed;
08352    time_t thispass = 0, lastpass = 0;
08353    int found;
08354    char buf[1024];
08355    struct pollfd *pfds=NULL;
08356    int lastalloc = -1;
08357    /* This thread monitors all the frame relay interfaces which are not yet in use
08358       (and thus do not have a separate thread) indefinitely */
08359    /* From here on out, we die whenever asked */
08360 #if 0
08361    if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
08362       ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
08363       return NULL;
08364    }
08365    ast_debug(1, "Monitor starting...\n");
08366 #endif
08367    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
08368 
08369    for (;;) {
08370       /* Lock the interface list */
08371       ast_mutex_lock(&iflock);
08372       if (!pfds || (lastalloc != ifcount)) {
08373          if (pfds) {
08374             ast_free(pfds);
08375             pfds = NULL;
08376          }
08377          if (ifcount) {
08378             if (!(pfds = ast_calloc(1, ifcount * sizeof(*pfds)))) {
08379                ast_mutex_unlock(&iflock);
08380                return NULL;
08381             }
08382          }
08383          lastalloc = ifcount;
08384       }
08385       /* Build the stuff we're going to poll on, that is the socket of every
08386          dahdi_pvt that does not have an associated owner channel */
08387       count = 0;
08388       i = iflist;
08389       while (i) {
08390          if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio)) {
08391             if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive && !i->mwisendactive) {
08392                /* This needs to be watched, as it lacks an owner */
08393                pfds[count].fd = i->subs[SUB_REAL].dfd;
08394                pfds[count].events = POLLPRI;
08395                pfds[count].revents = 0;
08396                /* If we are monitoring for VMWI or sending CID, we need to
08397                   read from the channel as well */
08398                if (i->cidspill || i->mwimonitor_fsk)
08399                   pfds[count].events |= POLLIN;
08400                count++;
08401             }
08402          }
08403          i = i->next;
08404       }
08405       /* Okay, now that we know what to do, release the interface lock */
08406       ast_mutex_unlock(&iflock);
08407       
08408       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
08409       pthread_testcancel();
08410       /* Wait at least a second for something to happen */
08411       res = poll(pfds, count, 1000);
08412       pthread_testcancel();
08413       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
08414 
08415       /* Okay, poll has finished.  Let's see what happened.  */
08416       if (res < 0) {
08417          if ((errno != EAGAIN) && (errno != EINTR))
08418             ast_log(LOG_WARNING, "poll return %d: %s\n", res, strerror(errno));
08419          continue;
08420       }
08421       /* Alright, lock the interface list again, and let's look and see what has
08422          happened */
08423       ast_mutex_lock(&iflock);
08424       found = 0;
08425       spoint = 0;
08426       lastpass = thispass;
08427       thispass = time(NULL);
08428       i = iflist;
08429       doomed = NULL;
08430       for (i = iflist;; i = i->next) {
08431          if (doomed) {
08432             int res;
08433             res = dahdi_destroy_channel_bynum(doomed->channel);
08434             if (!res) {
08435                ast_log(LOG_WARNING, "Couldn't find channel to destroy, hopefully another destroy operation just happened.\n");
08436             }
08437             doomed = NULL;
08438          }
08439          if (!i) {
08440             break;
08441          }
08442 
08443          if (thispass != lastpass) {
08444             if (!found && ((i == last) || ((i == iflist) && !last))) {
08445                last = i;
08446                if (last) {
08447                   if (!last->mwisendactive &&    last->sig & __DAHDI_SIG_FXO) {
08448                      res = has_voicemail(last);
08449                      if (last->msgstate != res) {
08450 
08451                         /* This channel has a new voicemail state,
08452                         * initiate a thread to send an MWI message
08453                         */
08454                         pthread_attr_t attr;
08455                         pthread_t threadid;
08456                         struct mwi_thread_data *mtd;
08457                         res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_VMWI, &res);
08458                         if (res2) {
08459                            /* TODO: This message will ALWAYS be generated on some cards; any way to restrict it to those cards where it is interesting? */
08460                            ast_debug(3, "Unable to control message waiting led on channel %d: %s\n", last->channel, strerror(errno));
08461                         }
08462                         pthread_attr_init(&attr);
08463                         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
08464                         if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
08465                            last->msgstate = res;
08466                            mtd->pvt = last;
08467                            last->mwisendactive = 1;
08468                            if (ast_pthread_create_background(&threadid, &attr, mwi_send_thread, mtd)) {
08469                               ast_log(LOG_WARNING, "Unable to start mwi send thread on channel %d\n", last->channel);
08470                               ast_free(mtd);
08471                               last->mwisendactive = 0;
08472                            }
08473                         }
08474                         found ++;
08475                      }
08476                   }
08477                   last = last->next;
08478                }
08479             }
08480          }
08481          if ((i->subs[SUB_REAL].dfd > -1) && i->sig) {
08482             if (i->radio && !i->owner)
08483             {
08484                res = dahdi_get_event(i->subs[SUB_REAL].dfd);
08485                if (res)
08486                {
08487                   ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
08488                   /* Don't hold iflock while handling init events */
08489                   ast_mutex_unlock(&iflock);
08490                   doomed = handle_init_event(i, res);
08491                   ast_mutex_lock(&iflock);   
08492                }
08493                continue;
08494             }              
08495             pollres = ast_fdisset(pfds, i->subs[SUB_REAL].dfd, count, &spoint);
08496             if (pollres & POLLIN) {
08497                if (i->owner || i->subs[SUB_REAL].owner) {
08498 #ifdef HAVE_PRI
08499                   if (!i->pri)
08500 #endif                  
08501                      ast_log(LOG_WARNING, "Whoa....  I'm owned but found (%d) in read...\n", i->subs[SUB_REAL].dfd);
08502                   continue;
08503                }
08504                if (!i->cidspill && !i->mwimonitor_fsk) {
08505                   ast_log(LOG_WARNING, "Whoa....  I'm reading but have no cidspill (%d)...\n", i->subs[SUB_REAL].dfd);
08506                   continue;
08507                }
08508                res = read(i->subs[SUB_REAL].dfd, buf, sizeof(buf));
08509                if (res > 0) {
08510                   if (i->mwimonitor_fsk) {
08511                      if (calc_energy((unsigned char *) buf, res, AST_LAW(i)) > mwilevel) {
08512                         pthread_attr_t attr;
08513                         pthread_t threadid;
08514                         struct mwi_thread_data *mtd;
08515 
08516                         pthread_attr_init(&attr);
08517                         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
08518 
08519                         ast_log(LOG_DEBUG, "Maybe some MWI on port %d!\n", i->channel);
08520                         if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
08521                            mtd->pvt = i;
08522                            memcpy(mtd->buf, buf, res);
08523                            mtd->len = res;
08524                            if (ast_pthread_create_background(&threadid, &attr, mwi_thread, mtd)) {
08525                               ast_log(LOG_WARNING, "Unable to start mwi thread on channel %d\n", i->channel);
08526                               ast_free(mtd);
08527                            }
08528                            i->mwimonitoractive = 1;
08529                         }
08530                      }
08531                   }
08532                } else {
08533                   ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno));
08534                }
08535             }
08536             if (pollres & POLLPRI) {
08537                if (i->owner || i->subs[SUB_REAL].owner) {
08538 #ifdef HAVE_PRI
08539                   if (!i->pri)
08540 #endif                  
08541                      ast_log(LOG_WARNING, "Whoa....  I'm owned but found (%d)...\n", i->subs[SUB_REAL].dfd);
08542                   continue;
08543                }
08544                res = dahdi_get_event(i->subs[SUB_REAL].dfd);
08545                ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
08546                /* Don't hold iflock while handling init events */
08547                ast_mutex_unlock(&iflock);
08548                doomed = handle_init_event(i, res);
08549                ast_mutex_lock(&iflock);   
08550             }
08551          }
08552       }
08553       ast_mutex_unlock(&iflock);
08554    }
08555    /* Never reached */
08556    return NULL;
08557    
08558 }
08559 
08560 static int restart_monitor(void)
08561 {
08562    /* If we're supposed to be stopped -- stay stopped */
08563    if (monitor_thread == AST_PTHREADT_STOP)
08564       return 0;
08565    ast_mutex_lock(&monlock);
08566    if (monitor_thread == pthread_self()) {
08567       ast_mutex_unlock(&monlock);
08568       ast_log(LOG_WARNING, "Cannot kill myself\n");
08569       return -1;
08570    }
08571    if (monitor_thread != AST_PTHREADT_NULL) {
08572       /* Wake up the thread */
08573       pthread_kill(monitor_thread, SIGURG);
08574    } else {
08575       /* Start a new monitor */
08576       if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
08577          ast_mutex_unlock(&monlock);
08578          ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
08579          return -1;
08580       }
08581    }
08582    ast_mutex_unlock(&monlock);
08583    return 0;
08584 }
08585 
08586 #ifdef HAVE_PRI
08587 static int pri_resolve_span(int *span, int channel, int offset, struct dahdi_spaninfo *si)
08588 {
08589    int x;
08590    int trunkgroup;
08591    /* Get appropriate trunk group if there is one */
08592    trunkgroup = pris[*span].mastertrunkgroup;
08593    if (trunkgroup) {
08594       /* Select a specific trunk group */
08595       for (x = 0; x < NUM_SPANS; x++) {
08596          if (pris[x].trunkgroup == trunkgroup) {
08597             *span = x;
08598             return 0;
08599          }
08600       }
08601       ast_log(LOG_WARNING, "Channel %d on span %d configured to use nonexistent trunk group %d\n", channel, *span, trunkgroup);
08602       *span = -1;
08603    } else {
08604       if (pris[*span].trunkgroup) {
08605          ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is trunk group %d (please use spanmap)\n", *span, pris[*span].trunkgroup);
08606          *span = -1;
08607       } else if (pris[*span].mastertrunkgroup) {
08608          ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is already part of trunk group %d\n", *span, pris[*span].mastertrunkgroup);
08609          *span = -1;
08610       } else {
08611          if (si->totalchans == 31) {
08612             /* E1 */
08613             pris[*span].dchannels[0] = 16 + offset;
08614          } else if (si->totalchans == 24) {
08615             /* T1 or J1 */
08616             pris[*span].dchannels[0] = 24 + offset;
08617          } else if (si->totalchans == 3) {
08618             /* BRI */
08619             pris[*span].dchannels[0] = 3 + offset;
08620          } else {
08621             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);
08622             *span = -1;
08623             return 0;
08624          }
08625          pris[*span].dchanavail[0] |= DCHAN_PROVISIONED;
08626          pris[*span].offset = offset;
08627          pris[*span].span = *span + 1;
08628       }
08629    }
08630    return 0;
08631 }
08632 
08633 static int pri_create_trunkgroup(int trunkgroup, int *channels)
08634 {
08635    struct dahdi_spaninfo si;
08636    struct dahdi_params p;
08637    int fd;
08638    int span;
08639    int ospan=0;
08640    int x,y;
08641    for (x = 0; x < NUM_SPANS; x++) {
08642       if (pris[x].trunkgroup == trunkgroup) {
08643          ast_log(LOG_WARNING, "Trunk group %d already exists on span %d, Primary d-channel %d\n", trunkgroup, x + 1, pris[x].dchannels[0]);
08644          return -1;
08645       }
08646    }
08647    for (y = 0; y < NUM_DCHANS; y++) {
08648       if (!channels[y]) 
08649          break;
08650       memset(&si, 0, sizeof(si));
08651       memset(&p, 0, sizeof(p));
08652       fd = open("/dev/dahdi/channel", O_RDWR);
08653       if (fd < 0) {
08654          ast_log(LOG_WARNING, "Failed to open channel: %s\n", strerror(errno));
08655          return -1;
08656       }
08657       x = channels[y];
08658       if (ioctl(fd, DAHDI_SPECIFY, &x)) {
08659          ast_log(LOG_WARNING, "Failed to specify channel %d: %s\n", channels[y], strerror(errno));
08660          close(fd);
08661          return -1;
08662       }
08663       if (ioctl(fd, DAHDI_GET_PARAMS, &p)) {
08664          ast_log(LOG_WARNING, "Failed to get channel parameters for channel %d: %s\n", channels[y], strerror(errno));
08665          return -1;
08666       }
08667       if (ioctl(fd, DAHDI_SPANSTAT, &si)) {
08668          ast_log(LOG_WARNING, "Failed go get span information on channel %d (span %d): %s\n", channels[y], p.spanno, strerror(errno));
08669          close(fd);
08670          return -1;
08671       }
08672       span = p.spanno - 1;
08673       if (pris[span].trunkgroup) {
08674          ast_log(LOG_WARNING, "Span %d is already provisioned for trunk group %d\n", span + 1, pris[span].trunkgroup);
08675          close(fd);
08676          return -1;
08677       }
08678       if (pris[span].pvts[0]) {
08679          ast_log(LOG_WARNING, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span + 1);
08680          close(fd);
08681          return -1;
08682       }
08683       if (!y) {
08684          pris[span].trunkgroup = trunkgroup;
08685          pris[span].offset = channels[y] - p.chanpos;
08686          ospan = span;
08687       }
08688       pris[ospan].dchannels[y] = channels[y];
08689       pris[ospan].dchanavail[y] |= DCHAN_PROVISIONED;
08690       pris[span].span = span + 1;
08691       close(fd);
08692    }
08693    return 0;   
08694 }
08695 
08696 static int pri_create_spanmap(int span, int trunkgroup, int logicalspan)
08697 {
08698    if (pris[span].mastertrunkgroup) {
08699       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);
08700       return -1;
08701    }
08702    pris[span].mastertrunkgroup = trunkgroup;
08703    pris[span].prilogicalspan = logicalspan;
08704    return 0;
08705 }
08706 
08707 #endif
08708 
08709 #ifdef HAVE_SS7
08710 
08711 static unsigned int parse_pointcode(const char *pcstring)
08712 {
08713    unsigned int code1, code2, code3;
08714    int numvals;
08715 
08716    numvals = sscanf(pcstring, "%30d-%30d-%30d", &code1, &code2, &code3);
08717    if (numvals == 1)
08718       return code1;
08719    if (numvals == 3)
08720       return (code1 << 16) | (code2 << 8) | code3;
08721 
08722    return 0;
08723 }
08724 
08725 static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
08726 {
08727    if ((linkset < 0) || (linkset >= NUM_SPANS))
08728       return NULL;
08729    else
08730       return &linksets[linkset - 1];
08731 }
08732 #endif /* HAVE_SS7 */
08733 
08734 /* converts a DAHDI sigtype to signalling as can be configured from
08735  * chan_dahdi.conf.
08736  * While both have basically the same values, this will later be the
08737  * place to add filters and sanity checks
08738  */
08739 static int sigtype_to_signalling(int sigtype)
08740 {
08741         return sigtype;
08742 }
08743 
08744 static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, struct dahdi_pri *pri, int reloading)
08745 {
08746    /* Make a dahdi_pvt structure for this interface (or CRV if "pri" is specified) */
08747    struct dahdi_pvt *tmp = NULL, *tmp2,  *prev = NULL;
08748    char fn[80];
08749    struct dahdi_bufferinfo bi;
08750 
08751    int res;
08752    int span = 0;
08753    int here = 0;
08754    int x;
08755    struct dahdi_pvt **wlist;
08756    struct dahdi_pvt **wend;
08757    struct dahdi_params p;
08758 
08759    wlist = &iflist;
08760    wend = &ifend;
08761 
08762 #ifdef HAVE_PRI
08763    if (pri) {
08764       wlist = &pri->crvs;
08765       wend = &pri->crvend;
08766    }
08767 #endif
08768 
08769    tmp2 = *wlist;
08770    prev = NULL;
08771 
08772    while (tmp2) {
08773       if (!tmp2->destroy) {
08774          if (tmp2->channel == channel) {
08775             tmp = tmp2;
08776             here = 1;
08777             break;
08778          }
08779          if (tmp2->channel > channel) {
08780             break;
08781          }
08782       }
08783       prev = tmp2;
08784       tmp2 = tmp2->next;
08785    }
08786 
08787    if (!here && reloading != 1) {
08788       if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
08789          if (tmp)
08790             free(tmp);
08791          return NULL;
08792       }
08793       ast_mutex_init(&tmp->lock);
08794       ifcount++;
08795       for (x = 0; x < 3; x++)
08796          tmp->subs[x].dfd = -1;
08797       tmp->channel = channel;
08798       tmp->priindication_oob = conf->chan.priindication_oob;
08799    }
08800 
08801    if (tmp) {
08802       int chan_sig = conf->chan.sig;
08803       if (!here) {
08804          if ((channel != CHAN_PSEUDO) && !pri) {
08805             int count = 0;
08806             snprintf(fn, sizeof(fn), "%d", channel);
08807             /* Open non-blocking */
08808             tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
08809             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 */
08810                usleep(1);
08811                tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
08812                count++;
08813             }
08814             /* Allocate a DAHDI structure */
08815             if (tmp->subs[SUB_REAL].dfd < 0) {
08816                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);
08817                destroy_dahdi_pvt(&tmp);
08818                return NULL;
08819             }
08820             memset(&p, 0, sizeof(p));
08821             res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
08822             if (res < 0) {
08823                ast_log(LOG_ERROR, "Unable to get parameters: %s\n", strerror(errno));
08824                destroy_dahdi_pvt(&tmp);
08825                return NULL;
08826             }
08827             if (conf->is_sig_auto)
08828                chan_sig = sigtype_to_signalling(p.sigtype);
08829             if (p.sigtype != (chan_sig & 0x3ffff)) {
08830                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));
08831                destroy_dahdi_pvt(&tmp);
08832                return NULL;
08833             }
08834             tmp->law = p.curlaw;
08835             tmp->span = p.spanno;
08836             span = p.spanno - 1;
08837          } else {
08838             if (channel == CHAN_PSEUDO)
08839                chan_sig = 0;
08840             else if ((chan_sig != SIG_FXOKS) && (chan_sig != SIG_FXSKS)) {
08841                ast_log(LOG_ERROR, "CRV's must use FXO/FXS Kewl Start (fxo_ks/fxs_ks) signalling only.\n");
08842                return NULL;
08843             }
08844          }
08845 #ifdef HAVE_SS7
08846          if (chan_sig == SIG_SS7) {
08847             struct dahdi_ss7 *ss7;
08848             int clear = 0;
08849             if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &clear)) {
08850                ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
08851                destroy_dahdi_pvt(&tmp);
08852                return NULL;
08853             }
08854 
08855             ss7 = ss7_resolve_linkset(cur_linkset);
08856             if (!ss7) {
08857                ast_log(LOG_ERROR, "Unable to find linkset %d\n", cur_linkset);
08858                destroy_dahdi_pvt(&tmp);
08859                return NULL;
08860             }
08861             if (cur_cicbeginswith < 0) {
08862                ast_log(LOG_ERROR, "Need to set cicbeginswith for the channels!\n");
08863                destroy_dahdi_pvt(&tmp);
08864                return NULL;
08865             }
08866 
08867             tmp->cic = cur_cicbeginswith++;
08868 
08869             /* DB: Add CIC's DPC information */
08870             tmp->dpc = cur_defaultdpc;
08871 
08872             tmp->ss7 = ss7;
08873             tmp->ss7call = NULL;
08874             ss7->pvts[ss7->numchans++] = tmp;
08875 
08876             ast_copy_string(ss7->internationalprefix, conf->ss7.internationalprefix, sizeof(ss7->internationalprefix));
08877             ast_copy_string(ss7->nationalprefix, conf->ss7.nationalprefix, sizeof(ss7->nationalprefix));
08878             ast_copy_string(ss7->subscriberprefix, conf->ss7.subscriberprefix, sizeof(ss7->subscriberprefix));
08879             ast_copy_string(ss7->unknownprefix, conf->ss7.unknownprefix, sizeof(ss7->unknownprefix));
08880 
08881             ss7->called_nai = conf->ss7.called_nai;
08882             ss7->calling_nai = conf->ss7.calling_nai;
08883          }
08884 #endif
08885 #ifdef HAVE_PRI
08886          if ((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP) || (chan_sig == SIG_GR303FXOKS) || (chan_sig == SIG_GR303FXSKS)) {
08887             int offset;
08888             int myswitchtype;
08889             int matchesdchan;
08890             int x,y;
08891             offset = 0;
08892             if (((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP)) 
08893                   && ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &offset)) {
08894                ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
08895                destroy_dahdi_pvt(&tmp);
08896                return NULL;
08897             }
08898             if (span >= NUM_SPANS) {
08899                ast_log(LOG_ERROR, "Channel %d does not lie on a span I know of (%d)\n", channel, span);
08900                destroy_dahdi_pvt(&tmp);
08901                return NULL;
08902             } else {
08903                struct dahdi_spaninfo si;
08904                si.spanno = 0;
08905                if (ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SPANSTAT,&si) == -1) {
08906                   ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno));
08907                   destroy_dahdi_pvt(&tmp);
08908                   return NULL;
08909                }
08910                /* Store the logical span first based upon the real span */
08911                tmp->logicalspan = pris[span].prilogicalspan;
08912                pri_resolve_span(&span, channel, (channel - p.chanpos), &si);
08913                if (span < 0) {
08914                   ast_log(LOG_WARNING, "Channel %d: Unable to find locate channel/trunk group!\n", channel);
08915                   destroy_dahdi_pvt(&tmp);
08916                   return NULL;
08917                }
08918                if ((chan_sig == SIG_PRI) ||
08919                      (chan_sig == SIG_BRI) ||
08920                      (chan_sig == SIG_BRI_PTMP))
08921                   myswitchtype = conf->pri.switchtype;
08922                else
08923                   myswitchtype = PRI_SWITCH_GR303_TMC;
08924                /* Make sure this isn't a d-channel */
08925                matchesdchan=0;
08926                for (x = 0; x < NUM_SPANS; x++) {
08927                   for (y = 0; y < NUM_DCHANS; y++) {
08928                      if (pris[x].dchannels[y] == tmp->channel) {
08929                         matchesdchan = 1;
08930                         break;
08931                      }
08932                   }
08933                }
08934                offset = p.chanpos;
08935                if (!matchesdchan) {
08936                   if (pris[span].nodetype && (pris[span].nodetype != conf->pri.nodetype)) {
08937                      ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].nodetype));
08938                      destroy_dahdi_pvt(&tmp);
08939                      return NULL;
08940                   }
08941                   if (pris[span].switchtype && (pris[span].switchtype != myswitchtype)) {
08942                      ast_log(LOG_ERROR, "Span %d is already a %s switch\n", span + 1, pri_switch2str(pris[span].switchtype));
08943                      destroy_dahdi_pvt(&tmp);
08944                      return NULL;
08945                   }
08946                   if ((pris[span].dialplan) && (pris[span].dialplan != conf->pri.dialplan)) {
08947                      ast_log(LOG_ERROR, "Span %d is already a %s dialing plan\n", span + 1, dialplan2str(pris[span].dialplan));
08948                      destroy_dahdi_pvt(&tmp);
08949                      return NULL;
08950                   }
08951                   if (!ast_strlen_zero(pris[span].idledial) && strcmp(pris[span].idledial, conf->pri.idledial)) {
08952                      ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, conf->pri.idledial);
08953                      destroy_dahdi_pvt(&tmp);
08954                      return NULL;
08955                   }
08956                   if (!ast_strlen_zero(pris[span].idleext) && strcmp(pris[span].idleext, conf->pri.idleext)) {
08957                      ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, conf->pri.idleext);
08958                      destroy_dahdi_pvt(&tmp);
08959                      return NULL;
08960                   }
08961                   if (pris[span].minunused && (pris[span].minunused != conf->pri.minunused)) {
08962                      ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, conf->pri.minunused);
08963                      destroy_dahdi_pvt(&tmp);
08964                      return NULL;
08965                   }
08966                   if (pris[span].minidle && (pris[span].minidle != conf->pri.minidle)) {
08967                      ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, conf->pri.minidle);
08968                      destroy_dahdi_pvt(&tmp);
08969                      return NULL;
08970                   }
08971                   if (pris[span].numchans >= MAX_CHANNELS) {
08972                      ast_log(LOG_ERROR, "Unable to add channel %d: Too many channels in trunk group %d!\n", channel,
08973                         pris[span].trunkgroup);
08974                      destroy_dahdi_pvt(&tmp);
08975                      return NULL;
08976                   }
08977 
08978                   pris[span].sig = chan_sig;
08979                   pris[span].nodetype = conf->pri.nodetype;
08980                   pris[span].switchtype = myswitchtype;
08981                   pris[span].nsf = conf->pri.nsf;
08982                   pris[span].dialplan = conf->pri.dialplan;
08983                   pris[span].localdialplan = conf->pri.localdialplan;
08984                   pris[span].pvts[pris[span].numchans++] = tmp;
08985                   pris[span].minunused = conf->pri.minunused;
08986                   pris[span].minidle = conf->pri.minidle;
08987                   pris[span].overlapdial = conf->pri.overlapdial;
08988 #ifdef HAVE_PRI_INBANDDISCONNECT
08989                   pris[span].inbanddisconnect = conf->pri.inbanddisconnect;
08990 #endif
08991                   pris[span].facilityenable = conf->pri.facilityenable;
08992                   ast_copy_string(pris[span].idledial, conf->pri.idledial, sizeof(pris[span].idledial));
08993                   ast_copy_string(pris[span].idleext, conf->pri.idleext, sizeof(pris[span].idleext));
08994                   ast_copy_string(pris[span].internationalprefix, conf->pri.internationalprefix, sizeof(pris[span].internationalprefix));
08995                   ast_copy_string(pris[span].nationalprefix, conf->pri.nationalprefix, sizeof(pris[span].nationalprefix));
08996                   ast_copy_string(pris[span].localprefix, conf->pri.localprefix, sizeof(pris[span].localprefix));
08997                   ast_copy_string(pris[span].privateprefix, conf->pri.privateprefix, sizeof(pris[span].privateprefix));
08998                   ast_copy_string(pris[span].unknownprefix, conf->pri.unknownprefix, sizeof(pris[span].unknownprefix));
08999                   pris[span].resetinterval = conf->pri.resetinterval;
09000                   
09001                   tmp->pri = &pris[span];
09002                   tmp->prioffset = offset;
09003                   tmp->call = NULL;
09004                } else {
09005                   ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", offset);
09006                   destroy_dahdi_pvt(&tmp);
09007                   return NULL;
09008                }
09009             }
09010          } else {
09011             tmp->prioffset = 0;
09012          }
09013 #endif
09014       } else {
09015          chan_sig = tmp->sig;
09016          if (tmp->subs[SUB_REAL].dfd > -1) {
09017             memset(&p, 0, sizeof(p));
09018             res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
09019          }
09020       }
09021       /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
09022       switch (chan_sig) {
09023       case SIG_FXSKS:
09024       case SIG_FXSLS:
09025       case SIG_EM:
09026       case SIG_EM_E1:
09027       case SIG_EMWINK:
09028       case SIG_FEATD:
09029       case SIG_FEATDMF:
09030       case SIG_FEATDMF_TA:
09031       case SIG_FEATB:
09032       case SIG_E911:
09033       case SIG_SF:
09034       case SIG_SFWINK:
09035       case SIG_FGC_CAMA:
09036       case SIG_FGC_CAMAMF:
09037       case SIG_SF_FEATD:
09038       case SIG_SF_FEATDMF:
09039       case SIG_SF_FEATB:
09040          p.starttime = 250;
09041          break;
09042       }
09043 
09044       if (tmp->radio) {
09045          /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
09046          p.channo = channel;
09047          p.rxwinktime = 1;
09048          p.rxflashtime = 1;
09049          p.starttime = 1;
09050          p.debouncetime = 5;
09051       }
09052       if (!tmp->radio) {
09053          p.channo = channel;
09054          /* Override timing settings based on config file */
09055          if (conf->timing.prewinktime >= 0)
09056             p.prewinktime = conf->timing.prewinktime;
09057          if (conf->timing.preflashtime >= 0)
09058             p.preflashtime = conf->timing.preflashtime;
09059          if (conf->timing.winktime >= 0)
09060             p.winktime = conf->timing.winktime;
09061          if (conf->timing.flashtime >= 0)
09062             p.flashtime = conf->timing.flashtime;
09063          if (conf->timing.starttime >= 0)
09064             p.starttime = conf->timing.starttime;
09065          if (conf->timing.rxwinktime >= 0)
09066             p.rxwinktime = conf->timing.rxwinktime;
09067          if (conf->timing.rxflashtime >= 0)
09068             p.rxflashtime = conf->timing.rxflashtime;
09069          if (conf->timing.debouncetime >= 0)
09070             p.debouncetime = conf->timing.debouncetime;
09071       }
09072 
09073       /* dont set parms on a pseudo-channel (or CRV) */
09074       if (tmp->subs[SUB_REAL].dfd >= 0)
09075       {
09076          res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_PARAMS, &p);
09077          if (res < 0) {
09078             ast_log(LOG_ERROR, "Unable to set parameters: %s\n", strerror(errno));
09079             destroy_dahdi_pvt(&tmp);
09080             return NULL;
09081          }
09082       }
09083 #if 1
09084       if (!here && (tmp->subs[SUB_REAL].dfd > -1)) {
09085          memset(&bi, 0, sizeof(bi));
09086          res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
09087          if (!res) {
09088             bi.txbufpolicy = conf->chan.buf_policy;
09089             bi.rxbufpolicy = conf->chan.buf_policy;
09090             bi.numbufs = conf->chan.buf_no;
09091             res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
09092             if (res < 0) {
09093                ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", channel, strerror(errno));
09094             }
09095          } else
09096             ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", channel, strerror(errno));
09097       }
09098 #endif
09099       tmp->immediate = conf->chan.immediate;
09100       tmp->transfertobusy = conf->chan.transfertobusy;
09101       if (chan_sig & __DAHDI_SIG_FXS) {
09102          tmp->mwimonitor_fsk = conf->chan.mwimonitor_fsk;
09103          tmp->mwimonitor_neon = conf->chan.mwimonitor_neon;
09104          tmp->mwimonitor_rpas = conf->chan.mwimonitor_rpas;
09105       }
09106       tmp->sig = chan_sig;
09107       tmp->outsigmod = conf->chan.outsigmod;
09108       tmp->ringt_base = ringt_base;
09109       tmp->firstradio = 0;
09110       if ((chan_sig == SIG_FXOKS) || (chan_sig == SIG_FXOLS) || (chan_sig == SIG_FXOGS))
09111          tmp->permcallwaiting = conf->chan.callwaiting;
09112       else
09113          tmp->permcallwaiting = 0;
09114       /* Flag to destroy the channel must be cleared on new mkif.  Part of changes for reload to work */
09115       tmp->destroy = 0;
09116       tmp->drings = conf->chan.drings;
09117 
09118       /* 10 is a nice default. */
09119       if (tmp->drings.ringnum[0].range == 0)
09120          tmp->drings.ringnum[0].range = 10;
09121       if (tmp->drings.ringnum[1].range == 0)
09122          tmp->drings.ringnum[1].range = 10;
09123       if (tmp->drings.ringnum[2].range == 0)
09124          tmp->drings.ringnum[2].range = 10;
09125 
09126       tmp->usedistinctiveringdetection = usedistinctiveringdetection;
09127       tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
09128       tmp->threewaycalling = conf->chan.threewaycalling;
09129       tmp->adsi = conf->chan.adsi;
09130       tmp->use_smdi = conf->chan.use_smdi;
09131       tmp->permhidecallerid = conf->chan.hidecallerid;
09132       tmp->callreturn = conf->chan.callreturn;
09133       tmp->echocancel = conf->chan.echocancel;
09134       tmp->echotraining = conf->chan.echotraining;
09135       tmp->pulse = conf->chan.pulse;
09136       if (tmp->echocancel.head.tap_length) {
09137          tmp->echocanbridged = conf->chan.echocanbridged;
09138       } else {
09139          if (conf->chan.echocanbridged)
09140             ast_log(LOG_NOTICE, "echocancelwhenbridged requires echocancel to be enabled; ignoring\n");
09141          tmp->echocanbridged = 0;
09142       }
09143       tmp->busydetect = conf->chan.busydetect;
09144       tmp->busycount = conf->chan.busycount;
09145       tmp->busy_tonelength = conf->chan.busy_tonelength;
09146       tmp->busy_quietlength = conf->chan.busy_quietlength;
09147       tmp->callprogress = conf->chan.callprogress;
09148       tmp->cancallforward = conf->chan.cancallforward;
09149       tmp->dtmfrelax = conf->chan.dtmfrelax;
09150       tmp->callwaiting = tmp->permcallwaiting;
09151       tmp->hidecallerid = tmp->permhidecallerid;
09152       tmp->channel = channel;
09153       tmp->stripmsd = conf->chan.stripmsd;
09154       tmp->use_callerid = conf->chan.use_callerid;
09155       tmp->cid_signalling = conf->chan.cid_signalling;
09156       tmp->cid_start = conf->chan.cid_start;
09157       tmp->dahditrcallerid = conf->chan.dahditrcallerid;
09158       tmp->restrictcid = conf->chan.restrictcid;
09159       tmp->use_callingpres = conf->chan.use_callingpres;
09160       tmp->priexclusive = conf->chan.priexclusive;
09161       if (tmp->usedistinctiveringdetection) {
09162          if (!tmp->use_callerid) {
09163             ast_log(LOG_NOTICE, "Distinctive Ring detect requires 'usecallerid' be on\n");
09164             tmp->use_callerid = 1;
09165          }
09166       }
09167 
09168       if (tmp->cid_signalling == CID_SIG_SMDI) {
09169          if (!tmp->use_smdi) {
09170             ast_log(LOG_WARNING, "SMDI callerid requires SMDI to be enabled, enabling...\n");
09171             tmp->use_smdi = 1;
09172          }
09173       }
09174       if (tmp->use_smdi) {
09175          tmp->smdi_iface = ast_smdi_interface_find(conf->smdi_port);
09176          if (!(tmp->smdi_iface)) {
09177             ast_log(LOG_ERROR, "Invalid SMDI port specfied, disabling SMDI support\n");
09178             tmp->use_smdi = 0;
09179          }
09180       }
09181 
09182       ast_copy_string(tmp->accountcode, conf->chan.accountcode, sizeof(tmp->accountcode));
09183       tmp->amaflags = conf->chan.amaflags;
09184       if (!here) {
09185          tmp->confno = -1;
09186          tmp->propconfno = -1;
09187       }
09188       tmp->canpark = conf->chan.canpark;
09189       tmp->transfer = conf->chan.transfer;
09190       ast_copy_string(tmp->defcontext,conf->chan.context,sizeof(tmp->defcontext));
09191       ast_copy_string(tmp->language, conf->chan.language, sizeof(tmp->language));
09192       ast_copy_string(tmp->mohinterpret, conf->chan.mohinterpret, sizeof(tmp->mohinterpret));
09193       ast_copy_string(tmp->mohsuggest, conf->chan.mohsuggest, sizeof(tmp->mohsuggest));
09194       ast_copy_string(tmp->context, conf->chan.context, sizeof(tmp->context));
09195       ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
09196       tmp->cid_ton = 0;
09197       if ((tmp->sig != SIG_PRI) || (tmp->sig != SIG_SS7) || (tmp->sig != SIG_BRI) || (tmp->sig != SIG_BRI_PTMP)) {
09198          ast_copy_string(tmp->cid_num, conf->chan.cid_num, sizeof(tmp->cid_num));
09199          ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name));
09200       } else {
09201          tmp->cid_num[0] = '\0';
09202          tmp->cid_name[0] = '\0';
09203       }
09204       ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
09205       if (channel != CHAN_PSEUDO && !ast_strlen_zero(tmp->mailbox)) {
09206          char *mailbox, *context;
09207          mailbox = context = ast_strdupa(tmp->mailbox);
09208          strsep(&context, "@");
09209          if (ast_strlen_zero(context))
09210             context = "default";
09211          tmp->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, NULL,
09212             AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
09213             AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
09214             AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
09215             AST_EVENT_IE_END);
09216       }
09217       tmp->msgstate = -1;
09218       tmp->group = conf->chan.group;
09219       tmp->callgroup = conf->chan.callgroup;
09220       tmp->pickupgroup= conf->chan.pickupgroup;
09221       if (conf->chan.vars) {
09222          struct ast_variable *v, *tmpvar;
09223                    for (v = conf->chan.vars ; v ; v = v->next) {
09224                          if ((tmpvar = ast_variable_new(v->name, v->value, v->file))) {
09225                                   tmpvar->next = tmp->vars;
09226                                    tmp->vars = tmpvar;
09227                            }
09228                   }
09229       }
09230       tmp->cid_rxgain = conf->chan.cid_rxgain;
09231       tmp->rxgain = conf->chan.rxgain;
09232       tmp->txgain = conf->chan.txgain;
09233       tmp->tonezone = conf->chan.tonezone;
09234       tmp->onhooktime = time(NULL);
09235       if (tmp->subs[SUB_REAL].dfd > -1) {
09236          set_actual_gain(tmp->subs[SUB_REAL].dfd, 0, tmp->rxgain, tmp->txgain, tmp->law);
09237          if (tmp->dsp)
09238             ast_dsp_set_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax);
09239          update_conf(tmp);
09240          if (!here) {
09241             if ((chan_sig != SIG_BRI) && (chan_sig != SIG_BRI_PTMP) && (chan_sig != SIG_PRI) && (chan_sig != SIG_SS7))
09242                /* Hang it up to be sure it's good */
09243                dahdi_set_hook(tmp->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
09244          }
09245          ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SETTONEZONE,&tmp->tonezone);
09246 #ifdef HAVE_PRI
09247          /* the dchannel is down so put the channel in alarm */
09248          if (tmp->pri && !pri_is_up(tmp->pri))
09249             tmp->inalarm = 1;
09250 #endif            
09251          if ((res = get_alarms(tmp)) != DAHDI_ALARM_NONE) {
09252             tmp->inalarm = 1;
09253             handle_alarms(tmp, res);
09254          }
09255       }
09256 
09257       tmp->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
09258       tmp->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
09259       tmp->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
09260       tmp->sendcalleridafter = conf->chan.sendcalleridafter;
09261       if (!here) {
09262          tmp->locallyblocked = tmp->remotelyblocked = 0;
09263          if ((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP) || (chan_sig == SIG_SS7))
09264             tmp->inservice = 0;
09265          else /* We default to in service on protocols that don't have a reset */
09266             tmp->inservice = 1;
09267       }
09268    }
09269    if (tmp && !here) {
09270       /* nothing on the iflist */
09271       if (!*wlist) {
09272          *wlist = tmp;
09273          tmp->prev = NULL;
09274          tmp->next = NULL;
09275          *wend = tmp;
09276       } else {
09277          /* at least one member on the iflist */
09278          struct dahdi_pvt *working = *wlist;
09279 
09280          /* check if we maybe have to put it on the begining */
09281          if (working->channel > tmp->channel) {
09282             tmp->next = *wlist;
09283             tmp->prev = NULL;
09284             (*wlist)->prev = tmp;
09285             *wlist = tmp;
09286          } else {
09287          /* go through all the members and put the member in the right place */
09288             while (working) {
09289                /* in the middle */
09290                if (working->next) {
09291                   if (working->channel < tmp->channel && working->next->channel > tmp->channel) {
09292                      tmp->next = working->next;
09293                      tmp->prev = working;
09294                      working->next->prev = tmp;
09295                      working->next = tmp;
09296                      break;
09297                   }
09298                } else {
09299                /* the last */
09300                   if (working->channel < tmp->channel) {
09301                      working->next = tmp;
09302                      tmp->next = NULL;
09303                      tmp->prev = working;
09304                      *wend = tmp;
09305                      break;
09306                   }
09307                }
09308                working = working->next;
09309             }
09310          }
09311       }
09312    }
09313    return tmp;
09314 }
09315 
09316 static inline int available(struct dahdi_pvt *p, int channelmatch, ast_group_t groupmatch, int *busy, int *channelmatched, int *groupmatched)
09317 {
09318    int res;
09319    struct dahdi_params par;
09320 
09321    /* First, check group matching */
09322    if (groupmatch) {
09323       if ((p->group & groupmatch) != groupmatch)
09324          return 0;
09325       *groupmatched = 1;
09326    }
09327    /* Check to see if we have a channel match */
09328    if (channelmatch != -1) {
09329       if (p->channel != channelmatch)
09330          return 0;
09331       *channelmatched = 1;
09332    }
09333    /* We're at least busy at this point */
09334    if (busy) {
09335       if ((p->sig == SIG_FXOKS) || (p->sig == SIG_FXOLS) || (p->sig == SIG_FXOGS))
09336          *busy = 1;
09337    }
09338    /* If do not disturb, definitely not */
09339    if (p->dnd)
09340       return 0;
09341    /* If guard time, definitely not */
09342    if (p->guardtime && (time(NULL) < p->guardtime)) 
09343       return 0;
09344 
09345    if (p->locallyblocked || p->remotelyblocked)
09346       return 0;
09347       
09348    /* If no owner definitely available */
09349    if (!p->owner) {
09350 #ifdef HAVE_PRI
09351       /* Trust PRI */
09352       if (p->pri) {
09353          if (p->resetting || p->call)
09354             return 0;
09355          else
09356             return 1;
09357       }
09358 #endif
09359 #ifdef HAVE_SS7
09360       /* Trust SS7 */
09361       if (p->ss7) {
09362          if (p->ss7call)
09363             return 0;
09364          else
09365             return 1;
09366       }
09367 #endif
09368       if (!(p->radio || (p->oprmode < 0)))
09369       {
09370          if (!p->sig || (p->sig == SIG_FXSLS))
09371             return 1;
09372          /* Check hook state */
09373          if (p->subs[SUB_REAL].dfd > -1) {
09374             memset(&par, 0, sizeof(par));
09375             res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
09376          } else {
09377             /* Assume not off hook on CVRS */
09378             res = 0;
09379             par.rxisoffhook = 0;
09380          }
09381          if (res) {
09382             ast_log(LOG_WARNING, "Unable to check hook state on channel %d: %s\n", p->channel, strerror(errno));
09383          } else if ((p->sig == SIG_FXSKS) || (p->sig == SIG_FXSGS)) {
09384             /* When "onhook" that means no battery on the line, and thus
09385               it is out of service..., if it's on a TDM card... If it's a channel
09386               bank, there is no telling... */
09387             if (par.rxbits > -1)
09388                return 1;
09389             if (par.rxisoffhook)
09390                return 1;
09391             else
09392                return 0;
09393          } else if (par.rxisoffhook) {
09394             ast_debug(1, "Channel %d off hook, can't use\n", p->channel);
09395             /* Not available when the other end is off hook */
09396 #ifdef DAHDI_CHECK_HOOKSTATE
09397             return 0;
09398 #else
09399             return 1;
09400 #endif
09401          }
09402       }
09403       return 1;
09404    }
09405 
09406    /* If it's not an FXO, forget about call wait */
09407    if ((p->sig != SIG_FXOKS) && (p->sig != SIG_FXOLS) && (p->sig != SIG_FXOGS)) 
09408       return 0;
09409 
09410    if (!p->callwaiting) {
09411       /* If they don't have call waiting enabled, then for sure they're unavailable at this point */
09412       return 0;
09413    }
09414 
09415    if (p->subs[SUB_CALLWAIT].dfd > -1) {
09416       /* If there is already a call waiting call, then we can't take a second one */
09417       return 0;
09418    }
09419    
09420    if ((p->owner->_state != AST_STATE_UP) &&
09421        ((p->owner->_state != AST_STATE_RINGING) || p->outgoing)) {
09422       /* If the current call is not up, then don't allow the call */
09423       return 0;
09424    }
09425    if ((p->subs[SUB_THREEWAY].owner) && (!p->subs[SUB_THREEWAY].inthreeway)) {
09426       /* Can't take a call wait when the three way calling hasn't been merged yet. */
09427       return 0;
09428    }
09429    /* We're cool */
09430    return 1;
09431 }
09432 
09433 static struct dahdi_pvt *chandup(struct dahdi_pvt *src)
09434 {
09435    struct dahdi_pvt *p;
09436    struct dahdi_bufferinfo bi;
09437    int res;
09438    
09439    if ((p = ast_malloc(sizeof(*p)))) {
09440       memcpy(p, src, sizeof(struct dahdi_pvt));
09441       ast_mutex_init(&p->lock);
09442       p->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
09443       /* Allocate a dahdi structure */
09444       if (p->subs[SUB_REAL].dfd < 0) {
09445          ast_log(LOG_ERROR, "Unable to dup channel: %s\n",  strerror(errno));
09446          destroy_dahdi_pvt(&p);
09447          return NULL;
09448       }
09449       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
09450       if (!res) {
09451          bi.txbufpolicy = src->buf_policy;
09452          bi.rxbufpolicy = src->buf_policy;
09453          bi.numbufs = src->buf_no;
09454          res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
09455          if (res < 0) {
09456             ast_log(LOG_WARNING, "Unable to set buffer policy on dup channel: %s\n", strerror(errno));
09457          }
09458       } else
09459          ast_log(LOG_WARNING, "Unable to check buffer policy on dup channel: %s\n", strerror(errno));
09460    }
09461    p->destroy = 1;
09462    p->next = iflist;
09463    p->prev = NULL;
09464    iflist = p;
09465    if (iflist->next)
09466       iflist->next->prev = p;
09467    return p;
09468 }
09469    
09470 
09471 #ifdef HAVE_PRI
09472 static int pri_find_empty_chan(struct dahdi_pri *pri, int backwards)
09473 {
09474    int x;
09475    if (backwards)
09476       x = pri->numchans;
09477    else
09478       x = 0;
09479    for (;;) {
09480       if (backwards && (x < 0))
09481          break;
09482       if (!backwards && (x >= pri->numchans))
09483          break;
09484       if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner) {
09485          ast_debug(1, "Found empty available channel %d/%d\n", 
09486             pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
09487          return x;
09488       }
09489       if (backwards)
09490          x--;
09491       else
09492          x++;
09493    }
09494    return -1;
09495 }
09496 #endif
09497 
09498 static struct ast_channel *dahdi_request(const char *type, int format, void *data, int *cause)
09499 {
09500    ast_group_t groupmatch = 0;
09501    int channelmatch = -1;
09502    int roundrobin = 0;
09503    int callwait = 0;
09504    int busy = 0;
09505    struct dahdi_pvt *p;
09506    struct ast_channel *tmp = NULL;
09507    char *dest=NULL;
09508    int x;
09509    char *s;
09510    char opt=0;
09511    int res=0, y=0;
09512    int backwards = 0;
09513 #ifdef HAVE_PRI
09514    int crv;
09515    int bearer = -1;
09516    int trunkgroup;
09517    struct dahdi_pri *pri=NULL;
09518 #endif   
09519    struct dahdi_pvt *exitpvt, *start, *end;
09520    ast_mutex_t *lock;
09521    int channelmatched = 0;
09522    int groupmatched = 0;
09523    
09524    /*
09525     * data is ---v
09526     * Dial(DAHDI/pseudo[/extension])
09527     * Dial(DAHDI/<channel#>[c|r<cadance#>|d][/extension])
09528     * Dial(DAHDI/<trunk_group#>:<crv#>[c|r<cadance#>|d][/extension])
09529     * Dial(DAHDI/(g|G|r|R)<group#(0-63)>[c|r<cadance#>|d][/extension])
09530     *
09531     * g - channel group allocation search forward
09532     * G - channel group allocation search backward
09533     * r - channel group allocation round robin search forward
09534     * R - channel group allocation round robin search backward
09535     *
09536     * c - Wait for DTMF digit to confirm answer
09537     * r<cadance#> - Set distintive ring cadance number
09538     * d - Force bearer capability for ISDN/SS7 call to digital.
09539     */
09540 
09541    /* Assume we're locking the iflock */
09542    lock = &iflock;
09543    start = iflist;
09544    end = ifend;
09545    if (data) {
09546       dest = ast_strdupa((char *)data);
09547    } else {
09548       ast_log(LOG_WARNING, "Channel requested with no data\n");
09549       return NULL;
09550    }
09551    if (toupper(dest[0]) == 'G' || toupper(dest[0])=='R') {
09552       /* Retrieve the group number */
09553       char *stringp;
09554 
09555       stringp = dest + 1;
09556       s = strsep(&stringp, "/");
09557       if ((res = sscanf(s, "%30d%1c%30d", &x, &opt, &y)) < 1) {
09558          ast_log(LOG_WARNING, "Unable to determine group for data %s\n", (char *)data);
09559          return NULL;
09560       }
09561       groupmatch = ((ast_group_t) 1 << x);
09562       if (toupper(dest[0]) == 'G') {
09563          if (dest[0] == 'G') {
09564             backwards = 1;
09565             p = ifend;
09566          } else
09567             p = iflist;
09568       } else {
09569          if (dest[0] == 'R') {
09570             backwards = 1;
09571             p = round_robin[x]?round_robin[x]->prev:ifend;
09572             if (!p)
09573                p = ifend;
09574          } else {
09575             p = round_robin[x]?round_robin[x]->next:iflist;
09576             if (!p)
09577                p = iflist;
09578          }
09579          roundrobin = 1;
09580       }
09581    } else {
09582       char *stringp;
09583 
09584       stringp = dest;
09585       s = strsep(&stringp, "/");
09586       p = iflist;
09587       if (!strcasecmp(s, "pseudo")) {
09588          /* Special case for pseudo */
09589          x = CHAN_PSEUDO;
09590          channelmatch = x;
09591       } 
09592 #ifdef HAVE_PRI
09593       else if ((res = sscanf(s, "%30d:%30d%1c%30d", &trunkgroup, &crv, &opt, &y)) > 1) {
09594          if ((trunkgroup < 1) || (crv < 1)) {
09595             ast_log(LOG_WARNING, "Unable to determine trunk group and CRV for data %s\n", (char *)data);
09596             return NULL;
09597          }
09598          res--;
09599          for (x = 0; x < NUM_SPANS; x++) {
09600             if (pris[x].trunkgroup == trunkgroup) {
09601                pri = pris + x;
09602                lock = &pri->lock;
09603                start = pri->crvs;
09604                end = pri->crvend;
09605                break;
09606             }
09607          }
09608          if (!pri) {
09609             ast_log(LOG_WARNING, "Unable to find trunk group %d\n", trunkgroup);
09610             return NULL;
09611          }
09612          channelmatch = crv;
09613          p = pris[x].crvs;
09614       }
09615 #endif
09616       else if ((res = sscanf(s, "%30d%1c%30d", &x, &opt, &y)) < 1) {
09617          ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", (char *)data);
09618          return NULL;
09619       } else {
09620          channelmatch = x;
09621       }
09622    }
09623    /* Search for an unowned channel */
09624    ast_mutex_lock(lock);
09625    exitpvt = p;
09626    while (p && !tmp) {
09627       if (roundrobin)
09628          round_robin[x] = p;
09629 #if 0
09630       ast_verbose("name = %s, %d, %d, %llu\n",p->owner ? p->owner->name : "<none>", p->channel, channelmatch, groupmatch);
09631 #endif
09632 
09633       if (p && available(p, channelmatch, groupmatch, &busy, &channelmatched, &groupmatched)) {
09634          ast_debug(1, "Using channel %d\n", p->channel);
09635          if (p->inalarm) 
09636             goto next;
09637 
09638          callwait = (p->owner != NULL);
09639 #ifdef HAVE_PRI
09640          if (pri && (p->subs[SUB_REAL].dfd < 0)) {
09641             if (p->sig != SIG_FXSKS) {
09642                /* Gotta find an actual channel to use for this
09643                   CRV if this isn't a callwait */
09644                bearer = pri_find_empty_chan(pri, 0);
09645                if (bearer < 0) {
09646                   ast_log(LOG_NOTICE, "Out of bearer channels on span %d for call to CRV %d:%d\n", pri->span, trunkgroup, crv);
09647                   p = NULL;
09648                   break;
09649                }
09650                pri_assign_bearer(p, pri, pri->pvts[bearer]);
09651             } else {
09652                if (alloc_sub(p, 0)) {
09653                   ast_log(LOG_NOTICE, "Failed to allocate place holder pseudo channel!\n");
09654                   p = NULL;
09655                   break;
09656                } else
09657                   ast_debug(1, "Allocated placeholder pseudo channel\n");
09658 
09659                p->pri = pri;
09660             }
09661          }
09662 #endif         
09663          if (p->channel == CHAN_PSEUDO) {
09664             p = chandup(p);
09665             if (!p) {
09666                break;
09667             }
09668          }
09669          if (p->owner) {
09670             if (alloc_sub(p, SUB_CALLWAIT)) {
09671                p = NULL;
09672                break;
09673             }
09674          }
09675          p->outgoing = 1;
09676          tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, 0);
09677          if (!tmp) {
09678             p->outgoing = 0;
09679          }
09680 #ifdef HAVE_PRI
09681          if (p->bearer) {
09682             /* Log owner to bearer channel, too */
09683             p->bearer->owner = tmp;
09684          }
09685 #endif         
09686          /* Make special notes */
09687          if (res > 1) {
09688             if (opt == 'c') {
09689                /* Confirm answer */
09690                p->confirmanswer = 1;
09691             } else if (opt == 'r') {
09692                /* Distinctive ring */
09693                if (res < 3)
09694                   ast_log(LOG_WARNING, "Distinctive ring missing identifier in '%s'\n", (char *)data);
09695                else
09696                   p->distinctivering = y;
09697             } else if (opt == 'd') {
09698                /* If this is an ISDN call, make it digital */
09699                p->digital = 1;
09700                if (tmp)
09701                   tmp->transfercapability = AST_TRANS_CAP_DIGITAL;
09702             } else {
09703                ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", opt, (char *)data);
09704             }
09705          }
09706          /* Note if the call is a call waiting call */
09707          if (tmp && callwait)
09708             tmp->cdrflags |= AST_CDR_CALLWAIT;
09709          break;
09710       }
09711 next:
09712       if (backwards) {
09713          p = p->prev;
09714          if (!p)
09715             p = end;
09716       } else {
09717          p = p->next;
09718          if (!p)
09719             p = start;
09720       }
09721       /* stop when you roll to the one that we started from */
09722       if (p == exitpvt)
09723          break;
09724    }
09725    ast_mutex_unlock(lock);
09726    restart_monitor();
09727    if (callwait)
09728       *cause = AST_CAUSE_BUSY;
09729    else if (!tmp) {
09730       if (channelmatched) {
09731          if (busy)
09732             *cause = AST_CAUSE_BUSY;
09733       } else if (groupmatched) {
09734          *cause = AST_CAUSE_CONGESTION;
09735       }
09736    }
09737       
09738    return tmp;
09739 }
09740 
09741 #if defined(HAVE_PRI) || defined(HAVE_SS7)
09742 static int dahdi_setlaw(int dfd, int law)
09743 {
09744    return ioctl(dfd, DAHDI_SETLAW, &law);
09745 }
09746 #endif
09747 
09748 #ifdef HAVE_SS7
09749 
09750 static int ss7_find_cic(struct dahdi_ss7 *linkset, int cic, unsigned int dpc)
09751 {
09752    int i;
09753    int winner = -1;
09754    for (i = 0; i < linkset->numchans; i++) {
09755       if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && linkset->pvts[i]->cic == cic)) {
09756          winner = i;
09757          break;
09758       }
09759    }
09760    return winner;
09761 }
09762 
09763 static void ss7_handle_cqm(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc)
09764 {
09765    unsigned char status[32];
09766    struct dahdi_pvt *p = NULL;
09767    int i, offset;
09768 
09769    for (i = 0; i < linkset->numchans; i++) {
09770       if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
09771          p = linkset->pvts[i];
09772          offset = p->cic - startcic;
09773          status[offset] = 0;
09774          if (p->locallyblocked)
09775             status[offset] |= (1 << 0) | (1 << 4);
09776          if (p->remotelyblocked)
09777             status[offset] |= (1 << 1) | (1 << 5);
09778          if (p->ss7call) {
09779             if (p->outgoing)
09780                status[offset] |= (1 << 3);
09781             else
09782                status[offset] |= (1 << 2);
09783          } else
09784             status[offset] |= 0x3 << 2;
09785       }
09786    }
09787 
09788    if (p)
09789       isup_cqr(linkset->ss7, startcic, endcic, dpc, status);
09790    else
09791       ast_log(LOG_WARNING, "Could not find any equipped circuits within CQM CICs\n");
09792    
09793 }
09794 
09795 static inline void ss7_block_cics(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc, unsigned char state[], int block)
09796 {
09797    int i;
09798 
09799    for (i = 0; i < linkset->numchans; i++) {
09800       if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
09801          if (state) {
09802             if (state[i])
09803                linkset->pvts[i]->remotelyblocked = block;
09804          } else
09805             linkset->pvts[i]->remotelyblocked = block;
09806       }
09807    }
09808 }
09809 
09810 static void ss7_inservice(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc)
09811 {
09812    int i;
09813 
09814    for (i = 0; i < linkset->numchans; i++) {
09815       if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic))))
09816          linkset->pvts[i]->inservice = 1;
09817    }
09818 }
09819 
09820 static void ss7_reset_linkset(struct dahdi_ss7 *linkset)
09821 {
09822    int i, startcic = -1, endcic, dpc;
09823 
09824    if (linkset->numchans <= 0)
09825       return;
09826 
09827    startcic = linkset->pvts[0]->cic;
09828    /* DB: CIC's DPC fix */
09829    dpc = linkset->pvts[0]->dpc;
09830 
09831    for (i = 0; i < linkset->numchans; i++) {
09832       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)) {
09833          continue;
09834       } else {
09835          endcic = linkset->pvts[i]->cic;
09836          ast_verbose("Resetting CICs %d to %d\n", startcic, endcic);
09837          isup_grs(linkset->ss7, startcic, endcic, dpc);
09838 
09839          /* DB: CIC's DPC fix */
09840          if (linkset->pvts[i+1]) {
09841             startcic = linkset->pvts[i+1]->cic;
09842             dpc = linkset->pvts[i+1]->dpc;
09843          }
09844       }
09845    }
09846 }
09847 
09848 static void dahdi_loopback(struct dahdi_pvt *p, int enable)
09849 {
09850    if (p->loopedback != enable) {
09851       if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_LOOPBACK, &enable)) {
09852          ast_log(LOG_WARNING, "Unable to set loopback on channel %d: %s\n", p->channel, strerror(errno));
09853          return;
09854       }
09855       p->loopedback = enable;
09856    }
09857 }
09858 
09859 /* XXX: This function is assumed to be called with the private channel lock and linkset lock held */
09860 static void ss7_start_call(struct dahdi_pvt *p, struct dahdi_ss7 *linkset)
09861 {
09862    struct ss7 *ss7 = linkset->ss7;
09863    int res;
09864    int law = 1;
09865    struct ast_channel *c;
09866    char tmp[256];
09867 
09868    if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law) == -1)
09869       ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, law, strerror(errno));
09870    
09871    if (linkset->type == SS7_ITU)
09872       law = DAHDI_LAW_ALAW;
09873    else
09874       law = DAHDI_LAW_MULAW;
09875 
09876    res = dahdi_setlaw(p->subs[SUB_REAL].dfd, law);
09877    if (res < 0) 
09878       ast_log(LOG_WARNING, "Unable to set law on channel %d\n", p->channel);
09879    
09880    if (!(linkset->flags & LINKSET_FLAG_EXPLICITACM)) {
09881       p->proceeding = 1;
09882       isup_acm(ss7, p->ss7call);
09883    }
09884 
09885    ast_mutex_unlock(&linkset->lock);
09886    c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, law, 0);
09887 
09888    if (!c) {
09889       ast_log(LOG_WARNING, "Unable to start PBX on CIC %d\n", p->cic);
09890       /* Holding this lock is assumed entering the function */
09891       ast_mutex_lock(&linkset->lock);
09892       return;
09893    } else
09894       ast_verb(3, "Accepting call to '%s' on CIC %d\n", p->exten, p->cic);
09895 
09896    dahdi_enable_ec(p);
09897 
09898    /* We only reference these variables in the context of the ss7_linkset function
09899     * when receiving either and IAM or a COT message.  Since they are only accessed
09900     * from this context, we should be safe to unlock around them */
09901 
09902    ast_mutex_unlock(&p->lock);
09903 
09904    if (!ast_strlen_zero(p->charge_number)) {
09905       pbx_builtin_setvar_helper(c, "SS7_CHARGE_NUMBER", p->charge_number);
09906       /* Clear this after we set it */
09907       p->charge_number[0] = 0;
09908    }
09909    if (!ast_strlen_zero(p->gen_add_number)) {
09910       pbx_builtin_setvar_helper(c, "SS7_GENERIC_ADDRESS", p->gen_add_number);
09911       /* Clear this after we set it */
09912       p->gen_add_number[0] = 0;
09913    }
09914    if (!ast_strlen_zero(p->jip_number)) {
09915       pbx_builtin_setvar_helper(c, "SS7_JIP", p->jip_number);
09916       /* Clear this after we set it */
09917       p->jip_number[0] = 0;
09918    }
09919    if (!ast_strlen_zero(p->gen_dig_number)) {
09920       pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGITS", p->gen_dig_number);
09921       /* Clear this after we set it */
09922       p->gen_dig_number[0] = 0;
09923    }
09924    if (!ast_strlen_zero(p->orig_called_num)) {
09925       pbx_builtin_setvar_helper(c, "SS7_ORIG_CALLED_NUM", p->orig_called_num);
09926       /* Clear this after we set it */
09927       p->orig_called_num[0] = 0;
09928    }
09929 
09930    snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_type);
09931    pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGTYPE", tmp);
09932    /* Clear this after we set it */
09933    p->gen_dig_type = 0;
09934 
09935    snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_scheme);
09936    pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGSCHEME", tmp);
09937    /* Clear this after we set it */
09938    p->gen_dig_scheme = 0;
09939 
09940    if (!ast_strlen_zero(p->lspi_ident)) {
09941       pbx_builtin_setvar_helper(c, "SS7_LSPI_IDENT", p->lspi_ident);
09942       /* Clear this after we set it */
09943       p->lspi_ident[0] = 0;
09944    }
09945 
09946    snprintf(tmp, sizeof(tmp), "%d", p->call_ref_ident);
09947    pbx_builtin_setvar_helper(c, "SS7_CALLREF_IDENT", tmp);
09948    /* Clear this after we set it */
09949    p->call_ref_ident = 0;
09950 
09951    snprintf(tmp, sizeof(tmp), "%d", p->call_ref_pc);
09952    pbx_builtin_setvar_helper(c, "SS7_CALLREF_PC", tmp);
09953    /* Clear this after we set it */
09954    p->call_ref_pc = 0;
09955 
09956    snprintf(tmp, sizeof(tmp), "%d", p->calling_party_cat);
09957    pbx_builtin_setvar_helper(c, "SS7_CALLING_PARTY_CATEGORY", tmp);
09958    /* Clear this after we set it */
09959    p->calling_party_cat = 0;
09960 
09961    if (!ast_strlen_zero(p->redirecting_num)) {
09962       pbx_builtin_setvar_helper(c, "SS7_REDIRECTING_NUMBER", p->redirecting_num);
09963       /* Clear this after we set it */
09964       p->redirecting_num[0] = 0;
09965    }
09966    if (!ast_strlen_zero(p->generic_name)) {
09967       pbx_builtin_setvar_helper(c, "SS7_GENERIC_NAME", p->generic_name);
09968       /* Clear this after we set it */
09969       p->generic_name[0] = 0;
09970    }
09971 
09972    ast_mutex_lock(&p->lock);
09973    ast_mutex_lock(&linkset->lock);
09974 }
09975 
09976 static void ss7_apply_plan_to_number(char *buf, size_t size, const struct dahdi_ss7 *ss7, const char *number, const unsigned nai)
09977 {
09978    if (ast_strlen_zero(number)) { /* make sure a number exists so prefix isn't placed on an empty string */
09979       if (size) {
09980          *buf = '\0';
09981       }
09982       return;
09983    }
09984    switch (nai) {
09985    case SS7_NAI_INTERNATIONAL:
09986       snprintf(buf, size, "%s%s", ss7->internationalprefix, number);
09987       break;
09988    case SS7_NAI_NATIONAL:
09989       snprintf(buf, size, "%s%s", ss7->nationalprefix, number);
09990       break;
09991    case SS7_NAI_SUBSCRIBER:
09992       snprintf(buf, size, "%s%s", ss7->subscriberprefix, number);
09993       break;
09994    case SS7_NAI_UNKNOWN:
09995       snprintf(buf, size, "%s%s", ss7->unknownprefix, number);
09996       break;
09997    default:
09998       snprintf(buf, size, "%s", number);
09999       break;
10000    }
10001 }
10002 static int ss7_pres_scr2cid_pres(char presentation_ind, char screening_ind)
10003 {
10004     return ((presentation_ind & 0x3) << 5) | (screening_ind & 0x3);
10005 }
10006 
10007 static void *ss7_linkset(void *data)
10008 {
10009    int res, i;
10010    struct timeval *next = NULL, tv;
10011    struct dahdi_ss7 *linkset = (struct dahdi_ss7 *) data;
10012    struct ss7 *ss7 = linkset->ss7;
10013    ss7_event *e = NULL;
10014    struct dahdi_pvt *p;
10015    int chanpos;
10016    struct pollfd pollers[NUM_DCHANS];
10017    int cic;
10018    unsigned int dpc;
10019    int nextms = 0;
10020 
10021    ss7_start(ss7);
10022 
10023    while(1) {
10024       ast_mutex_lock(&linkset->lock);
10025       if ((next = ss7_schedule_next(ss7))) {
10026          tv = ast_tvnow();
10027          tv.tv_sec = next->tv_sec - tv.tv_sec;
10028          tv.tv_usec = next->tv_usec - tv.tv_usec;
10029          if (tv.tv_usec < 0) {
10030             tv.tv_usec += 1000000;
10031             tv.tv_sec -= 1;
10032          }
10033          if (tv.tv_sec < 0) {
10034             tv.tv_sec = 0;
10035             tv.tv_usec = 0;
10036          }
10037          nextms = tv.tv_sec * 1000;
10038          nextms += tv.tv_usec / 1000;
10039       }
10040       ast_mutex_unlock(&linkset->lock);
10041 
10042       for (i = 0; i < linkset->numsigchans; i++) {
10043          pollers[i].fd = linkset->fds[i];
10044          pollers[i].events = ss7_pollflags(ss7, linkset->fds[i]);
10045          pollers[i].revents = 0;
10046       }
10047 
10048       res = poll(pollers, linkset->numsigchans, nextms);
10049       if ((res < 0) && (errno != EINTR)) {
10050          ast_log(LOG_ERROR, "poll(%s)\n", strerror(errno));
10051       } else if (!res) {
10052          ast_mutex_lock(&linkset->lock);
10053          ss7_schedule_run(ss7);
10054          ast_mutex_unlock(&linkset->lock);
10055          continue;
10056       }
10057 
10058       ast_mutex_lock(&linkset->lock);
10059       for (i = 0; i < linkset->numsigchans; i++) {
10060          if (pollers[i].revents & POLLPRI) {
10061             int x;
10062             if (ioctl(pollers[i].fd, DAHDI_GETEVENT, &x)) {
10063                ast_log(LOG_ERROR, "Error in exception retrieval!\n");
10064             }
10065             switch (x) {
10066             case DAHDI_EVENT_OVERRUN:
10067                ast_debug(1, "Overrun detected!\n");
10068                break;
10069             case DAHDI_EVENT_BADFCS:
10070                ast_debug(1, "Bad FCS\n");
10071                break;
10072             case DAHDI_EVENT_ABORT:
10073                ast_debug(1, "HDLC Abort\n");
10074                break;
10075             case DAHDI_EVENT_ALARM:
10076                ast_log(LOG_ERROR, "Alarm on link!\n");
10077                linkset->linkstate[i] |= (LINKSTATE_DOWN | LINKSTATE_INALARM);
10078                linkset->linkstate[i] &= ~LINKSTATE_UP;
10079                ss7_link_alarm(ss7, pollers[i].fd);
10080                break;
10081             case DAHDI_EVENT_NOALARM:
10082                ast_log(LOG_ERROR, "Alarm cleared on link\n");
10083                linkset->linkstate[i] &= ~(LINKSTATE_INALARM | LINKSTATE_DOWN);
10084                linkset->linkstate[i] |= LINKSTATE_STARTING;
10085                ss7_link_noalarm(ss7, pollers[i].fd);
10086                break;
10087             default:
10088                ast_log(LOG_ERROR, "Got exception %d!\n", x);
10089                break;
10090             }
10091          }
10092 
10093          if (pollers[i].revents & POLLIN) {
10094             ast_mutex_lock(&linkset->lock);
10095             res = ss7_read(ss7, pollers[i].fd);
10096             ast_mutex_unlock(&linkset->lock);
10097          }
10098 
10099          if (pollers[i].revents & POLLOUT) {
10100             ast_mutex_lock(&linkset->lock);
10101             res = ss7_write(ss7, pollers[i].fd);
10102             ast_mutex_unlock(&linkset->lock);
10103             if (res < 0) {
10104                ast_debug(1, "Error in write %s\n", strerror(errno));
10105             }
10106          }
10107       }
10108 
10109       while ((e = ss7_check_event(ss7))) {
10110          switch (e->e) {
10111          case SS7_EVENT_UP:
10112             if (linkset->state != LINKSET_STATE_UP) {
10113                ast_verbose("--- SS7 Up ---\n");
10114                ss7_reset_linkset(linkset);
10115             }
10116             linkset->state = LINKSET_STATE_UP;
10117             break;
10118          case SS7_EVENT_DOWN:
10119             ast_verbose("--- SS7 Down ---\n");
10120             linkset->state = LINKSET_STATE_DOWN;
10121             for (i = 0; i < linkset->numchans; i++) {
10122                struct dahdi_pvt *p = linkset->pvts[i];
10123                if (p)
10124                   p->inalarm = 1;
10125             }
10126             break;
10127          case MTP2_LINK_UP:
10128             ast_verbose("MTP2 link up (SLC %d)\n", e->gen.data);
10129             break;
10130          case MTP2_LINK_DOWN:
10131             ast_log(LOG_WARNING, "MTP2 link down (SLC %d)\n", e->gen.data);
10132             break;
10133          case ISUP_EVENT_CPG:
10134             chanpos = ss7_find_cic(linkset, e->cpg.cic, e->cpg.opc);
10135             if (chanpos < 0) {
10136                ast_log(LOG_WARNING, "CPG on unconfigured CIC %d\n", e->cpg.cic);
10137                break;
10138             }
10139             p = linkset->pvts[chanpos];
10140             ast_mutex_lock(&p->lock);
10141             switch (e->cpg.event) {
10142             case CPG_EVENT_ALERTING:
10143                p->alerting = 1;
10144                p->subs[SUB_REAL].needringing = 1;
10145                break;
10146             case CPG_EVENT_PROGRESS:
10147             case CPG_EVENT_INBANDINFO:
10148                {
10149                   struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, };
10150                   ast_debug(1, "Queuing frame PROGRESS on CIC %d\n", p->cic);
10151                   dahdi_queue_frame(p, &f, linkset);
10152                   p->progress = 1;
10153                   p->dialing = 0;
10154                   if (p->dsp && p->dsp_features) {
10155                           ast_dsp_set_features(p->dsp, p->dsp_features);
10156                           p->dsp_features = 0;
10157                   }
10158                }
10159                break;
10160             default:
10161                ast_debug(1, "Do not handle CPG with event type 0x%x\n", e->cpg.event);
10162             }
10163 
10164             ast_mutex_unlock(&p->lock);
10165             break;
10166          case ISUP_EVENT_RSC:
10167             ast_verbose("Resetting CIC %d\n", e->rsc.cic);
10168             chanpos = ss7_find_cic(linkset, e->rsc.cic, e->rsc.opc);
10169             if (chanpos < 0) {
10170                ast_log(LOG_WARNING, "RSC on unconfigured CIC %d\n", e->rsc.cic);
10171                break;
10172             }
10173             p = linkset->pvts[chanpos];
10174             ast_mutex_lock(&p->lock);
10175             p->inservice = 1;
10176             p->remotelyblocked = 0;
10177             dpc = p->dpc;
10178             isup_set_call_dpc(e->rsc.call, dpc);
10179             if (p->ss7call)
10180                p->ss7call = NULL;
10181             if (p->owner)
10182                p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
10183             ast_mutex_unlock(&p->lock);
10184             isup_rlc(ss7, e->rsc.call);
10185             break;
10186          case ISUP_EVENT_GRS:
10187             ast_debug(1, "Got Reset for CICs %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic);
10188             chanpos = ss7_find_cic(linkset, e->grs.startcic, e->grs.opc);
10189             if (chanpos < 0) {
10190                ast_log(LOG_WARNING, "GRS on unconfigured CIC %d\n", e->grs.startcic);
10191                break;
10192             }
10193             p = linkset->pvts[chanpos];
10194             isup_gra(ss7, e->grs.startcic, e->grs.endcic, e->grs.opc);
10195             ss7_block_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc, NULL, 0);
10196             break;
10197          case ISUP_EVENT_CQM:
10198             ast_debug(1, "Got Circuit group query message from CICs %d to %d\n", e->cqm.startcic, e->cqm.endcic);
10199             ss7_handle_cqm(linkset, e->cqm.startcic, e->cqm.endcic, e->cqm.opc);
10200             break;
10201          case ISUP_EVENT_GRA:
10202             ast_verbose("Got reset acknowledgement from CIC %d to %d.\n", e->gra.startcic, e->gra.endcic);
10203             ss7_inservice(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc);
10204             ss7_block_cics(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc, e->gra.status, 1);
10205             break;
10206          case ISUP_EVENT_IAM:
10207             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);
10208             chanpos = ss7_find_cic(linkset, e->iam.cic, e->iam.opc);
10209             if (chanpos < 0) {
10210                ast_log(LOG_WARNING, "IAM on unconfigured CIC %d\n", e->iam.cic);
10211                isup_rel(ss7, e->iam.call, -1);
10212                break;
10213             }
10214             p = linkset->pvts[chanpos];
10215             ast_mutex_lock(&p->lock);
10216             if (p->owner) {
10217                if (p->ss7call == e->iam.call) {
10218                   ast_mutex_unlock(&p->lock);
10219                   ast_log(LOG_WARNING, "Duplicate IAM requested on CIC %d\n", e->iam.cic);
10220                   break;
10221                } else {
10222                   ast_mutex_unlock(&p->lock);
10223                   ast_log(LOG_WARNING, "Ring requested on CIC %d already in use!\n", e->iam.cic);
10224                   break;
10225                }
10226             }
10227 
10228             dpc = p->dpc;
10229             p->ss7call = e->iam.call;
10230             isup_set_call_dpc(p->ss7call, dpc);
10231 
10232             if ((p->use_callerid) && (!ast_strlen_zero(e->iam.calling_party_num))) {
10233                ss7_apply_plan_to_number(p->cid_num, sizeof(p->cid_num), linkset, e->iam.calling_party_num, e->iam.calling_nai);
10234                p->callingpres = ss7_pres_scr2cid_pres(e->iam.presentation_ind, e->iam.screening_ind);
10235             } else
10236                p->cid_num[0] = 0;
10237 
10238             if (p->immediate) {
10239                p->exten[0] = 's';
10240                p->exten[1] = '\0';
10241             } else if (!ast_strlen_zero(e->iam.called_party_num)) {
10242                char *st;
10243                ss7_apply_plan_to_number(p->exten, sizeof(p->exten), linkset, e->iam.called_party_num, e->iam.called_nai);
10244                st = strchr(p->exten, '#');
10245                if (st)
10246                   *st = '\0';
10247                } else
10248                   p->exten[0] = '\0';
10249 
10250             p->cid_ani[0] = '\0';
10251             if ((p->use_callerid) && (!ast_strlen_zero(e->iam.generic_name)))
10252                ast_copy_string(p->cid_name, e->iam.generic_name, sizeof(p->cid_name));
10253             else
10254                p->cid_name[0] = '\0';
10255             
10256             p->cid_ani2 = e->iam.oli_ani2;
10257             p->cid_ton = 0;
10258             ast_copy_string(p->charge_number, e->iam.charge_number, sizeof(p->charge_number));
10259             ast_copy_string(p->gen_add_number, e->iam.gen_add_number, sizeof(p->gen_add_number));
10260             p->gen_add_type = e->iam.gen_add_type;
10261             p->gen_add_nai = e->iam.gen_add_nai;
10262             p->gen_add_pres_ind = e->iam.gen_add_pres_ind;
10263             p->gen_add_num_plan = e->iam.gen_add_num_plan;
10264             ast_copy_string(p->gen_dig_number, e->iam.gen_dig_number, sizeof(p->gen_dig_number));
10265             p->gen_dig_type = e->iam.gen_dig_type;
10266             p->gen_dig_scheme = e->iam.gen_dig_scheme;
10267             ast_copy_string(p->jip_number, e->iam.jip_number, sizeof(p->jip_number));
10268             ast_copy_string(p->orig_called_num, e->iam.orig_called_num, sizeof(p->orig_called_num));
10269             ast_copy_string(p->redirecting_num, e->iam.redirecting_num, sizeof(p->redirecting_num));
10270             ast_copy_string(p->generic_name, e->iam.generic_name, sizeof(p->generic_name));
10271             p->calling_party_cat = e->iam.calling_party_cat;
10272                
10273             /* Set DNID */
10274             if (!ast_strlen_zero(e->iam.called_party_num))
10275                ss7_apply_plan_to_number(p->dnid, sizeof(p->dnid), linkset, e->iam.called_party_num, e->iam.called_nai);
10276             
10277             if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
10278 
10279                if (e->iam.cot_check_required) {
10280                   dahdi_loopback(p, 1);
10281                } else
10282                   ss7_start_call(p, linkset);
10283             } else {
10284                ast_debug(1, "Call on CIC for unconfigured extension %s\n", p->exten);
10285                p->alreadyhungup = 1;
10286                isup_rel(ss7, e->iam.call, AST_CAUSE_UNALLOCATED);
10287             }
10288             ast_mutex_unlock(&p->lock);
10289             break;
10290          case ISUP_EVENT_COT:
10291             chanpos = ss7_find_cic(linkset, e->cot.cic, e->cot.opc);
10292             if (chanpos < 0) {
10293                ast_log(LOG_WARNING, "COT on unconfigured CIC %d\n", e->cot.cic);
10294                isup_rel(ss7, e->cot.call, -1);
10295                break;
10296             }
10297             p = linkset->pvts[chanpos];
10298 
10299             ast_mutex_lock(&p->lock);
10300 
10301             if (p->loopedback) {
10302                dahdi_loopback(p, 0);
10303                ss7_start_call(p, linkset);
10304             }
10305 
10306             ast_mutex_unlock(&p->lock);
10307 
10308             break;
10309          case ISUP_EVENT_CCR:
10310             ast_debug(1, "Got CCR request on CIC %d\n", e->ccr.cic);
10311             chanpos = ss7_find_cic(linkset, e->ccr.cic, e->ccr.opc);
10312             if (chanpos < 0) {
10313                ast_log(LOG_WARNING, "CCR on unconfigured CIC %d\n", e->ccr.cic);
10314                break;
10315             }
10316 
10317             p = linkset->pvts[chanpos];
10318 
10319             ast_mutex_lock(&p->lock);
10320             dahdi_loopback(p, 1);
10321             ast_mutex_unlock(&p->lock);
10322 
10323             isup_lpa(linkset->ss7, e->ccr.cic, p->dpc);
10324             break;
10325          case ISUP_EVENT_CVT:
10326             ast_debug(1, "Got CVT request on CIC %d\n", e->cvt.cic);
10327             chanpos = ss7_find_cic(linkset, e->cvt.cic, e->cvt.opc);
10328             if (chanpos < 0) {
10329                ast_log(LOG_WARNING, "CVT on unconfigured CIC %d\n", e->cvt.cic);
10330                break;
10331             }
10332             
10333             p = linkset->pvts[chanpos];
10334             
10335             ast_mutex_lock(&p->lock);
10336             dahdi_loopback(p, 1);
10337             ast_mutex_unlock(&p->lock);
10338             
10339             isup_cvr(linkset->ss7, e->cvt.cic, p->dpc);
10340             break;
10341          case ISUP_EVENT_REL:
10342             chanpos = ss7_find_cic(linkset, e->rel.cic, e->rel.opc);
10343             if (chanpos < 0) {
10344                ast_log(LOG_WARNING, "REL on unconfigured CIC %d\n", e->rel.cic);
10345                break;
10346             }
10347             p = linkset->pvts[chanpos];
10348             ast_mutex_lock(&p->lock);
10349             if (p->owner) {
10350                p->owner->hangupcause = e->rel.cause;
10351                p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
10352             } else if (!p->restartpending)
10353                ast_log(LOG_WARNING, "REL on channel (CIC %d) without owner!\n", p->cic);
10354 
10355             /* End the loopback if we have one */
10356             dahdi_loopback(p, 0);
10357 
10358             isup_rlc(ss7, e->rel.call);
10359             p->ss7call = NULL;
10360 
10361             ast_mutex_unlock(&p->lock);
10362             break;
10363          case ISUP_EVENT_ACM:
10364             chanpos = ss7_find_cic(linkset, e->acm.cic, e->acm.opc);
10365             if (chanpos < 0) {
10366                ast_log(LOG_WARNING, "ACM on unconfigured CIC %d\n", e->acm.cic);
10367                isup_rel(ss7, e->acm.call, -1);
10368                break;
10369             } else {
10370                struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
10371 
10372                p = linkset->pvts[chanpos];
10373 
10374                ast_debug(1, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
10375                
10376                if (e->acm.call_ref_ident > 0) {
10377                   p->rlt = 1; /* Setting it but not using it here*/
10378                }
10379 
10380                ast_mutex_lock(&p->lock);
10381                dahdi_queue_frame(p, &f, linkset);
10382                p->proceeding = 1;
10383                p->dialing = 0;
10384                /* Send alerting if subscriber is free */
10385                if (e->acm.called_party_status_ind == 1) {
10386                   p->alerting = 1;
10387                   p->subs[SUB_REAL].needringing = 1;
10388                }
10389                ast_mutex_unlock(&p->lock);
10390             }
10391             break;
10392          case ISUP_EVENT_CGB:
10393             chanpos = ss7_find_cic(linkset, e->cgb.startcic, e->cgb.opc);
10394             if (chanpos < 0) {
10395                ast_log(LOG_WARNING, "CGB on unconfigured CIC %d\n", e->cgb.startcic);
10396                break;
10397             }
10398             p = linkset->pvts[chanpos];
10399             ss7_block_cics(linkset, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, 1);
10400             isup_cgba(linkset->ss7, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, e->cgb.type);
10401             break;
10402          case ISUP_EVENT_CGU:
10403             chanpos = ss7_find_cic(linkset, e->cgu.startcic, e->cgu.opc);
10404             if (chanpos < 0) {
10405                ast_log(LOG_WARNING, "CGU on unconfigured CIC %d\n", e->cgu.startcic);
10406                break;
10407             }
10408             p = linkset->pvts[chanpos];
10409             ss7_block_cics(linkset, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, 0);
10410             isup_cgua(linkset->ss7, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, e->cgu.type);
10411             break;
10412          case ISUP_EVENT_UCIC:
10413             chanpos = ss7_find_cic(linkset, e->ucic.cic, e->ucic.opc);
10414             if (chanpos < 0) {
10415                ast_log(LOG_WARNING, "UCIC on unconfigured CIC %d\n", e->ucic.cic);
10416                break;
10417             }
10418             p = linkset->pvts[chanpos];
10419             ast_debug(1, "Unequiped Circuit Id Code on CIC %d\n", e->ucic.cic);
10420             ast_mutex_lock(&p->lock);
10421             p->remotelyblocked = 1;
10422             p->inservice = 0;
10423             ast_mutex_unlock(&p->lock);         //doesn't require a SS7 acknowledgement
10424             break;
10425          case ISUP_EVENT_BLO:
10426             chanpos = ss7_find_cic(linkset, e->blo.cic, e->blo.opc);
10427             if (chanpos < 0) {
10428                ast_log(LOG_WARNING, "BLO on unconfigured CIC %d\n", e->blo.cic);
10429                break;
10430             }
10431             p = linkset->pvts[chanpos];
10432             ast_debug(1, "Blocking CIC %d\n", e->blo.cic);
10433             ast_mutex_lock(&p->lock);
10434             p->remotelyblocked = 1;
10435             ast_mutex_unlock(&p->lock);
10436             isup_bla(linkset->ss7, e->blo.cic, p->dpc);
10437             break;
10438          case ISUP_EVENT_BLA:
10439             chanpos = ss7_find_cic(linkset, e->bla.cic, e->bla.opc);
10440             if (chanpos < 0) {
10441                ast_log(LOG_WARNING, "BLA on unconfigured CIC %d\n", e->bla.cic);
10442                break;
10443             }
10444             ast_debug(1, "Blocking CIC %d\n", e->bla.cic);
10445             p = linkset->pvts[chanpos];
10446             ast_mutex_lock(&p->lock);
10447             p->locallyblocked = 1;
10448             ast_mutex_unlock(&p->lock);
10449             break;
10450          case ISUP_EVENT_UBL:
10451             chanpos = ss7_find_cic(linkset, e->ubl.cic, e->ubl.opc);
10452             if (chanpos < 0) {
10453                ast_log(LOG_WARNING, "UBL on unconfigured CIC %d\n", e->ubl.cic);
10454                break;
10455             }
10456             p = linkset->pvts[chanpos];
10457             ast_debug(1, "Unblocking CIC %d\n", e->ubl.cic);
10458             ast_mutex_lock(&p->lock);
10459             p->remotelyblocked = 0;
10460             ast_mutex_unlock(&p->lock);
10461             isup_uba(linkset->ss7, e->ubl.cic, p->dpc);
10462             break;
10463          case ISUP_EVENT_UBA:
10464             chanpos = ss7_find_cic(linkset, e->uba.cic, e->uba.opc);
10465             if (chanpos < 0) {
10466                ast_log(LOG_WARNING, "UBA on unconfigured CIC %d\n", e->uba.cic);
10467                break;
10468             }
10469             p = linkset->pvts[chanpos];
10470             ast_debug(1, "Unblocking CIC %d\n", e->uba.cic);
10471             ast_mutex_lock(&p->lock);
10472             p->locallyblocked = 0;
10473             ast_mutex_unlock(&p->lock);
10474             break;
10475          case ISUP_EVENT_CON:
10476          case ISUP_EVENT_ANM:
10477             if (e->e == ISUP_EVENT_CON)
10478                cic = e->con.cic;
10479             else
10480                cic = e->anm.cic;
10481 
10482             chanpos = ss7_find_cic(linkset, cic, (e->e == ISUP_EVENT_ANM) ? e->anm.opc : e->con.opc);
10483             if (chanpos < 0) {
10484                ast_log(LOG_WARNING, "ANM/CON on unconfigured CIC %d\n", cic);
10485                isup_rel(ss7, (e->e == ISUP_EVENT_ANM) ? e->anm.call : e->con.call, -1);
10486                break;
10487             } else {
10488                p = linkset->pvts[chanpos];
10489                ast_mutex_lock(&p->lock);
10490                p->subs[SUB_REAL].needanswer = 1;
10491                if (p->dsp && p->dsp_features) {
10492                        ast_dsp_set_features(p->dsp, p->dsp_features);
10493                        p->dsp_features = 0;
10494                }
10495                dahdi_enable_ec(p);
10496                ast_mutex_unlock(&p->lock);
10497             }
10498             break;
10499          case ISUP_EVENT_RLC:
10500             chanpos = ss7_find_cic(linkset, e->rlc.cic, e->rlc.opc);
10501             if (chanpos < 0) {
10502                ast_log(LOG_WARNING, "RLC on unconfigured CIC %d\n", e->rlc.cic);
10503                break;
10504             } else {
10505                p = linkset->pvts[chanpos];
10506                ast_mutex_lock(&p->lock);
10507                if (p->alreadyhungup)
10508                   p->ss7call = NULL;
10509                else
10510                   ast_log(LOG_NOTICE, "Received RLC out and we haven't sent REL.  Ignoring.\n");
10511                ast_mutex_unlock(&p->lock);
10512                }
10513                break;
10514          case ISUP_EVENT_FAA:
10515             chanpos = ss7_find_cic(linkset, e->faa.cic, e->faa.opc);
10516             if (chanpos < 0) {
10517                ast_log(LOG_WARNING, "FAA on unconfigured CIC %d\n", e->faa.cic);
10518                break;
10519             } else {
10520                p = linkset->pvts[chanpos];
10521                ast_debug(1, "FAA received on CIC %d\n", e->faa.cic);
10522                ast_mutex_lock(&p->lock);
10523                if (p->alreadyhungup){
10524                   p->ss7call = NULL;
10525                   ast_log(LOG_NOTICE, "Received FAA and we haven't sent FAR.  Ignoring.\n");
10526                }
10527                ast_mutex_unlock(&p->lock);
10528             }
10529             break;
10530          default:
10531             ast_debug(1, "Unknown event %s\n", ss7_event2str(e->e));
10532             break;
10533          }
10534       }
10535       ast_mutex_unlock(&linkset->lock);
10536    }
10537 
10538    return 0;
10539 }
10540 
10541 static void dahdi_ss7_message(struct ss7 *ss7, char *s)
10542 {
10543 #if 0
10544    int i;
10545 
10546    for (i = 0; i < NUM_SPANS; i++)
10547       if (linksets[i].ss7 == ss7)
10548          break;
10549 
10550    ast_verbose("[%d] %s", i+1, s);
10551 #else
10552    ast_verbose("%s", s);
10553 #endif
10554 }
10555 
10556 static void dahdi_ss7_error(struct ss7 *ss7, char *s)
10557 {
10558 #if 0
10559    int i;
10560 
10561    for (i = 0; i < NUM_SPANS; i++)
10562       if (linksets[i].ss7 == ss7)
10563          break;
10564 
10565 #else
10566    ast_log(LOG_ERROR, "%s", s);
10567 #endif
10568 }
10569 
10570 #endif /* HAVE_SS7 */
10571 
10572 #ifdef HAVE_PRI
10573 static struct dahdi_pvt *pri_find_crv(struct dahdi_pri *pri, int crv)
10574 {
10575    struct dahdi_pvt *p;
10576    p = pri->crvs;
10577    while (p) {
10578       if (p->channel == crv)
10579          return p;
10580       p = p->next;
10581    }
10582    return NULL;
10583 }
10584 
10585 
10586 static int pri_find_principle(struct dahdi_pri *pri, int channel)
10587 {
10588    int x;
10589    int span = PRI_SPAN(channel);
10590    int spanfd;
10591    struct dahdi_params param;
10592    int principle = -1;
10593    int explicit = PRI_EXPLICIT(channel);
10594    channel = PRI_CHANNEL(channel);
10595 
10596    if (!explicit) {
10597       spanfd = pri_active_dchan_fd(pri);
10598       memset(&param, 0, sizeof(param));
10599       if (ioctl(spanfd, DAHDI_GET_PARAMS, &param))
10600          return -1;
10601       span = pris[param.spanno - 1].prilogicalspan;
10602    }
10603 
10604    for (x = 0; x < pri->numchans; x++) {
10605       if (pri->pvts[x] && (pri->pvts[x]->prioffset == channel) && (pri->pvts[x]->logicalspan == span)) {
10606          principle = x;
10607          break;
10608       }
10609    }
10610    
10611    return principle;
10612 }
10613 
10614 static int pri_fixup_principle(struct dahdi_pri *pri, int principle, q931_call *c)
10615 {
10616    int x;
10617    struct dahdi_pvt *crv;
10618    if (!c) {
10619       if (principle < 0)
10620          return -1;
10621       return principle;
10622    }
10623    if ((principle > -1) && 
10624       (principle < pri->numchans) && 
10625       (pri->pvts[principle]) && 
10626       (pri->pvts[principle]->call == c))
10627       return principle;
10628    /* First, check for other bearers */
10629    for (x = 0; x < pri->numchans; x++) {
10630       if (!pri->pvts[x])
10631          continue;
10632       if (pri->pvts[x]->call == c) {
10633          /* Found our call */
10634          if (principle != x) {
10635             struct dahdi_pvt *new = pri->pvts[principle], *old = pri->pvts[x];
10636 
10637             ast_verb(3, "Moving call from channel %d to channel %d\n",
10638                 old->channel, new->channel);
10639             if (new->owner) {
10640                ast_log(LOG_WARNING, "Can't fix up channel from %d to %d because %d is already in use\n",
10641                   old->channel, new->channel, new->channel);
10642                return -1;
10643             }
10644             /* Fix it all up now */
10645             new->owner = old->owner;
10646             old->owner = NULL;
10647             if (new->owner) {
10648                ast_string_field_build(new->owner, name, 
10649                             "DAHDI/%d:%d-%d", pri->trunkgroup,
10650                             new->channel, 1);
10651                new->owner->tech_pvt = new;
10652                ast_channel_set_fd(new->owner, 0, new->subs[SUB_REAL].dfd);
10653                new->subs[SUB_REAL].owner = old->subs[SUB_REAL].owner;
10654                old->subs[SUB_REAL].owner = NULL;
10655             } else
10656                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);
10657             new->call = old->call;
10658             old->call = NULL;
10659 
10660             /* Copy any DSP that may be present */
10661             new->dsp = old->dsp;
10662             new->dsp_features = old->dsp_features;
10663             old->dsp = NULL;
10664             old->dsp_features = 0;
10665          }
10666          return principle;
10667       }
10668    }
10669    /* Now check for a CRV with no bearer */
10670    crv = pri->crvs;
10671    while (crv) {
10672       if (crv->call == c) {
10673          /* This is our match...  Perform some basic checks */
10674          if (crv->bearer)
10675             ast_log(LOG_WARNING, "Trying to fix up call which already has a bearer which isn't the one we think it is\n");
10676          else if (pri->pvts[principle]->owner) 
10677             ast_log(LOG_WARNING, "Tring to fix up a call to a bearer which already has an owner!\n");
10678          else {
10679             /* Looks good.  Drop the pseudo channel now, clear up the assignment, and
10680                wakeup the potential sleeper */
10681             dahdi_close_sub(crv, SUB_REAL);
10682             pri->pvts[principle]->call = crv->call;
10683             pri_assign_bearer(crv, pri, pri->pvts[principle]);
10684             ast_debug(1, "Assigning bearer %d/%d to CRV %d:%d\n",
10685                pri->pvts[principle]->logicalspan, pri->pvts[principle]->prioffset,
10686                pri->trunkgroup, crv->channel);
10687             wakeup_sub(crv, SUB_REAL, pri);
10688          }
10689          return principle;
10690       }
10691       crv = crv->next;
10692    }
10693    ast_log(LOG_WARNING, "Call specified, but not found?\n");
10694    return -1;
10695 }
10696 
10697 static void *do_idle_thread(void *vchan)
10698 {
10699    struct ast_channel *chan = vchan;
10700    struct dahdi_pvt *pvt = chan->tech_pvt;
10701    struct ast_frame *f;
10702    char ex[80];
10703    /* Wait up to 30 seconds for an answer */
10704    int newms, ms = 30000;
10705    ast_verb(3, "Initiating idle call on channel %s\n", chan->name);
10706    snprintf(ex, sizeof(ex), "%d/%s", pvt->channel, pvt->pri->idledial);
10707    if (ast_call(chan, ex, 0)) {
10708       ast_log(LOG_WARNING, "Idle dial failed on '%s' to '%s'\n", chan->name, ex);
10709       ast_hangup(chan);
10710       return NULL;
10711    }
10712    while ((newms = ast_waitfor(chan, ms)) > 0) {
10713       f = ast_read(chan);
10714       if (!f) {
10715          /* Got hangup */
10716          break;
10717       }
10718       if (f->frametype == AST_FRAME_CONTROL) {
10719          switch (f->subclass) {
10720          case AST_CONTROL_ANSWER:
10721             /* Launch the PBX */
10722             ast_copy_string(chan->exten, pvt->pri->idleext, sizeof(chan->exten));
10723             ast_copy_string(chan->context, pvt->pri->idlecontext, sizeof(chan->context));
10724             chan->priority = 1;
10725             ast_verb(4, "Idle channel '%s' answered, sending to %s@%s\n", chan->name, chan->exten, chan->context);
10726             ast_pbx_run(chan);
10727             /* It's already hungup, return immediately */
10728             return NULL;
10729          case AST_CONTROL_BUSY:
10730             ast_verb(4, "Idle channel '%s' busy, waiting...\n", chan->name);
10731             break;
10732          case AST_CONTROL_CONGESTION:
10733             ast_verb(4, "Idle channel '%s' congested, waiting...\n", chan->name);
10734             break;
10735          };
10736       }
10737       ast_frfree(f);
10738       ms = newms;
10739    }
10740    /* Hangup the channel since nothing happend */
10741    ast_hangup(chan);
10742    return NULL;
10743 }
10744 
10745 #ifndef PRI_RESTART
10746 #error "Upgrade your libpri"
10747 #endif
10748 static void dahdi_pri_message(struct pri *pri, char *s)
10749 {
10750    int x, y;
10751    int dchan = -1, span = -1;
10752    int dchancount = 0;
10753 
10754    if (pri) {
10755       for (x = 0; x < NUM_SPANS; x++) {
10756          for (y = 0; y < NUM_DCHANS; y++) {
10757             if (pris[x].dchans[y])
10758                dchancount++;
10759 
10760             if (pris[x].dchans[y] == pri)
10761                dchan = y;
10762          }
10763          if (dchan >= 0) {
10764             span = x;
10765             break;
10766          }
10767          dchancount = 0;
10768       }
10769       if (dchancount > 1 && (span > -1))
10770          ast_verbose("[Span %d D-Channel %d]%s", span, dchan, s);
10771       else
10772          ast_verbose("%s", s);
10773    } else
10774       ast_verbose("%s", s);
10775 
10776    ast_mutex_lock(&pridebugfdlock);
10777 
10778    if (pridebugfd >= 0) {
10779       if (write(pridebugfd, s, strlen(s)) < 0) {
10780          ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
10781       }
10782    }
10783 
10784    ast_mutex_unlock(&pridebugfdlock);
10785 }
10786 
10787 static void dahdi_pri_error(struct pri *pri, char *s)
10788 {
10789    int x, y;
10790    int dchan = -1, span = -1;
10791    int dchancount = 0;
10792 
10793    if (pri) {
10794       for (x = 0; x < NUM_SPANS; x++) {
10795          for (y = 0; y < NUM_DCHANS; y++) {
10796             if (pris[x].dchans[y])
10797                dchancount++;
10798 
10799             if (pris[x].dchans[y] == pri)
10800                dchan = y;
10801          }
10802          if (dchan >= 0) {
10803             span = x;
10804             break;
10805          }
10806          dchancount = 0;
10807       }
10808       if ((dchancount > 1) && (span > -1))
10809          ast_log(LOG_ERROR, "[Span %d D-Channel %d] PRI: %s", span, dchan, s);
10810       else
10811          ast_log(LOG_ERROR, "%s", s);
10812    } else
10813       ast_log(LOG_ERROR, "%s", s);
10814 
10815    ast_mutex_lock(&pridebugfdlock);
10816 
10817    if (pridebugfd >= 0) {
10818       if (write(pridebugfd, s, strlen(s)) < 0) {
10819          ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
10820       }
10821    }
10822 
10823    ast_mutex_unlock(&pridebugfdlock);
10824 }
10825 
10826 static int pri_check_restart(struct dahdi_pri *pri)
10827 {
10828    do {
10829       pri->resetpos++;
10830    } while ((pri->resetpos < pri->numchans) &&
10831        (!pri->pvts[pri->resetpos] ||
10832         pri->pvts[pri->resetpos]->call ||
10833         pri->pvts[pri->resetpos]->resetting));
10834    if (pri->resetpos < pri->numchans) {
10835       /* Mark the channel as resetting and restart it */
10836       pri->pvts[pri->resetpos]->resetting = 1;
10837       pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[pri->resetpos]));
10838    } else {
10839       pri->resetting = 0;
10840       time(&pri->lastreset);
10841    }
10842    return 0;
10843 }
10844 
10845 static int pri_hangup_all(struct dahdi_pvt *p, struct dahdi_pri *pri)
10846 {
10847    int x;
10848    int redo;
10849    ast_mutex_unlock(&pri->lock);
10850    ast_mutex_lock(&p->lock);
10851    do {
10852       redo = 0;
10853       for (x = 0; x < 3; x++) {
10854          while (p->subs[x].owner && ast_channel_trylock(p->subs[x].owner)) {
10855             redo++;
10856             DEADLOCK_AVOIDANCE(&p->lock);
10857          }
10858          if (p->subs[x].owner) {
10859             ast_queue_hangup_with_cause(p->subs[x].owner, AST_CAUSE_PRE_EMPTED);
10860             ast_channel_unlock(p->subs[x].owner);
10861          }
10862       }
10863    } while (redo);
10864    ast_mutex_unlock(&p->lock);
10865    ast_mutex_lock(&pri->lock);
10866    return 0;
10867 }
10868 
10869 static char * redirectingreason2str(int redirectingreason)
10870 {
10871    switch (redirectingreason) {
10872    case 0:
10873       return "UNKNOWN";
10874    case 1:
10875       return "BUSY";
10876    case 2:
10877       return "NO_REPLY";
10878    case 0xF:
10879       return "UNCONDITIONAL";
10880    default:
10881       return "NOREDIRECT";
10882    }
10883 }
10884 
10885 static void apply_plan_to_number(char *buf, size_t size, const struct dahdi_pri *pri, const char *number, const int plan)
10886 {
10887    if (pri->dialplan == -2) { /* autodetect the TON but leave the number untouched */
10888       snprintf(buf, size, "%s", number);
10889       return;
10890    }
10891    if (ast_strlen_zero(number)) { /* make sure a number exists so prefix isn't placed on an empty string */
10892       if (size) {
10893          *buf = '\0';
10894       }
10895       return;
10896    }
10897    switch (plan) {
10898    case PRI_INTERNATIONAL_ISDN:     /* Q.931 dialplan == 0x11 international dialplan => prepend international prefix digits */
10899       snprintf(buf, size, "%s%s", pri->internationalprefix, number);
10900       break;
10901    case PRI_NATIONAL_ISDN:       /* Q.931 dialplan == 0x21 national dialplan => prepend national prefix digits */
10902       snprintf(buf, size, "%s%s", pri->nationalprefix, number);
10903       break;
10904    case PRI_LOCAL_ISDN:       /* Q.931 dialplan == 0x41 local dialplan => prepend local prefix digits */
10905       snprintf(buf, size, "%s%s", pri->localprefix, number);
10906       break;
10907    case PRI_PRIVATE:       /* Q.931 dialplan == 0x49 private dialplan => prepend private prefix digits */
10908       snprintf(buf, size, "%s%s", pri->privateprefix, number);
10909       break;
10910    case PRI_UNKNOWN:       /* Q.931 dialplan == 0x00 unknown dialplan => prepend unknown prefix digits */
10911       snprintf(buf, size, "%s%s", pri->unknownprefix, number);
10912       break;
10913    default:          /* other Q.931 dialplan => don't twiddle with callingnum */
10914       snprintf(buf, size, "%s", number);
10915       break;
10916    }
10917 }
10918 
10919 
10920 static void *pri_dchannel(void *vpri)
10921 {
10922    struct dahdi_pri *pri = vpri;
10923    pri_event *e;
10924    struct pollfd fds[NUM_DCHANS];
10925    int res;
10926    int chanpos = 0;
10927    int x;
10928    int haveidles;
10929    int activeidles;
10930    int nextidle = -1;
10931    struct ast_channel *c;
10932    struct timeval tv, lowest, *next;
10933    struct timeval lastidle = ast_tvnow();
10934    int doidling=0;
10935    char *cc;
10936    char idlen[80];
10937    struct ast_channel *idle;
10938    pthread_t p;
10939    time_t t;
10940    int i, which=-1;
10941    int numdchans;
10942    int cause=0;
10943    struct dahdi_pvt *crv;
10944    pthread_t threadid;
10945    char ani2str[6];
10946    char plancallingnum[256];
10947    char plancallingani[256];
10948    char calledtonstr[10];
10949    
10950    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
10951 
10952    gettimeofday(&lastidle, NULL);
10953    if (!ast_strlen_zero(pri->idledial) && !ast_strlen_zero(pri->idleext)) {
10954       /* Need to do idle dialing, check to be sure though */
10955       cc = strchr(pri->idleext, '@');
10956       if (cc) {
10957          *cc = '\0';
10958          cc++;
10959          ast_copy_string(pri->idlecontext, cc, sizeof(pri->idlecontext));
10960 #if 0
10961          /* Extensions may not be loaded yet */
10962          if (!ast_exists_extension(NULL, pri->idlecontext, pri->idleext, 1, NULL))
10963             ast_log(LOG_WARNING, "Extension '%s @ %s' does not exist\n", pri->idleext, pri->idlecontext);
10964          else
10965 #endif
10966             doidling = 1;
10967       } else
10968          ast_log(LOG_WARNING, "Idle dial string '%s' lacks '@context'\n", pri->idleext);
10969    }
10970    for (;;) {
10971       for (i = 0; i < NUM_DCHANS; i++) {
10972          if (!pri->dchannels[i])
10973             break;
10974          fds[i].fd = pri->fds[i];
10975          fds[i].events = POLLIN | POLLPRI;
10976          fds[i].revents = 0;
10977       }
10978       numdchans = i;
10979       time(&t);
10980       ast_mutex_lock(&pri->lock);
10981       if (pri->switchtype != PRI_SWITCH_GR303_TMC && (pri->resetinterval > 0)) {
10982          if (pri->resetting && pri_is_up(pri)) {
10983             if (pri->resetpos < 0)
10984                pri_check_restart(pri);
10985          } else {
10986             if (!pri->resetting  && (t - pri->lastreset) >= pri->resetinterval) {
10987                pri->resetting = 1;
10988                pri->resetpos = -1;
10989             }
10990          }
10991       }
10992       /* Look for any idle channels if appropriate */
10993       if (doidling && pri_is_up(pri)) {
10994          nextidle = -1;
10995          haveidles = 0;
10996          activeidles = 0;
10997          for (x = pri->numchans; x >= 0; x--) {
10998             if (pri->pvts[x] && !pri->pvts[x]->owner && 
10999                 !pri->pvts[x]->call) {
11000                if (haveidles < pri->minunused) {
11001                   haveidles++;
11002                } else if (!pri->pvts[x]->resetting) {
11003                   nextidle = x;
11004                   break;
11005                }
11006             } else if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall)
11007                activeidles++;
11008          }
11009          if (nextidle > -1) {
11010             if (ast_tvdiff_ms(ast_tvnow(), lastidle) > 1000) {
11011                /* Don't create a new idle call more than once per second */
11012                snprintf(idlen, sizeof(idlen), "%d/%s", pri->pvts[nextidle]->channel, pri->idledial);
11013                idle = dahdi_request("DAHDI", AST_FORMAT_ULAW, idlen, &cause);
11014                if (idle) {
11015                   pri->pvts[nextidle]->isidlecall = 1;
11016                   if (ast_pthread_create_background(&p, NULL, do_idle_thread, idle)) {
11017                      ast_log(LOG_WARNING, "Unable to start new thread for idle channel '%s'\n", idle->name);
11018                      dahdi_hangup(idle);
11019                   }
11020                } else
11021                   ast_log(LOG_WARNING, "Unable to request channel 'DAHDI/%s' for idle call\n", idlen);
11022                lastidle = ast_tvnow();
11023             }
11024          } else if ((haveidles < pri->minunused) &&
11025                (activeidles > pri->minidle)) {
11026             /* Mark something for hangup if there is something 
11027                that can be hungup */
11028             for (x = pri->numchans; x >= 0; x--) {
11029                /* find a candidate channel */
11030                if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall) {
11031                   pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11032                   haveidles++;
11033                   /* Stop if we have enough idle channels or
11034                     can't spare any more active idle ones */
11035                   if ((haveidles >= pri->minunused) ||
11036                       (activeidles <= pri->minidle))
11037                      break;
11038                } 
11039             }
11040          }
11041       }
11042       /* Start with reasonable max */
11043       lowest = ast_tv(60, 0);
11044       for (i = 0; i < NUM_DCHANS; i++) {
11045          /* Find lowest available d-channel */
11046          if (!pri->dchannels[i])
11047             break;
11048          if ((next = pri_schedule_next(pri->dchans[i]))) {
11049             /* We need relative time here */
11050             tv = ast_tvsub(*next, ast_tvnow());
11051             if (tv.tv_sec < 0) {
11052                tv = ast_tv(0,0);
11053             }
11054             if (doidling || pri->resetting) {
11055                if (tv.tv_sec > 1) {
11056                   tv = ast_tv(1, 0);
11057                }
11058             } else {
11059                if (tv.tv_sec > 60) {
11060                   tv = ast_tv(60, 0);
11061                }
11062             }
11063          } else if (doidling || pri->resetting) {
11064             /* Make sure we stop at least once per second if we're
11065                monitoring idle channels */
11066             tv = ast_tv(1,0);
11067          } else {
11068             /* Don't poll for more than 60 seconds */
11069             tv = ast_tv(60, 0);
11070          }
11071          if (!i || ast_tvcmp(tv, lowest) < 0) {
11072             lowest = tv;
11073          }
11074       }
11075       ast_mutex_unlock(&pri->lock);
11076 
11077       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
11078       pthread_testcancel();
11079       e = NULL;
11080       res = poll(fds, numdchans, lowest.tv_sec * 1000 + lowest.tv_usec / 1000);
11081       pthread_testcancel();
11082       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
11083 
11084       ast_mutex_lock(&pri->lock);
11085       if (!res) {
11086          for (which = 0; which < NUM_DCHANS; which++) {
11087             if (!pri->dchans[which])
11088                break;
11089             /* Just a timeout, run the scheduler */
11090             e = pri_schedule_run(pri->dchans[which]);
11091             if (e)
11092                break;
11093          }
11094       } else if (res > -1) {
11095          for (which = 0; which < NUM_DCHANS; which++) {
11096             if (!pri->dchans[which])
11097                break;
11098             if (fds[which].revents & POLLPRI) {
11099                /* Check for an event */
11100                x = 0;
11101                res = ioctl(pri->fds[which], DAHDI_GETEVENT, &x);
11102                if (x) {
11103                   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);
11104                   manager_event(EVENT_FLAG_SYSTEM, "PRIEvent",
11105                      "PRIEvent: %s\r\n"
11106                      "PRIEventCode: %d\r\n"
11107                      "D-channel: %s\r\n"
11108                      "Span: %d\r\n",
11109                      event2str(x),
11110                      x,
11111                      pri_order(which),
11112                      pri->span
11113                      );
11114                }
11115                /* Keep track of alarm state */  
11116                if (x == DAHDI_EVENT_ALARM) {
11117                   pri->dchanavail[which] &= ~(DCHAN_NOTINALARM | DCHAN_UP);
11118                   pri_find_dchan(pri);
11119                } else if (x == DAHDI_EVENT_NOALARM) {
11120                   pri->dchanavail[which] |= DCHAN_NOTINALARM;
11121                   pri_restart(pri->dchans[which]);
11122                }
11123             
11124                ast_debug(1, "Got event %s (%d) on D-channel for span %d\n", event2str(x), x, pri->span);
11125             } else if (fds[which].revents & POLLIN) {
11126                e = pri_check_event(pri->dchans[which]);
11127             }
11128             if (e)
11129                break;
11130          }
11131       } else if (errno != EINTR)
11132          ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
11133 
11134       if (e) {
11135          if (pri->debug)
11136             pri_dump_event(pri->dchans[which], e);
11137 
11138          if (e->e != PRI_EVENT_DCHAN_DOWN) {
11139             if (!(pri->dchanavail[which] & DCHAN_UP)) {
11140                ast_verb(2, "%s D-Channel on span %d up\n", pri_order(which), pri->span);
11141             }
11142             pri->dchanavail[which] |= DCHAN_UP;
11143          } else if (pri->sig != SIG_BRI_PTMP) {
11144             if (pri->dchanavail[which] & DCHAN_UP) {
11145                ast_verb(2, "%s D-Channel on span %d down\n", pri_order(which), pri->span);
11146             }
11147             pri->dchanavail[which] &= ~DCHAN_UP;
11148          }
11149 
11150          if ((e->e != PRI_EVENT_DCHAN_UP) && (e->e != PRI_EVENT_DCHAN_DOWN) && (pri->pri != pri->dchans[which]))
11151             /* Must be an NFAS group that has the secondary dchan active */
11152             pri->pri = pri->dchans[which];
11153 
11154          switch (e->e) {
11155          case PRI_EVENT_DCHAN_UP:
11156             if (!pri->pri) pri_find_dchan(pri);
11157 
11158             /* Note presense of D-channel */
11159             time(&pri->lastreset);
11160 
11161             /* Restart in 5 seconds */
11162             if (pri->resetinterval > -1) {
11163                pri->lastreset -= pri->resetinterval;
11164                pri->lastreset += 5;
11165             }
11166             pri->resetting = 0;
11167             /* Take the channels from inalarm condition */
11168             for (i = 0; i < pri->numchans; i++)
11169                if (pri->pvts[i]) {
11170                   pri->pvts[i]->inalarm = 0;
11171                }
11172             break;
11173          case PRI_EVENT_DCHAN_DOWN:
11174             pri_find_dchan(pri);
11175             if (!pri_is_up(pri)) {
11176                pri->resetting = 0;
11177                /* Hangup active channels and put them in alarm mode */
11178                for (i = 0; i < pri->numchans; i++) {
11179                   struct dahdi_pvt *p = pri->pvts[i];
11180                   if (p) {
11181                      if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
11182                         /* T309 is not enabled : hangup calls when alarm occurs */
11183                         if (p->call) {
11184                            if (p->pri && p->pri->pri) {
11185                               pri_hangup(p->pri->pri, p->call, -1);
11186                               pri_destroycall(p->pri->pri, p->call);
11187                               p->call = NULL;
11188                            } else
11189                               ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
11190                         }
11191                         if (p->realcall) {
11192                            pri_hangup_all(p->realcall, pri);
11193                         } else if (p->owner)
11194                            p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11195                      }
11196                      p->inalarm = 1;
11197                   }
11198                }
11199             }
11200             break;
11201          case PRI_EVENT_RESTART:
11202             if (e->restart.channel > -1) {
11203                chanpos = pri_find_principle(pri, e->restart.channel);
11204                if (chanpos < 0)
11205                   ast_log(LOG_WARNING, "Restart requested on odd/unavailable channel number %d/%d on span %d\n", 
11206                      PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
11207                else {
11208                   ast_verb(3, "B-channel %d/%d restarted on span %d\n",
11209                         PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
11210                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11211                   if (pri->pvts[chanpos]->call) {
11212                      pri_destroycall(pri->pri, pri->pvts[chanpos]->call);
11213                      pri->pvts[chanpos]->call = NULL;
11214                   }
11215                   /* Force soft hangup if appropriate */
11216                   if (pri->pvts[chanpos]->realcall) 
11217                      pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11218                   else if (pri->pvts[chanpos]->owner)
11219                      pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11220                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11221                }
11222             } else {
11223                ast_verb(3, "Restart on requested on entire span %d\n", pri->span);
11224                for (x = 0; x < pri->numchans; x++)
11225                   if (pri->pvts[x]) {
11226                      ast_mutex_lock(&pri->pvts[x]->lock);
11227                      if (pri->pvts[x]->call) {
11228                         pri_destroycall(pri->pri, pri->pvts[x]->call);
11229                         pri->pvts[x]->call = NULL;
11230                      }
11231                      if (pri->pvts[x]->realcall) 
11232                         pri_hangup_all(pri->pvts[x]->realcall, pri);
11233                      else if (pri->pvts[x]->owner)
11234                         pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11235                      ast_mutex_unlock(&pri->pvts[x]->lock);
11236                   }
11237             }
11238             break;
11239          case PRI_EVENT_KEYPAD_DIGIT:
11240             chanpos = pri_find_principle(pri, e->digit.channel);
11241             if (chanpos < 0) {
11242                ast_log(LOG_WARNING, "KEYPAD_DIGITs received on unconfigured channel %d/%d span %d\n", 
11243                   PRI_SPAN(e->digit.channel), PRI_CHANNEL(e->digit.channel), pri->span);
11244             } else {
11245                chanpos = pri_fixup_principle(pri, chanpos, e->digit.call);
11246                if (chanpos > -1) {
11247                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11248                   /* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
11249                   if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->digit.call && pri->pvts[chanpos]->owner) {
11250                      /* how to do that */
11251                      int digitlen = strlen(e->digit.digits);
11252                      char digit;
11253                      int i;               
11254                      for (i = 0; i < digitlen; i++) { 
11255                         digit = e->digit.digits[i];
11256                         {
11257                            struct ast_frame f = { AST_FRAME_DTMF, digit, };
11258                            dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11259                         }
11260                      }
11261                   }
11262                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11263                }
11264             }
11265             break;
11266             
11267          case PRI_EVENT_INFO_RECEIVED:
11268             chanpos = pri_find_principle(pri, e->ring.channel);
11269             if (chanpos < 0) {
11270                ast_log(LOG_WARNING, "INFO received on unconfigured channel %d/%d span %d\n", 
11271                   PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
11272             } else {
11273                chanpos = pri_fixup_principle(pri, chanpos, e->ring.call);
11274                if (chanpos > -1) {
11275                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11276                   /* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
11277                   if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) {
11278                      /* how to do that */
11279                      int digitlen = strlen(e->ring.callednum);
11280                      char digit;
11281                      int i;               
11282                      for (i = 0; i < digitlen; i++) { 
11283                         digit = e->ring.callednum[i];
11284                         {
11285                            struct ast_frame f = { AST_FRAME_DTMF, digit, };
11286                            dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11287                         }
11288                      }
11289                   }
11290                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11291                }
11292             }
11293             break;
11294          case PRI_EVENT_RING:
11295             crv = NULL;
11296             if (e->ring.channel == -1)
11297                chanpos = pri_find_empty_chan(pri, 1);
11298             else
11299                chanpos = pri_find_principle(pri, e->ring.channel);
11300             /* if no channel specified find one empty */
11301             if (chanpos < 0) {
11302                ast_log(LOG_WARNING, "Ring requested on unconfigured channel %d/%d span %d\n", 
11303                   PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
11304             } else {
11305                ast_mutex_lock(&pri->pvts[chanpos]->lock);
11306                if (pri->pvts[chanpos]->owner) {
11307                   if (pri->pvts[chanpos]->call == e->ring.call) {
11308                      ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n", 
11309                         PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
11310                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11311                      break;
11312                   } else {
11313                      /* This is where we handle initial glare */
11314                      ast_debug(1, "Ring requested on channel %d/%d already in use or previously requested on span %d.  Attempting to renegotiate channel.\n", 
11315                      PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
11316                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11317                      chanpos = -1;
11318                   }
11319                }
11320                if (chanpos > -1)
11321                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11322             }
11323             if ((chanpos < 0) && (e->ring.flexible))
11324                chanpos = pri_find_empty_chan(pri, 1);
11325             if (chanpos > -1) {
11326                ast_mutex_lock(&pri->pvts[chanpos]->lock);
11327                if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
11328                   /* Should be safe to lock CRV AFAIK while bearer is still locked */
11329                   crv = pri_find_crv(pri, pri_get_crv(pri->pri, e->ring.call, NULL));
11330                   if (crv)
11331                      ast_mutex_lock(&crv->lock);
11332                   if (!crv || crv->owner) {
11333                      pri->pvts[chanpos]->call = NULL;
11334                      if (crv) {
11335                         if (crv->owner)
11336                            crv->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11337                         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);
11338                      } else
11339                         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);
11340                      pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INVALID_CALL_REFERENCE);
11341                      if (crv)
11342                         ast_mutex_unlock(&crv->lock);
11343                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11344                      break;
11345                   }
11346                }
11347                pri->pvts[chanpos]->call = e->ring.call;
11348                apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
11349                if (pri->pvts[chanpos]->use_callerid) {
11350                   ast_shrink_phone_number(plancallingnum);
11351                   ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum, sizeof(pri->pvts[chanpos]->cid_num));
11352 #ifdef PRI_ANI
11353                   if (!ast_strlen_zero(e->ring.callingani)) {
11354                      apply_plan_to_number(plancallingani, sizeof(plancallingani), pri, e->ring.callingani, e->ring.callingplanani);
11355                      ast_shrink_phone_number(plancallingani);
11356                      ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani, sizeof(pri->pvts[chanpos]->cid_ani));
11357                   } else {
11358                      pri->pvts[chanpos]->cid_ani[0] = '\0';
11359                   }
11360 #endif
11361                   ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname, sizeof(pri->pvts[chanpos]->cid_name));
11362                   pri->pvts[chanpos]->cid_ton = e->ring.callingplan; /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
11363                } else {
11364                   pri->pvts[chanpos]->cid_num[0] = '\0';
11365                   pri->pvts[chanpos]->cid_ani[0] = '\0';
11366                   pri->pvts[chanpos]->cid_name[0] = '\0';
11367                   pri->pvts[chanpos]->cid_ton = 0;
11368                }
11369                apply_plan_to_number(pri->pvts[chanpos]->rdnis, sizeof(pri->pvts[chanpos]->rdnis), pri,
11370                           e->ring.redirectingnum, e->ring.callingplanrdnis);
11371                /* If immediate=yes go to s|1 */
11372                if (pri->pvts[chanpos]->immediate) {
11373                   ast_verb(3, "Going to extension s|1 because of immediate=yes\n");
11374                   pri->pvts[chanpos]->exten[0] = 's';
11375                   pri->pvts[chanpos]->exten[1] = '\0';
11376                }
11377                /* Get called number */
11378                else if (!ast_strlen_zero(e->ring.callednum)) {
11379                   ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
11380                   ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
11381                } else if (pri->overlapdial)
11382                   pri->pvts[chanpos]->exten[0] = '\0';
11383                else {
11384                   /* Some PRI circuits are set up to send _no_ digits.  Handle them as 's'. */
11385                   pri->pvts[chanpos]->exten[0] = 's';
11386                   pri->pvts[chanpos]->exten[1] = '\0';
11387                }
11388                /* Set DNID on all incoming calls -- even immediate */
11389                if (!ast_strlen_zero(e->ring.callednum))
11390                   ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
11391                /* No number yet, but received "sending complete"? */
11392                if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
11393                   ast_verb(3, "Going to extension s|1 because of Complete received\n");
11394                   pri->pvts[chanpos]->exten[0] = 's';
11395                   pri->pvts[chanpos]->exten[1] = '\0';
11396                }
11397 
11398                /* Make sure extension exists (or in overlap dial mode, can exist) */
11399                if (((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
11400                   ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
11401                   /* Setup law */
11402                   int law;
11403                   if (pri->switchtype != PRI_SWITCH_GR303_TMC) {
11404                      /* Set to audio mode at this point */
11405                      law = 1;
11406                      if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law) == -1)
11407                         ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", pri->pvts[chanpos]->channel, law, strerror(errno));
11408                   }
11409                   if (e->ring.layer1 == PRI_LAYER_1_ALAW)
11410                      law = DAHDI_LAW_ALAW;
11411                   else
11412                      law = DAHDI_LAW_MULAW;
11413                   res = dahdi_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].dfd, law);
11414                   if (res < 0) 
11415                      ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvts[chanpos]->channel);
11416                   res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].dfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
11417                   if (res < 0)
11418                      ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[chanpos]->channel);
11419                   if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
11420                      /* Just announce proceeding */
11421                      pri->pvts[chanpos]->proceeding = 1;
11422                      pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
11423                   } else {
11424                      if (pri->switchtype != PRI_SWITCH_GR303_TMC) 
11425                         pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
11426                      else
11427                         pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
11428                   }
11429                   /* Get the use_callingpres state */
11430                   pri->pvts[chanpos]->callingpres = e->ring.callingpres;
11431                
11432                   /* Start PBX */
11433                   if (!e->ring.complete
11434                      && (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
11435                      && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
11436                      /*
11437                       * Release the PRI lock while we create the channel
11438                       * so other threads can send D channel messages.
11439                       */
11440                      ast_mutex_unlock(&pri->lock);
11441                      if (crv) {
11442                         /* Set bearer and such */
11443                         pri_assign_bearer(crv, pri, pri->pvts[chanpos]);
11444                         c = dahdi_new(crv, AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
11445                         pri->pvts[chanpos]->owner = &inuse;
11446                         ast_debug(1, "Started up crv %d:%d on bearer channel %d\n", pri->trunkgroup, crv->channel, crv->bearer->channel);
11447                      } else {
11448                         c = dahdi_new(pri->pvts[chanpos], AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
11449                      }
11450                      ast_mutex_lock(&pri->lock);
11451                      if (c) {
11452                         if (!ast_strlen_zero(e->ring.callingsubaddr)) {
11453                            pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
11454                         }
11455                         if (e->ring.ani2 >= 0) {
11456                            snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
11457                            pbx_builtin_setvar_helper(c, "ANI2", ani2str);
11458                            pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
11459                         }
11460 
11461 #ifdef SUPPORT_USERUSER
11462                         if (!ast_strlen_zero(e->ring.useruserinfo)) {
11463                            pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
11464                         }
11465 #endif
11466 
11467                         snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
11468                         pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
11469                         if (e->ring.redirectingreason >= 0)
11470                            pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
11471                      }
11472                      if (c && !ast_pthread_create_detached(&threadid, NULL, ss_thread, c)) {
11473                         ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
11474                            plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
11475                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
11476                      } else {
11477                         ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
11478                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
11479                         if (c)
11480                            ast_hangup(c);
11481                         else {
11482                            pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
11483                            pri->pvts[chanpos]->call = NULL;
11484                         }
11485                      }
11486                   } else {
11487                      /*
11488                       * Release the PRI lock while we create the channel
11489                       * so other threads can send D channel messages.
11490                       */
11491                      ast_mutex_unlock(&pri->lock);
11492                      c = dahdi_new(pri->pvts[chanpos], AST_STATE_RING, 0, SUB_REAL, law, e->ring.ctype);
11493                      ast_mutex_lock(&pri->lock);
11494                      if (c) {
11495                         /*
11496                          * It is reasonably safe to set the following
11497                          * channel variables while the PRI and DAHDI private
11498                          * structures are locked.  The PBX has not been
11499                          * started yet and it is unlikely that any other task
11500                          * will do anything with the channel we have just
11501                          * created.
11502                          */
11503                         if (!ast_strlen_zero(e->ring.callingsubaddr)) {
11504                            pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
11505                         }
11506                         if (e->ring.ani2 >= 0) {
11507                            snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
11508                            pbx_builtin_setvar_helper(c, "ANI2", ani2str);
11509                            pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
11510                         }
11511 
11512 #ifdef SUPPORT_USERUSER
11513                         if (!ast_strlen_zero(e->ring.useruserinfo)) {
11514                            pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
11515                         }
11516 #endif
11517 
11518                         if (e->ring.redirectingreason >= 0)
11519                            pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
11520 
11521                         snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
11522                         pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
11523                      }
11524                      if (c && !ast_pbx_start(c)) {
11525                         ast_verb(3, "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
11526                            plancallingnum, pri->pvts[chanpos]->exten,
11527                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
11528 
11529                         dahdi_enable_ec(pri->pvts[chanpos]);
11530                      } else {
11531                         ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
11532                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
11533                         if (c) {
11534                            ast_hangup(c);
11535                         } else {
11536                            pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
11537                            pri->pvts[chanpos]->call = NULL;
11538                         }
11539                      }
11540                   }
11541                } else {
11542                   ast_verb(3, "Extension '%s' in context '%s' from '%s' does not exist.  Rejecting call on channel %d/%d, span %d\n",
11543                      pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context, pri->pvts[chanpos]->cid_num, pri->pvts[chanpos]->logicalspan,
11544                      pri->pvts[chanpos]->prioffset, pri->span);
11545                   pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
11546                   pri->pvts[chanpos]->call = NULL;
11547                   pri->pvts[chanpos]->exten[0] = '\0';
11548                }
11549                if (crv)
11550                   ast_mutex_unlock(&crv->lock);
11551                ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11552             } else {
11553                if (e->ring.flexible)
11554                   pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
11555                else
11556                   pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
11557             }
11558             break;
11559          case PRI_EVENT_RINGING:
11560             chanpos = pri_find_principle(pri, e->ringing.channel);
11561             if (chanpos < 0) {
11562                ast_log(LOG_WARNING, "Ringing requested on unconfigured channel %d/%d span %d\n", 
11563                   PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
11564             } else {
11565                chanpos = pri_fixup_principle(pri, chanpos, e->ringing.call);
11566                if (chanpos < 0) {
11567                   ast_log(LOG_WARNING, "Ringing requested on channel %d/%d not in use on span %d\n", 
11568                      PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
11569                } else {
11570                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11571                   if (ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) {
11572                      dahdi_enable_ec(pri->pvts[chanpos]);
11573                      pri->pvts[chanpos]->subs[SUB_REAL].needringing = 1;
11574                      pri->pvts[chanpos]->alerting = 1;
11575                   } else
11576                      ast_debug(1, "Deferring ringing notification because of extra digits to dial...\n");
11577 
11578 #ifdef PRI_PROGRESS_MASK
11579                   if (e->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE) {
11580 #else
11581                   if (e->ringing.progress == 8) {
11582 #endif
11583                      /* Now we can do call progress detection */
11584                      if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11585                         /* RINGING detection isn't required because we got ALERTING signal */
11586                         ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features & ~DSP_PROGRESS_RINGING);
11587                         pri->pvts[chanpos]->dsp_features = 0;
11588                      }
11589                   }
11590 
11591 #ifdef SUPPORT_USERUSER
11592                   if (!ast_strlen_zero(e->ringing.useruserinfo)) {
11593                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11594                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11595                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->ringing.useruserinfo);
11596                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11597                   }
11598 #endif
11599 
11600                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11601                }
11602             }
11603             break;
11604          case PRI_EVENT_PROGRESS:
11605             /* Get chan value if e->e is not PRI_EVNT_RINGING */
11606             chanpos = pri_find_principle(pri, e->proceeding.channel);
11607             if (chanpos > -1) {
11608 #ifdef PRI_PROGRESS_MASK
11609                if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)) {
11610 #else
11611                if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progress == 8)) {
11612 #endif
11613                   struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, };
11614 
11615                   if (e->proceeding.cause > -1) {
11616                      ast_verb(3, "PROGRESS with cause code %d received\n", e->proceeding.cause);
11617 
11618                      /* Work around broken, out of spec USER_BUSY cause in a progress message */
11619                      if (e->proceeding.cause == AST_CAUSE_USER_BUSY) {
11620                         if (pri->pvts[chanpos]->owner) {
11621                            ast_verb(3, "PROGRESS with 'user busy' received, signalling AST_CONTROL_BUSY instead of AST_CONTROL_PROGRESS\n");
11622 
11623                            pri->pvts[chanpos]->owner->hangupcause = e->proceeding.cause;
11624                            f.subclass = AST_CONTROL_BUSY;
11625                         }
11626                      }
11627                   }
11628                   
11629                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11630                   ast_debug(1, "Queuing frame from PRI_EVENT_PROGRESS on channel %d/%d span %d\n",
11631                      pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
11632                   dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11633 #ifdef PRI_PROGRESS_MASK
11634                   if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
11635 #else
11636                   if (e->proceeding.progress == 8) {
11637 #endif
11638                      /* Now we can do call progress detection */
11639                      if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11640                         ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
11641                         pri->pvts[chanpos]->dsp_features = 0;
11642                      }
11643                      /* Bring voice path up */
11644                      f.subclass = AST_CONTROL_PROGRESS;
11645                      dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11646                   }
11647                   pri->pvts[chanpos]->progress = 1;
11648                   pri->pvts[chanpos]->dialing = 0;
11649                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11650                }
11651             }
11652             break;
11653          case PRI_EVENT_PROCEEDING:
11654             chanpos = pri_find_principle(pri, e->proceeding.channel);
11655             if (chanpos > -1) {
11656                if (!pri->pvts[chanpos]->proceeding) {
11657                   struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
11658                   
11659                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11660                   ast_debug(1, "Queuing frame from PRI_EVENT_PROCEEDING on channel %d/%d span %d\n",
11661                      pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
11662                   dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11663 #ifdef PRI_PROGRESS_MASK
11664                   if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
11665 #else
11666                   if (e->proceeding.progress == 8) {
11667 #endif
11668                      /* Now we can do call progress detection */
11669                      if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11670                         ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
11671                         pri->pvts[chanpos]->dsp_features = 0;
11672                      }
11673                      /* Bring voice path up */
11674                      f.subclass = AST_CONTROL_PROGRESS;
11675                      dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11676                   }
11677                   pri->pvts[chanpos]->proceeding = 1;
11678                   pri->pvts[chanpos]->dialing = 0;
11679                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11680                }
11681             }
11682             break;
11683          case PRI_EVENT_FACNAME:
11684             chanpos = pri_find_principle(pri, e->facname.channel);
11685             if (chanpos < 0) {
11686                ast_log(LOG_WARNING, "Facility Name requested on unconfigured channel %d/%d span %d\n", 
11687                   PRI_SPAN(e->facname.channel), PRI_CHANNEL(e->facname.channel), pri->span);
11688             } else {
11689                chanpos = pri_fixup_principle(pri, chanpos, e->facname.call);
11690                if (chanpos < 0) {
11691                   ast_log(LOG_WARNING, "Facility Name requested on channel %d/%d not in use on span %d\n", 
11692                      PRI_SPAN(e->facname.channel), PRI_CHANNEL(e->facname.channel), pri->span);
11693                } else {
11694                   /* Re-use *69 field for PRI */
11695                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11696                   ast_copy_string(pri->pvts[chanpos]->lastcid_num, e->facname.callingnum, sizeof(pri->pvts[chanpos]->lastcid_num));
11697                   ast_copy_string(pri->pvts[chanpos]->lastcid_name, e->facname.callingname, sizeof(pri->pvts[chanpos]->lastcid_name));
11698                   pri->pvts[chanpos]->subs[SUB_REAL].needcallerid =1;
11699                   dahdi_enable_ec(pri->pvts[chanpos]);
11700                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11701                }
11702             }
11703             break;            
11704          case PRI_EVENT_ANSWER:
11705             chanpos = pri_find_principle(pri, e->answer.channel);
11706             if (chanpos < 0) {
11707                ast_log(LOG_WARNING, "Answer on unconfigured channel %d/%d span %d\n", 
11708                   PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
11709             } else {
11710                chanpos = pri_fixup_principle(pri, chanpos, e->answer.call);
11711                if (chanpos < 0) {
11712                   ast_log(LOG_WARNING, "Answer requested on channel %d/%d not in use on span %d\n", 
11713                      PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
11714                } else {
11715                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11716                   /* Now we can do call progress detection */
11717 
11718                   /* We changed this so it turns on the DSP no matter what... progress or no progress.
11719                    * By this time, we need DTMF detection and other features that were previously disabled
11720                    * -- Matt F */
11721                   if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11722                      ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
11723                      pri->pvts[chanpos]->dsp_features = 0;
11724                   }
11725                   if (pri->pvts[chanpos]->realcall && (pri->pvts[chanpos]->realcall->sig == SIG_FXSKS)) {
11726                      ast_debug(1, "Starting up GR-303 trunk now that we got CONNECT...\n");
11727                      x = DAHDI_START;
11728                      res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
11729                      if (res < 0) {
11730                         if (errno != EINPROGRESS) {
11731                            ast_log(LOG_WARNING, "Unable to start channel: %s\n", strerror(errno));
11732                         }
11733                      }
11734                   } else if (!ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) {
11735                      pri->pvts[chanpos]->dialing = 1;
11736                      /* Send any "w" waited stuff */
11737                      res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_DIAL, &pri->pvts[chanpos]->dop);
11738                      if (res < 0) {
11739                         ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", pri->pvts[chanpos]->channel, strerror(errno));
11740                         pri->pvts[chanpos]->dop.dialstr[0] = '\0';
11741                      } else
11742                         ast_debug(1, "Sent deferred digit string: %s\n", pri->pvts[chanpos]->dop.dialstr);
11743 
11744                      pri->pvts[chanpos]->dop.dialstr[0] = '\0';
11745                   } else if (pri->pvts[chanpos]->confirmanswer) {
11746                      ast_debug(1, "Waiting on answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel);
11747                   } else {
11748                      pri->pvts[chanpos]->dialing = 0;
11749                      pri->pvts[chanpos]->subs[SUB_REAL].needanswer =1;
11750                      /* Enable echo cancellation if it's not on already */
11751                      dahdi_enable_ec(pri->pvts[chanpos]);
11752                   }
11753 
11754 #ifdef SUPPORT_USERUSER
11755                   if (!ast_strlen_zero(e->answer.useruserinfo)) {
11756                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11757                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11758                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->answer.useruserinfo);
11759                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11760                   }
11761 #endif
11762 
11763                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11764                }
11765             }
11766             break;            
11767          case PRI_EVENT_HANGUP:
11768             chanpos = pri_find_principle(pri, e->hangup.channel);
11769             if (chanpos < 0) {
11770                ast_log(LOG_WARNING, "Hangup requested on unconfigured channel %d/%d span %d\n", 
11771                   PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11772             } else {
11773                chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
11774                if (chanpos > -1) {
11775                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11776                   if (!pri->pvts[chanpos]->alreadyhungup) {
11777                      /* we're calling here dahdi_hangup so once we get there we need to clear p->call after calling pri_hangup */
11778                      pri->pvts[chanpos]->alreadyhungup = 1;
11779                      if (pri->pvts[chanpos]->realcall) 
11780                         pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11781                      else if (pri->pvts[chanpos]->owner) {
11782                         /* Queue a BUSY instead of a hangup if our cause is appropriate */
11783                         pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
11784                         switch (pri->pvts[chanpos]->owner->_state) {
11785                         case AST_STATE_BUSY:
11786                         case AST_STATE_UP:
11787                            pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11788                            break;
11789                         default:
11790                            switch (e->hangup.cause) {
11791                            case PRI_CAUSE_USER_BUSY:
11792                               pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
11793                               break;
11794                            case PRI_CAUSE_CALL_REJECTED:
11795                            case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
11796                            case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
11797                            case PRI_CAUSE_SWITCH_CONGESTION:
11798                            case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
11799                            case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
11800                               pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
11801                               break;
11802                            default:
11803                               pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11804                            }
11805                            break;
11806                         }
11807                      }
11808                      ast_verb(3, "Channel %d/%d, span %d got hangup, cause %d\n",
11809                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, e->hangup.cause);
11810                   } else {
11811                      pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
11812                      pri->pvts[chanpos]->call = NULL;
11813                   }
11814                   if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
11815                      ast_verb(3, "Forcing restart of channel %d/%d on span %d since channel reported in use\n",
11816                            PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11817                      pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
11818                      pri->pvts[chanpos]->resetting = 1;
11819                   }
11820                   if (e->hangup.aoc_units > -1)
11821                      ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
11822                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
11823 
11824 #ifdef SUPPORT_USERUSER
11825                   if (pri->pvts[chanpos]->owner && !ast_strlen_zero(e->hangup.useruserinfo)) {
11826                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11827                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11828                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
11829                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11830                   }
11831 #endif
11832 
11833                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11834                } else {
11835                   ast_log(LOG_WARNING, "Hangup on bad channel %d/%d on span %d\n", 
11836                      PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11837                }
11838             } 
11839             break;
11840 #ifndef PRI_EVENT_HANGUP_REQ
11841 #error please update libpri
11842 #endif
11843          case PRI_EVENT_HANGUP_REQ:
11844             chanpos = pri_find_principle(pri, e->hangup.channel);
11845             if (chanpos < 0) {
11846                ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n", 
11847                   PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11848             } else {
11849                chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
11850                if (chanpos > -1) {
11851                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11852                   if (pri->pvts[chanpos]->realcall) 
11853                      pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11854                   else if (pri->pvts[chanpos]->owner) {
11855                      pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
11856                      switch (pri->pvts[chanpos]->owner->_state) {
11857                      case AST_STATE_BUSY:
11858                      case AST_STATE_UP:
11859                         pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11860                         break;
11861                      default:
11862                         switch (e->hangup.cause) {
11863                            case PRI_CAUSE_USER_BUSY:
11864                               pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
11865                               break;
11866                            case PRI_CAUSE_CALL_REJECTED:
11867                            case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
11868                            case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
11869                            case PRI_CAUSE_SWITCH_CONGESTION:
11870                            case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
11871                            case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
11872                               pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
11873                               break;
11874                            default:
11875                               pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11876                         }
11877                         break;
11878                      }
11879                      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);
11880                      if (e->hangup.aoc_units > -1)
11881                         ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
11882                               pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
11883                   } else {
11884                      pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
11885                      pri->pvts[chanpos]->call = NULL;
11886                   }
11887                   if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
11888                      ast_verb(3, "Forcing restart of channel %d/%d span %d since channel reported in use\n",
11889                            PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11890                      pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
11891                      pri->pvts[chanpos]->resetting = 1;
11892                   }
11893 
11894 #ifdef SUPPORT_USERUSER
11895                   if (!ast_strlen_zero(e->hangup.useruserinfo)) {
11896                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11897                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11898                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
11899                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11900                   }
11901 #endif
11902 
11903                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11904                } else {
11905                   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);
11906                }
11907             } 
11908             break;
11909          case PRI_EVENT_HANGUP_ACK:
11910             chanpos = pri_find_principle(pri, e->hangup.channel);
11911             if (chanpos < 0) {
11912                ast_log(LOG_WARNING, "Hangup ACK requested on unconfigured channel number %d/%d span %d\n", 
11913                   PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11914             } else {
11915                chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
11916                if (chanpos > -1) {
11917                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11918                   pri->pvts[chanpos]->call = NULL;
11919                   pri->pvts[chanpos]->resetting = 0;
11920                   if (pri->pvts[chanpos]->owner) {
11921                      ast_verb(3, "Channel %d/%d, span %d got hangup ACK\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11922                   }
11923 
11924 #ifdef SUPPORT_USERUSER
11925                   if (!ast_strlen_zero(e->hangup.useruserinfo)) {
11926                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11927                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11928                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
11929                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11930                   }
11931 #endif
11932 
11933                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11934                }
11935             }
11936             break;
11937          case PRI_EVENT_CONFIG_ERR:
11938             ast_log(LOG_WARNING, "PRI Error on span %d: %s\n", pri->trunkgroup, e->err.err);
11939             break;
11940          case PRI_EVENT_RESTART_ACK:
11941             chanpos = pri_find_principle(pri, e->restartack.channel);
11942             if (chanpos < 0) {
11943                /* Sometime switches (e.g. I421 / British Telecom) don't give us the
11944                   channel number, so we have to figure it out...  This must be why
11945                   everybody resets exactly a channel at a time. */
11946                for (x = 0; x < pri->numchans; x++) {
11947                   if (pri->pvts[x] && pri->pvts[x]->resetting) {
11948                      chanpos = x;
11949                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11950                      ast_debug(1, "Assuming restart ack is really for channel %d/%d span %d\n", pri->pvts[chanpos]->logicalspan, 
11951                         pri->pvts[chanpos]->prioffset, pri->span);
11952                      if (pri->pvts[chanpos]->realcall) 
11953                         pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11954                      else if (pri->pvts[chanpos]->owner) {
11955                         ast_log(LOG_WARNING, "Got restart ack on channel %d/%d with owner on span %d\n", pri->pvts[chanpos]->logicalspan, 
11956                            pri->pvts[chanpos]->prioffset, pri->span);
11957                         pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11958                      }
11959                      pri->pvts[chanpos]->resetting = 0;
11960                      ast_verb(3, "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
11961                            pri->pvts[chanpos]->prioffset, pri->span);
11962                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11963                      if (pri->resetting)
11964                         pri_check_restart(pri);
11965                      break;
11966                   }
11967                }
11968                if (chanpos < 0) {
11969                   ast_log(LOG_WARNING, "Restart ACK requested on strange channel %d/%d span %d\n", 
11970                      PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
11971                }
11972             } else {
11973                if (pri->pvts[chanpos]) {
11974                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11975                   if (pri->pvts[chanpos]->realcall) 
11976                      pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11977                   else if (pri->pvts[chanpos]->owner) {
11978                      ast_log(LOG_WARNING, "Got restart ack on channel %d/%d span %d with owner\n",
11979                         PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
11980                      pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11981                   }
11982                   pri->pvts[chanpos]->resetting = 0;
11983                   pri->pvts[chanpos]->inservice = 1;
11984                   ast_verb(3, "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
11985                            pri->pvts[chanpos]->prioffset, pri->span);
11986                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11987                   if (pri->resetting)
11988                      pri_check_restart(pri);
11989                }
11990             }
11991             break;
11992          case PRI_EVENT_SETUP_ACK:
11993             chanpos = pri_find_principle(pri, e->setup_ack.channel);
11994             if (chanpos < 0) {
11995                ast_log(LOG_WARNING, "Received SETUP_ACKNOWLEDGE on unconfigured channel %d/%d span %d\n", 
11996                   PRI_SPAN(e->setup_ack.channel), PRI_CHANNEL(e->setup_ack.channel), pri->span);
11997             } else {
11998                chanpos = pri_fixup_principle(pri, chanpos, e->setup_ack.call);
11999                if (chanpos > -1) {
12000                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
12001                   pri->pvts[chanpos]->setup_ack = 1;
12002                   /* Send any queued digits */
12003                   for (x = 0;x < strlen(pri->pvts[chanpos]->dialdest); x++) {
12004                      ast_debug(1, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]);
12005                      pri_information(pri->pri, pri->pvts[chanpos]->call, 
12006                         pri->pvts[chanpos]->dialdest[x]);
12007                   }
12008                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
12009                } else
12010                   ast_log(LOG_WARNING, "Unable to move channel %d!\n", e->setup_ack.channel);
12011             }
12012             break;
12013          case PRI_EVENT_NOTIFY:
12014             chanpos = pri_find_principle(pri, e->notify.channel);
12015             if (chanpos < 0) {
12016                ast_log(LOG_WARNING, "Received NOTIFY on unconfigured channel %d/%d span %d\n",
12017                   PRI_SPAN(e->notify.channel), PRI_CHANNEL(e->notify.channel), pri->span);
12018             } else {
12019                struct ast_frame f = { AST_FRAME_CONTROL, };
12020                ast_mutex_lock(&pri->pvts[chanpos]->lock);
12021                switch (e->notify.info) {
12022                case PRI_NOTIFY_REMOTE_HOLD:
12023                   f.subclass = AST_CONTROL_HOLD;
12024                   dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
12025                   break;
12026                case PRI_NOTIFY_REMOTE_RETRIEVAL:
12027                   f.subclass = AST_CONTROL_UNHOLD;
12028                   dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
12029                   break;
12030                }
12031                ast_mutex_unlock(&pri->pvts[chanpos]->lock);
12032             }
12033             break;
12034          default:
12035             ast_debug(1, "Event: %d\n", e->e);
12036          }
12037       }  
12038       ast_mutex_unlock(&pri->lock);
12039    }
12040    /* Never reached */
12041    return NULL;
12042 }
12043 
12044 static int start_pri(struct dahdi_pri *pri)
12045 {
12046    int res, x;
12047    struct dahdi_params p;
12048    struct dahdi_bufferinfo bi;
12049    struct dahdi_spaninfo si;
12050    int i;
12051    
12052    for (i = 0; i < NUM_DCHANS; i++) {
12053       if (!pri->dchannels[i])
12054          break;
12055       pri->fds[i] = open("/dev/dahdi/channel", O_RDWR);
12056       x = pri->dchannels[i];
12057       if ((pri->fds[i] < 0) || (ioctl(pri->fds[i],DAHDI_SPECIFY,&x) == -1)) {
12058          ast_log(LOG_ERROR, "Unable to open D-channel %d (%s)\n", x, strerror(errno));
12059          return -1;
12060       }
12061       memset(&p, 0, sizeof(p));
12062       res = ioctl(pri->fds[i], DAHDI_GET_PARAMS, &p);
12063       if (res) {
12064          dahdi_close_pri_fd(pri, i);
12065          ast_log(LOG_ERROR, "Unable to get parameters for D-channel %d (%s)\n", x, strerror(errno));
12066          return -1;
12067       }
12068       if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC)) {
12069          dahdi_close_pri_fd(pri, i);
12070          ast_log(LOG_ERROR, "D-channel %d is not in HDLC/FCS mode.\n", x);
12071          return -1;
12072       }
12073       memset(&si, 0, sizeof(si));
12074       res = ioctl(pri->fds[i], DAHDI_SPANSTAT, &si);
12075       if (res) {
12076          dahdi_close_pri_fd(pri, i);
12077          ast_log(LOG_ERROR, "Unable to get span state for D-channel %d (%s)\n", x, strerror(errno));
12078       }
12079       if (!si.alarms)
12080          pri->dchanavail[i] |= DCHAN_NOTINALARM;
12081       else
12082          pri->dchanavail[i] &= ~DCHAN_NOTINALARM;
12083       memset(&bi, 0, sizeof(bi));
12084       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
12085       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
12086       bi.numbufs = 32;
12087       bi.bufsize = 1024;
12088       if (ioctl(pri->fds[i], DAHDI_SET_BUFINFO, &bi)) {
12089          ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", x, strerror(errno));
12090          dahdi_close_pri_fd(pri, i);
12091          return -1;
12092       }
12093       switch (pri->sig) {
12094          case SIG_BRI:
12095             pri->dchans[i] = pri_new_bri(pri->fds[i], 1, pri->nodetype, pri->switchtype);
12096             break;
12097          case SIG_BRI_PTMP:
12098             pri->dchans[i] = pri_new_bri(pri->fds[i], 0, pri->nodetype, pri->switchtype);
12099             break;
12100          default:
12101             pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype);
12102       }
12103       /* Force overlap dial if we're doing GR-303! */
12104       if (pri->switchtype == PRI_SWITCH_GR303_TMC)
12105          pri->overlapdial |= DAHDI_OVERLAPDIAL_BOTH;
12106       pri_set_overlapdial(pri->dchans[i],(pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)?1:0);
12107 #ifdef HAVE_PRI_INBANDDISCONNECT
12108       pri_set_inbanddisconnect(pri->dchans[i], pri->inbanddisconnect);
12109 #endif
12110       /* Enslave to master if appropriate */
12111       if (i)
12112          pri_enslave(pri->dchans[0], pri->dchans[i]);
12113       if (!pri->dchans[i]) {
12114          dahdi_close_pri_fd(pri, i);
12115          ast_log(LOG_ERROR, "Unable to create PRI structure\n");
12116          return -1;
12117       }
12118       pri_set_debug(pri->dchans[i], DEFAULT_PRI_DEBUG);
12119       pri_set_nsf(pri->dchans[i], pri->nsf);
12120 #ifdef PRI_GETSET_TIMERS
12121       for (x = 0; x < PRI_MAX_TIMERS; x++) {
12122          if (pritimers[x] != 0)
12123             pri_set_timer(pri->dchans[i], x, pritimers[x]);
12124       }
12125 #endif
12126    }
12127    /* Assume primary is the one we use */
12128    pri->pri = pri->dchans[0];
12129    pri->resetpos = -1;
12130    if (ast_pthread_create_background(&pri->master, NULL, pri_dchannel, pri)) {
12131       for (i = 0; i < NUM_DCHANS; i++) {
12132          if (!pri->dchannels[i])
12133             break;
12134          dahdi_close_pri_fd(pri, i);
12135       }
12136       ast_log(LOG_ERROR, "Unable to spawn D-channel: %s\n", strerror(errno));
12137       return -1;
12138    }
12139    return 0;
12140 }
12141 
12142 static char *complete_span_helper(const char *line, const char *word, int pos, int state, int rpos)
12143 {
12144    int which, span;
12145    char *ret = NULL;
12146 
12147    if (pos != rpos)
12148       return ret;
12149 
12150    for (which = span = 0; span < NUM_SPANS; span++) {
12151       if (pris[span].pri && ++which > state) {
12152          if (asprintf(&ret, "%d", span + 1) < 0) { /* user indexes start from 1 */
12153             ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
12154          }
12155          break;
12156       }
12157    }
12158    return ret;
12159 }
12160 
12161 static char *complete_span_4(const char *line, const char *word, int pos, int state)
12162 {
12163    return complete_span_helper(line,word,pos,state,3);
12164 }
12165 
12166 static char *complete_span_5(const char *line, const char *word, int pos, int state)
12167 {
12168    return complete_span_helper(line,word,pos,state,4);
12169 }
12170 
12171 static char *handle_pri_unset_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12172 {
12173    switch (cmd) {
12174    case CLI_INIT:
12175       e->command = "pri unset debug file";
12176       e->usage = "Usage: pri unset debug file\n"
12177             "       Stop sending debug output to the previously \n"
12178                  "       specified file\n";
12179       return NULL;
12180    case CLI_GENERATE:
12181       return NULL;   
12182    }
12183    /* Assume it is unset */
12184    ast_mutex_lock(&pridebugfdlock);
12185    close(pridebugfd);
12186    pridebugfd = -1;
12187    ast_cli(a->fd, "PRI debug output to file disabled\n");
12188    ast_mutex_unlock(&pridebugfdlock);
12189    return CLI_SUCCESS;
12190 }
12191 
12192 static char *handle_pri_set_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12193 {
12194    int myfd;
12195    switch (cmd) {
12196    case CLI_INIT:
12197       e->command = "pri set debug file";
12198       e->usage = "Usage: pri set debug file [output-file]\n"
12199             "       Sends PRI debug output to the specified output file\n";
12200       return NULL;
12201    case CLI_GENERATE:
12202       return NULL;   
12203    }
12204    if (a->argc < 5)
12205       return CLI_SHOWUSAGE;
12206 
12207    if (ast_strlen_zero(a->argv[4]))
12208       return CLI_SHOWUSAGE;
12209 
12210    myfd = open(a->argv[4], O_CREAT|O_WRONLY, AST_FILE_MODE);
12211    if (myfd < 0) {
12212       ast_cli(a->fd, "Unable to open '%s' for writing\n", a->argv[4]);
12213       return CLI_SUCCESS;
12214    }
12215 
12216    ast_mutex_lock(&pridebugfdlock);
12217 
12218    if (pridebugfd >= 0)
12219       close(pridebugfd);
12220 
12221    pridebugfd = myfd;
12222    ast_copy_string(pridebugfilename,a->argv[4],sizeof(pridebugfilename));
12223    ast_mutex_unlock(&pridebugfdlock);
12224    ast_cli(a->fd, "PRI debug output will be sent to '%s'\n", a->argv[4]);
12225    return CLI_SUCCESS;
12226 }
12227 
12228 static char *handle_pri_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12229 {
12230    int span;
12231    int x;
12232    switch (cmd) {
12233    case CLI_INIT: 
12234       e->command = "pri debug span";
12235       e->usage = 
12236          "Usage: pri debug span <span>\n"
12237          "       Enables debugging on a given PRI span\n";
12238       return NULL;
12239    case CLI_GENERATE:   
12240       return complete_span_4(a->line, a->word, a->pos, a->n);
12241    }
12242    if (a->argc < 4) {
12243       return CLI_SHOWUSAGE;
12244    }
12245    span = atoi(a->argv[3]);
12246    if ((span < 1) || (span > NUM_SPANS)) {
12247       ast_cli(a->fd, "Invalid span %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
12248       return CLI_SUCCESS;
12249    }
12250    if (!pris[span-1].pri) {
12251       ast_cli(a->fd, "No PRI running on span %d\n", span);
12252       return CLI_SUCCESS;
12253    }
12254    for (x = 0; x < NUM_DCHANS; x++) {
12255       if (pris[span-1].dchans[x])
12256          pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU |
12257                                                PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE |
12258                                                PRI_DEBUG_Q921_STATE);
12259    }
12260    ast_cli(a->fd, "Enabled debugging on span %d\n", span);
12261    return CLI_SUCCESS;
12262 }
12263 
12264 
12265 
12266 static char *handle_pri_no_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12267 {
12268    int span;
12269    int x;
12270    switch (cmd) {
12271    case CLI_INIT:
12272       e->command = "pri no debug span";
12273       e->usage = 
12274          "Usage: pri no debug span <span>\n"
12275          "       Disables debugging on a given PRI span\n";
12276       return NULL;
12277    case CLI_GENERATE:
12278       return complete_span_5(a->line, a->word, a->pos, a->n);
12279    }
12280    if (a->argc < 5)
12281       return CLI_SHOWUSAGE;
12282 
12283    span = atoi(a->argv[4]);
12284    if ((span < 1) || (span > NUM_SPANS)) {
12285       ast_cli(a->fd, "Invalid span %s.  Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
12286       return CLI_SUCCESS;
12287    }
12288    if (!pris[span-1].pri) {
12289       ast_cli(a->fd, "No PRI running on span %d\n", span);
12290       return CLI_SUCCESS;
12291    }
12292    for (x = 0; x < NUM_DCHANS; x++) {
12293       if (pris[span-1].dchans[x])
12294          pri_set_debug(pris[span-1].dchans[x], 0);
12295    }
12296    ast_cli(a->fd, "Disabled debugging on span %d\n", span);
12297    return CLI_SUCCESS;
12298 }
12299 
12300 static char *handle_pri_really_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12301 {
12302    int span;
12303    int x;
12304    switch (cmd) {
12305    case CLI_INIT:
12306       e->command = "pri intensive debug span";
12307       e->usage = 
12308          "Usage: pri intensive debug span <span>\n"
12309          "       Enables debugging down to the Q.921 level\n";
12310       return NULL;
12311    case CLI_GENERATE:
12312       return complete_span_5(a->line, a->word, a->pos, a->n);
12313    }
12314 
12315    if (a->argc < 5)
12316       return CLI_SHOWUSAGE;
12317    span = atoi(a->argv[4]);
12318    if ((span < 1) || (span > NUM_SPANS)) {
12319       ast_cli(a->fd, "Invalid span %s.  Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
12320       return CLI_SUCCESS;
12321    }
12322    if (!pris[span-1].pri) {
12323       ast_cli(a->fd, "No PRI running on span %d\n", span);
12324       return CLI_SUCCESS;
12325    }
12326    for (x = 0; x < NUM_DCHANS; x++) {
12327       if (pris[span-1].dchans[x])
12328          pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU |
12329                                                PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE |
12330                                                PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_STATE);
12331    }
12332    ast_cli(a->fd, "Enabled EXTENSIVE debugging on span %d\n", span);
12333    return CLI_SUCCESS;
12334 }
12335 
12336 static void build_status(char *s, size_t len, int status, int active)
12337 {
12338    if (!s || len < 1) {
12339       return;
12340    }
12341    s[0] = '\0';
12342    if (status & DCHAN_PROVISIONED)
12343       strncat(s, "Provisioned, ", len - strlen(s) - 1);
12344    if (!(status & DCHAN_NOTINALARM))
12345       strncat(s, "In Alarm, ", len - strlen(s) - 1);
12346    if (status & DCHAN_UP)
12347       strncat(s, "Up", len - strlen(s) - 1);
12348    else
12349       strncat(s, "Down", len - strlen(s) - 1);
12350    if (active)
12351       strncat(s, ", Active", len - strlen(s) - 1);
12352    else
12353       strncat(s, ", Standby", len - strlen(s) - 1);
12354    s[len - 1] = '\0';
12355 }
12356 
12357 static char *handle_pri_show_spans(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12358 {
12359    int span;
12360    int x;
12361    char status[256];
12362 
12363    switch (cmd) {
12364    case CLI_INIT:
12365       e->command = "pri show spans";
12366       e->usage = 
12367          "Usage: pri show spans\n"
12368          "       Displays PRI Information\n";
12369       return NULL;
12370    case CLI_GENERATE:
12371       return NULL;   
12372    }
12373 
12374    if (a->argc != 3)
12375       return CLI_SHOWUSAGE;
12376 
12377    for (span = 0; span < NUM_SPANS; span++) {
12378       if (pris[span].pri) {
12379          for (x = 0; x < NUM_DCHANS; x++) {
12380             if (pris[span].dchannels[x]) {
12381                build_status(status, sizeof(status), pris[span].dchanavail[x], pris[span].dchans[x] == pris[span].pri);
12382                ast_cli(a->fd, "PRI span %d/%d: %s\n", span + 1, x, status);
12383             }
12384          }
12385       }
12386    }
12387    return CLI_SUCCESS;
12388 }
12389 
12390 static char *handle_pri_show_span(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12391 {
12392    int span;
12393    int x;
12394    char status[256];
12395    switch (cmd) {
12396    case CLI_INIT: 
12397       e->command = "pri show span";
12398       e->usage = 
12399          "Usage: pri show span <span>\n"
12400          "       Displays PRI Information on a given PRI span\n";
12401       return NULL;
12402    case CLI_GENERATE:
12403       return complete_span_4(a->line, a->word, a->pos, a->n);
12404    }
12405 
12406    if (a->argc < 4)
12407       return CLI_SHOWUSAGE;
12408    span = atoi(a->argv[3]);
12409    if ((span < 1) || (span > NUM_SPANS)) {
12410       ast_cli(a->fd, "Invalid span '%s'.  Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS);
12411       return CLI_SUCCESS;
12412    }
12413    if (!pris[span-1].pri) {
12414       ast_cli(a->fd, "No PRI running on span %d\n", span);
12415       return CLI_SUCCESS;
12416    }
12417    for (x = 0; x < NUM_DCHANS; x++) {
12418       if (pris[span-1].dchannels[x]) {
12419 #ifdef PRI_DUMP_INFO_STR
12420          char *info_str = NULL;
12421 #endif
12422          ast_cli(a->fd, "%s D-channel: %d\n", pri_order(x), pris[span-1].dchannels[x]);
12423          build_status(status, sizeof(status), pris[span-1].dchanavail[x], pris[span-1].dchans[x] == pris[span-1].pri);
12424          ast_cli(a->fd, "Status: %s\n", status);
12425 #ifdef PRI_DUMP_INFO_STR
12426          info_str = pri_dump_info_str(pris[span-1].pri);
12427          if (info_str) {
12428             ast_cli(a->fd, "%s", info_str);
12429             ast_free(info_str);
12430          }
12431 #else
12432          pri_dump_info(pris[span-1].pri);
12433 #endif
12434          ast_cli(a->fd, "Overlap Recv: %s\n\n", (pris[span-1].overlapdial & DAHDI_OVERLAPDIAL_INCOMING)?"Yes":"No");
12435       }
12436    }
12437    return CLI_SUCCESS;
12438 }
12439 
12440 static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12441 {
12442    int x;
12443    int span;
12444    int count=0;
12445    int debug=0;
12446 
12447    switch (cmd) {
12448    case CLI_INIT: 
12449       e->command = "pri show debug";
12450       e->usage = 
12451          "Usage: pri show debug\n"
12452          "  Show the debug state of pri spans\n";
12453       return NULL;
12454    case CLI_GENERATE:
12455       return NULL;   
12456    }
12457 
12458    for (span = 0; span < NUM_SPANS; span++) {
12459            if (pris[span].pri) {
12460          for (x = 0; x < NUM_DCHANS; x++) {
12461             debug = 0;
12462                if (pris[span].dchans[x]) {
12463                   debug = pri_get_debug(pris[span].dchans[x]);
12464                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" );
12465                count++;
12466             }
12467          }
12468       }
12469 
12470    }
12471    ast_mutex_lock(&pridebugfdlock);
12472    if (pridebugfd >= 0) 
12473       ast_cli(a->fd, "Logging PRI debug to file %s\n", pridebugfilename);
12474    ast_mutex_unlock(&pridebugfdlock);
12475        
12476    if (!count) 
12477       ast_cli(a->fd, "No debug set or no PRI running\n");
12478    return CLI_SUCCESS;
12479 }
12480 
12481 static char *handle_pri_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12482 {
12483    switch (cmd) {
12484    case CLI_INIT:
12485       e->command = "pri show version";
12486       e->usage = 
12487          "Usage: pri show version\n"
12488          "Show libpri version information\n";
12489       return NULL;
12490    case CLI_GENERATE:
12491       return NULL;
12492    }
12493 
12494    ast_cli(a->fd, "libpri version: %s\n", pri_get_version());
12495 
12496    return CLI_SUCCESS;
12497 }
12498 
12499 static struct ast_cli_entry dahdi_pri_cli[] = {
12500    AST_CLI_DEFINE(handle_pri_debug, "Enables PRI debugging on a span"),
12501    AST_CLI_DEFINE(handle_pri_no_debug, "Disables PRI debugging on a span"),
12502    AST_CLI_DEFINE(handle_pri_really_debug, "Enables REALLY INTENSE PRI debugging"),
12503    AST_CLI_DEFINE(handle_pri_show_spans, "Displays PRI Information"),
12504    AST_CLI_DEFINE(handle_pri_show_span, "Displays PRI Information"),
12505    AST_CLI_DEFINE(handle_pri_show_debug, "Displays current PRI debug settings"),
12506    AST_CLI_DEFINE(handle_pri_set_debug_file, "Sends PRI debug output to the specified file"),
12507    AST_CLI_DEFINE(handle_pri_unset_debug_file, "Ends PRI debug output to file"),
12508    AST_CLI_DEFINE(handle_pri_version, "Displays libpri version"),
12509 };
12510 
12511 #endif /* HAVE_PRI */
12512 
12513 static char *dahdi_destroy_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12514 {
12515    int channel;
12516    int ret;
12517    switch (cmd) {
12518    case CLI_INIT:
12519       e->command = "dahdi destroy channel";
12520       e->usage = 
12521          "Usage: dahdi destroy channel <chan num>\n"
12522          "  DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.  Immediately removes a given channel, whether it is in use or not\n";
12523       return NULL;
12524    case CLI_GENERATE:
12525       return NULL;   
12526    }
12527    if (a->argc != 4)
12528       return CLI_SHOWUSAGE;
12529    
12530    channel = atoi(a->argv[3]);
12531    ret = dahdi_destroy_channel_bynum(channel);
12532    return ( RESULT_SUCCESS == ret ) ? CLI_SUCCESS : CLI_FAILURE;
12533 }
12534 
12535 static void dahdi_softhangup_all(void)
12536 {
12537    struct dahdi_pvt *p;
12538 retry:
12539    ast_mutex_lock(&iflock);
12540     for (p = iflist; p; p = p->next) {
12541       ast_mutex_lock(&p->lock);
12542         if (p->owner && !p->restartpending) {
12543          if (ast_channel_trylock(p->owner)) {
12544             if (option_debug > 2)
12545                ast_verbose("Avoiding deadlock\n");
12546             /* Avoid deadlock since you're not supposed to lock iflock or pvt before a channel */
12547             ast_mutex_unlock(&p->lock);
12548             ast_mutex_unlock(&iflock);
12549             goto retry;
12550          }
12551          if (option_debug > 2)
12552             ast_verbose("Softhanging up on %s\n", p->owner->name);
12553          ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_EXPLICIT);
12554          p->restartpending = 1;
12555          num_restart_pending++;
12556          ast_channel_unlock(p->owner);
12557       }
12558       ast_mutex_unlock(&p->lock);
12559     }
12560    ast_mutex_unlock(&iflock);
12561 }
12562 
12563 static int setup_dahdi(int reload);
12564 static int dahdi_restart(void)
12565 {
12566 #if defined(HAVE_PRI) || defined(HAVE_SS7)
12567    int i, j;
12568 #endif
12569    int cancel_code;
12570    struct dahdi_pvt *p;
12571 
12572    ast_mutex_lock(&restart_lock);
12573 
12574    ast_verb(1, "Destroying channels and reloading DAHDI configuration.\n");
12575    dahdi_softhangup_all();
12576    ast_verb(4, "Initial softhangup of all DAHDI channels complete.\n");
12577 
12578 #if defined(HAVE_PRI)
12579    for (i = 0; i < NUM_SPANS; i++) {
12580       if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL)) {
12581          cancel_code = pthread_cancel(pris[i].master);
12582          pthread_kill(pris[i].master, SIGURG);
12583          ast_debug(4, "Waiting to join thread of span %d with pid=%p, cancel_code=%d\n", i, (void *) pris[i].master, cancel_code);
12584          pthread_join(pris[i].master, NULL);
12585          ast_debug(4, "Joined thread of span %d\n", i);
12586       }
12587    }
12588 #endif
12589 
12590 #if defined(HAVE_SS7)
12591    for (i = 0; i < NUM_SPANS; i++) {
12592       if (linksets[i].master && (linksets[i].master != AST_PTHREADT_NULL)) {
12593          cancel_code = pthread_cancel(linksets[i].master);
12594          pthread_kill(linksets[i].master, SIGURG);
12595          ast_debug(4, "Waiting to join thread of span %d with pid=%p, cancel_code=%d\n", i, (void *) linksets[i].master, cancel_code);
12596          pthread_join(linksets[i].master, NULL);
12597          ast_debug(4, "Joined thread of span %d\n", i);
12598       }
12599     }
12600 #endif
12601 
12602    ast_mutex_lock(&monlock);
12603    if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
12604       cancel_code = pthread_cancel(monitor_thread);
12605       pthread_kill(monitor_thread, SIGURG);
12606       ast_debug(4, "Waiting to join monitor thread with pid=%p, cancel_code=%d\n", (void *) monitor_thread, cancel_code);
12607       pthread_join(monitor_thread, NULL);
12608       ast_debug(4, "Joined monitor thread\n");
12609    }
12610    monitor_thread = AST_PTHREADT_NULL; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
12611 
12612    ast_mutex_lock(&mwi_thread_lock);
12613    while (mwi_thread_count > 0) {
12614       ast_debug(3, "Waiting on %d mwi_send_thread(s) to finish\n", mwi_thread_count);
12615       ast_cond_wait(&mwi_thread_complete, &mwi_thread_lock);
12616    }
12617    ast_mutex_unlock(&mwi_thread_lock);
12618    ast_mutex_lock(&ss_thread_lock);
12619    while (ss_thread_count > 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
12620       int x = DAHDI_FLASH;
12621       ast_debug(3, "Waiting on %d ss_thread(s) to finish\n", ss_thread_count);
12622 
12623       for (p = iflist; p; p = p->next) {
12624          if (p->owner)
12625             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 */      
12626          }
12627          ast_cond_wait(&ss_thread_complete, &ss_thread_lock);
12628       }
12629 
12630    /* ensure any created channels before monitor threads were stopped are hungup */
12631    dahdi_softhangup_all();
12632    ast_verb(4, "Final softhangup of all DAHDI channels complete.\n");
12633    destroy_all_channels();
12634    ast_debug(1, "Channels destroyed. Now re-reading config. %d active channels remaining.\n", ast_active_channels());
12635 
12636    ast_mutex_unlock(&monlock);
12637 
12638 #ifdef HAVE_PRI
12639    for (i = 0; i < NUM_SPANS; i++) {
12640       for (j = 0; j < NUM_DCHANS; j++)
12641          dahdi_close_pri_fd(&(pris[i]), j);
12642    }
12643 
12644    memset(pris, 0, sizeof(pris));
12645    for (i = 0; i < NUM_SPANS; i++) {
12646       ast_mutex_init(&pris[i].lock);
12647       pris[i].offset = -1;
12648       pris[i].master = AST_PTHREADT_NULL;
12649       for (j = 0; j < NUM_DCHANS; j++)
12650          pris[i].fds[j] = -1;
12651       }
12652    pri_set_error(dahdi_pri_error);
12653    pri_set_message(dahdi_pri_message);
12654 #endif
12655 #ifdef HAVE_SS7
12656    for (i = 0; i < NUM_SPANS; i++) {
12657       for (j = 0; j < NUM_DCHANS; j++)
12658          dahdi_close_ss7_fd(&(linksets[i]), j);
12659    }
12660 
12661    memset(linksets, 0, sizeof(linksets));
12662    for (i = 0; i < NUM_SPANS; i++) {
12663       ast_mutex_init(&linksets[i].lock);
12664       linksets[i].master = AST_PTHREADT_NULL;
12665       for (j = 0; j < NUM_DCHANS; j++)
12666          linksets[i].fds[j] = -1;
12667    }
12668    ss7_set_error(dahdi_ss7_error);
12669    ss7_set_message(dahdi_ss7_message);
12670 #endif
12671 
12672    if (setup_dahdi(2) != 0) {
12673       ast_log(LOG_WARNING, "Reload channels from dahdi config failed!\n");
12674       ast_mutex_unlock(&ss_thread_lock);
12675       return 1;
12676    }
12677    ast_mutex_unlock(&ss_thread_lock);
12678    ast_mutex_unlock(&restart_lock);
12679    return 0;
12680 }
12681 
12682 static char *dahdi_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12683 {
12684    switch (cmd) {
12685    case CLI_INIT:
12686       e->command = "dahdi restart";
12687       e->usage = 
12688          "Usage: dahdi restart\n"
12689          "  Restarts the DAHDI channels: destroys them all and then\n"
12690          "  re-reads them from chan_dahdi.conf.\n"
12691          "  Note that this will STOP any running CALL on DAHDI channels.\n"
12692          "";
12693       return NULL;
12694    case CLI_GENERATE:
12695       return NULL;
12696    }
12697    if (a->argc != 2)
12698       return CLI_SHOWUSAGE;
12699 
12700    if (dahdi_restart() != 0)
12701       return CLI_FAILURE;
12702    return CLI_SUCCESS;
12703 }
12704 
12705 static int action_dahdirestart(struct mansession *s, const struct message *m)
12706 {
12707    if (dahdi_restart() != 0) {
12708       astman_send_error(s, m, "Failed rereading DAHDI configuration");
12709       return 1;
12710    }
12711    astman_send_ack(s, m, "DAHDIRestart: Success");
12712    return 0;
12713 }
12714 
12715 static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12716 {
12717 #define FORMAT "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
12718 #define FORMAT2 "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
12719    unsigned int targetnum = 0;
12720    int filtertype = 0;
12721    struct dahdi_pvt *tmp = NULL;
12722    char tmps[20] = "";
12723    char statestr[20] = "";
12724    char blockstr[20] = "";
12725    ast_mutex_t *lock;
12726    struct dahdi_pvt *start;
12727 #ifdef HAVE_PRI
12728    int trunkgroup;
12729    struct dahdi_pri *pri = NULL;
12730    int x;
12731 #endif
12732    switch (cmd) {
12733    case CLI_INIT:
12734       e->command = "dahdi show channels [trunkgroup|group|context]";
12735       e->usage = 
12736          "Usage: dahdi show channels [ trunkgroup <trunkgroup> | group <group> | context <context> ]\n"
12737          "  Shows a list of available channels with optional filtering\n"
12738          "  <group> must be a number between 0 and 63\n";
12739       return NULL;
12740    case CLI_GENERATE:
12741       return NULL;   
12742    }
12743 
12744    lock = &iflock;
12745    start = iflist;
12746 
12747    /* syntax: dahdi show channels [ group <group> | context <context> | trunkgroup <trunkgroup> ] */
12748 
12749    if (!((a->argc == 3) || (a->argc == 5)))
12750       return CLI_SHOWUSAGE;
12751 
12752    if (a->argc == 5) {
12753 #ifdef HAVE_PRI
12754       if (!strcasecmp(a->argv[3], "trunkgroup")) {
12755          /* this option requires no special handling, so leave filtertype to zero */
12756          if ((trunkgroup = atoi(a->argv[4])) < 1)
12757             return CLI_SHOWUSAGE;
12758          for (x = 0; x < NUM_SPANS; x++) {
12759             if (pris[x].trunkgroup == trunkgroup) {
12760                pri = pris + x;
12761                break;
12762             }
12763          }
12764          if (pri) {
12765             start = pri->crvs;
12766             lock = &pri->lock;
12767          } else {
12768             ast_cli(a->fd, "No such trunk group %d\n", trunkgroup);
12769             return CLI_FAILURE;
12770          }
12771       } else
12772 #endif   
12773       if (!strcasecmp(a->argv[3], "group")) {
12774          targetnum = atoi(a->argv[4]);
12775          if ((targetnum < 0) || (targetnum > 63))
12776             return CLI_SHOWUSAGE;
12777          targetnum = 1 << targetnum;
12778          filtertype = 1;
12779       } else if (!strcasecmp(a->argv[3], "context")) {
12780          filtertype = 2;
12781       }
12782    }
12783 
12784    ast_mutex_lock(lock);
12785 #ifdef HAVE_PRI
12786    ast_cli(a->fd, FORMAT2, pri ? "CRV" : "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State");
12787 #else
12788    ast_cli(a->fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State");
12789 #endif   
12790    
12791    tmp = start;
12792    while (tmp) {
12793       if (filtertype) {
12794          switch(filtertype) {
12795          case 1: /* dahdi show channels group <group> */
12796             if (!(tmp->group & targetnum)) {
12797                tmp = tmp->next;
12798                continue;
12799             }
12800             break;
12801          case 2: /* dahdi show channels context <context> */
12802             if (strcasecmp(tmp->context, a->argv[4])) {
12803                tmp = tmp->next;
12804                continue;
12805             }
12806             break;
12807          default:
12808             ;
12809          }
12810       }
12811       if (tmp->channel > 0) {
12812          snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
12813       } else
12814          ast_copy_string(tmps, "pseudo", sizeof(tmps));
12815 
12816       if (tmp->locallyblocked)
12817          blockstr[0] = 'L';
12818       else
12819          blockstr[0] = ' ';
12820 
12821       if (tmp->remotelyblocked)
12822          blockstr[1] = 'R';
12823       else
12824          blockstr[1] = ' ';
12825 
12826       blockstr[2] = '\0';
12827 
12828       snprintf(statestr, sizeof(statestr), "%s", "In Service");
12829 
12830       ast_cli(a->fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, statestr);
12831       tmp = tmp->next;
12832    }
12833    ast_mutex_unlock(lock);
12834    return CLI_SUCCESS;
12835 #undef FORMAT
12836 #undef FORMAT2
12837 }
12838 
12839 static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12840 {
12841    int channel;
12842    struct dahdi_pvt *tmp = NULL;
12843    struct dahdi_confinfo ci;
12844    struct dahdi_params ps;
12845    int x;
12846    ast_mutex_t *lock;
12847    struct dahdi_pvt *start;
12848 #ifdef HAVE_PRI
12849    char *c;
12850    int trunkgroup;
12851    struct dahdi_pri *pri=NULL;
12852 #endif
12853    switch (cmd) {
12854    case CLI_INIT:
12855       e->command = "dahdi show channel";
12856       e->usage = 
12857          "Usage: dahdi show channel <chan num>\n"
12858          "  Detailed information about a given channel\n";
12859       return NULL;
12860    case CLI_GENERATE:
12861       return NULL;   
12862    }
12863 
12864    lock = &iflock;
12865    start = iflist;
12866 
12867    if (a->argc != 4)
12868       return CLI_SHOWUSAGE;
12869 #ifdef HAVE_PRI
12870    if ((c = strchr(a->argv[3], ':'))) {
12871       if (sscanf(a->argv[3], "%30d:%30d", &trunkgroup, &channel) != 2)
12872          return CLI_SHOWUSAGE;
12873       if ((trunkgroup < 1) || (channel < 1))
12874          return CLI_SHOWUSAGE;
12875       for (x = 0; x < NUM_SPANS; x++) {
12876          if (pris[x].trunkgroup == trunkgroup) {
12877             pri = pris + x;
12878             break;
12879          }
12880       }
12881       if (pri) {
12882          start = pri->crvs;
12883          lock = &pri->lock;
12884       } else {
12885          ast_cli(a->fd, "No such trunk group %d\n", trunkgroup);
12886          return CLI_FAILURE;
12887       }
12888    } else
12889 #endif
12890       channel = atoi(a->argv[3]);
12891 
12892    ast_mutex_lock(lock);
12893    tmp = start;
12894    while (tmp) {
12895       if (tmp->channel == channel) {
12896 #ifdef HAVE_PRI
12897          if (pri) 
12898             ast_cli(a->fd, "Trunk/CRV: %d/%d\n", trunkgroup, tmp->channel);
12899          else
12900 #endif         
12901          ast_cli(a->fd, "Channel: %d\n", tmp->channel);
12902          ast_cli(a->fd, "File Descriptor: %d\n", tmp->subs[SUB_REAL].dfd);
12903          ast_cli(a->fd, "Span: %d\n", tmp->span);
12904          ast_cli(a->fd, "Extension: %s\n", tmp->exten);
12905          ast_cli(a->fd, "Dialing: %s\n", tmp->dialing ? "yes" : "no");
12906          ast_cli(a->fd, "Context: %s\n", tmp->context);
12907          ast_cli(a->fd, "Caller ID: %s\n", tmp->cid_num);
12908          ast_cli(a->fd, "Calling TON: %d\n", tmp->cid_ton);
12909          ast_cli(a->fd, "Caller ID name: %s\n", tmp->cid_name);
12910          ast_cli(a->fd, "Mailbox: %s\n", S_OR(tmp->mailbox, "none"));
12911          if (tmp->vars) {
12912             struct ast_variable *v;
12913             ast_cli(a->fd, "Variables:\n");
12914             for (v = tmp->vars ; v ; v = v->next)
12915                ast_cli(a->fd, "       %s = %s\n", v->name, v->value);
12916          }
12917          ast_cli(a->fd, "Destroy: %d\n", tmp->destroy);
12918          ast_cli(a->fd, "InAlarm: %d\n", tmp->inalarm);
12919          ast_cli(a->fd, "Signalling Type: %s\n", sig2str(tmp->sig));
12920          ast_cli(a->fd, "Radio: %d\n", tmp->radio);
12921          ast_cli(a->fd, "Owner: %s\n", tmp->owner ? tmp->owner->name : "<None>");
12922          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)" : "");
12923          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)" : "");
12924          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)" : "");
12925          ast_cli(a->fd, "Confno: %d\n", tmp->confno);
12926          ast_cli(a->fd, "Propagated Conference: %d\n", tmp->propconfno);
12927          ast_cli(a->fd, "Real in conference: %d\n", tmp->inconference);
12928          ast_cli(a->fd, "DSP: %s\n", tmp->dsp ? "yes" : "no");
12929          ast_cli(a->fd, "Busy Detection: %s\n", tmp->busydetect ? "yes" : "no");
12930          if (tmp->busydetect) {
12931 #if defined(BUSYDETECT_TONEONLY)
12932             ast_cli(a->fd, "    Busy Detector Helper: BUSYDETECT_TONEONLY\n");
12933 #elif defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
12934             ast_cli(a->fd, "    Busy Detector Helper: BUSYDETECT_COMPARE_TONE_AND_SILENCE\n");
12935 #endif
12936 #ifdef BUSYDETECT_DEBUG
12937             ast_cli(a->fd, "    Busy Detector Debug: Enabled\n");
12938 #endif
12939             ast_cli(a->fd, "    Busy Count: %d\n", tmp->busycount);
12940             ast_cli(a->fd, "    Busy Pattern: %d,%d\n", tmp->busy_tonelength, tmp->busy_quietlength);
12941          }
12942          ast_cli(a->fd, "TDD: %s\n", tmp->tdd ? "yes" : "no");
12943          ast_cli(a->fd, "Relax DTMF: %s\n", tmp->dtmfrelax ? "yes" : "no");
12944          ast_cli(a->fd, "Dialing/CallwaitCAS: %d/%d\n", tmp->dialing, tmp->callwaitcas);
12945          ast_cli(a->fd, "Default law: %s\n", tmp->law == DAHDI_LAW_MULAW ? "ulaw" : tmp->law == DAHDI_LAW_ALAW ? "alaw" : "unknown");
12946          ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
12947          ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
12948          ast_cli(a->fd, "DND: %s\n", tmp->dnd ? "yes" : "no");
12949          ast_cli(a->fd, "Echo Cancellation:\n");
12950 
12951          if (tmp->echocancel.head.tap_length) {
12952             ast_cli(a->fd, "\t%d taps\n", tmp->echocancel.head.tap_length);
12953             for (x = 0; x < tmp->echocancel.head.param_count; x++) {
12954                ast_cli(a->fd, "\t\t%s: %ud\n", tmp->echocancel.params[x].name, tmp->echocancel.params[x].value);
12955             }
12956             ast_cli(a->fd, "\t%scurrently %s\n", tmp->echocanbridged ? "" : "(unless TDM bridged) ", tmp->echocanon ? "ON" : "OFF");
12957          } else {
12958             ast_cli(a->fd, "\tnone\n");
12959          }
12960          if (tmp->master)
12961             ast_cli(a->fd, "Master Channel: %d\n", tmp->master->channel);
12962          for (x = 0; x < MAX_SLAVES; x++) {
12963             if (tmp->slaves[x])
12964                ast_cli(a->fd, "Slave Channel: %d\n", tmp->slaves[x]->channel);
12965          }
12966 #ifdef HAVE_SS7
12967          if (tmp->ss7) {
12968             ast_cli(a->fd, "CIC: %d\n", tmp->cic);
12969          }
12970 #endif
12971 #ifdef HAVE_PRI
12972          if (tmp->pri) {
12973             ast_cli(a->fd, "PRI Flags: ");
12974             if (tmp->resetting)
12975                ast_cli(a->fd, "Resetting ");
12976             if (tmp->call)
12977                ast_cli(a->fd, "Call ");
12978             if (tmp->bearer)
12979                ast_cli(a->fd, "Bearer ");
12980             ast_cli(a->fd, "\n");
12981             if (tmp->logicalspan) 
12982                ast_cli(a->fd, "PRI Logical Span: %d\n", tmp->logicalspan);
12983             else
12984                ast_cli(a->fd, "PRI Logical Span: Implicit\n");
12985          }
12986             
12987 #endif
12988          memset(&ci, 0, sizeof(ci));
12989          ps.channo = tmp->channel;
12990          if (tmp->subs[SUB_REAL].dfd > -1) {
12991             memset(&ci, 0, sizeof(ci));
12992             if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
12993                ast_cli(a->fd, "Actual Confinfo: Num/%d, Mode/0x%04x\n", ci.confno, ci.confmode);
12994             }
12995             if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONFMUTE, &x)) {
12996                ast_cli(a->fd, "Actual Confmute: %s\n", x ? "Yes" : "No");
12997             }
12998             memset(&ps, 0, sizeof(ps));
12999             if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
13000                ast_log(LOG_WARNING, "Failed to get parameters on channel %d: %s\n", tmp->channel, strerror(errno));
13001             } else {
13002                ast_cli(a->fd, "Hookstate (FXS only): %s\n", ps.rxisoffhook ? "Offhook" : "Onhook");
13003             }
13004          }
13005          ast_mutex_unlock(lock);
13006          return CLI_SUCCESS;
13007       }
13008       tmp = tmp->next;
13009    }
13010    
13011    ast_cli(a->fd, "Unable to find given channel %d\n", channel);
13012    ast_mutex_unlock(lock);
13013    return CLI_FAILURE;
13014 }
13015 
13016 static char *handle_dahdi_show_cadences(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13017 {
13018    int i, j;
13019    switch (cmd) {
13020    case CLI_INIT:
13021       e->command = "dahdi show cadences";
13022       e->usage = 
13023          "Usage: dahdi show cadences\n"
13024          "       Shows all cadences currently defined\n";
13025       return NULL;
13026    case CLI_GENERATE:
13027       return NULL;   
13028    }
13029    for (i = 0; i < num_cadence; i++) {
13030       char output[1024];
13031       char tmp[16], tmp2[64];
13032       snprintf(tmp, sizeof(tmp), "r%d: ", i + 1);
13033       term_color(output, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(output));
13034 
13035       for (j = 0; j < 16; j++) {
13036          if (cadences[i].ringcadence[j] == 0)
13037             break;
13038          snprintf(tmp, sizeof(tmp), "%d", cadences[i].ringcadence[j]);
13039          if (cidrings[i] * 2 - 1 == j)
13040             term_color(tmp2, tmp, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp2) - 1);
13041          else
13042             term_color(tmp2, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(tmp2) - 1);
13043          if (j != 0)
13044             strncat(output, ",", sizeof(output) - strlen(output) - 1);
13045          strncat(output, tmp2, sizeof(output) - strlen(output) - 1);
13046       }
13047       ast_cli(a->fd,"%s\n",output);
13048    }
13049    return CLI_SUCCESS;
13050 }
13051 
13052 /* Based on irqmiss.c */
13053 static char *dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) 
13054 {
13055    #define FORMAT "%-40.40s %-7.7s %-6d %-6d %-6d %-3.3s %-4.4s %-8.8s %s\n"
13056    #define FORMAT2 "%-40.40s %-7.7s %-6.6s %-6.6s %-6.6s %-3.3s %-4.4s %-8.8s %s\n"
13057    int span;
13058    int res;
13059    char alarmstr[50];
13060 
13061    int ctl;
13062    struct dahdi_spaninfo s;
13063 
13064    switch (cmd) {
13065    case CLI_INIT:
13066       e->command = "dahdi show status";
13067       e->usage = 
13068          "Usage: dahdi show status\n"
13069          "       Shows a list of DAHDI cards with status\n";
13070       return NULL;
13071    case CLI_GENERATE:
13072       return NULL;   
13073    }
13074    ctl = open("/dev/dahdi/ctl", O_RDWR);
13075    if (ctl < 0) {
13076       ast_cli(a->fd, "No DAHDI found. Unable to open /dev/dahdi/ctl: %s\n", strerror(errno));
13077       return CLI_FAILURE;
13078    }
13079    ast_cli(a->fd, FORMAT2, "Description", "Alarms", "IRQ", "bpviol", "CRC4", "Framing", "Coding", "Options", "LBO");
13080 
13081    for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
13082       s.spanno = span;
13083       res = ioctl(ctl, DAHDI_SPANSTAT, &s);
13084       if (res) {
13085          continue;
13086       }
13087       alarmstr[0] = '\0';
13088       if (s.alarms > 0) {
13089          if (s.alarms & DAHDI_ALARM_BLUE)
13090             strcat(alarmstr, "BLU/");
13091          if (s.alarms & DAHDI_ALARM_YELLOW)
13092             strcat(alarmstr, "YEL/");
13093          if (s.alarms & DAHDI_ALARM_RED)
13094             strcat(alarmstr, "RED/");
13095          if (s.alarms & DAHDI_ALARM_LOOPBACK)
13096             strcat(alarmstr, "LB/");
13097          if (s.alarms & DAHDI_ALARM_RECOVER)
13098             strcat(alarmstr, "REC/");
13099          if (s.alarms & DAHDI_ALARM_NOTOPEN)
13100             strcat(alarmstr, "NOP/");
13101          if (!strlen(alarmstr))
13102             strcat(alarmstr, "UUU/");
13103          if (strlen(alarmstr)) {
13104             /* Strip trailing / */
13105             alarmstr[strlen(alarmstr) - 1] = '\0';
13106          }
13107       } else {
13108          if (s.numchans)
13109             strcpy(alarmstr, "OK");
13110          else
13111             strcpy(alarmstr, "UNCONFIGURED");
13112       }
13113 
13114       ast_cli(a->fd, FORMAT, s.desc, alarmstr, s.irqmisses, s.bpvcount, s.crc4count
13115             , s.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
13116               s.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
13117               s.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
13118               "CAS"
13119             , s.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
13120               s.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
13121               s.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
13122               "Unk"
13123             , s.lineconfig & DAHDI_CONFIG_CRC4 ?
13124               s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" : "YEL"
13125             , lbostr[s.lbo]
13126          );
13127    }
13128    close(ctl);
13129 
13130    return CLI_SUCCESS;
13131 #undef FORMAT
13132 #undef FORMAT2
13133 }
13134 
13135 static char *dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13136 {
13137    int pseudo_fd = -1;
13138    struct dahdi_versioninfo vi;
13139 
13140    switch (cmd) {
13141    case CLI_INIT:
13142       e->command = "dahdi show version";
13143       e->usage = 
13144          "Usage: dahdi show version\n"
13145          "       Shows the DAHDI version in use\n";
13146       return NULL;
13147    case CLI_GENERATE:
13148       return NULL;
13149    }
13150    if ((pseudo_fd = open("/dev/dahdi/ctl", O_RDONLY)) < 0) {
13151       ast_cli(a->fd, "Failed to open control file to get version.\n");
13152       return CLI_SUCCESS;
13153    }
13154 
13155    strcpy(vi.version, "Unknown");
13156    strcpy(vi.echo_canceller, "Unknown");
13157 
13158    if (ioctl(pseudo_fd, DAHDI_GETVERSION, &vi))
13159       ast_cli(a->fd, "Failed to get DAHDI version: %s\n", strerror(errno));
13160    else
13161       ast_cli(a->fd, "DAHDI Version: %s Echo Canceller: %s\n", vi.version, vi.echo_canceller);
13162 
13163    close(pseudo_fd);
13164 
13165    return CLI_SUCCESS;
13166 }
13167 
13168 static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13169 {
13170    int channel;
13171    int gain;
13172    int tx;
13173    struct dahdi_hwgain hwgain;
13174    struct dahdi_pvt *tmp = NULL;
13175 
13176    switch (cmd) {
13177    case CLI_INIT:
13178       e->command = "dahdi set hwgain";
13179       e->usage = 
13180          "Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
13181          "  Sets the hardware gain on a a given channel, overriding the\n"
13182          "   value provided at module loadtime, whether the channel is in\n"
13183          "   use or not.  Changes take effect immediately.\n"
13184          "   <rx|tx> which direction do you want to change (relative to our module)\n"
13185          "   <chan num> is the channel number relative to the device\n"
13186          "   <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
13187       return NULL;
13188    case CLI_GENERATE:
13189       return NULL;   
13190    }
13191 
13192    if (a->argc != 6)
13193       return CLI_SHOWUSAGE;
13194    
13195    if (!strcasecmp("rx", a->argv[3]))
13196       tx = 0; /* rx */
13197    else if (!strcasecmp("tx", a->argv[3]))
13198       tx = 1; /* tx */
13199    else
13200       return CLI_SHOWUSAGE;
13201 
13202    channel = atoi(a->argv[4]);
13203    gain = atof(a->argv[5])*10.0;
13204 
13205    ast_mutex_lock(&iflock);
13206 
13207    for (tmp = iflist; tmp; tmp = tmp->next) {
13208 
13209       if (tmp->channel != channel)
13210          continue;
13211 
13212       if (tmp->subs[SUB_REAL].dfd == -1)
13213          break;
13214 
13215       hwgain.newgain = gain;
13216       hwgain.tx = tx;
13217       if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_HWGAIN, &hwgain) < 0) {
13218          ast_cli(a->fd, "Unable to set the hardware gain for channel %d: %s\n", channel, strerror(errno));
13219          ast_mutex_unlock(&iflock);
13220          return CLI_FAILURE;
13221       }
13222       ast_cli(a->fd, "hardware %s gain set to %d (%.1f dB) on channel %d\n",
13223          tx ? "tx" : "rx", gain, (float)gain/10.0, channel);
13224       break;
13225    }
13226 
13227    ast_mutex_unlock(&iflock);
13228 
13229    if (tmp)
13230       return CLI_SUCCESS;
13231 
13232    ast_cli(a->fd, "Unable to find given channel %d\n", channel);
13233    return CLI_FAILURE;
13234 
13235 }
13236 
13237 static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13238 {
13239    int channel;
13240    float gain;
13241    int tx;
13242    int res;
13243    ast_mutex_t *lock;
13244    struct dahdi_pvt *tmp = NULL;
13245 
13246    switch (cmd) {
13247    case CLI_INIT:
13248       e->command = "dahdi set swgain";
13249       e->usage = 
13250          "Usage: dahdi set swgain <rx|tx> <chan#> <gain>\n"
13251          "  Sets the software gain on a a given channel, overriding the\n"
13252          "   value provided at module loadtime, whether the channel is in\n"
13253          "   use or not.  Changes take effect immediately.\n"
13254          "   <rx|tx> which direction do you want to change (relative to our module)\n"
13255          "   <chan num> is the channel number relative to the device\n"
13256          "   <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
13257       return NULL;
13258    case CLI_GENERATE:
13259       return NULL;   
13260    }
13261 
13262    lock = &iflock;
13263 
13264    if (a->argc != 6)
13265       return CLI_SHOWUSAGE;
13266    
13267    if (!strcasecmp("rx", a->argv[3]))
13268       tx = 0; /* rx */
13269    else if (!strcasecmp("tx", a->argv[3]))
13270       tx = 1; /* tx */
13271    else
13272       return CLI_SHOWUSAGE;
13273 
13274    channel = atoi(a->argv[4]);
13275    gain = atof(a->argv[5]);
13276 
13277    ast_mutex_lock(lock);
13278    for (tmp = iflist; tmp; tmp = tmp->next) {
13279 
13280       if (tmp->channel != channel)
13281          continue;
13282 
13283       if (tmp->subs[SUB_REAL].dfd == -1)
13284          break;
13285 
13286       if (tx)
13287          res = set_actual_txgain(tmp->subs[SUB_REAL].dfd, channel, gain, tmp->law);
13288       else
13289          res = set_actual_rxgain(tmp->subs[SUB_REAL].dfd, channel, gain, tmp->law);
13290 
13291       if (res) {
13292          ast_cli(a->fd, "Unable to set the software gain for channel %d\n", channel);
13293          ast_mutex_unlock(lock);
13294          return CLI_FAILURE;
13295       }
13296 
13297       ast_cli(a->fd, "software %s gain set to %.1f on channel %d\n",
13298          tx ? "tx" : "rx", gain, channel);
13299       break;
13300    }
13301    ast_mutex_unlock(lock);
13302 
13303    if (tmp)
13304       return CLI_SUCCESS;
13305 
13306    ast_cli(a->fd, "Unable to find given channel %d\n", channel);
13307    return CLI_FAILURE;
13308 
13309 }
13310 
13311 static char *dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13312 {
13313    int channel;
13314    int on;
13315    struct dahdi_pvt *dahdi_chan = NULL;
13316 
13317    switch (cmd) {
13318    case CLI_INIT:
13319       e->command = "dahdi set dnd";
13320       e->usage = 
13321          "Usage: dahdi set dnd <chan#> <on|off>\n"
13322          "  Sets/resets DND (Do Not Disturb) mode on a channel.\n"
13323          "  Changes take effect immediately.\n"
13324          "  <chan num> is the channel number\n"
13325          "  <on|off> Enable or disable DND mode?\n"
13326          ;
13327       return NULL;
13328    case CLI_GENERATE:
13329       return NULL;   
13330    }
13331 
13332    if (a->argc != 5)
13333       return CLI_SHOWUSAGE;
13334 
13335    if ((channel = atoi(a->argv[3])) <= 0) {
13336       ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
13337       return CLI_SHOWUSAGE;
13338    }
13339    
13340    if (ast_true(a->argv[4]))
13341       on = 1;
13342    else if (ast_false(a->argv[4]))
13343       on = 0;
13344    else {
13345       ast_cli(a->fd, "Expected 'on' or 'off', got '%s'\n", a->argv[4]);
13346       return CLI_SHOWUSAGE;
13347    }
13348 
13349    ast_mutex_lock(&iflock);
13350    for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
13351       if (dahdi_chan->channel != channel)
13352          continue;
13353 
13354       /* Found the channel. Actually set it */
13355       dahdi_dnd(dahdi_chan, on);
13356       break;
13357    }
13358    ast_mutex_unlock(&iflock);
13359 
13360    if (!dahdi_chan) {
13361       ast_cli(a->fd, "Unable to find given channel %d\n", channel);
13362       return CLI_FAILURE;
13363    }
13364 
13365    return CLI_SUCCESS;
13366 }
13367 
13368 static struct ast_cli_entry dahdi_cli[] = {
13369    AST_CLI_DEFINE(handle_dahdi_show_cadences, "List cadences"),
13370    AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
13371    AST_CLI_DEFINE(dahdi_show_channel, "Show information on a channel"),
13372    AST_CLI_DEFINE(dahdi_destroy_channel, "Destroy a channel"),
13373    AST_CLI_DEFINE(dahdi_restart_cmd, "Fully restart DAHDI channels"),
13374    AST_CLI_DEFINE(dahdi_show_status, "Show all DAHDI cards status"),
13375    AST_CLI_DEFINE(dahdi_show_version, "Show the DAHDI version in use"),
13376    AST_CLI_DEFINE(dahdi_set_hwgain, "Set hardware gain on a channel"),
13377    AST_CLI_DEFINE(dahdi_set_swgain, "Set software gain on a channel"),
13378    AST_CLI_DEFINE(dahdi_set_dnd, "Sets/resets DND (Do Not Disturb) mode on a channel"),
13379 };
13380 
13381 #define TRANSFER  0
13382 #define HANGUP    1
13383 
13384 static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
13385 {
13386    if (p) {
13387       switch (mode) {
13388          case TRANSFER:
13389             p->fake_event = DAHDI_EVENT_WINKFLASH;
13390             break;
13391          case HANGUP:
13392             p->fake_event = DAHDI_EVENT_ONHOOK;
13393             break;
13394          default:
13395             ast_log(LOG_WARNING, "I don't know how to handle transfer event with this: %d on channel %s\n",mode, p->owner->name);   
13396       }
13397    }
13398    return 0;
13399 }
13400 static struct dahdi_pvt *find_channel(int channel)
13401 {
13402    struct dahdi_pvt *p = iflist;
13403    while (p) {
13404       if (p->channel == channel) {
13405          break;
13406       }
13407       p = p->next;
13408    }
13409    return p;
13410 }
13411 
13412 static int action_dahdidndon(struct mansession *s, const struct message *m)
13413 {
13414    struct dahdi_pvt *p = NULL;
13415    const char *channel = astman_get_header(m, "DAHDIChannel");
13416 
13417    if (ast_strlen_zero(channel)) {
13418       astman_send_error(s, m, "No channel specified");
13419       return 0;
13420    }
13421    p = find_channel(atoi(channel));
13422    if (!p) {
13423       astman_send_error(s, m, "No such channel");
13424       return 0;
13425    }
13426    p->dnd = 1;
13427    astman_send_ack(s, m, "DND Enabled");
13428    return 0;
13429 }
13430 
13431 static int action_dahdidndoff(struct mansession *s, const struct message *m)
13432 {
13433    struct dahdi_pvt *p = NULL;
13434    const char *channel = astman_get_header(m, "DAHDIChannel");
13435 
13436    if (ast_strlen_zero(channel)) {
13437       astman_send_error(s, m, "No channel specified");
13438       return 0;
13439    }
13440    p = find_channel(atoi(channel));
13441    if (!p) {
13442       astman_send_error(s, m, "No such channel");
13443       return 0;
13444    }
13445    p->dnd = 0;
13446    astman_send_ack(s, m, "DND Disabled");
13447    return 0;
13448 }
13449 
13450 static int action_transfer(struct mansession *s, const struct message *m)
13451 {
13452    struct dahdi_pvt *p = NULL;
13453    const char *channel = astman_get_header(m, "DAHDIChannel");
13454 
13455    if (ast_strlen_zero(channel)) {
13456       astman_send_error(s, m, "No channel specified");
13457       return 0;
13458    }
13459    p = find_channel(atoi(channel));
13460    if (!p) {
13461       astman_send_error(s, m, "No such channel");
13462       return 0;
13463    }
13464    dahdi_fake_event(p,TRANSFER);
13465    astman_send_ack(s, m, "DAHDITransfer");
13466    return 0;
13467 }
13468 
13469 static int action_transferhangup(struct mansession *s, const struct message *m)
13470 {
13471    struct dahdi_pvt *p = NULL;
13472    const char *channel = astman_get_header(m, "DAHDIChannel");
13473 
13474    if (ast_strlen_zero(channel)) {
13475       astman_send_error(s, m, "No channel specified");
13476       return 0;
13477    }
13478    p = find_channel(atoi(channel));
13479    if (!p) {
13480       astman_send_error(s, m, "No such channel");
13481       return 0;
13482    }
13483    dahdi_fake_event(p,HANGUP);
13484    astman_send_ack(s, m, "DAHDIHangup");
13485    return 0;
13486 }
13487 
13488 static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
13489 {
13490    struct dahdi_pvt *p = NULL;
13491    const char *channel = astman_get_header(m, "DAHDIChannel");
13492    const char *number = astman_get_header(m, "Number");
13493    int i;
13494 
13495    if (ast_strlen_zero(channel)) {
13496       astman_send_error(s, m, "No channel specified");
13497       return 0;
13498    }
13499    if (ast_strlen_zero(number)) {
13500       astman_send_error(s, m, "No number specified");
13501       return 0;
13502    }
13503    p = find_channel(atoi(channel));
13504    if (!p) {
13505       astman_send_error(s, m, "No such channel");
13506       return 0;
13507    }
13508    if (!p->owner) {
13509       astman_send_error(s, m, "Channel does not have it's owner");
13510       return 0;
13511    }
13512    for (i = 0; i < strlen(number); i++) {
13513       struct ast_frame f = { AST_FRAME_DTMF, number[i] };
13514       dahdi_queue_frame(p, &f, NULL); 
13515    }
13516    astman_send_ack(s, m, "DAHDIDialOffhook");
13517    return 0;
13518 }
13519 
13520 static int action_dahdishowchannels(struct mansession *s, const struct message *m)
13521 {
13522    struct dahdi_pvt *tmp = NULL;
13523    const char *id = astman_get_header(m, "ActionID");
13524    const char *dahdichannel = astman_get_header(m, "DAHDIChannel");
13525    char idText[256] = "";
13526    int channels = 0;
13527    int dahdichanquery = -1;
13528    if (!ast_strlen_zero(dahdichannel)) {
13529       dahdichanquery = atoi(dahdichannel);
13530    }
13531 
13532    astman_send_ack(s, m, "DAHDI channel status will follow");
13533    if (!ast_strlen_zero(id))
13534       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
13535 
13536    ast_mutex_lock(&iflock);
13537    
13538    tmp = iflist;
13539    while (tmp) {
13540       if (tmp->channel > 0) {
13541          int alm = get_alarms(tmp);
13542 
13543          /* If a specific channel is queried for, only deliver status for that channel */
13544          if (dahdichanquery > 0 && tmp->channel != dahdichanquery)
13545             continue;
13546 
13547          channels++;
13548          if (tmp->owner) {
13549             /* Add data if we have a current call */
13550             astman_append(s,
13551                "Event: DAHDIShowChannels\r\n"
13552                "DAHDIChannel: %d\r\n"
13553                "Channel: %s\r\n"
13554                "Uniqueid: %s\r\n"
13555                "AccountCode: %s\r\n"
13556                "Signalling: %s\r\n"
13557                "SignallingCode: %d\r\n"
13558                "Context: %s\r\n"
13559                "DND: %s\r\n"
13560                "Alarm: %s\r\n"
13561                "%s"
13562                "\r\n",
13563                tmp->channel, 
13564                tmp->owner->name,
13565                tmp->owner->uniqueid,
13566                tmp->owner->accountcode,
13567                sig2str(tmp->sig), 
13568                tmp->sig,
13569                tmp->context, 
13570                tmp->dnd ? "Enabled" : "Disabled",
13571                alarm2str(alm), idText);
13572          } else {
13573             astman_append(s,
13574                "Event: DAHDIShowChannels\r\n"
13575                "DAHDIChannel: %d\r\n"
13576                "Signalling: %s\r\n"
13577                "SignallingCode: %d\r\n"
13578                "Context: %s\r\n"
13579                "DND: %s\r\n"
13580                "Alarm: %s\r\n"
13581                "%s"
13582                "\r\n",
13583                tmp->channel, sig2str(tmp->sig), tmp->sig, 
13584                tmp->context, 
13585                tmp->dnd ? "Enabled" : "Disabled",
13586                alarm2str(alm), idText);
13587          }
13588       } 
13589 
13590       tmp = tmp->next;
13591    }
13592 
13593    ast_mutex_unlock(&iflock);
13594    
13595    astman_append(s, 
13596       "Event: DAHDIShowChannelsComplete\r\n"
13597       "%s"
13598       "Items: %d\r\n"
13599       "\r\n", 
13600       idText,
13601       channels);
13602    return 0;
13603 }
13604 
13605 #ifdef HAVE_SS7
13606 static int linkset_addsigchan(int sigchan)
13607 {
13608    struct dahdi_ss7 *link;
13609    int res;
13610    int curfd;
13611    struct dahdi_params p;
13612    struct dahdi_bufferinfo bi;
13613    struct dahdi_spaninfo si;
13614 
13615 
13616    link = ss7_resolve_linkset(cur_linkset);
13617    if (!link) {
13618       ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
13619       return -1;
13620    }
13621 
13622    if (cur_ss7type < 0) {
13623       ast_log(LOG_ERROR, "Unspecified or invalid ss7type\n");
13624       return -1;
13625    }
13626 
13627    if (!link->ss7)
13628       link->ss7 = ss7_new(cur_ss7type);
13629 
13630    if (!link->ss7) {
13631       ast_log(LOG_ERROR, "Can't create new SS7!\n");
13632       return -1;
13633    }
13634 
13635    link->type = cur_ss7type;
13636 
13637    if (cur_pointcode < 0) {
13638       ast_log(LOG_ERROR, "Unspecified pointcode!\n");
13639       return -1;
13640    } else
13641       ss7_set_pc(link->ss7, cur_pointcode);
13642 
13643    if (sigchan < 0) {
13644       ast_log(LOG_ERROR, "Invalid sigchan!\n");
13645       return -1;
13646    } else {
13647       if (link->numsigchans >= NUM_DCHANS) {
13648          ast_log(LOG_ERROR, "Too many sigchans on linkset %d\n", cur_linkset);
13649          return -1;
13650       }
13651       curfd = link->numsigchans;
13652 
13653       link->fds[curfd] = open("/dev/dahdi/channel", O_RDWR, 0600);
13654       if ((link->fds[curfd] < 0) || (ioctl(link->fds[curfd],DAHDI_SPECIFY,&sigchan) == -1)) {
13655          ast_log(LOG_ERROR, "Unable to open SS7 sigchan %d (%s)\n", sigchan, strerror(errno));
13656          return -1;
13657       }
13658       memset(&p, 0, sizeof(p));
13659       res = ioctl(link->fds[curfd], DAHDI_GET_PARAMS, &p);
13660       if (res) {
13661          dahdi_close_ss7_fd(link, curfd);
13662          ast_log(LOG_ERROR, "Unable to get parameters for sigchan %d (%s)\n", sigchan, strerror(errno));
13663          return -1;
13664       }
13665       if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC) && (p.sigtype != DAHDI_SIG_MTP2)) {
13666          dahdi_close_ss7_fd(link, curfd);
13667          ast_log(LOG_ERROR, "sigchan %d is not in HDLC/FCS mode.\n", sigchan);
13668          return -1;
13669       }
13670 
13671       memset(&bi, 0, sizeof(bi));
13672       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
13673       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
13674       bi.numbufs = 32;
13675       bi.bufsize = 512;
13676 
13677       if (ioctl(link->fds[curfd], DAHDI_SET_BUFINFO, &bi)) {
13678          ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", sigchan, strerror(errno));
13679          dahdi_close_ss7_fd(link, curfd);
13680          return -1;
13681       }
13682 
13683       if (p.sigtype == DAHDI_SIG_MTP2)
13684          ss7_add_link(link->ss7, SS7_TRANSPORT_DAHDIMTP2, link->fds[curfd]);
13685       else
13686          ss7_add_link(link->ss7, SS7_TRANSPORT_DAHDIDCHAN, link->fds[curfd]);
13687 
13688       link->numsigchans++;
13689 
13690       memset(&si, 0, sizeof(si));
13691       res = ioctl(link->fds[curfd], DAHDI_SPANSTAT, &si);
13692       if (res) {
13693          dahdi_close_ss7_fd(link, curfd);
13694          ast_log(LOG_ERROR, "Unable to get span state for sigchan %d (%s)\n", sigchan, strerror(errno));
13695       }
13696 
13697       if (!si.alarms) {
13698          link->linkstate[curfd] = LINKSTATE_DOWN;
13699          ss7_link_noalarm(link->ss7, link->fds[curfd]);
13700       } else {
13701          link->linkstate[curfd] = LINKSTATE_DOWN | LINKSTATE_INALARM;
13702          ss7_link_alarm(link->ss7, link->fds[curfd]);
13703       }
13704    }
13705 
13706    if (cur_adjpointcode < 0) {
13707       ast_log(LOG_ERROR, "Unspecified adjpointcode!\n");
13708       return -1;
13709    } else {
13710       ss7_set_adjpc(link->ss7, link->fds[curfd], cur_adjpointcode);
13711    }
13712 
13713    if (cur_defaultdpc < 0) {
13714       ast_log(LOG_ERROR, "Unspecified defaultdpc!\n");
13715       return -1;
13716    }
13717 
13718    if (cur_networkindicator < 0) {
13719       ast_log(LOG_ERROR, "Invalid networkindicator!\n");
13720       return -1;
13721    } else
13722       ss7_set_network_ind(link->ss7, cur_networkindicator);
13723 
13724    return 0;
13725 }
13726 
13727 static char *handle_ss7_no_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13728 {
13729    int span;
13730    switch (cmd) {
13731    case CLI_INIT:
13732       e->command = "ss7 no debug linkset";
13733       e->usage = 
13734          "Usage: ss7 no debug linkset <span>\n"
13735          "       Disables debugging on a given SS7 linkset\n";
13736       return NULL;
13737    case CLI_GENERATE:
13738       return NULL;
13739    }
13740    if (a->argc < 5)
13741       return CLI_SHOWUSAGE;
13742    span = atoi(a->argv[4]);
13743    if ((span < 1) || (span > NUM_SPANS)) {
13744       ast_cli(a->fd, "Invalid linkset %s.  Should be a number from %d to %d\n", a->argv[4], 1, NUM_SPANS);
13745       return CLI_SUCCESS;
13746    }
13747    if (!linksets[span-1].ss7) {
13748       ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
13749       return CLI_SUCCESS;
13750    }
13751    if (linksets[span-1].ss7)
13752       ss7_set_debug(linksets[span-1].ss7, 0);
13753 
13754    ast_cli(a->fd, "Disabled debugging on linkset %d\n", span);
13755    return CLI_SUCCESS;
13756 }
13757 
13758 static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13759 {
13760    int span;
13761    switch (cmd) {
13762    case CLI_INIT:
13763       e->command = "ss7 debug linkset";
13764       e->usage = 
13765          "Usage: ss7 debug linkset <linkset>\n"
13766          "       Enables debugging on a given SS7 linkset\n";
13767       return NULL;
13768    case CLI_GENERATE:
13769       return NULL;
13770    }
13771    if (a->argc < 4)
13772       return CLI_SHOWUSAGE;
13773    span = atoi(a->argv[3]);
13774    if ((span < 1) || (span > NUM_SPANS)) {
13775       ast_cli(a->fd, "Invalid linkset %s.  Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS);
13776       return CLI_SUCCESS;
13777    }
13778    if (!linksets[span-1].ss7) {
13779       ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
13780       return CLI_SUCCESS;
13781    }
13782    if (linksets[span-1].ss7)
13783       ss7_set_debug(linksets[span-1].ss7, SS7_DEBUG_MTP2 | SS7_DEBUG_MTP3 | SS7_DEBUG_ISUP);
13784 
13785    ast_cli(a->fd, "Enabled debugging on linkset %d\n", span);
13786    return CLI_SUCCESS;
13787 }
13788 
13789 static char *handle_ss7_block_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13790 {
13791    int linkset, cic;
13792    int blocked = -1, i;
13793    switch (cmd) {
13794    case CLI_INIT:
13795       e->command = "ss7 block cic";
13796       e->usage = 
13797          "Usage: ss7 block cic <linkset> <CIC>\n"
13798          "       Sends a remote blocking request for the given CIC on the specified linkset\n";
13799       return NULL;
13800    case CLI_GENERATE:
13801       return NULL;
13802    }
13803    if (a->argc == 5)
13804       linkset = atoi(a->argv[3]);
13805    else
13806       return CLI_SHOWUSAGE;
13807 
13808    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13809       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13810       return CLI_SUCCESS;
13811    }
13812 
13813    if (!linksets[linkset-1].ss7) {
13814       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13815       return CLI_SUCCESS;
13816    }
13817 
13818    cic = atoi(a->argv[4]);
13819 
13820    if (cic < 1) {
13821       ast_cli(a->fd, "Invalid CIC specified!\n");
13822       return CLI_SUCCESS;
13823    }
13824 
13825    for (i = 0; i < linksets[linkset-1].numchans; i++) {
13826       if (linksets[linkset-1].pvts[i]->cic == cic) {
13827          blocked = linksets[linkset-1].pvts[i]->locallyblocked;
13828          if (!blocked) {
13829             ast_mutex_lock(&linksets[linkset-1].lock);
13830             isup_blo(linksets[linkset-1].ss7, cic, linksets[linkset-1].pvts[i]->dpc);
13831             ast_mutex_unlock(&linksets[linkset-1].lock);
13832          }
13833       }
13834    }
13835 
13836    if (blocked < 0) {
13837       ast_cli(a->fd, "Invalid CIC specified!\n");
13838       return CLI_SUCCESS;
13839    }
13840 
13841    if (!blocked)
13842       ast_cli(a->fd, "Sent blocking request for linkset %d on CIC %d\n", linkset, cic);
13843    else
13844       ast_cli(a->fd, "CIC %d already locally blocked\n", cic);
13845 
13846    /* Break poll on the linkset so it sends our messages */
13847    pthread_kill(linksets[linkset-1].master, SIGURG);
13848 
13849    return CLI_SUCCESS;
13850 }
13851 
13852 static char *handle_ss7_block_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13853 {
13854    int linkset;
13855    int i;
13856    switch (cmd) {
13857    case CLI_INIT:
13858       e->command = "ss7 block linkset";
13859       e->usage = 
13860          "Usage: ss7 block linkset <linkset number>\n"
13861          "       Sends a remote blocking request for all CICs on the given linkset\n";
13862       return NULL;
13863    case CLI_GENERATE:
13864       return NULL;
13865    }
13866    if (a->argc == 4)
13867       linkset = atoi(a->argv[3]);
13868    else
13869       return CLI_SHOWUSAGE;
13870 
13871    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13872       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13873       return CLI_SUCCESS;
13874    }
13875 
13876    if (!linksets[linkset-1].ss7) {
13877       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13878       return CLI_SUCCESS;
13879    }
13880 
13881    for (i = 0; i < linksets[linkset-1].numchans; i++) {
13882       ast_cli(a->fd, "Sending remote blocking request on CIC %d\n", linksets[linkset-1].pvts[i]->cic);
13883       ast_mutex_lock(&linksets[linkset-1].lock);
13884       isup_blo(linksets[linkset-1].ss7, linksets[linkset-1].pvts[i]->cic, linksets[linkset-1].pvts[i]->dpc);
13885       ast_mutex_unlock(&linksets[linkset-1].lock);
13886    }
13887 
13888    /* Break poll on the linkset so it sends our messages */
13889    pthread_kill(linksets[linkset-1].master, SIGURG);
13890 
13891    return CLI_SUCCESS;
13892 }
13893 
13894 static char *handle_ss7_unblock_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13895 {
13896    int linkset, cic;
13897    int i, blocked = -1;
13898    switch (cmd) {
13899    case CLI_INIT:
13900       e->command = "ss7 unblock cic";
13901       e->usage = 
13902          "Usage: ss7 unblock cic <linkset> <CIC>\n"
13903          "       Sends a remote unblocking request for the given CIC on the specified linkset\n";
13904       return NULL;
13905    case CLI_GENERATE:
13906       return NULL;
13907    }
13908 
13909    if (a->argc == 5)
13910       linkset = atoi(a->argv[3]);
13911    else
13912       return CLI_SHOWUSAGE;
13913 
13914    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13915       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13916       return CLI_SUCCESS;
13917    }
13918 
13919    if (!linksets[linkset-1].ss7) {
13920       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13921       return CLI_SUCCESS;
13922    }
13923 
13924    cic = atoi(a->argv[4]);
13925 
13926    if (cic < 1) {
13927       ast_cli(a->fd, "Invalid CIC specified!\n");
13928       return CLI_SUCCESS;
13929    }
13930 
13931    for (i = 0; i < linksets[linkset-1].numchans; i++) {
13932       if (linksets[linkset-1].pvts[i]->cic == cic) {
13933          blocked = linksets[linkset-1].pvts[i]->locallyblocked;
13934          if (blocked) {
13935             ast_mutex_lock(&linksets[linkset-1].lock);
13936             isup_ubl(linksets[linkset-1].ss7, cic, linksets[linkset-1].pvts[i]->dpc);
13937             ast_mutex_unlock(&linksets[linkset-1].lock);
13938          }
13939       }
13940    }
13941 
13942    if (blocked > 0)
13943       ast_cli(a->fd, "Sent unblocking request for linkset %d on CIC %d\n", linkset, cic);
13944 
13945    /* Break poll on the linkset so it sends our messages */
13946    pthread_kill(linksets[linkset-1].master, SIGURG);
13947 
13948    return CLI_SUCCESS;
13949 }
13950 
13951 static char *handle_ss7_unblock_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13952 {
13953    int linkset;
13954    int i;
13955    switch (cmd) {
13956    case CLI_INIT:
13957       e->command = "ss7 unblock linkset";
13958       e->usage = 
13959          "Usage: ss7 unblock linkset <linkset number>\n"
13960          "       Sends a remote unblocking request for all CICs on the specified linkset\n";
13961       return NULL;
13962    case CLI_GENERATE:
13963       return NULL;
13964    }
13965 
13966    if (a->argc == 4)
13967       linkset = atoi(a->argv[3]);
13968    else
13969       return CLI_SHOWUSAGE;
13970 
13971    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13972       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13973       return CLI_SUCCESS;
13974    }
13975 
13976    if (!linksets[linkset-1].ss7) {
13977       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13978       return CLI_SUCCESS;
13979    }
13980 
13981    for (i = 0; i < linksets[linkset-1].numchans; i++) {
13982       ast_cli(a->fd, "Sending remote unblock request on CIC %d\n", linksets[linkset-1].pvts[i]->cic);
13983       ast_mutex_lock(&linksets[linkset-1].lock);
13984       isup_ubl(linksets[linkset-1].ss7, linksets[linkset-1].pvts[i]->cic, linksets[linkset-1].pvts[i]->dpc);
13985       ast_mutex_unlock(&linksets[linkset-1].lock);
13986    }
13987 
13988    /* Break poll on the linkset so it sends our messages */
13989    pthread_kill(linksets[linkset-1].master, SIGURG);
13990 
13991    return CLI_SUCCESS;
13992 }
13993 
13994 static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13995 {
13996    int linkset;
13997    struct dahdi_ss7 *ss7;
13998    switch (cmd) {
13999    case CLI_INIT:
14000       e->command = "ss7 show linkset";
14001       e->usage = 
14002          "Usage: ss7 show linkset <span>\n"
14003          "       Shows the status of an SS7 linkset.\n";
14004       return NULL;
14005    case CLI_GENERATE:
14006       return NULL;
14007    }
14008 
14009    if (a->argc < 4)
14010       return CLI_SHOWUSAGE;
14011    linkset = atoi(a->argv[3]);
14012    if ((linkset < 1) || (linkset > NUM_SPANS)) {
14013       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
14014       return CLI_SUCCESS;
14015    }
14016    if (!linksets[linkset-1].ss7) {
14017       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
14018       return CLI_SUCCESS;
14019    }
14020    if (linksets[linkset-1].ss7)
14021       ss7 = &linksets[linkset-1];
14022 
14023    ast_cli(a->fd, "SS7 linkset %d status: %s\n", linkset, (ss7->state == LINKSET_STATE_UP) ? "Up" : "Down");
14024 
14025    return CLI_SUCCESS;
14026 }
14027 
14028 static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
14029 {
14030    switch (cmd) {
14031    case CLI_INIT:
14032       e->command = "ss7 show version";
14033       e->usage = 
14034          "Usage: ss7 show version\n"
14035          "  Show the libss7 version\n";
14036       return NULL;
14037    case CLI_GENERATE:
14038       return NULL;
14039    }
14040 
14041    ast_cli(a->fd, "libss7 version: %s\n", ss7_get_version());
14042 
14043    return CLI_SUCCESS;
14044 }
14045 
14046 static struct ast_cli_entry dahdi_ss7_cli[] = {
14047    AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"), 
14048    AST_CLI_DEFINE(handle_ss7_no_debug, "Disables SS7 debugging on a linkset"), 
14049    AST_CLI_DEFINE(handle_ss7_block_cic, "Blocks the given CIC"),
14050    AST_CLI_DEFINE(handle_ss7_unblock_cic, "Unblocks the given CIC"),
14051    AST_CLI_DEFINE(handle_ss7_block_linkset, "Blocks all CICs on a linkset"),
14052    AST_CLI_DEFINE(handle_ss7_unblock_linkset, "Unblocks all CICs on a linkset"),
14053    AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"),
14054    AST_CLI_DEFINE(handle_ss7_version, "Displays libss7 version"),
14055 };
14056 #endif /* HAVE_SS7 */
14057 
14058 static int __unload_module(void)
14059 {
14060    struct dahdi_pvt *p;
14061 #if defined(HAVE_PRI) || defined(HAVE_SS7)
14062    int i, j;
14063 #endif
14064 
14065 #ifdef HAVE_PRI
14066    for (i = 0; i < NUM_SPANS; i++) {
14067       if (pris[i].master != AST_PTHREADT_NULL) 
14068          pthread_cancel(pris[i].master);
14069    }
14070    ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
14071    ast_unregister_application(dahdi_send_keypad_facility_app);
14072 #endif
14073 #if defined(HAVE_SS7)
14074    for (i = 0; i < NUM_SPANS; i++) {
14075       if (linksets[i].master != AST_PTHREADT_NULL)
14076          pthread_cancel(linksets[i].master);
14077       }
14078    ast_cli_unregister_multiple(dahdi_ss7_cli, sizeof(dahdi_ss7_cli) / sizeof(struct ast_cli_entry));
14079 #endif
14080 
14081    ast_cli_unregister_multiple(dahdi_cli, sizeof(dahdi_cli) / sizeof(struct ast_cli_entry));
14082    ast_manager_unregister( "DAHDIDialOffhook" );
14083    ast_manager_unregister( "DAHDIHangup" );
14084    ast_manager_unregister( "DAHDITransfer" );
14085    ast_manager_unregister( "DAHDIDNDoff" );
14086    ast_manager_unregister( "DAHDIDNDon" );
14087    ast_manager_unregister("DAHDIShowChannels");
14088    ast_manager_unregister("DAHDIRestart");
14089    ast_channel_unregister(&dahdi_tech);
14090    ast_mutex_lock(&iflock);
14091    /* Hangup all interfaces if they have an owner */
14092    p = iflist;
14093    while (p) {
14094       if (p->owner)
14095          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
14096       p = p->next;
14097    }
14098    ast_mutex_unlock(&iflock);
14099    ast_mutex_lock(&monlock);
14100    if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
14101       pthread_cancel(monitor_thread);
14102       pthread_kill(monitor_thread, SIGURG);
14103       pthread_join(monitor_thread, NULL);
14104    }
14105    monitor_thread = AST_PTHREADT_STOP;
14106    ast_mutex_unlock(&monlock);
14107 
14108    destroy_all_channels();
14109 
14110 #if defined(HAVE_PRI)
14111    for (i = 0; i < NUM_SPANS; i++) {
14112       if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL))
14113          pthread_join(pris[i].master, NULL);
14114       for (j = 0; j < NUM_DCHANS; j++) {
14115          dahdi_close_pri_fd(&(pris[i]), j);
14116       }
14117    }
14118 #endif
14119 
14120 #if defined(HAVE_SS7)
14121    for (i = 0; i < NUM_SPANS; i++) {
14122       if (linksets[i].master && (linksets[i].master != AST_PTHREADT_NULL))
14123          pthread_join(linksets[i].master, NULL);
14124       for (j = 0; j < NUM_DCHANS; j++) {
14125          dahdi_close_ss7_fd(&(linksets[i]), j);
14126       }
14127    }
14128 #endif
14129 
14130    ast_cond_destroy(&mwi_thread_complete);
14131    ast_cond_destroy(&ss_thread_complete);
14132    return 0;
14133 }
14134 
14135 static int unload_module(void)
14136 {
14137 #if defined(HAVE_PRI) || defined(HAVE_SS7)
14138    int y;
14139 #endif
14140 #ifdef HAVE_PRI
14141    for (y = 0; y < NUM_SPANS; y++)
14142       ast_mutex_destroy(&pris[y].lock);
14143 #endif
14144 #ifdef HAVE_SS7
14145    for (y = 0; y < NUM_SPANS; y++)
14146       ast_mutex_destroy(&linksets[y].lock);
14147 #endif /* HAVE_SS7 */
14148    return __unload_module();
14149 }
14150 
14151 static int build_channels(struct dahdi_chan_conf *conf, int iscrv, const char *value, int reload, int lineno, int *found_pseudo)
14152 {
14153    char *c, *chan;
14154    int x, start, finish;
14155    struct dahdi_pvt *tmp;
14156 #ifdef HAVE_PRI
14157    struct dahdi_pri *pri;
14158    int trunkgroup, y;
14159 #endif
14160    
14161    if ((reload == 0) && (conf->chan.sig < 0) && !conf->is_sig_auto) {
14162       ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n");
14163       return -1;
14164    }
14165 
14166    c = ast_strdupa(value);
14167 
14168 #ifdef HAVE_PRI
14169    pri = NULL;
14170    if (iscrv) {
14171       if (sscanf(c, "%30d:%n", &trunkgroup, &y) != 1) {
14172          ast_log(LOG_WARNING, "CRV must begin with trunkgroup followed by a colon at line %d.\n", lineno);
14173          return -1;
14174       }
14175       if (trunkgroup < 1) {
14176          ast_log(LOG_WARNING, "CRV trunk group must be a positive number at line %d.\n", lineno);
14177          return -1;
14178       }
14179       c += y;
14180       for (y = 0; y < NUM_SPANS; y++) {
14181          if (pris[y].trunkgroup == trunkgroup) {
14182             pri = pris + y;
14183             break;
14184          }
14185       }
14186       if (!pri) {
14187          ast_log(LOG_WARNING, "No such trunk group %d at CRV declaration at line %d.\n", trunkgroup, lineno);
14188          return -1;
14189       }
14190    }
14191 #endif         
14192 
14193    while ((chan = strsep(&c, ","))) {
14194       if (sscanf(chan, "%30d-%30d", &start, &finish) == 2) {
14195          /* Range */
14196       } else if (sscanf(chan, "%30d", &start)) {
14197          /* Just one */
14198          finish = start;
14199       } else if (!strcasecmp(chan, "pseudo")) {
14200          finish = start = CHAN_PSEUDO;
14201          if (found_pseudo)
14202             *found_pseudo = 1;
14203       } else {
14204          ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
14205          return -1;
14206       }
14207       if (finish < start) {
14208          ast_log(LOG_WARNING, "Sillyness: %d < %d\n", start, finish);
14209          x = finish;
14210          finish = start;
14211          start = x;
14212       }
14213 
14214       for (x = start; x <= finish; x++) {
14215 #ifdef HAVE_PRI
14216          tmp = mkintf(x, conf, pri, reload);
14217 #else       
14218          tmp = mkintf(x, conf, NULL, reload);
14219 #endif         
14220 
14221          if (tmp) {
14222 #ifdef HAVE_PRI
14223                if (pri)
14224                ast_verb(3, "%s CRV %d:%d, %s signalling\n", reload ? "Reconfigured" : "Registered", trunkgroup, x, sig2str(tmp->sig));
14225                else
14226 #endif
14227                ast_verb(3, "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig));
14228          } else {
14229             ast_log(LOG_ERROR, "Unable to %s channel '%s'\n",
14230                (reload == 1) ? "reconfigure" : "register", value);
14231             return -1;
14232          }
14233       }
14234    }
14235 
14236    return 0;
14237 }
14238 
14239 /** The length of the parameters list of 'dahdichan'. 
14240  * \todo Move definition of MAX_CHANLIST_LEN to a proper place. */
14241 #define MAX_CHANLIST_LEN 80
14242 
14243 static void process_echocancel(struct dahdi_chan_conf *confp, const char *data, unsigned int line)
14244 {
14245    char *parse = ast_strdupa(data);
14246    char *params[DAHDI_MAX_ECHOCANPARAMS + 1];
14247    unsigned int param_count;
14248    unsigned int x;
14249 
14250    if (!(param_count = ast_app_separate_args(parse, ',', params, ARRAY_LEN(params))))
14251       return;
14252 
14253    memset(&confp->chan.echocancel, 0, sizeof(confp->chan.echocancel));
14254 
14255    /* first parameter is tap length, process it here */
14256 
14257    x = ast_strlen_zero(params[0]) ? 0 : atoi(params[0]);
14258    
14259    if ((x == 32) || (x == 64) || (x == 128) || (x == 256) || (x == 512) || (x == 1024))
14260       confp->chan.echocancel.head.tap_length = x;
14261    else if ((confp->chan.echocancel.head.tap_length = ast_true(params[0])))
14262       confp->chan.echocancel.head.tap_length = 128;
14263 
14264    /* now process any remaining parameters */
14265 
14266    for (x = 1; x < param_count; x++) {
14267       struct {
14268          char *name;
14269          char *value;
14270       } param;
14271 
14272       if (ast_app_separate_args(params[x], '=', (char **) &param, 2) < 1) {
14273          ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %d: '%s'\n", line, params[x]);
14274          continue;
14275       }
14276 
14277       if (ast_strlen_zero(param.name) || (strlen(param.name) > sizeof(confp->chan.echocancel.params[0].name)-1)) {
14278          ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %d: '%s'\n", line, param.name);
14279          continue;
14280       }
14281 
14282       strcpy(confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].name, param.name);
14283 
14284       if (param.value) {
14285          if (sscanf(param.value, "%30d", &confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].value) != 1) {
14286             ast_log(LOG_WARNING, "Invalid echocancel parameter value supplied at line %d: '%s'\n", line, param.value);
14287             continue;
14288          }
14289       }
14290       confp->chan.echocancel.head.param_count++;
14291    }
14292 }
14293 
14294 /*! process_dahdi() - ignore keyword 'channel' and similar */
14295 #define PROC_DAHDI_OPT_NOCHAN  (1 << 0) 
14296 /*! process_dahdi() - No warnings on non-existing cofiguration keywords */
14297 #define PROC_DAHDI_OPT_NOWARN  (1 << 1) 
14298 
14299 static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
14300 {
14301    struct dahdi_pvt *tmp;
14302    int y;
14303    int found_pseudo = 0;
14304    char dahdichan[MAX_CHANLIST_LEN] = {};
14305 
14306    for (; v; v = v->next) {
14307       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
14308          continue;
14309 
14310       /* must have parkinglot in confp before build_channels is called */
14311       if (!strcasecmp(v->name, "parkinglot")) {
14312          ast_copy_string(confp->chan.parkinglot, v->value, sizeof(confp->chan.parkinglot));
14313       }
14314 
14315       /* Create the interface list */
14316       if (!strcasecmp(v->name, "channel")
14317 #ifdef HAVE_PRI
14318           || !strcasecmp(v->name, "crv")
14319 #endif         
14320          ) {
14321          int iscrv;
14322          if (options & PROC_DAHDI_OPT_NOCHAN) {
14323             ast_log(LOG_WARNING, "Channel '%s' ignored.\n", v->value);
14324             continue;
14325          }
14326          iscrv = !strcasecmp(v->name, "crv");
14327          if (build_channels(confp, iscrv, v->value, reload, v->lineno, &found_pseudo))
14328                return -1;
14329          ast_log(LOG_DEBUG, "Channel '%s' configured.\n", v->value);
14330       } else if (!strcasecmp(v->name, "buffers")) {
14331          int res;
14332          char policy[21] = "";
14333 
14334          res = sscanf(v->value, "%30d,%20s", &confp->chan.buf_no, policy);
14335          if (res != 2) {
14336             ast_log(LOG_WARNING, "Parsing buffers option data failed, using defaults.\n");
14337             confp->chan.buf_no = numbufs;
14338             continue;
14339          }
14340          if (confp->chan.buf_no < 0)
14341             confp->chan.buf_no = numbufs;
14342          if (!strcasecmp(policy, "full")) {
14343             confp->chan.buf_policy = DAHDI_POLICY_WHEN_FULL;
14344          } else if (!strcasecmp(policy, "immediate")) {
14345             confp->chan.buf_policy = DAHDI_POLICY_IMMEDIATE;
14346          } else {
14347             ast_log(LOG_WARNING, "Invalid policy name given (%s).\n", policy);
14348          }
14349       } else if (!strcasecmp(v->name, "dahdichan")) {
14350          ast_copy_string(dahdichan, v->value, sizeof(dahdichan));
14351       } else if (!strcasecmp(v->name, "usedistinctiveringdetection")) {
14352          usedistinctiveringdetection = ast_true(v->value);
14353       } else if (!strcasecmp(v->name, "distinctiveringaftercid")) {
14354          distinctiveringaftercid = ast_true(v->value);
14355       } else if (!strcasecmp(v->name, "dring1context")) {
14356          ast_copy_string(confp->chan.drings.ringContext[0].contextData,v->value,sizeof(confp->chan.drings.ringContext[0].contextData));
14357       } else if (!strcasecmp(v->name, "dring2context")) {
14358          ast_copy_string(confp->chan.drings.ringContext[1].contextData,v->value,sizeof(confp->chan.drings.ringContext[1].contextData));
14359       } else if (!strcasecmp(v->name, "dring3context")) {
14360          ast_copy_string(confp->chan.drings.ringContext[2].contextData,v->value,sizeof(confp->chan.drings.ringContext[2].contextData));
14361       } else if (!strcasecmp(v->name, "dring1range")) {
14362          confp->chan.drings.ringnum[0].range = atoi(v->value);
14363       } else if (!strcasecmp(v->name, "dring2range")) {
14364          confp->chan.drings.ringnum[1].range = atoi(v->value);
14365       } else if (!strcasecmp(v->name, "dring3range")) {
14366          confp->chan.drings.ringnum[2].range = atoi(v->value);
14367       } else if (!strcasecmp(v->name, "dring1")) {
14368          sscanf(v->value, "%30d,%30d,%30d", &confp->chan.drings.ringnum[0].ring[0], &confp->chan.drings.ringnum[0].ring[1], &confp->chan.drings.ringnum[0].ring[2]);
14369       } else if (!strcasecmp(v->name, "dring2")) {
14370          sscanf(v->value, "%30d,%30d,%30d", &confp->chan.drings.ringnum[1].ring[0], &confp->chan.drings.ringnum[1].ring[1], &confp->chan.drings.ringnum[1].ring[2]);
14371       } else if (!strcasecmp(v->name, "dring3")) {
14372          sscanf(v->value, "%30d,%30d,%30d", &confp->chan.drings.ringnum[2].ring[0], &confp->chan.drings.ringnum[2].ring[1], &confp->chan.drings.ringnum[2].ring[2]);
14373       } else if (!strcasecmp(v->name, "usecallerid")) {
14374          confp->chan.use_callerid = ast_true(v->value);
14375       } else if (!strcasecmp(v->name, "cidsignalling")) {
14376          if (!strcasecmp(v->value, "bell"))
14377             confp->chan.cid_signalling = CID_SIG_BELL;
14378          else if (!strcasecmp(v->value, "v23"))
14379             confp->chan.cid_signalling = CID_SIG_V23;
14380          else if (!strcasecmp(v->value, "dtmf"))
14381             confp->chan.cid_signalling = CID_SIG_DTMF;
14382          else if (!strcasecmp(v->value, "smdi"))
14383             confp->chan.cid_signalling = CID_SIG_SMDI;
14384          else if (!strcasecmp(v->value, "v23_jp"))
14385             confp->chan.cid_signalling = CID_SIG_V23_JP;
14386          else if (ast_true(v->value))
14387             confp->chan.cid_signalling = CID_SIG_BELL;
14388       } else if (!strcasecmp(v->name, "cidstart")) {
14389          if (!strcasecmp(v->value, "ring"))
14390             confp->chan.cid_start = CID_START_RING;
14391          else if (!strcasecmp(v->value, "polarity_in"))
14392             confp->chan.cid_start = CID_START_POLARITY_IN;
14393          else if (!strcasecmp(v->value, "polarity"))
14394             confp->chan.cid_start = CID_START_POLARITY;
14395          else if (ast_true(v->value))
14396             confp->chan.cid_start = CID_START_RING;
14397       } else if (!strcasecmp(v->name, "threewaycalling")) {
14398          confp->chan.threewaycalling = ast_true(v->value);
14399       } else if (!strcasecmp(v->name, "cancallforward")) {
14400          confp->chan.cancallforward = ast_true(v->value);
14401       } else if (!strcasecmp(v->name, "relaxdtmf")) {
14402          if (ast_true(v->value)) 
14403             confp->chan.dtmfrelax = DSP_DIGITMODE_RELAXDTMF;
14404          else
14405             confp->chan.dtmfrelax = 0;
14406       } else if (!strcasecmp(v->name, "mailbox")) {
14407          ast_copy_string(confp->chan.mailbox, v->value, sizeof(confp->chan.mailbox));
14408       } else if (!strcasecmp(v->name, "hasvoicemail")) {
14409          if (ast_true(v->value) && ast_strlen_zero(confp->chan.mailbox)) {
14410             ast_copy_string(confp->chan.mailbox, cat, sizeof(confp->chan.mailbox));
14411          }
14412       } else if (!strcasecmp(v->name, "adsi")) {
14413          confp->chan.adsi = ast_true(v->value);
14414       } else if (!strcasecmp(v->name, "usesmdi")) {
14415          confp->chan.use_smdi = ast_true(v->value);
14416       } else if (!strcasecmp(v->name, "smdiport")) {
14417          ast_copy_string(confp->smdi_port, v->value, sizeof(confp->smdi_port));
14418       } else if (!strcasecmp(v->name, "transfer")) {
14419          confp->chan.transfer = ast_true(v->value);
14420       } else if (!strcasecmp(v->name, "canpark")) {
14421          confp->chan.canpark = ast_true(v->value);
14422       } else if (!strcasecmp(v->name, "echocancelwhenbridged")) {
14423          confp->chan.echocanbridged = ast_true(v->value);
14424       } else if (!strcasecmp(v->name, "busydetect")) {
14425          confp->chan.busydetect = ast_true(v->value);
14426       } else if (!strcasecmp(v->name, "busycount")) {
14427          confp->chan.busycount = atoi(v->value);
14428       } else if (!strcasecmp(v->name, "busypattern")) {
14429          if (sscanf(v->value, "%30d,%30d", &confp->chan.busy_tonelength, &confp->chan.busy_quietlength) != 2) {
14430             ast_log(LOG_ERROR, "busypattern= expects busypattern=tonelength,quietlength at line %d.\n", v->lineno);
14431          }
14432       } else if (!strcasecmp(v->name, "callprogress")) {
14433          confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS;
14434          if (ast_true(v->value))
14435             confp->chan.callprogress |= CALLPROGRESS_PROGRESS;
14436       } else if (!strcasecmp(v->name, "faxdetect")) {
14437          confp->chan.callprogress &= ~CALLPROGRESS_FAX;
14438          if (!strcasecmp(v->value, "incoming")) {
14439             confp->chan.callprogress |= CALLPROGRESS_FAX_INCOMING;
14440          } else if (!strcasecmp(v->value, "outgoing")) {
14441             confp->chan.callprogress |= CALLPROGRESS_FAX_OUTGOING;
14442          } else if (!strcasecmp(v->value, "both") || ast_true(v->value))
14443             confp->chan.callprogress |= CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING;
14444       } else if (!strcasecmp(v->name, "echocancel")) {
14445          process_echocancel(confp, v->value, v->lineno);
14446       } else if (!strcasecmp(v->name, "echotraining")) {
14447          if (sscanf(v->value, "%30d", &y) == 1) {
14448             if ((y < 10) || (y > 4000)) {
14449                ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 4000 ms at line %d.\n", v->lineno);             
14450             } else {
14451                confp->chan.echotraining = y;
14452             }
14453          } else if (ast_true(v->value)) {
14454             confp->chan.echotraining = 400;
14455          } else
14456             confp->chan.echotraining = 0;
14457       } else if (!strcasecmp(v->name, "hidecallerid")) {
14458          confp->chan.hidecallerid = ast_true(v->value);
14459       } else if (!strcasecmp(v->name, "hidecalleridname")) {
14460          confp->chan.hidecalleridname = ast_true(v->value);
14461       } else if (!strcasecmp(v->name, "pulsedial")) {
14462          confp->chan.pulse = ast_true(v->value);
14463       } else if (!strcasecmp(v->name, "callreturn")) {
14464          confp->chan.callreturn = ast_true(v->value);
14465       } else if (!strcasecmp(v->name, "callwaiting")) {
14466          confp->chan.callwaiting = ast_true(v->value);
14467       } else if (!strcasecmp(v->name, "callwaitingcallerid")) {
14468          confp->chan.callwaitingcallerid = ast_true(v->value);
14469       } else if (!strcasecmp(v->name, "context")) {
14470          ast_copy_string(confp->chan.context, v->value, sizeof(confp->chan.context));
14471       } else if (!strcasecmp(v->name, "language")) {
14472          ast_copy_string(confp->chan.language, v->value, sizeof(confp->chan.language));
14473       } else if (!strcasecmp(v->name, "progzone")) {
14474          ast_copy_string(progzone, v->value, sizeof(progzone));
14475       } else if (!strcasecmp(v->name, "mohinterpret") 
14476          ||!strcasecmp(v->name, "musiconhold") || !strcasecmp(v->name, "musicclass")) {
14477          ast_copy_string(confp->chan.mohinterpret, v->value, sizeof(confp->chan.mohinterpret));
14478       } else if (!strcasecmp(v->name, "mohsuggest")) {
14479          ast_copy_string(confp->chan.mohsuggest, v->value, sizeof(confp->chan.mohsuggest));
14480       } else if (!strcasecmp(v->name, "parkinglot")) {
14481          ast_copy_string(parkinglot, v->value, sizeof(parkinglot));
14482       } else if (!strcasecmp(v->name, "stripmsd")) {
14483          ast_log(LOG_NOTICE, "Configuration option \"%s\" has been deprecated. Please use dialplan instead\n", v->name);
14484          confp->chan.stripmsd = atoi(v->value);
14485       } else if (!strcasecmp(v->name, "jitterbuffers")) {
14486          numbufs = atoi(v->value);
14487       } else if (!strcasecmp(v->name, "group")) {
14488          confp->chan.group = ast_get_group(v->value);
14489       } else if (!strcasecmp(v->name, "callgroup")) {
14490          if (!strcasecmp(v->value, "none"))
14491             confp->chan.callgroup = 0;
14492          else
14493             confp->chan.callgroup = ast_get_group(v->value);
14494       } else if (!strcasecmp(v->name, "pickupgroup")) {
14495          if (!strcasecmp(v->value, "none"))
14496             confp->chan.pickupgroup = 0;
14497          else
14498             confp->chan.pickupgroup = ast_get_group(v->value);
14499       } else if (!strcasecmp(v->name, "setvar")) {
14500          char *varname = ast_strdupa(v->value), *varval = NULL;
14501          struct ast_variable *tmpvar;
14502          if (varname && (varval = strchr(varname, '='))) {
14503             *varval++ = '\0';
14504             if ((tmpvar = ast_variable_new(varname, varval, ""))) {
14505                tmpvar->next = confp->chan.vars;
14506                confp->chan.vars = tmpvar;
14507             }
14508          }
14509       } else if (!strcasecmp(v->name, "immediate")) {
14510          confp->chan.immediate = ast_true(v->value);
14511       } else if (!strcasecmp(v->name, "transfertobusy")) {
14512          confp->chan.transfertobusy = ast_true(v->value);
14513       } else if (!strcasecmp(v->name, "mwimonitor")) {
14514          confp->chan.mwimonitor_neon = 0;
14515          confp->chan.mwimonitor_fsk  = 0;
14516          confp->chan.mwimonitor_rpas = 0;
14517          if (strcasestr(v->value, "fsk")) {
14518             confp->chan.mwimonitor_fsk = 1;
14519          }
14520          if (strcasestr(v->value, "rpas")) {
14521             confp->chan.mwimonitor_rpas = 1;
14522          }
14523          if (strcasestr(v->value, "neon")) {
14524             confp->chan.mwimonitor_neon = 1;
14525          }
14526          /* If set to true or yes, assume that simple fsk is desired */
14527          if (ast_true(v->value)) {
14528             confp->chan.mwimonitor_fsk = 1;
14529          } 
14530       } else if (!strcasecmp(v->name, "cid_rxgain")) {
14531          if (sscanf(v->value, "%30f", &confp->chan.cid_rxgain) != 1) {
14532             ast_log(LOG_WARNING, "Invalid cid_rxgain: %s at line %d.\n", v->value, v->lineno);
14533          }
14534       } else if (!strcasecmp(v->name, "rxgain")) {
14535          if (sscanf(v->value, "%30f", &confp->chan.rxgain) != 1) {
14536             ast_log(LOG_WARNING, "Invalid rxgain: %s at line %d.\n", v->value, v->lineno);
14537          }
14538       } else if (!strcasecmp(v->name, "txgain")) {
14539          if (sscanf(v->value, "%30f", &confp->chan.txgain) != 1) {
14540             ast_log(LOG_WARNING, "Invalid txgain: %s at line %d.\n", v->value, v->lineno);
14541          }
14542       } else if (!strcasecmp(v->name, "tonezone")) {
14543          if (sscanf(v->value, "%30d", &confp->chan.tonezone) != 1) {
14544             ast_log(LOG_WARNING, "Invalid tonezone: %s at line %d.\n", v->value, v->lineno);
14545          }
14546       } else if (!strcasecmp(v->name, "callerid")) {
14547          if (!strcasecmp(v->value, "asreceived")) {
14548             confp->chan.cid_num[0] = '\0';
14549             confp->chan.cid_name[0] = '\0';
14550          } else {
14551             ast_callerid_split(v->value, confp->chan.cid_name, sizeof(confp->chan.cid_name), confp->chan.cid_num, sizeof(confp->chan.cid_num));
14552          } 
14553       } else if (!strcasecmp(v->name, "fullname")) {
14554          ast_copy_string(confp->chan.cid_name, v->value, sizeof(confp->chan.cid_name));
14555       } else if (!strcasecmp(v->name, "cid_number")) {
14556          ast_copy_string(confp->chan.cid_num, v->value, sizeof(confp->chan.cid_num));
14557       } else if (!strcasecmp(v->name, "useincomingcalleridondahditransfer")) {
14558          confp->chan.dahditrcallerid = ast_true(v->value);
14559       } else if (!strcasecmp(v->name, "restrictcid")) {
14560          confp->chan.restrictcid = ast_true(v->value);
14561       } else if (!strcasecmp(v->name, "usecallingpres")) {
14562          confp->chan.use_callingpres = ast_true(v->value);
14563       } else if (!strcasecmp(v->name, "accountcode")) {
14564          ast_copy_string(confp->chan.accountcode, v->value, sizeof(confp->chan.accountcode));
14565       } else if (!strcasecmp(v->name, "amaflags")) {
14566          y = ast_cdr_amaflags2int(v->value);
14567          if (y < 0) 
14568             ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d.\n", v->value, v->lineno);
14569          else
14570             confp->chan.amaflags = y;
14571       } else if (!strcasecmp(v->name, "polarityonanswerdelay")) {
14572          confp->chan.polarityonanswerdelay = atoi(v->value);
14573       } else if (!strcasecmp(v->name, "answeronpolarityswitch")) {
14574          confp->chan.answeronpolarityswitch = ast_true(v->value);
14575       } else if (!strcasecmp(v->name, "hanguponpolarityswitch")) {
14576          confp->chan.hanguponpolarityswitch = ast_true(v->value);
14577       } else if (!strcasecmp(v->name, "sendcalleridafter")) {
14578          confp->chan.sendcalleridafter = atoi(v->value);
14579       } else if (!strcasecmp(v->name, "mwimonitornotify")) {
14580          ast_copy_string(mwimonitornotify, v->value, sizeof(mwimonitornotify));
14581       } else if (!strcasecmp(v->name, "mwisendtype")) {
14582          if (!strcasecmp(v->value, "rpas")) { /* Ring Pulse Alert Signal */
14583             mwisend_rpas = 1;
14584          } else {
14585             mwisend_rpas = 0;
14586          }
14587       } else if (reload != 1) {
14588           if (!strcasecmp(v->name, "signalling") || !strcasecmp(v->name, "signaling")) {
14589             int orig_radio = confp->chan.radio;
14590             int orig_outsigmod = confp->chan.outsigmod;
14591             int orig_auto = confp->is_sig_auto;
14592 
14593             confp->chan.radio = 0;
14594             confp->chan.outsigmod = -1;
14595             confp->is_sig_auto = 0;
14596             if (!strcasecmp(v->value, "em")) {
14597                confp->chan.sig = SIG_EM;
14598             } else if (!strcasecmp(v->value, "em_e1")) {
14599                confp->chan.sig = SIG_EM_E1;
14600             } else if (!strcasecmp(v->value, "em_w")) {
14601                confp->chan.sig = SIG_EMWINK;
14602             } else if (!strcasecmp(v->value, "fxs_ls")) {
14603                confp->chan.sig = SIG_FXSLS;
14604             } else if (!strcasecmp(v->value, "fxs_gs")) {
14605                confp->chan.sig = SIG_FXSGS;
14606             } else if (!strcasecmp(v->value, "fxs_ks")) {
14607                confp->chan.sig = SIG_FXSKS;
14608             } else if (!strcasecmp(v->value, "fxo_ls")) {
14609                confp->chan.sig = SIG_FXOLS;
14610             } else if (!strcasecmp(v->value, "fxo_gs")) {
14611                confp->chan.sig = SIG_FXOGS;
14612             } else if (!strcasecmp(v->value, "fxo_ks")) {
14613                confp->chan.sig = SIG_FXOKS;
14614             } else if (!strcasecmp(v->value, "fxs_rx")) {
14615                confp->chan.sig = SIG_FXSKS;
14616                confp->chan.radio = 1;
14617             } else if (!strcasecmp(v->value, "fxo_rx")) {
14618                confp->chan.sig = SIG_FXOLS;
14619                confp->chan.radio = 1;
14620             } else if (!strcasecmp(v->value, "fxs_tx")) {
14621                confp->chan.sig = SIG_FXSLS;
14622                confp->chan.radio = 1;
14623             } else if (!strcasecmp(v->value, "fxo_tx")) {
14624                confp->chan.sig = SIG_FXOGS;
14625                confp->chan.radio = 1;
14626             } else if (!strcasecmp(v->value, "em_rx")) {
14627                confp->chan.sig = SIG_EM;
14628                confp->chan.radio = 1;
14629             } else if (!strcasecmp(v->value, "em_tx")) {
14630                confp->chan.sig = SIG_EM;
14631                confp->chan.radio = 1;
14632             } else if (!strcasecmp(v->value, "em_rxtx")) {
14633                confp->chan.sig = SIG_EM;
14634                confp->chan.radio = 2;
14635             } else if (!strcasecmp(v->value, "em_txrx")) {
14636                confp->chan.sig = SIG_EM;
14637                confp->chan.radio = 2;
14638             } else if (!strcasecmp(v->value, "sf")) {
14639                confp->chan.sig = SIG_SF;
14640             } else if (!strcasecmp(v->value, "sf_w")) {
14641                confp->chan.sig = SIG_SFWINK;
14642             } else if (!strcasecmp(v->value, "sf_featd")) {
14643                confp->chan.sig = SIG_FEATD;
14644             } else if (!strcasecmp(v->value, "sf_featdmf")) {
14645                confp->chan.sig = SIG_FEATDMF;
14646             } else if (!strcasecmp(v->value, "sf_featb")) {
14647                confp->chan.sig = SIG_SF_FEATB;
14648             } else if (!strcasecmp(v->value, "sf")) {
14649                confp->chan.sig = SIG_SF;
14650             } else if (!strcasecmp(v->value, "sf_rx")) {
14651                confp->chan.sig = SIG_SF;
14652                confp->chan.radio = 1;
14653             } else if (!strcasecmp(v->value, "sf_tx")) {
14654                confp->chan.sig = SIG_SF;
14655                confp->chan.radio = 1;
14656             } else if (!strcasecmp(v->value, "sf_rxtx")) {
14657                confp->chan.sig = SIG_SF;
14658                confp->chan.radio = 2;
14659             } else if (!strcasecmp(v->value, "sf_txrx")) {
14660                confp->chan.sig = SIG_SF;
14661                confp->chan.radio = 2;
14662             } else if (!strcasecmp(v->value, "featd")) {
14663                confp->chan.sig = SIG_FEATD;
14664             } else if (!strcasecmp(v->value, "featdmf")) {
14665                confp->chan.sig = SIG_FEATDMF;
14666             } else if (!strcasecmp(v->value, "featdmf_ta")) {
14667                confp->chan.sig = SIG_FEATDMF_TA;
14668             } else if (!strcasecmp(v->value, "e911")) {
14669                confp->chan.sig = SIG_E911;
14670             } else if (!strcasecmp(v->value, "fgccama")) {
14671                confp->chan.sig = SIG_FGC_CAMA;
14672             } else if (!strcasecmp(v->value, "fgccamamf")) {
14673                confp->chan.sig = SIG_FGC_CAMAMF;
14674             } else if (!strcasecmp(v->value, "featb")) {
14675                confp->chan.sig = SIG_FEATB;
14676 #ifdef HAVE_PRI
14677             } else if (!strcasecmp(v->value, "pri_net")) {
14678                confp->chan.sig = SIG_PRI;
14679                confp->pri.nodetype = PRI_NETWORK;
14680             } else if (!strcasecmp(v->value, "pri_cpe")) {
14681                confp->chan.sig = SIG_PRI;
14682                confp->pri.nodetype = PRI_CPE;
14683             } else if (!strcasecmp(v->value, "bri_cpe")) {
14684                confp->chan.sig = SIG_BRI;
14685                confp->pri.nodetype = PRI_CPE;
14686             } else if (!strcasecmp(v->value, "bri_net")) {
14687                confp->chan.sig = SIG_BRI;
14688                confp->pri.nodetype = PRI_NETWORK;
14689             } else if (!strcasecmp(v->value, "bri_cpe_ptmp")) {
14690                confp->chan.sig = SIG_BRI_PTMP;
14691                confp->pri.nodetype = PRI_CPE;
14692             } else if (!strcasecmp(v->value, "bri_net_ptmp")) {
14693                ast_log(LOG_WARNING, "How cool would it be if someone implemented this mode!  For now, sucks for you. (line %d)\n", v->lineno);
14694             } else if (!strcasecmp(v->value, "gr303fxoks_net")) {
14695                confp->chan.sig = SIG_GR303FXOKS;
14696                confp->pri.nodetype = PRI_NETWORK;
14697             } else if (!strcasecmp(v->value, "gr303fxsks_cpe")) {
14698                confp->chan.sig = SIG_GR303FXSKS;
14699                confp->pri.nodetype = PRI_CPE;
14700 #endif
14701 #ifdef HAVE_SS7
14702             } else if (!strcasecmp(v->value, "ss7")) {
14703                confp->chan.sig = SIG_SS7;
14704 #endif
14705             } else if (!strcasecmp(v->value, "auto")) {
14706                confp->is_sig_auto = 1;
14707             } else {
14708                confp->chan.outsigmod = orig_outsigmod;
14709                confp->chan.radio = orig_radio;
14710                confp->is_sig_auto = orig_auto;
14711                ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
14712             }
14713           } else if (!strcasecmp(v->name, "outsignalling") || !strcasecmp(v->name, "outsignaling")) {
14714             if (!strcasecmp(v->value, "em")) {
14715                confp->chan.outsigmod = SIG_EM;
14716             } else if (!strcasecmp(v->value, "em_e1")) {
14717                confp->chan.outsigmod = SIG_EM_E1;
14718             } else if (!strcasecmp(v->value, "em_w")) {
14719                confp->chan.outsigmod = SIG_EMWINK;
14720             } else if (!strcasecmp(v->value, "sf")) {
14721                confp->chan.outsigmod = SIG_SF;
14722             } else if (!strcasecmp(v->value, "sf_w")) {
14723                confp->chan.outsigmod = SIG_SFWINK;
14724             } else if (!strcasecmp(v->value, "sf_featd")) {
14725                confp->chan.outsigmod = SIG_FEATD;
14726             } else if (!strcasecmp(v->value, "sf_featdmf")) {
14727                confp->chan.outsigmod = SIG_FEATDMF;
14728             } else if (!strcasecmp(v->value, "sf_featb")) {
14729                confp->chan.outsigmod = SIG_SF_FEATB;
14730             } else if (!strcasecmp(v->value, "sf")) {
14731                confp->chan.outsigmod = SIG_SF;
14732             } else if (!strcasecmp(v->value, "featd")) {
14733                confp->chan.outsigmod = SIG_FEATD;
14734             } else if (!strcasecmp(v->value, "featdmf")) {
14735                confp->chan.outsigmod = SIG_FEATDMF;
14736             } else if (!strcasecmp(v->value, "featdmf_ta")) {
14737                confp->chan.outsigmod = SIG_FEATDMF_TA;
14738             } else if (!strcasecmp(v->value, "e911")) {
14739                confp->chan.outsigmod = SIG_E911;
14740             } else if (!strcasecmp(v->value, "fgccama")) {
14741                confp->chan.outsigmod = SIG_FGC_CAMA;
14742             } else if (!strcasecmp(v->value, "fgccamamf")) {
14743                confp->chan.outsigmod = SIG_FGC_CAMAMF;
14744             } else if (!strcasecmp(v->value, "featb")) {
14745                confp->chan.outsigmod = SIG_FEATB;
14746             } else {
14747                ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
14748             }
14749 #ifdef HAVE_PRI
14750          } else if (!strcasecmp(v->name, "pridialplan")) {
14751             if (!strcasecmp(v->value, "national")) {
14752                confp->pri.dialplan = PRI_NATIONAL_ISDN + 1;
14753             } else if (!strcasecmp(v->value, "unknown")) {
14754                confp->pri.dialplan = PRI_UNKNOWN + 1;
14755             } else if (!strcasecmp(v->value, "private")) {
14756                confp->pri.dialplan = PRI_PRIVATE + 1;
14757             } else if (!strcasecmp(v->value, "international")) {
14758                confp->pri.dialplan = PRI_INTERNATIONAL_ISDN + 1;
14759             } else if (!strcasecmp(v->value, "local")) {
14760                confp->pri.dialplan = PRI_LOCAL_ISDN + 1;
14761             } else if (!strcasecmp(v->value, "dynamic")) {
14762                confp->pri.dialplan = -1;
14763             } else if (!strcasecmp(v->value, "redundant")) {
14764                confp->pri.dialplan = -2;
14765             } else {
14766                ast_log(LOG_WARNING, "Unknown PRI dialplan '%s' at line %d.\n", v->value, v->lineno);
14767             }
14768          } else if (!strcasecmp(v->name, "prilocaldialplan")) {
14769             if (!strcasecmp(v->value, "national")) {
14770                confp->pri.localdialplan = PRI_NATIONAL_ISDN + 1;
14771             } else if (!strcasecmp(v->value, "unknown")) {
14772                confp->pri.localdialplan = PRI_UNKNOWN + 1;
14773             } else if (!strcasecmp(v->value, "private")) {
14774                confp->pri.localdialplan = PRI_PRIVATE + 1;
14775             } else if (!strcasecmp(v->value, "international")) {
14776                confp->pri.localdialplan = PRI_INTERNATIONAL_ISDN + 1;
14777             } else if (!strcasecmp(v->value, "local")) {
14778                confp->pri.localdialplan = PRI_LOCAL_ISDN + 1;
14779             } else if (!strcasecmp(v->value, "dynamic")) {
14780                confp->pri.localdialplan = -1;
14781             } else if (!strcasecmp(v->value, "redundant")) {
14782                confp->pri.localdialplan = -2;
14783             } else {
14784                ast_log(LOG_WARNING, "Unknown PRI localdialplan '%s' at line %d.\n", v->value, v->lineno);
14785             }
14786          } else if (!strcasecmp(v->name, "switchtype")) {
14787             if (!strcasecmp(v->value, "national")) 
14788                confp->pri.switchtype = PRI_SWITCH_NI2;
14789             else if (!strcasecmp(v->value, "ni1"))
14790                confp->pri.switchtype = PRI_SWITCH_NI1;
14791             else if (!strcasecmp(v->value, "dms100"))
14792                confp->pri.switchtype = PRI_SWITCH_DMS100;
14793             else if (!strcasecmp(v->value, "4ess"))
14794                confp->pri.switchtype = PRI_SWITCH_ATT4ESS;
14795             else if (!strcasecmp(v->value, "5ess"))
14796                confp->pri.switchtype = PRI_SWITCH_LUCENT5E;
14797             else if (!strcasecmp(v->value, "euroisdn"))
14798                confp->pri.switchtype = PRI_SWITCH_EUROISDN_E1;
14799             else if (!strcasecmp(v->value, "qsig"))
14800                confp->pri.switchtype = PRI_SWITCH_QSIG;
14801             else {
14802                ast_log(LOG_ERROR, "Unknown switchtype '%s' at line %d.\n", v->value, v->lineno);
14803                return -1;
14804             }
14805          } else if (!strcasecmp(v->name, "nsf")) {
14806             if (!strcasecmp(v->value, "sdn"))
14807                confp->pri.nsf = PRI_NSF_SDN;
14808             else if (!strcasecmp(v->value, "megacom"))
14809                confp->pri.nsf = PRI_NSF_MEGACOM;
14810             else if (!strcasecmp(v->value, "tollfreemegacom"))
14811                confp->pri.nsf = PRI_NSF_TOLL_FREE_MEGACOM;           
14812             else if (!strcasecmp(v->value, "accunet"))
14813                confp->pri.nsf = PRI_NSF_ACCUNET;
14814             else if (!strcasecmp(v->value, "none"))
14815                confp->pri.nsf = PRI_NSF_NONE;
14816             else {
14817                ast_log(LOG_WARNING, "Unknown network-specific facility '%s' at line %d.\n", v->value, v->lineno);
14818                confp->pri.nsf = PRI_NSF_NONE;
14819             }
14820          } else if (!strcasecmp(v->name, "priindication")) {
14821             if (!strcasecmp(v->value, "outofband"))
14822                confp->chan.priindication_oob = 1;
14823             else if (!strcasecmp(v->value, "inband"))
14824                confp->chan.priindication_oob = 0;
14825             else
14826                ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d.\n",
14827                   v->value, v->lineno);
14828          } else if (!strcasecmp(v->name, "priexclusive")) {
14829             confp->chan.priexclusive = ast_true(v->value);
14830          } else if (!strcasecmp(v->name, "internationalprefix")) {
14831             ast_copy_string(confp->pri.internationalprefix, v->value, sizeof(confp->pri.internationalprefix));
14832          } else if (!strcasecmp(v->name, "nationalprefix")) {
14833             ast_copy_string(confp->pri.nationalprefix, v->value, sizeof(confp->pri.nationalprefix));
14834          } else if (!strcasecmp(v->name, "localprefix")) {
14835             ast_copy_string(confp->pri.localprefix, v->value, sizeof(confp->pri.localprefix));
14836          } else if (!strcasecmp(v->name, "privateprefix")) {
14837             ast_copy_string(confp->pri.privateprefix, v->value, sizeof(confp->pri.privateprefix));
14838          } else if (!strcasecmp(v->name, "unknownprefix")) {
14839             ast_copy_string(confp->pri.unknownprefix, v->value, sizeof(confp->pri.unknownprefix));
14840          } else if (!strcasecmp(v->name, "resetinterval")) {
14841             if (!strcasecmp(v->value, "never"))
14842                confp->pri.resetinterval = -1;
14843             else if (atoi(v->value) >= 60)
14844                confp->pri.resetinterval = atoi(v->value);
14845             else
14846                ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
14847                   v->value, v->lineno);
14848          } else if (!strcasecmp(v->name, "minunused")) {
14849             confp->pri.minunused = atoi(v->value);
14850          } else if (!strcasecmp(v->name, "minidle")) {
14851             confp->pri.minidle = atoi(v->value); 
14852          } else if (!strcasecmp(v->name, "idleext")) {
14853             ast_copy_string(confp->pri.idleext, v->value, sizeof(confp->pri.idleext));
14854          } else if (!strcasecmp(v->name, "idledial")) {
14855             ast_copy_string(confp->pri.idledial, v->value, sizeof(confp->pri.idledial));
14856          } else if (!strcasecmp(v->name, "overlapdial")) {
14857             if (ast_true(v->value)) {
14858                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
14859             } else if (!strcasecmp(v->value, "incoming")) {
14860                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_INCOMING;
14861             } else if (!strcasecmp(v->value, "outgoing")) {
14862                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_OUTGOING;
14863             } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) {
14864                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
14865             } else {
14866                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_NONE;
14867             }
14868 #ifdef HAVE_PRI_INBANDDISCONNECT
14869          } else if (!strcasecmp(v->name, "inbanddisconnect")) {
14870             confp->pri.inbanddisconnect = ast_true(v->value);
14871 #endif
14872          } else if (!strcasecmp(v->name, "pritimer")) {
14873 #ifdef PRI_GETSET_TIMERS
14874             char tmp[20];
14875             char *timerc;
14876             char *c;
14877             int timer;
14878             int timeridx;
14879 
14880             ast_copy_string(tmp, v->value, sizeof(tmp));
14881             c = tmp;
14882             timerc = strsep(&c, ",");
14883             if (!ast_strlen_zero(timerc) && !ast_strlen_zero(c)) {
14884                timeridx = pri_timer2idx(timerc);
14885                timer = atoi(c);
14886                if (timeridx < 0 || PRI_MAX_TIMERS <= timeridx) {
14887                   ast_log(LOG_WARNING,
14888                      "'%s' is not a valid ISDN timer at line %d.\n", timerc,
14889                      v->lineno);
14890                } else if (!timer) {
14891                   ast_log(LOG_WARNING,
14892                      "'%s' is not a valid value for ISDN timer '%s' at line %d.\n",
14893                      c, timerc, v->lineno);
14894                } else {
14895                   pritimers[timeridx] = timer;
14896                }
14897             } else {
14898                ast_log(LOG_WARNING,
14899                   "'%s' is not a valid ISDN timer configuration string at line %d.\n",
14900                   v->value, v->lineno);
14901             }
14902 
14903          } else if (!strcasecmp(v->name, "facilityenable")) {
14904             confp->pri.facilityenable = ast_true(v->value);
14905 #endif /* PRI_GETSET_TIMERS */
14906 #endif /* HAVE_PRI */
14907 #ifdef HAVE_SS7
14908          } else if (!strcasecmp(v->name, "ss7type")) {
14909             if (!strcasecmp(v->value, "itu")) {
14910                cur_ss7type = SS7_ITU;
14911             } else if (!strcasecmp(v->value, "ansi")) {
14912                cur_ss7type = SS7_ANSI;
14913             } else
14914                ast_log(LOG_WARNING, "'%s' is an unknown ss7 switch type at line %d.!\n", v->value, v->lineno);
14915          } else if (!strcasecmp(v->name, "linkset")) {
14916             cur_linkset = atoi(v->value);
14917          } else if (!strcasecmp(v->name, "pointcode")) {
14918             cur_pointcode = parse_pointcode(v->value);
14919          } else if (!strcasecmp(v->name, "adjpointcode")) {
14920             cur_adjpointcode = parse_pointcode(v->value);
14921          } else if (!strcasecmp(v->name, "defaultdpc")) {
14922             cur_defaultdpc = parse_pointcode(v->value);
14923          } else if (!strcasecmp(v->name, "cicbeginswith")) {
14924             cur_cicbeginswith = atoi(v->value);
14925          } else if (!strcasecmp(v->name, "networkindicator")) {
14926             if (!strcasecmp(v->value, "national"))
14927                cur_networkindicator = SS7_NI_NAT;
14928             else if (!strcasecmp(v->value, "national_spare"))
14929                cur_networkindicator = SS7_NI_NAT_SPARE;
14930             else if (!strcasecmp(v->value, "international"))
14931                cur_networkindicator = SS7_NI_INT;
14932             else if (!strcasecmp(v->value, "international_spare"))
14933                cur_networkindicator = SS7_NI_INT_SPARE;
14934             else
14935                cur_networkindicator = -1;
14936          } else if (!strcasecmp(v->name, "ss7_internationalprefix")) {
14937             ast_copy_string(confp->ss7.internationalprefix, v->value, sizeof(confp->ss7.internationalprefix));
14938          } else if (!strcasecmp(v->name, "ss7_nationalprefix")) {
14939             ast_copy_string(confp->ss7.nationalprefix, v->value, sizeof(confp->ss7.nationalprefix));
14940          } else if (!strcasecmp(v->name, "ss7_subscriberprefix")) {
14941             ast_copy_string(confp->ss7.subscriberprefix, v->value, sizeof(confp->ss7.subscriberprefix));
14942          } else if (!strcasecmp(v->name, "ss7_unknownprefix")) {
14943             ast_copy_string(confp->ss7.unknownprefix, v->value, sizeof(confp->ss7.unknownprefix));
14944          } else if (!strcasecmp(v->name, "ss7_called_nai")) {
14945             if (!strcasecmp(v->value, "national")) {
14946                confp->ss7.called_nai = SS7_NAI_NATIONAL;
14947             } else if (!strcasecmp(v->value, "international")) {
14948                confp->ss7.called_nai = SS7_NAI_INTERNATIONAL;
14949             } else if (!strcasecmp(v->value, "subscriber")) {
14950                confp->ss7.called_nai = SS7_NAI_SUBSCRIBER;
14951             } else if (!strcasecmp(v->value, "dynamic")) {
14952                confp->ss7.called_nai = SS7_NAI_DYNAMIC;
14953             } else {
14954                ast_log(LOG_WARNING, "Unknown SS7 called_nai '%s' at line %d.\n", v->value, v->lineno);
14955             }
14956          } else if (!strcasecmp(v->name, "ss7_calling_nai")) {
14957             if (!strcasecmp(v->value, "national")) {
14958                confp->ss7.calling_nai = SS7_NAI_NATIONAL;
14959             } else if (!strcasecmp(v->value, "international")) {
14960                confp->ss7.calling_nai = SS7_NAI_INTERNATIONAL;
14961             } else if (!strcasecmp(v->value, "subscriber")) {
14962                confp->ss7.calling_nai = SS7_NAI_SUBSCRIBER;
14963             } else if (!strcasecmp(v->value, "dynamic")) {
14964                confp->ss7.calling_nai = SS7_NAI_DYNAMIC;
14965             } else {
14966                ast_log(LOG_WARNING, "Unknown SS7 calling_nai '%s' at line %d.\n", v->value, v->lineno);
14967             }
14968          } else if (!strcasecmp(v->name, "sigchan")) {
14969             int sigchan, res;
14970             sigchan = atoi(v->value);
14971             res = linkset_addsigchan(sigchan);
14972             if (res < 0)
14973                return -1;
14974 
14975          } else if (!strcasecmp(v->name, "ss7_explicitacm")) {
14976             struct dahdi_ss7 *link;
14977             link = ss7_resolve_linkset(cur_linkset);
14978             if (!link) {
14979                ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
14980                return -1;
14981             }
14982             if (ast_true(v->value))
14983                link->flags |= LINKSET_FLAG_EXPLICITACM;
14984 
14985 #endif /* HAVE_SS7 */
14986          } else if (!strcasecmp(v->name, "cadence")) {
14987             /* setup to scan our argument */
14988             int element_count, c[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
14989             int i;
14990             struct dahdi_ring_cadence new_cadence;
14991             int cid_location = -1;
14992             int firstcadencepos = 0;
14993             char original_args[80];
14994             int cadence_is_ok = 1;
14995 
14996             ast_copy_string(original_args, v->value, sizeof(original_args));
14997             /* 16 cadences allowed (8 pairs) */
14998             element_count = sscanf(v->value, "%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d,%30d", &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]);
14999    
15000             /* Cadence must be even (on/off) */
15001             if (element_count % 2 == 1) {
15002                ast_log(LOG_ERROR, "Must be a silence duration for each ring duration: %s at line %d.\n", original_args, v->lineno);
15003                cadence_is_ok = 0;
15004             }
15005    
15006             /* Ring cadences cannot be negative */
15007             for (i = 0; i < element_count; i++) {
15008                if (c[i] == 0) {
15009                   ast_log(LOG_ERROR, "Ring or silence duration cannot be zero: %s at line %d.\n", original_args, v->lineno);
15010                   cadence_is_ok = 0;
15011                   break;
15012                } else if (c[i] < 0) {
15013                   if (i % 2 == 1) {
15014                      /* Silence duration, negative possibly okay */
15015                      if (cid_location == -1) {
15016                         cid_location = i;
15017                         c[i] *= -1;
15018                      } else {
15019                         ast_log(LOG_ERROR, "CID location specified twice: %s at line %d.\n", original_args, v->lineno);
15020                         cadence_is_ok = 0;
15021                         break;
15022                      }
15023                   } else {
15024                      if (firstcadencepos == 0) {
15025                         firstcadencepos = i; /* only recorded to avoid duplicate specification */
15026                                  /* duration will be passed negative to the DAHDI driver */
15027                      } else {
15028                          ast_log(LOG_ERROR, "First cadence position specified twice: %s at line %d.\n", original_args, v->lineno);
15029                         cadence_is_ok = 0;
15030                         break;
15031                      }
15032                   }
15033                }
15034             }
15035    
15036             /* Substitute our scanned cadence */
15037             for (i = 0; i < 16; i++) {
15038                new_cadence.ringcadence[i] = c[i];
15039             }
15040    
15041             if (cadence_is_ok) {
15042                /* ---we scanned it without getting annoyed; now some sanity checks--- */
15043                if (element_count < 2) {
15044                   ast_log(LOG_ERROR, "Minimum cadence is ring,pause: %s at line %d.\n", original_args, v->lineno);
15045                } else {
15046                   if (cid_location == -1) {
15047                      /* user didn't say; default to first pause */
15048                      cid_location = 1;
15049                   } else {
15050                      /* convert element_index to cidrings value */
15051                      cid_location = (cid_location + 1) / 2;
15052                   }
15053                   /* ---we like their cadence; try to install it--- */
15054                   if (!user_has_defined_cadences++)
15055                      /* this is the first user-defined cadence; clear the default user cadences */
15056                      num_cadence = 0;
15057                   if ((num_cadence+1) >= NUM_CADENCE_MAX)
15058                      ast_log(LOG_ERROR, "Already %d cadences; can't add another: %s at line %d.\n", NUM_CADENCE_MAX, original_args, v->lineno);
15059                   else {
15060                      cadences[num_cadence] = new_cadence;
15061                      cidrings[num_cadence++] = cid_location;
15062                      ast_verb(3, "cadence 'r%d' added: %s\n",num_cadence,original_args);
15063                   }
15064                }
15065             }
15066          } else if (!strcasecmp(v->name, "ringtimeout")) {
15067             ringt_base = (atoi(v->value) * 8) / READ_SIZE;
15068          } else if (!strcasecmp(v->name, "prewink")) {
15069             confp->timing.prewinktime = atoi(v->value);
15070          } else if (!strcasecmp(v->name, "preflash")) {
15071             confp->timing.preflashtime = atoi(v->value);
15072          } else if (!strcasecmp(v->name, "wink")) {
15073             confp->timing.winktime = atoi(v->value);
15074          } else if (!strcasecmp(v->name, "flash")) {
15075             confp->timing.flashtime = atoi(v->value);
15076          } else if (!strcasecmp(v->name, "start")) {
15077             confp->timing.starttime = atoi(v->value);
15078          } else if (!strcasecmp(v->name, "rxwink")) {
15079             confp->timing.rxwinktime = atoi(v->value);
15080          } else if (!strcasecmp(v->name, "rxflash")) {
15081             confp->timing.rxflashtime = atoi(v->value);
15082          } else if (!strcasecmp(v->name, "debounce")) {
15083             confp->timing.debouncetime = atoi(v->value);
15084          } else if (!strcasecmp(v->name, "toneduration")) {
15085             int toneduration;
15086             int ctlfd;
15087             int res;
15088             struct dahdi_dialparams dps;
15089 
15090             ctlfd = open("/dev/dahdi/ctl", O_RDWR);
15091             if (ctlfd == -1) {
15092                ast_log(LOG_ERROR, "Unable to open /dev/dahdi/ctl to set toneduration at line %d.\n", v->lineno);
15093                return -1;
15094             }
15095 
15096             toneduration = atoi(v->value);
15097             if (toneduration > -1) {
15098                memset(&dps, 0, sizeof(dps));
15099 
15100                dps.dtmf_tonelen = dps.mfv1_tonelen = toneduration;
15101                res = ioctl(ctlfd, DAHDI_SET_DIALPARAMS, &dps);
15102                if (res < 0) {
15103                   ast_log(LOG_ERROR, "Invalid tone duration: %d ms at line %d: %s\n", toneduration, v->lineno, strerror(errno));
15104                   return -1;
15105                }
15106             }
15107             close(ctlfd);
15108          } else if (!strcasecmp(v->name, "defaultcic")) {
15109             ast_copy_string(defaultcic, v->value, sizeof(defaultcic));
15110          } else if (!strcasecmp(v->name, "defaultozz")) {
15111             ast_copy_string(defaultozz, v->value, sizeof(defaultozz));
15112          } else if (!strcasecmp(v->name, "mwilevel")) {
15113             mwilevel = atoi(v->value);
15114          }
15115       } else if (!(options & PROC_DAHDI_OPT_NOWARN) )
15116          ast_log(LOG_WARNING, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
15117    }
15118    if (dahdichan[0]) { 
15119       /* The user has set 'dahdichan' */
15120       /*< \todo pass proper line number instead of 0 */
15121       if (build_channels(confp, 0, dahdichan, reload, 0, &found_pseudo)) {
15122          return -1;
15123       }
15124    }
15125    /*< \todo why check for the pseudo in the per-channel section.
15126     * Any actual use for manual setup of the pseudo channel? */
15127    if (!found_pseudo && reload != 1) {
15128       /* use the default configuration for a channel, so
15129          that any settings from real configured channels
15130          don't "leak" into the pseudo channel config
15131       */
15132       struct dahdi_chan_conf conf = dahdi_chan_conf_default();
15133 
15134       tmp = mkintf(CHAN_PSEUDO, &conf, NULL, reload);
15135 
15136       if (tmp) {
15137          ast_verb(3, "Automatically generated pseudo channel\n");
15138       } else {
15139          ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
15140       }
15141    }
15142    return 0;
15143 }
15144       
15145 static int setup_dahdi(int reload)
15146 {
15147    struct ast_config *cfg, *ucfg;
15148    struct ast_variable *v;
15149    struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
15150    struct dahdi_chan_conf conf;
15151    struct ast_flags config_flags = { reload == 1 ? CONFIG_FLAG_FILEUNCHANGED : 0 };
15152    const char *cat;
15153    int res;
15154 
15155 #ifdef HAVE_PRI
15156    char *c;
15157    int spanno;
15158    int i;
15159    int logicalspan;
15160    int trunkgroup;
15161    int dchannels[NUM_DCHANS];
15162 #endif
15163 
15164    cfg = ast_config_load(config, config_flags);
15165 
15166    /* Error if we have no config file */
15167    if (!cfg) {
15168       ast_log(LOG_ERROR, "Unable to load config %s\n", config);
15169       return 0;
15170    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
15171       ucfg = ast_config_load("users.conf", config_flags);
15172       if (ucfg == CONFIG_STATUS_FILEUNCHANGED)
15173          return 0;
15174       ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
15175       cfg = ast_config_load(config, config_flags);
15176    } else {
15177       ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
15178       ucfg = ast_config_load("users.conf", config_flags);
15179    }
15180 
15181    /* It's a little silly to lock it, but we mind as well just to be sure */
15182    ast_mutex_lock(&iflock);
15183 #ifdef HAVE_PRI
15184    if (reload != 1) {
15185       /* Process trunkgroups first */
15186       v = ast_variable_browse(cfg, "trunkgroups");
15187       while (v) {
15188          if (!strcasecmp(v->name, "trunkgroup")) {
15189             trunkgroup = atoi(v->value);
15190             if (trunkgroup > 0) {
15191                if ((c = strchr(v->value, ','))) {
15192                   i = 0;
15193                   memset(dchannels, 0, sizeof(dchannels));
15194                   while (c && (i < NUM_DCHANS)) {
15195                      dchannels[i] = atoi(c + 1);
15196                      if (dchannels[i] < 0) {
15197                         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);
15198                      } else
15199                         i++;
15200                      c = strchr(c + 1, ',');
15201                   }
15202                   if (i) {
15203                      if (pri_create_trunkgroup(trunkgroup, dchannels)) {
15204                         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);
15205                   } else
15206                         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");
15207                   } else
15208                      ast_log(LOG_WARNING, "Trunk group %d lacks any valid D-channels at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
15209                } else
15210                   ast_log(LOG_WARNING, "Trunk group %d lacks a primary D-channel at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
15211             } else
15212                ast_log(LOG_WARNING, "Trunk group identifier must be a positive integer at line %d of chan_dahdi.conf\n", v->lineno);
15213          } else if (!strcasecmp(v->name, "spanmap")) {
15214             spanno = atoi(v->value);
15215             if (spanno > 0) {
15216                if ((c = strchr(v->value, ','))) {
15217                   trunkgroup = atoi(c + 1);
15218                   if (trunkgroup > 0) {
15219                      if ((c = strchr(c + 1, ','))) 
15220                         logicalspan = atoi(c + 1);
15221                      else
15222                         logicalspan = 0;
15223                      if (logicalspan >= 0) {
15224                         if (pri_create_spanmap(spanno - 1, trunkgroup, logicalspan)) {
15225                            ast_log(LOG_WARNING, "Failed to map span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
15226                      } else
15227                            ast_verb(2, "Mapped span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
15228                      } else
15229                         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);
15230                   } else
15231                      ast_log(LOG_WARNING, "Trunk group must be a postive number at line %d of chan_dahdi.conf\n", v->lineno);
15232                } else
15233                   ast_log(LOG_WARNING, "Missing trunk group for span map at line %d of chan_dahdi.conf\n", v->lineno);
15234             } else
15235                ast_log(LOG_WARNING, "Span number must be a postive integer at line %d of chan_dahdi.conf\n", v->lineno);
15236          } else {
15237             ast_log(LOG_NOTICE, "Ignoring unknown keyword '%s' in trunkgroups\n", v->name);
15238          }
15239          v = v->next;
15240       }
15241    }
15242 #endif
15243    
15244    /* Copy the default jb config over global_jbconf */
15245    memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
15246 
15247    mwimonitornotify[0] = '\0';
15248 
15249    v = ast_variable_browse(cfg, "channels");
15250    if ((res = process_dahdi(&base_conf, "", v, reload, 0))) {
15251       ast_mutex_unlock(&iflock);
15252       ast_config_destroy(cfg);
15253       if (ucfg) {
15254          ast_config_destroy(ucfg);
15255       }
15256       return res;
15257    }
15258 
15259    /* Now get configuration from all normal sections in chan_dahdi.conf: */
15260    for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
15261       /* [channels] and [trunkgroups] are used. Let's also reserve
15262        * [globals] and [general] for future use
15263        */
15264       if (!strcasecmp(cat, "general") || 
15265           !strcasecmp(cat, "trunkgroups") ||
15266           !strcasecmp(cat, "globals") ||
15267           !strcasecmp(cat, "channels")) {
15268          continue;
15269       }
15270 
15271       memcpy(&conf, &base_conf, sizeof(conf));
15272 
15273       if ((res = process_dahdi(&conf, cat, ast_variable_browse(cfg, cat), reload, PROC_DAHDI_OPT_NOCHAN))) {
15274          ast_mutex_unlock(&iflock);
15275          ast_config_destroy(cfg);
15276          if (ucfg) {
15277             ast_config_destroy(cfg);
15278          }
15279          return res;
15280       }
15281    }
15282 
15283    ast_config_destroy(cfg);
15284 
15285    if (ucfg) {
15286       const char *chans;
15287 
15288       process_dahdi(&base_conf, "", ast_variable_browse(ucfg, "general"), 1, 0);
15289 
15290       for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
15291          if (!strcasecmp(cat, "general")) {
15292             continue;
15293          }
15294 
15295          chans = ast_variable_retrieve(ucfg, cat, "dahdichan");
15296 
15297          if (ast_strlen_zero(chans)) {
15298             continue;
15299          }
15300 
15301          memcpy(&conf, &base_conf, sizeof(conf));
15302 
15303          if ((res = process_dahdi(&conf, cat, ast_variable_browse(ucfg, cat), reload, PROC_DAHDI_OPT_NOCHAN | PROC_DAHDI_OPT_NOWARN))) {
15304             ast_config_destroy(ucfg);
15305             ast_mutex_unlock(&iflock);
15306             return res;
15307          }
15308       }
15309       ast_config_destroy(ucfg);
15310    }
15311    ast_mutex_unlock(&iflock);
15312 
15313 #ifdef HAVE_PRI
15314    if (reload != 1) {
15315       int x;
15316       for (x = 0; x < NUM_SPANS; x++) {
15317          if (pris[x].pvts[0]) {
15318             if (start_pri(pris + x)) {
15319                ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
15320                return -1;
15321             } else
15322                ast_verb(2, "Starting D-Channel on span %d\n", x + 1);
15323          }
15324       }
15325    }
15326 #endif
15327 #ifdef HAVE_SS7
15328    if (reload != 1) {
15329       int x;
15330       for (x = 0; x < NUM_SPANS; x++) {
15331          if (linksets[x].ss7) {
15332             if (ast_pthread_create(&linksets[x].master, NULL, ss7_linkset, &linksets[x])) {
15333                ast_log(LOG_ERROR, "Unable to start SS7 linkset on span %d\n", x + 1);
15334                return -1;
15335             } else
15336                ast_verb(2, "Starting SS7 linkset on span %d\n", x + 1);
15337          }
15338       }
15339    }
15340 #endif
15341    /* And start the monitor for the first time */
15342    restart_monitor();
15343    return 0;
15344 }
15345 
15346 static int load_module(void)
15347 {
15348    int res;
15349 #if defined(HAVE_PRI) || defined(HAVE_SS7)
15350    int y, i;
15351 #endif
15352 
15353 #ifdef HAVE_PRI
15354    memset(pris, 0, sizeof(pris));
15355    for (y = 0; y < NUM_SPANS; y++) {
15356       ast_mutex_init(&pris[y].lock);
15357       pris[y].offset = -1;
15358       pris[y].master = AST_PTHREADT_NULL;
15359       for (i = 0; i < NUM_DCHANS; i++)
15360          pris[y].fds[i] = -1;
15361    }
15362    pri_set_error(dahdi_pri_error);
15363    pri_set_message(dahdi_pri_message);
15364    ast_register_application(dahdi_send_keypad_facility_app, dahdi_send_keypad_facility_exec,
15365          dahdi_send_keypad_facility_synopsis, dahdi_send_keypad_facility_descrip);
15366 #endif
15367 #ifdef HAVE_SS7
15368    memset(linksets, 0, sizeof(linksets));
15369    for (y = 0; y < NUM_SPANS; y++) {
15370       ast_mutex_init(&linksets[y].lock);
15371       linksets[y].master = AST_PTHREADT_NULL;
15372       for (i = 0; i < NUM_DCHANS; i++)
15373          linksets[y].fds[i] = -1;
15374    }
15375    ss7_set_error(dahdi_ss7_error);
15376    ss7_set_message(dahdi_ss7_message);
15377 #endif /* HAVE_SS7 */
15378    res = setup_dahdi(0);
15379    /* Make sure we can register our DAHDI channel type */
15380    if (res)
15381       return AST_MODULE_LOAD_DECLINE;
15382    if (ast_channel_register(&dahdi_tech)) {
15383       ast_log(LOG_ERROR, "Unable to register channel class 'DAHDI'\n");
15384       __unload_module();
15385       return AST_MODULE_LOAD_FAILURE;
15386    }
15387 #ifdef HAVE_PRI
15388    ast_string_field_init(&inuse, 16);
15389    ast_string_field_set(&inuse, name, "GR-303InUse");
15390    ast_cli_register_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
15391 #endif   
15392 #ifdef HAVE_SS7
15393    ast_cli_register_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
15394 #endif
15395 
15396    ast_cli_register_multiple(dahdi_cli, ARRAY_LEN(dahdi_cli));
15397    
15398    memset(round_robin, 0, sizeof(round_robin));
15399    ast_manager_register( "DAHDITransfer", 0, action_transfer, "Transfer DAHDI Channel" );
15400    ast_manager_register( "DAHDIHangup", 0, action_transferhangup, "Hangup DAHDI Channel" );
15401    ast_manager_register( "DAHDIDialOffhook", 0, action_dahdidialoffhook, "Dial over DAHDI channel while offhook" );
15402    ast_manager_register( "DAHDIDNDon", 0, action_dahdidndon, "Toggle DAHDI channel Do Not Disturb status ON" );
15403    ast_manager_register( "DAHDIDNDoff", 0, action_dahdidndoff, "Toggle DAHDI channel Do Not Disturb status OFF" );
15404    ast_manager_register("DAHDIShowChannels", 0, action_dahdishowchannels, "Show status DAHDI channels");
15405    ast_manager_register("DAHDIRestart", 0, action_dahdirestart, "Fully Restart DAHDI channels (terminates calls)");
15406 
15407    ast_cond_init(&mwi_thread_complete, NULL);
15408    ast_cond_init(&ss_thread_complete, NULL);
15409 
15410    return res;
15411 }
15412 
15413 static int dahdi_sendtext(struct ast_channel *c, const char *text)
15414 {
15415 #define  END_SILENCE_LEN 400
15416 #define  HEADER_MS 50
15417 #define  TRAILER_MS 5
15418 #define  HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
15419 #define  ASCII_BYTES_PER_CHAR 80
15420 
15421    unsigned char *buf,*mybuf;
15422    struct dahdi_pvt *p = c->tech_pvt;
15423    struct pollfd fds[1];
15424    int size,res,fd,len,x;
15425    int bytes=0;
15426    /* Initial carrier (imaginary) */
15427    float cr = 1.0;
15428    float ci = 0.0;
15429    float scont = 0.0;
15430    int idx;
15431 
15432    idx = dahdi_get_index(c, p, 0);
15433    if (idx < 0) {
15434       ast_log(LOG_WARNING, "Huh?  I don't exist?\n");
15435       return -1;
15436    }
15437    if (!text[0]) return(0); /* if nothing to send, dont */
15438    if ((!p->tdd) && (!p->mate)) return(0);  /* if not in TDD mode, just return */
15439    if (p->mate) 
15440       buf = ast_malloc(((strlen(text) + 1) * ASCII_BYTES_PER_CHAR) + END_SILENCE_LEN + HEADER_LEN);
15441    else
15442       buf = ast_malloc(((strlen(text) + 1) * TDD_BYTES_PER_CHAR) + END_SILENCE_LEN);
15443    if (!buf)
15444       return -1;
15445    mybuf = buf;
15446    if (p->mate) {
15447       int codec = AST_LAW(p);
15448       for (x = 0; x < HEADER_MS; x++) {   /* 50 ms of Mark */
15449          PUT_CLID_MARKMS;
15450       }
15451       /* Put actual message */
15452       for (x = 0; text[x]; x++) {
15453          PUT_CLID(text[x]);
15454       }
15455       for (x = 0; x < TRAILER_MS; x++) {  /* 5 ms of Mark */
15456          PUT_CLID_MARKMS;
15457       }
15458       len = bytes;
15459       buf = mybuf;
15460    } else {
15461       len = tdd_generate(p->tdd, buf, text);
15462       if (len < 1) {
15463          ast_log(LOG_ERROR, "TDD generate (len %d) failed!!\n", (int)strlen(text));
15464          ast_free(mybuf);
15465          return -1;
15466       }
15467    }
15468    memset(buf + len, 0x7f, END_SILENCE_LEN);
15469    len += END_SILENCE_LEN;
15470    fd = p->subs[idx].dfd;
15471    while (len) {
15472       if (ast_check_hangup(c)) {
15473          ast_free(mybuf);
15474          return -1;
15475       }
15476       size = len;
15477       if (size > READ_SIZE)
15478          size = READ_SIZE;
15479       fds[0].fd = fd;
15480       fds[0].events = POLLOUT | POLLPRI;
15481       fds[0].revents = 0;
15482       res = poll(fds, 1, -1);
15483       if (!res) {
15484          ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
15485          continue;
15486       }
15487         /* if got exception */
15488       if (fds[0].revents & POLLPRI) {
15489          ast_free(mybuf);
15490          return -1;
15491       }
15492       if (!(fds[0].revents & POLLOUT)) {
15493          ast_debug(1, "write fd not ready on channel %d\n", p->channel);
15494          continue;
15495       }
15496       res = write(fd, buf, size);
15497       if (res != size) {
15498          if (res == -1) {
15499             ast_free(mybuf);
15500             return -1;
15501          }
15502          ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
15503          break;
15504       }
15505       len -= size;
15506       buf += size;
15507    }
15508    ast_free(mybuf);
15509    return(0);
15510 }
15511 
15512 
15513 static int reload(void)
15514 {
15515    int res = 0;
15516 
15517    res = setup_dahdi(1);
15518    if (res) {
15519       ast_log(LOG_WARNING, "Reload of chan_dahdi.so is unsuccessful!\n");
15520       return -1;
15521    }
15522    return 0;
15523 }
15524 
15525 /* This is a workaround so that menuselect displays a proper description
15526  * AST_MODULE_INFO(, , "DAHDI Telephony"
15527  */
15528 
15529 #ifdef HAVE_PRI
15530 #ifdef HAVE_SS7
15531 #define tdesc "DAHDI Telephony w/PRI & SS7"
15532 #else
15533 #define tdesc "DAHDI Telephony w/PRI"
15534 #endif
15535 #else
15536 #ifdef HAVE_SS7
15537 #define tdesc "DAHDI Telephony w/SS7"
15538 #else
15539 #define tdesc "DAHDI Telephony"
15540 #endif
15541 #endif
15542 
15543 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
15544       .load = load_module,
15545       .unload = unload_module,
15546       .reload = reload,
15547           );
15548 
15549 

Generated on 8 Apr 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1