Tue Mar 2 17:31:45 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: 232093 $")
00051 
00052 #ifdef __NetBSD__
00053 #include <pthread.h>
00054 #include <signal.h>
00055 #else
00056 #include <sys/signal.h>
00057 #endif
00058 #include <sys/ioctl.h>
00059 #include <math.h>
00060 #include <ctype.h>
00061 
00062 #include <dahdi/user.h>
00063 #include <dahdi/tonezone.h>
00064 
00065 #ifdef HAVE_PRI
00066 #include <libpri.h>
00067 #endif
00068 
00069 #ifdef HAVE_SS7
00070 #include <libss7.h>
00071 #endif
00072 
00073 #include "asterisk/lock.h"
00074 #include "asterisk/channel.h"
00075 #include "asterisk/config.h"
00076 #include "asterisk/module.h"
00077 #include "asterisk/pbx.h"
00078 #include "asterisk/file.h"
00079 #include "asterisk/ulaw.h"
00080 #include "asterisk/alaw.h"
00081 #include "asterisk/callerid.h"
00082 #include "asterisk/adsi.h"
00083 #include "asterisk/cli.h"
00084 #include "asterisk/cdr.h"
00085 #include "asterisk/features.h"
00086 #include "asterisk/musiconhold.h"
00087 #include "asterisk/say.h"
00088 #include "asterisk/tdd.h"
00089 #include "asterisk/app.h"
00090 #include "asterisk/dsp.h"
00091 #include "asterisk/astdb.h"
00092 #include "asterisk/manager.h"
00093 #include "asterisk/causes.h"
00094 #include "asterisk/term.h"
00095 #include "asterisk/utils.h"
00096 #include "asterisk/transcap.h"
00097 #include "asterisk/stringfields.h"
00098 #include "asterisk/abstract_jb.h"
00099 #include "asterisk/smdi.h"
00100 #include "asterisk/astobj.h"
00101 #include "asterisk/event.h"
00102 #include "asterisk/devicestate.h"
00103 
00104 #define SMDI_MD_WAIT_TIMEOUT 1500 /* 1.5 seconds */
00105 
00106 static const char *lbostr[] = {
00107 "0 db (CSU)/0-133 feet (DSX-1)",
00108 "133-266 feet (DSX-1)",
00109 "266-399 feet (DSX-1)",
00110 "399-533 feet (DSX-1)",
00111 "533-655 feet (DSX-1)",
00112 "-7.5db (CSU)",
00113 "-15db (CSU)",
00114 "-22.5db (CSU)"
00115 };
00116 
00117 /*! Global jitterbuffer configuration - by default, jb is disabled */
00118 static struct ast_jb_conf default_jbconf =
00119 {
00120    .flags = 0,
00121    .max_size = -1,
00122    .resync_threshold = -1,
00123    .impl = ""
00124 };
00125 static struct ast_jb_conf global_jbconf;
00126 
00127 /* define this to send PRI user-user information elements */
00128 #undef SUPPORT_USERUSER
00129 
00130 /*! 
00131  * \note Define ZHONE_HACK to cause us to go off hook and then back on hook when
00132  * the user hangs up to reset the state machine so ring works properly.
00133  * This is used to be able to support kewlstart by putting the zhone in
00134  * groundstart mode since their forward disconnect supervision is entirely
00135  * broken even though their documentation says it isn't and their support
00136  * is entirely unwilling to provide any assistance with their channel banks
00137  * even though their web site says they support their products for life.
00138  */
00139 /* #define ZHONE_HACK */
00140 
00141 /*! \note
00142  * Define if you want to check the hook state for an FXO (FXS signalled) interface
00143  * before dialing on it.  Certain FXO interfaces always think they're out of
00144  * service with this method however.
00145  */
00146 /* #define DAHDI_CHECK_HOOKSTATE */
00147 
00148 /*! \brief Typically, how many rings before we should send Caller*ID */
00149 #define DEFAULT_CIDRINGS 1
00150 
00151 #define CHANNEL_PSEUDO -12
00152 
00153 #define AST_LAW(p) (((p)->law == DAHDI_LAW_ALAW) ? AST_FORMAT_ALAW : AST_FORMAT_ULAW)
00154 
00155 
00156 /*! \brief Signaling types that need to use MF detection should be placed in this macro */
00157 #define NEED_MFDETECT(p) (((p)->sig == SIG_FEATDMF) || ((p)->sig == SIG_FEATDMF_TA) || ((p)->sig == SIG_E911) || ((p)->sig == SIG_FGC_CAMA) || ((p)->sig == SIG_FGC_CAMAMF) || ((p)->sig == SIG_FEATB)) 
00158 
00159 static const char tdesc[] = "DAHDI Telephony Driver"
00160 #ifdef HAVE_PRI
00161                " w/PRI"
00162 #endif
00163 #ifdef HAVE_SS7
00164           " w/SS7"
00165 #endif
00166 ;
00167 
00168 static const char config[] = "chan_dahdi.conf";
00169 
00170 #define SIG_EM    DAHDI_SIG_EM
00171 #define SIG_EMWINK   (0x0100000 | DAHDI_SIG_EM)
00172 #define SIG_FEATD (0x0200000 | DAHDI_SIG_EM)
00173 #define  SIG_FEATDMF (0x0400000 | DAHDI_SIG_EM)
00174 #define  SIG_FEATB   (0x0800000 | DAHDI_SIG_EM)
00175 #define  SIG_E911 (0x1000000 | DAHDI_SIG_EM)
00176 #define  SIG_FEATDMF_TA (0x2000000 | DAHDI_SIG_EM)
00177 #define  SIG_FGC_CAMA   (0x4000000 | DAHDI_SIG_EM)
00178 #define  SIG_FGC_CAMAMF (0x8000000 | DAHDI_SIG_EM)
00179 #define SIG_FXSLS DAHDI_SIG_FXSLS
00180 #define SIG_FXSGS DAHDI_SIG_FXSGS
00181 #define SIG_FXSKS DAHDI_SIG_FXSKS
00182 #define SIG_FXOLS DAHDI_SIG_FXOLS
00183 #define SIG_FXOGS DAHDI_SIG_FXOGS
00184 #define SIG_FXOKS DAHDI_SIG_FXOKS
00185 #define SIG_PRI      DAHDI_SIG_CLEAR
00186 #define SIG_BRI      (0x2000000 | DAHDI_SIG_CLEAR)
00187 #define SIG_BRI_PTMP (0X4000000 | DAHDI_SIG_CLEAR)
00188 #define SIG_SS7      (0x1000000 | DAHDI_SIG_CLEAR)
00189 #define  SIG_SF      DAHDI_SIG_SF
00190 #define SIG_SFWINK   (0x0100000 | DAHDI_SIG_SF)
00191 #define SIG_SF_FEATD (0x0200000 | DAHDI_SIG_SF)
00192 #define  SIG_SF_FEATDMF (0x0400000 | DAHDI_SIG_SF)
00193 #define  SIG_SF_FEATB   (0x0800000 | DAHDI_SIG_SF)
00194 #define SIG_EM_E1 DAHDI_SIG_EM_E1
00195 #define SIG_GR303FXOKS  (0x0100000 | DAHDI_SIG_FXOKS)
00196 #define SIG_GR303FXSKS  (0x0100000 | DAHDI_SIG_FXSKS)
00197 
00198 #ifdef LOTS_OF_SPANS
00199 #define NUM_SPANS DAHDI_MAX_SPANS
00200 #else
00201 #define NUM_SPANS       32
00202 #endif
00203 #define NUM_DCHANS      4  /*!< No more than 4 d-channels */
00204 #define MAX_CHANNELS 672      /*!< No more than a DS3 per trunk group */
00205 
00206 #define CHAN_PSEUDO  -2
00207 
00208 #define DCHAN_PROVISIONED (1 << 0)
00209 #define DCHAN_NOTINALARM  (1 << 1)
00210 #define DCHAN_UP          (1 << 2)
00211 
00212 #define DCHAN_AVAILABLE (DCHAN_PROVISIONED | DCHAN_NOTINALARM | DCHAN_UP)
00213 
00214 /* Overlap dialing option types */
00215 #define DAHDI_OVERLAPDIAL_NONE 0
00216 #define DAHDI_OVERLAPDIAL_OUTGOING 1
00217 #define DAHDI_OVERLAPDIAL_INCOMING 2
00218 #define DAHDI_OVERLAPDIAL_BOTH (DAHDI_OVERLAPDIAL_INCOMING|DAHDI_OVERLAPDIAL_OUTGOING)
00219 
00220 
00221 #define CALLPROGRESS_PROGRESS    1
00222 #define CALLPROGRESS_FAX_OUTGOING   2
00223 #define CALLPROGRESS_FAX_INCOMING   4
00224 #define CALLPROGRESS_FAX      (CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
00225 
00226 static char defaultcic[64] = "";
00227 static char defaultozz[64] = "";
00228 
00229 static char parkinglot[AST_MAX_EXTENSION] = "";    /*!< Default parking lot for this channel */
00230 
00231 /*! Run this script when the MWI state changes on an FXO line, if mwimonitor is enabled */
00232 static char mwimonitornotify[PATH_MAX] = "";
00233 static int  mwisend_rpas = 0;
00234 
00235 static char progzone[10] = "";
00236 
00237 static int usedistinctiveringdetection = 0;
00238 static int distinctiveringaftercid = 0;
00239 
00240 static int numbufs = 4;
00241 
00242 static int mwilevel = 512;
00243 
00244 #ifdef HAVE_PRI
00245 static struct ast_channel inuse;
00246 #ifdef PRI_GETSET_TIMERS
00247 static int pritimers[PRI_MAX_TIMERS];
00248 #endif
00249 static int pridebugfd = -1;
00250 static char pridebugfilename[1024] = "";
00251 #endif
00252 
00253 /*! \brief Wait up to 16 seconds for first digit (FXO logic) */
00254 static int firstdigittimeout = 16000;
00255 
00256 /*! \brief How long to wait for following digits (FXO logic) */
00257 static int gendigittimeout = 8000;
00258 
00259 /*! \brief How long to wait for an extra digit, if there is an ambiguous match */
00260 static int matchdigittimeout = 3000;
00261 
00262 /*! \brief Protect the interface list (of dahdi_pvt's) */
00263 AST_MUTEX_DEFINE_STATIC(iflock);
00264 
00265 
00266 static int ifcount = 0;
00267 
00268 #ifdef HAVE_PRI
00269 AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
00270 #endif
00271 
00272 /*! \brief Protect the monitoring thread, so only one process can kill or start it, and not
00273    when it's doing something critical. */
00274 AST_MUTEX_DEFINE_STATIC(monlock);
00275 
00276 /*! \brief This is the thread for the monitor which checks for input on the channels
00277    which are not currently in use. */
00278 static pthread_t monitor_thread = AST_PTHREADT_NULL;
00279 static ast_cond_t mwi_thread_complete;
00280 static ast_cond_t ss_thread_complete;
00281 AST_MUTEX_DEFINE_STATIC(mwi_thread_lock);
00282 AST_MUTEX_DEFINE_STATIC(ss_thread_lock);
00283 AST_MUTEX_DEFINE_STATIC(restart_lock);
00284 static int mwi_thread_count = 0;
00285 static int ss_thread_count = 0;
00286 static int num_restart_pending = 0;
00287 
00288 static int restart_monitor(void);
00289 
00290 static enum ast_bridge_result dahdi_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms);
00291 
00292 static int dahdi_sendtext(struct ast_channel *c, const char *text);
00293 
00294 static void mwi_event_cb(const struct ast_event *event, void *userdata)
00295 {
00296    /* This module does not handle MWI in an event-based manner.  However, it
00297     * subscribes to MWI for each mailbox that is configured so that the core
00298     * knows that we care about it.  Then, chan_dahdi will get the MWI from the
00299     * event cache instead of checking the mailbox directly. */
00300 }
00301 
00302 /*! \brief Avoid the silly dahdi_getevent which ignores a bunch of events */
00303 static inline int dahdi_get_event(int fd)
00304 {
00305    int j;
00306    if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
00307       return -1;
00308    return j;
00309 }
00310 
00311 /*! \brief Avoid the silly dahdi_waitevent which ignores a bunch of events */
00312 static inline int dahdi_wait_event(int fd)
00313 {
00314    int i, j = 0;
00315    i = DAHDI_IOMUX_SIGEVENT;
00316    if (ioctl(fd, DAHDI_IOMUX, &i) == -1)
00317       return -1;
00318    if (ioctl(fd, DAHDI_GETEVENT, &j) == -1)
00319       return -1;
00320    return j;
00321 }
00322 
00323 /*! Chunk size to read -- we use 20ms chunks to make things happy. */
00324 #define READ_SIZE 160
00325 
00326 #define MASK_AVAIL      (1 << 0) /*!< Channel available for PRI use */
00327 #define MASK_INUSE      (1 << 1) /*!< Channel currently in use */
00328 
00329 #define CALLWAITING_SILENT_SAMPLES  ( (300 * 8) / READ_SIZE) /*!< 300 ms */
00330 #define CALLWAITING_REPEAT_SAMPLES  ( (10000 * 8) / READ_SIZE) /*!< 10,000 ms */
00331 #define CIDCW_EXPIRE_SAMPLES     ( (500 * 8) / READ_SIZE) /*!< 500 ms */
00332 #define MIN_MS_SINCE_FLASH       ( (2000) )  /*!< 2000 ms */
00333 #define DEFAULT_RINGT            ( (8000 * 8) / READ_SIZE) /*!< 8,000 ms */
00334 
00335 struct dahdi_pvt;
00336 
00337 /*!
00338  * \brief Configured ring timeout base.
00339  * \note Value computed from "ringtimeout" read in from chan_dahdi.conf if it exists.
00340  */
00341 static int ringt_base = DEFAULT_RINGT;
00342 
00343 #ifdef HAVE_SS7
00344 
00345 #define LINKSTATE_INALARM  (1 << 0)
00346 #define LINKSTATE_STARTING (1 << 1)
00347 #define LINKSTATE_UP    (1 << 2)
00348 #define LINKSTATE_DOWN     (1 << 3)
00349 
00350 #define SS7_NAI_DYNAMIC    -1
00351 
00352 #define LINKSET_FLAG_EXPLICITACM (1 << 0)
00353 
00354 struct dahdi_ss7 {
00355    pthread_t master;                /*!< Thread of master */
00356    ast_mutex_t lock;
00357    int fds[NUM_DCHANS];
00358    int numsigchans;
00359    int linkstate[NUM_DCHANS];
00360    int numchans;
00361    int type;
00362    enum {
00363       LINKSET_STATE_DOWN = 0,
00364       LINKSET_STATE_UP
00365    } state;
00366    char called_nai;                 /*!< Called Nature of Address Indicator */
00367    char calling_nai;                /*!< Calling Nature of Address Indicator */
00368    char internationalprefix[10];             /*!< country access code ('00' for european dialplans) */
00369    char nationalprefix[10];               /*!< area access code ('0' for european dialplans) */
00370    char subscriberprefix[20];             /*!< area access code + area code ('0'+area code for european dialplans) */
00371    char unknownprefix[20];                /*!< for unknown dialplans */
00372    struct ss7 *ss7;
00373    struct dahdi_pvt *pvts[MAX_CHANNELS];           /*!< Member channel pvt structs */
00374    int flags;                    /*!< Linkset flags */
00375 };
00376 
00377 static struct dahdi_ss7 linksets[NUM_SPANS];
00378 
00379 static int cur_ss7type = -1;
00380 static int cur_linkset = -1;
00381 static int cur_pointcode = -1;
00382 static int cur_cicbeginswith = -1;
00383 static int cur_adjpointcode = -1;
00384 static int cur_networkindicator = -1;
00385 static int cur_defaultdpc = -1;
00386 #endif /* HAVE_SS7 */
00387 
00388 #ifdef HAVE_PRI
00389 
00390 #define PVT_TO_CHANNEL(p) (((p)->prioffset) | ((p)->logicalspan << 8) | (p->pri->mastertrunkgroup ? 0x10000 : 0))
00391 #define PRI_CHANNEL(p) ((p) & 0xff)
00392 #define PRI_SPAN(p) (((p) >> 8) & 0xff)
00393 #define PRI_EXPLICIT(p) (((p) >> 16) & 0x01)
00394 
00395 struct dahdi_pri {
00396    pthread_t master;                /*!< Thread of master */
00397    ast_mutex_t lock;                /*!< Mutex */
00398    char idleext[AST_MAX_EXTENSION];          /*!< Where to idle extra calls */
00399    char idlecontext[AST_MAX_CONTEXT];           /*!< What context to use for idle */
00400    char idledial[AST_MAX_EXTENSION];            /*!< What to dial before dumping */
00401    int minunused;                   /*!< Min # of channels to keep empty */
00402    int minidle;                     /*!< Min # of "idling" calls to keep active */
00403    int nodetype;                    /*!< Node type */
00404    int switchtype;                     /*!< Type of switch to emulate */
00405    int nsf;                   /*!< Network-Specific Facilities */
00406    int dialplan;                    /*!< Dialing plan */
00407    int localdialplan;                  /*!< Local dialing plan */
00408    char internationalprefix[10];             /*!< country access code ('00' for european dialplans) */
00409    char nationalprefix[10];               /*!< area access code ('0' for european dialplans) */
00410    char localprefix[20];                  /*!< area access code + area code ('0'+area code for european dialplans) */
00411    char privateprefix[20];                /*!< for private dialplans */
00412    char unknownprefix[20];                /*!< for unknown dialplans */
00413    int dchannels[NUM_DCHANS];             /*!< What channel are the dchannels on */
00414    int trunkgroup;                     /*!< What our trunkgroup is */
00415    int mastertrunkgroup;                  /*!< What trunk group is our master */
00416    int prilogicalspan;                 /*!< Logical span number within trunk group */
00417    int numchans;                    /*!< Num of channels we represent */
00418    int overlapdial;                 /*!< In overlap dialing mode */
00419    int facilityenable;                 /*!< Enable facility IEs */
00420    struct pri *dchans[NUM_DCHANS];              /*!< Actual d-channels */
00421    int dchanavail[NUM_DCHANS];               /*!< Whether each channel is available */
00422    struct pri *pri;                 /*!< Currently active D-channel */
00423    /*! \brief TRUE if to dump PRI event info (Tested but never set) */
00424    int debug;
00425    int fds[NUM_DCHANS];                /*!< FD's for d-channels */
00426    /*! \brief Value set but not used */
00427    int offset;
00428    /*! \brief Span number put into user output messages */
00429    int span;
00430    /*! \brief TRUE if span is being reset/restarted */
00431    int resetting;
00432    /*! \brief Current position during a reset (-1 if not started) */
00433    int resetpos;
00434 #ifdef HAVE_PRI_INBANDDISCONNECT
00435    unsigned int inbanddisconnect:1;          /*!< Should we support inband audio after receiving DISCONNECT? */
00436 #endif
00437    time_t lastreset;                /*!< time when unused channels were last reset */
00438    long resetinterval;                 /*!< Interval (in seconds) for resetting unused channels */
00439    /*! \brief ISDN signalling type (SIG_PRI, SIG_BRI, SIG_BRI_PTMP, etc...) */
00440    int sig;
00441    struct dahdi_pvt *pvts[MAX_CHANNELS];           /*!< Member channel pvt structs */
00442    struct dahdi_pvt *crvs;                /*!< Member CRV structs */
00443    struct dahdi_pvt *crvend;                 /*!< Pointer to end of CRV structs */
00444 };
00445 
00446 
00447 static struct dahdi_pri pris[NUM_SPANS];
00448 
00449 #if 0
00450 #define DEFAULT_PRI_DEBUG (PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_STATE)
00451 #else
00452 #define DEFAULT_PRI_DEBUG 0
00453 #endif
00454 
00455 static inline void pri_rel(struct dahdi_pri *pri)
00456 {
00457    ast_mutex_unlock(&pri->lock);
00458 }
00459 
00460 #else
00461 /*! Shut up the compiler */
00462 struct dahdi_pri;
00463 #endif
00464 
00465 #define SUB_REAL  0        /*!< Active call */
00466 #define SUB_CALLWAIT 1        /*!< Call-Waiting call on hold */
00467 #define SUB_THREEWAY 2        /*!< Three-way call */
00468 
00469 /* Polarity states */
00470 #define POLARITY_IDLE   0
00471 #define POLARITY_REV    1
00472 
00473 
00474 struct distRingData {
00475    int ring[3];
00476    int range;
00477 };
00478 struct ringContextData {
00479    char contextData[AST_MAX_CONTEXT];
00480 };
00481 struct dahdi_distRings {
00482    struct distRingData ringnum[3];
00483    struct ringContextData ringContext[3];
00484 };
00485 
00486 static char *subnames[] = {
00487    "Real",
00488    "Callwait",
00489    "Threeway"
00490 };
00491 
00492 struct dahdi_subchannel {
00493    int dfd;
00494    struct ast_channel *owner;
00495    int chan;
00496    short buffer[AST_FRIENDLY_OFFSET/2 + READ_SIZE];
00497    struct ast_frame f;     /*!< One frame for each channel.  How did this ever work before? */
00498    unsigned int needringing:1;
00499    unsigned int needbusy:1;
00500    unsigned int needcongestion:1;
00501    unsigned int needcallerid:1;
00502    unsigned int needanswer:1;
00503    unsigned int needflash:1;
00504    unsigned int needhold:1;
00505    unsigned int needunhold:1;
00506    unsigned int linear:1;
00507    unsigned int inthreeway:1;
00508    struct dahdi_confinfo curconf;
00509 };
00510 
00511 #define CONF_USER_REAL     (1 << 0)
00512 #define CONF_USER_THIRDCALL   (1 << 1)
00513 
00514 #define MAX_SLAVES   4
00515 
00516 static struct dahdi_pvt {
00517    ast_mutex_t lock;
00518    struct ast_channel *owner;       /*!< Our current active owner (if applicable) */
00519                      /*!< Up to three channels can be associated with this call */
00520       
00521    struct dahdi_subchannel sub_unused;    /*!< Just a safety precaution */
00522    struct dahdi_subchannel subs[3];       /*!< Sub-channels */
00523    struct dahdi_confinfo saveconf;        /*!< Saved conference info */
00524 
00525    struct dahdi_pvt *slaves[MAX_SLAVES];     /*!< Slave to us (follows our conferencing) */
00526    struct dahdi_pvt *master;           /*!< Master to us (we follow their conferencing) */
00527    int inconference;          /*!< If our real should be in the conference */
00528    
00529    int buf_no;             /*!< Number of buffers */
00530    int buf_policy;            /*!< Buffer policy */
00531    int sig;             /*!< Signalling style */
00532    /*!
00533     * \brief Nonzero if the signaling type is sent over a radio.
00534     * \note Set to a couple of nonzero values but it is only tested like a boolean.
00535     */
00536    int radio;
00537    int outsigmod;             /*!< Outbound Signalling style (modifier) */
00538    int oprmode;               /*!< "Operator Services" mode */
00539    struct dahdi_pvt *oprpeer;          /*!< "Operator Services" peer tech_pvt ptr */
00540    /*! \brief Amount of gain to increase during caller id */
00541    float cid_rxgain;
00542    /*! \brief Rx gain set by chan_dahdi.conf */
00543    float rxgain;
00544    /*! \brief Tx gain set by chan_dahdi.conf */
00545    float txgain;
00546    int tonezone;              /*!< tone zone for this chan, or -1 for default */
00547    struct dahdi_pvt *next;          /*!< Next channel in list */
00548    struct dahdi_pvt *prev;          /*!< Prev channel in list */
00549 
00550    /* flags */
00551 
00552    /*!
00553     * \brief TRUE if ADSI (Analog Display Services Interface) available
00554     * \note Set from the "adsi" value read in from chan_dahdi.conf
00555     */
00556    unsigned int adsi:1;
00557    /*!
00558     * \brief TRUE if we can use a polarity reversal to mark when an outgoing
00559     * call is answered by the remote party.
00560     * \note Set from the "answeronpolarityswitch" value read in from chan_dahdi.conf
00561     */
00562    unsigned int answeronpolarityswitch:1;
00563    /*!
00564     * \brief TRUE if busy detection is enabled.
00565     * (Listens for the beep-beep busy pattern.)
00566     * \note Set from the "busydetect" value read in from chan_dahdi.conf
00567     */
00568    unsigned int busydetect:1;
00569    /*!
00570     * \brief TRUE if call return is enabled.
00571     * (*69, if your dialplan doesn't catch this first)
00572     * \note Set from the "callreturn" value read in from chan_dahdi.conf
00573     */
00574    unsigned int callreturn:1;
00575    /*!
00576     * \brief TRUE if busy extensions will hear the call-waiting tone
00577     * and can use hook-flash to switch between callers.
00578     * \note Can be disabled by dialing *70.
00579     * \note Initialized with the "callwaiting" value read in from chan_dahdi.conf
00580     */
00581    unsigned int callwaiting:1;
00582    /*!
00583     * \brief TRUE if send caller ID for Call Waiting
00584     * \note Set from the "callwaitingcallerid" value read in from chan_dahdi.conf
00585     */
00586    unsigned int callwaitingcallerid:1;
00587    /*!
00588     * \brief TRUE if support for call forwarding enabled.
00589     * Dial *72 to enable call forwarding.
00590     * Dial *73 to disable call forwarding.
00591     * \note Set from the "cancallforward" value read in from chan_dahdi.conf
00592     */
00593    unsigned int cancallforward:1;
00594    /*!
00595     * \brief TRUE if support for call parking is enabled.
00596     * \note Set from the "canpark" value read in from chan_dahdi.conf
00597     */
00598    unsigned int canpark:1;
00599    /*! \brief TRUE if to wait for a DTMF digit to confirm answer */
00600    unsigned int confirmanswer:1;
00601    /*!
00602     * \brief TRUE if the channel is to be destroyed on hangup.
00603     * (Used by pseudo channels.)
00604     */
00605    unsigned int destroy:1;
00606    unsigned int didtdd:1;           /*!< flag to say its done it once */
00607    /*! \brief TRUE if analog type line dialed no digits in Dial() */
00608    unsigned int dialednone:1;
00609    /*! \brief TRUE if in the process of dialing digits or sending something. */
00610    unsigned int dialing:1;
00611    /*! \brief TRUE if the transfer capability of the call is digital. */
00612    unsigned int digital:1;
00613    /*! \brief TRUE if Do-Not-Disturb is enabled. */
00614    unsigned int dnd:1;
00615    /*! \brief XXX BOOLEAN Purpose??? */
00616    unsigned int echobreak:1;
00617    /*!
00618     * \brief TRUE if echo cancellation enabled when bridged.
00619     * \note Initialized with the "echocancelwhenbridged" value read in from chan_dahdi.conf
00620     * \note Disabled if the echo canceller is not setup.
00621     */
00622    unsigned int echocanbridged:1;
00623    /*! \brief TRUE if echo cancellation is turned on. */
00624    unsigned int echocanon:1;
00625    /*! \brief TRUE if a fax tone has already been handled. */
00626    unsigned int faxhandled:1;
00627    /*! \brief TRUE if over a radio and dahdi_read() has been called. */
00628    unsigned int firstradio:1;
00629    /*!
00630     * \brief TRUE if the call will be considered "hung up" on a polarity reversal.
00631     * \note Set from the "hanguponpolarityswitch" value read in from chan_dahdi.conf
00632     */
00633    unsigned int hanguponpolarityswitch:1;
00634    /*! \brief TRUE if DTMF detection needs to be done by hardware. */
00635    unsigned int hardwaredtmf:1;
00636    /*!
00637     * \brief TRUE if the outgoing caller ID is blocked/hidden.
00638     * \note Caller ID can be disabled by dialing *67.
00639     * \note Caller ID can be enabled by dialing *82.
00640     * \note Initialized with the "hidecallerid" value read in from chan_dahdi.conf
00641     */
00642    unsigned int hidecallerid:1;
00643    /*!
00644     * \brief TRUE if hide just the name not the number for legacy PBX use.
00645     * \note Only applies to PRI channels.
00646     * \note Set from the "hidecalleridname" value read in from chan_dahdi.conf
00647     */
00648    unsigned int hidecalleridname:1;
00649    /*! \brief TRUE if DTMF detection is disabled. */
00650    unsigned int ignoredtmf:1;
00651    /*!
00652     * \brief TRUE if the channel should be answered immediately
00653     * without attempting to gather any digits.
00654     * \note Set from the "immediate" value read in from chan_dahdi.conf
00655     */
00656    unsigned int immediate:1;
00657    /*! \brief TRUE if in an alarm condition. */
00658    unsigned int inalarm:1;
00659    /*! \brief TRUE if TDD in MATE mode */
00660    unsigned int mate:1;
00661    /*! \brief TRUE if we originated the call leg. */
00662    unsigned int outgoing:1;
00663    /* unsigned int overlapdial:1;         unused and potentially confusing */
00664    /*!
00665     * \brief TRUE if busy extensions will hear the call-waiting tone
00666     * and can use hook-flash to switch between callers.
00667     * \note Set from the "callwaiting" value read in from chan_dahdi.conf
00668     */
00669    unsigned int permcallwaiting:1;
00670    /*!
00671     * \brief TRUE if the outgoing caller ID is blocked/restricted/hidden.
00672     * \note Set from the "hidecallerid" value read in from chan_dahdi.conf
00673     */
00674    unsigned int permhidecallerid:1;
00675    /*!
00676     * \brief TRUE if PRI congestion/busy indications are sent out-of-band.
00677     * \note Set from the "priindication" value read in from chan_dahdi.conf
00678     */
00679    unsigned int priindication_oob:1;
00680    /*!
00681     * \brief TRUE if PRI B channels are always exclusively selected.
00682     * \note Set from the "priexclusive" value read in from chan_dahdi.conf
00683     */
00684    unsigned int priexclusive:1;
00685    /*!
00686     * \brief TRUE if we will pulse dial.
00687     * \note Set from the "pulsedial" value read in from chan_dahdi.conf
00688     */
00689    unsigned int pulse:1;
00690    /*! \brief TRUE if a pulsed digit was detected. (Pulse dial phone detected) */
00691    unsigned int pulsedial:1;
00692    unsigned int restartpending:1;      /*!< flag to ensure counted only once for restart */
00693    /*!
00694     * \brief TRUE if caller ID is restricted.
00695     * \note Set but not used.  Should be deleted.  Redundant with permhidecallerid.
00696     * \note Set from the "restrictcid" value read in from chan_dahdi.conf
00697     */
00698    unsigned int restrictcid:1;
00699    /*!
00700     * \brief TRUE if three way calling is enabled
00701     * \note Set from the "threewaycalling" value read in from chan_dahdi.conf
00702     */
00703    unsigned int threewaycalling:1;
00704    /*!
00705     * \brief TRUE if call transfer is enabled
00706     * \note For FXS ports (either direct analog or over T1/E1):
00707     *   Support flash-hook call transfer
00708     * \note For digital ports using ISDN PRI protocols:
00709     *   Support switch-side transfer (called 2BCT, RLT or other names)
00710     * \note Set from the "transfer" value read in from chan_dahdi.conf
00711     */
00712    unsigned int transfer:1;
00713    /*!
00714     * \brief TRUE if caller ID is used on this channel.
00715     * \note PRI and SS7 spans will save caller ID from the networking peer.
00716     * \note FXS ports will generate the caller ID spill.
00717     * \note FXO ports will listen for the caller ID spill.
00718     * \note Set from the "usecallerid" value read in from chan_dahdi.conf
00719     */
00720    unsigned int use_callerid:1;
00721    /*!
00722     * \brief TRUE if we will use the calling presentation setting
00723     * from the Asterisk channel for outgoing calls.
00724     * \note Only applies to PRI and SS7 channels.
00725     * \note Set from the "usecallingpres" value read in from chan_dahdi.conf
00726     */
00727    unsigned int use_callingpres:1;
00728    /*!
00729     * \brief TRUE if distinctive rings are to be detected.
00730     * \note For FXO lines
00731     * \note Set indirectly from the "usedistinctiveringdetection" value read in from chan_dahdi.conf
00732     */
00733    unsigned int usedistinctiveringdetection:1;
00734    /*!
00735     * \brief TRUE if we should use the callerid from incoming call on dahdi transfer.
00736     * \note Set from the "useincomingcalleridondahditransfer" value read in from chan_dahdi.conf
00737     */
00738    unsigned int dahditrcallerid:1;
00739    /*!
00740     * \brief TRUE if allowed to flash-transfer to busy channels.
00741     * \note Set from the "transfertobusy" value read in from chan_dahdi.conf
00742     */
00743    unsigned int transfertobusy:1;
00744    /*!
00745     * \brief TRUE if the FXO port monitors for neon type MWI indications from the other end.
00746     * \note Set if the "mwimonitor" value read in contains "neon" from chan_dahdi.conf
00747     */
00748    unsigned int mwimonitor_neon:1;
00749    /*!
00750     * \brief TRUE if the FXO port monitors for fsk type MWI indications from the other end.
00751     * \note Set if the "mwimonitor" value read in contains "fsk" from chan_dahdi.conf
00752     */
00753    unsigned int mwimonitor_fsk:1;
00754    /*!
00755     * \brief TRUE if the FXO port monitors for rpas precursor to fsk MWI indications from the other end.
00756     * \note RPAS - Ring Pulse Alert Signal
00757     * \note Set if the "mwimonitor" value read in contains "rpas" from chan_dahdi.conf
00758     */
00759    unsigned int mwimonitor_rpas:1;
00760    /*! \brief TRUE if an MWI monitor thread is currently active */
00761    unsigned int mwimonitoractive:1;
00762    /*! \brief TRUE if a MWI message sending thread is active */
00763    unsigned int mwisendactive:1;
00764    /*!
00765     * \brief TRUE if channel is out of reset and ready
00766     * \note Set but not used.
00767     */
00768    unsigned int inservice:1;
00769    /*!
00770     * \brief TRUE if the channel is locally blocked.
00771     * \note Applies to SS7 channels.
00772     */
00773    unsigned int locallyblocked:1;
00774    /*!
00775     * \brief TRUE if the channel is remotely blocked.
00776     * \note Applies to SS7 channels.
00777     */
00778    unsigned int remotelyblocked:1;
00779 #if defined(HAVE_PRI) || defined(HAVE_SS7)
00780    /*!
00781     * \brief XXX BOOLEAN Purpose???
00782     * \note Applies to SS7 channels.
00783     */
00784    unsigned int rlt:1;
00785    /*! \brief TRUE if channel is alerting/ringing */
00786    unsigned int alerting:1;
00787    /*! \brief TRUE if the call has already gone/hungup */
00788    unsigned int alreadyhungup:1;
00789    /*!
00790     * \brief TRUE if this is an idle call
00791     * \note Applies to PRI channels.
00792     */
00793    unsigned int isidlecall:1;
00794    /*!
00795     * \brief TRUE if call is in a proceeding state.
00796     * The call has started working its way through the network.
00797     */
00798    unsigned int proceeding:1;
00799    /*! \brief TRUE if the call has seen progress through the network. */
00800    unsigned int progress:1;
00801    /*!
00802     * \brief TRUE if this channel is being reset/restarted
00803     * \note Applies to PRI channels.
00804     */
00805    unsigned int resetting:1;
00806    /*!
00807     * \brief TRUE if this channel has received a SETUP_ACKNOWLEDGE
00808     * \note Applies to PRI channels.
00809     */
00810    unsigned int setup_ack:1;
00811 #endif
00812    /*!
00813     * \brief TRUE if SMDI (Simplified Message Desk Interface) is enabled
00814     * \note Set from the "usesmdi" value read in from chan_dahdi.conf
00815     */
00816    unsigned int use_smdi:1;
00817    /*! \brief The serial port to listen for SMDI data on */
00818    struct ast_smdi_interface *smdi_iface;
00819 
00820    /*! \brief Distinctive Ring data */
00821    struct dahdi_distRings drings;
00822 
00823    /*!
00824     * \brief The configured context for incoming calls.
00825     * \note The "context" string read in from chan_dahdi.conf
00826     */
00827    char context[AST_MAX_CONTEXT];
00828    /*!
00829     * \brief Saved context string.
00830     */
00831    char defcontext[AST_MAX_CONTEXT];
00832    /*! \brief Extension to use in the dialplan. */
00833    char exten[AST_MAX_EXTENSION];
00834    /*!
00835     * \brief Language configured for calls.
00836     * \note The "language" string read in from chan_dahdi.conf
00837     */
00838    char language[MAX_LANGUAGE];
00839    /*!
00840     * \brief The configured music-on-hold class to use for calls.
00841     * \note The "musicclass" or "mohinterpret" or "musiconhold" string read in from chan_dahdi.conf
00842     */
00843    char mohinterpret[MAX_MUSICCLASS];
00844    /*!
00845     * \brief Suggested music-on-hold class for peer channel to use for calls.
00846     * \note The "mohsuggest" string read in from chan_dahdi.conf
00847     */
00848    char mohsuggest[MAX_MUSICCLASS];
00849    char parkinglot[AST_MAX_EXTENSION]; /*!< Parking lot for this channel */
00850 #if defined(PRI_ANI) || defined(HAVE_SS7)
00851    /*! \brief Automatic Number Identification number (Alternate PRI caller ID number) */
00852    char cid_ani[AST_MAX_EXTENSION];
00853 #endif
00854    /*! \brief Automatic Number Identification code from PRI */
00855    int cid_ani2;
00856    /*! \brief Caller ID number from an incoming call. */
00857    char cid_num[AST_MAX_EXTENSION];
00858    /*! \brief Caller ID Q.931 TON/NPI field values.  Set by PRI. Zero otherwise. */
00859    int cid_ton;
00860    /*! \brief Caller ID name from an incoming call. */
00861    char cid_name[AST_MAX_EXTENSION];
00862    /*! \brief Last Caller ID number from an incoming call. */
00863    char lastcid_num[AST_MAX_EXTENSION];
00864    /*! \brief Last Caller ID name from an incoming call. */
00865    char lastcid_name[AST_MAX_EXTENSION];
00866    char *origcid_num;            /*!< malloced original callerid */
00867    char *origcid_name;           /*!< malloced original callerid */
00868    /*! \brief Call waiting number. */
00869    char callwait_num[AST_MAX_EXTENSION];
00870    /*! \brief Call waiting name. */
00871    char callwait_name[AST_MAX_EXTENSION];
00872    /*! \brief Redirecting Directory Number Information Service (RDNIS) number */
00873    char rdnis[AST_MAX_EXTENSION];
00874    /*! \brief Dialed Number Identifier */
00875    char dnid[AST_MAX_EXTENSION];
00876    /*!
00877     * \brief Bitmapped groups this belongs to.
00878     * \note The "group" bitmapped group string read in from chan_dahdi.conf
00879     */
00880    ast_group_t group;
00881    /*! \brief Active PCM encoding format: DAHDI_LAW_ALAW or DAHDI_LAW_MULAW */
00882    int law;
00883    int confno;             /*!< Our conference */
00884    int confusers;             /*!< Who is using our conference */
00885    int propconfno;               /*!< Propagated conference number */
00886    /*!
00887     * \brief Bitmapped call groups this belongs to.
00888     * \note The "callgroup" bitmapped group string read in from chan_dahdi.conf
00889     */
00890    ast_group_t callgroup;
00891    /*!
00892     * \brief Bitmapped pickup groups this belongs to.
00893     * \note The "pickupgroup" bitmapped group string read in from chan_dahdi.conf
00894     */
00895    ast_group_t pickupgroup;
00896    /*!
00897     * \brief Channel variable list with associated values to set when a channel is created.
00898     * \note The "setvar" strings read in from chan_dahdi.conf
00899     */
00900    struct ast_variable *vars;
00901    int channel;               /*!< Channel Number or CRV */
00902    int span;               /*!< Span number */
00903    time_t guardtime;          /*!< Must wait this much time before using for new call */
00904    int cid_signalling;           /*!< CID signalling type bell202 or v23 */
00905    int cid_start;             /*!< CID start indicator, polarity or ring */
00906    int callingpres;           /*!< The value of callling presentation that we're going to use when placing a PRI call */
00907    int callwaitingrepeat;           /*!< How many samples to wait before repeating call waiting */
00908    int cidcwexpire;           /*!< When to expire our muting for CID/CW */
00909    /*! \brief Analog caller ID waveform sample buffer */
00910    unsigned char *cidspill;
00911    /*! \brief Position in the cidspill buffer to send out next. */
00912    int cidpos;
00913    /*! \brief Length of the cidspill buffer containing samples. */
00914    int cidlen;
00915    /*! \brief Ring timeout timer?? */
00916    int ringt;
00917    /*!
00918     * \brief Ring timeout base.
00919     * \note Value computed indirectly from "ringtimeout" read in from chan_dahdi.conf
00920     */
00921    int ringt_base;
00922    /*!
00923     * \brief Number of most significant digits/characters to strip from the dialed number.
00924     * \note Feature is deprecated.  Use dialplan logic.
00925     * \note The characters are stripped before the PRI TON/NPI prefix
00926     * characters are processed.
00927     */
00928    int stripmsd;
00929    /*! \brief BOOLEAN. XXX Meaning what?? */
00930    int callwaitcas;
00931    /*! \brief Number of call waiting rings. */
00932    int callwaitrings;
00933    /*! \brief Echo cancel parameters. */
00934    struct {
00935       struct dahdi_echocanparams head;
00936       struct dahdi_echocanparam params[DAHDI_MAX_ECHOCANPARAMS];
00937    } echocancel;
00938    /*!
00939     * \brief Echo training time. 0 = disabled
00940     * \note Set from the "echotraining" value read in from chan_dahdi.conf
00941     */
00942    int echotraining;
00943    /*! \brief Filled with 'w'.  XXX Purpose?? */
00944    char echorest[20];
00945    /*!
00946     * \brief Number of times to see "busy" tone before hanging up.
00947     * \note Set from the "busycount" value read in from chan_dahdi.conf
00948     */
00949    int busycount;
00950    /*!
00951     * \brief Length of "busy" tone on time.
00952     * \note Set from the "busypattern" value read in from chan_dahdi.conf
00953     */
00954    int busy_tonelength;
00955    /*!
00956     * \brief Length of "busy" tone off time.
00957     * \note Set from the "busypattern" value read in from chan_dahdi.conf
00958     */
00959    int busy_quietlength;
00960    /*!
00961     * \brief Bitmapped call progress detection flags. CALLPROGRESS_xxx values.
00962     * \note Bits set from the "callprogress" and "faxdetect" values read in from chan_dahdi.conf
00963     */
00964    int callprogress;
00965    struct timeval flashtime;        /*!< Last flash-hook time */
00966    /*! \brief Opaque DSP configuration structure. */
00967    struct ast_dsp *dsp;
00968    //int cref;             /*!< Call reference number (Not used) */
00969    /*! \brief DAHDI dial operation command struct for ioctl() call. */
00970    struct dahdi_dialoperation dop;
00971    int whichwink;             /*!< SIG_FEATDMF_TA Which wink are we on? */
00972    /*! \brief Second part of SIG_FEATDMF_TA wink operation. */
00973    char finaldial[64];
00974    char accountcode[AST_MAX_ACCOUNT_CODE];      /*!< Account code */
00975    int amaflags;              /*!< AMA Flags */
00976    struct tdd_state *tdd;           /*!< TDD flag */
00977    /*! \brief Accumulated call forwarding number. */
00978    char call_forward[AST_MAX_EXTENSION];
00979    /*!
00980     * \brief Voice mailbox location.
00981     * \note Set from the "mailbox" string read in from chan_dahdi.conf
00982     */
00983    char mailbox[AST_MAX_EXTENSION];
00984    /*! \brief Opaque event subscription parameters for message waiting indication support. */
00985    struct ast_event_sub *mwi_event_sub;
00986    /*! \brief Delayed dialing for E911.  Overlap digits for ISDN. */
00987    char dialdest[256];
00988    /*! \brief Time the interface went on-hook. */
00989    int onhooktime;
00990    /*! \brief -1 = unknown, 0 = no messages, 1 = new messages available */
00991    int msgstate;
00992    int distinctivering;          /*!< Which distinctivering to use */
00993    int cidrings;              /*!< Which ring to deliver CID on */
00994    int dtmfrelax;             /*!< whether to run in relaxed DTMF mode */
00995    /*! \brief Holding place for event injected from outside normal operation. */
00996    int fake_event;
00997    /*!
00998     * \brief Minimal time period (ms) between the answer polarity
00999     * switch and hangup polarity switch.
01000     */
01001    int polarityonanswerdelay;
01002    /*! \brief Start delay time if polarityonanswerdelay is nonzero. */
01003    struct timeval polaritydelaytv;
01004    /*!
01005     * \brief Send caller ID after this many rings.
01006     * \note Set from the "sendcalleridafter" value read in from chan_dahdi.conf
01007     */
01008    int sendcalleridafter;
01009 #ifdef HAVE_PRI
01010    /*! \brief DAHDI PRI control parameters */
01011    struct dahdi_pri *pri;
01012    /*! \brief XXX Purpose??? */
01013    struct dahdi_pvt *bearer;
01014    /*! \brief XXX Purpose??? */
01015    struct dahdi_pvt *realcall;
01016    /*! \brief Opaque libpri call control structure */
01017    q931_call *call;
01018    /*! \brief Channel number in span. */
01019    int prioffset;
01020    /*! \brief Logical span number within trunk group */
01021    int logicalspan;
01022 #endif   
01023    /*! \brief Current line interface polarity. POLARITY_IDLE, POLARITY_REV */
01024    int polarity;
01025    /*! \brief DSP feature flags: DSP_FEATURE_xxx */
01026    int dsp_features;
01027 #ifdef HAVE_SS7
01028    /*! \brief SS7 control parameters */
01029    struct dahdi_ss7 *ss7;
01030    /*! \brief Opaque libss7 call control structure */
01031    struct isup_call *ss7call;
01032    char charge_number[50];
01033    char gen_add_number[50];
01034    char gen_dig_number[50];
01035    char orig_called_num[50];
01036    char redirecting_num[50];
01037    char generic_name[50];
01038    unsigned char gen_add_num_plan;
01039    unsigned char gen_add_nai;
01040    unsigned char gen_add_pres_ind;
01041    unsigned char gen_add_type;
01042    unsigned char gen_dig_type;
01043    unsigned char gen_dig_scheme;
01044    char jip_number[50];
01045    unsigned char lspi_type;
01046    unsigned char lspi_scheme;
01047    unsigned char lspi_context;
01048    char lspi_ident[50];
01049    unsigned int call_ref_ident;
01050    unsigned int call_ref_pc;
01051    unsigned char calling_party_cat;
01052    int transcap;
01053    int cic;                   /*!< CIC associated with channel */
01054    unsigned int dpc;                /*!< CIC's DPC */
01055    unsigned int loopedback:1;
01056 #endif
01057    /*! \brief DTMF digit in progress.  0 when no digit in progress. */
01058    char begindigit;
01059    /*! \brief TRUE if confrence is muted. */
01060    int muting;
01061 } *iflist = NULL, *ifend = NULL;
01062 
01063 /*! \brief Channel configuration from chan_dahdi.conf .
01064  * This struct is used for parsing the [channels] section of chan_dahdi.conf.
01065  * Generally there is a field here for every possible configuration item.
01066  *
01067  * The state of fields is saved along the parsing and whenever a 'channel'
01068  * statement is reached, the current dahdi_chan_conf is used to configure the 
01069  * channel (struct dahdi_pvt)
01070  *
01071  * \see dahdi_chan_init for the default values.
01072  */
01073 struct dahdi_chan_conf {
01074    struct dahdi_pvt chan;
01075 #ifdef HAVE_PRI
01076    struct dahdi_pri pri;
01077 #endif
01078 
01079 #ifdef HAVE_SS7
01080    struct dahdi_ss7 ss7;
01081 #endif
01082    struct dahdi_params timing;
01083    int is_sig_auto; /*!< Use channel signalling from DAHDI? */
01084 
01085    /*!
01086     * \brief The serial port to listen for SMDI data on
01087     * \note Set from the "smdiport" string read in from chan_dahdi.conf
01088     */
01089    char smdi_port[SMDI_MAX_FILENAME_LEN];
01090 };
01091 
01092 /*! returns a new dahdi_chan_conf with default values (by-value) */
01093 static struct dahdi_chan_conf dahdi_chan_conf_default(void) {
01094    /* recall that if a field is not included here it is initialized
01095     * to 0 or equivalent
01096     */
01097    struct dahdi_chan_conf conf = {
01098 #ifdef HAVE_PRI
01099       .pri = {
01100          .nsf = PRI_NSF_NONE,
01101          .switchtype = PRI_SWITCH_NI2,
01102          .dialplan = PRI_UNKNOWN + 1,
01103          .localdialplan = PRI_NATIONAL_ISDN + 1,
01104          .nodetype = PRI_CPE,
01105 
01106          .minunused = 2,
01107          .idleext = "",
01108          .idledial = "",
01109          .internationalprefix = "",
01110          .nationalprefix = "",
01111          .localprefix = "",
01112          .privateprefix = "",
01113          .unknownprefix = "",
01114          .resetinterval = -1,
01115       },
01116 #endif
01117 #ifdef HAVE_SS7
01118       .ss7 = {
01119          .called_nai = SS7_NAI_NATIONAL,
01120          .calling_nai = SS7_NAI_NATIONAL,
01121          .internationalprefix = "",
01122          .nationalprefix = "",
01123          .subscriberprefix = "",
01124          .unknownprefix = ""
01125       },
01126 #endif
01127       .chan = {
01128          .context = "default",
01129          .cid_num = "",
01130          .cid_name = "",
01131          .mohinterpret = "default",
01132          .mohsuggest = "",
01133          .parkinglot = "",
01134          .transfertobusy = 1,
01135 
01136          .cid_signalling = CID_SIG_BELL,
01137          .cid_start = CID_START_RING,
01138          .dahditrcallerid = 0,
01139          .use_callerid = 1,
01140          .sig = -1,
01141          .outsigmod = -1,
01142 
01143          .cid_rxgain = +5.0,
01144 
01145          .tonezone = -1,
01146 
01147          .echocancel.head.tap_length = 1,
01148 
01149          .busycount = 3,
01150 
01151          .accountcode = "",
01152 
01153          .mailbox = "",
01154 
01155 
01156          .polarityonanswerdelay = 600,
01157 
01158          .sendcalleridafter = DEFAULT_CIDRINGS,
01159       
01160          .buf_policy = DAHDI_POLICY_IMMEDIATE,
01161          .buf_no = numbufs
01162       },
01163       .timing = {
01164          .prewinktime = -1,
01165          .preflashtime = -1,
01166          .winktime = -1,
01167          .flashtime = -1,
01168          .starttime = -1,
01169          .rxwinktime = -1,
01170          .rxflashtime = -1,
01171          .debouncetime = -1
01172       },
01173       .is_sig_auto = 1,
01174       .smdi_port = "/dev/ttyS0",
01175    };
01176 
01177    return conf;
01178 }
01179 
01180 
01181 static struct ast_channel *dahdi_request(const char *type, int format, void *data, int *cause);
01182 static int dahdi_digit_begin(struct ast_channel *ast, char digit);
01183 static int dahdi_digit_end(struct ast_channel *ast, char digit, unsigned int duration);
01184 static int dahdi_sendtext(struct ast_channel *c, const char *text);
01185 static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout);
01186 static int dahdi_hangup(struct ast_channel *ast);
01187 static int dahdi_answer(struct ast_channel *ast);
01188 static struct ast_frame *dahdi_read(struct ast_channel *ast);
01189 static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame);
01190 static struct ast_frame *dahdi_exception(struct ast_channel *ast);
01191 static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen);
01192 static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);
01193 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen);
01194 static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len);
01195 static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event);
01196 
01197 static const struct ast_channel_tech dahdi_tech = {
01198    .type = "DAHDI",
01199    .description = tdesc,
01200    .capabilities = AST_FORMAT_SLINEAR | AST_FORMAT_ULAW | AST_FORMAT_ALAW,
01201    .requester = dahdi_request,
01202    .send_digit_begin = dahdi_digit_begin,
01203    .send_digit_end = dahdi_digit_end,
01204    .send_text = dahdi_sendtext,
01205    .call = dahdi_call,
01206    .hangup = dahdi_hangup,
01207    .answer = dahdi_answer,
01208    .read = dahdi_read,
01209    .write = dahdi_write,
01210    .bridge = dahdi_bridge,
01211    .exception = dahdi_exception,
01212    .indicate = dahdi_indicate,
01213    .fixup = dahdi_fixup,
01214    .setoption = dahdi_setoption,
01215    .func_channel_read = dahdi_func_read,
01216 };
01217 
01218 #ifdef HAVE_PRI
01219 #define GET_CHANNEL(p) ((p)->bearer ? (p)->bearer->channel : p->channel)
01220 #else
01221 #define GET_CHANNEL(p) ((p)->channel)
01222 #endif
01223 
01224 struct dahdi_pvt *round_robin[32];
01225 
01226 #ifdef HAVE_PRI
01227 static inline int pri_grab(struct dahdi_pvt *pvt, struct dahdi_pri *pri)
01228 {
01229    int res;
01230    /* Grab the lock first */
01231    do {
01232       res = ast_mutex_trylock(&pri->lock);
01233       if (res) {
01234          DEADLOCK_AVOIDANCE(&pvt->lock);
01235       }
01236    } while (res);
01237    /* Then break the poll */
01238    if (pri->master != AST_PTHREADT_NULL)
01239       pthread_kill(pri->master, SIGURG);
01240    return 0;
01241 }
01242 #endif
01243 
01244 #ifdef HAVE_SS7
01245 static inline void ss7_rel(struct dahdi_ss7 *ss7)
01246 {
01247    ast_mutex_unlock(&ss7->lock);
01248 }
01249 
01250 static inline int ss7_grab(struct dahdi_pvt *pvt, struct dahdi_ss7 *pri)
01251 {
01252    int res;
01253    /* Grab the lock first */
01254    do {
01255       res = ast_mutex_trylock(&pri->lock);
01256       if (res) {
01257          DEADLOCK_AVOIDANCE(&pvt->lock);
01258       }
01259    } while (res);
01260    /* Then break the poll */
01261    if (pri->master != AST_PTHREADT_NULL)
01262       pthread_kill(pri->master, SIGURG);
01263    return 0;
01264 }
01265 #endif
01266 #define NUM_CADENCE_MAX 25
01267 static int num_cadence = 4;
01268 static int user_has_defined_cadences = 0;
01269 
01270 static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
01271    { { 125, 125, 2000, 4000 } },       /*!< Quick chirp followed by normal ring */
01272    { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
01273    { { 125, 125, 125, 125, 125, 4000 } }, /*!< Three short bursts */
01274    { { 1000, 500, 2500, 5000 } },   /*!< Long ring */
01275 };
01276 
01277 /*! \brief cidrings says in which pause to transmit the cid information, where the first pause
01278  * is 1, the second pause is 2 and so on.
01279  */
01280 
01281 static int cidrings[NUM_CADENCE_MAX] = {
01282    2,                            /*!< Right after first long ring */
01283    4,                            /*!< Right after long part */
01284    3,                            /*!< After third chirp */
01285    2,                            /*!< Second spell */
01286 };
01287 
01288 /* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
01289 static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}};
01290 
01291 #define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
01292          (p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
01293 
01294 #define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
01295 #define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
01296 
01297 static int dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok)
01298 {
01299    int res;
01300    if (p->subs[SUB_REAL].owner == ast)
01301       res = 0;
01302    else if (p->subs[SUB_CALLWAIT].owner == ast)
01303       res = 1;
01304    else if (p->subs[SUB_THREEWAY].owner == ast)
01305       res = 2;
01306    else {
01307       res = -1;
01308       if (!nullok)
01309          ast_log(LOG_WARNING, "Unable to get index, and nullok is not asserted\n");
01310    }
01311    return res;
01312 }
01313 
01314 #ifdef HAVE_PRI
01315 static void wakeup_sub(struct dahdi_pvt *p, int a, struct dahdi_pri *pri)
01316 #else
01317 static void wakeup_sub(struct dahdi_pvt *p, int a, void *pri)
01318 #endif
01319 {
01320 #ifdef HAVE_PRI
01321    if (pri)
01322       ast_mutex_unlock(&pri->lock);
01323 #endif         
01324    for (;;) {
01325       if (p->subs[a].owner) {
01326          if (ast_channel_trylock(p->subs[a].owner)) {
01327             DEADLOCK_AVOIDANCE(&p->lock);
01328          } else {
01329             ast_queue_frame(p->subs[a].owner, &ast_null_frame);
01330             ast_channel_unlock(p->subs[a].owner);
01331             break;
01332          }
01333       } else
01334          break;
01335    }
01336 #ifdef HAVE_PRI
01337    if (pri)
01338       ast_mutex_lock(&pri->lock);
01339 #endif         
01340 }
01341 
01342 static void dahdi_queue_frame(struct dahdi_pvt *p, struct ast_frame *f, void *data)
01343 {
01344 #ifdef HAVE_PRI
01345    struct dahdi_pri *pri = (struct dahdi_pri*) data;
01346 #endif
01347 #ifdef HAVE_SS7
01348    struct dahdi_ss7 *ss7 = (struct dahdi_ss7*) data;
01349 #endif
01350    /* We must unlock the PRI to avoid the possibility of a deadlock */
01351 #if defined(HAVE_PRI) || defined(HAVE_SS7)
01352    if (data) {
01353       switch (p->sig) {
01354 #ifdef HAVE_PRI
01355       case SIG_BRI:
01356       case SIG_BRI_PTMP:
01357       case SIG_PRI:
01358          ast_mutex_unlock(&pri->lock);
01359          break;
01360 #endif
01361 #ifdef HAVE_SS7
01362       case SIG_SS7:
01363          ast_mutex_unlock(&ss7->lock);
01364          break;
01365 #endif
01366       default:
01367          break;
01368       }
01369    }
01370 #endif      
01371    for (;;) {
01372       if (p->owner) {
01373          if (ast_channel_trylock(p->owner)) {
01374             DEADLOCK_AVOIDANCE(&p->lock);
01375          } else {
01376             ast_queue_frame(p->owner, f);
01377             ast_channel_unlock(p->owner);
01378             break;
01379          }
01380       } else
01381          break;
01382    }
01383 #if defined(HAVE_PRI) || defined(HAVE_SS7)
01384    if (data) {
01385       switch (p->sig) {
01386 #ifdef HAVE_PRI
01387       case SIG_BRI:
01388       case SIG_BRI_PTMP:
01389       case SIG_PRI:
01390          ast_mutex_lock(&pri->lock);
01391          break;
01392 #endif
01393 #ifdef HAVE_SS7
01394       case SIG_SS7:
01395          ast_mutex_lock(&ss7->lock);
01396          break;
01397 #endif
01398       default:
01399          break;
01400       }
01401    }
01402 
01403 #endif      
01404 }
01405 
01406 static int restore_gains(struct dahdi_pvt *p);
01407 
01408 static void swap_subs(struct dahdi_pvt *p, int a, int b)
01409 {
01410    int tchan;
01411    int tinthreeway;
01412    struct ast_channel *towner;
01413 
01414    ast_debug(1, "Swapping %d and %d\n", a, b);
01415 
01416    tchan = p->subs[a].chan;
01417    towner = p->subs[a].owner;
01418    tinthreeway = p->subs[a].inthreeway;
01419 
01420    p->subs[a].chan = p->subs[b].chan;
01421    p->subs[a].owner = p->subs[b].owner;
01422    p->subs[a].inthreeway = p->subs[b].inthreeway;
01423 
01424    p->subs[b].chan = tchan;
01425    p->subs[b].owner = towner;
01426    p->subs[b].inthreeway = tinthreeway;
01427 
01428    if (p->subs[a].owner) 
01429       ast_channel_set_fd(p->subs[a].owner, 0, p->subs[a].dfd);
01430    if (p->subs[b].owner) 
01431       ast_channel_set_fd(p->subs[b].owner, 0, p->subs[b].dfd);
01432    wakeup_sub(p, a, NULL);
01433    wakeup_sub(p, b, NULL);
01434 }
01435 
01436 static int dahdi_open(char *fn)
01437 {
01438    int fd;
01439    int isnum;
01440    int chan = 0;
01441    int bs;
01442    int x;
01443    isnum = 1;
01444    for (x = 0; x < strlen(fn); x++) {
01445       if (!isdigit(fn[x])) {
01446          isnum = 0;
01447          break;
01448       }
01449    }
01450    if (isnum) {
01451       chan = atoi(fn);
01452       if (chan < 1) {
01453          ast_log(LOG_WARNING, "Invalid channel number '%s'\n", fn);
01454          return -1;
01455       }
01456       fn = "/dev/dahdi/channel";
01457    }
01458    fd = open(fn, O_RDWR | O_NONBLOCK);
01459    if (fd < 0) {
01460       ast_log(LOG_WARNING, "Unable to open '%s': %s\n", fn, strerror(errno));
01461       return -1;
01462    }
01463    if (chan) {
01464       if (ioctl(fd, DAHDI_SPECIFY, &chan)) {
01465          x = errno;
01466          close(fd);
01467          errno = x;
01468          ast_log(LOG_WARNING, "Unable to specify channel %d: %s\n", chan, strerror(errno));
01469          return -1;
01470       }
01471    }
01472    bs = READ_SIZE;
01473    if (ioctl(fd, DAHDI_SET_BLOCKSIZE, &bs) == -1) {
01474       ast_log(LOG_WARNING, "Unable to set blocksize '%d': %s\n", bs,  strerror(errno));
01475       x = errno;
01476       close(fd);
01477       errno = x;
01478       return -1;
01479    }
01480    return fd;
01481 }
01482 
01483 static void dahdi_close(int fd)
01484 {
01485    if (fd > 0)
01486       close(fd);
01487 }
01488 
01489 static void dahdi_close_sub(struct dahdi_pvt *chan_pvt, int sub_num)
01490 {
01491    dahdi_close(chan_pvt->subs[sub_num].dfd);
01492    chan_pvt->subs[sub_num].dfd = -1;
01493 }
01494 
01495 #ifdef HAVE_PRI
01496 static void dahdi_close_pri_fd(struct dahdi_pri *pri, int fd_num)
01497 {
01498    dahdi_close(pri->fds[fd_num]);
01499    pri->fds[fd_num] = -1;
01500 }
01501 #endif
01502 
01503 #ifdef HAVE_SS7
01504 static void dahdi_close_ss7_fd(struct dahdi_ss7 *ss7, int fd_num)
01505 {
01506    dahdi_close(ss7->fds[fd_num]);
01507    ss7->fds[fd_num] = -1;
01508 }
01509 #endif
01510 
01511 static int dahdi_setlinear(int dfd, int linear)
01512 {
01513    int res;
01514    res = ioctl(dfd, DAHDI_SETLINEAR, &linear);
01515    if (res)
01516       return res;
01517    return 0;
01518 }
01519 
01520 
01521 static int alloc_sub(struct dahdi_pvt *p, int x)
01522 {
01523    struct dahdi_bufferinfo bi;
01524    int res;
01525    if (p->subs[x].dfd >= 0) {
01526       ast_log(LOG_WARNING, "%s subchannel of %d already in use\n", subnames[x], p->channel);
01527       return -1;
01528    }
01529 
01530    p->subs[x].dfd = dahdi_open("/dev/dahdi/pseudo");
01531    if (p->subs[x].dfd <= -1) {
01532       ast_log(LOG_WARNING, "Unable to open pseudo channel: %s\n", strerror(errno));
01533       return -1;
01534    }
01535 
01536    res = ioctl(p->subs[x].dfd, DAHDI_GET_BUFINFO, &bi);
01537    if (!res) {
01538       bi.txbufpolicy = p->buf_policy;
01539       bi.rxbufpolicy = p->buf_policy;
01540       bi.numbufs = p->buf_no;
01541       res = ioctl(p->subs[x].dfd, DAHDI_SET_BUFINFO, &bi);
01542       if (res < 0) {
01543          ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", x, strerror(errno));
01544       }
01545    } else 
01546       ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", x, strerror(errno));
01547 
01548    if (ioctl(p->subs[x].dfd, DAHDI_CHANNO, &p->subs[x].chan) == 1) {
01549       ast_log(LOG_WARNING, "Unable to get channel number for pseudo channel on FD %d: %s\n", p->subs[x].dfd, strerror(errno));
01550       dahdi_close_sub(p, x);
01551       p->subs[x].dfd = -1;
01552       return -1;
01553    }
01554    ast_debug(1, "Allocated %s subchannel on FD %d channel %d\n", subnames[x], p->subs[x].dfd, p->subs[x].chan);
01555    return 0;
01556 }
01557 
01558 static int unalloc_sub(struct dahdi_pvt *p, int x)
01559 {
01560    if (!x) {
01561       ast_log(LOG_WARNING, "Trying to unalloc the real channel %d?!?\n", p->channel);
01562       return -1;
01563    }
01564    ast_debug(1, "Released sub %d of channel %d\n", x, p->channel);
01565    dahdi_close_sub(p, x);
01566    p->subs[x].linear = 0;
01567    p->subs[x].chan = 0;
01568    p->subs[x].owner = NULL;
01569    p->subs[x].inthreeway = 0;
01570    p->polarity = POLARITY_IDLE;
01571    memset(&p->subs[x].curconf, 0, sizeof(p->subs[x].curconf));
01572    return 0;
01573 }
01574 
01575 static int digit_to_dtmfindex(char digit)
01576 {
01577    if (isdigit(digit))
01578       return DAHDI_TONE_DTMF_BASE + (digit - '0');
01579    else if (digit >= 'A' && digit <= 'D')
01580       return DAHDI_TONE_DTMF_A + (digit - 'A');
01581    else if (digit >= 'a' && digit <= 'd')
01582       return DAHDI_TONE_DTMF_A + (digit - 'a');
01583    else if (digit == '*')
01584       return DAHDI_TONE_DTMF_s;
01585    else if (digit == '#')
01586       return DAHDI_TONE_DTMF_p;
01587    else
01588       return -1;
01589 }
01590 
01591 static int dahdi_digit_begin(struct ast_channel *chan, char digit)
01592 {
01593    struct dahdi_pvt *pvt;
01594    int idx;
01595    int dtmf = -1;
01596    
01597    pvt = chan->tech_pvt;
01598 
01599    ast_mutex_lock(&pvt->lock);
01600 
01601    idx = dahdi_get_index(chan, pvt, 0);
01602 
01603    if ((idx != SUB_REAL) || !pvt->owner)
01604       goto out;
01605 
01606 #ifdef HAVE_PRI
01607    if (((pvt->sig == SIG_PRI) || (pvt->sig == SIG_BRI) || (pvt->sig == SIG_BRI_PTMP)) 
01608          && (chan->_state == AST_STATE_DIALING) && !pvt->proceeding) {
01609       if (pvt->setup_ack) {
01610          if (!pri_grab(pvt, pvt->pri)) {
01611             pri_information(pvt->pri->pri, pvt->call, digit);
01612             pri_rel(pvt->pri);
01613          } else
01614             ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", pvt->span);
01615       } else if (strlen(pvt->dialdest) < sizeof(pvt->dialdest) - 1) {
01616          int res;
01617          ast_debug(1, "Queueing digit '%c' since setup_ack not yet received\n", digit);
01618          res = strlen(pvt->dialdest);
01619          pvt->dialdest[res++] = digit;
01620          pvt->dialdest[res] = '\0';
01621       }
01622       goto out;
01623    }
01624 #endif
01625    if ((dtmf = digit_to_dtmfindex(digit)) == -1)
01626       goto out;
01627 
01628    if (pvt->pulse || ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &dtmf)) {
01629       int res;
01630       struct dahdi_dialoperation zo = {
01631          .op = DAHDI_DIAL_OP_APPEND,
01632       };
01633 
01634       zo.dialstr[0] = 'T';
01635       zo.dialstr[1] = digit;
01636       zo.dialstr[2] = '\0';
01637       if ((res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_DIAL, &zo)))
01638          ast_log(LOG_WARNING, "Couldn't dial digit %c: %s\n", digit, strerror(errno));
01639       else
01640          pvt->dialing = 1;
01641    } else {
01642       ast_debug(1, "Started VLDTMF digit '%c'\n", digit);
01643       pvt->dialing = 1;
01644       pvt->begindigit = digit;
01645    }
01646 
01647 out:
01648    ast_mutex_unlock(&pvt->lock);
01649 
01650    return 0;
01651 }
01652 
01653 static int dahdi_digit_end(struct ast_channel *chan, char digit, unsigned int duration)
01654 {
01655    struct dahdi_pvt *pvt;
01656    int res = 0;
01657    int idx;
01658    int x;
01659    
01660    pvt = chan->tech_pvt;
01661 
01662    ast_mutex_lock(&pvt->lock);
01663    
01664    idx = dahdi_get_index(chan, pvt, 0);
01665 
01666    if ((idx != SUB_REAL) || !pvt->owner || pvt->pulse)
01667       goto out;
01668 
01669 #ifdef HAVE_PRI
01670    /* This means that the digit was already sent via PRI signalling */
01671    if (((pvt->sig == SIG_PRI) || (pvt->sig == SIG_BRI) || (pvt->sig == SIG_BRI_PTMP))
01672          && !pvt->begindigit)
01673       goto out;
01674 #endif
01675 
01676    if (pvt->begindigit) {
01677       x = -1;
01678       ast_debug(1, "Ending VLDTMF digit '%c'\n", digit);
01679       res = ioctl(pvt->subs[SUB_REAL].dfd, DAHDI_SENDTONE, &x);
01680       pvt->dialing = 0;
01681       pvt->begindigit = 0;
01682    }
01683 
01684 out:
01685    ast_mutex_unlock(&pvt->lock);
01686 
01687    return res;
01688 }
01689 
01690 static char *events[] = {
01691    "No event",
01692    "On hook",
01693    "Ring/Answered",
01694    "Wink/Flash",
01695    "Alarm",
01696    "No more alarm",
01697    "HDLC Abort",
01698    "HDLC Overrun",
01699    "HDLC Bad FCS",
01700    "Dial Complete",
01701    "Ringer On",
01702    "Ringer Off",
01703    "Hook Transition Complete",
01704    "Bits Changed",
01705    "Pulse Start",
01706    "Timer Expired",
01707    "Timer Ping",
01708    "Polarity Reversal",
01709    "Ring Begin",
01710 };
01711 
01712 static struct {
01713    int alarm;
01714    char *name;
01715 } alarms[] = {
01716    { DAHDI_ALARM_RED, "Red Alarm" },
01717    { DAHDI_ALARM_YELLOW, "Yellow Alarm" },
01718    { DAHDI_ALARM_BLUE, "Blue Alarm" },
01719    { DAHDI_ALARM_RECOVER, "Recovering" },
01720    { DAHDI_ALARM_LOOPBACK, "Loopback" },
01721    { DAHDI_ALARM_NOTOPEN, "Not Open" },
01722    { DAHDI_ALARM_NONE, "None" },
01723 };
01724 
01725 static char *alarm2str(int alm)
01726 {
01727    int x;
01728    for (x = 0; x < ARRAY_LEN(alarms); x++) {
01729       if (alarms[x].alarm & alm)
01730          return alarms[x].name;
01731    }
01732    return alm ? "Unknown Alarm" : "No Alarm";
01733 }
01734 
01735 static char *event2str(int event)
01736 {
01737    static char buf[256];
01738    if ((event < (ARRAY_LEN(events))) && (event > -1))
01739       return events[event];
01740    sprintf(buf, "Event %d", event); /* safe */
01741    return buf;
01742 }
01743 
01744 #ifdef HAVE_PRI
01745 static char *dialplan2str(int dialplan)
01746 {
01747    if (dialplan == -1 || dialplan == -2) {
01748       return("Dynamically set dialplan in ISDN");
01749    }
01750    return (pri_plan2str(dialplan));
01751 }
01752 #endif
01753 
01754 static char *dahdi_sig2str(int sig)
01755 {
01756    static char buf[256];
01757    switch (sig) {
01758    case SIG_EM:
01759       return "E & M Immediate";
01760    case SIG_EMWINK:
01761       return "E & M Wink";
01762    case SIG_EM_E1:
01763       return "E & M E1";
01764    case SIG_FEATD:
01765       return "Feature Group D (DTMF)";
01766    case SIG_FEATDMF:
01767       return "Feature Group D (MF)";
01768    case SIG_FEATDMF_TA:
01769       return "Feature Groud D (MF) Tandem Access";
01770    case SIG_FEATB:
01771       return "Feature Group B (MF)";
01772    case SIG_E911:
01773       return "E911 (MF)";
01774    case SIG_FGC_CAMA:
01775       return "FGC/CAMA (Dialpulse)";
01776    case SIG_FGC_CAMAMF:
01777       return "FGC/CAMA (MF)";
01778    case SIG_FXSLS:
01779       return "FXS Loopstart";
01780    case SIG_FXSGS:
01781       return "FXS Groundstart";
01782    case SIG_FXSKS:
01783       return "FXS Kewlstart";
01784    case SIG_FXOLS:
01785       return "FXO Loopstart";
01786    case SIG_FXOGS:
01787       return "FXO Groundstart";
01788    case SIG_FXOKS:
01789       return "FXO Kewlstart";
01790    case SIG_PRI:
01791       return "ISDN PRI";
01792    case SIG_BRI:
01793       return "ISDN BRI Point to Point";
01794    case SIG_BRI_PTMP:
01795       return "ISDN BRI Point to MultiPoint";
01796    case SIG_SS7:
01797       return "SS7";
01798    case SIG_SF:
01799       return "SF (Tone) Immediate";
01800    case SIG_SFWINK:
01801       return "SF (Tone) Wink";
01802    case SIG_SF_FEATD:
01803       return "SF (Tone) with Feature Group D (DTMF)";
01804    case SIG_SF_FEATDMF:
01805       return "SF (Tone) with Feature Group D (MF)";
01806    case SIG_SF_FEATB:
01807       return "SF (Tone) with Feature Group B (MF)";
01808    case SIG_GR303FXOKS:
01809       return "GR-303 with FXOKS";
01810    case SIG_GR303FXSKS:
01811       return "GR-303 with FXSKS";
01812    case 0:
01813       return "Pseudo";
01814    default:
01815       snprintf(buf, sizeof(buf), "Unknown signalling %d", sig);
01816       return buf;
01817    }
01818 }
01819 
01820 #define sig2str dahdi_sig2str
01821 
01822 static int conf_add(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx, int slavechannel)
01823 {
01824    /* If the conference already exists, and we're already in it
01825       don't bother doing anything */
01826    struct dahdi_confinfo zi;
01827    
01828    memset(&zi, 0, sizeof(zi));
01829    zi.chan = 0;
01830 
01831    if (slavechannel > 0) {
01832       /* If we have only one slave, do a digital mon */
01833       zi.confmode = DAHDI_CONF_DIGITALMON;
01834       zi.confno = slavechannel;
01835    } else {
01836       if (!idx) {
01837          /* Real-side and pseudo-side both participate in conference */
01838          zi.confmode = DAHDI_CONF_REALANDPSEUDO | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER |
01839             DAHDI_CONF_PSEUDO_TALKER | DAHDI_CONF_PSEUDO_LISTENER;
01840       } else
01841          zi.confmode = DAHDI_CONF_CONF | DAHDI_CONF_TALKER | DAHDI_CONF_LISTENER;
01842       zi.confno = p->confno;
01843    }
01844    if ((zi.confno == c->curconf.confno) && (zi.confmode == c->curconf.confmode))
01845       return 0;
01846    if (c->dfd < 0)
01847       return 0;
01848    if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
01849       ast_log(LOG_WARNING, "Failed to add %d to conference %d/%d: %s\n", c->dfd, zi.confmode, zi.confno, strerror(errno));
01850       return -1;
01851    }
01852    if (slavechannel < 1) {
01853       p->confno = zi.confno;
01854    }
01855    memcpy(&c->curconf, &zi, sizeof(c->curconf));
01856    ast_debug(1, "Added %d to conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
01857    return 0;
01858 }
01859 
01860 static int isourconf(struct dahdi_pvt *p, struct dahdi_subchannel *c)
01861 {
01862    /* If they're listening to our channel, they're ours */  
01863    if ((p->channel == c->curconf.confno) && (c->curconf.confmode == DAHDI_CONF_DIGITALMON))
01864       return 1;
01865    /* If they're a talker on our (allocated) conference, they're ours */
01866    if ((p->confno > 0) && (p->confno == c->curconf.confno) && (c->curconf.confmode & DAHDI_CONF_TALKER))
01867       return 1;
01868    return 0;
01869 }
01870 
01871 static int conf_del(struct dahdi_pvt *p, struct dahdi_subchannel *c, int idx)
01872 {
01873    struct dahdi_confinfo zi;
01874    if (/* Can't delete if there's no dfd */
01875       (c->dfd < 0) ||
01876       /* Don't delete from the conference if it's not our conference */
01877       !isourconf(p, c)
01878       /* Don't delete if we don't think it's conferenced at all (implied) */
01879       ) return 0;
01880    memset(&zi, 0, sizeof(zi));
01881    if (ioctl(c->dfd, DAHDI_SETCONF, &zi)) {
01882       ast_log(LOG_WARNING, "Failed to drop %d from conference %d/%d: %s\n", c->dfd, c->curconf.confmode, c->curconf.confno, strerror(errno));
01883       return -1;
01884    }
01885    ast_debug(1, "Removed %d from conference %d/%d\n", c->dfd, c->curconf.confmode, c->curconf.confno);
01886    memcpy(&c->curconf, &zi, sizeof(c->curconf));
01887    return 0;
01888 }
01889 
01890 static int isslavenative(struct dahdi_pvt *p, struct dahdi_pvt **out)
01891 {
01892    int x;
01893    int useslavenative;
01894    struct dahdi_pvt *slave = NULL;
01895    /* Start out optimistic */
01896    useslavenative = 1;
01897    /* Update conference state in a stateless fashion */
01898    for (x = 0; x < 3; x++) {
01899       /* Any three-way calling makes slave native mode *definitely* out
01900          of the question */
01901       if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway)
01902          useslavenative = 0;
01903    }
01904    /* If we don't have any 3-way calls, check to see if we have
01905       precisely one slave */
01906    if (useslavenative) {
01907       for (x = 0; x < MAX_SLAVES; x++) {
01908          if (p->slaves[x]) {
01909             if (slave) {
01910                /* Whoops already have a slave!  No 
01911                   slave native and stop right away */
01912                slave = NULL;
01913                useslavenative = 0;
01914                break;
01915             } else {
01916                /* We have one slave so far */
01917                slave = p->slaves[x];
01918             }
01919          }
01920       }
01921    }
01922    /* If no slave, slave native definitely out */
01923    if (!slave)
01924       useslavenative = 0;
01925    else if (slave->law != p->law) {
01926       useslavenative = 0;
01927       slave = NULL;
01928    }
01929    if (out)
01930       *out = slave;
01931    return useslavenative;
01932 }
01933 
01934 static int reset_conf(struct dahdi_pvt *p)
01935 {
01936    p->confno = -1;
01937    memset(&p->subs[SUB_REAL].curconf, 0, sizeof(p->subs[SUB_REAL].curconf));
01938    if (p->subs[SUB_REAL].dfd > -1) {
01939       struct dahdi_confinfo zi;
01940 
01941       memset(&zi, 0, sizeof(zi));
01942       if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &zi))
01943          ast_log(LOG_WARNING, "Failed to reset conferencing on channel %d: %s\n", p->channel, strerror(errno));
01944    }
01945    return 0;
01946 }
01947 
01948 static int update_conf(struct dahdi_pvt *p)
01949 {
01950    int needconf = 0;
01951    int x;
01952    int useslavenative;
01953    struct dahdi_pvt *slave = NULL;
01954 
01955    useslavenative = isslavenative(p, &slave);
01956    /* Start with the obvious, general stuff */
01957    for (x = 0; x < 3; x++) {
01958       /* Look for three way calls */
01959       if ((p->subs[x].dfd > -1) && p->subs[x].inthreeway) {
01960          conf_add(p, &p->subs[x], x, 0);
01961          needconf++;
01962       } else {
01963          conf_del(p, &p->subs[x], x);
01964       }
01965    }
01966    /* If we have a slave, add him to our conference now. or DAX
01967       if this is slave native */
01968    for (x = 0; x < MAX_SLAVES; x++) {
01969       if (p->slaves[x]) {
01970          if (useslavenative)
01971             conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p));
01972          else {
01973             conf_add(p, &p->slaves[x]->subs[SUB_REAL], SUB_REAL, 0);
01974             needconf++;
01975          }
01976       }
01977    }
01978    /* If we're supposed to be in there, do so now */
01979    if (p->inconference && !p->subs[SUB_REAL].inthreeway) {
01980       if (useslavenative)
01981          conf_add(p, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(slave));
01982       else {
01983          conf_add(p, &p->subs[SUB_REAL], SUB_REAL, 0);
01984          needconf++;
01985       }
01986    }
01987    /* If we have a master, add ourselves to his conference */
01988    if (p->master) {
01989       if (isslavenative(p->master, NULL)) {
01990          conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, GET_CHANNEL(p->master));
01991       } else {
01992          conf_add(p->master, &p->subs[SUB_REAL], SUB_REAL, 0);
01993       }
01994    }
01995    if (!needconf) {
01996       /* Nobody is left (or should be left) in our conference.
01997          Kill it. */
01998       p->confno = -1;
01999    }
02000    ast_debug(1, "Updated conferencing on %d, with %d conference users\n", p->channel, needconf);
02001    return 0;
02002 }
02003 
02004 static void dahdi_enable_ec(struct dahdi_pvt *p)
02005 {
02006    int x;
02007    int res;
02008    if (!p)
02009       return;
02010    if (p->echocanon) {
02011       ast_debug(1, "Echo cancellation already on\n");
02012       return;
02013    }
02014    if (p->digital) {
02015       ast_debug(1, "Echo cancellation isn't required on digital connection\n");
02016       return;
02017    }
02018    if (p->echocancel.head.tap_length) {
02019       if ((p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP) || (p->sig == SIG_PRI) || (p->sig == SIG_SS7)) {
02020          x = 1;
02021          res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x);
02022          if (res)
02023             ast_log(LOG_WARNING, "Unable to enable audio mode on channel %d (%s)\n", p->channel, strerror(errno));
02024       }
02025       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &p->echocancel);
02026       if (res)  {
02027          ast_log(LOG_WARNING, "Unable to enable echo cancellation on channel %d (%s)\n", p->channel, strerror(errno));
02028       } else {
02029          p->echocanon = 1;
02030          ast_debug(1, "Enabled echo cancellation on channel %d\n", p->channel);
02031       }
02032    } else
02033       ast_debug(1, "No echo cancellation requested\n");
02034 }
02035 
02036 static void dahdi_train_ec(struct dahdi_pvt *p)
02037 {
02038    int x;
02039    int res;
02040    
02041    if (p && p->echocanon && p->echotraining) {
02042       x = p->echotraining;
02043       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOTRAIN, &x);
02044       if (res)
02045          ast_log(LOG_WARNING, "Unable to request echo training on channel %d: %s\n", p->channel, strerror(errno));
02046       else
02047          ast_debug(1, "Engaged echo training on channel %d\n", p->channel);
02048    } else {
02049       ast_debug(1, "No echo training requested\n");
02050    }
02051 }
02052 
02053 static void dahdi_disable_ec(struct dahdi_pvt *p)
02054 {
02055    int res;
02056 
02057    if (p->echocanon) {
02058       struct dahdi_echocanparams ecp = { .tap_length = 0 };
02059 
02060       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_ECHOCANCEL_PARAMS, &ecp);
02061 
02062       if (res)
02063          ast_log(LOG_WARNING, "Unable to disable echo cancellation on channel %d: %s\n", p->channel, strerror(errno));
02064       else
02065          ast_debug(1, "Disabled echo cancellation on channel %d\n", p->channel);
02066    }
02067 
02068    p->echocanon = 0;
02069 }
02070 
02071 static void fill_txgain(struct dahdi_gains *g, float gain, int law)
02072 {
02073    int j;
02074    int k;
02075    float linear_gain = pow(10.0, gain / 20.0);
02076 
02077    switch (law) {
02078    case DAHDI_LAW_ALAW:
02079       for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
02080          if (gain) {
02081             k = (int) (((float) AST_ALAW(j)) * linear_gain);
02082             if (k > 32767) k = 32767;
02083             if (k < -32767) k = -32767;
02084             g->txgain[j] = AST_LIN2A(k);
02085          } else {
02086             g->txgain[j] = j;
02087          }
02088       }
02089       break;
02090    case DAHDI_LAW_MULAW:
02091       for (j = 0; j < ARRAY_LEN(g->txgain); j++) {
02092          if (gain) {
02093             k = (int) (((float) AST_MULAW(j)) * linear_gain);
02094             if (k > 32767) k = 32767;
02095             if (k < -32767) k = -32767;
02096             g->txgain[j] = AST_LIN2MU(k);
02097          } else {
02098             g->txgain[j] = j;
02099          }
02100       }
02101       break;
02102    }
02103 }
02104 
02105 static void fill_rxgain(struct dahdi_gains *g, float gain, int law)
02106 {
02107    int j;
02108    int k;
02109    float linear_gain = pow(10.0, gain / 20.0);
02110 
02111    switch (law) {
02112    case DAHDI_LAW_ALAW:
02113       for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
02114          if (gain) {
02115             k = (int) (((float) AST_ALAW(j)) * linear_gain);
02116             if (k > 32767) k = 32767;
02117             if (k < -32767) k = -32767;
02118             g->rxgain[j] = AST_LIN2A(k);
02119          } else {
02120             g->rxgain[j] = j;
02121          }
02122       }
02123       break;
02124    case DAHDI_LAW_MULAW:
02125       for (j = 0; j < ARRAY_LEN(g->rxgain); j++) {
02126          if (gain) {
02127             k = (int) (((float) AST_MULAW(j)) * linear_gain);
02128             if (k > 32767) k = 32767;
02129             if (k < -32767) k = -32767;
02130             g->rxgain[j] = AST_LIN2MU(k);
02131          } else {
02132             g->rxgain[j] = j;
02133          }
02134       }
02135       break;
02136    }
02137 }
02138 
02139 static int set_actual_txgain(int fd, int chan, float gain, int law)
02140 {
02141    struct dahdi_gains g;
02142    int res;
02143 
02144    memset(&g, 0, sizeof(g));
02145    g.chan = chan;
02146    res = ioctl(fd, DAHDI_GETGAINS, &g);
02147    if (res) {
02148       ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
02149       return res;
02150    }
02151 
02152    fill_txgain(&g, gain, law);
02153 
02154    return ioctl(fd, DAHDI_SETGAINS, &g);
02155 }
02156 
02157 static int set_actual_rxgain(int fd, int chan, float gain, int law)
02158 {
02159    struct dahdi_gains g;
02160    int res;
02161 
02162    memset(&g, 0, sizeof(g));
02163    g.chan = chan;
02164    res = ioctl(fd, DAHDI_GETGAINS, &g);
02165    if (res) {
02166       ast_debug(1, "Failed to read gains: %s\n", strerror(errno));
02167       return res;
02168    }
02169 
02170    fill_rxgain(&g, gain, law);
02171 
02172    return ioctl(fd, DAHDI_SETGAINS, &g);
02173 }
02174 
02175 static int set_actual_gain(int fd, int chan, float rxgain, float txgain, int law)
02176 {
02177    return set_actual_txgain(fd, chan, txgain, law) | set_actual_rxgain(fd, chan, rxgain, law);
02178 }
02179 
02180 static int bump_gains(struct dahdi_pvt *p)
02181 {
02182    int res;
02183 
02184    /* Bump receive gain by value stored in cid_rxgain */
02185    res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain + p->cid_rxgain, p->txgain, p->law);
02186    if (res) {
02187       ast_log(LOG_WARNING, "Unable to bump gain: %s\n", strerror(errno));
02188       return -1;
02189    }
02190 
02191    return 0;
02192 }
02193 
02194 static int restore_gains(struct dahdi_pvt *p)
02195 {
02196    int res;
02197 
02198    res = set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law);
02199    if (res) {
02200       ast_log(LOG_WARNING, "Unable to restore gains: %s\n", strerror(errno));
02201       return -1;
02202    }
02203 
02204    return 0;
02205 }
02206 
02207 static inline int dahdi_set_hook(int fd, int hs)
02208 {
02209    int x, res;
02210 
02211    x = hs;
02212    res = ioctl(fd, DAHDI_HOOK, &x);
02213 
02214    if (res < 0) {
02215       if (errno == EINPROGRESS)
02216          return 0;
02217       ast_log(LOG_WARNING, "DAHDI hook failed returned %d (trying %d): %s\n", res, hs, strerror(errno));
02218       /* will expectedly fail if phone is off hook during operation, such as during a restart */
02219    }
02220 
02221    return res;
02222 }
02223 
02224 static inline int dahdi_confmute(struct dahdi_pvt *p, int muted)
02225 {
02226    int x, y, res;
02227    x = muted;
02228    if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
02229       y = 1;
02230       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &y);
02231       if (res)
02232          ast_log(LOG_WARNING, "Unable to set audio mode on %d: %s\n", p->channel, strerror(errno));
02233    }
02234    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_CONFMUTE, &x);
02235    if (res < 0)
02236       ast_log(LOG_WARNING, "DAHDI confmute(%d) failed on channel %d: %s\n", muted, p->channel, strerror(errno));
02237    return res;
02238 }
02239 
02240 static int save_conference(struct dahdi_pvt *p)
02241 {
02242    struct dahdi_confinfo c;
02243    int res;
02244    if (p->saveconf.confmode) {
02245       ast_log(LOG_WARNING, "Can't save conference -- already in use\n");
02246       return -1;
02247    }
02248    p->saveconf.chan = 0;
02249    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &p->saveconf);
02250    if (res) {
02251       ast_log(LOG_WARNING, "Unable to get conference info: %s\n", strerror(errno));
02252       p->saveconf.confmode = 0;
02253       return -1;
02254    }
02255    memset(&c, 0, sizeof(c));
02256    c.confmode = DAHDI_CONF_NORMAL;
02257    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &c);
02258    if (res) {
02259       ast_log(LOG_WARNING, "Unable to set conference info: %s\n", strerror(errno));
02260       return -1;
02261    }
02262    ast_debug(1, "Disabled conferencing\n");
02263    return 0;
02264 }
02265 
02266 /*!
02267  * \brief Send MWI state change
02268  *
02269  * \arg mailbox_full This is the mailbox associated with the FXO line that the
02270  *      MWI state has changed on.
02271  * \arg thereornot This argument should simply be set to 1 or 0, to indicate
02272  *      whether there are messages waiting or not.
02273  *
02274  *  \return nothing
02275  *
02276  * This function does two things:
02277  *
02278  * 1) It generates an internal Asterisk event notifying any other module that
02279  *    cares about MWI that the state of a mailbox has changed.
02280  *
02281  * 2) It runs the script specified by the mwimonitornotify option to allow
02282  *    some custom handling of the state change.
02283  */
02284 static void notify_message(char *mailbox_full, int thereornot)
02285 {
02286    char s[sizeof(mwimonitornotify) + 80];
02287    struct ast_event *event;
02288    char *mailbox, *context;
02289 
02290    /* Strip off @default */
02291    context = mailbox = ast_strdupa(mailbox_full);
02292    strsep(&context, "@");
02293    if (ast_strlen_zero(context))
02294       context = "default";
02295 
02296    if (!(event = ast_event_new(AST_EVENT_MWI,
02297          AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
02298          AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
02299          AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
02300          AST_EVENT_IE_OLDMSGS, AST_EVENT_IE_PLTYPE_UINT, thereornot,
02301          AST_EVENT_IE_END))) {
02302       return;
02303    }
02304 
02305    ast_event_queue_and_cache(event);
02306 
02307    if (!ast_strlen_zero(mailbox) && !ast_strlen_zero(mwimonitornotify)) {
02308       snprintf(s, sizeof(s), "%s %s %d", mwimonitornotify, mailbox, thereornot);
02309       ast_safe_system(s);
02310    }
02311 }
02312 
02313 static int restore_conference(struct dahdi_pvt *p)
02314 {
02315    int res;
02316    if (p->saveconf.confmode) {
02317       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCONF, &p->saveconf);
02318       p->saveconf.confmode = 0;
02319       if (res) {
02320          ast_log(LOG_WARNING, "Unable to restore conference info: %s\n", strerror(errno));
02321          return -1;
02322       }
02323    }
02324    ast_debug(1, "Restored conferencing\n");
02325    return 0;
02326 }
02327 
02328 static int send_callerid(struct dahdi_pvt *p);
02329 
02330 static int send_cwcidspill(struct dahdi_pvt *p)
02331 {
02332    p->callwaitcas = 0;
02333    p->cidcwexpire = 0;
02334    if (!(p->cidspill = ast_malloc(MAX_CALLERID_SIZE)))
02335       return -1;
02336    p->cidlen = ast_callerid_callwaiting_generate(p->cidspill, p->callwait_name, p->callwait_num, AST_LAW(p));
02337    /* Make sure we account for the end */
02338    p->cidlen += READ_SIZE * 4;
02339    p->cidpos = 0;
02340    send_callerid(p);
02341    ast_verb(3, "CPE supports Call Waiting Caller*ID.  Sending '%s/%s'\n", p->callwait_name, p->callwait_num);
02342    return 0;
02343 }
02344 
02345 static int has_voicemail(struct dahdi_pvt *p)
02346 {
02347    int new_msgs;
02348    struct ast_event *event;
02349    char *mailbox, *context;
02350 
02351    mailbox = context = ast_strdupa(p->mailbox);
02352    strsep(&context, "@");
02353    if (ast_strlen_zero(context))
02354       context = "default";
02355 
02356    event = ast_event_get_cached(AST_EVENT_MWI,
02357       AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
02358       AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
02359       AST_EVENT_IE_END);
02360 
02361    if (event) {
02362       new_msgs = ast_event_get_ie_uint(event, AST_EVENT_IE_NEWMSGS);
02363       ast_event_destroy(event);
02364    } else
02365       new_msgs = ast_app_has_voicemail(p->mailbox, NULL);
02366 
02367    return new_msgs;
02368 }
02369 
02370 static int send_callerid(struct dahdi_pvt *p)
02371 {
02372    /* Assumes spill in p->cidspill, p->cidlen in length and we're p->cidpos into it */
02373    int res;
02374    /* Take out of linear mode if necessary */
02375    if (p->subs[SUB_REAL].linear) {
02376       p->subs[SUB_REAL].linear = 0;
02377       dahdi_setlinear(p->subs[SUB_REAL].dfd, 0);
02378    }
02379    while (p->cidpos < p->cidlen) {
02380       res = write(p->subs[SUB_REAL].dfd, p->cidspill + p->cidpos, p->cidlen - p->cidpos);
02381       if (res < 0) {
02382          if (errno == EAGAIN)
02383             return 0;
02384          else {
02385             ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
02386             return -1;
02387          }
02388       }
02389       if (!res)
02390          return 0;
02391       p->cidpos += res;
02392    }
02393    ast_free(p->cidspill);
02394    p->cidspill = NULL;
02395    if (p->callwaitcas) {
02396       /* Wait for CID/CW to expire */
02397       p->cidcwexpire = CIDCW_EXPIRE_SAMPLES;
02398    } else
02399       restore_conference(p);
02400    return 0;
02401 }
02402 
02403 static int dahdi_callwait(struct ast_channel *ast)
02404 {
02405    struct dahdi_pvt *p = ast->tech_pvt;
02406    p->callwaitingrepeat = CALLWAITING_REPEAT_SAMPLES;
02407    if (p->cidspill) {
02408       ast_log(LOG_WARNING, "Spill already exists?!?\n");
02409       ast_free(p->cidspill);
02410    }
02411    if (!(p->cidspill = ast_malloc(2400 /* SAS */ + 680 /* CAS */ + READ_SIZE * 4)))
02412       return -1;
02413    save_conference(p);
02414    /* Silence */
02415    memset(p->cidspill, 0x7f, 2400 + 600 + READ_SIZE * 4);
02416    if (!p->callwaitrings && p->callwaitingcallerid) {
02417       ast_gen_cas(p->cidspill, 1, 2400 + 680, AST_LAW(p));
02418       p->callwaitcas = 1;
02419       p->cidlen = 2400 + 680 + READ_SIZE * 4;
02420    } else {
02421       ast_gen_cas(p->cidspill, 1, 2400, AST_LAW(p));
02422       p->callwaitcas = 0;
02423       p->cidlen = 2400 + READ_SIZE * 4;
02424    }
02425    p->cidpos = 0;
02426    send_callerid(p);
02427    
02428    return 0;
02429 }
02430 
02431 #ifdef HAVE_SS7
02432 static unsigned char cid_pres2ss7pres(int cid_pres)
02433 {
02434     return (cid_pres >> 5) & 0x03;
02435 }
02436 
02437 static unsigned char cid_pres2ss7screen(int cid_pres)
02438 {
02439    return cid_pres & 0x03;
02440 }
02441 #endif
02442 
02443 static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
02444 {
02445    struct dahdi_pvt *p = ast->tech_pvt;
02446    int x, res, idx,mysig;
02447    char *c, *n, *l;
02448 #ifdef HAVE_PRI
02449    char *s = NULL;
02450 #endif
02451    char dest[256]; /* must be same length as p->dialdest */
02452    ast_mutex_lock(&p->lock);
02453    ast_copy_string(dest, rdest, sizeof(dest));
02454    ast_copy_string(p->dialdest, rdest, sizeof(p->dialdest));
02455    if ((ast->_state == AST_STATE_BUSY)) {
02456       p->subs[SUB_REAL].needbusy = 1;
02457       ast_mutex_unlock(&p->lock);
02458       return 0;
02459    }
02460    if ((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) {
02461       ast_log(LOG_WARNING, "dahdi_call called on %s, neither down nor reserved\n", ast->name);
02462       ast_mutex_unlock(&p->lock);
02463       return -1;
02464    }
02465    p->dialednone = 0;
02466    if ((p->radio || (p->oprmode < 0)))  /* if a radio channel, up immediately */
02467    {
02468       /* Special pseudo -- automatically up */
02469       ast_setstate(ast, AST_STATE_UP); 
02470       ast_mutex_unlock(&p->lock);
02471       return 0;
02472    }
02473    x = DAHDI_FLUSH_READ | DAHDI_FLUSH_WRITE;
02474    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
02475    if (res)
02476       ast_log(LOG_WARNING, "Unable to flush input on channel %d: %s\n", p->channel, strerror(errno));
02477    p->outgoing = 1;
02478 
02479    if (IS_DIGITAL(ast->transfercapability)){
02480       set_actual_gain(p->subs[SUB_REAL].dfd, 0, 0, 0, p->law);
02481    } else {
02482       set_actual_gain(p->subs[SUB_REAL].dfd, 0, p->rxgain, p->txgain, p->law);
02483    }  
02484 
02485    mysig = p->sig;
02486    if (p->outsigmod > -1)
02487       mysig = p->outsigmod;
02488 
02489    switch (mysig) {
02490    case SIG_FXOLS:
02491    case SIG_FXOGS:
02492    case SIG_FXOKS:
02493       if (p->owner == ast) {
02494          /* Normal ring, on hook */
02495          
02496          /* Don't send audio while on hook, until the call is answered */
02497          p->dialing = 1;
02498          if (p->use_callerid) {
02499             /* Generate the Caller-ID spill if desired */
02500             if (p->cidspill) {
02501                ast_log(LOG_WARNING, "cidspill already exists??\n");
02502                ast_free(p->cidspill);
02503             }
02504             p->callwaitcas = 0;
02505             if ((p->cidspill = ast_malloc(MAX_CALLERID_SIZE))) {
02506                p->cidlen = ast_callerid_generate(p->cidspill, ast->cid.cid_name, ast->cid.cid_num, AST_LAW(p));
02507                p->cidpos = 0;
02508                send_callerid(p);
02509             }
02510          }
02511          /* Choose proper cadence */
02512          if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
02513             if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
02514                ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast->name, strerror(errno));
02515             p->cidrings = cidrings[p->distinctivering - 1];
02516          } else {
02517             if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
02518                ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast->name, strerror(errno));
02519             p->cidrings = p->sendcalleridafter;
02520          }
02521 
02522          /* nick@dccinc.com 4/3/03 mods to allow for deferred dialing */
02523          c = strchr(dest, '/');
02524          if (c)
02525             c++;
02526          if (c && (strlen(c) < p->stripmsd)) {
02527             ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
02528             c = NULL;
02529          }
02530          if (c) {
02531             p->dop.op = DAHDI_DIAL_OP_REPLACE;
02532             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "Tw%s", c);
02533             ast_debug(1, "FXO: setup deferred dialstring: %s\n", c);
02534          } else {
02535             p->dop.dialstr[0] = '\0';
02536          }
02537          x = DAHDI_RING;
02538          if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x) && (errno != EINPROGRESS)) {
02539             ast_log(LOG_WARNING, "Unable to ring phone: %s\n", strerror(errno));
02540             ast_mutex_unlock(&p->lock);
02541             return -1;
02542          }
02543          p->dialing = 1;
02544       } else {
02545          /* Call waiting call */
02546          p->callwaitrings = 0;
02547          if (ast->cid.cid_num)
02548             ast_copy_string(p->callwait_num, ast->cid.cid_num, sizeof(p->callwait_num));
02549          else
02550             p->callwait_num[0] = '\0';
02551          if (ast->cid.cid_name)
02552             ast_copy_string(p->callwait_name, ast->cid.cid_name, sizeof(p->callwait_name));
02553          else
02554             p->callwait_name[0] = '\0';
02555          /* Call waiting tone instead */
02556          if (dahdi_callwait(ast)) {
02557             ast_mutex_unlock(&p->lock);
02558             return -1;
02559          }
02560          /* Make ring-back */
02561          if (tone_zone_play_tone(p->subs[SUB_CALLWAIT].dfd, DAHDI_TONE_RINGTONE))
02562             ast_log(LOG_WARNING, "Unable to generate call-wait ring-back on channel %s\n", ast->name);
02563             
02564       }
02565       n = ast->cid.cid_name;
02566       l = ast->cid.cid_num;
02567       if (l)
02568          ast_copy_string(p->lastcid_num, l, sizeof(p->lastcid_num));
02569       else
02570          p->lastcid_num[0] = '\0';
02571       if (n)
02572          ast_copy_string(p->lastcid_name, n, sizeof(p->lastcid_name));
02573       else
02574          p->lastcid_name[0] = '\0';
02575       ast_setstate(ast, AST_STATE_RINGING);
02576       idx = dahdi_get_index(ast, p, 0);
02577       if (idx > -1) {
02578          p->subs[idx].needringing = 1;
02579       }
02580       break;
02581    case SIG_FXSLS:
02582    case SIG_FXSGS:
02583    case SIG_FXSKS:
02584       if (p->answeronpolarityswitch || p->hanguponpolarityswitch) {
02585          ast_debug(1, "Ignore possible polarity reversal on line seizure\n");
02586          p->polaritydelaytv = ast_tvnow();
02587       }
02588       /* fall through */
02589    case SIG_EMWINK:
02590    case SIG_EM:
02591    case SIG_EM_E1:
02592    case SIG_FEATD:
02593    case SIG_FEATDMF:
02594    case SIG_E911:
02595    case SIG_FGC_CAMA:
02596    case SIG_FGC_CAMAMF:
02597    case SIG_FEATB:
02598    case SIG_SFWINK:
02599    case SIG_SF:
02600    case SIG_SF_FEATD:
02601    case SIG_SF_FEATDMF:
02602    case SIG_FEATDMF_TA:
02603    case SIG_SF_FEATB:
02604       c = strchr(dest, '/');
02605       if (c)
02606          c++;
02607       else
02608          c = "";
02609       if (strlen(c) < p->stripmsd) {
02610          ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
02611          ast_mutex_unlock(&p->lock);
02612          return -1;
02613       }
02614 #ifdef HAVE_PRI
02615       /* Start the trunk, if not GR-303 */
02616       if (!p->pri) {
02617 #endif
02618          x = DAHDI_START;
02619          res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
02620          if (res < 0) {
02621             if (errno != EINPROGRESS) {
02622                ast_log(LOG_WARNING, "Unable to start channel: %s\n", strerror(errno));
02623                ast_mutex_unlock(&p->lock);
02624                return -1;
02625             }
02626          }
02627 #ifdef HAVE_PRI
02628       }
02629 #endif
02630       ast_debug(1, "Dialing '%s'\n", c);
02631       p->dop.op = DAHDI_DIAL_OP_REPLACE;
02632 
02633       c += p->stripmsd;
02634 
02635       switch (mysig) {
02636       case SIG_FEATD:
02637          l = ast->cid.cid_num;
02638          if (l) 
02639             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T*%s*%s*", l, c);
02640          else
02641             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T**%s*", c);
02642          break;
02643       case SIG_FEATDMF:
02644          l = ast->cid.cid_num;
02645          if (l) 
02646             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*00%s#*%s#", l, c);
02647          else
02648             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*02#*%s#", c);
02649          break;
02650       case SIG_FEATDMF_TA:
02651       {
02652          const char *cic, *ozz;
02653 
02654          /* If you have to go through a Tandem Access point you need to use this */
02655          ozz = pbx_builtin_getvar_helper(p->owner, "FEATDMF_OZZ");
02656          if (!ozz)
02657             ozz = defaultozz;
02658          cic = pbx_builtin_getvar_helper(p->owner, "FEATDMF_CIC");
02659          if (!cic)
02660             cic = defaultcic;
02661          if (!ozz || !cic) {
02662             ast_log(LOG_WARNING, "Unable to dial channel of type feature group D MF tandem access without CIC or OZZ set\n");
02663             ast_mutex_unlock(&p->lock);
02664             return -1;
02665          }
02666          snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s%s#", ozz, cic);
02667          snprintf(p->finaldial, sizeof(p->finaldial), "M*%s#", c);
02668          p->whichwink = 0;
02669       }
02670          break;
02671       case SIG_E911:
02672          ast_copy_string(p->dop.dialstr, "M*911#", sizeof(p->dop.dialstr));
02673          break;
02674       case SIG_FGC_CAMA:
02675          snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%s", c);
02676          break;
02677       case SIG_FGC_CAMAMF:
02678       case SIG_FEATB:
02679          snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%s#", c);
02680          break;
02681       default:
02682          if (p->pulse)
02683             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "P%sw", c);
02684          else
02685             snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T%sw", c);
02686          break;
02687       }
02688 
02689       if (p->echotraining && (strlen(p->dop.dialstr) > 4)) {
02690          memset(p->echorest, 'w', sizeof(p->echorest) - 1);
02691          strcpy(p->echorest + (p->echotraining / 400) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
02692          p->echorest[sizeof(p->echorest) - 1] = '\0';
02693          p->echobreak = 1;
02694          p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
02695       } else
02696          p->echobreak = 0;
02697       if (!res) {
02698          if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
02699             int saveerr = errno;
02700 
02701             x = DAHDI_ONHOOK;
02702             ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
02703             ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
02704             ast_mutex_unlock(&p->lock);
02705             return -1;
02706          }
02707       } else
02708          ast_debug(1, "Deferring dialing...\n");
02709 
02710       p->dialing = 1;
02711       if (ast_strlen_zero(c))
02712          p->dialednone = 1;
02713       ast_setstate(ast, AST_STATE_DIALING);
02714       break;
02715    case 0:
02716       /* Special pseudo -- automatically up*/
02717       ast_setstate(ast, AST_STATE_UP);
02718       break;      
02719    case SIG_PRI:
02720    case SIG_BRI:
02721    case SIG_BRI_PTMP:
02722    case SIG_SS7:
02723       /* We'll get it in a moment -- but use dialdest to store pre-setup_ack digits */
02724       p->dialdest[0] = '\0';
02725       p->dialing = 1;
02726       break;
02727    default:
02728       ast_debug(1, "not yet implemented\n");
02729       ast_mutex_unlock(&p->lock);
02730       return -1;
02731    }
02732 #ifdef HAVE_SS7
02733    if (p->ss7) {
02734       char ss7_called_nai;
02735       int called_nai_strip;
02736       char ss7_calling_nai;
02737       int calling_nai_strip;
02738       const char *charge_str = NULL;
02739       const char *gen_address = NULL;
02740       const char *gen_digits = NULL;
02741       const char *gen_dig_type = NULL;
02742       const char *gen_dig_scheme = NULL;
02743       const char *gen_name = NULL;
02744       const char *jip_digits = NULL;
02745       const char *lspi_ident = NULL;
02746       const char *rlt_flag = NULL;
02747       const char *call_ref_id = NULL;
02748       const char *call_ref_pc = NULL;
02749       const char *send_far = NULL;
02750 
02751       c = strchr(dest, '/');
02752       if (c) {
02753          c++;
02754       } else {
02755          c = "";
02756       }
02757       if (strlen(c) < p->stripmsd) {
02758          ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
02759          ast_mutex_unlock(&p->lock);
02760          return -1;
02761       }
02762 
02763       if (!p->hidecallerid) {
02764          l = ast->cid.cid_num;
02765       } else {
02766          l = NULL;
02767       }
02768 
02769       if (ss7_grab(p, p->ss7)) {
02770          ast_log(LOG_WARNING, "Failed to grab SS7!\n");
02771          ast_mutex_unlock(&p->lock);
02772          return -1;
02773       }
02774       p->digital = IS_DIGITAL(ast->transfercapability);
02775       p->ss7call = isup_new_call(p->ss7->ss7);
02776 
02777       if (!p->ss7call) {
02778          ss7_rel(p->ss7);
02779          ast_mutex_unlock(&p->lock);
02780          ast_log(LOG_ERROR, "Unable to allocate new SS7 call!\n");
02781          return -1;
02782       }
02783 
02784       called_nai_strip = 0;
02785       ss7_called_nai = p->ss7->called_nai;
02786       if (ss7_called_nai == SS7_NAI_DYNAMIC) { /* compute dynamically */
02787          if (strncmp(c + p->stripmsd, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
02788             called_nai_strip = strlen(p->ss7->internationalprefix);
02789             ss7_called_nai = SS7_NAI_INTERNATIONAL;
02790          } else if (strncmp(c + p->stripmsd, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
02791             called_nai_strip = strlen(p->ss7->nationalprefix);
02792             ss7_called_nai = SS7_NAI_NATIONAL;
02793          } else {
02794             ss7_called_nai = SS7_NAI_SUBSCRIBER;
02795          }
02796       }
02797       isup_set_called(p->ss7call, c + p->stripmsd + called_nai_strip, ss7_called_nai, p->ss7->ss7);
02798 
02799       calling_nai_strip = 0;
02800       ss7_calling_nai = p->ss7->calling_nai;
02801       if ((l != NULL) && (ss7_calling_nai == SS7_NAI_DYNAMIC)) { /* compute dynamically */
02802          if (strncmp(l, p->ss7->internationalprefix, strlen(p->ss7->internationalprefix)) == 0) {
02803             calling_nai_strip = strlen(p->ss7->internationalprefix);
02804             ss7_calling_nai = SS7_NAI_INTERNATIONAL;
02805          } else if (strncmp(l, p->ss7->nationalprefix, strlen(p->ss7->nationalprefix)) == 0) {
02806             calling_nai_strip = strlen(p->ss7->nationalprefix);
02807             ss7_calling_nai = SS7_NAI_NATIONAL;
02808          } else {
02809             ss7_calling_nai = SS7_NAI_SUBSCRIBER;
02810          }
02811       }
02812       isup_set_calling(p->ss7call, l ? (l + calling_nai_strip) : NULL, ss7_calling_nai,
02813          p->use_callingpres ? cid_pres2ss7pres(ast->cid.cid_pres) : (l ? SS7_PRESENTATION_ALLOWED : SS7_PRESENTATION_RESTRICTED),
02814          p->use_callingpres ? cid_pres2ss7screen(ast->cid.cid_pres) : SS7_SCREENING_USER_PROVIDED );
02815 
02816       isup_set_oli(p->ss7call, ast->cid.cid_ani2);
02817       isup_init_call(p->ss7->ss7, p->ss7call, p->cic, p->dpc);
02818 
02819       ast_channel_lock(ast);
02820       /* Set the charge number if it is set */
02821       charge_str = pbx_builtin_getvar_helper(ast, "SS7_CHARGE_NUMBER");
02822       if (charge_str)
02823          isup_set_charge(p->ss7call, charge_str, SS7_ANI_CALLING_PARTY_SUB_NUMBER, 0x10);
02824       
02825       gen_address = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_ADDRESS");
02826       if (gen_address)
02827          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 */
02828       
02829       gen_digits = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGITS");
02830       gen_dig_type = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGTYPE");
02831       gen_dig_scheme = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_DIGSCHEME");
02832       if (gen_digits)
02833          isup_set_gen_digits(p->ss7call, gen_digits, atoi(gen_dig_type), atoi(gen_dig_scheme)); 
02834       
02835       gen_name = pbx_builtin_getvar_helper(ast, "SS7_GENERIC_NAME");
02836       if (gen_name)
02837          isup_set_generic_name(p->ss7call, gen_name, GEN_NAME_TYPE_CALLING_NAME, GEN_NAME_AVAIL_AVAILABLE, GEN_NAME_PRES_ALLOWED);
02838 
02839       jip_digits = pbx_builtin_getvar_helper(ast, "SS7_JIP");
02840       if (jip_digits)
02841          isup_set_jip_digits(p->ss7call, jip_digits);
02842       
02843       lspi_ident = pbx_builtin_getvar_helper(ast, "SS7_LSPI_IDENT");
02844       if (lspi_ident)
02845          isup_set_lspi(p->ss7call, lspi_ident, 0x18, 0x7, 0x00); 
02846       
02847       rlt_flag = pbx_builtin_getvar_helper(ast, "SS7_RLT_ON");
02848       if ((rlt_flag) && ((strncmp("NO", rlt_flag, strlen(rlt_flag))) != 0 )) {
02849          isup_set_lspi(p->ss7call, rlt_flag, 0x18, 0x7, 0x00); /* Setting for Nortel DMS-250/500 */
02850       }
02851       
02852       call_ref_id = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_IDENT");
02853       call_ref_pc = pbx_builtin_getvar_helper(ast, "SS7_CALLREF_PC");
02854       if (call_ref_id && call_ref_pc) {
02855          isup_set_callref(p->ss7call, atoi(call_ref_id),
02856                 call_ref_pc ? atoi(call_ref_pc) : 0);
02857       }
02858       
02859       send_far = pbx_builtin_getvar_helper(ast, "SS7_SEND_FAR");
02860       if ((send_far) && ((strncmp("NO", send_far, strlen(send_far))) != 0 ))
02861          (isup_far(p->ss7->ss7, p->ss7call));
02862       
02863       ast_channel_unlock(ast);
02864 
02865       isup_iam(p->ss7->ss7, p->ss7call);
02866       ast_setstate(ast, AST_STATE_DIALING);
02867       ss7_rel(p->ss7);
02868    }
02869 #endif /* HAVE_SS7 */
02870 #ifdef HAVE_PRI
02871    if (p->pri) {
02872       struct pri_sr *sr;
02873 #ifdef SUPPORT_USERUSER
02874       const char *useruser;
02875 #endif
02876       int pridialplan;
02877       int dp_strip;
02878       int prilocaldialplan;
02879       int ldp_strip;
02880       int exclusive;
02881       const char *rr_str;
02882       int redirect_reason;
02883 
02884       c = strchr(dest, '/');
02885       if (c) {
02886          c++;
02887       } else {
02888          c = "";
02889       }
02890 
02891       l = NULL;
02892       n = NULL;
02893       if (!p->hidecallerid) {
02894          l = ast->cid.cid_num;
02895          if (!p->hidecalleridname) {
02896             n = ast->cid.cid_name;
02897          }
02898       }
02899 
02900       if (strlen(c) < p->stripmsd) {
02901          ast_log(LOG_WARNING, "Number '%s' is shorter than stripmsd (%d)\n", c, p->stripmsd);
02902          ast_mutex_unlock(&p->lock);
02903          return -1;
02904       }
02905       if (mysig != SIG_FXSKS) {
02906          p->dop.op = DAHDI_DIAL_OP_REPLACE;
02907          s = strchr(c + p->stripmsd, 'w');
02908          if (s) {
02909             if (strlen(s) > 1)
02910                snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "T%s", s);
02911             else
02912                p->dop.dialstr[0] = '\0';
02913             *s = '\0';
02914          } else {
02915             p->dop.dialstr[0] = '\0';
02916          }
02917       }
02918       if (pri_grab(p, p->pri)) {
02919          ast_log(LOG_WARNING, "Failed to grab PRI!\n");
02920          ast_mutex_unlock(&p->lock);
02921          return -1;
02922       }
02923       if (!(p->call = pri_new_call(p->pri->pri))) {
02924          ast_log(LOG_WARNING, "Unable to create call on channel %d\n", p->channel);
02925          pri_rel(p->pri);
02926          ast_mutex_unlock(&p->lock);
02927          return -1;
02928       }
02929       if (!(sr = pri_sr_new())) {
02930          ast_log(LOG_WARNING, "Failed to allocate setup request channel %d\n", p->channel);
02931          pri_rel(p->pri);
02932          ast_mutex_unlock(&p->lock);
02933       }
02934       if (p->bearer || (mysig == SIG_FXSKS)) {
02935          if (p->bearer) {
02936             ast_debug(1, "Oooh, I have a bearer on %d (%d:%d)\n", PVT_TO_CHANNEL(p->bearer), p->bearer->logicalspan, p->bearer->channel);
02937             p->bearer->call = p->call;
02938          } else
02939             ast_debug(1, "I'm being setup with no bearer right now...\n");
02940 
02941          pri_set_crv(p->pri->pri, p->call, p->channel, 0);
02942       }
02943       p->digital = IS_DIGITAL(ast->transfercapability);
02944 
02945       /* Should the picked channel be used exclusively? */
02946       if (p->priexclusive || p->pri->nodetype == PRI_NETWORK) {
02947          exclusive = 1;
02948       } else {
02949          exclusive = 0;
02950       }
02951       
02952       pri_sr_set_channel(sr, p->bearer ? PVT_TO_CHANNEL(p->bearer) : PVT_TO_CHANNEL(p), exclusive, 1);
02953       pri_sr_set_bearer(sr, p->digital ? PRI_TRANS_CAP_DIGITAL : ast->transfercapability, 
02954                (p->digital ? -1 : 
02955                   ((p->law == DAHDI_LAW_ALAW) ? PRI_LAYER_1_ALAW : PRI_LAYER_1_ULAW)));
02956       if (p->pri->facilityenable)
02957          pri_facility_enable(p->pri->pri);
02958 
02959       ast_verb(3, "Requested transfer capability: 0x%.2x - %s\n", ast->transfercapability, ast_transfercapability2str(ast->transfercapability));
02960       dp_strip = 0;
02961       pridialplan = p->pri->dialplan - 1;
02962       if (pridialplan == -2 || pridialplan == -3) { /* compute dynamically */
02963          if (strncmp(c + p->stripmsd, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
02964             if (pridialplan == -2) {
02965                dp_strip = strlen(p->pri->internationalprefix);
02966             }
02967             pridialplan = PRI_INTERNATIONAL_ISDN;
02968          } else if (strncmp(c + p->stripmsd, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
02969             if (pridialplan == -2) {
02970                dp_strip = strlen(p->pri->nationalprefix);
02971             }
02972             pridialplan = PRI_NATIONAL_ISDN;
02973          } else {
02974             pridialplan = PRI_LOCAL_ISDN;
02975          }
02976       }
02977       while (c[p->stripmsd] > '9' && c[p->stripmsd] != '*' && c[p->stripmsd] != '#') {
02978          switch (c[p->stripmsd]) {
02979          case 'U':
02980             pridialplan = (PRI_TON_UNKNOWN << 4) | (pridialplan & 0xf);
02981             break;
02982          case 'I':
02983             pridialplan = (PRI_TON_INTERNATIONAL << 4) | (pridialplan & 0xf);
02984             break;
02985          case 'N':
02986             pridialplan = (PRI_TON_NATIONAL << 4) | (pridialplan & 0xf);
02987             break;
02988          case 'L':
02989             pridialplan = (PRI_TON_NET_SPECIFIC << 4) | (pridialplan & 0xf);
02990             break;
02991          case 'S':
02992             pridialplan = (PRI_TON_SUBSCRIBER << 4) | (pridialplan & 0xf);
02993             break;
02994          case 'V':
02995             pridialplan = (PRI_TON_ABBREVIATED << 4) | (pridialplan & 0xf);
02996             break;
02997          case 'R':
02998             pridialplan = (PRI_TON_RESERVED << 4) | (pridialplan & 0xf);
02999             break;
03000          case 'u':
03001             pridialplan = PRI_NPI_UNKNOWN | (pridialplan & 0xf0);
03002             break;
03003          case 'e':
03004             pridialplan = PRI_NPI_E163_E164 | (pridialplan & 0xf0);
03005             break;
03006          case 'x':
03007             pridialplan = PRI_NPI_X121 | (pridialplan & 0xf0);
03008             break;
03009          case 'f':
03010             pridialplan = PRI_NPI_F69 | (pridialplan & 0xf0);
03011             break;
03012          case 'n':
03013             pridialplan = PRI_NPI_NATIONAL | (pridialplan & 0xf0);
03014             break;
03015          case 'p':
03016             pridialplan = PRI_NPI_PRIVATE | (pridialplan & 0xf0);
03017             break;
03018          case 'r':
03019             pridialplan = PRI_NPI_RESERVED | (pridialplan & 0xf0);
03020             break;
03021          default:
03022             if (isalpha(c[p->stripmsd])) {
03023                ast_log(LOG_WARNING, "Unrecognized pridialplan %s modifier: %c\n",
03024                   c[p->stripmsd] > 'Z' ? "NPI" : "TON", c[p->stripmsd]);
03025             }
03026             break;
03027          }
03028          c++;
03029       }
03030       pri_sr_set_called(sr, c + p->stripmsd + dp_strip, pridialplan, s ? 1 : 0);
03031 
03032       ldp_strip = 0;
03033       prilocaldialplan = p->pri->localdialplan - 1;
03034       if ((l != NULL) && (prilocaldialplan == -2 || prilocaldialplan == -3)) { /* compute dynamically */
03035          if (strncmp(l, p->pri->internationalprefix, strlen(p->pri->internationalprefix)) == 0) {
03036             if (prilocaldialplan == -2) {
03037                ldp_strip = strlen(p->pri->internationalprefix);
03038             }
03039             prilocaldialplan = PRI_INTERNATIONAL_ISDN;
03040          } else if (strncmp(l, p->pri->nationalprefix, strlen(p->pri->nationalprefix)) == 0) {
03041             if (prilocaldialplan == -2) {
03042                ldp_strip = strlen(p->pri->nationalprefix);
03043             }
03044             prilocaldialplan = PRI_NATIONAL_ISDN;
03045          } else {
03046             prilocaldialplan = PRI_LOCAL_ISDN;
03047          }
03048       }
03049       if (l != NULL) {
03050          while (*l > '9' && *l != '*' && *l != '#') {
03051             switch (*l) {
03052             case 'U':
03053                prilocaldialplan = (PRI_TON_UNKNOWN << 4) | (prilocaldialplan & 0xf);
03054                break;
03055             case 'I':
03056                prilocaldialplan = (PRI_TON_INTERNATIONAL << 4) | (prilocaldialplan & 0xf);
03057                break;
03058             case 'N':
03059                prilocaldialplan = (PRI_TON_NATIONAL << 4) | (prilocaldialplan & 0xf);
03060                break;
03061             case 'L':
03062                prilocaldialplan = (PRI_TON_NET_SPECIFIC << 4) | (prilocaldialplan & 0xf);
03063                break;
03064             case 'S':
03065                prilocaldialplan = (PRI_TON_SUBSCRIBER << 4) | (prilocaldialplan & 0xf);
03066                break;
03067             case 'V':
03068                prilocaldialplan = (PRI_TON_ABBREVIATED << 4) | (prilocaldialplan & 0xf);
03069                break;
03070             case 'R':
03071                prilocaldialplan = (PRI_TON_RESERVED << 4) | (prilocaldialplan & 0xf);
03072                break;
03073             case 'u':
03074                prilocaldialplan = PRI_NPI_UNKNOWN | (prilocaldialplan & 0xf0);
03075                break;
03076             case 'e':
03077                prilocaldialplan = PRI_NPI_E163_E164 | (prilocaldialplan & 0xf0);
03078                break;
03079             case 'x':
03080                prilocaldialplan = PRI_NPI_X121 | (prilocaldialplan & 0xf0);
03081                break;
03082             case 'f':
03083                prilocaldialplan = PRI_NPI_F69 | (prilocaldialplan & 0xf0);
03084                break;
03085             case 'n':
03086                prilocaldialplan = PRI_NPI_NATIONAL | (prilocaldialplan & 0xf0);
03087                break;
03088             case 'p':
03089                prilocaldialplan = PRI_NPI_PRIVATE | (prilocaldialplan & 0xf0);
03090                break;
03091             case 'r':
03092                prilocaldialplan = PRI_NPI_RESERVED | (prilocaldialplan & 0xf0);
03093                break;
03094             default:
03095                if (isalpha(*l)) {
03096                   ast_log(LOG_WARNING,
03097                      "Unrecognized prilocaldialplan %s modifier: %c\n",
03098                      *l > 'Z' ? "NPI" : "TON", *l);
03099                }
03100                break;
03101             }
03102             l++;
03103          }
03104       }
03105       pri_sr_set_caller(sr, l ? (l + ldp_strip) : NULL, n, prilocaldialplan,
03106          p->use_callingpres ? ast->cid.cid_pres : (l ? PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN : PRES_NUMBER_NOT_AVAILABLE));
03107       if ((rr_str = pbx_builtin_getvar_helper(ast, "PRIREDIRECTREASON"))) {
03108          if (!strcasecmp(rr_str, "UNKNOWN"))
03109             redirect_reason = 0;
03110          else if (!strcasecmp(rr_str, "BUSY"))
03111             redirect_reason = 1;
03112          else if (!strcasecmp(rr_str, "NO_REPLY") || !strcasecmp(rr_str, "NOANSWER"))
03113          /* the NOANSWER is to match diversion-reason from chan_sip, (which never reads PRIREDIRECTREASON) */
03114             redirect_reason = 2;
03115          else if (!strcasecmp(rr_str, "UNCONDITIONAL"))
03116             redirect_reason = 15;
03117          else
03118             redirect_reason = PRI_REDIR_UNCONDITIONAL;
03119       } else
03120          redirect_reason = PRI_REDIR_UNCONDITIONAL;
03121       pri_sr_set_redirecting(sr, ast->cid.cid_rdnis, p->pri->localdialplan - 1, PRES_ALLOWED_USER_NUMBER_PASSED_SCREEN, redirect_reason);
03122 
03123 #ifdef SUPPORT_USERUSER
03124       /* User-user info */
03125       useruser = pbx_builtin_getvar_helper(p->owner, "USERUSERINFO");
03126 
03127       if (useruser)
03128          pri_sr_set_useruser(sr, useruser);
03129 #endif
03130 
03131       if (pri_setup(p->pri->pri, p->call, sr)) {
03132          ast_log(LOG_WARNING, "Unable to setup call to %s (using %s)\n", 
03133             c + p->stripmsd + dp_strip, dialplan2str(p->pri->dialplan));
03134          pri_rel(p->pri);
03135          ast_mutex_unlock(&p->lock);
03136          pri_sr_free(sr);
03137          return -1;
03138       }
03139       pri_sr_free(sr);
03140       ast_setstate(ast, AST_STATE_DIALING);
03141       pri_rel(p->pri);
03142    }
03143 #endif      
03144    ast_mutex_unlock(&p->lock);
03145    return 0;
03146 }
03147 
03148 static void destroy_dahdi_pvt(struct dahdi_pvt **pvt)
03149 {
03150    struct dahdi_pvt *p = *pvt;
03151    /* Remove channel from the list */
03152    if (p->prev)
03153       p->prev->next = p->next;
03154    if (p->next)
03155       p->next->prev = p->prev;
03156    if (p->use_smdi)
03157       ast_smdi_interface_unref(p->smdi_iface);
03158    if (p->mwi_event_sub)
03159       ast_event_unsubscribe(p->mwi_event_sub);
03160    if (p->vars) {
03161       ast_variables_destroy(p->vars);
03162    }
03163    ast_mutex_destroy(&p->lock);
03164    dahdi_close_sub(p, SUB_REAL);
03165    if (p->owner)
03166       p->owner->tech_pvt = NULL;
03167    free(p);
03168    *pvt = NULL;
03169 }
03170 
03171 static int destroy_channel(struct dahdi_pvt *prev, struct dahdi_pvt *cur, int now)
03172 {
03173    int owned = 0;
03174    int i = 0;
03175 
03176    if (!now) {
03177       if (cur->owner) {
03178          owned = 1;
03179       }
03180 
03181       for (i = 0; i < 3; i++) {
03182          if (cur->subs[i].owner) {
03183             owned = 1;
03184          }
03185       }
03186       if (!owned) {
03187          if (prev) {
03188             prev->next = cur->next;
03189             if (prev->next)
03190                prev->next->prev = prev;
03191             else
03192                ifend = prev;
03193          } else {
03194             iflist = cur->next;
03195             if (iflist)
03196                iflist->prev = NULL;
03197             else
03198                ifend = NULL;
03199          }
03200          destroy_dahdi_pvt(&cur);
03201       }
03202    } else {
03203       if (prev) {
03204          prev->next = cur->next;
03205          if (prev->next)
03206             prev->next->prev = prev;
03207          else
03208             ifend = prev;
03209       } else {
03210          iflist = cur->next;
03211          if (iflist)
03212             iflist->prev = NULL;
03213          else
03214             ifend = NULL;
03215       }
03216       destroy_dahdi_pvt(&cur);
03217    }
03218    return 0;
03219 }
03220 
03221 static void destroy_all_channels(void)
03222 {
03223    int x;
03224    struct dahdi_pvt *p, *pl;
03225 
03226    while (num_restart_pending) {
03227       usleep(1);
03228    }
03229 
03230    ast_mutex_lock(&iflock);
03231    /* Destroy all the interfaces and free their memory */
03232    p = iflist;
03233    while (p) {
03234       /* Free any callerid */
03235       if (p->cidspill)
03236          ast_free(p->cidspill);
03237       pl = p;
03238       p = p->next;
03239       x = pl->channel;
03240       /* Free associated memory */
03241       if (pl)
03242          destroy_dahdi_pvt(&pl);
03243       if (option_verbose > 2) 
03244          ast_verbose(VERBOSE_PREFIX_2 "Unregistered channel %d\n", x);
03245    }
03246    iflist = NULL;
03247    ifcount = 0;
03248    ast_mutex_unlock(&iflock);
03249 }
03250 
03251 #ifdef HAVE_PRI
03252 static char *dahdi_send_keypad_facility_app = "DAHDISendKeypadFacility";
03253 
03254 static char *dahdi_send_keypad_facility_synopsis = "Send digits out of band over a PRI";
03255 
03256 static char *dahdi_send_keypad_facility_descrip = 
03257 "  DAHDISendKeypadFacility(): This application will send the given string of digits in a Keypad Facility\n"
03258 "  IE over the current channel.\n";
03259 
03260 static int dahdi_send_keypad_facility_exec(struct ast_channel *chan, void *data)
03261 {
03262    /* Data will be our digit string */
03263    struct dahdi_pvt *p;
03264    char *digits = (char *) data;
03265 
03266    if (ast_strlen_zero(digits)) {
03267       ast_debug(1, "No digit string sent to application!\n");
03268       return -1;
03269    }
03270 
03271    p = (struct dahdi_pvt *)chan->tech_pvt;
03272 
03273    if (!p) {
03274       ast_debug(1, "Unable to find technology private\n");
03275       return -1;
03276    }
03277 
03278    ast_mutex_lock(&p->lock);
03279 
03280    if (!p->pri || !p->call) {
03281       ast_debug(1, "Unable to find pri or call on channel!\n");
03282       ast_mutex_unlock(&p->lock);
03283       return -1;
03284    }
03285 
03286    if (!pri_grab(p, p->pri)) {
03287       pri_keypad_facility(p->pri->pri, p->call, digits);
03288       pri_rel(p->pri);
03289    } else {
03290       ast_debug(1, "Unable to grab pri to send keypad facility!\n");
03291       ast_mutex_unlock(&p->lock);
03292       return -1;
03293    }
03294 
03295    ast_mutex_unlock(&p->lock);
03296 
03297    return 0;
03298 }
03299 
03300 static int pri_is_up(struct dahdi_pri *pri)
03301 {
03302    int x;
03303    for (x = 0; x < NUM_DCHANS; x++) {
03304       if (pri->dchanavail[x] == DCHAN_AVAILABLE)
03305          return 1;
03306    }
03307    return 0;
03308 }
03309 
03310 static int pri_assign_bearer(struct dahdi_pvt *crv, struct dahdi_pri *pri, struct dahdi_pvt *bearer)
03311 {
03312    bearer->owner = &inuse;
03313    bearer->realcall = crv;
03314    crv->subs[SUB_REAL].dfd = bearer->subs[SUB_REAL].dfd;
03315    if (crv->subs[SUB_REAL].owner)
03316       ast_channel_set_fd(crv->subs[SUB_REAL].owner, 0, crv->subs[SUB_REAL].dfd);
03317    crv->bearer = bearer;
03318    crv->call = bearer->call;
03319    crv->pri = pri;
03320    return 0;
03321 }
03322 
03323 static char *pri_order(int level)
03324 {
03325    switch (level) {
03326    case 0:
03327       return "Primary";
03328    case 1:
03329       return "Secondary";
03330    case 2:
03331       return "Tertiary";
03332    case 3:
03333       return "Quaternary";
03334    default:
03335       return "<Unknown>";
03336    }     
03337 }
03338 
03339 /* Returns fd of the active dchan */
03340 static int pri_active_dchan_fd(struct dahdi_pri *pri)
03341 {
03342    int x = -1;
03343 
03344    for (x = 0; x < NUM_DCHANS; x++) {
03345       if ((pri->dchans[x] == pri->pri))
03346          break;
03347    }
03348 
03349    return pri->fds[x];
03350 }
03351 
03352 static int pri_find_dchan(struct dahdi_pri *pri)
03353 {
03354    int oldslot = -1;
03355    struct pri *old;
03356    int newslot = -1;
03357    int x;
03358    old = pri->pri;
03359    for (x = 0; x < NUM_DCHANS; x++) {
03360       if ((pri->dchanavail[x] == DCHAN_AVAILABLE) && (newslot < 0))
03361          newslot = x;
03362       if (pri->dchans[x] == old) {
03363          oldslot = x;
03364       }
03365    }
03366    if (newslot < 0) {
03367       newslot = 0;
03368       ast_log(LOG_WARNING, "No D-channels available!  Using Primary channel %d as D-channel anyway!\n",
03369          pri->dchannels[newslot]);
03370    }
03371    if (old && (oldslot != newslot))
03372       ast_log(LOG_NOTICE, "Switching from from d-channel %d to channel %d!\n",
03373          pri->dchannels[oldslot], pri->dchannels[newslot]);
03374    pri->pri = pri->dchans[newslot];
03375    return 0;
03376 }
03377 #endif
03378 
03379 static int dahdi_hangup(struct ast_channel *ast)
03380 {
03381    int res;
03382    int idx,x, law;
03383    /*static int restore_gains(struct dahdi_pvt *p);*/
03384    struct dahdi_pvt *p = ast->tech_pvt;
03385    struct dahdi_pvt *tmp = NULL;
03386    struct dahdi_pvt *prev = NULL;
03387    struct dahdi_params par;
03388 
03389    ast_debug(1, "dahdi_hangup(%s)\n", ast->name);
03390    if (!ast->tech_pvt) {
03391       ast_log(LOG_WARNING, "Asked to hangup channel not connected\n");
03392       return 0;
03393    }
03394    
03395    ast_mutex_lock(&p->lock);
03396    
03397    idx = dahdi_get_index(ast, p, 1);
03398 
03399    if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
03400       x = 1;
03401       ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
03402       p->cid_num[0] = '\0';
03403       p->cid_name[0] = '\0';
03404    }
03405 
03406    x = 0;
03407    dahdi_confmute(p, 0);
03408    p->muting = 0;
03409    restore_gains(p);
03410    if (p->origcid_num) {
03411       ast_copy_string(p->cid_num, p->origcid_num, sizeof(p->cid_num));
03412       ast_free(p->origcid_num);
03413       p->origcid_num = NULL;
03414    }  
03415    if (p->origcid_name) {
03416       ast_copy_string(p->cid_name, p->origcid_name, sizeof(p->cid_name));
03417       ast_free(p->origcid_name);
03418       p->origcid_name = NULL;
03419    }  
03420    if (p->dsp)
03421       ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
03422    p->exten[0] = '\0';
03423 
03424    ast_debug(1, "Hangup: channel: %d index = %d, normal = %d, callwait = %d, thirdcall = %d\n",
03425       p->channel, idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
03426    p->ignoredtmf = 0;
03427    
03428    if (idx > -1) {
03429       /* Real channel, do some fixup */
03430       p->subs[idx].owner = NULL;
03431       p->subs[idx].needanswer = 0;
03432       p->subs[idx].needflash = 0;
03433       p->subs[idx].needringing = 0;
03434       p->subs[idx].needbusy = 0;
03435       p->subs[idx].needcongestion = 0;
03436       p->subs[idx].linear = 0;
03437       p->subs[idx].needcallerid = 0;
03438       p->polarity = POLARITY_IDLE;
03439       dahdi_setlinear(p->subs[idx].dfd, 0);
03440       if (idx == SUB_REAL) {
03441          if ((p->subs[SUB_CALLWAIT].dfd > -1) && (p->subs[SUB_THREEWAY].dfd > -1)) {
03442             ast_debug(1, "Normal call hung up with both three way call and a call waiting call in place?\n");
03443             if (p->subs[SUB_CALLWAIT].inthreeway) {
03444                /* We had flipped over to answer a callwait and now it's gone */
03445                ast_debug(1, "We were flipped over to the callwait, moving back and unowning.\n");
03446                /* Move to the call-wait, but un-own us until they flip back. */
03447                swap_subs(p, SUB_CALLWAIT, SUB_REAL);
03448                unalloc_sub(p, SUB_CALLWAIT);
03449                p->owner = NULL;
03450             } else {
03451                /* The three way hung up, but we still have a call wait */
03452                ast_debug(1, "We were in the threeway and have a callwait still.  Ditching the threeway.\n");
03453                swap_subs(p, SUB_THREEWAY, SUB_REAL);
03454                unalloc_sub(p, SUB_THREEWAY);
03455                if (p->subs[SUB_REAL].inthreeway) {
03456                   /* This was part of a three way call.  Immediately make way for
03457                      another call */
03458                   ast_debug(1, "Call was complete, setting owner to former third call\n");
03459                   p->owner = p->subs[SUB_REAL].owner;
03460                } else {
03461                   /* This call hasn't been completed yet...  Set owner to NULL */
03462                   ast_debug(1, "Call was incomplete, setting owner to NULL\n");
03463                   p->owner = NULL;
03464                }
03465                p->subs[SUB_REAL].inthreeway = 0;
03466             }
03467          } else if (p->subs[SUB_CALLWAIT].dfd > -1) {
03468             /* Move to the call-wait and switch back to them. */
03469             swap_subs(p, SUB_CALLWAIT, SUB_REAL);
03470             unalloc_sub(p, SUB_CALLWAIT);
03471             p->owner = p->subs[SUB_REAL].owner;
03472             if (p->owner->_state != AST_STATE_UP)
03473                p->subs[SUB_REAL].needanswer = 1;
03474             if (ast_bridged_channel(p->subs[SUB_REAL].owner))
03475                ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
03476          } else if (p->subs[SUB_THREEWAY].dfd > -1) {
03477             swap_subs(p, SUB_THREEWAY, SUB_REAL);
03478             unalloc_sub(p, SUB_THREEWAY);
03479             if (p->subs[SUB_REAL].inthreeway) {
03480                /* This was part of a three way call.  Immediately make way for
03481                   another call */
03482                ast_debug(1, "Call was complete, setting owner to former third call\n");
03483                p->owner = p->subs[SUB_REAL].owner;
03484             } else {
03485                /* This call hasn't been completed yet...  Set owner to NULL */
03486                ast_debug(1, "Call was incomplete, setting owner to NULL\n");
03487                p->owner = NULL;
03488             }
03489             p->subs[SUB_REAL].inthreeway = 0;
03490          }
03491       } else if (idx == SUB_CALLWAIT) {
03492          /* Ditch the holding callwait call, and immediately make it availabe */
03493          if (p->subs[SUB_CALLWAIT].inthreeway) {
03494             /* This is actually part of a three way, placed on hold.  Place the third part
03495                on music on hold now */
03496             if (p->subs[SUB_THREEWAY].owner && ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
03497                ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD, 
03498                   S_OR(p->mohsuggest, NULL),
03499                   !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
03500             }
03501             p->subs[SUB_THREEWAY].inthreeway = 0;
03502             /* Make it the call wait now */
03503             swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
03504             unalloc_sub(p, SUB_THREEWAY);
03505          } else
03506             unalloc_sub(p, SUB_CALLWAIT);
03507       } else if (idx == SUB_THREEWAY) {
03508          if (p->subs[SUB_CALLWAIT].inthreeway) {
03509             /* The other party of the three way call is currently in a call-wait state.
03510                Start music on hold for them, and take the main guy out of the third call */
03511             if (p->subs[SUB_CALLWAIT].owner && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
03512                ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD, 
03513                   S_OR(p->mohsuggest, NULL),
03514                   !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
03515             }
03516             p->subs[SUB_CALLWAIT].inthreeway = 0;
03517          }
03518          p->subs[SUB_REAL].inthreeway = 0;
03519          /* If this was part of a three way call index, let us make
03520             another three way call */
03521          unalloc_sub(p, SUB_THREEWAY);
03522       } else {
03523          /* This wasn't any sort of call, but how are we an index? */
03524          ast_log(LOG_WARNING, "Index found but not any type of call?\n");
03525       }
03526    }
03527 
03528    if (!p->subs[SUB_REAL].owner && !p->subs[SUB_CALLWAIT].owner && !p->subs[SUB_THREEWAY].owner) {
03529       p->owner = NULL;
03530       p->ringt = 0;
03531       p->distinctivering = 0;
03532       p->confirmanswer = 0;
03533       p->cidrings = 1;
03534       p->outgoing = 0;
03535       p->digital = 0;
03536       p->faxhandled = 0;
03537       p->pulsedial = 0;
03538       p->onhooktime = time(NULL);
03539 #if defined(HAVE_PRI) || defined(HAVE_SS7)
03540       p->proceeding = 0;
03541       p->dialing = 0;
03542       p->progress = 0;
03543       p->alerting = 0;
03544       p->setup_ack = 0;
03545       p->rlt = 0;
03546 #endif      
03547       if (p->dsp) {
03548          ast_dsp_free(p->dsp);
03549          p->dsp = NULL;
03550       }
03551 
03552       law = DAHDI_LAW_DEFAULT;
03553       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETLAW, &law);
03554       if (res < 0) 
03555          ast_log(LOG_WARNING, "Unable to set law on channel %d to default: %s\n", p->channel, strerror(errno));
03556       /* Perform low level hangup if no owner left */
03557 #ifdef HAVE_SS7
03558       if (p->ss7) {
03559          if (p->ss7call) {
03560             if (!ss7_grab(p, p->ss7)) {
03561                if (!p->alreadyhungup) {
03562                   const char *cause = pbx_builtin_getvar_helper(ast,"SS7_CAUSE");
03563                   int icause = ast->hangupcause ? ast->hangupcause : -1;
03564 
03565                   if (cause) {
03566                      if (atoi(cause))
03567                         icause = atoi(cause);
03568                   }
03569                   isup_rel(p->ss7->ss7, p->ss7call, icause);
03570                   ss7_rel(p->ss7);
03571                   p->alreadyhungup = 1;
03572                } else
03573                   ast_log(LOG_WARNING, "Trying to hangup twice!\n");
03574             } else {
03575                ast_log(LOG_WARNING, "Unable to grab SS7 on CIC %d\n", p->cic);
03576                res = -1;
03577             }
03578          }
03579       }
03580 #endif
03581 #ifdef HAVE_PRI
03582       if (p->pri) {
03583 #ifdef SUPPORT_USERUSER
03584          const char *useruser = pbx_builtin_getvar_helper(ast,"USERUSERINFO");
03585 #endif
03586 
03587          /* Make sure we have a call (or REALLY have a call in the case of a PRI) */
03588          if (p->call && (!p->bearer || (p->bearer->call == p->call))) {
03589             if (!pri_grab(p, p->pri)) {
03590                if (p->alreadyhungup) {
03591                   ast_debug(1, "Already hungup...  Calling hangup once, and clearing call\n");
03592 
03593 #ifdef SUPPORT_USERUSER
03594                   pri_call_set_useruser(p->call, useruser);
03595 #endif
03596 
03597                   pri_hangup(p->pri->pri, p->call, -1);
03598                   p->call = NULL;
03599                   if (p->bearer) 
03600                      p->bearer->call = NULL;
03601                } else {
03602                   const char *cause = pbx_builtin_getvar_helper(ast,"PRI_CAUSE");
03603                   int icause = ast->hangupcause ? ast->hangupcause : -1;
03604                   ast_debug(1, "Not yet hungup...  Calling hangup once with icause, and clearing call\n");
03605 
03606 #ifdef SUPPORT_USERUSER
03607                   pri_call_set_useruser(p->call, useruser);
03608 #endif
03609 
03610                   p->alreadyhungup = 1;
03611                   if (p->bearer)
03612                      p->bearer->alreadyhungup = 1;
03613                   if (cause) {
03614                      if (atoi(cause))
03615                         icause = atoi(cause);
03616                   }
03617                   pri_hangup(p->pri->pri, p->call, icause);
03618                }
03619                if (res < 0) 
03620                   ast_log(LOG_WARNING, "pri_disconnect failed\n");
03621                pri_rel(p->pri);        
03622             } else {
03623                ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
03624                res = -1;
03625             }
03626          } else {
03627             if (p->bearer)
03628                ast_debug(1, "Bearer call is %p, while ours is still %p\n", p->bearer->call, p->call);
03629             p->call = NULL;
03630             res = 0;
03631          }
03632       }
03633 #endif
03634       if (p->sig && ((p->sig != SIG_PRI) && (p->sig != SIG_SS7) && (p->sig != SIG_BRI) && (p->sig != SIG_BRI_PTMP)))
03635          res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
03636       if (res < 0) {
03637          ast_log(LOG_WARNING, "Unable to hangup line %s\n", ast->name);
03638       }
03639       switch (p->sig) {
03640       case SIG_FXOGS:
03641       case SIG_FXOLS:
03642       case SIG_FXOKS:
03643          memset(&par, 0, sizeof(par));
03644          res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
03645          if (!res) {
03646 #if 0
03647             ast_debug(1, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
03648 #endif
03649             /* If they're off hook, try playing congestion */
03650             if ((par.rxisoffhook) && (!(p->radio || (p->oprmode < 0))))
03651                tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
03652             else
03653                tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
03654          }
03655          break;
03656       case SIG_FXSGS:
03657       case SIG_FXSLS:
03658       case SIG_FXSKS:
03659          /* Make sure we're not made available for at least two seconds assuming
03660             we were actually used for an inbound or outbound call. */
03661          if (ast->_state != AST_STATE_RESERVED) {
03662             time(&p->guardtime);
03663             p->guardtime += 2;
03664          }
03665          break;
03666       default:
03667          tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
03668       }
03669       if (p->cidspill)
03670          ast_free(p->cidspill);
03671       if (p->sig)
03672          dahdi_disable_ec(p);
03673       x = 0;
03674       ast_channel_setoption(ast,AST_OPTION_TONE_VERIFY,&x,sizeof(char),0);
03675       ast_channel_setoption(ast,AST_OPTION_TDD,&x,sizeof(char),0);
03676       p->didtdd = 0;
03677       p->cidspill = NULL;
03678       p->callwaitcas = 0;
03679       p->callwaiting = p->permcallwaiting;
03680       p->hidecallerid = p->permhidecallerid;
03681       p->dialing = 0;
03682       p->rdnis[0] = '\0';
03683       update_conf(p);
03684       reset_conf(p);
03685       /* Restore data mode */
03686       if ((p->sig == SIG_PRI) || (p->sig == SIG_SS7) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
03687          x = 0;
03688          ast_channel_setoption(ast,AST_OPTION_AUDIO_MODE,&x,sizeof(char),0);
03689       }
03690 #ifdef HAVE_PRI
03691       if (p->bearer) {
03692          ast_debug(1, "Freeing up bearer channel %d\n", p->bearer->channel);
03693          /* Free up the bearer channel as well, and
03694             don't use its file descriptor anymore */
03695          update_conf(p->bearer);
03696          reset_conf(p->bearer);
03697          p->bearer->owner = NULL;
03698          p->bearer->realcall = NULL;
03699          p->bearer = NULL;
03700          p->subs[SUB_REAL].dfd = -1;
03701          p->pri = NULL;
03702       }
03703 #endif
03704       if (num_restart_pending == 0)
03705          restart_monitor();
03706    }
03707 
03708    p->callwaitingrepeat = 0;
03709    p->cidcwexpire = 0;
03710    p->oprmode = 0;
03711    ast->tech_pvt = NULL;
03712    ast_mutex_unlock(&p->lock);
03713    ast_module_unref(ast_module_info->self);
03714    ast_verb(3, "Hungup '%s'\n", ast->name);
03715 
03716    ast_mutex_lock(&iflock);
03717 
03718    if (p->restartpending) {
03719       num_restart_pending--;
03720    }
03721 
03722    tmp = iflist;
03723    prev = NULL;
03724    if (p->destroy) {
03725       while (tmp) {
03726          if (tmp == p) {
03727             destroy_channel(prev, tmp, 0);
03728             break;
03729          } else {
03730             prev = tmp;
03731             tmp = tmp->next;
03732          }
03733       }
03734    }
03735    ast_mutex_unlock(&iflock);
03736    return 0;
03737 }
03738 
03739 static int dahdi_answer(struct ast_channel *ast)
03740 {
03741    struct dahdi_pvt *p = ast->tech_pvt;
03742    int res = 0;
03743    int idx;
03744    int oldstate = ast->_state;
03745    ast_setstate(ast, AST_STATE_UP);
03746    ast_mutex_lock(&p->lock);
03747    idx = dahdi_get_index(ast, p, 0);
03748    if (idx < 0)
03749       idx = SUB_REAL;
03750    /* nothing to do if a radio channel */
03751    if ((p->radio || (p->oprmode < 0))) {
03752       ast_mutex_unlock(&p->lock);
03753       return 0;
03754    }
03755    switch (p->sig) {
03756    case SIG_FXSLS:
03757    case SIG_FXSGS:
03758    case SIG_FXSKS:
03759       p->ringt = 0;
03760       /* Fall through */
03761    case SIG_EM:
03762    case SIG_EM_E1:
03763    case SIG_EMWINK:
03764    case SIG_FEATD:
03765    case SIG_FEATDMF:
03766    case SIG_FEATDMF_TA:
03767    case SIG_E911:
03768    case SIG_FGC_CAMA:
03769    case SIG_FGC_CAMAMF:
03770    case SIG_FEATB:
03771    case SIG_SF:
03772    case SIG_SFWINK:
03773    case SIG_SF_FEATD:
03774    case SIG_SF_FEATDMF:
03775    case SIG_SF_FEATB:
03776    case SIG_FXOLS:
03777    case SIG_FXOGS:
03778    case SIG_FXOKS:
03779       /* Pick up the line */
03780       ast_debug(1, "Took %s off hook\n", ast->name);
03781       if (p->hanguponpolarityswitch) {
03782          p->polaritydelaytv = ast_tvnow();
03783       }
03784       res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
03785       tone_zone_play_tone(p->subs[idx].dfd, -1);
03786       p->dialing = 0;
03787       if ((idx == SUB_REAL) && p->subs[SUB_THREEWAY].inthreeway) {
03788          if (oldstate == AST_STATE_RINGING) {
03789             ast_debug(1, "Finally swapping real and threeway\n");
03790             tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, -1);
03791             swap_subs(p, SUB_THREEWAY, SUB_REAL);
03792             p->owner = p->subs[SUB_REAL].owner;
03793          }
03794       }
03795       if (p->sig & __DAHDI_SIG_FXS) {
03796          dahdi_enable_ec(p);
03797          dahdi_train_ec(p);
03798       }
03799       break;
03800 #ifdef HAVE_PRI
03801    case SIG_BRI:
03802    case SIG_BRI_PTMP:
03803    case SIG_PRI:
03804       /* Send a pri acknowledge */
03805       if (!pri_grab(p, p->pri)) {
03806          p->proceeding = 1;
03807          p->dialing = 0;
03808          res = pri_answer(p->pri->pri, p->call, 0, !p->digital);
03809          pri_rel(p->pri);
03810       } else {
03811          ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
03812          res = -1;
03813       }
03814       break;
03815 #endif
03816 #ifdef HAVE_SS7
03817    case SIG_SS7:
03818       if (!ss7_grab(p, p->ss7)) {
03819          p->proceeding = 1;
03820          res = isup_anm(p->ss7->ss7, p->ss7call);
03821          ss7_rel(p->ss7);
03822       } else {
03823          ast_log(LOG_WARNING, "Unable to grab SS7 on span %d\n", p->span);
03824          res = -1;
03825       }
03826       break;
03827 #endif
03828    case 0:
03829       ast_mutex_unlock(&p->lock);
03830       return 0;
03831    default:
03832       ast_log(LOG_WARNING, "Don't know how to answer signalling %d (channel %d)\n", p->sig, p->channel);
03833       res = -1;
03834    }
03835    ast_mutex_unlock(&p->lock);
03836    return res;
03837 }
03838 
03839 static int dahdi_setoption(struct ast_channel *chan, int option, void *data, int datalen)
03840 {
03841    char *cp;
03842    signed char *scp;
03843    int x;
03844    int idx;
03845    struct dahdi_pvt *p = chan->tech_pvt, *pp;
03846    struct oprmode *oprmode;
03847    
03848 
03849    /* all supported options require data */
03850    if (!data || (datalen < 1)) {
03851       errno = EINVAL;
03852       return -1;
03853    }
03854 
03855    switch (option) {
03856    case AST_OPTION_TXGAIN:
03857       scp = (signed char *) data;
03858       idx = dahdi_get_index(chan, p, 0);
03859       if (idx < 0) {
03860          ast_log(LOG_WARNING, "No index in TXGAIN?\n");
03861          return -1;
03862       }
03863       ast_debug(1, "Setting actual tx gain on %s to %f\n", chan->name, p->txgain + (float) *scp);
03864       return set_actual_txgain(p->subs[idx].dfd, 0, p->txgain + (float) *scp, p->law);
03865    case AST_OPTION_RXGAIN:
03866       scp = (signed char *) data;
03867       idx = dahdi_get_index(chan, p, 0);
03868       if (idx < 0) {
03869          ast_log(LOG_WARNING, "No index in RXGAIN?\n");
03870          return -1;
03871       }
03872       ast_debug(1, "Setting actual rx gain on %s to %f\n", chan->name, p->rxgain + (float) *scp);
03873       return set_actual_rxgain(p->subs[idx].dfd, 0, p->rxgain + (float) *scp, p->law);
03874    case AST_OPTION_TONE_VERIFY:
03875       if (!p->dsp)
03876          break;
03877       cp = (char *) data;
03878       switch (*cp) {
03879       case 1:
03880          ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF(1) on %s\n",chan->name);
03881          ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | p->dtmfrelax);  /* set mute mode if desired */
03882          break;
03883       case 2:
03884          ast_debug(1, "Set option TONE VERIFY, mode: MUTECONF/MAX(2) on %s\n",chan->name);
03885          ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MUTECONF | DSP_DIGITMODE_MUTEMAX | p->dtmfrelax);  /* set mute mode if desired */
03886          break;
03887       default:
03888          ast_debug(1, "Set option TONE VERIFY, mode: OFF(0) on %s\n",chan->name);
03889          ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);  /* set mute mode if desired */
03890          break;
03891       }
03892       break;
03893    case AST_OPTION_TDD:
03894       /* turn on or off TDD */
03895       cp = (char *) data;
03896       p->mate = 0;
03897       if (!*cp) { /* turn it off */
03898          ast_debug(1, "Set option TDD MODE, value: OFF(0) on %s\n",chan->name);
03899          if (p->tdd)
03900             tdd_free(p->tdd);
03901          p->tdd = 0;
03902          break;
03903       }
03904       ast_debug(1, "Set option TDD MODE, value: %s(%d) on %s\n",
03905          (*cp == 2) ? "MATE" : "ON", (int) *cp, chan->name);
03906       dahdi_disable_ec(p);
03907       /* otherwise, turn it on */
03908       if (!p->didtdd) { /* if havent done it yet */
03909          unsigned char mybuf[41000];/*! \todo XXX This is an abuse of the stack!! */
03910          unsigned char *buf;
03911          int size, res, fd, len;
03912          struct pollfd fds[1];
03913 
03914          buf = mybuf;
03915          memset(buf, 0x7f, sizeof(mybuf)); /* set to silence */
03916          ast_tdd_gen_ecdisa(buf + 16000, 16000);  /* put in tone */
03917          len = 40000;
03918          idx = dahdi_get_index(chan, p, 0);
03919          if (idx < 0) {
03920             ast_log(LOG_WARNING, "No index in TDD?\n");
03921             return -1;
03922          }
03923          fd = p->subs[idx].dfd;
03924          while (len) {
03925             if (ast_check_hangup(chan))
03926                return -1;
03927             size = len;
03928             if (size > READ_SIZE)
03929                size = READ_SIZE;
03930             fds[0].fd = fd;
03931             fds[0].events = POLLPRI | POLLOUT;
03932             fds[0].revents = 0;
03933             res = poll(fds, 1, -1);
03934             if (!res) {
03935                ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
03936                continue;
03937             }
03938             /* if got exception */
03939             if (fds[0].revents & POLLPRI)
03940                return -1;
03941             if (!(fds[0].revents & POLLOUT)) {
03942                ast_debug(1, "write fd not ready on channel %d\n", p->channel);
03943                continue;
03944             }
03945             res = write(fd, buf, size);
03946             if (res != size) {
03947                if (res == -1) return -1;
03948                ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
03949                break;
03950             }
03951             len -= size;
03952             buf += size;
03953          }
03954          p->didtdd = 1; /* set to have done it now */    
03955       }
03956       if (*cp == 2) { /* Mate mode */
03957          if (p->tdd)
03958             tdd_free(p->tdd);
03959          p->tdd = 0;
03960          p->mate = 1;
03961          break;
03962       }     
03963       if (!p->tdd) { /* if we dont have one yet */
03964          p->tdd = tdd_new(); /* allocate one */
03965       }     
03966       break;
03967    case AST_OPTION_RELAXDTMF:  /* Relax DTMF decoding (or not) */
03968       if (!p->dsp)
03969          break;
03970       cp = (char *) data;
03971       ast_debug(1, "Set option RELAX DTMF, value: %s(%d) on %s\n",
03972          *cp ? "ON" : "OFF", (int) *cp, chan->name);
03973       ast_dsp_set_digitmode(p->dsp, ((*cp) ? DSP_DIGITMODE_RELAXDTMF : DSP_DIGITMODE_DTMF) | p->dtmfrelax);
03974       break;
03975    case AST_OPTION_AUDIO_MODE:  /* Set AUDIO mode (or not) */
03976       cp = (char *) data;
03977       if (!*cp) {    
03978          ast_debug(1, "Set option AUDIO MODE, value: OFF(0) on %s\n", chan->name);
03979          x = 0;
03980          dahdi_disable_ec(p);
03981       } else {    
03982          ast_debug(1, "Set option AUDIO MODE, value: ON(1) on %s\n", chan->name);
03983          x = 1;
03984       }
03985       if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &x) == -1)
03986          ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, x, strerror(errno));
03987       break;
03988    case AST_OPTION_OPRMODE:  /* Operator services mode */
03989       oprmode = (struct oprmode *) data;
03990       pp = oprmode->peer->tech_pvt;
03991       p->oprmode = pp->oprmode = 0;
03992       /* setup peers */
03993       p->oprpeer = pp;
03994       pp->oprpeer = p;
03995       /* setup modes, if any */
03996       if (oprmode->mode) 
03997       {
03998          pp->oprmode = oprmode->mode;
03999          p->oprmode = -oprmode->mode;
04000       }
04001       ast_debug(1, "Set Operator Services mode, value: %d on %s/%s\n",
04002          oprmode->mode, chan->name,oprmode->peer->name);
04003       break;
04004    case AST_OPTION_ECHOCAN:
04005       cp = (char *) data;
04006       if (*cp) {
04007          ast_debug(1, "Enabling echo cancelation on %s\n", chan->name);
04008          dahdi_enable_ec(p);
04009       } else {
04010          ast_debug(1, "Disabling echo cancelation on %s\n", chan->name);
04011          dahdi_disable_ec(p);
04012       }
04013       break;
04014    }
04015    errno = 0;
04016 
04017    return 0;
04018 }
04019 
04020 static int dahdi_func_read(struct ast_channel *chan, const char *function, char *data, char *buf, size_t len)
04021 {
04022    struct dahdi_pvt *p = chan->tech_pvt;
04023    
04024    if (!strcasecmp(data, "rxgain")) {
04025       ast_mutex_lock(&p->lock);
04026       snprintf(buf, len, "%f", p->rxgain);
04027       ast_mutex_unlock(&p->lock);   
04028    } else if (!strcasecmp(data, "txgain")) {
04029       ast_mutex_lock(&p->lock);
04030       snprintf(buf, len, "%f", p->txgain);
04031       ast_mutex_unlock(&p->lock);   
04032    } else {
04033       ast_copy_string(buf, "", len);
04034    }
04035    return 0;
04036 }
04037 
04038 
04039 static void dahdi_unlink(struct dahdi_pvt *slave, struct dahdi_pvt *master, int needlock)
04040 {
04041    /* Unlink a specific slave or all slaves/masters from a given master */
04042    int x;
04043    int hasslaves;
04044    if (!master)
04045       return;
04046    if (needlock) {
04047       ast_mutex_lock(&master->lock);
04048       if (slave) {
04049          while (ast_mutex_trylock(&slave->lock)) {
04050             DEADLOCK_AVOIDANCE(&master->lock);
04051          }
04052       }
04053    }
04054    hasslaves = 0;
04055    for (x = 0; x < MAX_SLAVES; x++) {
04056       if (master->slaves[x]) {
04057          if (!slave || (master->slaves[x] == slave)) {
04058             /* Take slave out of the conference */
04059             ast_debug(1, "Unlinking slave %d from %d\n", master->slaves[x]->channel, master->channel);
04060             conf_del(master, &master->slaves[x]->subs[SUB_REAL], SUB_REAL);
04061             conf_del(master->slaves[x], &master->subs[SUB_REAL], SUB_REAL);
04062             master->slaves[x]->master = NULL;
04063             master->slaves[x] = NULL;
04064          } else
04065             hasslaves = 1;
04066       }
04067       if (!hasslaves)
04068          master->inconference = 0;
04069    }
04070    if (!slave) {
04071       if (master->master) {
04072          /* Take master out of the conference */
04073          conf_del(master->master, &master->subs[SUB_REAL], SUB_REAL);
04074          conf_del(master, &master->master->subs[SUB_REAL], SUB_REAL);
04075          hasslaves = 0;
04076          for (x = 0; x < MAX_SLAVES; x++) {
04077             if (master->master->slaves[x] == master)
04078                master->master->slaves[x] = NULL;
04079             else if (master->master->slaves[x])
04080                hasslaves = 1;
04081          }
04082          if (!hasslaves)
04083             master->master->inconference = 0;
04084       }
04085       master->master = NULL;
04086    }
04087    update_conf(master);
04088    if (needlock) {
04089       if (slave)
04090          ast_mutex_unlock(&slave->lock);
04091       ast_mutex_unlock(&master->lock);
04092    }
04093 }
04094 
04095 static void dahdi_link(struct dahdi_pvt *slave, struct dahdi_pvt *master) {
04096    int x;
04097    if (!slave || !master) {
04098       ast_log(LOG_WARNING, "Tried to link to/from NULL??\n");
04099       return;
04100    }
04101    for (x = 0; x < MAX_SLAVES; x++) {
04102       if (!master->slaves[x]) {
04103          master->slaves[x] = slave;
04104          break;
04105       }
04106    }
04107    if (x >= MAX_SLAVES) {
04108       ast_log(LOG_WARNING, "Replacing slave %d with new slave, %d\n", master->slaves[MAX_SLAVES - 1]->channel, slave->channel);
04109       master->slaves[MAX_SLAVES - 1] = slave;
04110    }
04111    if (slave->master) 
04112       ast_log(LOG_WARNING, "Replacing master %d with new master, %d\n", slave->master->channel, master->channel);
04113    slave->master = master;
04114    
04115    ast_debug(1, "Making %d slave to master %d at %d\n", slave->channel, master->channel, x);
04116 }
04117 
04118 static void disable_dtmf_detect(struct dahdi_pvt *p)
04119 {
04120    int val;
04121 
04122    p->ignoredtmf = 1;
04123 
04124    val = 0;
04125    ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
04126 
04127    if (!p->hardwaredtmf && p->dsp) {
04128       p->dsp_features &= ~DSP_FEATURE_DIGIT_DETECT;
04129       ast_dsp_set_features(p->dsp, p->dsp_features);
04130    }
04131 }
04132 
04133 static void enable_dtmf_detect(struct dahdi_pvt *p)
04134 {
04135    int val;
04136 
04137    if (p->channel == CHAN_PSEUDO)
04138       return;
04139 
04140    p->ignoredtmf = 0;
04141 
04142    val = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
04143    ioctl(p->subs[SUB_REAL].dfd, DAHDI_TONEDETECT, &val);
04144 
04145    if (!p->hardwaredtmf && p->dsp) {
04146       p->dsp_features |= DSP_FEATURE_DIGIT_DETECT;
04147       ast_dsp_set_features(p->dsp, p->dsp_features);
04148    }
04149 }
04150 
04151 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)
04152 {
04153    struct ast_channel *who;
04154    struct dahdi_pvt *p0, *p1, *op0, *op1;
04155    struct dahdi_pvt *master = NULL, *slave = NULL;
04156    struct ast_frame *f;
04157    int inconf = 0;
04158    int nothingok = 1;
04159    int ofd0, ofd1;
04160    int oi0, oi1, i0 = -1, i1 = -1, t0, t1;
04161    int os0 = -1, os1 = -1;
04162    int priority = 0;
04163    struct ast_channel *oc0, *oc1;
04164    enum ast_bridge_result res;
04165 
04166 #ifdef PRI_2BCT
04167    int triedtopribridge = 0;
04168    q931_call *q931c0 = NULL, *q931c1 = NULL;
04169 #endif
04170 
04171    /* For now, don't attempt to native bridge if either channel needs DTMF detection.
04172       There is code below to handle it properly until DTMF is actually seen,
04173       but due to currently unresolved issues it's ignored...
04174    */
04175 
04176    if (flags & (AST_BRIDGE_DTMF_CHANNEL_0 | AST_BRIDGE_DTMF_CHANNEL_1))
04177       return AST_BRIDGE_FAILED_NOWARN;
04178 
04179    ast_channel_lock(c0);
04180    while (ast_channel_trylock(c1)) {
04181       CHANNEL_DEADLOCK_AVOIDANCE(c0);
04182    }
04183 
04184    p0 = c0->tech_pvt;
04185    p1 = c1->tech_pvt;
04186    /* cant do pseudo-channels here */
04187    if (!p0 || (!p0->sig) || !p1 || (!p1->sig)) {
04188       ast_channel_unlock(c0);
04189       ast_channel_unlock(c1);
04190       return AST_BRIDGE_FAILED_NOWARN;
04191    }
04192 
04193    oi0 = dahdi_get_index(c0, p0, 0);
04194    oi1 = dahdi_get_index(c1, p1, 0);
04195    if ((oi0 < 0) || (oi1 < 0)) {
04196       ast_channel_unlock(c0);
04197       ast_channel_unlock(c1);
04198       return AST_BRIDGE_FAILED;
04199    }
04200 
04201    op0 = p0 = c0->tech_pvt;
04202    op1 = p1 = c1->tech_pvt;
04203    ofd0 = c0->fds[0];
04204    ofd1 = c1->fds[0];
04205    oc0 = p0->owner;
04206    oc1 = p1->owner;
04207 
04208    if (ast_mutex_trylock(&p0->lock)) {
04209       /* Don't block, due to potential for deadlock */
04210       ast_channel_unlock(c0);
04211       ast_channel_unlock(c1);
04212       ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
04213       return AST_BRIDGE_RETRY;
04214    }
04215    if (ast_mutex_trylock(&p1->lock)) {
04216       /* Don't block, due to potential for deadlock */
04217       ast_mutex_unlock(&p0->lock);
04218       ast_channel_unlock(c0);
04219       ast_channel_unlock(c1);
04220       ast_log(LOG_NOTICE, "Avoiding deadlock...\n");
04221       return AST_BRIDGE_RETRY;
04222    }
04223 
04224    if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
04225       if (p0->owner && p1->owner) {
04226          /* If we don't have a call-wait in a 3-way, and we aren't in a 3-way, we can be master */
04227          if (!p0->subs[SUB_CALLWAIT].inthreeway && !p1->subs[SUB_REAL].inthreeway) {
04228             master = p0;
04229             slave = p1;
04230             inconf = 1;
04231          } else if (!p1->subs[SUB_CALLWAIT].inthreeway && !p0->subs[SUB_REAL].inthreeway) {
04232             master = p1;
04233             slave = p0;
04234             inconf = 1;
04235          } else {
04236             ast_log(LOG_WARNING, "Huh?  Both calls are callwaits or 3-ways?  That's clever...?\n");
04237             ast_log(LOG_WARNING, "p0: chan %d/%d/CW%d/3W%d, p1: chan %d/%d/CW%d/3W%d\n",
04238                p0->channel,
04239                oi0, (p0->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
04240                p0->subs[SUB_REAL].inthreeway, p0->channel,
04241                oi0, (p1->subs[SUB_CALLWAIT].dfd > -1) ? 1 : 0,
04242                p1->subs[SUB_REAL].inthreeway);
04243          }
04244          nothingok = 0;
04245       }
04246    } else if ((oi0 == SUB_REAL) && (oi1 == SUB_THREEWAY)) {
04247       if (p1->subs[SUB_THREEWAY].inthreeway) {
04248          master = p1;
04249          slave = p0;
04250          nothingok = 0;
04251       }
04252    } else if ((oi0 == SUB_THREEWAY) && (oi1 == SUB_REAL)) {
04253       if (p0->subs[SUB_THREEWAY].inthreeway) {
04254          master = p0;
04255          slave = p1;
04256          nothingok = 0;
04257       }
04258    } else if ((oi0 == SUB_REAL) && (oi1 == SUB_CALLWAIT)) {
04259       /* We have a real and a call wait.  If we're in a three way call, put us in it, otherwise, 
04260          don't put us in anything */
04261       if (p1->subs[SUB_CALLWAIT].inthreeway) {
04262          master = p1;
04263          slave = p0;
04264          nothingok = 0;
04265       }
04266    } else if ((oi0 == SUB_CALLWAIT) && (oi1 == SUB_REAL)) {
04267       /* Same as previous */
04268       if (p0->subs[SUB_CALLWAIT].inthreeway) {
04269          master = p0;
04270          slave = p1;
04271          nothingok = 0;
04272       }
04273    }
04274    ast_debug(1, "master: %d, slave: %d, nothingok: %d\n",
04275       master ? master->channel : 0, slave ? slave->channel : 0, nothingok);
04276    if (master && slave) {
04277       /* Stop any tones, or play ringtone as appropriate.  If they're bridged
04278          in an active threeway call with a channel that is ringing, we should
04279          indicate ringing. */
04280       if ((oi1 == SUB_THREEWAY) && 
04281           p1->subs[SUB_THREEWAY].inthreeway && 
04282           p1->subs[SUB_REAL].owner && 
04283           p1->subs[SUB_REAL].inthreeway && 
04284           (p1->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
04285          ast_debug(1, "Playing ringback on %s since %s is in a ringing three-way\n", c0->name, c1->name);
04286          tone_zone_play_tone(p0->subs[oi0].dfd, DAHDI_TONE_RINGTONE);
04287          os1 = p1->subs[SUB_REAL].owner->_state;
04288       } else {
04289          ast_debug(1, "Stopping tones on %d/%d talking to %d/%d\n", p0->channel, oi0, p1->channel, oi1);
04290          tone_zone_play_tone(p0->subs[oi0].dfd, -1);
04291       }
04292       if ((oi0 == SUB_THREEWAY) && 
04293           p0->subs[SUB_THREEWAY].inthreeway && 
04294           p0->subs[SUB_REAL].owner && 
04295           p0->subs[SUB_REAL].inthreeway && 
04296           (p0->subs[SUB_REAL].owner->_state == AST_STATE_RINGING)) {
04297          ast_debug(1, "Playing ringback on %s since %s is in a ringing three-way\n", c1->name, c0->name);
04298          tone_zone_play_tone(p1->subs[oi1].dfd, DAHDI_TONE_RINGTONE);
04299          os0 = p0->subs[SUB_REAL].owner->_state;
04300       } else {
04301          ast_debug(1, "Stopping tones on %d/%d talking to %d/%d\n", p1->channel, oi1, p0->channel, oi0);
04302          tone_zone_play_tone(p1->subs[oi0].dfd, -1);
04303       }
04304       if ((oi0 == SUB_REAL) && (oi1 == SUB_REAL)) {
04305          if (!p0->echocanbridged || !p1->echocanbridged) {
04306             /* Disable echo cancellation if appropriate */
04307             dahdi_disable_ec(p0);
04308             dahdi_disable_ec(p1);
04309          }
04310       }
04311       dahdi_link(slave, master);
04312       master->inconference = inconf;
04313    } else if (!nothingok)
04314       ast_log(LOG_WARNING, "Can't link %d/%s with %d/%s\n", p0->channel, subnames[oi0], p1->channel, subnames[oi1]);
04315 
04316    update_conf(p0);
04317    update_conf(p1);
04318    t0 = p0->subs[SUB_REAL].inthreeway;
04319    t1 = p1->subs[SUB_REAL].inthreeway;
04320 
04321    ast_mutex_unlock(&p0->lock);
04322    ast_mutex_unlock(&p1->lock);
04323 
04324    ast_channel_unlock(c0);
04325    ast_channel_unlock(c1);
04326 
04327    /* Native bridge failed */
04328    if ((!master || !slave) && !nothingok) {
04329       dahdi_enable_ec(p0);
04330       dahdi_enable_ec(p1);
04331       return AST_BRIDGE_FAILED;
04332    }
04333    
04334    ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);
04335 
04336    if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
04337       disable_dtmf_detect(op0);
04338 
04339    if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
04340       disable_dtmf_detect(op1);
04341 
04342    for (;;) {
04343       struct ast_channel *c0_priority[2] = {c0, c1};
04344       struct ast_channel *c1_priority[2] = {c1, c0};
04345 
04346       /* Here's our main loop...  Start by locking things, looking for private parts, 
04347          and then balking if anything is wrong */
04348       
04349       ast_channel_lock(c0);
04350       while (ast_channel_trylock(c1)) {
04351          CHANNEL_DEADLOCK_AVOIDANCE(c0);
04352       }
04353 
04354       p0 = c0->tech_pvt;
04355       p1 = c1->tech_pvt;
04356 
04357       if (op0 == p0)
04358          i0 = dahdi_get_index(c0, p0, 1);
04359       if (op1 == p1)
04360          i1 = dahdi_get_index(c1, p1, 1);
04361 
04362       ast_channel_unlock(c0);
04363       ast_channel_unlock(c1);
04364 
04365       if (!timeoutms || 
04366           (op0 != p0) ||
04367           (op1 != p1) || 
04368           (ofd0 != c0->fds[0]) || 
04369           (ofd1 != c1->fds[0]) ||
04370           (p0->subs[SUB_REAL].owner && (os0 > -1) && (os0 != p0->subs[SUB_REAL].owner->_state)) || 
04371           (p1->subs[SUB_REAL].owner && (os1 > -1) && (os1 != p1->subs[SUB_REAL].owner->_state)) || 
04372           (oc0 != p0->owner) || 
04373           (oc1 != p1->owner) ||
04374           (t0 != p0->subs[SUB_REAL].inthreeway) ||
04375           (t1 != p1->subs[SUB_REAL].inthreeway) ||
04376           (oi0 != i0) ||
04377           (oi1 != i1)) {
04378          ast_debug(1, "Something changed out on %d/%d to %d/%d, returning -3 to restart\n",
04379             op0->channel, oi0, op1->channel, oi1);
04380          res = AST_BRIDGE_RETRY;
04381          goto return_from_bridge;
04382       }
04383 
04384 #ifdef PRI_2BCT
04385       q931c0 = p0->call;
04386       q931c1 = p1->call;
04387       if (p0->transfer && p1->transfer 
04388           && q931c0 && q931c1 
04389           && !triedtopribridge) {
04390          pri_channel_bridge(q931c0, q931c1);
04391          triedtopribridge = 1;
04392       }
04393 #endif
04394 
04395       who = ast_waitfor_n(priority ? c0_priority : c1_priority, 2, &timeoutms);
04396       if (!who) {
04397          ast_debug(1, "Ooh, empty read...\n");
04398          continue;
04399       }
04400       f = ast_read(who);
04401       if (!f || (f->frametype == AST_FRAME_CONTROL)) {
04402          *fo = f;
04403          *rc = who;
04404          res = AST_BRIDGE_COMPLETE;
04405          goto return_from_bridge;
04406       }
04407       if (f->frametype == AST_FRAME_DTMF) {
04408          if ((who == c0) && p0->pulsedial) {
04409             ast_write(c1, f);
04410          } else if ((who == c1) && p1->pulsedial) {
04411             ast_write(c0, f);
04412          } else {
04413             *fo = f;
04414             *rc = who;
04415             res = AST_BRIDGE_COMPLETE;
04416             goto return_from_bridge;
04417          }
04418       }
04419       ast_frfree(f);
04420       
04421       /* Swap who gets priority */
04422       priority = !priority;
04423    }
04424 
04425 return_from_bridge:
04426    if (op0 == p0)
04427       dahdi_enable_ec(p0);
04428 
04429    if (op1 == p1)
04430       dahdi_enable_ec(p1);
04431 
04432    if (!(flags & AST_BRIDGE_DTMF_CHANNEL_0) && (oi0 == SUB_REAL))
04433       enable_dtmf_detect(op0);
04434 
04435    if (!(flags & AST_BRIDGE_DTMF_CHANNEL_1) && (oi1 == SUB_REAL))
04436       enable_dtmf_detect(op1);
04437 
04438    dahdi_unlink(slave, master, 1);
04439 
04440    return res;
04441 }
04442 
04443 static int dahdi_fixup(struct ast_channel *oldchan, struct ast_channel *newchan)
04444 {
04445    struct dahdi_pvt *p = newchan->tech_pvt;
04446    int x;
04447    ast_mutex_lock(&p->lock);
04448    ast_debug(1, "New owner for channel %d is %s\n", p->channel, newchan->name);
04449    if (p->owner == oldchan) {
04450       p->owner = newchan;
04451    }
04452    for (x = 0; x < 3; x++)
04453       if (p->subs[x].owner == oldchan) {
04454          if (!x)
04455             dahdi_unlink(NULL, p, 0);
04456          p->subs[x].owner = newchan;
04457       }
04458    if (newchan->_state == AST_STATE_RINGING) 
04459       dahdi_indicate(newchan, AST_CONTROL_RINGING, NULL, 0);
04460    update_conf(p);
04461    ast_mutex_unlock(&p->lock);
04462    return 0;
04463 }
04464 
04465 static int dahdi_ring_phone(struct dahdi_pvt *p)
04466 {
04467    int x;
04468    int res;
04469    /* Make sure our transmit state is on hook */
04470    x = 0;
04471    x = DAHDI_ONHOOK;
04472    res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
04473    do {
04474       x = DAHDI_RING;
04475       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
04476       if (res) {
04477          switch (errno) {
04478          case EBUSY:
04479          case EINTR:
04480             /* Wait just in case */
04481             usleep(10000);
04482             continue;
04483          case EINPROGRESS:
04484             res = 0;
04485             break;
04486          default:
04487             ast_log(LOG_WARNING, "Couldn't ring the phone: %s\n", strerror(errno));
04488             res = 0;
04489          }
04490       }
04491    } while (res);
04492    return res;
04493 }
04494 
04495 static void *ss_thread(void *data);
04496 
04497 static struct ast_channel *dahdi_new(struct dahdi_pvt *, int, int, int, int, int);
04498 
04499 static int attempt_transfer(struct dahdi_pvt *p)
04500 {
04501    /* In order to transfer, we need at least one of the channels to
04502       actually be in a call bridge.  We can't conference two applications
04503       together (but then, why would we want to?) */
04504    if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
04505       /* The three-way person we're about to transfer to could still be in MOH, so
04506          stop if now if appropriate */
04507       if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner))
04508          ast_queue_control(p->subs[SUB_THREEWAY].owner, AST_CONTROL_UNHOLD);
04509       if (p->subs[SUB_REAL].owner->_state == AST_STATE_RINGING) {
04510          ast_indicate(ast_bridged_channel(p->subs[SUB_REAL].owner), AST_CONTROL_RINGING);
04511       }
04512       if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RING) {
04513          tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
04514       }
04515        if (ast_channel_masquerade(p->subs[SUB_THREEWAY].owner, ast_bridged_channel(p->subs[SUB_REAL].owner))) {
04516          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
04517                ast_bridged_channel(p->subs[SUB_REAL].owner)->name, p->subs[SUB_THREEWAY].owner->name);
04518          return -1;
04519       }
04520       /* Orphan the channel after releasing the lock */
04521       ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04522       unalloc_sub(p, SUB_THREEWAY);
04523    } else if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
04524       ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
04525       if (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_RINGING) {
04526          ast_indicate(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), AST_CONTROL_RINGING);
04527       }
04528       if (p->subs[SUB_REAL].owner->_state == AST_STATE_RING) {
04529          tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
04530       }
04531       if (ast_channel_masquerade(p->subs[SUB_REAL].owner, ast_bridged_channel(p->subs[SUB_THREEWAY].owner))) {
04532          ast_log(LOG_WARNING, "Unable to masquerade %s as %s\n",
04533                ast_bridged_channel(p->subs[SUB_THREEWAY].owner)->name, p->subs[SUB_REAL].owner->name);
04534          return -1;
04535       }
04536       /* Three-way is now the REAL */
04537       swap_subs(p, SUB_THREEWAY, SUB_REAL);
04538       ast_channel_unlock(p->subs[SUB_REAL].owner);
04539       unalloc_sub(p, SUB_THREEWAY);
04540       /* Tell the caller not to hangup */
04541       return 1;
04542    } else {
04543       ast_debug(1, "Neither %s nor %s are in a bridge, nothing to transfer\n",
04544          p->subs[SUB_REAL].owner->name, p->subs[SUB_THREEWAY].owner->name);
04545       p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
04546       return -1;
04547    }
04548    return 0;
04549 }
04550 
04551 static int check_for_conference(struct dahdi_pvt *p)
04552 {
04553    struct dahdi_confinfo ci;
04554    /* Fine if we already have a master, etc */
04555    if (p->master || (p->confno > -1))
04556       return 0;
04557    memset(&ci, 0, sizeof(ci));
04558    if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
04559       ast_log(LOG_WARNING, "Failed to get conference info on channel %d: %s\n", p->channel, strerror(errno));
04560       return 0;
04561    }
04562    /* If we have no master and don't have a confno, then 
04563       if we're in a conference, it's probably a MeetMe room or
04564       some such, so don't let us 3-way out! */
04565    if ((p->subs[SUB_REAL].curconf.confno != ci.confno) || (p->subs[SUB_REAL].curconf.confmode != ci.confmode)) {
04566       ast_verb(3, "Avoiding 3-way call when in an external conference\n");
04567       return 1;
04568    }
04569    return 0;
04570 }
04571 
04572 /*! Checks channel for alarms
04573  * \param p a channel to check for alarms.
04574  * \returns the alarms on the span to which the channel belongs, or alarms on
04575  *          the channel if no span alarms.
04576  */
04577 static int get_alarms(struct dahdi_pvt *p)
04578 {
04579    int res;
04580    struct dahdi_spaninfo zi;
04581    struct dahdi_params params;
04582 
04583    memset(&zi, 0, sizeof(zi));
04584    zi.spanno = p->span;
04585 
04586    if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SPANSTAT, &zi)) >= 0) {
04587       if (zi.alarms != DAHDI_ALARM_NONE)
04588          return zi.alarms;
04589    } else {
04590       ast_log(LOG_WARNING, "Unable to determine alarm on channel %d: %s\n", p->channel, strerror(errno));
04591       return 0;
04592    }
04593 
04594    /* No alarms on the span. Check for channel alarms. */
04595    memset(&params, 0, sizeof(params));
04596    if ((res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &params)) >= 0)
04597       return params.chan_alarms;
04598 
04599    ast_log(LOG_WARNING, "Unable to determine alarm on channel %d\n", p->channel);
04600 
04601    return DAHDI_ALARM_NONE;
04602 }
04603 
04604 static void dahdi_handle_dtmfup(struct ast_channel *ast, int idx, struct ast_frame **dest)
04605 {
04606    struct dahdi_pvt *p = ast->tech_pvt;
04607    struct ast_frame *f = *dest;
04608 
04609    ast_debug(1, "DTMF digit: %c on %s\n", f->subclass, ast->name);
04610 
04611    if (p->confirmanswer) {
04612       ast_debug(1, "Confirm answer on %s!\n", ast->name);
04613       /* Upon receiving a DTMF digit, consider this an answer confirmation instead
04614          of a DTMF digit */
04615       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04616       p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
04617       *dest = &p->subs[idx].f;
04618       /* Reset confirmanswer so DTMF's will behave properly for the duration of the call */
04619       p->confirmanswer = 0;
04620    } else if (p->callwaitcas) {
04621       if ((f->subclass == 'A') || (f->subclass == 'D')) {
04622          ast_debug(1, "Got some DTMF, but it's for the CAS\n");
04623          if (p->cidspill)
04624             ast_free(p->cidspill);
04625          send_cwcidspill(p);
04626       }
04627       p->callwaitcas = 0;
04628       p->subs[idx].f.frametype = AST_FRAME_NULL;
04629       p->subs[idx].f.subclass = 0;
04630       *dest = &p->subs[idx].f;
04631    } else if (f->subclass == 'f') {
04632       /* Fax tone -- Handle and return NULL */
04633       if ((p->callprogress & CALLPROGRESS_FAX) && !p->faxhandled) {
04634          p->faxhandled = 1;
04635          if (strcmp(ast->exten, "fax")) {
04636             const char *target_context = S_OR(ast->macrocontext, ast->context);
04637 
04638             /* We need to unlock 'ast' here because ast_exists_extension has the
04639              * potential to start autoservice on the channel. Such action is prone
04640              * to deadlock.
04641              */
04642             ast_mutex_unlock(&p->lock);
04643             ast_channel_unlock(ast);
04644             if (ast_exists_extension(ast, target_context, "fax", 1, ast->cid.cid_num)) {
04645                ast_channel_lock(ast);
04646                ast_mutex_lock(&p->lock);
04647                ast_verb(3, "Redirecting %s to fax extension\n", ast->name);
04648                /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
04649                pbx_builtin_setvar_helper(ast, "FAXEXTEN", ast->exten);
04650                if (ast_async_goto(ast, target_context, "fax", 1))
04651                   ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, target_context);
04652             } else {
04653                ast_channel_lock(ast);
04654                ast_mutex_lock(&p->lock);
04655                ast_log(LOG_NOTICE, "Fax detected, but no fax extension\n");
04656             }
04657          } else {
04658             ast_debug(1, "Already in a fax extension, not redirecting\n");
04659          }
04660       } else {
04661          ast_debug(1, "Fax already handled\n");
04662       }
04663       dahdi_confmute(p, 0);
04664       p->subs[idx].f.frametype = AST_FRAME_NULL;
04665       p->subs[idx].f.subclass = 0;
04666       *dest = &p->subs[idx].f;
04667    }
04668 }
04669          
04670 static void handle_alarms(struct dahdi_pvt *p, int alms)
04671 {
04672    const char *alarm_str = alarm2str(alms);
04673 
04674    ast_log(LOG_WARNING, "Detected alarm on channel %d: %s\n", p->channel, alarm_str);
04675    manager_event(EVENT_FLAG_SYSTEM, "Alarm",
04676             "Alarm: %s\r\n"
04677             "Channel: %d\r\n",
04678             alarm_str, p->channel);
04679 }
04680 
04681 static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
04682 {
04683    int res, x;
04684    int idx, mysig;
04685    char *c;
04686    struct dahdi_pvt *p = ast->tech_pvt;
04687    pthread_t threadid;
04688    struct ast_channel *chan;
04689    struct ast_frame *f;
04690 
04691    idx = dahdi_get_index(ast, p, 0);
04692    mysig = p->sig;
04693    if (p->outsigmod > -1)
04694       mysig = p->outsigmod;
04695    p->subs[idx].f.frametype = AST_FRAME_NULL;
04696    p->subs[idx].f.subclass = 0;
04697    p->subs[idx].f.datalen = 0;
04698    p->subs[idx].f.samples = 0;
04699    p->subs[idx].f.mallocd = 0;
04700    p->subs[idx].f.offset = 0;
04701    p->subs[idx].f.src = "dahdi_handle_event";
04702    p->subs[idx].f.data.ptr = NULL;
04703    f = &p->subs[idx].f;
04704 
04705    if (idx < 0)
04706       return &p->subs[idx].f;
04707    if (p->fake_event) {
04708       res = p->fake_event;
04709       p->fake_event = 0;
04710    } else
04711       res = dahdi_get_event(p->subs[idx].dfd);
04712 
04713    ast_debug(1, "Got event %s(%d) on channel %d (index %d)\n", event2str(res), res, p->channel, idx);
04714 
04715    if (res & (DAHDI_EVENT_PULSEDIGIT | DAHDI_EVENT_DTMFUP)) {
04716       p->pulsedial =  (res & DAHDI_EVENT_PULSEDIGIT) ? 1 : 0;
04717       ast_debug(1, "Detected %sdigit '%c'\n", p->pulsedial ? "pulse ": "", res & 0xff);
04718 #ifdef HAVE_PRI
04719       if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
04720          /* absorb event */
04721       } else {
04722 #endif
04723          dahdi_confmute(p, 0);
04724          p->subs[idx].f.frametype = AST_FRAME_DTMF_END;
04725          p->subs[idx].f.subclass = res & 0xff;
04726 #ifdef HAVE_PRI
04727       }
04728 #endif
04729       dahdi_handle_dtmfup(ast, idx, &f);
04730       return f;
04731    }
04732 
04733    if (res & DAHDI_EVENT_DTMFDOWN) {
04734       ast_debug(1, "DTMF Down '%c'\n", res & 0xff);
04735       /* Mute conference */
04736       dahdi_confmute(p, 1);
04737       p->subs[idx].f.frametype = AST_FRAME_DTMF_BEGIN;
04738       p->subs[idx].f.subclass = res & 0xff;
04739       return &p->subs[idx].f;
04740    }
04741 
04742    switch (res) {
04743       case DAHDI_EVENT_EC_DISABLED:
04744          ast_verb(3, "Channel %d echo canceler disabled due to CED detection\n", p->channel);
04745          p->echocanon = 0;
04746          break;
04747       case DAHDI_EVENT_BITSCHANGED:
04748          ast_log(LOG_WARNING, "Received bits changed on %s signalling?\n", sig2str(p->sig));
04749       case DAHDI_EVENT_PULSE_START:
04750          /* Stop tone if there's a pulse start and the PBX isn't started */
04751          if (!ast->pbx)
04752             tone_zone_play_tone(p->subs[idx].dfd, -1);
04753          break;   
04754       case DAHDI_EVENT_DIALCOMPLETE:
04755          if (p->inalarm) break;
04756          if ((p->radio || (p->oprmode < 0))) break;
04757          if (ioctl(p->subs[idx].dfd,DAHDI_DIALING,&x) == -1) {
04758             ast_log(LOG_DEBUG, "DAHDI_DIALING ioctl failed on %s: %s\n",ast->name, strerror(errno));
04759             return NULL;
04760          }
04761          if (!x) { /* if not still dialing in driver */
04762             dahdi_enable_ec(p);
04763             if (p->echobreak) {
04764                dahdi_train_ec(p);
04765                ast_copy_string(p->dop.dialstr, p->echorest, sizeof(p->dop.dialstr));
04766                p->dop.op = DAHDI_DIAL_OP_REPLACE;
04767                res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
04768                p->echobreak = 0;
04769             } else {
04770                p->dialing = 0;
04771                if ((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) {
04772                   /* if thru with dialing after offhook */
04773                   if (ast->_state == AST_STATE_DIALING_OFFHOOK) {
04774                      ast_setstate(ast, AST_STATE_UP);
04775                      p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04776                      p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
04777                      break;
04778                   } else { /* if to state wait for offhook to dial rest */
04779                      /* we now wait for off hook */
04780                      ast_setstate(ast,AST_STATE_DIALING_OFFHOOK);
04781                   }
04782                }
04783                if (ast->_state == AST_STATE_DIALING) {
04784                   if ((p->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(p) && p->dsp && p->outgoing) {
04785                      ast_debug(1, "Done dialing, but waiting for progress detection before doing more...\n");
04786                   } 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)))) {
04787                      ast_setstate(ast, AST_STATE_RINGING);
04788                   } else if (!p->answeronpolarityswitch) {
04789                      ast_setstate(ast, AST_STATE_UP);
04790                      p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04791                      p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
04792                      /* If aops=0 and hops=1, this is necessary */
04793                      p->polarity = POLARITY_REV;
04794                   } else {
04795                      /* Start clean, so we can catch the change to REV polarity when party answers */
04796                      p->polarity = POLARITY_IDLE;
04797                   }
04798                }
04799             }
04800          }
04801          break;
04802       case DAHDI_EVENT_ALARM:
04803 #ifdef HAVE_PRI
04804          if ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) {
04805             if (!p->pri || !p->pri->pri || (pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0)) {
04806                /* T309 is not enabled : hangup calls when alarm occurs */
04807                if (p->call) {
04808                   if (p->pri && p->pri->pri) {
04809                      if (!pri_grab(p, p->pri)) {
04810                         pri_hangup(p->pri->pri, p->call, -1);
04811                         pri_destroycall(p->pri->pri, p->call);
04812                         p->call = NULL;
04813                         pri_rel(p->pri);
04814                      } else
04815                         ast_log(LOG_WARNING, "Failed to grab PRI!\n");
04816                   } else
04817                      ast_log(LOG_WARNING, "The PRI Call has not been destroyed\n");
04818                }
04819                if (p->owner)
04820                   p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
04821             }
04822          }
04823          if (p->bearer)
04824             p->bearer->inalarm = 1;
04825          else
04826 #endif
04827          p->inalarm = 1;
04828          res = get_alarms(p);
04829          handle_alarms(p, res);
04830 #ifdef HAVE_PRI
04831          if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
04832             /* fall through intentionally */
04833          } else {
04834             break;
04835          }
04836 #endif
04837 #ifdef HAVE_SS7
04838          if (p->sig == SIG_SS7)
04839             break;
04840 #endif
04841       case DAHDI_EVENT_ONHOOK:
04842          if (p->radio) {
04843             p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04844             p->subs[idx].f.subclass = AST_CONTROL_RADIO_UNKEY;
04845             break;
04846          }
04847          if (p->oprmode < 0)
04848          {
04849             if (p->oprmode != -1) break;
04850             if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
04851             {
04852                /* Make sure it starts ringing */
04853                dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
04854                dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RING);
04855                save_conference(p->oprpeer);
04856                tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
04857             }
04858             break;
04859          }
04860          switch (p->sig) {
04861          case SIG_FXOLS:
04862          case SIG_FXOGS:
04863          case SIG_FXOKS:
04864             p->onhooktime = time(NULL);
04865             p->msgstate = -1;
04866             /* Check for some special conditions regarding call waiting */
04867             if (idx == SUB_REAL) {
04868                /* The normal line was hung up */
04869                if (p->subs[SUB_CALLWAIT].owner) {
04870                   /* There's a call waiting call, so ring the phone, but make it unowned in the mean time */
04871                   swap_subs(p, SUB_CALLWAIT, SUB_REAL);
04872                   ast_verb(3, "Channel %d still has (callwait) call, ringing phone\n", p->channel);
04873                   unalloc_sub(p, SUB_CALLWAIT); 
04874 #if 0
04875                   p->subs[idx].needanswer = 0;
04876                   p->subs[idx].needringing = 0;
04877 #endif                  
04878                   p->callwaitingrepeat = 0;
04879                   p->cidcwexpire = 0;
04880                   p->owner = NULL;
04881                   /* Don't start streaming audio yet if the incoming call isn't up yet */
04882                   if (p->subs[SUB_REAL].owner->_state != AST_STATE_UP)
04883                      p->dialing = 1;
04884                   dahdi_ring_phone(p);
04885                } else if (p->subs[SUB_THREEWAY].owner) {
04886                   unsigned int mssinceflash;
04887                   /* Here we have to retain the lock on both the main channel, the 3-way channel, and
04888                      the private structure -- not especially easy or clean */
04889                   while (p->subs[SUB_THREEWAY].owner && ast_channel_trylock(p->subs[SUB_THREEWAY].owner)) {
04890                      /* Yuck, didn't get the lock on the 3-way, gotta release everything and re-grab! */
04891                      DLA_UNLOCK(&p->lock);
04892                      CHANNEL_DEADLOCK_AVOIDANCE(ast);
04893                      /* We can grab ast and p in that order, without worry.  We should make sure
04894                         nothing seriously bad has happened though like some sort of bizarre double
04895                         masquerade! */
04896                      DLA_LOCK(&p->lock);
04897                      if (p->owner != ast) {
04898                         ast_log(LOG_WARNING, "This isn't good...\n");
04899                         return NULL;
04900                      }
04901                   }
04902                   if (!p->subs[SUB_THREEWAY].owner) {
04903                      ast_log(LOG_NOTICE, "Whoa, threeway disappeared kinda randomly.\n");
04904                      return NULL;
04905                   }
04906                   mssinceflash = ast_tvdiff_ms(ast_tvnow(), p->flashtime);
04907                   ast_debug(1, "Last flash was %d ms ago\n", mssinceflash);
04908                   if (mssinceflash < MIN_MS_SINCE_FLASH) {
04909                      /* It hasn't been long enough since the last flashook.  This is probably a bounce on 
04910                         hanging up.  Hangup both channels now */
04911                      if (p->subs[SUB_THREEWAY].owner)
04912                         ast_queue_hangup_with_cause(p->subs[SUB_THREEWAY].owner, AST_CAUSE_NO_ANSWER);
04913                      p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
04914                      ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
04915                      ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04916                   } else if ((ast->pbx) || (ast->_state == AST_STATE_UP)) {
04917                      if (p->transfer) {
04918                         /* In any case this isn't a threeway call anymore */
04919                         p->subs[SUB_REAL].inthreeway = 0;
04920                         p->subs[SUB_THREEWAY].inthreeway = 0;
04921                         /* Only attempt transfer if the phone is ringing; why transfer to busy tone eh? */
04922                         if (!p->transfertobusy && ast->_state == AST_STATE_BUSY) {
04923                            ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04924                            /* Swap subs and dis-own channel */
04925                            swap_subs(p, SUB_THREEWAY, SUB_REAL);
04926                            p->owner = NULL;
04927                            /* Ring the phone */
04928                            dahdi_ring_phone(p);
04929                         } else {
04930                            if ((res = attempt_transfer(p)) < 0) {
04931                               p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
04932                               if (p->subs[SUB_THREEWAY].owner)
04933                                  ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04934                            } else if (res) {
04935                               /* Don't actually hang up at this point */
04936                               if (p->subs[SUB_THREEWAY].owner)
04937                                  ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04938                               break;
04939                            }
04940                         }
04941                      } else {
04942                         p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
04943                         if (p->subs[SUB_THREEWAY].owner)
04944                            ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04945                      }
04946                   } else {
04947                      ast_channel_unlock(p->subs[SUB_THREEWAY].owner);
04948                      /* Swap subs and dis-own channel */
04949                      swap_subs(p, SUB_THREEWAY, SUB_REAL);
04950                      p->owner = NULL;
04951                      /* Ring the phone */
04952                      dahdi_ring_phone(p);
04953                   }
04954                }
04955             } else {
04956                ast_log(LOG_WARNING, "Got a hangup and my index is %d?\n", idx);
04957             }
04958             /* Fall through */
04959          default:
04960             dahdi_disable_ec(p);
04961             return NULL;
04962          }
04963          break;
04964       case DAHDI_EVENT_RINGOFFHOOK:
04965          if (p->inalarm) break;
04966          if (p->oprmode < 0)
04967          {
04968             if ((p->sig == SIG_FXOLS) || (p->sig == SIG_FXOKS) || (p->sig == SIG_FXOGS))
04969             {
04970                /* Make sure it stops ringing */
04971                dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
04972                tone_zone_play_tone(p->oprpeer->subs[SUB_REAL].dfd, -1);
04973                restore_conference(p->oprpeer);
04974             }
04975             break;
04976          }
04977          if (p->radio)
04978          {
04979             p->subs[idx].f.frametype = AST_FRAME_CONTROL;
04980             p->subs[idx].f.subclass = AST_CONTROL_RADIO_KEY;
04981             break;
04982          }
04983          /* for E911, its supposed to wait for offhook then dial
04984             the second half of the dial string */
04985          if (((mysig == SIG_E911) || (mysig == SIG_FGC_CAMA) || (mysig == SIG_FGC_CAMAMF)) && (ast->_state == AST_STATE_DIALING_OFFHOOK)) {
04986             c = strchr(p->dialdest, '/');
04987             if (c)
04988                c++;
04989             else
04990                c = p->dialdest;
04991             if (*c) snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*0%s#", c);
04992             else ast_copy_string(p->dop.dialstr,"M*2#", sizeof(p->dop.dialstr));
04993             if (strlen(p->dop.dialstr) > 4) {
04994                memset(p->echorest, 'w', sizeof(p->echorest) - 1);
04995                strcpy(p->echorest + (p->echotraining / 401) + 1, p->dop.dialstr + strlen(p->dop.dialstr) - 2);
04996                p->echorest[sizeof(p->echorest) - 1] = '\0';
04997                p->echobreak = 1;
04998                p->dop.dialstr[strlen(p->dop.dialstr)-2] = '\0';
04999             } else
05000                p->echobreak = 0;
05001             if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop)) {
05002                int saveerr = errno;
05003 
05004                x = DAHDI_ONHOOK;
05005                ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
05006                ast_log(LOG_WARNING, "Dialing failed on channel %d: %s\n", p->channel, strerror(saveerr));
05007                return NULL;
05008                }
05009             p->dialing = 1;
05010             return &p->subs[idx].f;
05011          }
05012          switch (p->sig) {
05013          case SIG_FXOLS:
05014          case SIG_FXOGS:
05015          case SIG_FXOKS:
05016             switch (ast->_state) {
05017             case AST_STATE_RINGING:
05018                dahdi_enable_ec(p);
05019                dahdi_train_ec(p);
05020                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05021                p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
05022                /* Make sure it stops ringing */
05023                dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
05024                ast_debug(1, "channel %d answered\n", p->channel);
05025                if (p->cidspill) {
05026                   /* Cancel any running CallerID spill */
05027                   ast_free(p->cidspill);
05028                   p->cidspill = NULL;
05029                }
05030                p->dialing = 0;
05031                p->callwaitcas = 0;
05032                if (p->confirmanswer) {
05033                   /* Ignore answer if "confirm answer" is enabled */
05034                   p->subs[idx].f.frametype = AST_FRAME_NULL;
05035                   p->subs[idx].f.subclass = 0;
05036                } else if (!ast_strlen_zero(p->dop.dialstr)) {
05037                   /* nick@dccinc.com 4/3/03 - fxo should be able to do deferred dialing */
05038                   res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
05039                   if (res < 0) {
05040                      ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
05041                      p->dop.dialstr[0] = '\0';
05042                      return NULL;
05043                   } else {
05044                      ast_debug(1, "Sent FXO deferred digit string: %s\n", p->dop.dialstr);
05045                      p->subs[idx].f.frametype = AST_FRAME_NULL;
05046                      p->subs[idx].f.subclass = 0;
05047                      p->dialing = 1;
05048                   }
05049                   p->dop.dialstr[0] = '\0';
05050                   ast_setstate(ast, AST_STATE_DIALING);
05051                } else
05052                   ast_setstate(ast, AST_STATE_UP);
05053                return &p->subs[idx].f;
05054             case AST_STATE_DOWN:
05055                ast_setstate(ast, AST_STATE_RING);
05056                ast->rings = 1;
05057                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05058                p->subs[idx].f.subclass = AST_CONTROL_OFFHOOK;
05059                ast_debug(1, "channel %d picked up\n", p->channel);
05060                return &p->subs[idx].f;
05061             case AST_STATE_UP:
05062                /* Make sure it stops ringing */
05063                dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
05064                /* Okay -- probably call waiting*/
05065                if (ast_bridged_channel(p->owner))
05066                   ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
05067                p->subs[idx].needunhold = 1;
05068                break;
05069             case AST_STATE_RESERVED:
05070                /* Start up dialtone */
05071                if (has_voicemail(p))
05072                   res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
05073                else
05074                   res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
05075                break;
05076             default:
05077                ast_log(LOG_WARNING, "FXO phone off hook in weird state %d??\n", ast->_state);
05078             }
05079             break;
05080          case SIG_FXSLS:
05081          case SIG_FXSGS:
05082          case SIG_FXSKS:
05083             if (ast->_state == AST_STATE_RING) {
05084                p->ringt = p->ringt_base;
05085             }
05086 
05087             /* If we get a ring then we cannot be in 
05088              * reversed polarity. So we reset to idle */
05089             ast_debug(1, "Setting IDLE polarity due "
05090                "to ring. Old polarity was %d\n", 
05091                p->polarity);
05092             p->polarity = POLARITY_IDLE;
05093 
05094             /* Fall through */
05095          case SIG_EM:
05096          case SIG_EM_E1:
05097          case SIG_EMWINK:
05098          case SIG_FEATD:
05099          case SIG_FEATDMF:
05100          case SIG_FEATDMF_TA:
05101          case SIG_E911:
05102          case SIG_FGC_CAMA:
05103          case SIG_FGC_CAMAMF:
05104          case SIG_FEATB:
05105          case SIG_SF:
05106          case SIG_SFWINK:
05107          case SIG_SF_FEATD:
05108          case SIG_SF_FEATDMF:
05109          case SIG_SF_FEATB:
05110             if (ast->_state == AST_STATE_PRERING)
05111                ast_setstate(ast, AST_STATE_RING);
05112             if ((ast->_state == AST_STATE_DOWN) || (ast->_state == AST_STATE_RING)) {
05113                ast_debug(1, "Ring detected\n");
05114                p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05115                p->subs[idx].f.subclass = AST_CONTROL_RING;
05116             } else if (p->outgoing && ((ast->_state == AST_STATE_RINGING) || (ast->_state == AST_STATE_DIALING))) {
05117                ast_debug(1, "Line answered\n");
05118                if (p->confirmanswer) {
05119                   p->subs[idx].f.frametype = AST_FRAME_NULL;
05120                   p->subs[idx].f.subclass = 0;
05121                } else {
05122                   p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05123                   p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
05124                   ast_setstate(ast, AST_STATE_UP);
05125                }
05126             } else if (ast->_state != AST_STATE_RING)
05127                ast_log(LOG_WARNING, "Ring/Off-hook in strange state %d on channel %d\n", ast->_state, p->channel);
05128             break;
05129          default:
05130             ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
05131          }
05132          break;
05133       case DAHDI_EVENT_RINGBEGIN:
05134          switch (p->sig) {
05135          case SIG_FXSLS:
05136          case SIG_FXSGS:
05137          case SIG_FXSKS:
05138             if (ast->_state == AST_STATE_RING) {
05139                p->ringt = p->ringt_base;
05140             }
05141             break;
05142          }
05143          break;
05144       case DAHDI_EVENT_RINGEROFF:
05145          if (p->inalarm) break;
05146          if ((p->radio || (p->oprmode < 0))) break;
05147          ast->rings++;
05148          if ((ast->rings > p->cidrings) && (p->cidspill)) {
05149             ast_log(LOG_WARNING, "Didn't finish Caller-ID spill.  Cancelling.\n");
05150             ast_free(p->cidspill);
05151             p->cidspill = NULL;
05152             p->callwaitcas = 0;
05153          }
05154          p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05155          p->subs[idx].f.subclass = AST_CONTROL_RINGING;
05156          break;
05157       case DAHDI_EVENT_RINGERON:
05158          break;
05159       case DAHDI_EVENT_NOALARM:
05160          p->inalarm = 0;
05161 #ifdef HAVE_PRI
05162          /* Extremely unlikely but just in case */
05163          if (p->bearer)
05164             p->bearer->inalarm = 0;
05165 #endif            
05166          ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", p->channel);
05167          manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
05168                         "Channel: %d\r\n", p->channel);
05169          break;
05170       case DAHDI_EVENT_WINKFLASH:
05171          if (p->inalarm) break;
05172          if (p->radio) break;
05173          if (p->oprmode < 0) break;
05174          if (p->oprmode > 1)
05175          {
05176             struct dahdi_params par;
05177 
05178             memset(&par, 0, sizeof(par));
05179             if (ioctl(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par) != -1)
05180             {
05181                if (!par.rxisoffhook)
05182                {
05183                   /* Make sure it stops ringing */
05184                   dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RINGOFF);
05185                   dahdi_set_hook(p->oprpeer->subs[SUB_REAL].dfd, DAHDI_RING);
05186                   save_conference(p);
05187                   tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
05188                }
05189             }
05190             break;
05191          }
05192          /* Remember last time we got a flash-hook */
05193          p->flashtime = ast_tvnow();
05194          switch (mysig) {
05195          case SIG_FXOLS:
05196          case SIG_FXOGS:
05197          case SIG_FXOKS:
05198             ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
05199                idx, p->subs[SUB_REAL].dfd, p->subs[SUB_CALLWAIT].dfd, p->subs[SUB_THREEWAY].dfd);
05200             p->callwaitcas = 0;
05201 
05202             if (idx != SUB_REAL) {
05203                ast_log(LOG_WARNING, "Got flash hook with index %d on channel %d?!?\n", idx, p->channel);
05204                goto winkflashdone;
05205             }
05206             
05207             if (p->subs[SUB_CALLWAIT].owner) {
05208                /* Swap to call-wait */
05209                swap_subs(p, SUB_REAL, SUB_CALLWAIT);
05210                tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
05211                p->owner = p->subs[SUB_REAL].owner;
05212                ast_debug(1, "Making %s the new owner\n", p->owner->name);
05213                if (p->owner->_state == AST_STATE_RINGING) {
05214                   ast_setstate(p->owner, AST_STATE_UP);
05215                   p->subs[SUB_REAL].needanswer = 1;
05216                }
05217                p->callwaitingrepeat = 0;
05218                p->cidcwexpire = 0;
05219                /* Start music on hold if appropriate */
05220                if (!p->subs[SUB_CALLWAIT].inthreeway && ast_bridged_channel(p->subs[SUB_CALLWAIT].owner)) {
05221                   ast_queue_control_data(p->subs[SUB_CALLWAIT].owner, AST_CONTROL_HOLD,
05222                      S_OR(p->mohsuggest, NULL),
05223                      !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
05224                }
05225                p->subs[SUB_CALLWAIT].needhold = 1;
05226                if (ast_bridged_channel(p->subs[SUB_REAL].owner)) {
05227                   ast_queue_control_data(p->subs[SUB_REAL].owner, AST_CONTROL_HOLD,
05228                      S_OR(p->mohsuggest, NULL),
05229                      !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
05230                }
05231                p->subs[SUB_REAL].needunhold = 1;
05232             } else if (!p->subs[SUB_THREEWAY].owner) {
05233                if (!p->threewaycalling) {
05234                   /* Just send a flash if no 3-way calling */
05235                   p->subs[SUB_REAL].needflash = 1;
05236                   goto winkflashdone;
05237                } else if (!check_for_conference(p)) {
05238                   char cid_num[256];
05239                   char cid_name[256];
05240 
05241                   cid_num[0] = 0;
05242                   cid_name[0] = 0;
05243                   if (p->dahditrcallerid && p->owner) {
05244                      if (p->owner->cid.cid_num)
05245                         ast_copy_string(cid_num, p->owner->cid.cid_num, sizeof(cid_num));
05246                      if (p->owner->cid.cid_name)
05247                         ast_copy_string(cid_name, p->owner->cid.cid_name, sizeof(cid_name));
05248                   }
05249                   /* XXX This section needs much more error checking!!! XXX */
05250                   /* Start a 3-way call if feasible */
05251                   if (!((ast->pbx) ||
05252                         (ast->_state == AST_STATE_UP) ||
05253                         (ast->_state == AST_STATE_RING))) {
05254                      ast_debug(1, "Flash when call not up or ringing\n");
05255                      goto winkflashdone;
05256                   }
05257                   if (alloc_sub(p, SUB_THREEWAY)) {
05258                      ast_log(LOG_WARNING, "Unable to allocate three-way subchannel\n");
05259                      goto winkflashdone;
05260                   }
05261                   /* Make new channel */
05262                   chan = dahdi_new(p, AST_STATE_RESERVED, 0, SUB_THREEWAY, 0, 0);
05263                   if (p->dahditrcallerid) {
05264                      if (!p->origcid_num)
05265                         p->origcid_num = ast_strdup(p->cid_num);
05266                      if (!p->origcid_name)
05267                         p->origcid_name = ast_strdup(p->cid_name);
05268                      ast_copy_string(p->cid_num, cid_num, sizeof(p->cid_num));
05269                      ast_copy_string(p->cid_name, cid_name, sizeof(p->cid_name));
05270                   }
05271                   /* Swap things around between the three-way and real call */
05272                   swap_subs(p, SUB_THREEWAY, SUB_REAL);
05273                   /* Disable echo canceller for better dialing */
05274                   dahdi_disable_ec(p);
05275                   res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_DIALRECALL);
05276                   if (res)
05277                      ast_log(LOG_WARNING, "Unable to start dial recall tone on channel %d\n", p->channel);
05278                   p->owner = chan;
05279                   if (!chan) {
05280                      ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", p->channel);
05281                   } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
05282                      ast_log(LOG_WARNING, "Unable to start simple switch on channel %d\n", p->channel);
05283                      res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
05284                      dahdi_enable_ec(p);
05285                      ast_hangup(chan);
05286                   } else {
05287                      struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner);
05288                      int way3bridge = 0, cdr3way = 0;
05289                      
05290                      if (!other) {
05291                         other = ast_bridged_channel(p->subs[SUB_REAL].owner);
05292                      } else
05293                         way3bridge = 1;
05294                      
05295                      if (p->subs[SUB_THREEWAY].owner->cdr)
05296                         cdr3way = 1;
05297                      
05298                      ast_verb(3, "Started three way call on channel %d\n", p->channel);
05299 
05300                      /* Start music on hold if appropriate */
05301                      if (ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
05302                         ast_queue_control_data(p->subs[SUB_THREEWAY].owner, AST_CONTROL_HOLD,
05303                            S_OR(p->mohsuggest, NULL),
05304                            !ast_strlen_zero(p->mohsuggest) ? strlen(p->mohsuggest) + 1 : 0);
05305                      }
05306                      p->subs[SUB_THREEWAY].needhold = 1;
05307                   }
05308                }
05309             } else {
05310                /* Already have a 3 way call */
05311                if (p->subs[SUB_THREEWAY].inthreeway) {
05312                   /* Call is already up, drop the last person */
05313                   ast_debug(1, "Got flash with three way call up, dropping last call on %d\n", p->channel);
05314                   /* If the primary call isn't answered yet, use it */
05315                   if ((p->subs[SUB_REAL].owner->_state != AST_STATE_UP) && (p->subs[SUB_THREEWAY].owner->_state == AST_STATE_UP)) {
05316                      /* Swap back -- we're dropping the real 3-way that isn't finished yet*/
05317                      swap_subs(p, SUB_THREEWAY, SUB_REAL);
05318                      p->owner = p->subs[SUB_REAL].owner;
05319                   }
05320                   /* Drop the last call and stop the conference */
05321                   ast_verb(3, "Dropping three-way call on %s\n", p->subs[SUB_THREEWAY].owner->name);
05322                   p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
05323                   p->subs[SUB_REAL].inthreeway = 0;
05324                   p->subs[SUB_THREEWAY].inthreeway = 0;
05325                } else {
05326                   /* Lets see what we're up to */
05327                   if (((ast->pbx) || (ast->_state == AST_STATE_UP)) && 
05328                       (p->transfertobusy || (ast->_state != AST_STATE_BUSY))) {
05329                      int otherindex = SUB_THREEWAY;
05330                      struct ast_channel *other = ast_bridged_channel(p->subs[SUB_THREEWAY].owner);
05331                      int way3bridge = 0, cdr3way = 0;
05332                      
05333                      if (!other) {
05334                         other = ast_bridged_channel(p->subs[SUB_REAL].owner);
05335                      } else
05336                         way3bridge = 1;
05337                      
05338                      if (p->subs[SUB_THREEWAY].owner->cdr)
05339                         cdr3way = 1;
05340 
05341                      ast_verb(3, "Building conference on call on %s and %s\n", p->subs[SUB_THREEWAY].owner->name, p->subs[SUB_REAL].owner->name);
05342                      /* Put them in the threeway, and flip */
05343                      p->subs[SUB_THREEWAY].inthreeway = 1;
05344                      p->subs[SUB_REAL].inthreeway = 1;
05345                      if (ast->_state == AST_STATE_UP) {
05346                         swap_subs(p, SUB_THREEWAY, SUB_REAL);
05347                         otherindex = SUB_REAL;
05348                      }
05349                      if (p->subs[otherindex].owner && ast_bridged_channel(p->subs[otherindex].owner))
05350                         ast_queue_control(p->subs[otherindex].owner, AST_CONTROL_UNHOLD);
05351                      p->subs[otherindex].needunhold = 1;
05352                      p->owner = p->subs[SUB_REAL].owner;
05353                      if (ast->_state == AST_STATE_RINGING) {
05354                         ast_debug(1, "Enabling ringtone on real and threeway\n");
05355                         res = tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
05356                         res = tone_zone_play_tone(p->subs[SUB_THREEWAY].dfd, DAHDI_TONE_RINGTONE);
05357                      }
05358                   } else {
05359                      ast_verb(3, "Dumping incomplete call on on %s\n", p->subs[SUB_THREEWAY].owner->name);
05360                      swap_subs(p, SUB_THREEWAY, SUB_REAL);
05361                      p->subs[SUB_THREEWAY].owner->_softhangup |= AST_SOFTHANGUP_DEV;
05362                      p->owner = p->subs[SUB_REAL].owner;
05363                      if (p->subs[SUB_REAL].owner && ast_bridged_channel(p->subs[SUB_REAL].owner))
05364                         ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
05365                      p->subs[SUB_REAL].needunhold = 1;
05366                      dahdi_enable_ec(p);
05367                   }
05368                      
05369                }
05370             }
05371          winkflashdone:              
05372             update_conf(p);
05373             break;
05374          case SIG_EM:
05375          case SIG_EM_E1:
05376          case SIG_FEATD:
05377          case SIG_SF:
05378          case SIG_SFWINK:
05379          case SIG_SF_FEATD:
05380          case SIG_FXSLS:
05381          case SIG_FXSGS:
05382             if (option_debug) {
05383                if (p->dialing)
05384                   ast_debug(1, "Ignoring wink on channel %d\n", p->channel);
05385                else
05386                   ast_debug(1, "Got wink in weird state %d on channel %d\n", ast->_state, p->channel);
05387             }
05388             break;
05389          case SIG_FEATDMF_TA:
05390             switch (p->whichwink) {
05391             case 0:
05392                ast_debug(1, "ANI2 set to '%d' and ANI is '%s'\n", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
05393                snprintf(p->dop.dialstr, sizeof(p->dop.dialstr), "M*%d%s#", p->owner->cid.cid_ani2, p->owner->cid.cid_ani);
05394                break;
05395             case 1:
05396                ast_copy_string(p->dop.dialstr, p->finaldial, sizeof(p->dop.dialstr));
05397                break;
05398             case 2:
05399                ast_log(LOG_WARNING, "Received unexpected wink on channel of type SIG_FEATDMF_TA\n");
05400                return NULL;
05401             }
05402             p->whichwink++;
05403             /* Fall through */
05404          case SIG_FEATDMF:
05405          case SIG_E911:
05406          case SIG_FGC_CAMAMF:
05407          case SIG_FGC_CAMA:
05408          case SIG_FEATB:
05409          case SIG_SF_FEATDMF:
05410          case SIG_SF_FEATB:
05411          case SIG_EMWINK:
05412             /* FGD MF and EMWINK *Must* wait for wink */
05413             if (!ast_strlen_zero(p->dop.dialstr)) {
05414                res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
05415                if (res < 0) {
05416                   ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
05417                   p->dop.dialstr[0] = '\0';
05418                   return NULL;
05419                } else 
05420                   ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
05421             }
05422             p->dop.dialstr[0] = '\0';
05423             break;
05424          default:
05425             ast_log(LOG_WARNING, "Don't know how to handle ring/off hook for signalling %d\n", p->sig);
05426          }
05427          break;
05428       case DAHDI_EVENT_HOOKCOMPLETE:
05429          if (p->inalarm) break;
05430          if ((p->radio || (p->oprmode < 0))) break;
05431          switch (mysig) {
05432          case SIG_FXSLS:  /* only interesting for FXS */
05433          case SIG_FXSGS:
05434          case SIG_FXSKS:
05435          case SIG_EM:
05436          case SIG_EM_E1:
05437          case SIG_EMWINK:
05438          case SIG_FEATD:
05439          case SIG_SF:
05440          case SIG_SFWINK:
05441          case SIG_SF_FEATD:
05442             if (!ast_strlen_zero(p->dop.dialstr)) {
05443                res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_DIAL, &p->dop);
05444                if (res < 0) {
05445                   ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", p->channel, strerror(errno));
05446                   p->dop.dialstr[0] = '\0';
05447                   return NULL;
05448                } else 
05449                   ast_debug(1, "Sent deferred digit string: %s\n", p->dop.dialstr);
05450             }
05451             p->dop.dialstr[0] = '\0';
05452             p->dop.op = DAHDI_DIAL_OP_REPLACE;
05453             break;
05454          case SIG_FEATDMF:
05455          case SIG_FEATDMF_TA:
05456          case SIG_E911:
05457          case SIG_FGC_CAMA:
05458          case SIG_FGC_CAMAMF:
05459          case SIG_FEATB:
05460          case SIG_SF_FEATDMF:
05461          case SIG_SF_FEATB:
05462             ast_debug(1, "Got hook complete in MF FGD, waiting for wink now on channel %d\n",p->channel);
05463             break;
05464          default:
05465             break;
05466          }
05467          break;
05468       case DAHDI_EVENT_POLARITY:
05469          /*
05470           * If we get a Polarity Switch event, this could be
05471           * due to line seizure, remote end connect or remote end disconnect.
05472           *
05473           * Check to see if we should change the polarity state and
05474           * mark the channel as UP or if this is an indication
05475           * of remote end disconnect.
05476           */
05477 
05478          if (p->polarityonanswerdelay > 0) {
05479             /* check if event is not too soon after OffHook or Answer */
05480                if (ast_tvdiff_ms(ast_tvnow(), p->polaritydelaytv) > p->polarityonanswerdelay) {
05481                switch (ast->_state) {
05482                case AST_STATE_DIALING:       /*!< Digits (or equivalent) have been dialed */
05483                case AST_STATE_RINGING:       /*!< Remote end is ringing */
05484                   if (p->answeronpolarityswitch) {
05485                      ast_debug(1, "Answering on polarity switch! channel %d\n", p->channel);
05486                      ast_setstate(p->owner, AST_STATE_UP);
05487                      p->polarity = POLARITY_REV;
05488                      if (p->hanguponpolarityswitch) {
05489                         p->polaritydelaytv = ast_tvnow();
05490                      }
05491                   } else {
05492                      ast_debug(1, "Ignore Answer on polarity switch, channel %d\n", p->channel);
05493                   }
05494                   break;
05495                case AST_STATE_UP:         /*!< Line is up */
05496                case AST_STATE_RING:       /*!< Line is ringing */
05497                   if (p->hanguponpolarityswitch) {
05498                      ast_debug(1, "HangingUp on polarity switch! channel %d\n", p->channel);
05499                      ast_softhangup(p->owner, AST_SOFTHANGUP_EXPLICIT);
05500                      p->polarity = POLARITY_IDLE;
05501                   } else {
05502                      ast_debug(1, "Ignore Hangup on polarity switch, channel %d\n", p->channel);
05503                   }
05504                   break;
05505 
05506                case AST_STATE_DOWN:       /*!< Channel is down and available */
05507                case AST_STATE_RESERVED:      /*!< Channel is down, but reserved */
05508                case AST_STATE_OFFHOOK:       /*!< Channel is off hook */
05509                case AST_STATE_BUSY:       /*!< Line is busy */
05510                case AST_STATE_DIALING_OFFHOOK:     /*!< Digits (or equivalent) have been dialed while offhook */
05511                case AST_STATE_PRERING:       /*!< Channel has detected an incoming call and is waiting for ring */
05512                default:
05513                   if (p->answeronpolarityswitch || p->hanguponpolarityswitch) {
05514                      ast_debug(1, "Ignoring Polarity switch on channel %d, state %d\n", p->channel, ast->_state);
05515                   }
05516 
05517                }
05518 
05519             } else {
05520                /* event is too soon after OffHook or Answer */
05521                switch (ast->_state) {
05522                case AST_STATE_DIALING:       /*!< Digits (or equivalent) have been dialed */
05523                case AST_STATE_RINGING:       /*!< Remote end is ringing */
05524                   if (p->answeronpolarityswitch) {
05525                      ast_debug(1, "Polarity switch detected but NOT answering (too close to OffHook event) on channel %d, state %d\n", p->channel, ast->_state);
05526                   }
05527                   break;
05528 
05529                case AST_STATE_UP:         /*!< Line is up */
05530                case AST_STATE_RING:       /*!< Line is ringing */
05531                   if (p->hanguponpolarityswitch) {
05532                      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);
05533                   }
05534                   break;
05535 
05536                default: 
05537                   if (p->answeronpolarityswitch || p->hanguponpolarityswitch) {
05538                      ast_debug(1, "Polarity switch detected (too close to previous event) on channel %d, state %d\n", p->channel, ast->_state);
05539                   }
05540                }
05541             }
05542          }
05543                         /* Added more log_debug information below to provide a better indication of what is going on */
05544          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) );
05545          break;
05546       default:
05547          ast_debug(1, "Dunno what to do with event %d on channel %d\n", res, p->channel);
05548    }
05549    return &p->subs[idx].f;
05550 }
05551 
05552 static struct ast_frame *__dahdi_exception(struct ast_channel *ast)
05553 {
05554    struct dahdi_pvt *p = ast->tech_pvt;
05555    int res;
05556    int usedindex=-1;
05557    int idx;
05558    struct ast_frame *f;
05559 
05560 
05561    idx = dahdi_get_index(ast, p, 1);
05562    
05563    p->subs[idx].f.frametype = AST_FRAME_NULL;
05564    p->subs[idx].f.datalen = 0;
05565    p->subs[idx].f.samples = 0;
05566    p->subs[idx].f.mallocd = 0;
05567    p->subs[idx].f.offset = 0;
05568    p->subs[idx].f.subclass = 0;
05569    p->subs[idx].f.delivery = ast_tv(0,0);
05570    p->subs[idx].f.src = "dahdi_exception";
05571    p->subs[idx].f.data.ptr = NULL;
05572    
05573    
05574    if ((!p->owner) && (!(p->radio || (p->oprmode < 0)))) {
05575       /* If nobody owns us, absorb the event appropriately, otherwise
05576          we loop indefinitely.  This occurs when, during call waiting, the
05577          other end hangs up our channel so that it no longer exists, but we
05578          have neither FLASH'd nor ONHOOK'd to signify our desire to
05579          change to the other channel. */
05580       if (p->fake_event) {
05581          res = p->fake_event;
05582          p->fake_event = 0;
05583       } else
05584          res = dahdi_get_event(p->subs[SUB_REAL].dfd);
05585       /* Switch to real if there is one and this isn't something really silly... */
05586       if ((res != DAHDI_EVENT_RINGEROFF) && (res != DAHDI_EVENT_RINGERON) &&
05587          (res != DAHDI_EVENT_HOOKCOMPLETE)) {
05588          ast_debug(1, "Restoring owner of channel %d on event %d\n", p->channel, res);
05589          p->owner = p->subs[SUB_REAL].owner;
05590          if (p->owner && ast_bridged_channel(p->owner))
05591             ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
05592          p->subs[SUB_REAL].needunhold = 1;
05593       }
05594       switch (res) {
05595       case DAHDI_EVENT_ONHOOK:
05596          dahdi_disable_ec(p);
05597          if (p->owner) {
05598             ast_verb(3, "Channel %s still has call, ringing phone\n", p->owner->name);
05599             dahdi_ring_phone(p);
05600             p->callwaitingrepeat = 0;
05601             p->cidcwexpire = 0;
05602          } else
05603             ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
05604          update_conf(p);
05605          break;
05606       case DAHDI_EVENT_RINGOFFHOOK:
05607          dahdi_enable_ec(p);
05608          dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
05609          if (p->owner && (p->owner->_state == AST_STATE_RINGING)) {
05610             p->subs[SUB_REAL].needanswer = 1;
05611             p->dialing = 0;
05612          }
05613          break;
05614       case DAHDI_EVENT_HOOKCOMPLETE:
05615       case DAHDI_EVENT_RINGERON:
05616       case DAHDI_EVENT_RINGEROFF:
05617          /* Do nothing */
05618          break;
05619       case DAHDI_EVENT_WINKFLASH:
05620          p->flashtime = ast_tvnow();
05621          if (p->owner) {
05622             ast_verb(3, "Channel %d flashed to other channel %s\n", p->channel, p->owner->name);
05623             if (p->owner->_state != AST_STATE_UP) {
05624                /* Answer if necessary */
05625                usedindex = dahdi_get_index(p->owner, p, 0);
05626                if (usedindex > -1) {
05627                   p->subs[usedindex].needanswer = 1;
05628                }
05629                ast_setstate(p->owner, AST_STATE_UP);
05630             }
05631             p->callwaitingrepeat = 0;
05632             p->cidcwexpire = 0;
05633             if (ast_bridged_channel(p->owner))
05634                ast_queue_control(p->owner, AST_CONTROL_UNHOLD);
05635             p->subs[SUB_REAL].needunhold = 1;
05636          } else
05637             ast_log(LOG_WARNING, "Absorbed on hook, but nobody is left!?!?\n");
05638          update_conf(p);
05639          break;
05640       default:
05641          ast_log(LOG_WARNING, "Don't know how to absorb event %s\n", event2str(res));
05642       }
05643       f = &p->subs[idx].f;
05644       return f;
05645    }
05646    if (!(p->radio || (p->oprmode < 0))) 
05647       ast_debug(1, "Exception on %d, channel %d\n", ast->fds[0],p->channel);
05648    /* If it's not us, return NULL immediately */
05649    if (ast != p->owner) {
05650       ast_log(LOG_WARNING, "We're %s, not %s\n", ast->name, p->owner->name);
05651       f = &p->subs[idx].f;
05652       return f;
05653    }
05654    f = dahdi_handle_event(ast);
05655    return f;
05656 }
05657 
05658 static struct ast_frame *dahdi_exception(struct ast_channel *ast)
05659 {
05660    struct dahdi_pvt *p = ast->tech_pvt;
05661    struct ast_frame *f;
05662    ast_mutex_lock(&p->lock);
05663    f = __dahdi_exception(ast);
05664    ast_mutex_unlock(&p->lock);
05665    return f;
05666 }
05667 
05668 static struct ast_frame  *dahdi_read(struct ast_channel *ast)
05669 {
05670    struct dahdi_pvt *p = ast->tech_pvt;
05671    int res;
05672    int idx;
05673    void *readbuf;
05674    struct ast_frame *f;
05675 
05676    while (ast_mutex_trylock(&p->lock)) {
05677       CHANNEL_DEADLOCK_AVOIDANCE(ast);
05678    }
05679 
05680    idx = dahdi_get_index(ast, p, 0);
05681    
05682    /* Hang up if we don't really exist */
05683    if (idx < 0)   {
05684       ast_log(LOG_WARNING, "We dont exist?\n");
05685       ast_mutex_unlock(&p->lock);
05686       return NULL;
05687    }
05688    
05689    if ((p->radio || (p->oprmode < 0)) && p->inalarm) {
05690       ast_mutex_unlock(&p->lock);
05691       return NULL;
05692    }
05693 
05694    p->subs[idx].f.frametype = AST_FRAME_NULL;
05695    p->subs[idx].f.datalen = 0;
05696    p->subs[idx].f.samples = 0;
05697    p->subs[idx].f.mallocd = 0;
05698    p->subs[idx].f.offset = 0;
05699    p->subs[idx].f.subclass = 0;
05700    p->subs[idx].f.delivery = ast_tv(0,0);
05701    p->subs[idx].f.src = "dahdi_read";
05702    p->subs[idx].f.data.ptr = NULL;
05703    
05704    /* make sure it sends initial key state as first frame */
05705    if ((p->radio || (p->oprmode < 0)) && (!p->firstradio))
05706    {
05707       struct dahdi_params ps;
05708 
05709       memset(&ps, 0, sizeof(ps));
05710       ps.channo = p->channel;
05711       if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
05712          ast_mutex_unlock(&p->lock);
05713          return NULL;
05714       }
05715       p->firstradio = 1;
05716       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05717       if (ps.rxisoffhook)
05718       {
05719          p->subs[idx].f.subclass = AST_CONTROL_RADIO_KEY;
05720       }
05721       else
05722       {
05723          p->subs[idx].f.subclass = AST_CONTROL_RADIO_UNKEY;
05724       }
05725       ast_mutex_unlock(&p->lock);
05726       return &p->subs[idx].f;
05727    }
05728    if (p->ringt == 1) {
05729       ast_mutex_unlock(&p->lock);
05730       return NULL;
05731    }
05732    else if (p->ringt > 0) 
05733       p->ringt--;
05734 
05735    if (p->subs[idx].needringing) {
05736       /* Send ringing frame if requested */
05737       p->subs[idx].needringing = 0;
05738       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05739       p->subs[idx].f.subclass = AST_CONTROL_RINGING;
05740       ast_setstate(ast, AST_STATE_RINGING);
05741       ast_mutex_unlock(&p->lock);
05742       return &p->subs[idx].f;
05743    }
05744 
05745    if (p->subs[idx].needbusy) {
05746       /* Send busy frame if requested */
05747       p->subs[idx].needbusy = 0;
05748       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05749       p->subs[idx].f.subclass = AST_CONTROL_BUSY;
05750       ast_mutex_unlock(&p->lock);
05751       return &p->subs[idx].f;
05752    }
05753 
05754    if (p->subs[idx].needcongestion) {
05755       /* Send congestion frame if requested */
05756       p->subs[idx].needcongestion = 0;
05757       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05758       p->subs[idx].f.subclass = AST_CONTROL_CONGESTION;
05759       ast_mutex_unlock(&p->lock);
05760       return &p->subs[idx].f;
05761    }
05762 
05763    if (p->subs[idx].needcallerid) {
05764       ast_set_callerid(ast, S_OR(p->lastcid_num, NULL),
05765                      S_OR(p->lastcid_name, NULL),
05766                      S_OR(p->lastcid_num, NULL)
05767                      );
05768       p->subs[idx].needcallerid = 0;
05769    }
05770    
05771    if (p->subs[idx].needanswer) {
05772       /* Send answer frame if requested */
05773       p->subs[idx].needanswer = 0;
05774       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05775       p->subs[idx].f.subclass = AST_CONTROL_ANSWER;
05776       ast_mutex_unlock(&p->lock);
05777       return &p->subs[idx].f;
05778    }  
05779    
05780    if (p->subs[idx].needflash) {
05781       /* Send answer frame if requested */
05782       p->subs[idx].needflash = 0;
05783       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05784       p->subs[idx].f.subclass = AST_CONTROL_FLASH;
05785       ast_mutex_unlock(&p->lock);
05786       return &p->subs[idx].f;
05787    }  
05788    
05789    if (p->subs[idx].needhold) {
05790       /* Send answer frame if requested */
05791       p->subs[idx].needhold = 0;
05792       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05793       p->subs[idx].f.subclass = AST_CONTROL_HOLD;
05794       ast_mutex_unlock(&p->lock);
05795       ast_debug(1, "Sending hold on '%s'\n", ast->name);
05796       return &p->subs[idx].f;
05797    }  
05798    
05799    if (p->subs[idx].needunhold) {
05800       /* Send answer frame if requested */
05801       p->subs[idx].needunhold = 0;
05802       p->subs[idx].f.frametype = AST_FRAME_CONTROL;
05803       p->subs[idx].f.subclass = AST_CONTROL_UNHOLD;
05804       ast_mutex_unlock(&p->lock);
05805       ast_debug(1, "Sending unhold on '%s'\n", ast->name);
05806       return &p->subs[idx].f;
05807    }  
05808    
05809    if (ast->rawreadformat == AST_FORMAT_SLINEAR) {
05810       if (!p->subs[idx].linear) {
05811          p->subs[idx].linear = 1;
05812          res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
05813          if (res) 
05814             ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to linear mode.\n", p->channel, idx);
05815       }
05816    } else if ((ast->rawreadformat == AST_FORMAT_ULAW) ||
05817          (ast->rawreadformat == AST_FORMAT_ALAW)) {
05818       if (p->subs[idx].linear) {
05819          p->subs[idx].linear = 0;
05820          res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
05821          if (res) 
05822             ast_log(LOG_WARNING, "Unable to set channel %d (index %d) to companded mode.\n", p->channel, idx);
05823       }
05824    } else {
05825       ast_log(LOG_WARNING, "Don't know how to read frames in format %s\n", ast_getformatname(ast->rawreadformat));
05826       ast_mutex_unlock(&p->lock);
05827       return NULL;
05828    }
05829    readbuf = ((unsigned char *)p->subs[idx].buffer) + AST_FRIENDLY_OFFSET;
05830    CHECK_BLOCKING(ast);
05831    res = read(p->subs[idx].dfd, readbuf, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
05832    ast_clear_flag(ast, AST_FLAG_BLOCKING);
05833    /* Check for hangup */
05834    if (res < 0) {
05835       f = NULL;
05836       if (res == -1)  {
05837          if (errno == EAGAIN) {
05838             /* Return "NULL" frame if there is nobody there */
05839             ast_mutex_unlock(&p->lock);
05840             return &p->subs[idx].f;
05841          } else if (errno == ELAST) {
05842             f = __dahdi_exception(ast);
05843          } else
05844             ast_log(LOG_WARNING, "dahdi_rec: %s\n", strerror(errno));
05845       }
05846       ast_mutex_unlock(&p->lock);
05847       return f;
05848    }
05849    if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
05850       ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
05851       f = __dahdi_exception(ast);
05852       ast_mutex_unlock(&p->lock);
05853       return f;
05854    }
05855    if (p->tdd) { /* if in TDD mode, see if we receive that */
05856       int c;
05857 
05858       c = tdd_feed(p->tdd,readbuf,READ_SIZE);
05859       if (c < 0) {
05860          ast_debug(1,"tdd_feed failed\n");
05861          ast_mutex_unlock(&p->lock);
05862          return NULL;
05863       }
05864       if (c) { /* if a char to return */
05865          p->subs[idx].f.subclass = 0;
05866          p->subs[idx].f.frametype = AST_FRAME_TEXT;
05867          p->subs[idx].f.mallocd = 0;
05868          p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
05869          p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET;
05870          p->subs[idx].f.datalen = 1;
05871          *((char *) p->subs[idx].f.data.ptr) = c;
05872          ast_mutex_unlock(&p->lock);
05873          return &p->subs[idx].f;
05874       }
05875    }
05876    /* Ensure the CW timer decrements only on a single subchannel */
05877    if (p->callwaitingrepeat && dahdi_get_index(ast, p, 1) == SUB_REAL) {
05878       p->callwaitingrepeat--;
05879    }
05880    if (p->cidcwexpire)
05881       p->cidcwexpire--;
05882    /* Repeat callwaiting */
05883    if (p->callwaitingrepeat == 1) {
05884       p->callwaitrings++;
05885       dahdi_callwait(ast);
05886    }
05887    /* Expire CID/CW */
05888    if (p->cidcwexpire == 1) {
05889       ast_verb(3, "CPE does not support Call Waiting Caller*ID.\n");
05890       restore_conference(p);
05891    }
05892    if (p->subs[idx].linear) {
05893       p->subs[idx].f.datalen = READ_SIZE * 2;
05894    } else 
05895       p->subs[idx].f.datalen = READ_SIZE;
05896 
05897    /* Handle CallerID Transmission */
05898    if ((p->owner == ast) && p->cidspill &&((ast->_state == AST_STATE_UP) || (ast->rings == p->cidrings))) {
05899       send_callerid(p);
05900    }
05901 
05902    p->subs[idx].f.frametype = AST_FRAME_VOICE;
05903    p->subs[idx].f.subclass = ast->rawreadformat;
05904    p->subs[idx].f.samples = READ_SIZE;
05905    p->subs[idx].f.mallocd = 0;
05906    p->subs[idx].f.offset = AST_FRIENDLY_OFFSET;
05907    p->subs[idx].f.data.ptr = p->subs[idx].buffer + AST_FRIENDLY_OFFSET / sizeof(p->subs[idx].buffer[0]);
05908 #if 0
05909    ast_debug(1, "Read %d of voice on %s\n", p->subs[idx].f.datalen, ast->name);
05910 #endif   
05911    if (p->dialing || /* Transmitting something */
05912       (idx && (ast->_state != AST_STATE_UP)) || /* Three-way or callwait that isn't up */
05913       ((idx == SUB_CALLWAIT) && !p->subs[SUB_CALLWAIT].inthreeway) /* Inactive and non-confed call-wait */
05914       ) {
05915       /* Whoops, we're still dialing, or in a state where we shouldn't transmit....
05916          don't send anything */
05917       p->subs[idx].f.frametype = AST_FRAME_NULL;
05918       p->subs[idx].f.subclass = 0;
05919       p->subs[idx].f.samples = 0;
05920       p->subs[idx].f.mallocd = 0;
05921       p->subs[idx].f.offset = 0;
05922       p->subs[idx].f.data.ptr = NULL;
05923       p->subs[idx].f.datalen= 0;
05924    }
05925    if (p->dsp && (!p->ignoredtmf || p->callwaitcas || p->busydetect  || p->callprogress) && !idx) {
05926       /* Perform busy detection. etc on the dahdi line */
05927       int mute;
05928 
05929       f = ast_dsp_process(ast, p->dsp, &p->subs[idx].f);
05930 
05931       /* Check if DSP code thinks we should be muting this frame and mute the conference if so */
05932       mute = ast_dsp_was_muted(p->dsp);
05933       if (p->muting != mute) {
05934          p->muting = mute;
05935          dahdi_confmute(p, mute);
05936       }
05937 
05938       if (f) {
05939          if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_BUSY)) {
05940             if ((ast->_state == AST_STATE_UP) && !p->outgoing) {
05941                /* Treat this as a "hangup" instead of a "busy" on the assumption that
05942                   a busy  */
05943                f = NULL;
05944             }
05945          } else if (f->frametype == AST_FRAME_DTMF) {
05946 #ifdef HAVE_PRI
05947             if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) && p->pri && 
05948                 ((!p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) ||
05949                  (p->outgoing && (p->pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)))) {
05950                /* Don't accept in-band DTMF when in overlap dial mode */
05951                f->frametype = AST_FRAME_NULL;
05952                f->subclass = 0;
05953             }
05954 #endif            
05955             /* DSP clears us of being pulse */
05956             p->pulsedial = 0;
05957          }
05958       }
05959    } else 
05960       f = &p->subs[idx].f; 
05961 
05962    if (f && (f->frametype == AST_FRAME_DTMF))
05963       dahdi_handle_dtmfup(ast, idx, &f);
05964 
05965    /* If we have a fake_event, trigger exception to handle it */
05966    if (p->fake_event)
05967       ast_set_flag(ast, AST_FLAG_EXCEPTION);
05968 
05969    ast_mutex_unlock(&p->lock);
05970    return f;
05971 }
05972 
05973 static int my_dahdi_write(struct dahdi_pvt *p, unsigned char *buf, int len, int idx, int linear)
05974 {
05975    int sent=0;
05976    int size;
05977    int res;
05978    int fd;
05979    fd = p->subs[idx].dfd;
05980    while (len) {
05981       size = len;
05982       if (size > (linear ? READ_SIZE * 2 : READ_SIZE))
05983          size = (linear ? READ_SIZE * 2 : READ_SIZE);
05984       res = write(fd, buf, size);
05985       if (res != size) {
05986          ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
05987          return sent;
05988       }
05989       len -= size;
05990       buf += size;
05991    }
05992    return sent;
05993 }
05994 
05995 static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
05996 {
05997    struct dahdi_pvt *p = ast->tech_pvt;
05998    int res;
05999    int idx;
06000    idx = dahdi_get_index(ast, p, 0);
06001    if (idx < 0) {
06002       ast_log(LOG_WARNING, "%s doesn't really exist?\n", ast->name);
06003       return -1;
06004    }
06005 
06006 #if 0
06007 #ifdef HAVE_PRI
06008    ast_mutex_lock(&p->lock);
06009    if (!p->proceeding && p->sig==SIG_PRI && p->pri && !p->outgoing) {
06010       if (p->pri->pri) {      
06011          if (!pri_grab(p, p->pri)) {
06012                pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
06013                pri_rel(p->pri);
06014          } else
06015                ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06016       }
06017       p->proceeding=1;
06018    }
06019    ast_mutex_unlock(&p->lock);
06020 #endif
06021 #endif
06022    /* Write a frame of (presumably voice) data */
06023    if (frame->frametype != AST_FRAME_VOICE) {
06024       if (frame->frametype != AST_FRAME_IMAGE)
06025          ast_log(LOG_WARNING, "Don't know what to do with frame type '%d'\n", frame->frametype);
06026       return 0;
06027    }
06028    if ((frame->subclass != AST_FORMAT_SLINEAR) && 
06029        (frame->subclass != AST_FORMAT_ULAW) &&
06030        (frame->subclass != AST_FORMAT_ALAW)) {
06031       ast_log(LOG_WARNING, "Cannot handle frames in %d format\n", frame->subclass);
06032       return -1;
06033    }
06034    if (p->dialing) {
06035       ast_debug(1, "Dropping frame since I'm still dialing on %s...\n",ast->name);
06036       return 0;
06037    }
06038    if (!p->owner) {
06039       ast_debug(1, "Dropping frame since there is no active owner on %s...\n",ast->name);
06040       return 0;
06041    }
06042    if (p->cidspill) {
06043       ast_debug(1, "Dropping frame since I've still got a callerid spill\n");
06044       return 0;
06045    }
06046    /* Return if it's not valid data */
06047    if (!frame->data.ptr || !frame->datalen)
06048       return 0;
06049 
06050    if (frame->subclass == AST_FORMAT_SLINEAR) {
06051       if (!p->subs[idx].linear) {
06052          p->subs[idx].linear = 1;
06053          res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
06054          if (res)
06055             ast_log(LOG_WARNING, "Unable to set linear mode on channel %d\n", p->channel);
06056       }
06057       res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 1);
06058    } else {
06059       /* x-law already */
06060       if (p->subs[idx].linear) {
06061          p->subs[idx].linear = 0;
06062          res = dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
06063          if (res)
06064             ast_log(LOG_WARNING, "Unable to set companded mode on channel %d\n", p->channel);
06065       }
06066       res = my_dahdi_write(p, (unsigned char *)frame->data.ptr, frame->datalen, idx, 0);
06067    }
06068    if (res < 0) {
06069       ast_log(LOG_WARNING, "write failed: %s\n", strerror(errno));
06070       return -1;
06071    } 
06072    return 0;
06073 }
06074 
06075 static int dahdi_indicate(struct ast_channel *chan, int condition, const void *data, size_t datalen)
06076 {
06077    struct dahdi_pvt *p = chan->tech_pvt;
06078    int res=-1;
06079    int idx;
06080    int func = DAHDI_FLASH;
06081    ast_mutex_lock(&p->lock);
06082    idx = dahdi_get_index(chan, p, 0);
06083    ast_debug(1, "Requested indication %d on channel %s\n", condition, chan->name);
06084    if (idx == SUB_REAL) {
06085       switch (condition) {
06086       case AST_CONTROL_BUSY:
06087 #ifdef HAVE_PRI
06088          if (p->priindication_oob && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))) {
06089             chan->hangupcause = AST_CAUSE_USER_BUSY;
06090             chan->_softhangup |= AST_SOFTHANGUP_DEV;
06091             res = 0;
06092          } else if (!p->progress && 
06093                ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
06094                && p->pri && !p->outgoing) {
06095             if (p->pri->pri) {      
06096                if (!pri_grab(p, p->pri)) {
06097                   pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
06098                   pri_rel(p->pri);
06099                }
06100                else
06101                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06102             }
06103             p->progress = 1;
06104             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY);
06105          } else
06106 #endif
06107             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_BUSY);
06108          break;
06109       case AST_CONTROL_RINGING:
06110 #ifdef HAVE_PRI
06111          if ((!p->alerting) && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) 
06112                && p->pri && !p->outgoing && (chan->_state != AST_STATE_UP)) {
06113             if (p->pri->pri) {      
06114                if (!pri_grab(p, p->pri)) {
06115                   pri_acknowledge(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
06116                   pri_rel(p->pri);
06117                }
06118                else
06119                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06120             }
06121             p->alerting = 1;
06122          }
06123 
06124 #endif
06125 #ifdef HAVE_SS7
06126          if ((!p->alerting) && (p->sig == SIG_SS7) && p->ss7 && !p->outgoing && (chan->_state != AST_STATE_UP)) {
06127             if (p->ss7->ss7) {
06128                ss7_grab(p, p->ss7);
06129                
06130                if ((isup_far(p->ss7->ss7, p->ss7call)) != -1)
06131                   p->rlt = 1;
06132                if (p->rlt != 1) /* No need to send CPG if call will be RELEASE */
06133                   isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_ALERTING);
06134                p->alerting = 1;
06135                ss7_rel(p->ss7);
06136             }
06137          }
06138 #endif
06139             
06140          res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_RINGTONE);
06141          
06142          if (chan->_state != AST_STATE_UP) {
06143             if ((chan->_state != AST_STATE_RING) ||
06144                ((p->sig != SIG_FXSKS) &&
06145              (p->sig != SIG_FXSLS) &&
06146              (p->sig != SIG_FXSGS)))
06147             ast_setstate(chan, AST_STATE_RINGING);
06148          }
06149          break;
06150       case AST_CONTROL_PROCEEDING:
06151          ast_debug(1,"Received AST_CONTROL_PROCEEDING on %s\n",chan->name);
06152 #ifdef HAVE_PRI
06153          if (!p->proceeding && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
06154                && p->pri && !p->outgoing) {
06155             if (p->pri->pri) {      
06156                if (!pri_grab(p, p->pri)) {
06157                   pri_proceeding(p->pri->pri,p->call, PVT_TO_CHANNEL(p), !p->digital);
06158                   pri_rel(p->pri);
06159                }
06160                else
06161                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06162             }
06163             p->proceeding = 1;
06164             p->dialing = 0;
06165          }
06166 #endif
06167 #ifdef HAVE_SS7
06168          /* This IF sends the FAR for an answered ALEG call */
06169          if (chan->_state == AST_STATE_UP && (p->rlt != 1) && (p->sig == SIG_SS7)){
06170             if ((isup_far(p->ss7->ss7, p->ss7call)) != -1)
06171                p->rlt = 1; 
06172          }
06173             
06174          if (!p->proceeding && p->sig == SIG_SS7 && p->ss7 && !p->outgoing) {
06175             if (p->ss7->ss7) {
06176                ss7_grab(p, p->ss7);
06177                isup_acm(p->ss7->ss7, p->ss7call);
06178                p->proceeding = 1;
06179                ss7_rel(p->ss7);
06180 
06181             }
06182          }
06183 #endif
06184          /* don't continue in ast_indicate */
06185          res = 0;
06186          break;
06187       case AST_CONTROL_PROGRESS:
06188          ast_debug(1,"Received AST_CONTROL_PROGRESS on %s\n",chan->name);
06189 #ifdef HAVE_PRI
06190          p->digital = 0;   /* Digital-only calls isn't allows any inband progress messages */
06191          if (!p->progress && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))
06192                && p->pri && !p->outgoing) {
06193             if (p->pri->pri) {      
06194                if (!pri_grab(p, p->pri)) {
06195                   pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
06196                   pri_rel(p->pri);
06197                }
06198                else
06199                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06200             }
06201             p->progress = 1;
06202          }
06203 #endif
06204 #ifdef HAVE_SS7
06205          if (!p->progress && p->sig==SIG_SS7 && p->ss7 && !p->outgoing) {
06206             if (p->ss7->ss7) {
06207                ss7_grab(p, p->ss7);
06208                isup_cpg(p->ss7->ss7, p->ss7call, CPG_EVENT_INBANDINFO);
06209                p->progress = 1;
06210                ss7_rel(p->ss7);
06211                /* enable echo canceler here on SS7 calls */
06212                dahdi_enable_ec(p);
06213 
06214             }
06215          }
06216 #endif
06217          /* don't continue in ast_indicate */
06218          res = 0;
06219          break;
06220       case AST_CONTROL_CONGESTION:
06221          chan->hangupcause = AST_CAUSE_CONGESTION;
06222 #ifdef HAVE_PRI
06223          if (p->priindication_oob && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP))) {
06224             chan->hangupcause = AST_CAUSE_SWITCH_CONGESTION;
06225             chan->_softhangup |= AST_SOFTHANGUP_DEV;
06226             res = 0;
06227          } else if (!p->progress && ((p->sig == SIG_PRI) || (p->sig == SIG_BRI) || (p->sig == SIG_BRI_PTMP)) 
06228                && p->pri && !p->outgoing) {
06229             if (p->pri) {     
06230                if (!pri_grab(p, p->pri)) {
06231                   pri_progress(p->pri->pri,p->call, PVT_TO_CHANNEL(p), 1);
06232                   pri_rel(p->pri);
06233                } else
06234                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);
06235             }
06236             p->progress = 1;
06237             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06238          } else
06239 #endif
06240             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06241          break;
06242       case AST_CONTROL_HOLD:
06243 #ifdef HAVE_PRI
06244          if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
06245             if (!pri_grab(p, p->pri)) {
06246                res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_HOLD);
06247                pri_rel(p->pri);
06248             } else
06249                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);       
06250          } else
06251 #endif
06252             ast_moh_start(chan, data, p->mohinterpret);
06253          break;
06254       case AST_CONTROL_UNHOLD:
06255 #ifdef HAVE_PRI
06256          if (p->pri && !strcasecmp(p->mohinterpret, "passthrough")) {
06257             if (!pri_grab(p, p->pri)) {
06258                res = pri_notify(p->pri->pri, p->call, p->prioffset, PRI_NOTIFY_REMOTE_RETRIEVAL);
06259                pri_rel(p->pri);
06260             } else
06261                   ast_log(LOG_WARNING, "Unable to grab PRI on span %d\n", p->span);       
06262          } else
06263 #endif
06264             ast_moh_stop(chan);
06265          break;
06266       case AST_CONTROL_RADIO_KEY:
06267          if (p->radio) 
06268              res =  dahdi_set_hook(p->subs[idx].dfd, DAHDI_OFFHOOK);
06269          res = 0;
06270          break;
06271       case AST_CONTROL_RADIO_UNKEY:
06272          if (p->radio)
06273              res =  dahdi_set_hook(p->subs[idx].dfd, DAHDI_RINGOFF);
06274          res = 0;
06275          break;
06276       case AST_CONTROL_FLASH:
06277          /* flash hookswitch */
06278          if (ISTRUNK(p) && (p->sig != SIG_PRI)) {
06279             /* Clear out the dial buffer */
06280             p->dop.dialstr[0] = '\0';
06281             if ((ioctl(p->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
06282                ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n", 
06283                   chan->name, strerror(errno));
06284             } else
06285                res = 0;
06286          } else
06287             res = 0;
06288          break;
06289       case AST_CONTROL_SRCUPDATE:
06290          res = 0;
06291          break;
06292       case -1:
06293          res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06294          break;
06295       }
06296    } else
06297       res = 0;
06298    ast_mutex_unlock(&p->lock);
06299    return res;
06300 }
06301 
06302 static struct ast_channel *dahdi_new(struct dahdi_pvt *i, int state, int startpbx, int idx, int law, int transfercapability)
06303 {
06304    struct ast_channel *tmp;
06305    int deflaw;
06306    int res;
06307    int x,y;
06308    int features;
06309    struct ast_str *chan_name;
06310    struct ast_variable *v;
06311    struct dahdi_params ps;
06312    if (i->subs[idx].owner) {
06313       ast_log(LOG_WARNING, "Channel %d already has a %s call\n", i->channel,subnames[idx]);
06314       return NULL;
06315    }
06316    y = 1;
06317    chan_name = ast_str_alloca(32);
06318    do {
06319 #ifdef HAVE_PRI
06320       if (i->bearer || (i->pri && (i->sig == SIG_FXSKS)))
06321          ast_str_set(&chan_name, 0, "%d:%d-%d", i->pri->trunkgroup, i->channel, y);
06322       else
06323 #endif
06324       if (i->channel == CHAN_PSEUDO)
06325          ast_str_set(&chan_name, 0, "pseudo-%ld", ast_random());
06326       else  
06327          ast_str_set(&chan_name, 0, "%d-%d", i->channel, y);
06328       for (x = 0; x < 3; x++) {
06329          if ((idx != x) && i->subs[x].owner && !strcasecmp(chan_name->str, i->subs[x].owner->name + 6))
06330             break;
06331       }
06332       y++;
06333    } while (x < 3);
06334    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);
06335    if (!tmp)
06336       return NULL;
06337    tmp->tech = &dahdi_tech;
06338    memset(&ps, 0, sizeof(ps));
06339    ps.channo = i->channel;
06340    res = ioctl(i->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps);
06341    if (res) {
06342       ast_log(LOG_WARNING, "Unable to get parameters, assuming MULAW: %s\n", strerror(errno));
06343       ps.curlaw = DAHDI_LAW_MULAW;
06344    }
06345    if (ps.curlaw == DAHDI_LAW_ALAW)
06346       deflaw = AST_FORMAT_ALAW;
06347    else
06348       deflaw = AST_FORMAT_ULAW;
06349    if (law) {
06350       if (law == DAHDI_LAW_ALAW)
06351          deflaw = AST_FORMAT_ALAW;
06352       else
06353          deflaw = AST_FORMAT_ULAW;
06354    }
06355    ast_channel_set_fd(tmp, 0, i->subs[idx].dfd);
06356    tmp->nativeformats = deflaw;
06357    /* Start out assuming ulaw since it's smaller :) */
06358    tmp->rawreadformat = deflaw;
06359    tmp->readformat = deflaw;
06360    tmp->rawwriteformat = deflaw;
06361    tmp->writeformat = deflaw;
06362    i->subs[idx].linear = 0;
06363    dahdi_setlinear(i->subs[idx].dfd, i->subs[idx].linear);
06364    features = 0;
06365    if (idx == SUB_REAL) {
06366       if (i->busydetect && CANBUSYDETECT(i))
06367          features |= DSP_FEATURE_BUSY_DETECT;
06368       if ((i->callprogress & CALLPROGRESS_PROGRESS) && CANPROGRESSDETECT(i))
06369          features |= DSP_FEATURE_CALL_PROGRESS;
06370       if ((!i->outgoing && (i->callprogress & CALLPROGRESS_FAX_INCOMING)) || 
06371           (i->outgoing && (i->callprogress & CALLPROGRESS_FAX_OUTGOING))) {
06372          features |= DSP_FEATURE_FAX_DETECT;
06373       }
06374       x = DAHDI_TONEDETECT_ON | DAHDI_TONEDETECT_MUTE;
06375       if (ioctl(i->subs[idx].dfd, DAHDI_TONEDETECT, &x)) {
06376          i->hardwaredtmf = 0;
06377          features |= DSP_FEATURE_DIGIT_DETECT;
06378       } else if (NEED_MFDETECT(i)) {
06379          i->hardwaredtmf = 1;
06380          features |= DSP_FEATURE_DIGIT_DETECT;
06381       }
06382    }
06383    if (features) {
06384       if (i->dsp) {
06385          ast_debug(1, "Already have a dsp on %s?\n", tmp->name);
06386       } else {
06387          if (i->channel != CHAN_PSEUDO)
06388             i->dsp = ast_dsp_new();
06389          else
06390             i->dsp = NULL;
06391          if (i->dsp) {
06392             i->dsp_features = features;
06393 #if defined(HAVE_PRI) || defined(HAVE_SS7)
06394             /* We cannot do progress detection until receives PROGRESS message */
06395             if (i->outgoing && ((i->sig == SIG_PRI) || (i->sig == SIG_BRI) || (i->sig == SIG_BRI_PTMP) || (i->sig == SIG_SS7))) {
06396                /* Remember requested DSP features, don't treat
06397                   talking as ANSWER */
06398                i->dsp_features = features & ~DSP_PROGRESS_TALK;
06399                features = 0;
06400             }
06401 #endif
06402             ast_dsp_set_features(i->dsp, features);
06403             ast_dsp_set_digitmode(i->dsp, DSP_DIGITMODE_DTMF | i->dtmfrelax);
06404             if (!ast_strlen_zero(progzone))
06405                ast_dsp_set_call_progress_zone(i->dsp, progzone);
06406             if (i->busydetect && CANBUSYDETECT(i)) {
06407                ast_dsp_set_busy_count(i->dsp, i->busycount);
06408                ast_dsp_set_busy_pattern(i->dsp, i->busy_tonelength, i->busy_quietlength);
06409             }
06410          }
06411       }
06412    }
06413       
06414    if (state == AST_STATE_RING)
06415       tmp->rings = 1;
06416    tmp->tech_pvt = i;
06417    if ((i->sig == SIG_FXOKS) || (i->sig == SIG_FXOGS) || (i->sig == SIG_FXOLS)) {
06418       /* Only FXO signalled stuff can be picked up */
06419       tmp->callgroup = i->callgroup;
06420       tmp->pickupgroup = i->pickupgroup;
06421    }
06422    if (!ast_strlen_zero(i->parkinglot))
06423       ast_string_field_set(tmp, parkinglot, i->parkinglot);
06424    if (!ast_strlen_zero(i->language))
06425       ast_string_field_set(tmp, language, i->language);
06426    if (!i->owner)
06427       i->owner = tmp;
06428    if (!ast_strlen_zero(i->accountcode))
06429       ast_string_field_set(tmp, accountcode, i->accountcode);
06430    if (i->amaflags)
06431       tmp->amaflags = i->amaflags;
06432    i->subs[idx].owner = tmp;
06433    ast_copy_string(tmp->context, i->context, sizeof(tmp->context));
06434    ast_string_field_set(tmp, call_forward, i->call_forward);
06435    /* If we've been told "no ADSI" then enforce it */
06436    if (!i->adsi)
06437       tmp->adsicpe = AST_ADSI_UNAVAILABLE;
06438    if (!ast_strlen_zero(i->exten))
06439       ast_copy_string(tmp->exten, i->exten, sizeof(tmp->exten));
06440    if (!ast_strlen_zero(i->rdnis))
06441       tmp->cid.cid_rdnis = ast_strdup(i->rdnis);
06442    if (!ast_strlen_zero(i->dnid))
06443       tmp->cid.cid_dnid = ast_strdup(i->dnid);
06444 
06445    /* Don't use ast_set_callerid() here because it will
06446     * generate a needless NewCallerID event */
06447 #ifdef PRI_ANI
06448    if (!ast_strlen_zero(i->cid_ani))
06449       tmp->cid.cid_ani = ast_strdup(i->cid_ani);
06450    else  
06451       tmp->cid.cid_ani = ast_strdup(i->cid_num);
06452 #else
06453    tmp->cid.cid_ani = ast_strdup(i->cid_num);
06454 #endif
06455    tmp->cid.cid_pres = i->callingpres;
06456    tmp->cid.cid_ton = i->cid_ton;
06457    tmp->cid.cid_ani2 = i->cid_ani2;
06458 #if defined(HAVE_PRI) || defined(HAVE_SS7)
06459    tmp->transfercapability = transfercapability;
06460    pbx_builtin_setvar_helper(tmp, "TRANSFERCAPABILITY", ast_transfercapability2str(transfercapability));
06461    if (transfercapability & AST_TRANS_CAP_DIGITAL)
06462       i->digital = 1;
06463    /* Assume calls are not idle calls unless we're told differently */
06464    i->isidlecall = 0;
06465    i->alreadyhungup = 0;
06466 #endif
06467    /* clear the fake event in case we posted one before we had ast_channel */
06468    i->fake_event = 0;
06469    /* Assure there is no confmute on this channel */
06470    dahdi_confmute(i, 0);
06471    i->muting = 0;
06472    /* Configure the new channel jb */
06473    ast_jb_configure(tmp, &global_jbconf);
06474 
06475    ast_devstate_changed_literal(ast_state_chan2dev(state), tmp->name);
06476 
06477    for (v = i->vars ; v ; v = v->next)
06478                 pbx_builtin_setvar_helper(tmp, v->name, v->value);
06479 
06480    if (startpbx) {
06481       if (ast_pbx_start(tmp)) {
06482          ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
06483          ast_hangup(tmp);
06484          i->owner = NULL;
06485          return NULL;
06486       }
06487    }
06488 
06489    ast_module_ref(ast_module_info->self);
06490    return tmp;
06491 }
06492 
06493 
06494 static int my_getsigstr(struct ast_channel *chan, char *str, const char *term, int ms)
06495 {
06496    char c;
06497 
06498    *str = 0; /* start with empty output buffer */
06499    for (;;)
06500    {
06501       /* Wait for the first digit (up to specified ms). */
06502       c = ast_waitfordigit(chan, ms);
06503       /* if timeout, hangup or error, return as such */
06504       if (c < 1)
06505          return c;
06506       *str++ = c;
06507       *str = 0;
06508       if (strchr(term, c))
06509          return 1;
06510    }
06511 }
06512 
06513 static int dahdi_wink(struct dahdi_pvt *p, int idx)
06514 {
06515    int j;
06516    dahdi_set_hook(p->subs[idx].dfd, DAHDI_WINK);
06517    for (;;)
06518    {
06519          /* set bits of interest */
06520       j = DAHDI_IOMUX_SIGEVENT;
06521           /* wait for some happening */
06522       if (ioctl(p->subs[idx].dfd,DAHDI_IOMUX,&j) == -1) return(-1);
06523          /* exit loop if we have it */
06524       if (j & DAHDI_IOMUX_SIGEVENT) break;
06525    }
06526      /* get the event info */
06527    if (ioctl(p->subs[idx].dfd,DAHDI_GETEVENT,&j) == -1) return(-1);
06528    return 0;
06529 }
06530 
06531 /*! \brief enable or disable the chan_dahdi Do-Not-Disturb mode for a DAHDI channel
06532  * \param dahdichan "Physical" DAHDI channel (e.g: DAHDI/5)
06533  * \param on 1 to enable, 0 to disable
06534  *
06535  * chan_dahdi has a DND (Do Not Disturb) mode for each dahdichan (physical 
06536  * DAHDI channel). Use this to enable or disable it.
06537  *
06538  * \bug the use of the word "channel" for those dahdichans is really confusing.
06539  */
06540 static void dahdi_dnd(struct dahdi_pvt *dahdichan, int on)
06541 {
06542    /* Do not disturb */
06543    dahdichan->dnd = on;
06544    ast_verb(3, "%s DND on channel %d\n", 
06545          on? "Enabled" : "Disabled",
06546          dahdichan->channel);
06547    manager_event(EVENT_FLAG_SYSTEM, "DNDState",
06548          "Channel: DAHDI/%d\r\n"
06549          "Status: %s\r\n", dahdichan->channel,
06550          on? "enabled" : "disabled");
06551 }
06552 
06553 static void *ss_thread(void *data)
06554 {
06555    struct ast_channel *chan = data;
06556    struct dahdi_pvt *p = chan->tech_pvt;
06557    char exten[AST_MAX_EXTENSION] = "";
06558    char exten2[AST_MAX_EXTENSION] = "";
06559    unsigned char buf[256];
06560    char dtmfcid[300];
06561    char dtmfbuf[300];
06562    struct callerid_state *cs = NULL;
06563    char *name = NULL, *number = NULL;
06564    int distMatches;
06565    int curRingData[3];
06566    int receivedRingT;
06567    int counter1;
06568    int counter;
06569    int samples = 0;
06570    struct ast_smdi_md_message *smdi_msg = NULL;
06571    int flags = 0;
06572    int i;
06573    int timeout;
06574    int getforward = 0;
06575    char *s1, *s2;
06576    int len = 0;
06577    int res;
06578    int idx;
06579 
06580    ast_mutex_lock(&ss_thread_lock);
06581    ss_thread_count++;
06582    ast_mutex_unlock(&ss_thread_lock);
06583    /* in the bizarre case where the channel has become a zombie before we
06584       even get started here, abort safely
06585    */
06586    if (!p) {
06587       ast_log(LOG_WARNING, "Channel became a zombie before simple switch could be started (%s)\n", chan->name);
06588       ast_hangup(chan);
06589       goto quit;
06590    }
06591    ast_verb(3, "Starting simple switch on '%s'\n", chan->name);
06592    idx = dahdi_get_index(chan, p, 1);
06593    if (idx < 0) {
06594       ast_log(LOG_WARNING, "Huh?\n");
06595       ast_hangup(chan);
06596       goto quit;
06597    }
06598    if (p->dsp)
06599       ast_dsp_digitreset(p->dsp);
06600    switch (p->sig) {
06601 #ifdef HAVE_PRI
06602    case SIG_PRI:
06603    case SIG_BRI:
06604    case SIG_BRI_PTMP:
06605       /* Now loop looking for an extension */
06606       ast_copy_string(exten, p->exten, sizeof(exten));
06607       len = strlen(exten);
06608       res = 0;
06609       while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
06610          if (len && !ast_ignore_pattern(chan->context, exten))
06611             tone_zone_play_tone(p->subs[idx].dfd, -1);
06612          else
06613             tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
06614          if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num))
06615             timeout = matchdigittimeout;
06616          else
06617             timeout = gendigittimeout;
06618          res = ast_waitfordigit(chan, timeout);
06619          if (res < 0) {
06620             ast_debug(1, "waitfordigit returned < 0...\n");
06621             ast_hangup(chan);
06622             goto quit;
06623          } else if (res) {
06624             exten[len++] = res;
06625             exten[len] = '\0';
06626          } else
06627             break;
06628       }
06629       /* if no extension was received ('unspecified') on overlap call, use the 's' extension */
06630       if (ast_strlen_zero(exten)) {
06631          ast_verb(3, "Going to extension s|1 because of empty extension received on overlap call\n");
06632          exten[0] = 's';
06633          exten[1] = '\0';
06634       }
06635       tone_zone_play_tone(p->subs[idx].dfd, -1);
06636       if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num)) {
06637          /* Start the real PBX */
06638          ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06639          if (p->dsp) ast_dsp_digitreset(p->dsp);
06640          dahdi_enable_ec(p);
06641          ast_setstate(chan, AST_STATE_RING);
06642          res = ast_pbx_run(chan);
06643          if (res) {
06644             ast_log(LOG_WARNING, "PBX exited non-zero!\n");
06645          }
06646       } else {
06647          ast_debug(1, "No such possible extension '%s' in context '%s'\n", exten, chan->context);
06648          chan->hangupcause = AST_CAUSE_UNALLOCATED;
06649          ast_hangup(chan);
06650          p->exten[0] = '\0';
06651          /* Since we send release complete here, we won't get one */
06652          p->call = NULL;
06653       }
06654       goto quit;
06655       break;
06656 #endif
06657    case SIG_FEATD:
06658    case SIG_FEATDMF:
06659    case SIG_FEATDMF_TA:
06660    case SIG_E911:
06661    case SIG_FGC_CAMAMF:
06662    case SIG_FEATB:
06663    case SIG_EMWINK:
06664    case SIG_SF_FEATD:
06665    case SIG_SF_FEATDMF:
06666    case SIG_SF_FEATB:
06667    case SIG_SFWINK:
06668       if (dahdi_wink(p, idx)) 
06669          goto quit;
06670       /* Fall through */
06671    case SIG_EM:
06672    case SIG_EM_E1:
06673    case SIG_SF:
06674    case SIG_FGC_CAMA:
06675       res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06676       if (p->dsp)
06677          ast_dsp_digitreset(p->dsp);
06678       /* set digit mode appropriately */
06679       if (p->dsp) {
06680          if (NEED_MFDETECT(p))
06681             ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax); 
06682          else 
06683             ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
06684       }
06685       memset(dtmfbuf, 0, sizeof(dtmfbuf));
06686       /* Wait for the first digit only if immediate=no */
06687       if (!p->immediate)
06688          /* Wait for the first digit (up to 5 seconds). */
06689          res = ast_waitfordigit(chan, 5000);
06690       else
06691          res = 0;
06692       if (res > 0) {
06693          /* save first char */
06694          dtmfbuf[0] = res;
06695          switch (p->sig) {
06696          case SIG_FEATD:
06697          case SIG_SF_FEATD:
06698             res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
06699             if (res > 0)
06700                res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
06701             if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06702             break;
06703          case SIG_FEATDMF_TA:
06704             res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
06705             if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06706             if (dahdi_wink(p, idx)) goto quit;
06707             dtmfbuf[0] = 0;
06708             /* Wait for the first digit (up to 5 seconds). */
06709             res = ast_waitfordigit(chan, 5000);
06710             if (res <= 0) break;
06711             dtmfbuf[0] = res;
06712             /* fall through intentionally */
06713          case SIG_FEATDMF:
06714          case SIG_E911:
06715          case SIG_FGC_CAMAMF:
06716          case SIG_SF_FEATDMF:
06717             res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
06718             /* if international caca, do it again to get real ANO */
06719             if ((p->sig == SIG_FEATDMF) && (dtmfbuf[1] != '0') && (strlen(dtmfbuf) != 14))
06720             {
06721                if (dahdi_wink(p, idx)) goto quit;
06722                dtmfbuf[0] = 0;
06723                /* Wait for the first digit (up to 5 seconds). */
06724                res = ast_waitfordigit(chan, 5000);
06725                if (res <= 0) break;
06726                dtmfbuf[0] = res;
06727                res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
06728             }
06729             if (res > 0) {
06730                /* if E911, take off hook */
06731                if (p->sig == SIG_E911)
06732                   dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
06733                res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "#", 3000);
06734             }
06735             if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06736             break;
06737          case SIG_FEATB:
06738          case SIG_SF_FEATB:
06739             res = my_getsigstr(chan, dtmfbuf + 1, "#", 3000);
06740             if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06741             break;
06742          case SIG_EMWINK:
06743             /* if we received a '*', we are actually receiving Feature Group D
06744                dial syntax, so use that mode; otherwise, fall through to normal
06745                mode
06746             */
06747             if (res == '*') {
06748                res = my_getsigstr(chan, dtmfbuf + 1, "*", 3000);
06749                if (res > 0)
06750                   res = my_getsigstr(chan, dtmfbuf + strlen(dtmfbuf), "*", 3000);
06751                if ((res < 1) && (p->dsp)) ast_dsp_digitreset(p->dsp);
06752                break;
06753             }
06754          default:
06755             /* If we got the first digit, get the rest */
06756             len = 1;
06757             dtmfbuf[len] = '\0';
06758             while ((len < AST_MAX_EXTENSION-1) && ast_matchmore_extension(chan, chan->context, dtmfbuf, 1, p->cid_num)) {
06759                if (ast_exists_extension(chan, chan->context, dtmfbuf, 1, p->cid_num)) {
06760                   timeout = matchdigittimeout;
06761                } else {
06762                   timeout = gendigittimeout;
06763                }
06764                res = ast_waitfordigit(chan, timeout);
06765                if (res < 0) {
06766                   ast_debug(1, "waitfordigit returned < 0...\n");
06767                   ast_hangup(chan);
06768                   goto quit;
06769                } else if (res) {
06770                   dtmfbuf[len++] = res;
06771                   dtmfbuf[len] = '\0';
06772                } else {
06773                   break;
06774                }
06775             }
06776             break;
06777          }
06778       }
06779       if (res == -1) {
06780          ast_log(LOG_WARNING, "getdtmf on channel %d: %s\n", p->channel, strerror(errno));
06781          ast_hangup(chan);
06782          goto quit;
06783       } else if (res < 0) {
06784          ast_debug(1, "Got hung up before digits finished\n");
06785          ast_hangup(chan);
06786          goto quit;
06787       }
06788 
06789       if (p->sig == SIG_FGC_CAMA) {
06790          char anibuf[100];
06791 
06792          if (ast_safe_sleep(chan,1000) == -1) {
06793                            ast_hangup(chan);
06794                            goto quit;
06795          }
06796                         dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
06797                         ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_MF | p->dtmfrelax);
06798                         res = my_getsigstr(chan, anibuf, "#", 10000);
06799                         if ((res > 0) && (strlen(anibuf) > 2)) {
06800             if (anibuf[strlen(anibuf) - 1] == '#')
06801                anibuf[strlen(anibuf) - 1] = 0;
06802             ast_set_callerid(chan, anibuf + 2, NULL, anibuf + 2);
06803          }
06804                         ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax);
06805       }
06806 
06807       ast_copy_string(exten, dtmfbuf, sizeof(exten));
06808       if (ast_strlen_zero(exten))
06809          ast_copy_string(exten, "s", sizeof(exten));
06810       if (p->sig == SIG_FEATD || p->sig == SIG_EMWINK) {
06811          /* Look for Feature Group D on all E&M Wink and Feature Group D trunks */
06812          if (exten[0] == '*') {
06813             char *stringp=NULL;
06814             ast_copy_string(exten2, exten, sizeof(exten2));
06815             /* Parse out extension and callerid */
06816             stringp=exten2 +1;
06817             s1 = strsep(&stringp, "*");
06818             s2 = strsep(&stringp, "*");
06819             if (s2) {
06820                if (!ast_strlen_zero(p->cid_num))
06821                   ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
06822                else
06823                   ast_set_callerid(chan, s1, NULL, s1);
06824                ast_copy_string(exten, s2, sizeof(exten));
06825             } else
06826                ast_copy_string(exten, s1, sizeof(exten));
06827          } else if (p->sig == SIG_FEATD)
06828             ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d.  Assuming E&M Wink instead\n", p->channel);
06829       }
06830       if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
06831          if (exten[0] == '*') {
06832             char *stringp=NULL;
06833             ast_copy_string(exten2, exten, sizeof(exten2));
06834             /* Parse out extension and callerid */
06835             stringp=exten2 +1;
06836             s1 = strsep(&stringp, "#");
06837             s2 = strsep(&stringp, "#");
06838             if (s2) {
06839                if (!ast_strlen_zero(p->cid_num))
06840                   ast_set_callerid(chan, p->cid_num, NULL, p->cid_num);
06841                else
06842                   if (*(s1 + 2))
06843                      ast_set_callerid(chan, s1 + 2, NULL, s1 + 2);
06844                ast_copy_string(exten, s2 + 1, sizeof(exten));
06845             } else
06846                ast_copy_string(exten, s1 + 2, sizeof(exten));
06847          } else
06848             ast_log(LOG_WARNING, "Got a non-Feature Group D input on channel %d.  Assuming E&M Wink instead\n", p->channel);
06849       }
06850       if ((p->sig == SIG_E911) || (p->sig == SIG_FGC_CAMAMF)) {
06851          if (exten[0] == '*') {
06852             char *stringp=NULL;
06853             ast_copy_string(exten2, exten, sizeof(exten2));
06854             /* Parse out extension and callerid */
06855             stringp=exten2 +1;
06856             s1 = strsep(&stringp, "#");
06857             s2 = strsep(&stringp, "#");
06858             if (s2 && (*(s2 + 1) == '0')) {
06859                if (*(s2 + 2))
06860                   ast_set_callerid(chan, s2 + 2, NULL, s2 + 2);
06861             }
06862             if (s1)  ast_copy_string(exten, s1, sizeof(exten));
06863             else ast_copy_string(exten, "911", sizeof(exten));
06864          } else
06865             ast_log(LOG_WARNING, "Got a non-E911/FGC CAMA input on channel %d.  Assuming E&M Wink instead\n", p->channel);
06866       }
06867       if (p->sig == SIG_FEATB) {
06868          if (exten[0] == '*') {
06869             char *stringp=NULL;
06870             ast_copy_string(exten2, exten, sizeof(exten2));
06871             /* Parse out extension and callerid */
06872             stringp=exten2 +1;
06873             s1 = strsep(&stringp, "#");
06874             ast_copy_string(exten, exten2 + 1, sizeof(exten));
06875          } else
06876             ast_log(LOG_WARNING, "Got a non-Feature Group B input on channel %d.  Assuming E&M Wink instead\n", p->channel);
06877       }
06878       if ((p->sig == SIG_FEATDMF) || (p->sig == SIG_FEATDMF_TA)) {
06879          dahdi_wink(p, idx);
06880                         /* some switches require a minimum guard time between
06881                            the last FGD wink and something that answers
06882                            immediately. This ensures it */
06883                         if (ast_safe_sleep(chan,100)) goto quit;
06884       }
06885       dahdi_enable_ec(p);
06886       if (NEED_MFDETECT(p)) {
06887          if (p->dsp) {
06888             if (!p->hardwaredtmf)
06889                ast_dsp_set_digitmode(p->dsp, DSP_DIGITMODE_DTMF | p->dtmfrelax); 
06890             else {
06891                ast_dsp_free(p->dsp);
06892                p->dsp = NULL;
06893             }
06894          }
06895       }
06896 
06897       if (ast_exists_extension(chan, chan->context, exten, 1, chan->cid.cid_num)) {
06898          ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06899          if (p->dsp) ast_dsp_digitreset(p->dsp);
06900          res = ast_pbx_run(chan);
06901          if (res) {
06902             ast_log(LOG_WARNING, "PBX exited non-zero\n");
06903             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06904          }
06905          goto quit;
06906       } else {
06907          ast_verb(2, "Unknown extension '%s' in context '%s' requested\n", exten, chan->context);
06908          sleep(2);
06909          res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_INFO);
06910          if (res < 0)
06911             ast_log(LOG_WARNING, "Unable to start special tone on %d\n", p->channel);
06912          else
06913             sleep(1);
06914          res = ast_streamfile(chan, "ss-noservice", chan->language);
06915          if (res >= 0)
06916             ast_waitstream(chan, "");
06917          res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06918          ast_hangup(chan);
06919          goto quit;
06920       }
06921       break;
06922    case SIG_FXOLS:
06923    case SIG_FXOGS:
06924    case SIG_FXOKS:
06925       /* Read the first digit */
06926       timeout = firstdigittimeout;
06927       /* If starting a threeway call, never timeout on the first digit so someone
06928          can use flash-hook as a "hold" feature */
06929       if (p->subs[SUB_THREEWAY].owner) 
06930          timeout = 999999;
06931       while (len < AST_MAX_EXTENSION-1) {
06932          /* Read digit unless it's supposed to be immediate, in which case the
06933             only answer is 's' */
06934          if (p->immediate) 
06935             res = 's';
06936          else
06937             res = ast_waitfordigit(chan, timeout);
06938          timeout = 0;
06939          if (res < 0) {
06940             ast_debug(1, "waitfordigit returned < 0...\n");
06941             res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06942             ast_hangup(chan);
06943             goto quit;
06944          } else if (res)  {
06945             ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res, res, timeout);
06946             exten[len++]=res;
06947             exten[len] = '\0';
06948          }
06949          if (!ast_ignore_pattern(chan->context, exten))
06950             tone_zone_play_tone(p->subs[idx].dfd, -1);
06951          else
06952             tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
06953          if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num) && strcmp(exten, ast_parking_ext())) {
06954             if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
06955                if (getforward) {
06956                   /* Record this as the forwarding extension */
06957                   ast_copy_string(p->call_forward, exten, sizeof(p->call_forward)); 
06958                   ast_verb(3, "Setting call forward to '%s' on channel %d\n", p->call_forward, p->channel);
06959                   res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
06960                   if (res)
06961                      break;
06962                   usleep(500000);
06963                   res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06964                   sleep(1);
06965                   memset(exten, 0, sizeof(exten));
06966                   res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALTONE);
06967                   len = 0;
06968                   getforward = 0;
06969                } else  {
06970                   res = tone_zone_play_tone(p->subs[idx].dfd, -1);
06971                   ast_copy_string(chan->exten, exten, sizeof(chan->exten));
06972                   if (!ast_strlen_zero(p->cid_num)) {
06973                      if (!p->hidecallerid)
06974                         ast_set_callerid(chan, p->cid_num, NULL, p->cid_num); 
06975                      else
06976                         ast_set_callerid(chan, NULL, NULL, p->cid_num); 
06977                   }
06978                   if (!ast_strlen_zero(p->cid_name)) {
06979                      if (!p->hidecallerid)
06980                         ast_set_callerid(chan, NULL, p->cid_name, NULL);
06981                   }
06982                   ast_setstate(chan, AST_STATE_RING);
06983                   dahdi_enable_ec(p);
06984                   res = ast_pbx_run(chan);
06985                   if (res) {
06986                      ast_log(LOG_WARNING, "PBX exited non-zero\n");
06987                      res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06988                   }
06989                   goto quit;
06990                }
06991             } else {
06992                /* It's a match, but they just typed a digit, and there is an ambiguous match,
06993                   so just set the timeout to matchdigittimeout and wait some more */
06994                timeout = matchdigittimeout;
06995             }
06996          } else if (res == 0) {
06997             ast_debug(1, "not enough digits (and no ambiguous match)...\n");
06998             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
06999             dahdi_wait_event(p->subs[idx].dfd);
07000             ast_hangup(chan);
07001             goto quit;
07002          } else if (p->callwaiting && !strcmp(exten, "*70")) {
07003             ast_verb(3, "Disabling call waiting on %s\n", chan->name);
07004             /* Disable call waiting if enabled */
07005             p->callwaiting = 0;
07006             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07007             if (res) {
07008                ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", 
07009                   chan->name, strerror(errno));
07010             }
07011             len = 0;
07012             ioctl(p->subs[idx].dfd,DAHDI_CONFDIAG,&len);
07013             memset(exten, 0, sizeof(exten));
07014             timeout = firstdigittimeout;
07015                
07016          } else if (!strcmp(exten,ast_pickup_ext())) {
07017             /* Scan all channels and see if there are any
07018              * ringing channels that have call groups
07019              * that equal this channels pickup group  
07020              */
07021             if (idx == SUB_REAL) {
07022                /* Switch us from Third call to Call Wait */
07023                if (p->subs[SUB_THREEWAY].owner) {
07024                   /* If you make a threeway call and the *8# a call, it should actually 
07025                      look like a callwait */
07026                   alloc_sub(p, SUB_CALLWAIT);   
07027                   swap_subs(p, SUB_CALLWAIT, SUB_THREEWAY);
07028                   unalloc_sub(p, SUB_THREEWAY);
07029                }
07030                dahdi_enable_ec(p);
07031                if (ast_pickup_call(chan)) {
07032                   ast_debug(1, "No call pickup possible...\n");
07033                   res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07034                   dahdi_wait_event(p->subs[idx].dfd);
07035                }
07036                ast_hangup(chan);
07037                goto quit;
07038             } else {
07039                ast_log(LOG_WARNING, "Huh?  Got *8# on call not on real\n");
07040                ast_hangup(chan);
07041                goto quit;
07042             }
07043             
07044          } else if (!p->hidecallerid && !strcmp(exten, "*67")) {
07045             ast_verb(3, "Disabling Caller*ID on %s\n", chan->name);
07046             /* Disable Caller*ID if enabled */
07047             p->hidecallerid = 1;
07048             if (chan->cid.cid_num)
07049                ast_free(chan->cid.cid_num);
07050             chan->cid.cid_num = NULL;
07051             if (chan->cid.cid_name)
07052                ast_free(chan->cid.cid_name);
07053             chan->cid.cid_name = NULL;
07054             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07055             if (res) {
07056                ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", 
07057                   chan->name, strerror(errno));
07058             }
07059             len = 0;
07060             memset(exten, 0, sizeof(exten));
07061             timeout = firstdigittimeout;
07062          } else if (p->callreturn && !strcmp(exten, "*69")) {
07063             res = 0;
07064             if (!ast_strlen_zero(p->lastcid_num)) {
07065                res = ast_say_digit_str(chan, p->lastcid_num, "", chan->language);
07066             }
07067             if (!res)
07068                res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07069             break;
07070          } else if (!strcmp(exten, "*78")) {
07071             dahdi_dnd(p, 1);
07072             /* Do not disturb */
07073             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07074             getforward = 0;
07075             memset(exten, 0, sizeof(exten));
07076             len = 0;
07077          } else if (!strcmp(exten, "*79")) {
07078             dahdi_dnd(p, 0);
07079             /* Do not disturb */
07080             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07081             getforward = 0;
07082             memset(exten, 0, sizeof(exten));
07083             len = 0;
07084          } else if (p->cancallforward && !strcmp(exten, "*72")) {
07085             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07086             getforward = 1;
07087             memset(exten, 0, sizeof(exten));
07088             len = 0;
07089          } else if (p->cancallforward && !strcmp(exten, "*73")) {
07090             ast_verb(3, "Cancelling call forwarding on channel %d\n", p->channel);
07091             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07092             memset(p->call_forward, 0, sizeof(p->call_forward));
07093             getforward = 0;
07094             memset(exten, 0, sizeof(exten));
07095             len = 0;
07096          } else if ((p->transfer || p->canpark) && !strcmp(exten, ast_parking_ext()) && 
07097                   p->subs[SUB_THREEWAY].owner &&
07098                   ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
07099             /* This is a three way call, the main call being a real channel, 
07100                and we're parking the first call. */
07101             ast_masq_park_call(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), chan, 0, NULL);
07102             ast_verb(3, "Parking call to '%s'\n", chan->name);
07103             break;
07104          } else if (!ast_strlen_zero(p->lastcid_num) && !strcmp(exten, "*60")) {
07105             ast_verb(3, "Blacklisting number %s\n", p->lastcid_num);
07106             res = ast_db_put("blacklist", p->lastcid_num, "1");
07107             if (!res) {
07108                res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07109                memset(exten, 0, sizeof(exten));
07110                len = 0;
07111             }
07112          } else if (p->hidecallerid && !strcmp(exten, "*82")) {
07113             ast_verb(3, "Enabling Caller*ID on %s\n", chan->name);
07114             /* Enable Caller*ID if enabled */
07115             p->hidecallerid = 0;
07116             if (chan->cid.cid_num)
07117                ast_free(chan->cid.cid_num);
07118             chan->cid.cid_num = NULL;
07119             if (chan->cid.cid_name)
07120                ast_free(chan->cid.cid_name);
07121             chan->cid.cid_name = NULL;
07122             ast_set_callerid(chan, p->cid_num, p->cid_name, NULL);
07123             res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_DIALRECALL);
07124             if (res) {
07125                ast_log(LOG_WARNING, "Unable to do dial recall on channel %s: %s\n", 
07126                   chan->name, strerror(errno));
07127             }
07128             len = 0;
07129             memset(exten, 0, sizeof(exten));
07130             timeout = firstdigittimeout;
07131          } else if (!strcmp(exten, "*0")) {
07132             struct ast_channel *nbridge = 
07133                p->subs[SUB_THREEWAY].owner;
07134             struct dahdi_pvt *pbridge = NULL;
07135               /* set up the private struct of the bridged one, if any */
07136             if (nbridge && ast_bridged_channel(nbridge)) 
07137                pbridge = ast_bridged_channel(nbridge)->tech_pvt;
07138             if (nbridge && pbridge && 
07139                 (nbridge->tech == &dahdi_tech) && 
07140                 (ast_bridged_channel(nbridge)->tech == &dahdi_tech) &&
07141                 ISTRUNK(pbridge)) {
07142                int func = DAHDI_FLASH;
07143                /* Clear out the dial buffer */
07144                p->dop.dialstr[0] = '\0';
07145                /* flash hookswitch */
07146                if ((ioctl(pbridge->subs[SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
07147                   ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n", 
07148                      nbridge->name, strerror(errno));
07149                }
07150                swap_subs(p, SUB_REAL, SUB_THREEWAY);
07151                unalloc_sub(p, SUB_THREEWAY);
07152                p->owner = p->subs[SUB_REAL].owner;
07153                if (ast_bridged_channel(p->subs[SUB_REAL].owner))
07154                   ast_queue_control(p->subs[SUB_REAL].owner, AST_CONTROL_UNHOLD);
07155                ast_hangup(chan);
07156                goto quit;
07157             } else {
07158                tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07159                dahdi_wait_event(p->subs[idx].dfd);
07160                tone_zone_play_tone(p->subs[idx].dfd, -1);
07161                swap_subs(p, SUB_REAL, SUB_THREEWAY);
07162                unalloc_sub(p, SUB_THREEWAY);
07163                p->owner = p->subs[SUB_REAL].owner;
07164                ast_hangup(chan);
07165                goto quit;
07166             }              
07167          } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) &&
07168                      ((exten[0] != '*') || (strlen(exten) > 2))) {
07169             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);
07170             break;
07171          }
07172          if (!timeout)
07173             timeout = gendigittimeout;
07174          if (len && !ast_ignore_pattern(chan->context, exten))
07175             tone_zone_play_tone(p->subs[idx].dfd, -1);
07176       }
07177       break;
07178    case SIG_FXSLS:
07179    case SIG_FXSGS:
07180    case SIG_FXSKS:
07181 #ifdef HAVE_PRI
07182       if (p->pri) {
07183          /* This is a GR-303 trunk actually.  Wait for the first ring... */
07184          struct ast_frame *f;
07185          int res;
07186          time_t start;
07187 
07188          time(&start);
07189          ast_setstate(chan, AST_STATE_RING);
07190          while (time(NULL) < start + 3) {
07191             res = ast_waitfor(chan, 1000);
07192             if (res) {
07193                f = ast_read(chan);
07194                if (!f) {
07195                   ast_log(LOG_WARNING, "Whoa, hangup while waiting for first ring!\n");
07196                   ast_hangup(chan);
07197                   goto quit;
07198                } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RING)) {
07199                   res = 1;
07200                } else
07201                   res = 0;
07202                ast_frfree(f);
07203                if (res) {
07204                   ast_debug(1, "Got ring!\n");
07205                   res = 0;
07206                   break;
07207                }
07208             }
07209          }
07210       }
07211 #endif
07212       /* check for SMDI messages */
07213       if (p->use_smdi && p->smdi_iface) {
07214          smdi_msg = ast_smdi_md_message_wait(p->smdi_iface, SMDI_MD_WAIT_TIMEOUT);
07215 
07216          if (smdi_msg != NULL) {
07217             ast_copy_string(chan->exten, smdi_msg->fwd_st, sizeof(chan->exten));
07218 
07219             if (smdi_msg->type == 'B')
07220                pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "b");
07221             else if (smdi_msg->type == 'N')
07222                pbx_builtin_setvar_helper(chan, "_SMDI_VM_TYPE", "u");
07223 
07224             ast_debug(1, "Received SMDI message on %s\n", chan->name);
07225          } else {
07226             ast_log(LOG_WARNING, "SMDI enabled but no SMDI message present\n");
07227          }
07228       }
07229 
07230       if (p->use_callerid && (p->cid_signalling == CID_SIG_SMDI && smdi_msg)) {
07231             number = smdi_msg->calling_st;
07232 
07233       /* If we want caller id, we're in a prering state due to a polarity reversal
07234        * and we're set to use a polarity reversal to trigger the start of caller id,
07235        * grab the caller id and wait for ringing to start... */
07236       } else if (p->use_callerid && (chan->_state == AST_STATE_PRERING && (p->cid_start == CID_START_POLARITY || p->cid_start == CID_START_POLARITY_IN))) {
07237          /* If set to use DTMF CID signalling, listen for DTMF */
07238          if (p->cid_signalling == CID_SIG_DTMF) {
07239             int k = 0;
07240             cs = NULL;
07241             ast_debug(1, "Receiving DTMF cid on "
07242                "channel %s\n", chan->name);
07243             dahdi_setlinear(p->subs[idx].dfd, 0);
07244             res = 2000;
07245             for (;;) {
07246                struct ast_frame *f;
07247                res = ast_waitfor(chan, res);
07248                if (res <= 0) {
07249                   ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
07250                      "Exiting simple switch\n");
07251                   ast_hangup(chan);
07252                   goto quit;
07253                } 
07254                f = ast_read(chan);
07255                if (!f)
07256                   break;
07257                if (f->frametype == AST_FRAME_DTMF) {
07258                   dtmfbuf[k++] = f->subclass;
07259                   ast_debug(1, "CID got digit '%c'\n", f->subclass);
07260                   res = 2000;
07261                }
07262                ast_frfree(f);
07263                if (chan->_state == AST_STATE_RING ||
07264                    chan->_state == AST_STATE_RINGING) 
07265                   break; /* Got ring */
07266             }
07267             dtmfbuf[k] = '\0';
07268             dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
07269             /* Got cid and ring. */
07270             ast_debug(1, "CID got string '%s'\n", dtmfbuf);
07271             callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
07272             ast_debug(1, "CID is '%s', flags %d\n", 
07273                dtmfcid, flags);
07274             /* If first byte is NULL, we have no cid */
07275             if (!ast_strlen_zero(dtmfcid)) 
07276                number = dtmfcid;
07277             else
07278                number = NULL;
07279          /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
07280          } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
07281             cs = callerid_new(p->cid_signalling);
07282             if (cs) {
07283                samples = 0;
07284 #if 1
07285                bump_gains(p);
07286 #endif
07287                /* Take out of linear mode for Caller*ID processing */
07288                dahdi_setlinear(p->subs[idx].dfd, 0);
07289                
07290                /* First we wait and listen for the Caller*ID */
07291                for (;;) {  
07292                   i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07293                   if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
07294                      ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07295                      callerid_free(cs);
07296                      ast_hangup(chan);
07297                      goto quit;
07298                   }
07299                   if (i & DAHDI_IOMUX_SIGEVENT) {
07300                      res = dahdi_get_event(p->subs[idx].dfd);
07301                      ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
07302 
07303                      if (p->cid_signalling == CID_SIG_V23_JP) {
07304                         if (res == DAHDI_EVENT_RINGBEGIN) {
07305                            res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
07306                            usleep(1);
07307                         }
07308                      } else {
07309                         res = 0;
07310                         break;
07311                      }
07312                   } else if (i & DAHDI_IOMUX_READ) {
07313                      res = read(p->subs[idx].dfd, buf, sizeof(buf));
07314                      if (res < 0) {
07315                         if (errno != ELAST) {
07316                            ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07317                            callerid_free(cs);
07318                            ast_hangup(chan);
07319                            goto quit;
07320                         }
07321                         break;
07322                      }
07323                      samples += res;
07324 
07325                      if  (p->cid_signalling == CID_SIG_V23_JP) {
07326                         res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
07327                      } else {
07328                         res = callerid_feed(cs, buf, res, AST_LAW(p));
07329                      }
07330 
07331                      if (res < 0) {
07332                         ast_log(LOG_WARNING, "CallerID feed failed on channel '%s'\n", chan->name);
07333                         break;
07334                      } else if (res)
07335                         break;
07336                      else if (samples > (8000 * 10))
07337                         break;
07338                   }
07339                }
07340                if (res == 1) {
07341                   callerid_get(cs, &name, &number, &flags);
07342                   ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
07343                }
07344 
07345                if (p->cid_signalling == CID_SIG_V23_JP) {
07346                   res = dahdi_set_hook(p->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
07347                   usleep(1);
07348                   res = 4000;
07349                } else {
07350 
07351                   /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */ 
07352                   res = 2000;
07353                }
07354 
07355                for (;;) {
07356                   struct ast_frame *f;
07357                   res = ast_waitfor(chan, res);
07358                   if (res <= 0) {
07359                      ast_log(LOG_WARNING, "CID timed out waiting for ring. "
07360                         "Exiting simple switch\n");
07361                      ast_hangup(chan);
07362                      goto quit;
07363                   } 
07364                   if (!(f = ast_read(chan))) {
07365                      ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n");
07366                      ast_hangup(chan);
07367                      goto quit;
07368                   }
07369                   ast_frfree(f);
07370                   if (chan->_state == AST_STATE_RING ||
07371                       chan->_state == AST_STATE_RINGING) 
07372                      break; /* Got ring */
07373                }
07374    
07375                /* We must have a ring by now, so, if configured, lets try to listen for
07376                 * distinctive ringing */ 
07377                if (p->usedistinctiveringdetection) {
07378                   len = 0;
07379                   distMatches = 0;
07380                   /* Clear the current ring data array so we dont have old data in it. */
07381                   for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
07382                      curRingData[receivedRingT] = 0;
07383                   receivedRingT = 0;
07384                   counter = 0;
07385                   counter1 = 0;
07386                   /* Check to see if context is what it should be, if not set to be. */
07387                   if (strcmp(p->context,p->defcontext) != 0) {
07388                      ast_copy_string(p->context, p->defcontext, sizeof(p->context));
07389                      ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
07390                   }
07391       
07392                   for (;;) {  
07393                      i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07394                      if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
07395                         ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07396                         callerid_free(cs);
07397                         ast_hangup(chan);
07398                         goto quit;
07399                      }
07400                      if (i & DAHDI_IOMUX_SIGEVENT) {
07401                         res = dahdi_get_event(p->subs[idx].dfd);
07402                         ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
07403                         res = 0;
07404                         /* Let us detect distinctive ring */
07405       
07406                         curRingData[receivedRingT] = p->ringt;
07407       
07408                         if (p->ringt < p->ringt_base/2)
07409                            break;
07410                         /* Increment the ringT counter so we can match it against
07411                            values in chan_dahdi.conf for distinctive ring */
07412                         if (++receivedRingT == ARRAY_LEN(curRingData))
07413                            break;
07414                      } else if (i & DAHDI_IOMUX_READ) {
07415                         res = read(p->subs[idx].dfd, buf, sizeof(buf));
07416                         if (res < 0) {
07417                            if (errno != ELAST) {
07418                               ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07419                               callerid_free(cs);
07420                               ast_hangup(chan);
07421                               goto quit;
07422                            }
07423                            break;
07424                         }
07425                         if (p->ringt) 
07426                            p->ringt--;
07427                         if (p->ringt == 1) {
07428                            res = -1;
07429                            break;
07430                         }
07431                      }
07432                   }
07433                      /* this only shows up if you have n of the dring patterns filled in */
07434                   ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
07435                   for (counter = 0; counter < 3; counter++) {
07436                      /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
07437                      channel */
07438                      distMatches = 0;
07439                      for (counter1 = 0; counter1 < 3; counter1++) {
07440                         ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
07441                         if (p->drings.ringnum[counter].ring[counter1] == -1) {
07442                            ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
07443                            curRingData[counter1]);
07444                            distMatches++;
07445                         }
07446                         else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
07447                             curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
07448                            ast_verb(3, "Ring pattern matched in range: %d to %d\n",
07449                            (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
07450                            (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
07451                            distMatches++;
07452                         }
07453                      }
07454 
07455                      if (distMatches == 3) {
07456                         /* The ring matches, set the context to whatever is for distinctive ring.. */
07457                         ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context));
07458                         ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context));
07459                         ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
07460                         break;
07461                      }
07462                   }
07463                }
07464                /* Restore linear mode (if appropriate) for Caller*ID processing */
07465                dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
07466 #if 1
07467                restore_gains(p);
07468 #endif            
07469             } else
07470                ast_log(LOG_WARNING, "Unable to get caller ID space\n");       
07471          } else {
07472             ast_log(LOG_WARNING, "Channel %s in prering "
07473                "state, but I have nothing to do. "
07474                "Terminating simple switch, should be "
07475                "restarted by the actual ring.\n", 
07476                chan->name);
07477             ast_hangup(chan);
07478             goto quit;
07479          }
07480       } else if (p->use_callerid && p->cid_start == CID_START_RING) {
07481                         if (p->cid_signalling == CID_SIG_DTMF) {
07482                                 int k = 0;
07483                                 cs = NULL;
07484                                 dahdi_setlinear(p->subs[idx].dfd, 0);
07485                                 res = 2000;
07486                                 for (;;) {
07487                                         struct ast_frame *f;
07488                                         res = ast_waitfor(chan, res);
07489                                         if (res <= 0) {
07490                                                 ast_log(LOG_WARNING, "DTMFCID timed out waiting for ring. "
07491                                                                 "Exiting simple switch\n");
07492                                                 ast_hangup(chan);
07493                                                 return NULL;
07494                                         }
07495                                         f = ast_read(chan);
07496                                         if (f->frametype == AST_FRAME_DTMF) {
07497                                                 dtmfbuf[k++] = f->subclass;
07498                                                 ast_log(LOG_DEBUG, "CID got digit '%c'\n", f->subclass);
07499                                                 res = 2000;
07500                                         }
07501                                         ast_frfree(f);
07502 
07503                                         if (p->ringt_base == p->ringt)
07504                                                 break;
07505 
07506                                 }
07507                                 dtmfbuf[k] = '\0';
07508                                 dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
07509                                 /* Got cid and ring. */
07510                                 callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
07511                                 ast_log(LOG_DEBUG, "CID is '%s', flags %d\n",
07512                                                 dtmfcid, flags);
07513                                 /* If first byte is NULL, we have no cid */
07514                                 if (!ast_strlen_zero(dtmfcid))
07515                                         number = dtmfcid;
07516                                 else
07517                                         number = NULL;
07518                                 /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
07519                         } else {
07520          /* FSK Bell202 callerID */
07521          cs = callerid_new(p->cid_signalling);
07522          if (cs) {
07523 #if 1
07524             bump_gains(p);
07525 #endif            
07526             samples = 0;
07527             len = 0;
07528             distMatches = 0;
07529             /* Clear the current ring data array so we dont have old data in it. */
07530             for (receivedRingT = 0; receivedRingT < ARRAY_LEN(curRingData); receivedRingT++)
07531                curRingData[receivedRingT] = 0;
07532             receivedRingT = 0;
07533             counter = 0;
07534             counter1 = 0;
07535             /* Check to see if context is what it should be, if not set to be. */
07536             if (strcmp(p->context,p->defcontext) != 0) {
07537                ast_copy_string(p->context, p->defcontext, sizeof(p->context));
07538                ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
07539             }
07540 
07541             /* Take out of linear mode for Caller*ID processing */
07542             dahdi_setlinear(p->subs[idx].dfd, 0);
07543             for (;;) {  
07544                i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07545                if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
07546                   ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07547                   callerid_free(cs);
07548                   ast_hangup(chan);
07549                   goto quit;
07550                }
07551                if (i & DAHDI_IOMUX_SIGEVENT) {
07552                   res = dahdi_get_event(p->subs[idx].dfd);
07553                   ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
07554                   /* If we get a PR event, they hung up while processing calerid */
07555                   if ( res == DAHDI_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
07556                      ast_log(LOG_DEBUG, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
07557                      p->polarity = POLARITY_IDLE;
07558                      callerid_free(cs);
07559                      ast_hangup(chan);
07560                      goto quit;
07561                   }
07562                   res = 0;
07563                   /* Let us detect callerid when the telco uses distinctive ring */
07564 
07565                   curRingData[receivedRingT] = p->ringt;
07566 
07567                   if (p->ringt < p->ringt_base/2)
07568                      break;
07569                   /* Increment the ringT counter so we can match it against
07570                      values in chan_dahdi.conf for distinctive ring */
07571                   if (++receivedRingT == ARRAY_LEN(curRingData))
07572                      break;
07573                } else if (i & DAHDI_IOMUX_READ) {
07574                   res = read(p->subs[idx].dfd, buf, sizeof(buf));
07575                   if (res < 0) {
07576                      if (errno != ELAST) {
07577                         ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07578                         callerid_free(cs);
07579                         ast_hangup(chan);
07580                         goto quit;
07581                      }
07582                      break;
07583                   }
07584                   if (p->ringt) 
07585                      p->ringt--;
07586                   if (p->ringt == 1) {
07587                      res = -1;
07588                      break;
07589                   }
07590                   samples += res;
07591                   res = callerid_feed(cs, buf, res, AST_LAW(p));
07592                   if (res < 0) {
07593                      ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
07594                      break;
07595                   } else if (res)
07596                      break;
07597                   else if (samples > (8000 * 10))
07598                      break;
07599                }
07600             }
07601             if (res == 1) {
07602                callerid_get(cs, &name, &number, &flags);
07603                ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
07604             }
07605             if (distinctiveringaftercid == 1) {
07606                /* Clear the current ring data array so we dont have old data in it. */
07607                for (receivedRingT = 0; receivedRingT < 3; receivedRingT++) {
07608                   curRingData[receivedRingT] = 0;
07609                }
07610                receivedRingT = 0;
07611                ast_verb(3, "Detecting post-CID distinctive ring\n");
07612                for (;;) {
07613                   i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07614                   if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i)))    {
07615                      ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07616                      callerid_free(cs);
07617                      ast_hangup(chan);
07618                      goto quit;
07619                   }
07620                   if (i & DAHDI_IOMUX_SIGEVENT) {
07621                      res = dahdi_get_event(p->subs[idx].dfd);
07622                      ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
07623                      res = 0;
07624                      /* Let us detect callerid when the telco uses distinctive ring */
07625 
07626                      curRingData[receivedRingT] = p->ringt;
07627 
07628                      if (p->ringt < p->ringt_base/2)
07629                         break;
07630                      /* Increment the ringT counter so we can match it against
07631                         values in chan_dahdi.conf for distinctive ring */
07632                      if (++receivedRingT == ARRAY_LEN(curRingData))
07633                         break;
07634                   } else if (i & DAHDI_IOMUX_READ) {
07635                      res = read(p->subs[idx].dfd, buf, sizeof(buf));
07636                      if (res < 0) {
07637                         if (errno != ELAST) {
07638                            ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07639                            callerid_free(cs);
07640                            ast_hangup(chan);
07641                            goto quit;
07642                         }
07643                         break;
07644                      }
07645                   if (p->ringt)
07646                      p->ringt--;
07647                      if (p->ringt == 1) {
07648                         res = -1;
07649                         break;
07650                      }
07651                   }
07652                }
07653             }
07654             if (p->usedistinctiveringdetection) {
07655                   /* this only shows up if you have n of the dring patterns filled in */
07656                ast_verb(3, "Detected ring pattern: %d,%d,%d\n",curRingData[0],curRingData[1],curRingData[2]);
07657 
07658                for (counter = 0; counter < 3; counter++) {
07659                   /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this
07660                   channel */
07661                      /* this only shows up if you have n of the dring patterns filled in */
07662                   ast_verb(3, "Checking %d,%d,%d\n",
07663                         p->drings.ringnum[counter].ring[0],
07664                         p->drings.ringnum[counter].ring[1],
07665                         p->drings.ringnum[counter].ring[2]);
07666                   distMatches = 0;
07667                   for (counter1 = 0; counter1 < 3; counter1++) {
07668                      ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
07669                      if (p->drings.ringnum[counter].ring[counter1] == -1) {
07670                         ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
07671                         curRingData[counter1]);
07672                         distMatches++;
07673                      }
07674                      else if (curRingData[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
07675                          curRingData[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
07676                         ast_verb(3, "Ring pattern matched in range: %d to %d\n",
07677                         (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
07678                         (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
07679                         distMatches++;
07680                      }
07681                   }
07682                   if (distMatches == 3) {
07683                      /* The ring matches, set the context to whatever is for distinctive ring.. */
07684                      ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context));
07685                      ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context));
07686                      ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
07687                      break;
07688                   }
07689                }
07690             }
07691             /* Restore linear mode (if appropriate) for Caller*ID processing */
07692             dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
07693 #if 1
07694             restore_gains(p);
07695 #endif            
07696             if (res < 0) {
07697                ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", chan->name);
07698             }
07699          } else
07700             ast_log(LOG_WARNING, "Unable to get caller ID space\n");
07701       }
07702       }
07703       else
07704          cs = NULL;
07705 
07706       if (number)
07707          ast_shrink_phone_number(number);
07708       ast_set_callerid(chan, number, name, number);
07709 
07710       if (smdi_msg)
07711          ASTOBJ_UNREF(smdi_msg, ast_smdi_md_message_destroy);
07712 
07713       if (cs)
07714          callerid_free(cs);
07715       /* If the CID had Message waiting payload, assume that this for MWI only and hangup the call */
07716       if (flags & CID_MSGWAITING) {
07717          ast_log(LOG_NOTICE, "MWI: Channel %d message waiting!\n", p->channel);
07718          notify_message(p->mailbox, 1);
07719          /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
07720          if (p->mwimonitor_rpas) {
07721             ast_hangup(chan);
07722             return NULL;
07723          }
07724       } else if (flags & CID_NOMSGWAITING) {
07725          ast_log(LOG_NOTICE, "MWI: Channel %d no message waiting!\n", p->channel);
07726          notify_message(p->mailbox, 0);
07727          /* If generated using Ring Pulse Alert, then ring has been answered as a call and needs to be hungup */
07728          if (p->mwimonitor_rpas) {
07729             ast_hangup(chan);
07730             return NULL;
07731          }
07732       }
07733 
07734       ast_setstate(chan, AST_STATE_RING);
07735       chan->rings = 1;
07736       p->ringt = p->ringt_base;
07737       res = ast_pbx_run(chan);
07738       if (res) {
07739          ast_hangup(chan);
07740          ast_log(LOG_WARNING, "PBX exited non-zero\n");
07741       }
07742       goto quit;
07743    default:
07744       ast_log(LOG_WARNING, "Don't know how to handle simple switch with signalling %s on channel %d\n", sig2str(p->sig), p->channel);
07745       res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07746       if (res < 0)
07747             ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
07748    }
07749    res = tone_zone_play_tone(p->subs[idx].dfd, DAHDI_TONE_CONGESTION);
07750    if (res < 0)
07751          ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", p->channel);
07752    ast_hangup(chan);
07753 quit:
07754    ast_mutex_lock(&ss_thread_lock);
07755    ss_thread_count--;
07756    ast_cond_signal(&ss_thread_complete);
07757    ast_mutex_unlock(&ss_thread_lock);
07758    return NULL;
07759 }
07760 
07761 struct mwi_thread_data {
07762    struct dahdi_pvt *pvt;
07763    unsigned char buf[READ_SIZE];
07764    size_t len;
07765 };
07766 
07767 static int calc_energy(const unsigned char *buf, int len, int law)
07768 {
07769    int x;
07770    int sum = 0;
07771 
07772    if (!len)
07773       return 0;
07774 
07775    for (x = 0; x < len; x++)
07776       sum += abs(law == AST_FORMAT_ULAW ? AST_MULAW(buf[x]) : AST_ALAW(buf[x]));
07777 
07778    return sum / len;
07779 }
07780 
07781 static void *mwi_thread(void *data)
07782 {
07783    struct mwi_thread_data *mtd = data;
07784    struct callerid_state *cs;
07785    pthread_t threadid;
07786    int samples = 0;
07787    char *name, *number;
07788    int flags;
07789    int i, res;
07790    unsigned int spill_done = 0;
07791    int spill_result = -1;
07792    
07793    if (!(cs = callerid_new(mtd->pvt->cid_signalling))) {
07794       mtd->pvt->mwimonitoractive = 0;
07795 
07796       return NULL;
07797    }
07798    
07799    callerid_feed(cs, mtd->buf, mtd->len, AST_LAW(mtd->pvt));
07800 
07801    bump_gains(mtd->pvt);
07802 
07803    for (;;) {  
07804       i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07805       if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
07806          ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07807          goto quit;
07808       }
07809 
07810       if (i & DAHDI_IOMUX_SIGEVENT) {
07811          struct ast_channel *chan;
07812 
07813          /* If we get an event, screen out events that we do not act on.
07814           * Otherwise, cancel and go to the simple switch to let it deal with it.
07815           */
07816          res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
07817 
07818          switch (res) {
07819          case DAHDI_EVENT_NEONMWI_ACTIVE:
07820          case DAHDI_EVENT_NEONMWI_INACTIVE:
07821          case DAHDI_EVENT_NONE:
07822          case DAHDI_EVENT_BITSCHANGED:
07823             break;
07824          case DAHDI_EVENT_NOALARM:
07825             mtd->pvt->inalarm = 0;
07826             ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", mtd->pvt->channel);
07827             manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
07828                "Channel: %d\r\n", mtd->pvt->channel);
07829             break;
07830          case DAHDI_EVENT_ALARM:
07831             mtd->pvt->inalarm = 1;
07832             res = get_alarms(mtd->pvt);
07833             handle_alarms(mtd->pvt, res);
07834             break; /* What to do on channel alarm ???? -- fall thru intentionally?? */
07835          default:
07836             ast_log(LOG_NOTICE, "Got event %d (%s)...  Passing along to ss_thread\n", res, event2str(res));
07837             callerid_free(cs);
07838             
07839             restore_gains(mtd->pvt);
07840             mtd->pvt->ringt = mtd->pvt->ringt_base;
07841 
07842             if ((chan = dahdi_new(mtd->pvt, AST_STATE_RING, 0, SUB_REAL, 0, 0))) {
07843                if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
07844                   ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", mtd->pvt->channel);
07845                   res = tone_zone_play_tone(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
07846                   if (res < 0)
07847                      ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", mtd->pvt->channel);
07848                   ast_hangup(chan);
07849                   goto quit;
07850                }
07851                goto quit_no_clean;
07852 
07853             } else {
07854                ast_log(LOG_WARNING, "Could not create channel to handle call\n");
07855             }
07856          }
07857       } else if (i & DAHDI_IOMUX_READ) {
07858          if ((res = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
07859             if (errno != ELAST) {
07860                ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
07861                goto quit;
07862             }
07863             break;
07864          }
07865          samples += res;
07866          if (!spill_done) {
07867             if ((spill_result = callerid_feed(cs, mtd->buf, res, AST_LAW(mtd->pvt))) < 0) {
07868                ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
07869                break;
07870             } else if (spill_result) {
07871                spill_done = 1;
07872             }
07873          } else {
07874             /* keep reading data until the energy level drops below the threshold
07875                so we don't get another 'trigger' on the remaining carrier signal
07876             */
07877             if (calc_energy(mtd->buf, res, AST_LAW(mtd->pvt)) <= mwilevel)
07878                break;
07879          }
07880          if (samples > (8000 * 4)) /*Termination case - time to give up*/
07881             break;
07882       }
07883    }
07884 
07885    if (spill_result == 1) {
07886       callerid_get(cs, &name, &number, &flags);
07887       if (flags & CID_MSGWAITING) {
07888          ast_log(LOG_NOTICE, "mwi: Have Messages on channel %d\n", mtd->pvt->channel);
07889          notify_message(mtd->pvt->mailbox, 1);
07890       } else if (flags & CID_NOMSGWAITING) {
07891          ast_log(LOG_NOTICE, "mwi: No Messages on channel %d\n", mtd->pvt->channel);
07892          notify_message(mtd->pvt->mailbox, 0);
07893       } else {
07894          ast_log(LOG_NOTICE, "mwi: Status unknown on channel %d\n", mtd->pvt->channel);
07895       }
07896    }
07897 
07898 
07899 quit:
07900    callerid_free(cs);
07901 
07902    restore_gains(mtd->pvt);
07903 
07904 quit_no_clean:
07905    mtd->pvt->mwimonitoractive = 0;
07906 
07907    ast_free(mtd);
07908 
07909    return NULL;
07910 }
07911 
07912 /* States for sending MWI message
07913  * First three states are required for send Ring Pulse Alert Signal 
07914  */
07915 enum mwisend_states {
07916    MWI_SEND_SA,
07917  MWI_SEND_SA_WAIT,
07918  MWI_SEND_PAUSE,
07919  MWI_SEND_SPILL,
07920  MWI_SEND_CLEANUP,
07921  MWI_SEND_DONE
07922 };
07923 
07924 static void *mwi_send_thread(void *data)
07925 {
07926    struct mwi_thread_data *mtd = data;
07927    struct timeval timeout_basis, suspend, now;
07928    int x, i, res;
07929    int num_read;
07930    enum mwisend_states mwi_send_state = MWI_SEND_SPILL; /*Assume FSK only */
07931 
07932    ast_mutex_lock(&mwi_thread_lock);
07933    mwi_thread_count++;
07934    ast_mutex_unlock(&mwi_thread_lock);
07935 
07936    /* Determine how this spill is to be sent */
07937    if(mwisend_rpas) {
07938       mwi_send_state = MWI_SEND_SA;
07939    }
07940 
07941    gettimeofday(&timeout_basis, NULL);
07942    
07943    mtd->pvt->cidspill = ast_calloc(1, MAX_CALLERID_SIZE);
07944    if (!mtd->pvt->cidspill) {
07945       mtd->pvt->mwisendactive = 0;
07946       ast_free(mtd);
07947       return NULL;
07948    }
07949    x = DAHDI_FLUSH_BOTH;
07950    res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_FLUSH, &x);
07951    x = 3000;
07952    ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_ONHOOKTRANSFER, &x);
07953    mtd->pvt->cidlen = vmwi_generate(mtd->pvt->cidspill, has_voicemail(mtd->pvt), CID_MWI_TYPE_MDMF_FULL,
07954                             AST_LAW(mtd->pvt), mtd->pvt->cid_name, mtd->pvt->cid_num, 0);
07955    mtd->pvt->cidpos = 0;
07956 
07957    while (MWI_SEND_DONE != mwi_send_state) {
07958       num_read = 0;
07959       gettimeofday(&now, NULL);
07960       if ( 10 < (now.tv_sec - timeout_basis.tv_sec)) {
07961          ast_log(LOG_WARNING, "MWI Send TIMEOUT in state %d\n", mwi_send_state);
07962          goto quit;
07963       }
07964 
07965       i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
07966       if ((res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_IOMUX, &i))) {
07967          ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
07968          goto quit;
07969       }
07970 
07971       if (i & DAHDI_IOMUX_SIGEVENT) {
07972          /* If we get an event, screen out events that we do not act on.
07973          * Otherwise, let handle_init_event determine what is needed
07974          */
07975          res = dahdi_get_event(mtd->pvt->subs[SUB_REAL].dfd);
07976          switch (res) {
07977             case DAHDI_EVENT_RINGEROFF:
07978                if(mwi_send_state == MWI_SEND_SA_WAIT) {
07979                   if (dahdi_set_hook(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_RINGOFF) ) {
07980                      ast_log(LOG_WARNING, "Unable to finsh RP-AS: %s\n", strerror(errno));
07981                      goto quit;
07982                   }
07983                   mwi_send_state = MWI_SEND_PAUSE;
07984                   gettimeofday(&suspend, NULL);
07985                }
07986                break;
07987             case DAHDI_EVENT_RINGERON:
07988             case DAHDI_EVENT_HOOKCOMPLETE:
07989                break;
07990             default:
07991                /* Got to the default init event handler */
07992                if (0 < handle_init_event(mtd->pvt, res)) {
07993                   /* I've spawned a thread, get out */
07994                   goto quit;
07995                }
07996                break;
07997          }
07998       } else if (i & DAHDI_IOMUX_READ) {
07999          if ((num_read = read(mtd->pvt->subs[SUB_REAL].dfd, mtd->buf, sizeof(mtd->buf))) < 0) {
08000             if (errno != ELAST) {
08001                ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
08002                goto quit;
08003             }
08004             break;
08005          }
08006       }
08007       /* Perform mwi send action */
08008       switch ( mwi_send_state) {
08009          case MWI_SEND_SA:
08010             /* Send the Ring Pulse Signal Alert */
08011             res = ioctl(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &AS_RP_cadence);
08012             if (res) {
08013                ast_log(LOG_WARNING, "Unable to set RP-AS ring cadence: %s\n", strerror(errno));
08014                goto quit;
08015             }
08016             dahdi_set_hook(mtd->pvt->subs[SUB_REAL].dfd, DAHDI_RING);
08017             mwi_send_state = MWI_SEND_SA_WAIT;
08018             break;
08019             case MWI_SEND_SA_WAIT:  /* do nothing until I get RINGEROFF event */
08020                break;
08021                case MWI_SEND_PAUSE:  /* Wait between alert and spill - min of 500 mS*/
08022                   gettimeofday(&now, NULL);
08023                   if ((int)(now.tv_sec - suspend.tv_sec) * 1000000 + (int)now.tv_usec - (int)suspend.tv_usec > 500000) {
08024                      mwi_send_state = MWI_SEND_SPILL;
08025                   }
08026                   break;
08027          case MWI_SEND_SPILL:
08028             /* We read some number of bytes.  Write an equal amount of data */
08029             if(0 < num_read) {
08030                if (num_read > mtd->pvt->cidlen - mtd->pvt->cidpos)
08031                   num_read = mtd->pvt->cidlen - mtd->pvt->cidpos;
08032                res = write(mtd->pvt->subs[SUB_REAL].dfd, mtd->pvt->cidspill + mtd->pvt->cidpos, num_read);
08033                if (res > 0) {
08034                   mtd->pvt->cidpos += res;
08035                   if (mtd->pvt->cidpos >= mtd->pvt->cidlen) {
08036                      ast_free(mtd->pvt->cidspill);
08037                      mtd->pvt->cidspill = NULL;
08038                      mtd->pvt->cidpos = 0;
08039                      mtd->pvt->cidlen = 0;
08040                      mwi_send_state = MWI_SEND_CLEANUP;
08041                   }
08042                } else {
08043                   ast_log(LOG_WARNING, "MWI Send Write failed: %s\n", strerror(errno));
08044                   goto quit;
08045                }
08046             }
08047             break;
08048          case MWI_SEND_CLEANUP:
08049             /* For now, do nothing */
08050             mwi_send_state = MWI_SEND_DONE;
08051             break;
08052          default:
08053             /* Should not get here, punt*/
08054             goto quit;
08055             break;
08056       }
08057    }
08058 
08059 quit:
08060    if(mtd->pvt->cidspill) {
08061       ast_free(mtd->pvt->cidspill);
08062       mtd->pvt->cidspill = NULL;
08063    }
08064    mtd->pvt->mwisendactive = 0;
08065    ast_free(mtd);
08066 
08067    ast_mutex_lock(&mwi_thread_lock);
08068    mwi_thread_count--;
08069    ast_cond_signal(&mwi_thread_complete);
08070    ast_mutex_unlock(&mwi_thread_lock);
08071 
08072    return NULL;
08073 }
08074 
08075 
08076 /* destroy a DAHDI channel, identified by its number */
08077 static int dahdi_destroy_channel_bynum(int channel)
08078 {
08079    struct dahdi_pvt *tmp = NULL;
08080    struct dahdi_pvt *prev = NULL;
08081 
08082    tmp = iflist;
08083    while (tmp) {
08084       if (tmp->channel == channel) {
08085          int x = DAHDI_FLASH;
08086          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 */
08087          destroy_channel(prev, tmp, 1);
08088          ast_module_unref(ast_module_info->self);
08089          return RESULT_SUCCESS;
08090       }
08091       prev = tmp;
08092       tmp = tmp->next;
08093    }
08094    return RESULT_FAILURE;
08095 }
08096 
08097 static struct dahdi_pvt *handle_init_event(struct dahdi_pvt *i, int event)
08098 {
08099    int res;
08100    pthread_t threadid;
08101    struct ast_channel *chan;
08102 
08103    /* Handle an event on a given channel for the monitor thread. */
08104 
08105    switch (event) {
08106    case DAHDI_EVENT_NONE:
08107    case DAHDI_EVENT_BITSCHANGED:
08108       break;
08109    case DAHDI_EVENT_WINKFLASH:
08110    case DAHDI_EVENT_RINGOFFHOOK:
08111       if (i->inalarm) break;
08112       if (i->radio) break;
08113       /* Got a ring/answer.  What kind of channel are we? */
08114       switch (i->sig) {
08115       case SIG_FXOLS:
08116       case SIG_FXOGS:
08117       case SIG_FXOKS:
08118          res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
08119          if (res && (errno == EBUSY))
08120             break;
08121          if (i->cidspill) {
08122             /* Cancel VMWI spill */
08123             ast_free(i->cidspill);
08124             i->cidspill = NULL;
08125          }
08126          if (i->immediate) {
08127             dahdi_enable_ec(i);
08128             /* The channel is immediately up.  Start right away */
08129             res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_RINGTONE);
08130             chan = dahdi_new(i, AST_STATE_RING, 1, SUB_REAL, 0, 0);
08131             if (!chan) {
08132                ast_log(LOG_WARNING, "Unable to start PBX on channel %d\n", i->channel);
08133                res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
08134                if (res < 0)
08135                   ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
08136             }
08137          } else {
08138             /* Check for callerid, digits, etc */
08139             chan = dahdi_new(i, AST_STATE_RESERVED, 0, SUB_REAL, 0, 0);
08140             if (chan) {
08141                if (has_voicemail(i))
08142                   res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_STUTTER);
08143                else
08144                   res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_DIALTONE);
08145                if (res < 0) 
08146                   ast_log(LOG_WARNING, "Unable to play dialtone on channel %d, do you have defaultzone and loadzone defined?\n", i->channel);
08147                if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
08148                   ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
08149                   res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
08150                   if (res < 0)
08151                      ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
08152                   ast_hangup(chan);
08153                }
08154             } else
08155                ast_log(LOG_WARNING, "Unable to create channel\n");
08156          }
08157          break;
08158       case SIG_FXSLS:
08159       case SIG_FXSGS:
08160       case SIG_FXSKS:
08161             i->ringt = i->ringt_base;
08162             /* Fall through */
08163       case SIG_EMWINK:
08164       case SIG_FEATD:
08165       case SIG_FEATDMF:
08166       case SIG_FEATDMF_TA:
08167       case SIG_E911:
08168       case SIG_FGC_CAMA:
08169       case SIG_FGC_CAMAMF:
08170       case SIG_FEATB:
08171       case SIG_EM:
08172       case SIG_EM_E1:
08173       case SIG_SFWINK:
08174       case SIG_SF_FEATD:
08175       case SIG_SF_FEATDMF:
08176       case SIG_SF_FEATB:
08177       case SIG_SF:
08178          /* Check for callerid, digits, etc */
08179          if (i->cid_start == CID_START_POLARITY_IN) {
08180             chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0);
08181          } else {
08182             chan = dahdi_new(i, AST_STATE_RING, 0, SUB_REAL, 0, 0);
08183          }
08184 
08185          if (!chan) {
08186             ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
08187          } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
08188             ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
08189             res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
08190             if (res < 0) {
08191                ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
08192             }
08193             ast_hangup(chan);
08194          }
08195          break;
08196       default:
08197          ast_log(LOG_WARNING, "Don't know how to handle ring/answer with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
08198          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
08199          if (res < 0)
08200                ast_log(LOG_WARNING, "Unable to play congestion tone on channel %d\n", i->channel);
08201          return NULL;
08202       }
08203       break;
08204    case DAHDI_EVENT_NOALARM:
08205       i->inalarm = 0;
08206       ast_log(LOG_NOTICE, "Alarm cleared on channel %d\n", i->channel);
08207       manager_event(EVENT_FLAG_SYSTEM, "AlarmClear",
08208          "Channel: %d\r\n", i->channel);
08209       break;
08210    case DAHDI_EVENT_ALARM:
08211       i->inalarm = 1;
08212       res = get_alarms(i);
08213       handle_alarms(i, res);
08214       /* fall thru intentionally */
08215    case DAHDI_EVENT_ONHOOK:
08216       if (i->radio)
08217          break;
08218       /* Back on hook.  Hang up. */
08219       switch (i->sig) {
08220       case SIG_FXOLS:
08221       case SIG_FXOGS:
08222       case SIG_FEATD:
08223       case SIG_FEATDMF:
08224       case SIG_FEATDMF_TA:
08225       case SIG_E911:
08226       case SIG_FGC_CAMA:
08227       case SIG_FGC_CAMAMF:
08228       case SIG_FEATB:
08229       case SIG_EM:
08230       case SIG_EM_E1:
08231       case SIG_EMWINK:
08232       case SIG_SF_FEATD:
08233       case SIG_SF_FEATDMF:
08234       case SIG_SF_FEATB:
08235       case SIG_SF:
08236       case SIG_SFWINK:
08237       case SIG_FXSLS:
08238       case SIG_FXSGS:
08239       case SIG_FXSKS:
08240       case SIG_GR303FXSKS:
08241          dahdi_disable_ec(i);
08242          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
08243          dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
08244          break;
08245       case SIG_GR303FXOKS:
08246       case SIG_FXOKS:
08247          dahdi_disable_ec(i);
08248          /* Diddle the battery for the zhone */
08249 #ifdef ZHONE_HACK
08250          dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
08251          usleep(1);
08252 #endif         
08253          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
08254          dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
08255          break;
08256       case SIG_PRI:
08257       case SIG_SS7:
08258       case SIG_BRI:
08259       case SIG_BRI_PTMP:
08260          dahdi_disable_ec(i);
08261          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
08262          break;
08263       default:
08264          ast_log(LOG_WARNING, "Don't know how to handle on hook with signalling %s on channel %d\n", sig2str(i->sig), i->channel);
08265          res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
08266          return NULL;
08267       }
08268       break;
08269    case DAHDI_EVENT_POLARITY:
08270       switch (i->sig) {
08271       case SIG_FXSLS:
08272       case SIG_FXSKS:
08273       case SIG_FXSGS:
08274          /* We have already got a PR before the channel was 
08275             created, but it wasn't handled. We need polarity 
08276             to be REV for remote hangup detection to work. 
08277             At least in Spain */
08278          if (i->hanguponpolarityswitch)
08279             i->polarity = POLARITY_REV;
08280          if (i->cid_start == CID_START_POLARITY || i->cid_start == CID_START_POLARITY_IN) {
08281             i->polarity = POLARITY_REV;
08282             ast_verb(2, "Starting post polarity "
08283                    "CID detection on channel %d\n",
08284                    i->channel);
08285             chan = dahdi_new(i, AST_STATE_PRERING, 0, SUB_REAL, 0, 0);
08286             if (!chan) {
08287                ast_log(LOG_WARNING, "Cannot allocate new structure on channel %d\n", i->channel);
08288             } else if (ast_pthread_create_detached(&threadid, NULL, ss_thread, chan)) {
08289                ast_log(LOG_WARNING, "Unable to start simple switch thread on channel %d\n", i->channel);
08290             }
08291          }
08292          break;
08293       default:
08294          ast_log(LOG_WARNING, "handle_init_event detected "
08295             "polarity reversal on non-FXO (SIG_FXS) "
08296             "interface %d\n", i->channel);
08297       }
08298       break;
08299    case DAHDI_EVENT_REMOVED: /* destroy channel, will actually do so in do_monitor */
08300       ast_log(LOG_NOTICE, 
08301             "Got DAHDI_EVENT_REMOVED. Destroying channel %d\n", 
08302             i->channel);
08303       return i;
08304    case DAHDI_EVENT_NEONMWI_ACTIVE:
08305       if (i->mwimonitor_neon) {
08306          notify_message(i->mailbox, 1);
08307          ast_log(LOG_NOTICE, "NEON MWI set for channel %d, mailbox %s \n", i->channel, i->mailbox);
08308       }
08309       break;
08310    case DAHDI_EVENT_NEONMWI_INACTIVE:
08311       if (i->mwimonitor_neon) {
08312          notify_message(i->mailbox, 0);
08313          ast_log(LOG_NOTICE, "NEON MWI cleared for channel %d, mailbox %s\n", i->channel, i->mailbox);
08314       }
08315       break;
08316    }
08317    return NULL;
08318 }
08319 
08320 static void *do_monitor(void *data)
08321 {
08322    int count, res, res2, spoint, pollres=0;
08323    struct dahdi_pvt *i;
08324    struct dahdi_pvt *last = NULL;
08325    struct dahdi_pvt *doomed;
08326    time_t thispass = 0, lastpass = 0;
08327    int found;
08328    char buf[1024];
08329    struct pollfd *pfds=NULL;
08330    int lastalloc = -1;
08331    /* This thread monitors all the frame relay interfaces which are not yet in use
08332       (and thus do not have a separate thread) indefinitely */
08333    /* From here on out, we die whenever asked */
08334 #if 0
08335    if (pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL)) {
08336       ast_log(LOG_WARNING, "Unable to set cancel type to asynchronous\n");
08337       return NULL;
08338    }
08339    ast_debug(1, "Monitor starting...\n");
08340 #endif
08341    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
08342 
08343    for (;;) {
08344       /* Lock the interface list */
08345       ast_mutex_lock(&iflock);
08346       if (!pfds || (lastalloc != ifcount)) {
08347          if (pfds) {
08348             ast_free(pfds);
08349             pfds = NULL;
08350          }
08351          if (ifcount) {
08352             if (!(pfds = ast_calloc(1, ifcount * sizeof(*pfds)))) {
08353                ast_mutex_unlock(&iflock);
08354                return NULL;
08355             }
08356          }
08357          lastalloc = ifcount;
08358       }
08359       /* Build the stuff we're going to poll on, that is the socket of every
08360          dahdi_pvt that does not have an associated owner channel */
08361       count = 0;
08362       i = iflist;
08363       while (i) {
08364          if ((i->subs[SUB_REAL].dfd > -1) && i->sig && (!i->radio)) {
08365             if (!i->owner && !i->subs[SUB_REAL].owner && !i->mwimonitoractive && !i->mwisendactive) {
08366                /* This needs to be watched, as it lacks an owner */
08367                pfds[count].fd = i->subs[SUB_REAL].dfd;
08368                pfds[count].events = POLLPRI;
08369                pfds[count].revents = 0;
08370                /* If we are monitoring for VMWI or sending CID, we need to
08371                   read from the channel as well */
08372                if (i->cidspill || i->mwimonitor_fsk)
08373                   pfds[count].events |= POLLIN;
08374                count++;
08375             }
08376          }
08377          i = i->next;
08378       }
08379       /* Okay, now that we know what to do, release the interface lock */
08380       ast_mutex_unlock(&iflock);
08381       
08382       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
08383       pthread_testcancel();
08384       /* Wait at least a second for something to happen */
08385       res = poll(pfds, count, 1000);
08386       pthread_testcancel();
08387       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
08388 
08389       /* Okay, poll has finished.  Let's see what happened.  */
08390       if (res < 0) {
08391          if ((errno != EAGAIN) && (errno != EINTR))
08392             ast_log(LOG_WARNING, "poll return %d: %s\n", res, strerror(errno));
08393          continue;
08394       }
08395       /* Alright, lock the interface list again, and let's look and see what has
08396          happened */
08397       ast_mutex_lock(&iflock);
08398       found = 0;
08399       spoint = 0;
08400       lastpass = thispass;
08401       thispass = time(NULL);
08402       i = iflist;
08403       doomed = NULL;
08404       for (i = iflist;; i = i->next) {
08405          if (doomed) {
08406             int res;
08407             res = dahdi_destroy_channel_bynum(doomed->channel);
08408             if (!res) {
08409                ast_log(LOG_WARNING, "Couldn't find channel to destroy, hopefully another destroy operation just happened.\n");
08410             }
08411             doomed = NULL;
08412          }
08413          if (!i) {
08414             break;
08415          }
08416 
08417          if (thispass != lastpass) {
08418             if (!found && ((i == last) || ((i == iflist) && !last))) {
08419                last = i;
08420                if (last) {
08421                   if (!last->mwisendactive &&    last->sig & __DAHDI_SIG_FXO) {
08422                      res = has_voicemail(last);
08423                      if (last->msgstate != res) {
08424 
08425                         /* This channel has a new voicemail state,
08426                         * initiate a thread to send an MWI message
08427                         */
08428                         pthread_attr_t attr;
08429                         pthread_t threadid;
08430                         struct mwi_thread_data *mtd;
08431                         res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_VMWI, &res);
08432                         if (res2) {
08433                            /* TODO: This message will ALWAYS be generated on some cards; any way to restrict it to those cards where it is interesting? */
08434                            ast_debug(3, "Unable to control message waiting led on channel %d: %s\n", last->channel, strerror(errno));
08435                         }
08436                         pthread_attr_init(&attr);
08437                         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
08438                         if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
08439                            last->msgstate = res;
08440                            mtd->pvt = last;
08441                            last->mwisendactive = 1;
08442                            if (ast_pthread_create_background(&threadid, &attr, mwi_send_thread, mtd)) {
08443                               ast_log(LOG_WARNING, "Unable to start mwi send thread on channel %d\n", last->channel);
08444                               ast_free(mtd);
08445                               last->mwisendactive = 0;
08446                            }
08447                         }
08448                         found ++;
08449                      }
08450                   }
08451                   last = last->next;
08452                }
08453             }
08454          }
08455          if ((i->subs[SUB_REAL].dfd > -1) && i->sig) {
08456             if (i->radio && !i->owner)
08457             {
08458                res = dahdi_get_event(i->subs[SUB_REAL].dfd);
08459                if (res)
08460                {
08461                   ast_debug(1, "Monitor doohicky got event %s on radio channel %d\n", event2str(res), i->channel);
08462                   /* Don't hold iflock while handling init events */
08463                   ast_mutex_unlock(&iflock);
08464                   doomed = handle_init_event(i, res);
08465                   ast_mutex_lock(&iflock);   
08466                }
08467                continue;
08468             }              
08469             pollres = ast_fdisset(pfds, i->subs[SUB_REAL].dfd, count, &spoint);
08470             if (pollres & POLLIN) {
08471                if (i->owner || i->subs[SUB_REAL].owner) {
08472 #ifdef HAVE_PRI
08473                   if (!i->pri)
08474 #endif                  
08475                      ast_log(LOG_WARNING, "Whoa....  I'm owned but found (%d) in read...\n", i->subs[SUB_REAL].dfd);
08476                   continue;
08477                }
08478                if (!i->cidspill && !i->mwimonitor_fsk) {
08479                   ast_log(LOG_WARNING, "Whoa....  I'm reading but have no cidspill (%d)...\n", i->subs[SUB_REAL].dfd);
08480                   continue;
08481                }
08482                res = read(i->subs[SUB_REAL].dfd, buf, sizeof(buf));
08483                if (res > 0) {
08484                   if (i->mwimonitor_fsk) {
08485                      if (calc_energy((unsigned char *) buf, res, AST_LAW(i)) > mwilevel) {
08486                         pthread_attr_t attr;
08487                         pthread_t threadid;
08488                         struct mwi_thread_data *mtd;
08489 
08490                         pthread_attr_init(&attr);
08491                         pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
08492 
08493                         ast_log(LOG_DEBUG, "Maybe some MWI on port %d!\n", i->channel);
08494                         if ((mtd = ast_calloc(1, sizeof(*mtd)))) {
08495                            mtd->pvt = i;
08496                            memcpy(mtd->buf, buf, res);
08497                            mtd->len = res;
08498                            if (ast_pthread_create_background(&threadid, &attr, mwi_thread, mtd)) {
08499                               ast_log(LOG_WARNING, "Unable to start mwi thread on channel %d\n", i->channel);
08500                               ast_free(mtd);
08501                            }
08502                            i->mwimonitoractive = 1;
08503                         }
08504                      }
08505                   }
08506                } else {
08507                   ast_log(LOG_WARNING, "Read failed with %d: %s\n", res, strerror(errno));
08508                }
08509             }
08510             if (pollres & POLLPRI) {
08511                if (i->owner || i->subs[SUB_REAL].owner) {
08512 #ifdef HAVE_PRI
08513                   if (!i->pri)
08514 #endif                  
08515                      ast_log(LOG_WARNING, "Whoa....  I'm owned but found (%d)...\n", i->subs[SUB_REAL].dfd);
08516                   continue;
08517                }
08518                res = dahdi_get_event(i->subs[SUB_REAL].dfd);
08519                ast_debug(1, "Monitor doohicky got event %s on channel %d\n", event2str(res), i->channel);
08520                /* Don't hold iflock while handling init events */
08521                ast_mutex_unlock(&iflock);
08522                doomed = handle_init_event(i, res);
08523                ast_mutex_lock(&iflock);   
08524             }
08525          }
08526       }
08527       ast_mutex_unlock(&iflock);
08528    }
08529    /* Never reached */
08530    return NULL;
08531    
08532 }
08533 
08534 static int restart_monitor(void)
08535 {
08536    /* If we're supposed to be stopped -- stay stopped */
08537    if (monitor_thread == AST_PTHREADT_STOP)
08538       return 0;
08539    ast_mutex_lock(&monlock);
08540    if (monitor_thread == pthread_self()) {
08541       ast_mutex_unlock(&monlock);
08542       ast_log(LOG_WARNING, "Cannot kill myself\n");
08543       return -1;
08544    }
08545    if (monitor_thread != AST_PTHREADT_NULL) {
08546       /* Wake up the thread */
08547       pthread_kill(monitor_thread, SIGURG);
08548    } else {
08549       /* Start a new monitor */
08550       if (ast_pthread_create_background(&monitor_thread, NULL, do_monitor, NULL) < 0) {
08551          ast_mutex_unlock(&monlock);
08552          ast_log(LOG_ERROR, "Unable to start monitor thread.\n");
08553          return -1;
08554       }
08555    }
08556    ast_mutex_unlock(&monlock);
08557    return 0;
08558 }
08559 
08560 #ifdef HAVE_PRI
08561 static int pri_resolve_span(int *span, int channel, int offset, struct dahdi_spaninfo *si)
08562 {
08563    int x;
08564    int trunkgroup;
08565    /* Get appropriate trunk group if there is one */
08566    trunkgroup = pris[*span].mastertrunkgroup;
08567    if (trunkgroup) {
08568       /* Select a specific trunk group */
08569       for (x = 0; x < NUM_SPANS; x++) {
08570          if (pris[x].trunkgroup == trunkgroup) {
08571             *span = x;
08572             return 0;
08573          }
08574       }
08575       ast_log(LOG_WARNING, "Channel %d on span %d configured to use nonexistent trunk group %d\n", channel, *span, trunkgroup);
08576       *span = -1;
08577    } else {
08578       if (pris[*span].trunkgroup) {
08579          ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is trunk group %d (please use spanmap)\n", *span, pris[*span].trunkgroup);
08580          *span = -1;
08581       } else if (pris[*span].mastertrunkgroup) {
08582          ast_log(LOG_WARNING, "Unable to use span %d implicitly since it is already part of trunk group %d\n", *span, pris[*span].mastertrunkgroup);
08583          *span = -1;
08584       } else {
08585          if (si->totalchans == 31) {
08586             /* E1 */
08587             pris[*span].dchannels[0] = 16 + offset;
08588          } else if (si->totalchans == 24) {
08589             /* T1 or J1 */
08590             pris[*span].dchannels[0] = 24 + offset;
08591          } else if (si->totalchans == 3) {
08592             /* BRI */
08593             pris[*span].dchannels[0] = 3 + offset;
08594          } else {
08595             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);
08596             *span = -1;
08597             return 0;
08598          }
08599          pris[*span].dchanavail[0] |= DCHAN_PROVISIONED;
08600          pris[*span].offset = offset;
08601          pris[*span].span = *span + 1;
08602       }
08603    }
08604    return 0;
08605 }
08606 
08607 static int pri_create_trunkgroup(int trunkgroup, int *channels)
08608 {
08609    struct dahdi_spaninfo si;
08610    struct dahdi_params p;
08611    int fd;
08612    int span;
08613    int ospan=0;
08614    int x,y;
08615    for (x = 0; x < NUM_SPANS; x++) {
08616       if (pris[x].trunkgroup == trunkgroup) {
08617          ast_log(LOG_WARNING, "Trunk group %d already exists on span %d, Primary d-channel %d\n", trunkgroup, x + 1, pris[x].dchannels[0]);
08618          return -1;
08619       }
08620    }
08621    for (y = 0; y < NUM_DCHANS; y++) {
08622       if (!channels[y]) 
08623          break;
08624       memset(&si, 0, sizeof(si));
08625       memset(&p, 0, sizeof(p));
08626       fd = open("/dev/dahdi/channel", O_RDWR);
08627       if (fd < 0) {
08628          ast_log(LOG_WARNING, "Failed to open channel: %s\n", strerror(errno));
08629          return -1;
08630       }
08631       x = channels[y];
08632       if (ioctl(fd, DAHDI_SPECIFY, &x)) {
08633          ast_log(LOG_WARNING, "Failed to specify channel %d: %s\n", channels[y], strerror(errno));
08634          close(fd);
08635          return -1;
08636       }
08637       if (ioctl(fd, DAHDI_GET_PARAMS, &p)) {
08638          ast_log(LOG_WARNING, "Failed to get channel parameters for channel %d: %s\n", channels[y], strerror(errno));
08639          return -1;
08640       }
08641       if (ioctl(fd, DAHDI_SPANSTAT, &si)) {
08642          ast_log(LOG_WARNING, "Failed go get span information on channel %d (span %d): %s\n", channels[y], p.spanno, strerror(errno));
08643          close(fd);
08644          return -1;
08645       }
08646       span = p.spanno - 1;
08647       if (pris[span].trunkgroup) {
08648          ast_log(LOG_WARNING, "Span %d is already provisioned for trunk group %d\n", span + 1, pris[span].trunkgroup);
08649          close(fd);
08650          return -1;
08651       }
08652       if (pris[span].pvts[0]) {
08653          ast_log(LOG_WARNING, "Span %d is already provisioned with channels (implicit PRI maybe?)\n", span + 1);
08654          close(fd);
08655          return -1;
08656       }
08657       if (!y) {
08658          pris[span].trunkgroup = trunkgroup;
08659          pris[span].offset = channels[y] - p.chanpos;
08660          ospan = span;
08661       }
08662       pris[ospan].dchannels[y] = channels[y];
08663       pris[ospan].dchanavail[y] |= DCHAN_PROVISIONED;
08664       pris[span].span = span + 1;
08665       close(fd);
08666    }
08667    return 0;   
08668 }
08669 
08670 static int pri_create_spanmap(int span, int trunkgroup, int logicalspan)
08671 {
08672    if (pris[span].mastertrunkgroup) {
08673       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);
08674       return -1;
08675    }
08676    pris[span].mastertrunkgroup = trunkgroup;
08677    pris[span].prilogicalspan = logicalspan;
08678    return 0;
08679 }
08680 
08681 #endif
08682 
08683 #ifdef HAVE_SS7
08684 
08685 static unsigned int parse_pointcode(const char *pcstring)
08686 {
08687    unsigned int code1, code2, code3;
08688    int numvals;
08689 
08690    numvals = sscanf(pcstring, "%30d-%30d-%30d", &code1, &code2, &code3);
08691    if (numvals == 1)
08692       return code1;
08693    if (numvals == 3)
08694       return (code1 << 16) | (code2 << 8) | code3;
08695 
08696    return 0;
08697 }
08698 
08699 static struct dahdi_ss7 * ss7_resolve_linkset(int linkset)
08700 {
08701    if ((linkset < 0) || (linkset >= NUM_SPANS))
08702       return NULL;
08703    else
08704       return &linksets[linkset - 1];
08705 }
08706 #endif /* HAVE_SS7 */
08707 
08708 /* converts a DAHDI sigtype to signalling as can be configured from
08709  * chan_dahdi.conf.
08710  * While both have basically the same values, this will later be the
08711  * place to add filters and sanity checks
08712  */
08713 static int sigtype_to_signalling(int sigtype)
08714 {
08715         return sigtype;
08716 }
08717 
08718 static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf, struct dahdi_pri *pri, int reloading)
08719 {
08720    /* Make a dahdi_pvt structure for this interface (or CRV if "pri" is specified) */
08721    struct dahdi_pvt *tmp = NULL, *tmp2,  *prev = NULL;
08722    char fn[80];
08723    struct dahdi_bufferinfo bi;
08724 
08725    int res;
08726    int span = 0;
08727    int here = 0;
08728    int x;
08729    struct dahdi_pvt **wlist;
08730    struct dahdi_pvt **wend;
08731    struct dahdi_params p;
08732 
08733    wlist = &iflist;
08734    wend = &ifend;
08735 
08736 #ifdef HAVE_PRI
08737    if (pri) {
08738       wlist = &pri->crvs;
08739       wend = &pri->crvend;
08740    }
08741 #endif
08742 
08743    tmp2 = *wlist;
08744    prev = NULL;
08745 
08746    while (tmp2) {
08747       if (!tmp2->destroy) {
08748          if (tmp2->channel == channel) {
08749             tmp = tmp2;
08750             here = 1;
08751             break;
08752          }
08753          if (tmp2->channel > channel) {
08754             break;
08755          }
08756       }
08757       prev = tmp2;
08758       tmp2 = tmp2->next;
08759    }
08760 
08761    if (!here && reloading != 1) {
08762       if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
08763          if (tmp)
08764             free(tmp);
08765          return NULL;
08766       }
08767       ast_mutex_init(&tmp->lock);
08768       ifcount++;
08769       for (x = 0; x < 3; x++)
08770          tmp->subs[x].dfd = -1;
08771       tmp->channel = channel;
08772       tmp->priindication_oob = conf->chan.priindication_oob;
08773    }
08774 
08775    if (tmp) {
08776       int chan_sig = conf->chan.sig;
08777       if (!here) {
08778          if ((channel != CHAN_PSEUDO) && !pri) {
08779             int count = 0;
08780             snprintf(fn, sizeof(fn), "%d", channel);
08781             /* Open non-blocking */
08782             tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
08783             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 */
08784                usleep(1);
08785                tmp->subs[SUB_REAL].dfd = dahdi_open(fn);
08786                count++;
08787             }
08788             /* Allocate a DAHDI structure */
08789             if (tmp->subs[SUB_REAL].dfd < 0) {
08790                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);
08791                destroy_dahdi_pvt(&tmp);
08792                return NULL;
08793             }
08794             memset(&p, 0, sizeof(p));
08795             res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
08796             if (res < 0) {
08797                ast_log(LOG_ERROR, "Unable to get parameters: %s\n", strerror(errno));
08798                destroy_dahdi_pvt(&tmp);
08799                return NULL;
08800             }
08801             if (conf->is_sig_auto)
08802                chan_sig = sigtype_to_signalling(p.sigtype);
08803             if (p.sigtype != (chan_sig & 0x3ffff)) {
08804                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));
08805                destroy_dahdi_pvt(&tmp);
08806                return NULL;
08807             }
08808             tmp->law = p.curlaw;
08809             tmp->span = p.spanno;
08810             span = p.spanno - 1;
08811          } else {
08812             if (channel == CHAN_PSEUDO)
08813                chan_sig = 0;
08814             else if ((chan_sig != SIG_FXOKS) && (chan_sig != SIG_FXSKS)) {
08815                ast_log(LOG_ERROR, "CRV's must use FXO/FXS Kewl Start (fxo_ks/fxs_ks) signalling only.\n");
08816                return NULL;
08817             }
08818          }
08819 #ifdef HAVE_SS7
08820          if (chan_sig == SIG_SS7) {
08821             struct dahdi_ss7 *ss7;
08822             int clear = 0;
08823             if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &clear)) {
08824                ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
08825                destroy_dahdi_pvt(&tmp);
08826                return NULL;
08827             }
08828 
08829             ss7 = ss7_resolve_linkset(cur_linkset);
08830             if (!ss7) {
08831                ast_log(LOG_ERROR, "Unable to find linkset %d\n", cur_linkset);
08832                destroy_dahdi_pvt(&tmp);
08833                return NULL;
08834             }
08835             if (cur_cicbeginswith < 0) {
08836                ast_log(LOG_ERROR, "Need to set cicbeginswith for the channels!\n");
08837                destroy_dahdi_pvt(&tmp);
08838                return NULL;
08839             }
08840 
08841             tmp->cic = cur_cicbeginswith++;
08842 
08843             /* DB: Add CIC's DPC information */
08844             tmp->dpc = cur_defaultdpc;
08845 
08846             tmp->ss7 = ss7;
08847             tmp->ss7call = NULL;
08848             ss7->pvts[ss7->numchans++] = tmp;
08849 
08850             ast_copy_string(ss7->internationalprefix, conf->ss7.internationalprefix, sizeof(ss7->internationalprefix));
08851             ast_copy_string(ss7->nationalprefix, conf->ss7.nationalprefix, sizeof(ss7->nationalprefix));
08852             ast_copy_string(ss7->subscriberprefix, conf->ss7.subscriberprefix, sizeof(ss7->subscriberprefix));
08853             ast_copy_string(ss7->unknownprefix, conf->ss7.unknownprefix, sizeof(ss7->unknownprefix));
08854 
08855             ss7->called_nai = conf->ss7.called_nai;
08856             ss7->calling_nai = conf->ss7.calling_nai;
08857          }
08858 #endif
08859 #ifdef HAVE_PRI
08860          if ((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP) || (chan_sig == SIG_GR303FXOKS) || (chan_sig == SIG_GR303FXSKS)) {
08861             int offset;
08862             int myswitchtype;
08863             int matchesdchan;
08864             int x,y;
08865             offset = 0;
08866             if (((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP)) 
08867                   && ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &offset)) {
08868                ast_log(LOG_ERROR, "Unable to set clear mode on clear channel %d of span %d: %s\n", channel, p.spanno, strerror(errno));
08869                destroy_dahdi_pvt(&tmp);
08870                return NULL;
08871             }
08872             if (span >= NUM_SPANS) {
08873                ast_log(LOG_ERROR, "Channel %d does not lie on a span I know of (%d)\n", channel, span);
08874                destroy_dahdi_pvt(&tmp);
08875                return NULL;
08876             } else {
08877                struct dahdi_spaninfo si;
08878                si.spanno = 0;
08879                if (ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SPANSTAT,&si) == -1) {
08880                   ast_log(LOG_ERROR, "Unable to get span status: %s\n", strerror(errno));
08881                   destroy_dahdi_pvt(&tmp);
08882                   return NULL;
08883                }
08884                /* Store the logical span first based upon the real span */
08885                tmp->logicalspan = pris[span].prilogicalspan;
08886                pri_resolve_span(&span, channel, (channel - p.chanpos), &si);
08887                if (span < 0) {
08888                   ast_log(LOG_WARNING, "Channel %d: Unable to find locate channel/trunk group!\n", channel);
08889                   destroy_dahdi_pvt(&tmp);
08890                   return NULL;
08891                }
08892                if ((chan_sig == SIG_PRI) ||
08893                      (chan_sig == SIG_BRI) ||
08894                      (chan_sig == SIG_BRI_PTMP))
08895                   myswitchtype = conf->pri.switchtype;
08896                else
08897                   myswitchtype = PRI_SWITCH_GR303_TMC;
08898                /* Make sure this isn't a d-channel */
08899                matchesdchan=0;
08900                for (x = 0; x < NUM_SPANS; x++) {
08901                   for (y = 0; y < NUM_DCHANS; y++) {
08902                      if (pris[x].dchannels[y] == tmp->channel) {
08903                         matchesdchan = 1;
08904                         break;
08905                      }
08906                   }
08907                }
08908                offset = p.chanpos;
08909                if (!matchesdchan) {
08910                   if (pris[span].nodetype && (pris[span].nodetype != conf->pri.nodetype)) {
08911                      ast_log(LOG_ERROR, "Span %d is already a %s node\n", span + 1, pri_node2str(pris[span].nodetype));
08912                      destroy_dahdi_pvt(&tmp);
08913                      return NULL;
08914                   }
08915                   if (pris[span].switchtype && (pris[span].switchtype != myswitchtype)) {
08916                      ast_log(LOG_ERROR, "Span %d is already a %s switch\n", span + 1, pri_switch2str(pris[span].switchtype));
08917                      destroy_dahdi_pvt(&tmp);
08918                      return NULL;
08919                   }
08920                   if ((pris[span].dialplan) && (pris[span].dialplan != conf->pri.dialplan)) {
08921                      ast_log(LOG_ERROR, "Span %d is already a %s dialing plan\n", span + 1, dialplan2str(pris[span].dialplan));
08922                      destroy_dahdi_pvt(&tmp);
08923                      return NULL;
08924                   }
08925                   if (!ast_strlen_zero(pris[span].idledial) && strcmp(pris[span].idledial, conf->pri.idledial)) {
08926                      ast_log(LOG_ERROR, "Span %d already has idledial '%s'.\n", span + 1, conf->pri.idledial);
08927                      destroy_dahdi_pvt(&tmp);
08928                      return NULL;
08929                   }
08930                   if (!ast_strlen_zero(pris[span].idleext) && strcmp(pris[span].idleext, conf->pri.idleext)) {
08931                      ast_log(LOG_ERROR, "Span %d already has idleext '%s'.\n", span + 1, conf->pri.idleext);
08932                      destroy_dahdi_pvt(&tmp);
08933                      return NULL;
08934                   }
08935                   if (pris[span].minunused && (pris[span].minunused != conf->pri.minunused)) {
08936                      ast_log(LOG_ERROR, "Span %d already has minunused of %d.\n", span + 1, conf->pri.minunused);
08937                      destroy_dahdi_pvt(&tmp);
08938                      return NULL;
08939                   }
08940                   if (pris[span].minidle && (pris[span].minidle != conf->pri.minidle)) {
08941                      ast_log(LOG_ERROR, "Span %d already has minidle of %d.\n", span + 1, conf->pri.minidle);
08942                      destroy_dahdi_pvt(&tmp);
08943                      return NULL;
08944                   }
08945                   if (pris[span].numchans >= MAX_CHANNELS) {
08946                      ast_log(LOG_ERROR, "Unable to add channel %d: Too many channels in trunk group %d!\n", channel,
08947                         pris[span].trunkgroup);
08948                      destroy_dahdi_pvt(&tmp);
08949                      return NULL;
08950                   }
08951 
08952                   pris[span].sig = chan_sig;
08953                   pris[span].nodetype = conf->pri.nodetype;
08954                   pris[span].switchtype = myswitchtype;
08955                   pris[span].nsf = conf->pri.nsf;
08956                   pris[span].dialplan = conf->pri.dialplan;
08957                   pris[span].localdialplan = conf->pri.localdialplan;
08958                   pris[span].pvts[pris[span].numchans++] = tmp;
08959                   pris[span].minunused = conf->pri.minunused;
08960                   pris[span].minidle = conf->pri.minidle;
08961                   pris[span].overlapdial = conf->pri.overlapdial;
08962 #ifdef HAVE_PRI_INBANDDISCONNECT
08963                   pris[span].inbanddisconnect = conf->pri.inbanddisconnect;
08964 #endif
08965                   pris[span].facilityenable = conf->pri.facilityenable;
08966                   ast_copy_string(pris[span].idledial, conf->pri.idledial, sizeof(pris[span].idledial));
08967                   ast_copy_string(pris[span].idleext, conf->pri.idleext, sizeof(pris[span].idleext));
08968                   ast_copy_string(pris[span].internationalprefix, conf->pri.internationalprefix, sizeof(pris[span].internationalprefix));
08969                   ast_copy_string(pris[span].nationalprefix, conf->pri.nationalprefix, sizeof(pris[span].nationalprefix));
08970                   ast_copy_string(pris[span].localprefix, conf->pri.localprefix, sizeof(pris[span].localprefix));
08971                   ast_copy_string(pris[span].privateprefix, conf->pri.privateprefix, sizeof(pris[span].privateprefix));
08972                   ast_copy_string(pris[span].unknownprefix, conf->pri.unknownprefix, sizeof(pris[span].unknownprefix));
08973                   pris[span].resetinterval = conf->pri.resetinterval;
08974                   
08975                   tmp->pri = &pris[span];
08976                   tmp->prioffset = offset;
08977                   tmp->call = NULL;
08978                } else {
08979                   ast_log(LOG_ERROR, "Channel %d is reserved for D-channel.\n", offset);
08980                   destroy_dahdi_pvt(&tmp);
08981                   return NULL;
08982                }
08983             }
08984          } else {
08985             tmp->prioffset = 0;
08986          }
08987 #endif
08988       } else {
08989          chan_sig = tmp->sig;
08990          if (tmp->subs[SUB_REAL].dfd > -1) {
08991             memset(&p, 0, sizeof(p));
08992             res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
08993          }
08994       }
08995       /* Adjust starttime on loopstart and kewlstart trunks to reasonable values */
08996       switch (chan_sig) {
08997       case SIG_FXSKS:
08998       case SIG_FXSLS:
08999       case SIG_EM:
09000       case SIG_EM_E1:
09001       case SIG_EMWINK:
09002       case SIG_FEATD:
09003       case SIG_FEATDMF:
09004       case SIG_FEATDMF_TA:
09005       case SIG_FEATB:
09006       case SIG_E911:
09007       case SIG_SF:
09008       case SIG_SFWINK:
09009       case SIG_FGC_CAMA:
09010       case SIG_FGC_CAMAMF:
09011       case SIG_SF_FEATD:
09012       case SIG_SF_FEATDMF:
09013       case SIG_SF_FEATB:
09014          p.starttime = 250;
09015          break;
09016       }
09017 
09018       if (tmp->radio) {
09019          /* XXX Waiting to hear back from Jim if these should be adjustable XXX */
09020          p.channo = channel;
09021          p.rxwinktime = 1;
09022          p.rxflashtime = 1;
09023          p.starttime = 1;
09024          p.debouncetime = 5;
09025       }
09026       if (!tmp->radio) {
09027          p.channo = channel;
09028          /* Override timing settings based on config file */
09029          if (conf->timing.prewinktime >= 0)
09030             p.prewinktime = conf->timing.prewinktime;
09031          if (conf->timing.preflashtime >= 0)
09032             p.preflashtime = conf->timing.preflashtime;
09033          if (conf->timing.winktime >= 0)
09034             p.winktime = conf->timing.winktime;
09035          if (conf->timing.flashtime >= 0)
09036             p.flashtime = conf->timing.flashtime;
09037          if (conf->timing.starttime >= 0)
09038             p.starttime = conf->timing.starttime;
09039          if (conf->timing.rxwinktime >= 0)
09040             p.rxwinktime = conf->timing.rxwinktime;
09041          if (conf->timing.rxflashtime >= 0)
09042             p.rxflashtime = conf->timing.rxflashtime;
09043          if (conf->timing.debouncetime >= 0)
09044             p.debouncetime = conf->timing.debouncetime;
09045       }
09046 
09047       /* dont set parms on a pseudo-channel (or CRV) */
09048       if (tmp->subs[SUB_REAL].dfd >= 0)
09049       {
09050          res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_PARAMS, &p);
09051          if (res < 0) {
09052             ast_log(LOG_ERROR, "Unable to set parameters: %s\n", strerror(errno));
09053             destroy_dahdi_pvt(&tmp);
09054             return NULL;
09055          }
09056       }
09057 #if 1
09058       if (!here && (tmp->subs[SUB_REAL].dfd > -1)) {
09059          memset(&bi, 0, sizeof(bi));
09060          res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
09061          if (!res) {
09062             bi.txbufpolicy = conf->chan.buf_policy;
09063             bi.rxbufpolicy = conf->chan.buf_policy;
09064             bi.numbufs = conf->chan.buf_no;
09065             res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
09066             if (res < 0) {
09067                ast_log(LOG_WARNING, "Unable to set buffer policy on channel %d: %s\n", channel, strerror(errno));
09068             }
09069          } else
09070             ast_log(LOG_WARNING, "Unable to check buffer policy on channel %d: %s\n", channel, strerror(errno));
09071       }
09072 #endif
09073       tmp->immediate = conf->chan.immediate;
09074       tmp->transfertobusy = conf->chan.transfertobusy;
09075       if (chan_sig & __DAHDI_SIG_FXS) {
09076          tmp->mwimonitor_fsk = conf->chan.mwimonitor_fsk;
09077          tmp->mwimonitor_neon = conf->chan.mwimonitor_neon;
09078          tmp->mwimonitor_rpas = conf->chan.mwimonitor_rpas;
09079       }
09080       tmp->sig = chan_sig;
09081       tmp->outsigmod = conf->chan.outsigmod;
09082       tmp->ringt_base = ringt_base;
09083       tmp->firstradio = 0;
09084       if ((chan_sig == SIG_FXOKS) || (chan_sig == SIG_FXOLS) || (chan_sig == SIG_FXOGS))
09085          tmp->permcallwaiting = conf->chan.callwaiting;
09086       else
09087          tmp->permcallwaiting = 0;
09088       /* Flag to destroy the channel must be cleared on new mkif.  Part of changes for reload to work */
09089       tmp->destroy = 0;
09090       tmp->drings = conf->chan.drings;
09091 
09092       /* 10 is a nice default. */
09093       if (tmp->drings.ringnum[0].range == 0)
09094          tmp->drings.ringnum[0].range = 10;
09095       if (tmp->drings.ringnum[1].range == 0)
09096          tmp->drings.ringnum[1].range = 10;
09097       if (tmp->drings.ringnum[2].range == 0)
09098          tmp->drings.ringnum[2].range = 10;
09099 
09100       tmp->usedistinctiveringdetection = usedistinctiveringdetection;
09101       tmp->callwaitingcallerid = conf->chan.callwaitingcallerid;
09102       tmp->threewaycalling = conf->chan.threewaycalling;
09103       tmp->adsi = conf->chan.adsi;
09104       tmp->use_smdi = conf->chan.use_smdi;
09105       tmp->permhidecallerid = conf->chan.hidecallerid;
09106       tmp->callreturn = conf->chan.callreturn;
09107       tmp->echocancel = conf->chan.echocancel;
09108       tmp->echotraining = conf->chan.echotraining;
09109       tmp->pulse = conf->chan.pulse;
09110       if (tmp->echocancel.head.tap_length) {
09111          tmp->echocanbridged = conf->chan.echocanbridged;
09112       } else {
09113          if (conf->chan.echocanbridged)
09114             ast_log(LOG_NOTICE, "echocancelwhenbridged requires echocancel to be enabled; ignoring\n");
09115          tmp->echocanbridged = 0;
09116       }
09117       tmp->busydetect = conf->chan.busydetect;
09118       tmp->busycount = conf->chan.busycount;
09119       tmp->busy_tonelength = conf->chan.busy_tonelength;
09120       tmp->busy_quietlength = conf->chan.busy_quietlength;
09121       tmp->callprogress = conf->chan.callprogress;
09122       tmp->cancallforward = conf->chan.cancallforward;
09123       tmp->dtmfrelax = conf->chan.dtmfrelax;
09124       tmp->callwaiting = tmp->permcallwaiting;
09125       tmp->hidecallerid = tmp->permhidecallerid;
09126       tmp->channel = channel;
09127       tmp->stripmsd = conf->chan.stripmsd;
09128       tmp->use_callerid = conf->chan.use_callerid;
09129       tmp->cid_signalling = conf->chan.cid_signalling;
09130       tmp->cid_start = conf->chan.cid_start;
09131       tmp->dahditrcallerid = conf->chan.dahditrcallerid;
09132       tmp->restrictcid = conf->chan.restrictcid;
09133       tmp->use_callingpres = conf->chan.use_callingpres;
09134       tmp->priexclusive = conf->chan.priexclusive;
09135       if (tmp->usedistinctiveringdetection) {
09136          if (!tmp->use_callerid) {
09137             ast_log(LOG_NOTICE, "Distinctive Ring detect requires 'usecallerid' be on\n");
09138             tmp->use_callerid = 1;
09139          }
09140       }
09141 
09142       if (tmp->cid_signalling == CID_SIG_SMDI) {
09143          if (!tmp->use_smdi) {
09144             ast_log(LOG_WARNING, "SMDI callerid requires SMDI to be enabled, enabling...\n");
09145             tmp->use_smdi = 1;
09146          }
09147       }
09148       if (tmp->use_smdi) {
09149          tmp->smdi_iface = ast_smdi_interface_find(conf->smdi_port);
09150          if (!(tmp->smdi_iface)) {
09151             ast_log(LOG_ERROR, "Invalid SMDI port specfied, disabling SMDI support\n");
09152             tmp->use_smdi = 0;
09153          }
09154       }
09155 
09156       ast_copy_string(tmp->accountcode, conf->chan.accountcode, sizeof(tmp->accountcode));
09157       tmp->amaflags = conf->chan.amaflags;
09158       if (!here) {
09159          tmp->confno = -1;
09160          tmp->propconfno = -1;
09161       }
09162       tmp->canpark = conf->chan.canpark;
09163       tmp->transfer = conf->chan.transfer;
09164       ast_copy_string(tmp->defcontext,conf->chan.context,sizeof(tmp->defcontext));
09165       ast_copy_string(tmp->language, conf->chan.language, sizeof(tmp->language));
09166       ast_copy_string(tmp->mohinterpret, conf->chan.mohinterpret, sizeof(tmp->mohinterpret));
09167       ast_copy_string(tmp->mohsuggest, conf->chan.mohsuggest, sizeof(tmp->mohsuggest));
09168       ast_copy_string(tmp->context, conf->chan.context, sizeof(tmp->context));
09169       ast_copy_string(tmp->parkinglot, conf->chan.parkinglot, sizeof(tmp->parkinglot));
09170       tmp->cid_ton = 0;
09171       if ((tmp->sig != SIG_PRI) || (tmp->sig != SIG_SS7) || (tmp->sig != SIG_BRI) || (tmp->sig != SIG_BRI_PTMP)) {
09172          ast_copy_string(tmp->cid_num, conf->chan.cid_num, sizeof(tmp->cid_num));
09173          ast_copy_string(tmp->cid_name, conf->chan.cid_name, sizeof(tmp->cid_name));
09174       } else {
09175          tmp->cid_num[0] = '\0';
09176          tmp->cid_name[0] = '\0';
09177       }
09178       ast_copy_string(tmp->mailbox, conf->chan.mailbox, sizeof(tmp->mailbox));
09179       if (channel != CHAN_PSEUDO && !ast_strlen_zero(tmp->mailbox)) {
09180          char *mailbox, *context;
09181          mailbox = context = ast_strdupa(tmp->mailbox);
09182          strsep(&context, "@");
09183          if (ast_strlen_zero(context))
09184             context = "default";
09185          tmp->mwi_event_sub = ast_event_subscribe(AST_EVENT_MWI, mwi_event_cb, NULL,
09186             AST_EVENT_IE_MAILBOX, AST_EVENT_IE_PLTYPE_STR, mailbox,
09187             AST_EVENT_IE_CONTEXT, AST_EVENT_IE_PLTYPE_STR, context,
09188             AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
09189             AST_EVENT_IE_END);
09190       }
09191       tmp->msgstate = -1;
09192       tmp->group = conf->chan.group;
09193       tmp->callgroup = conf->chan.callgroup;
09194       tmp->pickupgroup= conf->chan.pickupgroup;
09195       if (conf->chan.vars) {
09196          tmp->vars = ast_variable_new(conf->chan.vars->name, conf->chan.vars->value, "");
09197       }
09198       tmp->cid_rxgain = conf->chan.cid_rxgain;
09199       tmp->rxgain = conf->chan.rxgain;
09200       tmp->txgain = conf->chan.txgain;
09201       tmp->tonezone = conf->chan.tonezone;
09202       tmp->onhooktime = time(NULL);
09203       if (tmp->subs[SUB_REAL].dfd > -1) {
09204          set_actual_gain(tmp->subs[SUB_REAL].dfd, 0, tmp->rxgain, tmp->txgain, tmp->law);
09205          if (tmp->dsp)
09206             ast_dsp_set_digitmode(tmp->dsp, DSP_DIGITMODE_DTMF | tmp->dtmfrelax);
09207          update_conf(tmp);
09208          if (!here) {
09209             if ((chan_sig != SIG_BRI) && (chan_sig != SIG_BRI_PTMP) && (chan_sig != SIG_PRI) && (chan_sig != SIG_SS7))
09210                /* Hang it up to be sure it's good */
09211                dahdi_set_hook(tmp->subs[SUB_REAL].dfd, DAHDI_ONHOOK);
09212          }
09213          ioctl(tmp->subs[SUB_REAL].dfd,DAHDI_SETTONEZONE,&tmp->tonezone);
09214 #ifdef HAVE_PRI
09215          /* the dchannel is down so put the channel in alarm */
09216          if (tmp->pri && !pri_is_up(tmp->pri))
09217             tmp->inalarm = 1;
09218 #endif            
09219          if ((res = get_alarms(tmp)) != DAHDI_ALARM_NONE) {
09220             tmp->inalarm = 1;
09221             handle_alarms(tmp, res);
09222          }
09223       }
09224 
09225       tmp->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
09226       tmp->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
09227       tmp->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
09228       tmp->sendcalleridafter = conf->chan.sendcalleridafter;
09229       if (!here) {
09230          tmp->locallyblocked = tmp->remotelyblocked = 0;
09231          if ((chan_sig == SIG_PRI) || (chan_sig == SIG_BRI) || (chan_sig == SIG_BRI_PTMP) || (chan_sig == SIG_SS7))
09232             tmp->inservice = 0;
09233          else /* We default to in service on protocols that don't have a reset */
09234             tmp->inservice = 1;
09235       }
09236    }
09237    if (tmp && !here) {
09238       /* nothing on the iflist */
09239       if (!*wlist) {
09240          *wlist = tmp;
09241          tmp->prev = NULL;
09242          tmp->next = NULL;
09243          *wend = tmp;
09244       } else {
09245          /* at least one member on the iflist */
09246          struct dahdi_pvt *working = *wlist;
09247 
09248          /* check if we maybe have to put it on the begining */
09249          if (working->channel > tmp->channel) {
09250             tmp->next = *wlist;
09251             tmp->prev = NULL;
09252             (*wlist)->prev = tmp;
09253             *wlist = tmp;
09254          } else {
09255          /* go through all the members and put the member in the right place */
09256             while (working) {
09257                /* in the middle */
09258                if (working->next) {
09259                   if (working->channel < tmp->channel && working->next->channel > tmp->channel) {
09260                      tmp->next = working->next;
09261                      tmp->prev = working;
09262                      working->next->prev = tmp;
09263                      working->next = tmp;
09264                      break;
09265                   }
09266                } else {
09267                /* the last */
09268                   if (working->channel < tmp->channel) {
09269                      working->next = tmp;
09270                      tmp->next = NULL;
09271                      tmp->prev = working;
09272                      *wend = tmp;
09273                      break;
09274                   }
09275                }
09276                working = working->next;
09277             }
09278          }
09279       }
09280    }
09281    return tmp;
09282 }
09283 
09284 static inline int available(struct dahdi_pvt *p, int channelmatch, ast_group_t groupmatch, int *busy, int *channelmatched, int *groupmatched)
09285 {
09286    int res;
09287    struct dahdi_params par;
09288 
09289    /* First, check group matching */
09290    if (groupmatch) {
09291       if ((p->group & groupmatch) != groupmatch)
09292          return 0;
09293       *groupmatched = 1;
09294    }
09295    /* Check to see if we have a channel match */
09296    if (channelmatch != -1) {
09297       if (p->channel != channelmatch)
09298          return 0;
09299       *channelmatched = 1;
09300    }
09301    /* We're at least busy at this point */
09302    if (busy) {
09303       if ((p->sig == SIG_FXOKS) || (p->sig == SIG_FXOLS) || (p->sig == SIG_FXOGS))
09304          *busy = 1;
09305    }
09306    /* If do not disturb, definitely not */
09307    if (p->dnd)
09308       return 0;
09309    /* If guard time, definitely not */
09310    if (p->guardtime && (time(NULL) < p->guardtime)) 
09311       return 0;
09312 
09313    if (p->locallyblocked || p->remotelyblocked)
09314       return 0;
09315       
09316    /* If no owner definitely available */
09317    if (!p->owner) {
09318 #ifdef HAVE_PRI
09319       /* Trust PRI */
09320       if (p->pri) {
09321          if (p->resetting || p->call)
09322             return 0;
09323          else
09324             return 1;
09325       }
09326 #endif
09327 #ifdef HAVE_SS7
09328       /* Trust SS7 */
09329       if (p->ss7) {
09330          if (p->ss7call)
09331             return 0;
09332          else
09333             return 1;
09334       }
09335 #endif
09336       if (!(p->radio || (p->oprmode < 0)))
09337       {
09338          if (!p->sig || (p->sig == SIG_FXSLS))
09339             return 1;
09340          /* Check hook state */
09341          if (p->subs[SUB_REAL].dfd > -1) {
09342             memset(&par, 0, sizeof(par));
09343             res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
09344          } else {
09345             /* Assume not off hook on CVRS */
09346             res = 0;
09347             par.rxisoffhook = 0;
09348          }
09349          if (res) {
09350             ast_log(LOG_WARNING, "Unable to check hook state on channel %d: %s\n", p->channel, strerror(errno));
09351          } else if ((p->sig == SIG_FXSKS) || (p->sig == SIG_FXSGS)) {
09352             /* When "onhook" that means no battery on the line, and thus
09353               it is out of service..., if it's on a TDM card... If it's a channel
09354               bank, there is no telling... */
09355             if (par.rxbits > -1)
09356                return 1;
09357             if (par.rxisoffhook)
09358                return 1;
09359             else
09360                return 0;
09361          } else if (par.rxisoffhook) {
09362             ast_debug(1, "Channel %d off hook, can't use\n", p->channel);
09363             /* Not available when the other end is off hook */
09364 #ifdef DAHDI_CHECK_HOOKSTATE
09365             return 0;
09366 #else
09367             return 1;
09368 #endif
09369          }
09370       }
09371       return 1;
09372    }
09373 
09374    /* If it's not an FXO, forget about call wait */
09375    if ((p->sig != SIG_FXOKS) && (p->sig != SIG_FXOLS) && (p->sig != SIG_FXOGS)) 
09376       return 0;
09377 
09378    if (!p->callwaiting) {
09379       /* If they don't have call waiting enabled, then for sure they're unavailable at this point */
09380       return 0;
09381    }
09382 
09383    if (p->subs[SUB_CALLWAIT].dfd > -1) {
09384       /* If there is already a call waiting call, then we can't take a second one */
09385       return 0;
09386    }
09387    
09388    if ((p->owner->_state != AST_STATE_UP) &&
09389        ((p->owner->_state != AST_STATE_RINGING) || p->outgoing)) {
09390       /* If the current call is not up, then don't allow the call */
09391       return 0;
09392    }
09393    if ((p->subs[SUB_THREEWAY].owner) && (!p->subs[SUB_THREEWAY].inthreeway)) {
09394       /* Can't take a call wait when the three way calling hasn't been merged yet. */
09395       return 0;
09396    }
09397    /* We're cool */
09398    return 1;
09399 }
09400 
09401 static struct dahdi_pvt *chandup(struct dahdi_pvt *src)
09402 {
09403    struct dahdi_pvt *p;
09404    struct dahdi_bufferinfo bi;
09405    int res;
09406    
09407    if ((p = ast_malloc(sizeof(*p)))) {
09408       memcpy(p, src, sizeof(struct dahdi_pvt));
09409       ast_mutex_init(&p->lock);
09410       p->subs[SUB_REAL].dfd = dahdi_open("/dev/dahdi/pseudo");
09411       /* Allocate a dahdi structure */
09412       if (p->subs[SUB_REAL].dfd < 0) {
09413          ast_log(LOG_ERROR, "Unable to dup channel: %s\n",  strerror(errno));
09414          destroy_dahdi_pvt(&p);
09415          return NULL;
09416       }
09417       res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_BUFINFO, &bi);
09418       if (!res) {
09419          bi.txbufpolicy = src->buf_policy;
09420          bi.rxbufpolicy = src->buf_policy;
09421          bi.numbufs = src->buf_no;
09422          res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_SET_BUFINFO, &bi);
09423          if (res < 0) {
09424             ast_log(LOG_WARNING, "Unable to set buffer policy on dup channel: %s\n", strerror(errno));
09425          }
09426       } else
09427          ast_log(LOG_WARNING, "Unable to check buffer policy on dup channel: %s\n", strerror(errno));
09428    }
09429    p->destroy = 1;
09430    p->next = iflist;
09431    p->prev = NULL;
09432    iflist = p;
09433    if (iflist->next)
09434       iflist->next->prev = p;
09435    return p;
09436 }
09437    
09438 
09439 #ifdef HAVE_PRI
09440 static int pri_find_empty_chan(struct dahdi_pri *pri, int backwards)
09441 {
09442    int x;
09443    if (backwards)
09444       x = pri->numchans;
09445    else
09446       x = 0;
09447    for (;;) {
09448       if (backwards && (x < 0))
09449          break;
09450       if (!backwards && (x >= pri->numchans))
09451          break;
09452       if (pri->pvts[x] && !pri->pvts[x]->inalarm && !pri->pvts[x]->owner) {
09453          ast_debug(1, "Found empty available channel %d/%d\n", 
09454             pri->pvts[x]->logicalspan, pri->pvts[x]->prioffset);
09455          return x;
09456       }
09457       if (backwards)
09458          x--;
09459       else
09460          x++;
09461    }
09462    return -1;
09463 }
09464 #endif
09465 
09466 static struct ast_channel *dahdi_request(const char *type, int format, void *data, int *cause)
09467 {
09468    ast_group_t groupmatch = 0;
09469    int channelmatch = -1;
09470    int roundrobin = 0;
09471    int callwait = 0;
09472    int busy = 0;
09473    struct dahdi_pvt *p;
09474    struct ast_channel *tmp = NULL;
09475    char *dest=NULL;
09476    int x;
09477    char *s;
09478    char opt=0;
09479    int res=0, y=0;
09480    int backwards = 0;
09481 #ifdef HAVE_PRI
09482    int crv;
09483    int bearer = -1;
09484    int trunkgroup;
09485    struct dahdi_pri *pri=NULL;
09486 #endif   
09487    struct dahdi_pvt *exitpvt, *start, *end;
09488    ast_mutex_t *lock;
09489    int channelmatched = 0;
09490    int groupmatched = 0;
09491    
09492    /*
09493     * data is ---v
09494     * Dial(DAHDI/pseudo[/extension])
09495     * Dial(DAHDI/<channel#>[c|r<cadance#>|d][/extension])
09496     * Dial(DAHDI/<trunk_group#>:<crv#>[c|r<cadance#>|d][/extension])
09497     * Dial(DAHDI/(g|G|r|R)<group#(0-63)>[c|r<cadance#>|d][/extension])
09498     *
09499     * g - channel group allocation search forward
09500     * G - channel group allocation search backward
09501     * r - channel group allocation round robin search forward
09502     * R - channel group allocation round robin search backward
09503     *
09504     * c - Wait for DTMF digit to confirm answer
09505     * r<cadance#> - Set distintive ring cadance number
09506     * d - Force bearer capability for ISDN/SS7 call to digital.
09507     */
09508 
09509    /* Assume we're locking the iflock */
09510    lock = &iflock;
09511    start = iflist;
09512    end = ifend;
09513    if (data) {
09514       dest = ast_strdupa((char *)data);
09515    } else {
09516       ast_log(LOG_WARNING, "Channel requested with no data\n");
09517       return NULL;
09518    }
09519    if (toupper(dest[0]) == 'G' || toupper(dest[0])=='R') {
09520       /* Retrieve the group number */
09521       char *stringp;
09522 
09523       stringp = dest + 1;
09524       s = strsep(&stringp, "/");
09525       if ((res = sscanf(s, "%30d%1c%30d", &x, &opt, &y)) < 1) {
09526          ast_log(LOG_WARNING, "Unable to determine group for data %s\n", (char *)data);
09527          return NULL;
09528       }
09529       groupmatch = ((ast_group_t) 1 << x);
09530       if (toupper(dest[0]) == 'G') {
09531          if (dest[0] == 'G') {
09532             backwards = 1;
09533             p = ifend;
09534          } else
09535             p = iflist;
09536       } else {
09537          if (dest[0] == 'R') {
09538             backwards = 1;
09539             p = round_robin[x]?round_robin[x]->prev:ifend;
09540             if (!p)
09541                p = ifend;
09542          } else {
09543             p = round_robin[x]?round_robin[x]->next:iflist;
09544             if (!p)
09545                p = iflist;
09546          }
09547          roundrobin = 1;
09548       }
09549    } else {
09550       char *stringp;
09551 
09552       stringp = dest;
09553       s = strsep(&stringp, "/");
09554       p = iflist;
09555       if (!strcasecmp(s, "pseudo")) {
09556          /* Special case for pseudo */
09557          x = CHAN_PSEUDO;
09558          channelmatch = x;
09559       } 
09560 #ifdef HAVE_PRI
09561       else if ((res = sscanf(s, "%30d:%30d%1c%30d", &trunkgroup, &crv, &opt, &y)) > 1) {
09562          if ((trunkgroup < 1) || (crv < 1)) {
09563             ast_log(LOG_WARNING, "Unable to determine trunk group and CRV for data %s\n", (char *)data);
09564             return NULL;
09565          }
09566          res--;
09567          for (x = 0; x < NUM_SPANS; x++) {
09568             if (pris[x].trunkgroup == trunkgroup) {
09569                pri = pris + x;
09570                lock = &pri->lock;
09571                start = pri->crvs;
09572                end = pri->crvend;
09573                break;
09574             }
09575          }
09576          if (!pri) {
09577             ast_log(LOG_WARNING, "Unable to find trunk group %d\n", trunkgroup);
09578             return NULL;
09579          }
09580          channelmatch = crv;
09581          p = pris[x].crvs;
09582       }
09583 #endif
09584       else if ((res = sscanf(s, "%30d%1c%30d", &x, &opt, &y)) < 1) {
09585          ast_log(LOG_WARNING, "Unable to determine channel for data %s\n", (char *)data);
09586          return NULL;
09587       } else {
09588          channelmatch = x;
09589       }
09590    }
09591    /* Search for an unowned channel */
09592    ast_mutex_lock(lock);
09593    exitpvt = p;
09594    while (p && !tmp) {
09595       if (roundrobin)
09596          round_robin[x] = p;
09597 #if 0
09598       ast_verbose("name = %s, %d, %d, %llu\n",p->owner ? p->owner->name : "<none>", p->channel, channelmatch, groupmatch);
09599 #endif
09600 
09601       if (p && available(p, channelmatch, groupmatch, &busy, &channelmatched, &groupmatched)) {
09602          ast_debug(1, "Using channel %d\n", p->channel);
09603          if (p->inalarm) 
09604             goto next;
09605 
09606          callwait = (p->owner != NULL);
09607 #ifdef HAVE_PRI
09608          if (pri && (p->subs[SUB_REAL].dfd < 0)) {
09609             if (p->sig != SIG_FXSKS) {
09610                /* Gotta find an actual channel to use for this
09611                   CRV if this isn't a callwait */
09612                bearer = pri_find_empty_chan(pri, 0);
09613                if (bearer < 0) {
09614                   ast_log(LOG_NOTICE, "Out of bearer channels on span %d for call to CRV %d:%d\n", pri->span, trunkgroup, crv);
09615                   p = NULL;
09616                   break;
09617                }
09618                pri_assign_bearer(p, pri, pri->pvts[bearer]);
09619             } else {
09620                if (alloc_sub(p, 0)) {
09621                   ast_log(LOG_NOTICE, "Failed to allocate place holder pseudo channel!\n");
09622                   p = NULL;
09623                   break;
09624                } else
09625                   ast_debug(1, "Allocated placeholder pseudo channel\n");
09626 
09627                p->pri = pri;
09628             }
09629          }
09630 #endif         
09631          if (p->channel == CHAN_PSEUDO) {
09632             p = chandup(p);
09633             if (!p) {
09634                break;
09635             }
09636          }
09637          if (p->owner) {
09638             if (alloc_sub(p, SUB_CALLWAIT)) {
09639                p = NULL;
09640                break;
09641             }
09642          }
09643          p->outgoing = 1;
09644          tmp = dahdi_new(p, AST_STATE_RESERVED, 0, p->owner ? SUB_CALLWAIT : SUB_REAL, 0, 0);
09645          if (!tmp) {
09646             p->outgoing = 0;
09647          }
09648 #ifdef HAVE_PRI
09649          if (p->bearer) {
09650             /* Log owner to bearer channel, too */
09651             p->bearer->owner = tmp;
09652          }
09653 #endif         
09654          /* Make special notes */
09655          if (res > 1) {
09656             if (opt == 'c') {
09657                /* Confirm answer */
09658                p->confirmanswer = 1;
09659             } else if (opt == 'r') {
09660                /* Distinctive ring */
09661                if (res < 3)
09662                   ast_log(LOG_WARNING, "Distinctive ring missing identifier in '%s'\n", (char *)data);
09663                else
09664                   p->distinctivering = y;
09665             } else if (opt == 'd') {
09666                /* If this is an ISDN call, make it digital */
09667                p->digital = 1;
09668                if (tmp)
09669                   tmp->transfercapability = AST_TRANS_CAP_DIGITAL;
09670             } else {
09671                ast_log(LOG_WARNING, "Unknown option '%c' in '%s'\n", opt, (char *)data);
09672             }
09673          }
09674          /* Note if the call is a call waiting call */
09675          if (tmp && callwait)
09676             tmp->cdrflags |= AST_CDR_CALLWAIT;
09677          break;
09678       }
09679 next:
09680       if (backwards) {
09681          p = p->prev;
09682          if (!p)
09683             p = end;
09684       } else {
09685          p = p->next;
09686          if (!p)
09687             p = start;
09688       }
09689       /* stop when you roll to the one that we started from */
09690       if (p == exitpvt)
09691          break;
09692    }
09693    ast_mutex_unlock(lock);
09694    restart_monitor();
09695    if (callwait)
09696       *cause = AST_CAUSE_BUSY;
09697    else if (!tmp) {
09698       if (channelmatched) {
09699          if (busy)
09700             *cause = AST_CAUSE_BUSY;
09701       } else if (groupmatched) {
09702          *cause = AST_CAUSE_CONGESTION;
09703       }
09704    }
09705       
09706    return tmp;
09707 }
09708 
09709 #if defined(HAVE_PRI) || defined(HAVE_SS7)
09710 static int dahdi_setlaw(int dfd, int law)
09711 {
09712    return ioctl(dfd, DAHDI_SETLAW, &law);
09713 }
09714 #endif
09715 
09716 #ifdef HAVE_SS7
09717 
09718 static int ss7_find_cic(struct dahdi_ss7 *linkset, int cic, unsigned int dpc)
09719 {
09720    int i;
09721    int winner = -1;
09722    for (i = 0; i < linkset->numchans; i++) {
09723       if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && linkset->pvts[i]->cic == cic)) {
09724          winner = i;
09725          break;
09726       }
09727    }
09728    return winner;
09729 }
09730 
09731 static void ss7_handle_cqm(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc)
09732 {
09733    unsigned char status[32];
09734    struct dahdi_pvt *p = NULL;
09735    int i, offset;
09736 
09737    for (i = 0; i < linkset->numchans; i++) {
09738       if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
09739          p = linkset->pvts[i];
09740          offset = p->cic - startcic;
09741          status[offset] = 0;
09742          if (p->locallyblocked)
09743             status[offset] |= (1 << 0) | (1 << 4);
09744          if (p->remotelyblocked)
09745             status[offset] |= (1 << 1) | (1 << 5);
09746          if (p->ss7call) {
09747             if (p->outgoing)
09748                status[offset] |= (1 << 3);
09749             else
09750                status[offset] |= (1 << 2);
09751          } else
09752             status[offset] |= 0x3 << 2;
09753       }
09754    }
09755 
09756    if (p)
09757       isup_cqr(linkset->ss7, startcic, endcic, dpc, status);
09758    else
09759       ast_log(LOG_WARNING, "Could not find any equipped circuits within CQM CICs\n");
09760    
09761 }
09762 
09763 static inline void ss7_block_cics(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc, unsigned char state[], int block)
09764 {
09765    int i;
09766 
09767    for (i = 0; i < linkset->numchans; i++) {
09768       if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic)))) {
09769          if (state) {
09770             if (state[i])
09771                linkset->pvts[i]->remotelyblocked = block;
09772          } else
09773             linkset->pvts[i]->remotelyblocked = block;
09774       }
09775    }
09776 }
09777 
09778 static void ss7_inservice(struct dahdi_ss7 *linkset, int startcic, int endcic, unsigned int dpc)
09779 {
09780    int i;
09781 
09782    for (i = 0; i < linkset->numchans; i++) {
09783       if (linkset->pvts[i] && (linkset->pvts[i]->dpc == dpc && ((linkset->pvts[i]->cic >= startcic) && (linkset->pvts[i]->cic <= endcic))))
09784          linkset->pvts[i]->inservice = 1;
09785    }
09786 }
09787 
09788 static void ss7_reset_linkset(struct dahdi_ss7 *linkset)
09789 {
09790    int i, startcic = -1, endcic, dpc;
09791 
09792    if (linkset->numchans <= 0)
09793       return;
09794 
09795    startcic = linkset->pvts[0]->cic;
09796    /* DB: CIC's DPC fix */
09797    dpc = linkset->pvts[0]->dpc;
09798 
09799    for (i = 0; i < linkset->numchans; i++) {
09800       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)) {
09801          continue;
09802       } else {
09803          endcic = linkset->pvts[i]->cic;
09804          ast_verbose("Resetting CICs %d to %d\n", startcic, endcic);
09805          isup_grs(linkset->ss7, startcic, endcic, dpc);
09806 
09807          /* DB: CIC's DPC fix */
09808          if (linkset->pvts[i+1]) {
09809             startcic = linkset->pvts[i+1]->cic;
09810             dpc = linkset->pvts[i+1]->dpc;
09811          }
09812       }
09813    }
09814 }
09815 
09816 static void dahdi_loopback(struct dahdi_pvt *p, int enable)
09817 {
09818    if (p->loopedback != enable) {
09819       if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_LOOPBACK, &enable)) {
09820          ast_log(LOG_WARNING, "Unable to set loopback on channel %d: %s\n", p->channel, strerror(errno));
09821          return;
09822       }
09823       p->loopedback = enable;
09824    }
09825 }
09826 
09827 /* XXX: This function is assumed to be called with the private channel lock and linkset lock held */
09828 static void ss7_start_call(struct dahdi_pvt *p, struct dahdi_ss7 *linkset)
09829 {
09830    struct ss7 *ss7 = linkset->ss7;
09831    int res;
09832    int law = 1;
09833    struct ast_channel *c;
09834    char tmp[256];
09835 
09836    if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law) == -1)
09837       ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", p->channel, law, strerror(errno));
09838    
09839    if (linkset->type == SS7_ITU)
09840       law = DAHDI_LAW_ALAW;
09841    else
09842       law = DAHDI_LAW_MULAW;
09843 
09844    res = dahdi_setlaw(p->subs[SUB_REAL].dfd, law);
09845    if (res < 0) 
09846       ast_log(LOG_WARNING, "Unable to set law on channel %d\n", p->channel);
09847    
09848    if (!(linkset->flags & LINKSET_FLAG_EXPLICITACM)) {
09849       p->proceeding = 1;
09850       isup_acm(ss7, p->ss7call);
09851    }
09852 
09853    ast_mutex_unlock(&linkset->lock);
09854    c = dahdi_new(p, AST_STATE_RING, 1, SUB_REAL, law, 0);
09855 
09856    if (!c) {
09857       ast_log(LOG_WARNING, "Unable to start PBX on CIC %d\n", p->cic);
09858       /* Holding this lock is assumed entering the function */
09859       ast_mutex_lock(&linkset->lock);
09860       return;
09861    } else
09862       ast_verb(3, "Accepting call to '%s' on CIC %d\n", p->exten, p->cic);
09863 
09864    dahdi_enable_ec(p);
09865 
09866    /* We only reference these variables in the context of the ss7_linkset function
09867     * when receiving either and IAM or a COT message.  Since they are only accessed
09868     * from this context, we should be safe to unlock around them */
09869 
09870    ast_mutex_unlock(&p->lock);
09871 
09872    if (!ast_strlen_zero(p->charge_number)) {
09873       pbx_builtin_setvar_helper(c, "SS7_CHARGE_NUMBER", p->charge_number);
09874       /* Clear this after we set it */
09875       p->charge_number[0] = 0;
09876    }
09877    if (!ast_strlen_zero(p->gen_add_number)) {
09878       pbx_builtin_setvar_helper(c, "SS7_GENERIC_ADDRESS", p->gen_add_number);
09879       /* Clear this after we set it */
09880       p->gen_add_number[0] = 0;
09881    }
09882    if (!ast_strlen_zero(p->jip_number)) {
09883       pbx_builtin_setvar_helper(c, "SS7_JIP", p->jip_number);
09884       /* Clear this after we set it */
09885       p->jip_number[0] = 0;
09886    }
09887    if (!ast_strlen_zero(p->gen_dig_number)) {
09888       pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGITS", p->gen_dig_number);
09889       /* Clear this after we set it */
09890       p->gen_dig_number[0] = 0;
09891    }
09892    if (!ast_strlen_zero(p->orig_called_num)) {
09893       pbx_builtin_setvar_helper(c, "SS7_ORIG_CALLED_NUM", p->orig_called_num);
09894       /* Clear this after we set it */
09895       p->orig_called_num[0] = 0;
09896    }
09897 
09898    snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_type);
09899    pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGTYPE", tmp);
09900    /* Clear this after we set it */
09901    p->gen_dig_type = 0;
09902 
09903    snprintf(tmp, sizeof(tmp), "%d", p->gen_dig_scheme);
09904    pbx_builtin_setvar_helper(c, "SS7_GENERIC_DIGSCHEME", tmp);
09905    /* Clear this after we set it */
09906    p->gen_dig_scheme = 0;
09907 
09908    if (!ast_strlen_zero(p->lspi_ident)) {
09909       pbx_builtin_setvar_helper(c, "SS7_LSPI_IDENT", p->lspi_ident);
09910       /* Clear this after we set it */
09911       p->lspi_ident[0] = 0;
09912    }
09913 
09914    snprintf(tmp, sizeof(tmp), "%d", p->call_ref_ident);
09915    pbx_builtin_setvar_helper(c, "SS7_CALLREF_IDENT", tmp);
09916    /* Clear this after we set it */
09917    p->call_ref_ident = 0;
09918 
09919    snprintf(tmp, sizeof(tmp), "%d", p->call_ref_pc);
09920    pbx_builtin_setvar_helper(c, "SS7_CALLREF_PC", tmp);
09921    /* Clear this after we set it */
09922    p->call_ref_pc = 0;
09923 
09924    snprintf(tmp, sizeof(tmp), "%d", p->calling_party_cat);
09925    pbx_builtin_setvar_helper(c, "SS7_CALLING_PARTY_CATEGORY", tmp);
09926    /* Clear this after we set it */
09927    p->calling_party_cat = 0;
09928 
09929    if (!ast_strlen_zero(p->redirecting_num)) {
09930       pbx_builtin_setvar_helper(c, "SS7_REDIRECTING_NUMBER", p->redirecting_num);
09931       /* Clear this after we set it */
09932       p->redirecting_num[0] = 0;
09933    }
09934    if (!ast_strlen_zero(p->generic_name)) {
09935       pbx_builtin_setvar_helper(c, "SS7_GENERIC_NAME", p->generic_name);
09936       /* Clear this after we set it */
09937       p->generic_name[0] = 0;
09938    }
09939 
09940    ast_mutex_lock(&p->lock);
09941    ast_mutex_lock(&linkset->lock);
09942 }
09943 
09944 static void ss7_apply_plan_to_number(char *buf, size_t size, const struct dahdi_ss7 *ss7, const char *number, const unsigned nai)
09945 {
09946    if (ast_strlen_zero(number)) { /* make sure a number exists so prefix isn't placed on an empty string */
09947       if (size) {
09948          *buf = '\0';
09949       }
09950       return;
09951    }
09952    switch (nai) {
09953    case SS7_NAI_INTERNATIONAL:
09954       snprintf(buf, size, "%s%s", ss7->internationalprefix, number);
09955       break;
09956    case SS7_NAI_NATIONAL:
09957       snprintf(buf, size, "%s%s", ss7->nationalprefix, number);
09958       break;
09959    case SS7_NAI_SUBSCRIBER:
09960       snprintf(buf, size, "%s%s", ss7->subscriberprefix, number);
09961       break;
09962    case SS7_NAI_UNKNOWN:
09963       snprintf(buf, size, "%s%s", ss7->unknownprefix, number);
09964       break;
09965    default:
09966       snprintf(buf, size, "%s", number);
09967       break;
09968    }
09969 }
09970 static int ss7_pres_scr2cid_pres(char presentation_ind, char screening_ind)
09971 {
09972     return ((presentation_ind & 0x3) << 5) | (screening_ind & 0x3);
09973 }
09974 
09975 static void *ss7_linkset(void *data)
09976 {
09977    int res, i;
09978    struct timeval *next = NULL, tv;
09979    struct dahdi_ss7 *linkset = (struct dahdi_ss7 *) data;
09980    struct ss7 *ss7 = linkset->ss7;
09981    ss7_event *e = NULL;
09982    struct dahdi_pvt *p;
09983    int chanpos;
09984    struct pollfd pollers[NUM_DCHANS];
09985    int cic;
09986    unsigned int dpc;
09987    int nextms = 0;
09988 
09989    ss7_start(ss7);
09990 
09991    while(1) {
09992       ast_mutex_lock(&linkset->lock);
09993       if ((next = ss7_schedule_next(ss7))) {
09994          tv = ast_tvnow();
09995          tv.tv_sec = next->tv_sec - tv.tv_sec;
09996          tv.tv_usec = next->tv_usec - tv.tv_usec;
09997          if (tv.tv_usec < 0) {
09998             tv.tv_usec += 1000000;
09999             tv.tv_sec -= 1;
10000          }
10001          if (tv.tv_sec < 0) {
10002             tv.tv_sec = 0;
10003             tv.tv_usec = 0;
10004          }
10005          nextms = tv.tv_sec * 1000;
10006          nextms += tv.tv_usec / 1000;
10007       }
10008       ast_mutex_unlock(&linkset->lock);
10009 
10010       for (i = 0; i < linkset->numsigchans; i++) {
10011          pollers[i].fd = linkset->fds[i];
10012          pollers[i].events = ss7_pollflags(ss7, linkset->fds[i]);
10013          pollers[i].revents = 0;
10014       }
10015 
10016       res = poll(pollers, linkset->numsigchans, nextms);
10017       if ((res < 0) && (errno != EINTR)) {
10018          ast_log(LOG_ERROR, "poll(%s)\n", strerror(errno));
10019       } else if (!res) {
10020          ast_mutex_lock(&linkset->lock);
10021          ss7_schedule_run(ss7);
10022          ast_mutex_unlock(&linkset->lock);
10023          continue;
10024       }
10025 
10026       ast_mutex_lock(&linkset->lock);
10027       for (i = 0; i < linkset->numsigchans; i++) {
10028          if (pollers[i].revents & POLLPRI) {
10029             int x;
10030             if (ioctl(pollers[i].fd, DAHDI_GETEVENT, &x)) {
10031                ast_log(LOG_ERROR, "Error in exception retrieval!\n");
10032             }
10033             switch (x) {
10034             case DAHDI_EVENT_OVERRUN:
10035                ast_debug(1, "Overrun detected!\n");
10036                break;
10037             case DAHDI_EVENT_BADFCS:
10038                ast_debug(1, "Bad FCS\n");
10039                break;
10040             case DAHDI_EVENT_ABORT:
10041                ast_debug(1, "HDLC Abort\n");
10042                break;
10043             case DAHDI_EVENT_ALARM:
10044                ast_log(LOG_ERROR, "Alarm on link!\n");
10045                linkset->linkstate[i] |= (LINKSTATE_DOWN | LINKSTATE_INALARM);
10046                linkset->linkstate[i] &= ~LINKSTATE_UP;
10047                ss7_link_alarm(ss7, pollers[i].fd);
10048                break;
10049             case DAHDI_EVENT_NOALARM:
10050                ast_log(LOG_ERROR, "Alarm cleared on link\n");
10051                linkset->linkstate[i] &= ~(LINKSTATE_INALARM | LINKSTATE_DOWN);
10052                linkset->linkstate[i] |= LINKSTATE_STARTING;
10053                ss7_link_noalarm(ss7, pollers[i].fd);
10054                break;
10055             default:
10056                ast_log(LOG_ERROR, "Got exception %d!\n", x);
10057                break;
10058             }
10059          }
10060 
10061          if (pollers[i].revents & POLLIN) {
10062             ast_mutex_lock(&linkset->lock);
10063             res = ss7_read(ss7, pollers[i].fd);
10064             ast_mutex_unlock(&linkset->lock);
10065          }
10066 
10067          if (pollers[i].revents & POLLOUT) {
10068             ast_mutex_lock(&linkset->lock);
10069             res = ss7_write(ss7, pollers[i].fd);
10070             ast_mutex_unlock(&linkset->lock);
10071             if (res < 0) {
10072                ast_debug(1, "Error in write %s\n", strerror(errno));
10073             }
10074          }
10075       }
10076 
10077       while ((e = ss7_check_event(ss7))) {
10078          switch (e->e) {
10079          case SS7_EVENT_UP:
10080             if (linkset->state != LINKSET_STATE_UP) {
10081                ast_verbose("--- SS7 Up ---\n");
10082                ss7_reset_linkset(linkset);
10083             }
10084             linkset->state = LINKSET_STATE_UP;
10085             break;
10086          case SS7_EVENT_DOWN:
10087             ast_verbose("--- SS7 Down ---\n");
10088             linkset->state = LINKSET_STATE_DOWN;
10089             for (i = 0; i < linkset->numchans; i++) {
10090                struct dahdi_pvt *p = linkset->pvts[i];
10091                if (p)
10092                   p->inalarm = 1;
10093             }
10094             break;
10095          case MTP2_LINK_UP:
10096             ast_verbose("MTP2 link up (SLC %d)\n", e->gen.data);
10097             break;
10098          case MTP2_LINK_DOWN:
10099             ast_log(LOG_WARNING, "MTP2 link down (SLC %d)\n", e->gen.data);
10100             break;
10101          case ISUP_EVENT_CPG:
10102             chanpos = ss7_find_cic(linkset, e->cpg.cic, e->cpg.opc);
10103             if (chanpos < 0) {
10104                ast_log(LOG_WARNING, "CPG on unconfigured CIC %d\n", e->cpg.cic);
10105                break;
10106             }
10107             p = linkset->pvts[chanpos];
10108             ast_mutex_lock(&p->lock);
10109             switch (e->cpg.event) {
10110             case CPG_EVENT_ALERTING:
10111                p->alerting = 1;
10112                p->subs[SUB_REAL].needringing = 1;
10113                break;
10114             case CPG_EVENT_PROGRESS:
10115             case CPG_EVENT_INBANDINFO:
10116                {
10117                   struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, };
10118                   ast_debug(1, "Queuing frame PROGRESS on CIC %d\n", p->cic);
10119                   dahdi_queue_frame(p, &f, linkset);
10120                   p->progress = 1;
10121                   p->dialing = 0;
10122                   if (p->dsp && p->dsp_features) {
10123                           ast_dsp_set_features(p->dsp, p->dsp_features);
10124                           p->dsp_features = 0;
10125                   }
10126                }
10127                break;
10128             default:
10129                ast_debug(1, "Do not handle CPG with event type 0x%x\n", e->cpg.event);
10130             }
10131 
10132             ast_mutex_unlock(&p->lock);
10133             break;
10134          case ISUP_EVENT_RSC:
10135             ast_verbose("Resetting CIC %d\n", e->rsc.cic);
10136             chanpos = ss7_find_cic(linkset, e->rsc.cic, e->rsc.opc);
10137             if (chanpos < 0) {
10138                ast_log(LOG_WARNING, "RSC on unconfigured CIC %d\n", e->rsc.cic);
10139                break;
10140             }
10141             p = linkset->pvts[chanpos];
10142             ast_mutex_lock(&p->lock);
10143             p->inservice = 1;
10144             p->remotelyblocked = 0;
10145             dpc = p->dpc;
10146             isup_set_call_dpc(e->rsc.call, dpc);
10147             if (p->ss7call)
10148                p->ss7call = NULL;
10149             if (p->owner)
10150                p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
10151             ast_mutex_unlock(&p->lock);
10152             isup_rlc(ss7, e->rsc.call);
10153             break;
10154          case ISUP_EVENT_GRS:
10155             ast_debug(1, "Got Reset for CICs %d to %d: Acknowledging\n", e->grs.startcic, e->grs.endcic);
10156             chanpos = ss7_find_cic(linkset, e->grs.startcic, e->grs.opc);
10157             if (chanpos < 0) {
10158                ast_log(LOG_WARNING, "GRS on unconfigured CIC %d\n", e->grs.startcic);
10159                break;
10160             }
10161             p = linkset->pvts[chanpos];
10162             isup_gra(ss7, e->grs.startcic, e->grs.endcic, e->grs.opc);
10163             ss7_block_cics(linkset, e->grs.startcic, e->grs.endcic, e->grs.opc, NULL, 0);
10164             break;
10165          case ISUP_EVENT_CQM:
10166             ast_debug(1, "Got Circuit group query message from CICs %d to %d\n", e->cqm.startcic, e->cqm.endcic);
10167             ss7_handle_cqm(linkset, e->cqm.startcic, e->cqm.endcic, e->cqm.opc);
10168             break;
10169          case ISUP_EVENT_GRA:
10170             ast_verbose("Got reset acknowledgement from CIC %d to %d.\n", e->gra.startcic, e->gra.endcic);
10171             ss7_inservice(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc);
10172             ss7_block_cics(linkset, e->gra.startcic, e->gra.endcic, e->gra.opc, e->gra.status, 1);
10173             break;
10174          case ISUP_EVENT_IAM:
10175             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);
10176             chanpos = ss7_find_cic(linkset, e->iam.cic, e->iam.opc);
10177             if (chanpos < 0) {
10178                ast_log(LOG_WARNING, "IAM on unconfigured CIC %d\n", e->iam.cic);
10179                isup_rel(ss7, e->iam.call, -1);
10180                break;
10181             }
10182             p = linkset->pvts[chanpos];
10183             ast_mutex_lock(&p->lock);
10184             if (p->owner) {
10185                if (p->ss7call == e->iam.call) {
10186                   ast_mutex_unlock(&p->lock);
10187                   ast_log(LOG_WARNING, "Duplicate IAM requested on CIC %d\n", e->iam.cic);
10188                   break;
10189                } else {
10190                   ast_mutex_unlock(&p->lock);
10191                   ast_log(LOG_WARNING, "Ring requested on CIC %d already in use!\n", e->iam.cic);
10192                   break;
10193                }
10194             }
10195 
10196             dpc = p->dpc;
10197             p->ss7call = e->iam.call;
10198             isup_set_call_dpc(p->ss7call, dpc);
10199 
10200             if ((p->use_callerid) && (!ast_strlen_zero(e->iam.calling_party_num))) {
10201                ss7_apply_plan_to_number(p->cid_num, sizeof(p->cid_num), linkset, e->iam.calling_party_num, e->iam.calling_nai);
10202                p->callingpres = ss7_pres_scr2cid_pres(e->iam.presentation_ind, e->iam.screening_ind);
10203             } else
10204                p->cid_num[0] = 0;
10205 
10206             if (p->immediate) {
10207                p->exten[0] = 's';
10208                p->exten[1] = '\0';
10209             } else if (!ast_strlen_zero(e->iam.called_party_num)) {
10210                char *st;
10211                ss7_apply_plan_to_number(p->exten, sizeof(p->exten), linkset, e->iam.called_party_num, e->iam.called_nai);
10212                st = strchr(p->exten, '#');
10213                if (st)
10214                   *st = '\0';
10215                } else
10216                   p->exten[0] = '\0';
10217 
10218             p->cid_ani[0] = '\0';
10219             if ((p->use_callerid) && (!ast_strlen_zero(e->iam.generic_name)))
10220                ast_copy_string(p->cid_name, e->iam.generic_name, sizeof(p->cid_name));
10221             else
10222                p->cid_name[0] = '\0';
10223             
10224             p->cid_ani2 = e->iam.oli_ani2;
10225             p->cid_ton = 0;
10226             ast_copy_string(p->charge_number, e->iam.charge_number, sizeof(p->charge_number));
10227             ast_copy_string(p->gen_add_number, e->iam.gen_add_number, sizeof(p->gen_add_number));
10228             p->gen_add_type = e->iam.gen_add_type;
10229             p->gen_add_nai = e->iam.gen_add_nai;
10230             p->gen_add_pres_ind = e->iam.gen_add_pres_ind;
10231             p->gen_add_num_plan = e->iam.gen_add_num_plan;
10232             ast_copy_string(p->gen_dig_number, e->iam.gen_dig_number, sizeof(p->gen_dig_number));
10233             p->gen_dig_type = e->iam.gen_dig_type;
10234             p->gen_dig_scheme = e->iam.gen_dig_scheme;
10235             ast_copy_string(p->jip_number, e->iam.jip_number, sizeof(p->jip_number));
10236             ast_copy_string(p->orig_called_num, e->iam.orig_called_num, sizeof(p->orig_called_num));
10237             ast_copy_string(p->redirecting_num, e->iam.redirecting_num, sizeof(p->redirecting_num));
10238             ast_copy_string(p->generic_name, e->iam.generic_name, sizeof(p->generic_name));
10239             p->calling_party_cat = e->iam.calling_party_cat;
10240                
10241             /* Set DNID */
10242             if (!ast_strlen_zero(e->iam.called_party_num))
10243                ss7_apply_plan_to_number(p->dnid, sizeof(p->dnid), linkset, e->iam.called_party_num, e->iam.called_nai);
10244             
10245             if (ast_exists_extension(NULL, p->context, p->exten, 1, p->cid_num)) {
10246 
10247                if (e->iam.cot_check_required) {
10248                   dahdi_loopback(p, 1);
10249                } else
10250                   ss7_start_call(p, linkset);
10251             } else {
10252                ast_debug(1, "Call on CIC for unconfigured extension %s\n", p->exten);
10253                p->alreadyhungup = 1;
10254                isup_rel(ss7, e->iam.call, AST_CAUSE_UNALLOCATED);
10255             }
10256             ast_mutex_unlock(&p->lock);
10257             break;
10258          case ISUP_EVENT_COT:
10259             chanpos = ss7_find_cic(linkset, e->cot.cic, e->cot.opc);
10260             if (chanpos < 0) {
10261                ast_log(LOG_WARNING, "COT on unconfigured CIC %d\n", e->cot.cic);
10262                isup_rel(ss7, e->cot.call, -1);
10263                break;
10264             }
10265             p = linkset->pvts[chanpos];
10266 
10267             ast_mutex_lock(&p->lock);
10268 
10269             if (p->loopedback) {
10270                dahdi_loopback(p, 0);
10271                ss7_start_call(p, linkset);
10272             }
10273 
10274             ast_mutex_unlock(&p->lock);
10275 
10276             break;
10277          case ISUP_EVENT_CCR:
10278             ast_debug(1, "Got CCR request on CIC %d\n", e->ccr.cic);
10279             chanpos = ss7_find_cic(linkset, e->ccr.cic, e->ccr.opc);
10280             if (chanpos < 0) {
10281                ast_log(LOG_WARNING, "CCR on unconfigured CIC %d\n", e->ccr.cic);
10282                break;
10283             }
10284 
10285             p = linkset->pvts[chanpos];
10286 
10287             ast_mutex_lock(&p->lock);
10288             dahdi_loopback(p, 1);
10289             ast_mutex_unlock(&p->lock);
10290 
10291             isup_lpa(linkset->ss7, e->ccr.cic, p->dpc);
10292             break;
10293          case ISUP_EVENT_CVT:
10294             ast_debug(1, "Got CVT request on CIC %d\n", e->cvt.cic);
10295             chanpos = ss7_find_cic(linkset, e->cvt.cic, e->cvt.opc);
10296             if (chanpos < 0) {
10297                ast_log(LOG_WARNING, "CVT on unconfigured CIC %d\n", e->cvt.cic);
10298                break;
10299             }
10300             
10301             p = linkset->pvts[chanpos];
10302             
10303             ast_mutex_lock(&p->lock);
10304             dahdi_loopback(p, 1);
10305             ast_mutex_unlock(&p->lock);
10306             
10307             isup_cvr(linkset->ss7, e->cvt.cic, p->dpc);
10308             break;
10309          case ISUP_EVENT_REL:
10310             chanpos = ss7_find_cic(linkset, e->rel.cic, e->rel.opc);
10311             if (chanpos < 0) {
10312                ast_log(LOG_WARNING, "REL on unconfigured CIC %d\n", e->rel.cic);
10313                break;
10314             }
10315             p = linkset->pvts[chanpos];
10316             ast_mutex_lock(&p->lock);
10317             if (p->owner) {
10318                p->owner->hangupcause = e->rel.cause;
10319                p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
10320             } else if (!p->restartpending)
10321                ast_log(LOG_WARNING, "REL on channel (CIC %d) without owner!\n", p->cic);
10322 
10323             /* End the loopback if we have one */
10324             dahdi_loopback(p, 0);
10325 
10326             isup_rlc(ss7, e->rel.call);
10327             p->ss7call = NULL;
10328 
10329             ast_mutex_unlock(&p->lock);
10330             break;
10331          case ISUP_EVENT_ACM:
10332             chanpos = ss7_find_cic(linkset, e->acm.cic, e->acm.opc);
10333             if (chanpos < 0) {
10334                ast_log(LOG_WARNING, "ACM on unconfigured CIC %d\n", e->acm.cic);
10335                isup_rel(ss7, e->acm.call, -1);
10336                break;
10337             } else {
10338                struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
10339 
10340                p = linkset->pvts[chanpos];
10341 
10342                ast_debug(1, "Queueing frame from SS7_EVENT_ACM on CIC %d\n", p->cic);
10343                
10344                if (e->acm.call_ref_ident > 0) {
10345                   p->rlt = 1; /* Setting it but not using it here*/
10346                }
10347 
10348                ast_mutex_lock(&p->lock);
10349                dahdi_queue_frame(p, &f, linkset);
10350                p->proceeding = 1;
10351                p->dialing = 0;
10352                /* Send alerting if subscriber is free */
10353                if (e->acm.called_party_status_ind == 1) {
10354                   p->alerting = 1;
10355                   p->subs[SUB_REAL].needringing = 1;
10356                }
10357                ast_mutex_unlock(&p->lock);
10358             }
10359             break;
10360          case ISUP_EVENT_CGB:
10361             chanpos = ss7_find_cic(linkset, e->cgb.startcic, e->cgb.opc);
10362             if (chanpos < 0) {
10363                ast_log(LOG_WARNING, "CGB on unconfigured CIC %d\n", e->cgb.startcic);
10364                break;
10365             }
10366             p = linkset->pvts[chanpos];
10367             ss7_block_cics(linkset, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, 1);
10368             isup_cgba(linkset->ss7, e->cgb.startcic, e->cgb.endcic, e->cgb.opc, e->cgb.status, e->cgb.type);
10369             break;
10370          case ISUP_EVENT_CGU:
10371             chanpos = ss7_find_cic(linkset, e->cgu.startcic, e->cgu.opc);
10372             if (chanpos < 0) {
10373                ast_log(LOG_WARNING, "CGU on unconfigured CIC %d\n", e->cgu.startcic);
10374                break;
10375             }
10376             p = linkset->pvts[chanpos];
10377             ss7_block_cics(linkset, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, 0);
10378             isup_cgua(linkset->ss7, e->cgu.startcic, e->cgu.endcic, e->cgu.opc, e->cgu.status, e->cgu.type);
10379             break;
10380          case ISUP_EVENT_UCIC:
10381             chanpos = ss7_find_cic(linkset, e->ucic.cic, e->ucic.opc);
10382             if (chanpos < 0) {
10383                ast_log(LOG_WARNING, "UCIC on unconfigured CIC %d\n", e->ucic.cic);
10384                break;
10385             }
10386             p = linkset->pvts[chanpos];
10387             ast_debug(1, "Unequiped Circuit Id Code on CIC %d\n", e->ucic.cic);
10388             ast_mutex_lock(&p->lock);
10389             p->remotelyblocked = 1;
10390             p->inservice = 0;
10391             ast_mutex_unlock(&p->lock);         //doesn't require a SS7 acknowledgement
10392             break;
10393          case ISUP_EVENT_BLO:
10394             chanpos = ss7_find_cic(linkset, e->blo.cic, e->blo.opc);
10395             if (chanpos < 0) {
10396                ast_log(LOG_WARNING, "BLO on unconfigured CIC %d\n", e->blo.cic);
10397                break;
10398             }
10399             p = linkset->pvts[chanpos];
10400             ast_debug(1, "Blocking CIC %d\n", e->blo.cic);
10401             ast_mutex_lock(&p->lock);
10402             p->remotelyblocked = 1;
10403             ast_mutex_unlock(&p->lock);
10404             isup_bla(linkset->ss7, e->blo.cic, p->dpc);
10405             break;
10406          case ISUP_EVENT_BLA:
10407             chanpos = ss7_find_cic(linkset, e->bla.cic, e->bla.opc);
10408             if (chanpos < 0) {
10409                ast_log(LOG_WARNING, "BLA on unconfigured CIC %d\n", e->bla.cic);
10410                break;
10411             }
10412             ast_debug(1, "Blocking CIC %d\n", e->bla.cic);
10413             p = linkset->pvts[chanpos];
10414             ast_mutex_lock(&p->lock);
10415             p->locallyblocked = 1;
10416             ast_mutex_unlock(&p->lock);
10417             break;
10418          case ISUP_EVENT_UBL:
10419             chanpos = ss7_find_cic(linkset, e->ubl.cic, e->ubl.opc);
10420             if (chanpos < 0) {
10421                ast_log(LOG_WARNING, "UBL on unconfigured CIC %d\n", e->ubl.cic);
10422                break;
10423             }
10424             p = linkset->pvts[chanpos];
10425             ast_debug(1, "Unblocking CIC %d\n", e->ubl.cic);
10426             ast_mutex_lock(&p->lock);
10427             p->remotelyblocked = 0;
10428             ast_mutex_unlock(&p->lock);
10429             isup_uba(linkset->ss7, e->ubl.cic, p->dpc);
10430             break;
10431          case ISUP_EVENT_UBA:
10432             chanpos = ss7_find_cic(linkset, e->uba.cic, e->uba.opc);
10433             if (chanpos < 0) {
10434                ast_log(LOG_WARNING, "UBA on unconfigured CIC %d\n", e->uba.cic);
10435                break;
10436             }
10437             p = linkset->pvts[chanpos];
10438             ast_debug(1, "Unblocking CIC %d\n", e->uba.cic);
10439             ast_mutex_lock(&p->lock);
10440             p->locallyblocked = 0;
10441             ast_mutex_unlock(&p->lock);
10442             break;
10443          case ISUP_EVENT_CON:
10444          case ISUP_EVENT_ANM:
10445             if (e->e == ISUP_EVENT_CON)
10446                cic = e->con.cic;
10447             else
10448                cic = e->anm.cic;
10449 
10450             chanpos = ss7_find_cic(linkset, cic, (e->e == ISUP_EVENT_ANM) ? e->anm.opc : e->con.opc);
10451             if (chanpos < 0) {
10452                ast_log(LOG_WARNING, "ANM/CON on unconfigured CIC %d\n", cic);
10453                isup_rel(ss7, (e->e == ISUP_EVENT_ANM) ? e->anm.call : e->con.call, -1);
10454                break;
10455             } else {
10456                p = linkset->pvts[chanpos];
10457                ast_mutex_lock(&p->lock);
10458                p->subs[SUB_REAL].needanswer = 1;
10459                if (p->dsp && p->dsp_features) {
10460                        ast_dsp_set_features(p->dsp, p->dsp_features);
10461                        p->dsp_features = 0;
10462                }
10463                dahdi_enable_ec(p);
10464                ast_mutex_unlock(&p->lock);
10465             }
10466             break;
10467          case ISUP_EVENT_RLC:
10468             chanpos = ss7_find_cic(linkset, e->rlc.cic, e->rlc.opc);
10469             if (chanpos < 0) {
10470                ast_log(LOG_WARNING, "RLC on unconfigured CIC %d\n", e->rlc.cic);
10471                break;
10472             } else {
10473                p = linkset->pvts[chanpos];
10474                ast_mutex_lock(&p->lock);
10475                if (p->alreadyhungup)
10476                   p->ss7call = NULL;
10477                else
10478                   ast_log(LOG_NOTICE, "Received RLC out and we haven't sent REL.  Ignoring.\n");
10479                ast_mutex_unlock(&p->lock);
10480                }
10481                break;
10482          case ISUP_EVENT_FAA:
10483             chanpos = ss7_find_cic(linkset, e->faa.cic, e->faa.opc);
10484             if (chanpos < 0) {
10485                ast_log(LOG_WARNING, "FAA on unconfigured CIC %d\n", e->faa.cic);
10486                break;
10487             } else {
10488                p = linkset->pvts[chanpos];
10489                ast_debug(1, "FAA received on CIC %d\n", e->faa.cic);
10490                ast_mutex_lock(&p->lock);
10491                if (p->alreadyhungup){
10492                   p->ss7call = NULL;
10493                   ast_log(LOG_NOTICE, "Received FAA and we haven't sent FAR.  Ignoring.\n");
10494                }
10495                ast_mutex_unlock(&p->lock);
10496             }
10497             break;
10498          default:
10499             ast_debug(1, "Unknown event %s\n", ss7_event2str(e->e));
10500             break;
10501          }
10502       }
10503       ast_mutex_unlock(&linkset->lock);
10504    }
10505 
10506    return 0;
10507 }
10508 
10509 static void dahdi_ss7_message(struct ss7 *ss7, char *s)
10510 {
10511 #if 0
10512    int i;
10513 
10514    for (i = 0; i < NUM_SPANS; i++)
10515       if (linksets[i].ss7 == ss7)
10516          break;
10517 
10518    ast_verbose("[%d] %s", i+1, s);
10519 #else
10520    ast_verbose("%s", s);
10521 #endif
10522 }
10523 
10524 static void dahdi_ss7_error(struct ss7 *ss7, char *s)
10525 {
10526 #if 0
10527    int i;
10528 
10529    for (i = 0; i < NUM_SPANS; i++)
10530       if (linksets[i].ss7 == ss7)
10531          break;
10532 
10533 #else
10534    ast_log(LOG_ERROR, "%s", s);
10535 #endif
10536 }
10537 
10538 #endif /* HAVE_SS7 */
10539 
10540 #ifdef HAVE_PRI
10541 static struct dahdi_pvt *pri_find_crv(struct dahdi_pri *pri, int crv)
10542 {
10543    struct dahdi_pvt *p;
10544    p = pri->crvs;
10545    while (p) {
10546       if (p->channel == crv)
10547          return p;
10548       p = p->next;
10549    }
10550    return NULL;
10551 }
10552 
10553 
10554 static int pri_find_principle(struct dahdi_pri *pri, int channel)
10555 {
10556    int x;
10557    int span = PRI_SPAN(channel);
10558    int spanfd;
10559    struct dahdi_params param;
10560    int principle = -1;
10561    int explicit = PRI_EXPLICIT(channel);
10562    channel = PRI_CHANNEL(channel);
10563 
10564    if (!explicit) {
10565       spanfd = pri_active_dchan_fd(pri);
10566       memset(&param, 0, sizeof(param));
10567       if (ioctl(spanfd, DAHDI_GET_PARAMS, &param))
10568          return -1;
10569       span = pris[param.spanno - 1].prilogicalspan;
10570    }
10571 
10572    for (x = 0; x < pri->numchans; x++) {
10573       if (pri->pvts[x] && (pri->pvts[x]->prioffset == channel) && (pri->pvts[x]->logicalspan == span)) {
10574          principle = x;
10575          break;
10576       }
10577    }
10578    
10579    return principle;
10580 }
10581 
10582 static int pri_fixup_principle(struct dahdi_pri *pri, int principle, q931_call *c)
10583 {
10584    int x;
10585    struct dahdi_pvt *crv;
10586    if (!c) {
10587       if (principle < 0)
10588          return -1;
10589       return principle;
10590    }
10591    if ((principle > -1) && 
10592       (principle < pri->numchans) && 
10593       (pri->pvts[principle]) && 
10594       (pri->pvts[principle]->call == c))
10595       return principle;
10596    /* First, check for other bearers */
10597    for (x = 0; x < pri->numchans; x++) {
10598       if (!pri->pvts[x])
10599          continue;
10600       if (pri->pvts[x]->call == c) {
10601          /* Found our call */
10602          if (principle != x) {
10603             struct dahdi_pvt *new = pri->pvts[principle], *old = pri->pvts[x];
10604 
10605             ast_verb(3, "Moving call from channel %d to channel %d\n",
10606                 old->channel, new->channel);
10607             if (new->owner) {
10608                ast_log(LOG_WARNING, "Can't fix up channel from %d to %d because %d is already in use\n",
10609                   old->channel, new->channel, new->channel);
10610                return -1;
10611             }
10612             /* Fix it all up now */
10613             new->owner = old->owner;
10614             old->owner = NULL;
10615             if (new->owner) {
10616                ast_string_field_build(new->owner, name, 
10617                             "DAHDI/%d:%d-%d", pri->trunkgroup,
10618                             new->channel, 1);
10619                new->owner->tech_pvt = new;
10620                ast_channel_set_fd(new->owner, 0, new->subs[SUB_REAL].dfd);
10621                new->subs[SUB_REAL].owner = old->subs[SUB_REAL].owner;
10622                old->subs[SUB_REAL].owner = NULL;
10623             } else
10624                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);
10625             new->call = old->call;
10626             old->call = NULL;
10627 
10628             /* Copy any DSP that may be present */
10629             new->dsp = old->dsp;
10630             new->dsp_features = old->dsp_features;
10631             old->dsp = NULL;
10632             old->dsp_features = 0;
10633          }
10634          return principle;
10635       }
10636    }
10637    /* Now check for a CRV with no bearer */
10638    crv = pri->crvs;
10639    while (crv) {
10640       if (crv->call == c) {
10641          /* This is our match...  Perform some basic checks */
10642          if (crv->bearer)
10643             ast_log(LOG_WARNING, "Trying to fix up call which already has a bearer which isn't the one we think it is\n");
10644          else if (pri->pvts[principle]->owner) 
10645             ast_log(LOG_WARNING, "Tring to fix up a call to a bearer which already has an owner!\n");
10646          else {
10647             /* Looks good.  Drop the pseudo channel now, clear up the assignment, and
10648                wakeup the potential sleeper */
10649             dahdi_close_sub(crv, SUB_REAL);
10650             pri->pvts[principle]->call = crv->call;
10651             pri_assign_bearer(crv, pri, pri->pvts[principle]);
10652             ast_debug(1, "Assigning bearer %d/%d to CRV %d:%d\n",
10653                pri->pvts[principle]->logicalspan, pri->pvts[principle]->prioffset,
10654                pri->trunkgroup, crv->channel);
10655             wakeup_sub(crv, SUB_REAL, pri);
10656          }
10657          return principle;
10658       }
10659       crv = crv->next;
10660    }
10661    ast_log(LOG_WARNING, "Call specified, but not found?\n");
10662    return -1;
10663 }
10664 
10665 static void *do_idle_thread(void *vchan)
10666 {
10667    struct ast_channel *chan = vchan;
10668    struct dahdi_pvt *pvt = chan->tech_pvt;
10669    struct ast_frame *f;
10670    char ex[80];
10671    /* Wait up to 30 seconds for an answer */
10672    int newms, ms = 30000;
10673    ast_verb(3, "Initiating idle call on channel %s\n", chan->name);
10674    snprintf(ex, sizeof(ex), "%d/%s", pvt->channel, pvt->pri->idledial);
10675    if (ast_call(chan, ex, 0)) {
10676       ast_log(LOG_WARNING, "Idle dial failed on '%s' to '%s'\n", chan->name, ex);
10677       ast_hangup(chan);
10678       return NULL;
10679    }
10680    while ((newms = ast_waitfor(chan, ms)) > 0) {
10681       f = ast_read(chan);
10682       if (!f) {
10683          /* Got hangup */
10684          break;
10685       }
10686       if (f->frametype == AST_FRAME_CONTROL) {
10687          switch (f->subclass) {
10688          case AST_CONTROL_ANSWER:
10689             /* Launch the PBX */
10690             ast_copy_string(chan->exten, pvt->pri->idleext, sizeof(chan->exten));
10691             ast_copy_string(chan->context, pvt->pri->idlecontext, sizeof(chan->context));
10692             chan->priority = 1;
10693             ast_verb(4, "Idle channel '%s' answered, sending to %s@%s\n", chan->name, chan->exten, chan->context);
10694             ast_pbx_run(chan);
10695             /* It's already hungup, return immediately */
10696             return NULL;
10697          case AST_CONTROL_BUSY:
10698             ast_verb(4, "Idle channel '%s' busy, waiting...\n", chan->name);
10699             break;
10700          case AST_CONTROL_CONGESTION:
10701             ast_verb(4, "Idle channel '%s' congested, waiting...\n", chan->name);
10702             break;
10703          };
10704       }
10705       ast_frfree(f);
10706       ms = newms;
10707    }
10708    /* Hangup the channel since nothing happend */
10709    ast_hangup(chan);
10710    return NULL;
10711 }
10712 
10713 #ifndef PRI_RESTART
10714 #error "Upgrade your libpri"
10715 #endif
10716 static void dahdi_pri_message(struct pri *pri, char *s)
10717 {
10718    int x, y;
10719    int dchan = -1, span = -1;
10720    int dchancount = 0;
10721 
10722    if (pri) {
10723       for (x = 0; x < NUM_SPANS; x++) {
10724          for (y = 0; y < NUM_DCHANS; y++) {
10725             if (pris[x].dchans[y])
10726                dchancount++;
10727 
10728             if (pris[x].dchans[y] == pri)
10729                dchan = y;
10730          }
10731          if (dchan >= 0) {
10732             span = x;
10733             break;
10734          }
10735          dchancount = 0;
10736       }
10737       if (dchancount > 1 && (span > -1))
10738          ast_verbose("[Span %d D-Channel %d]%s", span, dchan, s);
10739       else
10740          ast_verbose("%s", s);
10741    } else
10742       ast_verbose("%s", s);
10743 
10744    ast_mutex_lock(&pridebugfdlock);
10745 
10746    if (pridebugfd >= 0) {
10747       if (write(pridebugfd, s, strlen(s)) < 0) {
10748          ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
10749       }
10750    }
10751 
10752    ast_mutex_unlock(&pridebugfdlock);
10753 }
10754 
10755 static void dahdi_pri_error(struct pri *pri, char *s)
10756 {
10757    int x, y;
10758    int dchan = -1, span = -1;
10759    int dchancount = 0;
10760 
10761    if (pri) {
10762       for (x = 0; x < NUM_SPANS; x++) {
10763          for (y = 0; y < NUM_DCHANS; y++) {
10764             if (pris[x].dchans[y])
10765                dchancount++;
10766 
10767             if (pris[x].dchans[y] == pri)
10768                dchan = y;
10769          }
10770          if (dchan >= 0) {
10771             span = x;
10772             break;
10773          }
10774          dchancount = 0;
10775       }
10776       if ((dchancount > 1) && (span > -1))
10777          ast_log(LOG_ERROR, "[Span %d D-Channel %d] PRI: %s", span, dchan, s);
10778       else
10779          ast_log(LOG_ERROR, "%s", s);
10780    } else
10781       ast_log(LOG_ERROR, "%s", s);
10782 
10783    ast_mutex_lock(&pridebugfdlock);
10784 
10785    if (pridebugfd >= 0) {
10786       if (write(pridebugfd, s, strlen(s)) < 0) {
10787          ast_log(LOG_WARNING, "write() failed: %s\n", strerror(errno));
10788       }
10789    }
10790 
10791    ast_mutex_unlock(&pridebugfdlock);
10792 }
10793 
10794 static int pri_check_restart(struct dahdi_pri *pri)
10795 {
10796    do {
10797       pri->resetpos++;
10798    } while ((pri->resetpos < pri->numchans) &&
10799        (!pri->pvts[pri->resetpos] ||
10800         pri->pvts[pri->resetpos]->call ||
10801         pri->pvts[pri->resetpos]->resetting));
10802    if (pri->resetpos < pri->numchans) {
10803       /* Mark the channel as resetting and restart it */
10804       pri->pvts[pri->resetpos]->resetting = 1;
10805       pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[pri->resetpos]));
10806    } else {
10807       pri->resetting = 0;
10808       time(&pri->lastreset);
10809    }
10810    return 0;
10811 }
10812 
10813 static int pri_hangup_all(struct dahdi_pvt *p, struct dahdi_pri *pri)
10814 {
10815    int x;
10816    int redo;
10817    ast_mutex_unlock(&pri->lock);
10818    ast_mutex_lock(&p->lock);
10819    do {
10820       redo = 0;
10821       for (x = 0; x < 3; x++) {
10822          while (p->subs[x].owner && ast_channel_trylock(p->subs[x].owner)) {
10823             redo++;
10824             DEADLOCK_AVOIDANCE(&p->lock);
10825          }
10826          if (p->subs[x].owner) {
10827             ast_queue_hangup_with_cause(p->subs[x].owner, AST_CAUSE_PRE_EMPTED);
10828             ast_channel_unlock(p->subs[x].owner);
10829          }
10830       }
10831    } while (redo);
10832    ast_mutex_unlock(&p->lock);
10833    ast_mutex_lock(&pri->lock);
10834    return 0;
10835 }
10836 
10837 static char * redirectingreason2str(int redirectingreason)
10838 {
10839    switch (redirectingreason) {
10840    case 0:
10841       return "UNKNOWN";
10842    case 1:
10843       return "BUSY";
10844    case 2:
10845       return "NO_REPLY";
10846    case 0xF:
10847       return "UNCONDITIONAL";
10848    default:
10849       return "NOREDIRECT";
10850    }
10851 }
10852 
10853 static void apply_plan_to_number(char *buf, size_t size, const struct dahdi_pri *pri, const char *number, const int plan)
10854 {
10855    if (pri->dialplan == -2) { /* autodetect the TON but leave the number untouched */
10856       snprintf(buf, size, "%s", number);
10857       return;
10858    }
10859    if (ast_strlen_zero(number)) { /* make sure a number exists so prefix isn't placed on an empty string */
10860       if (size) {
10861          *buf = '\0';
10862       }
10863       return;
10864    }
10865    switch (plan) {
10866    case PRI_INTERNATIONAL_ISDN:     /* Q.931 dialplan == 0x11 international dialplan => prepend international prefix digits */
10867       snprintf(buf, size, "%s%s", pri->internationalprefix, number);
10868       break;
10869    case PRI_NATIONAL_ISDN:       /* Q.931 dialplan == 0x21 national dialplan => prepend national prefix digits */
10870       snprintf(buf, size, "%s%s", pri->nationalprefix, number);
10871       break;
10872    case PRI_LOCAL_ISDN:       /* Q.931 dialplan == 0x41 local dialplan => prepend local prefix digits */
10873       snprintf(buf, size, "%s%s", pri->localprefix, number);
10874       break;
10875    case PRI_PRIVATE:       /* Q.931 dialplan == 0x49 private dialplan => prepend private prefix digits */
10876       snprintf(buf, size, "%s%s", pri->privateprefix, number);
10877       break;
10878    case PRI_UNKNOWN:       /* Q.931 dialplan == 0x00 unknown dialplan => prepend unknown prefix digits */
10879       snprintf(buf, size, "%s%s", pri->unknownprefix, number);
10880       break;
10881    default:          /* other Q.931 dialplan => don't twiddle with callingnum */
10882       snprintf(buf, size, "%s", number);
10883       break;
10884    }
10885 }
10886 
10887 
10888 static void *pri_dchannel(void *vpri)
10889 {
10890    struct dahdi_pri *pri = vpri;
10891    pri_event *e;
10892    struct pollfd fds[NUM_DCHANS];
10893    int res;
10894    int chanpos = 0;
10895    int x;
10896    int haveidles;
10897    int activeidles;
10898    int nextidle = -1;
10899    struct ast_channel *c;
10900    struct timeval tv, lowest, *next;
10901    struct timeval lastidle = ast_tvnow();
10902    int doidling=0;
10903    char *cc;
10904    char idlen[80];
10905    struct ast_channel *idle;
10906    pthread_t p;
10907    time_t t;
10908    int i, which=-1;
10909    int numdchans;
10910    int cause=0;
10911    struct dahdi_pvt *crv;
10912    pthread_t threadid;
10913    char ani2str[6];
10914    char plancallingnum[256];
10915    char plancallingani[256];
10916    char calledtonstr[10];
10917    
10918    pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
10919 
10920    gettimeofday(&lastidle, NULL);
10921    if (!ast_strlen_zero(pri->idledial) && !ast_strlen_zero(pri->idleext)) {
10922       /* Need to do idle dialing, check to be sure though */
10923       cc = strchr(pri->idleext, '@');
10924       if (cc) {
10925          *cc = '\0';
10926          cc++;
10927          ast_copy_string(pri->idlecontext, cc, sizeof(pri->idlecontext));
10928 #if 0
10929          /* Extensions may not be loaded yet */
10930          if (!ast_exists_extension(NULL, pri->idlecontext, pri->idleext, 1, NULL))
10931             ast_log(LOG_WARNING, "Extension '%s @ %s' does not exist\n", pri->idleext, pri->idlecontext);
10932          else
10933 #endif
10934             doidling = 1;
10935       } else
10936          ast_log(LOG_WARNING, "Idle dial string '%s' lacks '@context'\n", pri->idleext);
10937    }
10938    for (;;) {
10939       for (i = 0; i < NUM_DCHANS; i++) {
10940          if (!pri->dchannels[i])
10941             break;
10942          fds[i].fd = pri->fds[i];
10943          fds[i].events = POLLIN | POLLPRI;
10944          fds[i].revents = 0;
10945       }
10946       numdchans = i;
10947       time(&t);
10948       ast_mutex_lock(&pri->lock);
10949       if (pri->switchtype != PRI_SWITCH_GR303_TMC && (pri->resetinterval > 0)) {
10950          if (pri->resetting && pri_is_up(pri)) {
10951             if (pri->resetpos < 0)
10952                pri_check_restart(pri);
10953          } else {
10954             if (!pri->resetting  && (t - pri->lastreset) >= pri->resetinterval) {
10955                pri->resetting = 1;
10956                pri->resetpos = -1;
10957             }
10958          }
10959       }
10960       /* Look for any idle channels if appropriate */
10961       if (doidling && pri_is_up(pri)) {
10962          nextidle = -1;
10963          haveidles = 0;
10964          activeidles = 0;
10965          for (x = pri->numchans; x >= 0; x--) {
10966             if (pri->pvts[x] && !pri->pvts[x]->owner && 
10967                 !pri->pvts[x]->call) {
10968                if (haveidles < pri->minunused) {
10969                   haveidles++;
10970                } else if (!pri->pvts[x]->resetting) {
10971                   nextidle = x;
10972                   break;
10973                }
10974             } else if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall)
10975                activeidles++;
10976          }
10977          if (nextidle > -1) {
10978             if (ast_tvdiff_ms(ast_tvnow(), lastidle) > 1000) {
10979                /* Don't create a new idle call more than once per second */
10980                snprintf(idlen, sizeof(idlen), "%d/%s", pri->pvts[nextidle]->channel, pri->idledial);
10981                idle = dahdi_request("DAHDI", AST_FORMAT_ULAW, idlen, &cause);
10982                if (idle) {
10983                   pri->pvts[nextidle]->isidlecall = 1;
10984                   if (ast_pthread_create_background(&p, NULL, do_idle_thread, idle)) {
10985                      ast_log(LOG_WARNING, "Unable to start new thread for idle channel '%s'\n", idle->name);
10986                      dahdi_hangup(idle);
10987                   }
10988                } else
10989                   ast_log(LOG_WARNING, "Unable to request channel 'DAHDI/%s' for idle call\n", idlen);
10990                lastidle = ast_tvnow();
10991             }
10992          } else if ((haveidles < pri->minunused) &&
10993                (activeidles > pri->minidle)) {
10994             /* Mark something for hangup if there is something 
10995                that can be hungup */
10996             for (x = pri->numchans; x >= 0; x--) {
10997                /* find a candidate channel */
10998                if (pri->pvts[x] && pri->pvts[x]->owner && pri->pvts[x]->isidlecall) {
10999                   pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11000                   haveidles++;
11001                   /* Stop if we have enough idle channels or
11002                     can't spare any more active idle ones */
11003                   if ((haveidles >= pri->minunused) ||
11004                       (activeidles <= pri->minidle))
11005                      break;
11006                } 
11007             }
11008          }
11009       }
11010       /* Start with reasonable max */
11011       lowest = ast_tv(60, 0);
11012       for (i = 0; i < NUM_DCHANS; i++) {
11013          /* Find lowest available d-channel */
11014          if (!pri->dchannels[i])
11015             break;
11016          if ((next = pri_schedule_next(pri->dchans[i]))) {
11017             /* We need relative time here */
11018             tv = ast_tvsub(*next, ast_tvnow());
11019             if (tv.tv_sec < 0) {
11020                tv = ast_tv(0,0);
11021             }
11022             if (doidling || pri->resetting) {
11023                if (tv.tv_sec > 1) {
11024                   tv = ast_tv(1, 0);
11025                }
11026             } else {
11027                if (tv.tv_sec > 60) {
11028                   tv = ast_tv(60, 0);
11029                }
11030             }
11031          } else if (doidling || pri->resetting) {
11032             /* Make sure we stop at least once per second if we're
11033                monitoring idle channels */
11034             tv = ast_tv(1,0);
11035          } else {
11036             /* Don't poll for more than 60 seconds */
11037             tv = ast_tv(60, 0);
11038          }
11039          if (!i || ast_tvcmp(tv, lowest) < 0) {
11040             lowest = tv;
11041          }
11042       }
11043       ast_mutex_unlock(&pri->lock);
11044 
11045       pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
11046       pthread_testcancel();
11047       e = NULL;
11048       res = poll(fds, numdchans, lowest.tv_sec * 1000 + lowest.tv_usec / 1000);
11049       pthread_testcancel();
11050       pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
11051 
11052       ast_mutex_lock(&pri->lock);
11053       if (!res) {
11054          for (which = 0; which < NUM_DCHANS; which++) {
11055             if (!pri->dchans[which])
11056                break;
11057             /* Just a timeout, run the scheduler */
11058             e = pri_schedule_run(pri->dchans[which]);
11059             if (e)
11060                break;
11061          }
11062       } else if (res > -1) {
11063          for (which = 0; which < NUM_DCHANS; which++) {
11064             if (!pri->dchans[which])
11065                break;
11066             if (fds[which].revents & POLLPRI) {
11067                /* Check for an event */
11068                x = 0;
11069                res = ioctl(pri->fds[which], DAHDI_GETEVENT, &x);
11070                if (x) {
11071                   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);
11072                   manager_event(EVENT_FLAG_SYSTEM, "PRIEvent",
11073                      "PRIEvent: %s\r\n"
11074                      "PRIEventCode: %d\r\n"
11075                      "D-channel: %s\r\n"
11076                      "Span: %d\r\n",
11077                      event2str(x),
11078                      x,
11079                      pri_order(which),
11080                      pri->span
11081                      );
11082                }
11083                /* Keep track of alarm state */  
11084                if (x == DAHDI_EVENT_ALARM) {
11085                   pri->dchanavail[which] &= ~(DCHAN_NOTINALARM | DCHAN_UP);
11086                   pri_find_dchan(pri);
11087                } else if (x == DAHDI_EVENT_NOALARM) {
11088                   pri->dchanavail[which] |= DCHAN_NOTINALARM;
11089                   pri_restart(pri->dchans[which]);
11090                }
11091             
11092                ast_debug(1, "Got event %s (%d) on D-channel for span %d\n", event2str(x), x, pri->span);
11093             } else if (fds[which].revents & POLLIN) {
11094                e = pri_check_event(pri->dchans[which]);
11095             }
11096             if (e)
11097                break;
11098          }
11099       } else if (errno != EINTR)
11100          ast_log(LOG_WARNING, "pri_event returned error %d (%s)\n", errno, strerror(errno));
11101 
11102       if (e) {
11103          if (pri->debug)
11104             pri_dump_event(pri->dchans[which], e);
11105 
11106          if (e->e != PRI_EVENT_DCHAN_DOWN) {
11107             if (!(pri->dchanavail[which] & DCHAN_UP)) {
11108                ast_verb(2, "%s D-Channel on span %d up\n", pri_order(which), pri->span);
11109             }
11110             pri->dchanavail[which] |= DCHAN_UP;
11111          } else if (pri->sig != SIG_BRI_PTMP) {
11112             if (pri->dchanavail[which] & DCHAN_UP) {
11113                ast_verb(2, "%s D-Channel on span %d down\n", pri_order(which), pri->span);
11114             }
11115             pri->dchanavail[which] &= ~DCHAN_UP;
11116          }
11117 
11118          if ((e->e != PRI_EVENT_DCHAN_UP) && (e->e != PRI_EVENT_DCHAN_DOWN) && (pri->pri != pri->dchans[which]))
11119             /* Must be an NFAS group that has the secondary dchan active */
11120             pri->pri = pri->dchans[which];
11121 
11122          switch (e->e) {
11123          case PRI_EVENT_DCHAN_UP:
11124             if (!pri->pri) pri_find_dchan(pri);
11125 
11126             /* Note presense of D-channel */
11127             time(&pri->lastreset);
11128 
11129             /* Restart in 5 seconds */
11130             if (pri->resetinterval > -1) {
11131                pri->lastreset -= pri->resetinterval;
11132                pri->lastreset += 5;
11133             }
11134             pri->resetting = 0;
11135             /* Take the channels from inalarm condition */
11136             for (i = 0; i < pri->numchans; i++)
11137                if (pri->pvts[i]) {
11138                   pri->pvts[i]->inalarm = 0;
11139                }
11140             break;
11141          case PRI_EVENT_DCHAN_DOWN:
11142             pri_find_dchan(pri);
11143             if (!pri_is_up(pri)) {
11144                pri->resetting = 0;
11145                /* Hangup active channels and put them in alarm mode */
11146                for (i = 0; i < pri->numchans; i++) {
11147                   struct dahdi_pvt *p = pri->pvts[i];
11148                   if (p) {
11149                      if (!p->pri || !p->pri->pri || pri_get_timer(p->pri->pri, PRI_TIMER_T309) < 0) {
11150                         /* T309 is not enabled : hangup calls when alarm occurs */
11151                         if (p->call) {
11152                            if (p->pri && p->pri->pri) {
11153                               pri_hangup(p->pri->pri, p->call, -1);
11154                               pri_destroycall(p->pri->pri, p->call);
11155                               p->call = NULL;
11156                            } else
11157                               ast_log(LOG_WARNING, "The PRI Call have not been destroyed\n");
11158                         }
11159                         if (p->realcall) {
11160                            pri_hangup_all(p->realcall, pri);
11161                         } else if (p->owner)
11162                            p->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11163                      }
11164                      p->inalarm = 1;
11165                   }
11166                }
11167             }
11168             break;
11169          case PRI_EVENT_RESTART:
11170             if (e->restart.channel > -1) {
11171                chanpos = pri_find_principle(pri, e->restart.channel);
11172                if (chanpos < 0)
11173                   ast_log(LOG_WARNING, "Restart requested on odd/unavailable channel number %d/%d on span %d\n", 
11174                      PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
11175                else {
11176                   ast_verb(3, "B-channel %d/%d restarted on span %d\n",
11177                         PRI_SPAN(e->restart.channel), PRI_CHANNEL(e->restart.channel), pri->span);
11178                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11179                   if (pri->pvts[chanpos]->call) {
11180                      pri_destroycall(pri->pri, pri->pvts[chanpos]->call);
11181                      pri->pvts[chanpos]->call = NULL;
11182                   }
11183                   /* Force soft hangup if appropriate */
11184                   if (pri->pvts[chanpos]->realcall) 
11185                      pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11186                   else if (pri->pvts[chanpos]->owner)
11187                      pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11188                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11189                }
11190             } else {
11191                ast_verb(3, "Restart on requested on entire span %d\n", pri->span);
11192                for (x = 0; x < pri->numchans; x++)
11193                   if (pri->pvts[x]) {
11194                      ast_mutex_lock(&pri->pvts[x]->lock);
11195                      if (pri->pvts[x]->call) {
11196                         pri_destroycall(pri->pri, pri->pvts[x]->call);
11197                         pri->pvts[x]->call = NULL;
11198                      }
11199                      if (pri->pvts[x]->realcall) 
11200                         pri_hangup_all(pri->pvts[x]->realcall, pri);
11201                      else if (pri->pvts[x]->owner)
11202                         pri->pvts[x]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11203                      ast_mutex_unlock(&pri->pvts[x]->lock);
11204                   }
11205             }
11206             break;
11207          case PRI_EVENT_KEYPAD_DIGIT:
11208             chanpos = pri_find_principle(pri, e->digit.channel);
11209             if (chanpos < 0) {
11210                ast_log(LOG_WARNING, "KEYPAD_DIGITs received on unconfigured channel %d/%d span %d\n", 
11211                   PRI_SPAN(e->digit.channel), PRI_CHANNEL(e->digit.channel), pri->span);
11212             } else {
11213                chanpos = pri_fixup_principle(pri, chanpos, e->digit.call);
11214                if (chanpos > -1) {
11215                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11216                   /* queue DTMF frame if the PBX for this call was already started (we're forwarding KEYPAD_DIGITs further on */
11217                   if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->digit.call && pri->pvts[chanpos]->owner) {
11218                      /* how to do that */
11219                      int digitlen = strlen(e->digit.digits);
11220                      char digit;
11221                      int i;               
11222                      for (i = 0; i < digitlen; i++) { 
11223                         digit = e->digit.digits[i];
11224                         {
11225                            struct ast_frame f = { AST_FRAME_DTMF, digit, };
11226                            dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11227                         }
11228                      }
11229                   }
11230                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11231                }
11232             }
11233             break;
11234             
11235          case PRI_EVENT_INFO_RECEIVED:
11236             chanpos = pri_find_principle(pri, e->ring.channel);
11237             if (chanpos < 0) {
11238                ast_log(LOG_WARNING, "INFO received on unconfigured channel %d/%d span %d\n", 
11239                   PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
11240             } else {
11241                chanpos = pri_fixup_principle(pri, chanpos, e->ring.call);
11242                if (chanpos > -1) {
11243                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11244                   /* queue DTMF frame if the PBX for this call was already started (we're forwarding INFORMATION further on */
11245                   if ((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && pri->pvts[chanpos]->call==e->ring.call && pri->pvts[chanpos]->owner) {
11246                      /* how to do that */
11247                      int digitlen = strlen(e->ring.callednum);
11248                      char digit;
11249                      int i;               
11250                      for (i = 0; i < digitlen; i++) { 
11251                         digit = e->ring.callednum[i];
11252                         {
11253                            struct ast_frame f = { AST_FRAME_DTMF, digit, };
11254                            dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11255                         }
11256                      }
11257                   }
11258                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11259                }
11260             }
11261             break;
11262          case PRI_EVENT_RING:
11263             crv = NULL;
11264             if (e->ring.channel == -1)
11265                chanpos = pri_find_empty_chan(pri, 1);
11266             else
11267                chanpos = pri_find_principle(pri, e->ring.channel);
11268             /* if no channel specified find one empty */
11269             if (chanpos < 0) {
11270                ast_log(LOG_WARNING, "Ring requested on unconfigured channel %d/%d span %d\n", 
11271                   PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
11272             } else {
11273                ast_mutex_lock(&pri->pvts[chanpos]->lock);
11274                if (pri->pvts[chanpos]->owner) {
11275                   if (pri->pvts[chanpos]->call == e->ring.call) {
11276                      ast_log(LOG_WARNING, "Duplicate setup requested on channel %d/%d already in use on span %d\n", 
11277                         PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
11278                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11279                      break;
11280                   } else {
11281                      /* This is where we handle initial glare */
11282                      ast_debug(1, "Ring requested on channel %d/%d already in use or previously requested on span %d.  Attempting to renegotiate channel.\n", 
11283                      PRI_SPAN(e->ring.channel), PRI_CHANNEL(e->ring.channel), pri->span);
11284                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11285                      chanpos = -1;
11286                   }
11287                }
11288                if (chanpos > -1)
11289                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11290             }
11291             if ((chanpos < 0) && (e->ring.flexible))
11292                chanpos = pri_find_empty_chan(pri, 1);
11293             if (chanpos > -1) {
11294                ast_mutex_lock(&pri->pvts[chanpos]->lock);
11295                if (pri->switchtype == PRI_SWITCH_GR303_TMC) {
11296                   /* Should be safe to lock CRV AFAIK while bearer is still locked */
11297                   crv = pri_find_crv(pri, pri_get_crv(pri->pri, e->ring.call, NULL));
11298                   if (crv)
11299                      ast_mutex_lock(&crv->lock);
11300                   if (!crv || crv->owner) {
11301                      pri->pvts[chanpos]->call = NULL;
11302                      if (crv) {
11303                         if (crv->owner)
11304                            crv->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11305                         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);
11306                      } else
11307                         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);
11308                      pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_INVALID_CALL_REFERENCE);
11309                      if (crv)
11310                         ast_mutex_unlock(&crv->lock);
11311                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11312                      break;
11313                   }
11314                }
11315                pri->pvts[chanpos]->call = e->ring.call;
11316                apply_plan_to_number(plancallingnum, sizeof(plancallingnum), pri, e->ring.callingnum, e->ring.callingplan);
11317                if (pri->pvts[chanpos]->use_callerid) {
11318                   ast_shrink_phone_number(plancallingnum);
11319                   ast_copy_string(pri->pvts[chanpos]->cid_num, plancallingnum, sizeof(pri->pvts[chanpos]->cid_num));
11320 #ifdef PRI_ANI
11321                   if (!ast_strlen_zero(e->ring.callingani)) {
11322                      apply_plan_to_number(plancallingani, sizeof(plancallingani), pri, e->ring.callingani, e->ring.callingplanani);
11323                      ast_shrink_phone_number(plancallingani);
11324                      ast_copy_string(pri->pvts[chanpos]->cid_ani, plancallingani, sizeof(pri->pvts[chanpos]->cid_ani));
11325                   } else {
11326                      pri->pvts[chanpos]->cid_ani[0] = '\0';
11327                   }
11328 #endif
11329                   ast_copy_string(pri->pvts[chanpos]->cid_name, e->ring.callingname, sizeof(pri->pvts[chanpos]->cid_name));
11330                   pri->pvts[chanpos]->cid_ton = e->ring.callingplan; /* this is the callingplan (TON/NPI), e->ring.callingplan>>4 would be the TON */
11331                } else {
11332                   pri->pvts[chanpos]->cid_num[0] = '\0';
11333                   pri->pvts[chanpos]->cid_ani[0] = '\0';
11334                   pri->pvts[chanpos]->cid_name[0] = '\0';
11335                   pri->pvts[chanpos]->cid_ton = 0;
11336                }
11337                apply_plan_to_number(pri->pvts[chanpos]->rdnis, sizeof(pri->pvts[chanpos]->rdnis), pri,
11338                           e->ring.redirectingnum, e->ring.callingplanrdnis);
11339                /* If immediate=yes go to s|1 */
11340                if (pri->pvts[chanpos]->immediate) {
11341                   ast_verb(3, "Going to extension s|1 because of immediate=yes\n");
11342                   pri->pvts[chanpos]->exten[0] = 's';
11343                   pri->pvts[chanpos]->exten[1] = '\0';
11344                }
11345                /* Get called number */
11346                else if (!ast_strlen_zero(e->ring.callednum)) {
11347                   ast_copy_string(pri->pvts[chanpos]->exten, e->ring.callednum, sizeof(pri->pvts[chanpos]->exten));
11348                   ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
11349                } else if (pri->overlapdial)
11350                   pri->pvts[chanpos]->exten[0] = '\0';
11351                else {
11352                   /* Some PRI circuits are set up to send _no_ digits.  Handle them as 's'. */
11353                   pri->pvts[chanpos]->exten[0] = 's';
11354                   pri->pvts[chanpos]->exten[1] = '\0';
11355                }
11356                /* Set DNID on all incoming calls -- even immediate */
11357                if (!ast_strlen_zero(e->ring.callednum))
11358                   ast_copy_string(pri->pvts[chanpos]->dnid, e->ring.callednum, sizeof(pri->pvts[chanpos]->dnid));
11359                /* No number yet, but received "sending complete"? */
11360                if (e->ring.complete && (ast_strlen_zero(e->ring.callednum))) {
11361                   ast_verb(3, "Going to extension s|1 because of Complete received\n");
11362                   pri->pvts[chanpos]->exten[0] = 's';
11363                   pri->pvts[chanpos]->exten[1] = '\0';
11364                }
11365 
11366                /* Make sure extension exists (or in overlap dial mode, can exist) */
11367                if (((pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING) && ast_canmatch_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) ||
11368                   ast_exists_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
11369                   /* Setup law */
11370                   int law;
11371                   if (pri->switchtype != PRI_SWITCH_GR303_TMC) {
11372                      /* Set to audio mode at this point */
11373                      law = 1;
11374                      if (ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_AUDIOMODE, &law) == -1)
11375                         ast_log(LOG_WARNING, "Unable to set audio mode on channel %d to %d: %s\n", pri->pvts[chanpos]->channel, law, strerror(errno));
11376                   }
11377                   if (e->ring.layer1 == PRI_LAYER_1_ALAW)
11378                      law = DAHDI_LAW_ALAW;
11379                   else
11380                      law = DAHDI_LAW_MULAW;
11381                   res = dahdi_setlaw(pri->pvts[chanpos]->subs[SUB_REAL].dfd, law);
11382                   if (res < 0) 
11383                      ast_log(LOG_WARNING, "Unable to set law on channel %d\n", pri->pvts[chanpos]->channel);
11384                   res = set_actual_gain(pri->pvts[chanpos]->subs[SUB_REAL].dfd, 0, pri->pvts[chanpos]->rxgain, pri->pvts[chanpos]->txgain, law);
11385                   if (res < 0)
11386                      ast_log(LOG_WARNING, "Unable to set gains on channel %d\n", pri->pvts[chanpos]->channel);
11387                   if (e->ring.complete || !(pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)) {
11388                      /* Just announce proceeding */
11389                      pri->pvts[chanpos]->proceeding = 1;
11390                      pri_proceeding(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 0);
11391                   } else {
11392                      if (pri->switchtype != PRI_SWITCH_GR303_TMC) 
11393                         pri_need_more_info(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
11394                      else
11395                         pri_answer(pri->pri, e->ring.call, PVT_TO_CHANNEL(pri->pvts[chanpos]), 1);
11396                   }
11397                   /* Get the use_callingpres state */
11398                   pri->pvts[chanpos]->callingpres = e->ring.callingpres;
11399                
11400                   /* Start PBX */
11401                   if (!e->ring.complete
11402                      && (pri->overlapdial & DAHDI_OVERLAPDIAL_INCOMING)
11403                      && ast_matchmore_extension(NULL, pri->pvts[chanpos]->context, pri->pvts[chanpos]->exten, 1, pri->pvts[chanpos]->cid_num)) {
11404                      /*
11405                       * Release the PRI lock while we create the channel
11406                       * so other threads can send D channel messages.
11407                       */
11408                      ast_mutex_unlock(&pri->lock);
11409                      if (crv) {
11410                         /* Set bearer and such */
11411                         pri_assign_bearer(crv, pri, pri->pvts[chanpos]);
11412                         c = dahdi_new(crv, AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
11413                         pri->pvts[chanpos]->owner = &inuse;
11414                         ast_debug(1, "Started up crv %d:%d on bearer channel %d\n", pri->trunkgroup, crv->channel, crv->bearer->channel);
11415                      } else {
11416                         c = dahdi_new(pri->pvts[chanpos], AST_STATE_RESERVED, 0, SUB_REAL, law, e->ring.ctype);
11417                      }
11418                      ast_mutex_lock(&pri->lock);
11419                      if (c) {
11420                         if (!ast_strlen_zero(e->ring.callingsubaddr)) {
11421                            pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
11422                         }
11423                         if (e->ring.ani2 >= 0) {
11424                            snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
11425                            pbx_builtin_setvar_helper(c, "ANI2", ani2str);
11426                            pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
11427                         }
11428 
11429 #ifdef SUPPORT_USERUSER
11430                         if (!ast_strlen_zero(e->ring.useruserinfo)) {
11431                            pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
11432                         }
11433 #endif
11434 
11435                         snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
11436                         pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
11437                         if (e->ring.redirectingreason >= 0)
11438                            pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
11439                      }
11440                      if (c && !ast_pthread_create_detached(&threadid, NULL, ss_thread, c)) {
11441                         ast_verb(3, "Accepting overlap call from '%s' to '%s' on channel %d/%d, span %d\n",
11442                            plancallingnum, S_OR(pri->pvts[chanpos]->exten, "<unspecified>"),
11443                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
11444                      } else {
11445                         ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
11446                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
11447                         if (c)
11448                            ast_hangup(c);
11449                         else {
11450                            pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
11451                            pri->pvts[chanpos]->call = NULL;
11452                         }
11453                      }
11454                   } else {
11455                      /*
11456                       * Release the PRI lock while we create the channel
11457                       * so other threads can send D channel messages.
11458                       */
11459                      ast_mutex_unlock(&pri->lock);
11460                      c = dahdi_new(pri->pvts[chanpos], AST_STATE_RING, 0, SUB_REAL, law, e->ring.ctype);
11461                      ast_mutex_lock(&pri->lock);
11462                      if (c) {
11463                         /*
11464                          * It is reasonably safe to set the following
11465                          * channel variables while the PRI and DAHDI private
11466                          * structures are locked.  The PBX has not been
11467                          * started yet and it is unlikely that any other task
11468                          * will do anything with the channel we have just
11469                          * created.
11470                          */
11471                         if (!ast_strlen_zero(e->ring.callingsubaddr)) {
11472                            pbx_builtin_setvar_helper(c, "CALLINGSUBADDR", e->ring.callingsubaddr);
11473                         }
11474                         if (e->ring.ani2 >= 0) {
11475                            snprintf(ani2str, sizeof(ani2str), "%d", e->ring.ani2);
11476                            pbx_builtin_setvar_helper(c, "ANI2", ani2str);
11477                            pri->pvts[chanpos]->cid_ani2 = e->ring.ani2;
11478                         }
11479 
11480 #ifdef SUPPORT_USERUSER
11481                         if (!ast_strlen_zero(e->ring.useruserinfo)) {
11482                            pbx_builtin_setvar_helper(c, "USERUSERINFO", e->ring.useruserinfo);
11483                         }
11484 #endif
11485 
11486                         if (e->ring.redirectingreason >= 0)
11487                            pbx_builtin_setvar_helper(c, "PRIREDIRECTREASON", redirectingreason2str(e->ring.redirectingreason));
11488 
11489                         snprintf(calledtonstr, sizeof(calledtonstr), "%d", e->ring.calledplan);
11490                         pbx_builtin_setvar_helper(c, "CALLEDTON", calledtonstr);
11491                      }
11492                      if (c && !ast_pbx_start(c)) {
11493                         ast_verb(3, "Accepting call from '%s' to '%s' on channel %d/%d, span %d\n",
11494                            plancallingnum, pri->pvts[chanpos]->exten,
11495                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
11496 
11497                         dahdi_enable_ec(pri->pvts[chanpos]);
11498                      } else {
11499                         ast_log(LOG_WARNING, "Unable to start PBX on channel %d/%d, span %d\n",
11500                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span);
11501                         if (c) {
11502                            ast_hangup(c);
11503                         } else {
11504                            pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_SWITCH_CONGESTION);
11505                            pri->pvts[chanpos]->call = NULL;
11506                         }
11507                      }
11508                   }
11509                } else {
11510                   ast_verb(3, "Extension '%s' in context '%s' from '%s' does not exist.  Rejecting call on channel %d/%d, span %d\n",
11511                      pri->pvts[chanpos]->exten, pri->pvts[chanpos]->context, pri->pvts[chanpos]->cid_num, pri->pvts[chanpos]->logicalspan,
11512                      pri->pvts[chanpos]->prioffset, pri->span);
11513                   pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_UNALLOCATED);
11514                   pri->pvts[chanpos]->call = NULL;
11515                   pri->pvts[chanpos]->exten[0] = '\0';
11516                }
11517                if (crv)
11518                   ast_mutex_unlock(&crv->lock);
11519                ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11520             } else {
11521                if (e->ring.flexible)
11522                   pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION);
11523                else
11524                   pri_hangup(pri->pri, e->ring.call, PRI_CAUSE_REQUESTED_CHAN_UNAVAIL);
11525             }
11526             break;
11527          case PRI_EVENT_RINGING:
11528             chanpos = pri_find_principle(pri, e->ringing.channel);
11529             if (chanpos < 0) {
11530                ast_log(LOG_WARNING, "Ringing requested on unconfigured channel %d/%d span %d\n", 
11531                   PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
11532             } else {
11533                chanpos = pri_fixup_principle(pri, chanpos, e->ringing.call);
11534                if (chanpos < 0) {
11535                   ast_log(LOG_WARNING, "Ringing requested on channel %d/%d not in use on span %d\n", 
11536                      PRI_SPAN(e->ringing.channel), PRI_CHANNEL(e->ringing.channel), pri->span);
11537                } else {
11538                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11539                   if (ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) {
11540                      dahdi_enable_ec(pri->pvts[chanpos]);
11541                      pri->pvts[chanpos]->subs[SUB_REAL].needringing = 1;
11542                      pri->pvts[chanpos]->alerting = 1;
11543                   } else
11544                      ast_debug(1, "Deferring ringing notification because of extra digits to dial...\n");
11545 
11546 #ifdef PRI_PROGRESS_MASK
11547                   if (e->ringing.progressmask & PRI_PROG_INBAND_AVAILABLE) {
11548 #else
11549                   if (e->ringing.progress == 8) {
11550 #endif
11551                      /* Now we can do call progress detection */
11552                      if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11553                         /* RINGING detection isn't required because we got ALERTING signal */
11554                         ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features & ~DSP_PROGRESS_RINGING);
11555                         pri->pvts[chanpos]->dsp_features = 0;
11556                      }
11557                   }
11558 
11559 #ifdef SUPPORT_USERUSER
11560                   if (!ast_strlen_zero(e->ringing.useruserinfo)) {
11561                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11562                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11563                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->ringing.useruserinfo);
11564                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11565                   }
11566 #endif
11567 
11568                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11569                }
11570             }
11571             break;
11572          case PRI_EVENT_PROGRESS:
11573             /* Get chan value if e->e is not PRI_EVNT_RINGING */
11574             chanpos = pri_find_principle(pri, e->proceeding.channel);
11575             if (chanpos > -1) {
11576 #ifdef PRI_PROGRESS_MASK
11577                if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE)) {
11578 #else
11579                if ((!pri->pvts[chanpos]->progress) || (e->proceeding.progress == 8)) {
11580 #endif
11581                   struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROGRESS, };
11582 
11583                   if (e->proceeding.cause > -1) {
11584                      ast_verb(3, "PROGRESS with cause code %d received\n", e->proceeding.cause);
11585 
11586                      /* Work around broken, out of spec USER_BUSY cause in a progress message */
11587                      if (e->proceeding.cause == AST_CAUSE_USER_BUSY) {
11588                         if (pri->pvts[chanpos]->owner) {
11589                            ast_verb(3, "PROGRESS with 'user busy' received, signalling AST_CONTROL_BUSY instead of AST_CONTROL_PROGRESS\n");
11590 
11591                            pri->pvts[chanpos]->owner->hangupcause = e->proceeding.cause;
11592                            f.subclass = AST_CONTROL_BUSY;
11593                         }
11594                      }
11595                   }
11596                   
11597                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11598                   ast_debug(1, "Queuing frame from PRI_EVENT_PROGRESS on channel %d/%d span %d\n",
11599                      pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
11600                   dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11601 #ifdef PRI_PROGRESS_MASK
11602                   if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
11603 #else
11604                   if (e->proceeding.progress == 8) {
11605 #endif
11606                      /* Now we can do call progress detection */
11607                      if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11608                         ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
11609                         pri->pvts[chanpos]->dsp_features = 0;
11610                      }
11611                      /* Bring voice path up */
11612                      f.subclass = AST_CONTROL_PROGRESS;
11613                      dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11614                   }
11615                   pri->pvts[chanpos]->progress = 1;
11616                   pri->pvts[chanpos]->dialing = 0;
11617                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11618                }
11619             }
11620             break;
11621          case PRI_EVENT_PROCEEDING:
11622             chanpos = pri_find_principle(pri, e->proceeding.channel);
11623             if (chanpos > -1) {
11624                if (!pri->pvts[chanpos]->proceeding) {
11625                   struct ast_frame f = { AST_FRAME_CONTROL, AST_CONTROL_PROCEEDING, };
11626                   
11627                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11628                   ast_debug(1, "Queuing frame from PRI_EVENT_PROCEEDING on channel %d/%d span %d\n",
11629                      pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset,pri->span);
11630                   dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11631 #ifdef PRI_PROGRESS_MASK
11632                   if (e->proceeding.progressmask & PRI_PROG_INBAND_AVAILABLE) {
11633 #else
11634                   if (e->proceeding.progress == 8) {
11635 #endif
11636                      /* Now we can do call progress detection */
11637                      if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11638                         ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
11639                         pri->pvts[chanpos]->dsp_features = 0;
11640                      }
11641                      /* Bring voice path up */
11642                      f.subclass = AST_CONTROL_PROGRESS;
11643                      dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11644                   }
11645                   pri->pvts[chanpos]->proceeding = 1;
11646                   pri->pvts[chanpos]->dialing = 0;
11647                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11648                }
11649             }
11650             break;
11651          case PRI_EVENT_FACNAME:
11652             chanpos = pri_find_principle(pri, e->facname.channel);
11653             if (chanpos < 0) {
11654                ast_log(LOG_WARNING, "Facility Name requested on unconfigured channel %d/%d span %d\n", 
11655                   PRI_SPAN(e->facname.channel), PRI_CHANNEL(e->facname.channel), pri->span);
11656             } else {
11657                chanpos = pri_fixup_principle(pri, chanpos, e->facname.call);
11658                if (chanpos < 0) {
11659                   ast_log(LOG_WARNING, "Facility Name requested on channel %d/%d not in use on span %d\n", 
11660                      PRI_SPAN(e->facname.channel), PRI_CHANNEL(e->facname.channel), pri->span);
11661                } else {
11662                   /* Re-use *69 field for PRI */
11663                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11664                   ast_copy_string(pri->pvts[chanpos]->lastcid_num, e->facname.callingnum, sizeof(pri->pvts[chanpos]->lastcid_num));
11665                   ast_copy_string(pri->pvts[chanpos]->lastcid_name, e->facname.callingname, sizeof(pri->pvts[chanpos]->lastcid_name));
11666                   pri->pvts[chanpos]->subs[SUB_REAL].needcallerid =1;
11667                   dahdi_enable_ec(pri->pvts[chanpos]);
11668                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11669                }
11670             }
11671             break;            
11672          case PRI_EVENT_ANSWER:
11673             chanpos = pri_find_principle(pri, e->answer.channel);
11674             if (chanpos < 0) {
11675                ast_log(LOG_WARNING, "Answer on unconfigured channel %d/%d span %d\n", 
11676                   PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
11677             } else {
11678                chanpos = pri_fixup_principle(pri, chanpos, e->answer.call);
11679                if (chanpos < 0) {
11680                   ast_log(LOG_WARNING, "Answer requested on channel %d/%d not in use on span %d\n", 
11681                      PRI_SPAN(e->answer.channel), PRI_CHANNEL(e->answer.channel), pri->span);
11682                } else {
11683                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11684                   /* Now we can do call progress detection */
11685 
11686                   /* We changed this so it turns on the DSP no matter what... progress or no progress.
11687                    * By this time, we need DTMF detection and other features that were previously disabled
11688                    * -- Matt F */
11689                   if (pri->pvts[chanpos]->dsp && pri->pvts[chanpos]->dsp_features) {
11690                      ast_dsp_set_features(pri->pvts[chanpos]->dsp, pri->pvts[chanpos]->dsp_features);
11691                      pri->pvts[chanpos]->dsp_features = 0;
11692                   }
11693                   if (pri->pvts[chanpos]->realcall && (pri->pvts[chanpos]->realcall->sig == SIG_FXSKS)) {
11694                      ast_debug(1, "Starting up GR-303 trunk now that we got CONNECT...\n");
11695                      x = DAHDI_START;
11696                      res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_HOOK, &x);
11697                      if (res < 0) {
11698                         if (errno != EINPROGRESS) {
11699                            ast_log(LOG_WARNING, "Unable to start channel: %s\n", strerror(errno));
11700                         }
11701                      }
11702                   } else if (!ast_strlen_zero(pri->pvts[chanpos]->dop.dialstr)) {
11703                      pri->pvts[chanpos]->dialing = 1;
11704                      /* Send any "w" waited stuff */
11705                      res = ioctl(pri->pvts[chanpos]->subs[SUB_REAL].dfd, DAHDI_DIAL, &pri->pvts[chanpos]->dop);
11706                      if (res < 0) {
11707                         ast_log(LOG_WARNING, "Unable to initiate dialing on trunk channel %d: %s\n", pri->pvts[chanpos]->channel, strerror(errno));
11708                         pri->pvts[chanpos]->dop.dialstr[0] = '\0';
11709                      } else
11710                         ast_debug(1, "Sent deferred digit string: %s\n", pri->pvts[chanpos]->dop.dialstr);
11711 
11712                      pri->pvts[chanpos]->dop.dialstr[0] = '\0';
11713                   } else if (pri->pvts[chanpos]->confirmanswer) {
11714                      ast_debug(1, "Waiting on answer confirmation on channel %d!\n", pri->pvts[chanpos]->channel);
11715                   } else {
11716                      pri->pvts[chanpos]->dialing = 0;
11717                      pri->pvts[chanpos]->subs[SUB_REAL].needanswer =1;
11718                      /* Enable echo cancellation if it's not on already */
11719                      dahdi_enable_ec(pri->pvts[chanpos]);
11720                   }
11721 
11722 #ifdef SUPPORT_USERUSER
11723                   if (!ast_strlen_zero(e->answer.useruserinfo)) {
11724                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11725                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11726                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->answer.useruserinfo);
11727                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11728                   }
11729 #endif
11730 
11731                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11732                }
11733             }
11734             break;            
11735          case PRI_EVENT_HANGUP:
11736             chanpos = pri_find_principle(pri, e->hangup.channel);
11737             if (chanpos < 0) {
11738                ast_log(LOG_WARNING, "Hangup requested on unconfigured channel %d/%d span %d\n", 
11739                   PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11740             } else {
11741                chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
11742                if (chanpos > -1) {
11743                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11744                   if (!pri->pvts[chanpos]->alreadyhungup) {
11745                      /* we're calling here dahdi_hangup so once we get there we need to clear p->call after calling pri_hangup */
11746                      pri->pvts[chanpos]->alreadyhungup = 1;
11747                      if (pri->pvts[chanpos]->realcall) 
11748                         pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11749                      else if (pri->pvts[chanpos]->owner) {
11750                         /* Queue a BUSY instead of a hangup if our cause is appropriate */
11751                         pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
11752                         switch (pri->pvts[chanpos]->owner->_state) {
11753                         case AST_STATE_BUSY:
11754                         case AST_STATE_UP:
11755                            pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11756                            break;
11757                         default:
11758                            switch (e->hangup.cause) {
11759                            case PRI_CAUSE_USER_BUSY:
11760                               pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
11761                               break;
11762                            case PRI_CAUSE_CALL_REJECTED:
11763                            case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
11764                            case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
11765                            case PRI_CAUSE_SWITCH_CONGESTION:
11766                            case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
11767                            case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
11768                               pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
11769                               break;
11770                            default:
11771                               pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11772                            }
11773                            break;
11774                         }
11775                      }
11776                      ast_verb(3, "Channel %d/%d, span %d got hangup, cause %d\n",
11777                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, e->hangup.cause);
11778                   } else {
11779                      pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
11780                      pri->pvts[chanpos]->call = NULL;
11781                   }
11782                   if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
11783                      ast_verb(3, "Forcing restart of channel %d/%d on span %d since channel reported in use\n",
11784                            PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11785                      pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
11786                      pri->pvts[chanpos]->resetting = 1;
11787                   }
11788                   if (e->hangup.aoc_units > -1)
11789                      ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
11790                            pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
11791 
11792 #ifdef SUPPORT_USERUSER
11793                   if (pri->pvts[chanpos]->owner && !ast_strlen_zero(e->hangup.useruserinfo)) {
11794                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11795                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11796                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
11797                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11798                   }
11799 #endif
11800 
11801                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11802                } else {
11803                   ast_log(LOG_WARNING, "Hangup on bad channel %d/%d on span %d\n", 
11804                      PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11805                }
11806             } 
11807             break;
11808 #ifndef PRI_EVENT_HANGUP_REQ
11809 #error please update libpri
11810 #endif
11811          case PRI_EVENT_HANGUP_REQ:
11812             chanpos = pri_find_principle(pri, e->hangup.channel);
11813             if (chanpos < 0) {
11814                ast_log(LOG_WARNING, "Hangup REQ requested on unconfigured channel %d/%d span %d\n", 
11815                   PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11816             } else {
11817                chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
11818                if (chanpos > -1) {
11819                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11820                   if (pri->pvts[chanpos]->realcall) 
11821                      pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11822                   else if (pri->pvts[chanpos]->owner) {
11823                      pri->pvts[chanpos]->owner->hangupcause = e->hangup.cause;
11824                      switch (pri->pvts[chanpos]->owner->_state) {
11825                      case AST_STATE_BUSY:
11826                      case AST_STATE_UP:
11827                         pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11828                         break;
11829                      default:
11830                         switch (e->hangup.cause) {
11831                            case PRI_CAUSE_USER_BUSY:
11832                               pri->pvts[chanpos]->subs[SUB_REAL].needbusy =1;
11833                               break;
11834                            case PRI_CAUSE_CALL_REJECTED:
11835                            case PRI_CAUSE_NETWORK_OUT_OF_ORDER:
11836                            case PRI_CAUSE_NORMAL_CIRCUIT_CONGESTION:
11837                            case PRI_CAUSE_SWITCH_CONGESTION:
11838                            case PRI_CAUSE_DESTINATION_OUT_OF_ORDER:
11839                            case PRI_CAUSE_NORMAL_TEMPORARY_FAILURE:
11840                               pri->pvts[chanpos]->subs[SUB_REAL].needcongestion =1;
11841                               break;
11842                            default:
11843                               pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11844                         }
11845                         break;
11846                      }
11847                      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);
11848                      if (e->hangup.aoc_units > -1)
11849                         ast_verb(3, "Channel %d/%d, span %d received AOC-E charging %d unit%s\n",
11850                               pri->pvts[chanpos]->logicalspan, pri->pvts[chanpos]->prioffset, pri->span, (int)e->hangup.aoc_units, (e->hangup.aoc_units == 1) ? "" : "s");
11851                   } else {
11852                      pri_hangup(pri->pri, pri->pvts[chanpos]->call, e->hangup.cause);
11853                      pri->pvts[chanpos]->call = NULL;
11854                   }
11855                   if (e->hangup.cause == PRI_CAUSE_REQUESTED_CHAN_UNAVAIL) {
11856                      ast_verb(3, "Forcing restart of channel %d/%d span %d since channel reported in use\n",
11857                            PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11858                      pri_reset(pri->pri, PVT_TO_CHANNEL(pri->pvts[chanpos]));
11859                      pri->pvts[chanpos]->resetting = 1;
11860                   }
11861 
11862 #ifdef SUPPORT_USERUSER
11863                   if (!ast_strlen_zero(e->hangup.useruserinfo)) {
11864                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11865                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11866                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
11867                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11868                   }
11869 #endif
11870 
11871                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11872                } else {
11873                   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);
11874                }
11875             } 
11876             break;
11877          case PRI_EVENT_HANGUP_ACK:
11878             chanpos = pri_find_principle(pri, e->hangup.channel);
11879             if (chanpos < 0) {
11880                ast_log(LOG_WARNING, "Hangup ACK requested on unconfigured channel number %d/%d span %d\n", 
11881                   PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11882             } else {
11883                chanpos = pri_fixup_principle(pri, chanpos, e->hangup.call);
11884                if (chanpos > -1) {
11885                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11886                   pri->pvts[chanpos]->call = NULL;
11887                   pri->pvts[chanpos]->resetting = 0;
11888                   if (pri->pvts[chanpos]->owner) {
11889                      ast_verb(3, "Channel %d/%d, span %d got hangup ACK\n", PRI_SPAN(e->hangup.channel), PRI_CHANNEL(e->hangup.channel), pri->span);
11890                   }
11891 
11892 #ifdef SUPPORT_USERUSER
11893                   if (!ast_strlen_zero(e->hangup.useruserinfo)) {
11894                      struct ast_channel *owner = pri->pvts[chanpos]->owner;
11895                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11896                      pbx_builtin_setvar_helper(owner, "USERUSERINFO", e->hangup.useruserinfo);
11897                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11898                   }
11899 #endif
11900 
11901                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11902                }
11903             }
11904             break;
11905          case PRI_EVENT_CONFIG_ERR:
11906             ast_log(LOG_WARNING, "PRI Error on span %d: %s\n", pri->trunkgroup, e->err.err);
11907             break;
11908          case PRI_EVENT_RESTART_ACK:
11909             chanpos = pri_find_principle(pri, e->restartack.channel);
11910             if (chanpos < 0) {
11911                /* Sometime switches (e.g. I421 / British Telecom) don't give us the
11912                   channel number, so we have to figure it out...  This must be why
11913                   everybody resets exactly a channel at a time. */
11914                for (x = 0; x < pri->numchans; x++) {
11915                   if (pri->pvts[x] && pri->pvts[x]->resetting) {
11916                      chanpos = x;
11917                      ast_mutex_lock(&pri->pvts[chanpos]->lock);
11918                      ast_debug(1, "Assuming restart ack is really for channel %d/%d span %d\n", pri->pvts[chanpos]->logicalspan, 
11919                         pri->pvts[chanpos]->prioffset, pri->span);
11920                      if (pri->pvts[chanpos]->realcall) 
11921                         pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11922                      else if (pri->pvts[chanpos]->owner) {
11923                         ast_log(LOG_WARNING, "Got restart ack on channel %d/%d with owner on span %d\n", pri->pvts[chanpos]->logicalspan, 
11924                            pri->pvts[chanpos]->prioffset, pri->span);
11925                         pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11926                      }
11927                      pri->pvts[chanpos]->resetting = 0;
11928                      ast_verb(3, "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
11929                            pri->pvts[chanpos]->prioffset, pri->span);
11930                      ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11931                      if (pri->resetting)
11932                         pri_check_restart(pri);
11933                      break;
11934                   }
11935                }
11936                if (chanpos < 0) {
11937                   ast_log(LOG_WARNING, "Restart ACK requested on strange channel %d/%d span %d\n", 
11938                      PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
11939                }
11940             } else {
11941                if (pri->pvts[chanpos]) {
11942                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11943                   if (pri->pvts[chanpos]->realcall) 
11944                      pri_hangup_all(pri->pvts[chanpos]->realcall, pri);
11945                   else if (pri->pvts[chanpos]->owner) {
11946                      ast_log(LOG_WARNING, "Got restart ack on channel %d/%d span %d with owner\n",
11947                         PRI_SPAN(e->restartack.channel), PRI_CHANNEL(e->restartack.channel), pri->span);
11948                      pri->pvts[chanpos]->owner->_softhangup |= AST_SOFTHANGUP_DEV;
11949                   }
11950                   pri->pvts[chanpos]->resetting = 0;
11951                   pri->pvts[chanpos]->inservice = 1;
11952                   ast_verb(3, "B-channel %d/%d successfully restarted on span %d\n", pri->pvts[chanpos]->logicalspan,
11953                            pri->pvts[chanpos]->prioffset, pri->span);
11954                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11955                   if (pri->resetting)
11956                      pri_check_restart(pri);
11957                }
11958             }
11959             break;
11960          case PRI_EVENT_SETUP_ACK:
11961             chanpos = pri_find_principle(pri, e->setup_ack.channel);
11962             if (chanpos < 0) {
11963                ast_log(LOG_WARNING, "Received SETUP_ACKNOWLEDGE on unconfigured channel %d/%d span %d\n", 
11964                   PRI_SPAN(e->setup_ack.channel), PRI_CHANNEL(e->setup_ack.channel), pri->span);
11965             } else {
11966                chanpos = pri_fixup_principle(pri, chanpos, e->setup_ack.call);
11967                if (chanpos > -1) {
11968                   ast_mutex_lock(&pri->pvts[chanpos]->lock);
11969                   pri->pvts[chanpos]->setup_ack = 1;
11970                   /* Send any queued digits */
11971                   for (x = 0;x < strlen(pri->pvts[chanpos]->dialdest); x++) {
11972                      ast_debug(1, "Sending pending digit '%c'\n", pri->pvts[chanpos]->dialdest[x]);
11973                      pri_information(pri->pri, pri->pvts[chanpos]->call, 
11974                         pri->pvts[chanpos]->dialdest[x]);
11975                   }
11976                   ast_mutex_unlock(&pri->pvts[chanpos]->lock);
11977                } else
11978                   ast_log(LOG_WARNING, "Unable to move channel %d!\n", e->setup_ack.channel);
11979             }
11980             break;
11981          case PRI_EVENT_NOTIFY:
11982             chanpos = pri_find_principle(pri, e->notify.channel);
11983             if (chanpos < 0) {
11984                ast_log(LOG_WARNING, "Received NOTIFY on unconfigured channel %d/%d span %d\n",
11985                   PRI_SPAN(e->notify.channel), PRI_CHANNEL(e->notify.channel), pri->span);
11986             } else {
11987                struct ast_frame f = { AST_FRAME_CONTROL, };
11988                ast_mutex_lock(&pri->pvts[chanpos]->lock);
11989                switch (e->notify.info) {
11990                case PRI_NOTIFY_REMOTE_HOLD:
11991                   f.subclass = AST_CONTROL_HOLD;
11992                   dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11993                   break;
11994                case PRI_NOTIFY_REMOTE_RETRIEVAL:
11995                   f.subclass = AST_CONTROL_UNHOLD;
11996                   dahdi_queue_frame(pri->pvts[chanpos], &f, pri);
11997                   break;
11998                }
11999                ast_mutex_unlock(&pri->pvts[chanpos]->lock);
12000             }
12001             break;
12002          default:
12003             ast_debug(1, "Event: %d\n", e->e);
12004          }
12005       }  
12006       ast_mutex_unlock(&pri->lock);
12007    }
12008    /* Never reached */
12009    return NULL;
12010 }
12011 
12012 static int start_pri(struct dahdi_pri *pri)
12013 {
12014    int res, x;
12015    struct dahdi_params p;
12016    struct dahdi_bufferinfo bi;
12017    struct dahdi_spaninfo si;
12018    int i;
12019    
12020    for (i = 0; i < NUM_DCHANS; i++) {
12021       if (!pri->dchannels[i])
12022          break;
12023       pri->fds[i] = open("/dev/dahdi/channel", O_RDWR);
12024       x = pri->dchannels[i];
12025       if ((pri->fds[i] < 0) || (ioctl(pri->fds[i],DAHDI_SPECIFY,&x) == -1)) {
12026          ast_log(LOG_ERROR, "Unable to open D-channel %d (%s)\n", x, strerror(errno));
12027          return -1;
12028       }
12029       memset(&p, 0, sizeof(p));
12030       res = ioctl(pri->fds[i], DAHDI_GET_PARAMS, &p);
12031       if (res) {
12032          dahdi_close_pri_fd(pri, i);
12033          ast_log(LOG_ERROR, "Unable to get parameters for D-channel %d (%s)\n", x, strerror(errno));
12034          return -1;
12035       }
12036       if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC)) {
12037          dahdi_close_pri_fd(pri, i);
12038          ast_log(LOG_ERROR, "D-channel %d is not in HDLC/FCS mode.\n", x);
12039          return -1;
12040       }
12041       memset(&si, 0, sizeof(si));
12042       res = ioctl(pri->fds[i], DAHDI_SPANSTAT, &si);
12043       if (res) {
12044          dahdi_close_pri_fd(pri, i);
12045          ast_log(LOG_ERROR, "Unable to get span state for D-channel %d (%s)\n", x, strerror(errno));
12046       }
12047       if (!si.alarms)
12048          pri->dchanavail[i] |= DCHAN_NOTINALARM;
12049       else
12050          pri->dchanavail[i] &= ~DCHAN_NOTINALARM;
12051       memset(&bi, 0, sizeof(bi));
12052       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
12053       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
12054       bi.numbufs = 32;
12055       bi.bufsize = 1024;
12056       if (ioctl(pri->fds[i], DAHDI_SET_BUFINFO, &bi)) {
12057          ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", x, strerror(errno));
12058          dahdi_close_pri_fd(pri, i);
12059          return -1;
12060       }
12061       switch (pri->sig) {
12062          case SIG_BRI:
12063             pri->dchans[i] = pri_new_bri(pri->fds[i], 1, pri->nodetype, pri->switchtype);
12064             break;
12065          case SIG_BRI_PTMP:
12066             pri->dchans[i] = pri_new_bri(pri->fds[i], 0, pri->nodetype, pri->switchtype);
12067             break;
12068          default:
12069             pri->dchans[i] = pri_new(pri->fds[i], pri->nodetype, pri->switchtype);
12070       }
12071       /* Force overlap dial if we're doing GR-303! */
12072       if (pri->switchtype == PRI_SWITCH_GR303_TMC)
12073          pri->overlapdial |= DAHDI_OVERLAPDIAL_BOTH;
12074       pri_set_overlapdial(pri->dchans[i],(pri->overlapdial & DAHDI_OVERLAPDIAL_OUTGOING)?1:0);
12075 #ifdef HAVE_PRI_INBANDDISCONNECT
12076       pri_set_inbanddisconnect(pri->dchans[i], pri->inbanddisconnect);
12077 #endif
12078       /* Enslave to master if appropriate */
12079       if (i)
12080          pri_enslave(pri->dchans[0], pri->dchans[i]);
12081       if (!pri->dchans[i]) {
12082          dahdi_close_pri_fd(pri, i);
12083          ast_log(LOG_ERROR, "Unable to create PRI structure\n");
12084          return -1;
12085       }
12086       pri_set_debug(pri->dchans[i], DEFAULT_PRI_DEBUG);
12087       pri_set_nsf(pri->dchans[i], pri->nsf);
12088 #ifdef PRI_GETSET_TIMERS
12089       for (x = 0; x < PRI_MAX_TIMERS; x++) {
12090          if (pritimers[x] != 0)
12091             pri_set_timer(pri->dchans[i], x, pritimers[x]);
12092       }
12093 #endif
12094    }
12095    /* Assume primary is the one we use */
12096    pri->pri = pri->dchans[0];
12097    pri->resetpos = -1;
12098    if (ast_pthread_create_background(&pri->master, NULL, pri_dchannel, pri)) {
12099       for (i = 0; i < NUM_DCHANS; i++) {
12100          if (!pri->dchannels[i])
12101             break;
12102          dahdi_close_pri_fd(pri, i);
12103       }
12104       ast_log(LOG_ERROR, "Unable to spawn D-channel: %s\n", strerror(errno));
12105       return -1;
12106    }
12107    return 0;
12108 }
12109 
12110 static char *complete_span_helper(const char *line, const char *word, int pos, int state, int rpos)
12111 {
12112    int which, span;
12113    char *ret = NULL;
12114 
12115    if (pos != rpos)
12116       return ret;
12117 
12118    for (which = span = 0; span < NUM_SPANS; span++) {
12119       if (pris[span].pri && ++which > state) {
12120          if (asprintf(&ret, "%d", span + 1) < 0) { /* user indexes start from 1 */
12121             ast_log(LOG_WARNING, "asprintf() failed: %s\n", strerror(errno));
12122          }
12123          break;
12124       }
12125    }
12126    return ret;
12127 }
12128 
12129 static char *complete_span_4(const char *line, const char *word, int pos, int state)
12130 {
12131    return complete_span_helper(line,word,pos,state,3);
12132 }
12133 
12134 static char *complete_span_5(const char *line, const char *word, int pos, int state)
12135 {
12136    return complete_span_helper(line,word,pos,state,4);
12137 }
12138 
12139 static char *handle_pri_unset_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12140 {
12141    switch (cmd) {
12142    case CLI_INIT:
12143       e->command = "pri unset debug file";
12144       e->usage = "Usage: pri unset debug file\n"
12145             "       Stop sending debug output to the previously \n"
12146                  "       specified file\n";
12147       return NULL;
12148    case CLI_GENERATE:
12149       return NULL;   
12150    }
12151    /* Assume it is unset */
12152    ast_mutex_lock(&pridebugfdlock);
12153    close(pridebugfd);
12154    pridebugfd = -1;
12155    ast_cli(a->fd, "PRI debug output to file disabled\n");
12156    ast_mutex_unlock(&pridebugfdlock);
12157    return CLI_SUCCESS;
12158 }
12159 
12160 static char *handle_pri_set_debug_file(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12161 {
12162    int myfd;
12163    switch (cmd) {
12164    case CLI_INIT:
12165       e->command = "pri set debug file";
12166       e->usage = "Usage: pri set debug file [output-file]\n"
12167             "       Sends PRI debug output to the specified output file\n";
12168       return NULL;
12169    case CLI_GENERATE:
12170       return NULL;   
12171    }
12172    if (a->argc < 5)
12173       return CLI_SHOWUSAGE;
12174 
12175    if (ast_strlen_zero(a->argv[4]))
12176       return CLI_SHOWUSAGE;
12177 
12178    myfd = open(a->argv[4], O_CREAT|O_WRONLY, AST_FILE_MODE);
12179    if (myfd < 0) {
12180       ast_cli(a->fd, "Unable to open '%s' for writing\n", a->argv[4]);
12181       return CLI_SUCCESS;
12182    }
12183 
12184    ast_mutex_lock(&pridebugfdlock);
12185 
12186    if (pridebugfd >= 0)
12187       close(pridebugfd);
12188 
12189    pridebugfd = myfd;
12190    ast_copy_string(pridebugfilename,a->argv[4],sizeof(pridebugfilename));
12191    ast_mutex_unlock(&pridebugfdlock);
12192    ast_cli(a->fd, "PRI debug output will be sent to '%s'\n", a->argv[4]);
12193    return CLI_SUCCESS;
12194 }
12195 
12196 static char *handle_pri_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12197 {
12198    int span;
12199    int x;
12200    switch (cmd) {
12201    case CLI_INIT: 
12202       e->command = "pri debug span";
12203       e->usage = 
12204          "Usage: pri debug span <span>\n"
12205          "       Enables debugging on a given PRI span\n";
12206       return NULL;
12207    case CLI_GENERATE:   
12208       return complete_span_4(a->line, a->word, a->pos, a->n);
12209    }
12210    if (a->argc < 4) {
12211       return CLI_SHOWUSAGE;
12212    }
12213    span = atoi(a->argv[3]);
12214    if ((span < 1) || (span > NUM_SPANS)) {
12215       ast_cli(a->fd, "Invalid span %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
12216       return CLI_SUCCESS;
12217    }
12218    if (!pris[span-1].pri) {
12219       ast_cli(a->fd, "No PRI running on span %d\n", span);
12220       return CLI_SUCCESS;
12221    }
12222    for (x = 0; x < NUM_DCHANS; x++) {
12223       if (pris[span-1].dchans[x])
12224          pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU |
12225                                                PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE |
12226                                                PRI_DEBUG_Q921_STATE);
12227    }
12228    ast_cli(a->fd, "Enabled debugging on span %d\n", span);
12229    return CLI_SUCCESS;
12230 }
12231 
12232 
12233 
12234 static char *handle_pri_no_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12235 {
12236    int span;
12237    int x;
12238    switch (cmd) {
12239    case CLI_INIT:
12240       e->command = "pri no debug span";
12241       e->usage = 
12242          "Usage: pri no debug span <span>\n"
12243          "       Disables debugging on a given PRI span\n";
12244       return NULL;
12245    case CLI_GENERATE:
12246       return complete_span_5(a->line, a->word, a->pos, a->n);
12247    }
12248    if (a->argc < 5)
12249       return CLI_SHOWUSAGE;
12250 
12251    span = atoi(a->argv[4]);
12252    if ((span < 1) || (span > NUM_SPANS)) {
12253       ast_cli(a->fd, "Invalid span %s.  Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
12254       return CLI_SUCCESS;
12255    }
12256    if (!pris[span-1].pri) {
12257       ast_cli(a->fd, "No PRI running on span %d\n", span);
12258       return CLI_SUCCESS;
12259    }
12260    for (x = 0; x < NUM_DCHANS; x++) {
12261       if (pris[span-1].dchans[x])
12262          pri_set_debug(pris[span-1].dchans[x], 0);
12263    }
12264    ast_cli(a->fd, "Disabled debugging on span %d\n", span);
12265    return CLI_SUCCESS;
12266 }
12267 
12268 static char *handle_pri_really_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12269 {
12270    int span;
12271    int x;
12272    switch (cmd) {
12273    case CLI_INIT:
12274       e->command = "pri intensive debug span";
12275       e->usage = 
12276          "Usage: pri intensive debug span <span>\n"
12277          "       Enables debugging down to the Q.921 level\n";
12278       return NULL;
12279    case CLI_GENERATE:
12280       return complete_span_5(a->line, a->word, a->pos, a->n);
12281    }
12282 
12283    if (a->argc < 5)
12284       return CLI_SHOWUSAGE;
12285    span = atoi(a->argv[4]);
12286    if ((span < 1) || (span > NUM_SPANS)) {
12287       ast_cli(a->fd, "Invalid span %s.  Should be a number %d to %d\n", a->argv[4], 1, NUM_SPANS);
12288       return CLI_SUCCESS;
12289    }
12290    if (!pris[span-1].pri) {
12291       ast_cli(a->fd, "No PRI running on span %d\n", span);
12292       return CLI_SUCCESS;
12293    }
12294    for (x = 0; x < NUM_DCHANS; x++) {
12295       if (pris[span-1].dchans[x])
12296          pri_set_debug(pris[span-1].dchans[x], PRI_DEBUG_APDU |
12297                                                PRI_DEBUG_Q931_DUMP | PRI_DEBUG_Q931_STATE |
12298                                                PRI_DEBUG_Q921_RAW | PRI_DEBUG_Q921_DUMP | PRI_DEBUG_Q921_STATE);
12299    }
12300    ast_cli(a->fd, "Enabled EXTENSIVE debugging on span %d\n", span);
12301    return CLI_SUCCESS;
12302 }
12303 
12304 static void build_status(char *s, size_t len, int status, int active)
12305 {
12306    if (!s || len < 1) {
12307       return;
12308    }
12309    s[0] = '\0';
12310    if (status & DCHAN_PROVISIONED)
12311       strncat(s, "Provisioned, ", len - strlen(s) - 1);
12312    if (!(status & DCHAN_NOTINALARM))
12313       strncat(s, "In Alarm, ", len - strlen(s) - 1);
12314    if (status & DCHAN_UP)
12315       strncat(s, "Up", len - strlen(s) - 1);
12316    else
12317       strncat(s, "Down", len - strlen(s) - 1);
12318    if (active)
12319       strncat(s, ", Active", len - strlen(s) - 1);
12320    else
12321       strncat(s, ", Standby", len - strlen(s) - 1);
12322    s[len - 1] = '\0';
12323 }
12324 
12325 static char *handle_pri_show_spans(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12326 {
12327    int span;
12328    int x;
12329    char status[256];
12330 
12331    switch (cmd) {
12332    case CLI_INIT:
12333       e->command = "pri show spans";
12334       e->usage = 
12335          "Usage: pri show spans\n"
12336          "       Displays PRI Information\n";
12337       return NULL;
12338    case CLI_GENERATE:
12339       return NULL;   
12340    }
12341 
12342    if (a->argc != 3)
12343       return CLI_SHOWUSAGE;
12344 
12345    for (span = 0; span < NUM_SPANS; span++) {
12346       if (pris[span].pri) {
12347          for (x = 0; x < NUM_DCHANS; x++) {
12348             if (pris[span].dchannels[x]) {
12349                build_status(status, sizeof(status), pris[span].dchanavail[x], pris[span].dchans[x] == pris[span].pri);
12350                ast_cli(a->fd, "PRI span %d/%d: %s\n", span + 1, x, status);
12351             }
12352          }
12353       }
12354    }
12355    return CLI_SUCCESS;
12356 }
12357 
12358 static char *handle_pri_show_span(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12359 {
12360    int span;
12361    int x;
12362    char status[256];
12363    switch (cmd) {
12364    case CLI_INIT: 
12365       e->command = "pri show span";
12366       e->usage = 
12367          "Usage: pri show span <span>\n"
12368          "       Displays PRI Information on a given PRI span\n";
12369       return NULL;
12370    case CLI_GENERATE:
12371       return complete_span_4(a->line, a->word, a->pos, a->n);
12372    }
12373 
12374    if (a->argc < 4)
12375       return CLI_SHOWUSAGE;
12376    span = atoi(a->argv[3]);
12377    if ((span < 1) || (span > NUM_SPANS)) {
12378       ast_cli(a->fd, "Invalid span '%s'.  Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS);
12379       return CLI_SUCCESS;
12380    }
12381    if (!pris[span-1].pri) {
12382       ast_cli(a->fd, "No PRI running on span %d\n", span);
12383       return CLI_SUCCESS;
12384    }
12385    for (x = 0; x < NUM_DCHANS; x++) {
12386       if (pris[span-1].dchannels[x]) {
12387 #ifdef PRI_DUMP_INFO_STR
12388          char *info_str = NULL;
12389 #endif
12390          ast_cli(a->fd, "%s D-channel: %d\n", pri_order(x), pris[span-1].dchannels[x]);
12391          build_status(status, sizeof(status), pris[span-1].dchanavail[x], pris[span-1].dchans[x] == pris[span-1].pri);
12392          ast_cli(a->fd, "Status: %s\n", status);
12393 #ifdef PRI_DUMP_INFO_STR
12394          info_str = pri_dump_info_str(pris[span-1].pri);
12395          if (info_str) {
12396             ast_cli(a->fd, "%s", info_str);
12397             ast_free(info_str);
12398          }
12399 #else
12400          pri_dump_info(pris[span-1].pri);
12401 #endif
12402          ast_cli(a->fd, "Overlap Recv: %s\n\n", (pris[span-1].overlapdial & DAHDI_OVERLAPDIAL_INCOMING)?"Yes":"No");
12403       }
12404    }
12405    return CLI_SUCCESS;
12406 }
12407 
12408 static char *handle_pri_show_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12409 {
12410    int x;
12411    int span;
12412    int count=0;
12413    int debug=0;
12414 
12415    switch (cmd) {
12416    case CLI_INIT: 
12417       e->command = "pri show debug";
12418       e->usage = 
12419          "Usage: pri show debug\n"
12420          "  Show the debug state of pri spans\n";
12421       return NULL;
12422    case CLI_GENERATE:
12423       return NULL;   
12424    }
12425 
12426    for (span = 0; span < NUM_SPANS; span++) {
12427            if (pris[span].pri) {
12428          for (x = 0; x < NUM_DCHANS; x++) {
12429             debug = 0;
12430                if (pris[span].dchans[x]) {
12431                   debug = pri_get_debug(pris[span].dchans[x]);
12432                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" );
12433                count++;
12434             }
12435          }
12436       }
12437 
12438    }
12439    ast_mutex_lock(&pridebugfdlock);
12440    if (pridebugfd >= 0) 
12441       ast_cli(a->fd, "Logging PRI debug to file %s\n", pridebugfilename);
12442    ast_mutex_unlock(&pridebugfdlock);
12443        
12444    if (!count) 
12445       ast_cli(a->fd, "No debug set or no PRI running\n");
12446    return CLI_SUCCESS;
12447 }
12448 
12449 static char *handle_pri_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12450 {
12451    switch (cmd) {
12452    case CLI_INIT:
12453       e->command = "pri show version";
12454       e->usage = 
12455          "Usage: pri show version\n"
12456          "Show libpri version information\n";
12457       return NULL;
12458    case CLI_GENERATE:
12459       return NULL;
12460    }
12461 
12462    ast_cli(a->fd, "libpri version: %s\n", pri_get_version());
12463 
12464    return CLI_SUCCESS;
12465 }
12466 
12467 static struct ast_cli_entry dahdi_pri_cli[] = {
12468    AST_CLI_DEFINE(handle_pri_debug, "Enables PRI debugging on a span"),
12469    AST_CLI_DEFINE(handle_pri_no_debug, "Disables PRI debugging on a span"),
12470    AST_CLI_DEFINE(handle_pri_really_debug, "Enables REALLY INTENSE PRI debugging"),
12471    AST_CLI_DEFINE(handle_pri_show_spans, "Displays PRI Information"),
12472    AST_CLI_DEFINE(handle_pri_show_span, "Displays PRI Information"),
12473    AST_CLI_DEFINE(handle_pri_show_debug, "Displays current PRI debug settings"),
12474    AST_CLI_DEFINE(handle_pri_set_debug_file, "Sends PRI debug output to the specified file"),
12475    AST_CLI_DEFINE(handle_pri_unset_debug_file, "Ends PRI debug output to file"),
12476    AST_CLI_DEFINE(handle_pri_version, "Displays libpri version"),
12477 };
12478 
12479 #endif /* HAVE_PRI */
12480 
12481 static char *dahdi_destroy_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12482 {
12483    int channel;
12484    int ret;
12485    switch (cmd) {
12486    case CLI_INIT:
12487       e->command = "dahdi destroy channel";
12488       e->usage = 
12489          "Usage: dahdi destroy channel <chan num>\n"
12490          "  DON'T USE THIS UNLESS YOU KNOW WHAT YOU ARE DOING.  Immediately removes a given channel, whether it is in use or not\n";
12491       return NULL;
12492    case CLI_GENERATE:
12493       return NULL;   
12494    }
12495    if (a->argc != 4)
12496       return CLI_SHOWUSAGE;
12497    
12498    channel = atoi(a->argv[3]);
12499    ret = dahdi_destroy_channel_bynum(channel);
12500    return ( RESULT_SUCCESS == ret ) ? CLI_SUCCESS : CLI_FAILURE;
12501 }
12502 
12503 static void dahdi_softhangup_all(void)
12504 {
12505    struct dahdi_pvt *p;
12506 retry:
12507    ast_mutex_lock(&iflock);
12508     for (p = iflist; p; p = p->next) {
12509       ast_mutex_lock(&p->lock);
12510         if (p->owner && !p->restartpending) {
12511          if (ast_channel_trylock(p->owner)) {
12512             if (option_debug > 2)
12513                ast_verbose("Avoiding deadlock\n");
12514             /* Avoid deadlock since you're not supposed to lock iflock or pvt before a channel */
12515             ast_mutex_unlock(&p->lock);
12516             ast_mutex_unlock(&iflock);
12517             goto retry;
12518          }
12519          if (option_debug > 2)
12520             ast_verbose("Softhanging up on %s\n", p->owner->name);
12521          ast_softhangup_nolock(p->owner, AST_SOFTHANGUP_EXPLICIT);
12522          p->restartpending = 1;
12523          num_restart_pending++;
12524          ast_channel_unlock(p->owner);
12525       }
12526       ast_mutex_unlock(&p->lock);
12527     }
12528    ast_mutex_unlock(&iflock);
12529 }
12530 
12531 static int setup_dahdi(int reload);
12532 static int dahdi_restart(void)
12533 {
12534 #if defined(HAVE_PRI) || defined(HAVE_SS7)
12535    int i, j;
12536 #endif
12537    int cancel_code;
12538    struct dahdi_pvt *p;
12539 
12540    ast_mutex_lock(&restart_lock);
12541 
12542    ast_verb(1, "Destroying channels and reloading DAHDI configuration.\n");
12543    dahdi_softhangup_all();
12544    ast_verb(4, "Initial softhangup of all DAHDI channels complete.\n");
12545 
12546 #if defined(HAVE_PRI)
12547    for (i = 0; i < NUM_SPANS; i++) {
12548       if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL)) {
12549          cancel_code = pthread_cancel(pris[i].master);
12550          pthread_kill(pris[i].master, SIGURG);
12551          ast_debug(4, "Waiting to join thread of span %d with pid=%p, cancel_code=%d\n", i, (void *) pris[i].master, cancel_code);
12552          pthread_join(pris[i].master, NULL);
12553          ast_debug(4, "Joined thread of span %d\n", i);
12554       }
12555    }
12556 #endif
12557 
12558 #if defined(HAVE_SS7)
12559    for (i = 0; i < NUM_SPANS; i++) {
12560       if (linksets[i].master && (linksets[i].master != AST_PTHREADT_NULL)) {
12561          cancel_code = pthread_cancel(linksets[i].master);
12562          pthread_kill(linksets[i].master, SIGURG);
12563          ast_debug(4, "Waiting to join thread of span %d with pid=%p, cancel_code=%d\n", i, (void *) linksets[i].master, cancel_code);
12564          pthread_join(linksets[i].master, NULL);
12565          ast_debug(4, "Joined thread of span %d\n", i);
12566       }
12567     }
12568 #endif
12569 
12570    ast_mutex_lock(&monlock);
12571    if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
12572       cancel_code = pthread_cancel(monitor_thread);
12573       pthread_kill(monitor_thread, SIGURG);
12574       ast_debug(4, "Waiting to join monitor thread with pid=%p, cancel_code=%d\n", (void *) monitor_thread, cancel_code);
12575       pthread_join(monitor_thread, NULL);
12576       ast_debug(4, "Joined monitor thread\n");
12577    }
12578    monitor_thread = AST_PTHREADT_NULL; /* prepare to restart thread in setup_dahdi once channels are reconfigured */
12579 
12580    ast_mutex_lock(&mwi_thread_lock);
12581    while (mwi_thread_count > 0) {
12582       ast_debug(3, "Waiting on %d mwi_send_thread(s) to finish\n", mwi_thread_count);
12583       ast_cond_wait(&mwi_thread_complete, &mwi_thread_lock);
12584    }
12585    ast_mutex_unlock(&mwi_thread_lock);
12586    ast_mutex_lock(&ss_thread_lock);
12587    while (ss_thread_count > 0) { /* let ss_threads finish and run dahdi_hangup before dahvi_pvts are destroyed */
12588       int x = DAHDI_FLASH;
12589       ast_debug(3, "Waiting on %d ss_thread(s) to finish\n", ss_thread_count);
12590 
12591       for (p = iflist; p; p = p->next) {
12592          if (p->owner)
12593             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 */      
12594          }
12595          ast_cond_wait(&ss_thread_complete, &ss_thread_lock);
12596       }
12597 
12598    /* ensure any created channels before monitor threads were stopped are hungup */
12599    dahdi_softhangup_all();
12600    ast_verb(4, "Final softhangup of all DAHDI channels complete.\n");
12601    destroy_all_channels();
12602    ast_debug(1, "Channels destroyed. Now re-reading config. %d active channels remaining.\n", ast_active_channels());
12603 
12604    ast_mutex_unlock(&monlock);
12605 
12606 #ifdef HAVE_PRI
12607    for (i = 0; i < NUM_SPANS; i++) {
12608       for (j = 0; j < NUM_DCHANS; j++)
12609          dahdi_close_pri_fd(&(pris[i]), j);
12610    }
12611 
12612    memset(pris, 0, sizeof(pris));
12613    for (i = 0; i < NUM_SPANS; i++) {
12614       ast_mutex_init(&pris[i].lock);
12615       pris[i].offset = -1;
12616       pris[i].master = AST_PTHREADT_NULL;
12617       for (j = 0; j < NUM_DCHANS; j++)
12618          pris[i].fds[j] = -1;
12619       }
12620    pri_set_error(dahdi_pri_error);
12621    pri_set_message(dahdi_pri_message);
12622 #endif
12623 #ifdef HAVE_SS7
12624    for (i = 0; i < NUM_SPANS; i++) {
12625       for (j = 0; j < NUM_DCHANS; j++)
12626          dahdi_close_ss7_fd(&(linksets[i]), j);
12627    }
12628 
12629    memset(linksets, 0, sizeof(linksets));
12630    for (i = 0; i < NUM_SPANS; i++) {
12631       ast_mutex_init(&linksets[i].lock);
12632       linksets[i].master = AST_PTHREADT_NULL;
12633       for (j = 0; j < NUM_DCHANS; j++)
12634          linksets[i].fds[j] = -1;
12635    }
12636    ss7_set_error(dahdi_ss7_error);
12637    ss7_set_message(dahdi_ss7_message);
12638 #endif
12639 
12640    if (setup_dahdi(2) != 0) {
12641       ast_log(LOG_WARNING, "Reload channels from dahdi config failed!\n");
12642       ast_mutex_unlock(&ss_thread_lock);
12643       return 1;
12644    }
12645    ast_mutex_unlock(&ss_thread_lock);
12646    ast_mutex_unlock(&restart_lock);
12647    return 0;
12648 }
12649 
12650 static char *dahdi_restart_cmd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12651 {
12652    switch (cmd) {
12653    case CLI_INIT:
12654       e->command = "dahdi restart";
12655       e->usage = 
12656          "Usage: dahdi restart\n"
12657          "  Restarts the DAHDI channels: destroys them all and then\n"
12658          "  re-reads them from chan_dahdi.conf.\n"
12659          "  Note that this will STOP any running CALL on DAHDI channels.\n"
12660          "";
12661       return NULL;
12662    case CLI_GENERATE:
12663       return NULL;
12664    }
12665    if (a->argc != 2)
12666       return CLI_SHOWUSAGE;
12667 
12668    if (dahdi_restart() != 0)
12669       return CLI_FAILURE;
12670    return CLI_SUCCESS;
12671 }
12672 
12673 static int action_dahdirestart(struct mansession *s, const struct message *m)
12674 {
12675    if (dahdi_restart() != 0) {
12676       astman_send_error(s, m, "Failed rereading DAHDI configuration");
12677       return 1;
12678    }
12679    astman_send_ack(s, m, "DAHDIRestart: Success");
12680    return 0;
12681 }
12682 
12683 static char *dahdi_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12684 {
12685 #define FORMAT "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
12686 #define FORMAT2 "%7s %-10.10s %-15.15s %-10.10s %-20.20s %-10.10s %-10.10s\n"
12687    unsigned int targetnum = 0;
12688    int filtertype = 0;
12689    struct dahdi_pvt *tmp = NULL;
12690    char tmps[20] = "";
12691    char statestr[20] = "";
12692    char blockstr[20] = "";
12693    ast_mutex_t *lock;
12694    struct dahdi_pvt *start;
12695 #ifdef HAVE_PRI
12696    int trunkgroup;
12697    struct dahdi_pri *pri = NULL;
12698    int x;
12699 #endif
12700    switch (cmd) {
12701    case CLI_INIT:
12702       e->command = "dahdi show channels [trunkgroup|group|context]";
12703       e->usage = 
12704          "Usage: dahdi show channels [ trunkgroup <trunkgroup> | group <group> | context <context> ]\n"
12705          "  Shows a list of available channels with optional filtering\n"
12706          "  <group> must be a number between 0 and 63\n";
12707       return NULL;
12708    case CLI_GENERATE:
12709       return NULL;   
12710    }
12711 
12712    lock = &iflock;
12713    start = iflist;
12714 
12715    /* syntax: dahdi show channels [ group <group> | context <context> | trunkgroup <trunkgroup> ] */
12716 
12717    if (!((a->argc == 3) || (a->argc == 5)))
12718       return CLI_SHOWUSAGE;
12719 
12720    if (a->argc == 5) {
12721 #ifdef HAVE_PRI
12722       if (!strcasecmp(a->argv[3], "trunkgroup")) {
12723          /* this option requires no special handling, so leave filtertype to zero */
12724          if ((trunkgroup = atoi(a->argv[4])) < 1)
12725             return CLI_SHOWUSAGE;
12726          for (x = 0; x < NUM_SPANS; x++) {
12727             if (pris[x].trunkgroup == trunkgroup) {
12728                pri = pris + x;
12729                break;
12730             }
12731          }
12732          if (pri) {
12733             start = pri->crvs;
12734             lock = &pri->lock;
12735          } else {
12736             ast_cli(a->fd, "No such trunk group %d\n", trunkgroup);
12737             return CLI_FAILURE;
12738          }
12739       } else
12740 #endif   
12741       if (!strcasecmp(a->argv[3], "group")) {
12742          targetnum = atoi(a->argv[4]);
12743          if ((targetnum < 0) || (targetnum > 63))
12744             return CLI_SHOWUSAGE;
12745          targetnum = 1 << targetnum;
12746          filtertype = 1;
12747       } else if (!strcasecmp(a->argv[3], "context")) {
12748          filtertype = 2;
12749       }
12750    }
12751 
12752    ast_mutex_lock(lock);
12753 #ifdef HAVE_PRI
12754    ast_cli(a->fd, FORMAT2, pri ? "CRV" : "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State");
12755 #else
12756    ast_cli(a->fd, FORMAT2, "Chan", "Extension", "Context", "Language", "MOH Interpret", "Blocked", "State");
12757 #endif   
12758    
12759    tmp = start;
12760    while (tmp) {
12761       if (filtertype) {
12762          switch(filtertype) {
12763          case 1: /* dahdi show channels group <group> */
12764             if (!(tmp->group & targetnum)) {
12765                tmp = tmp->next;
12766                continue;
12767             }
12768             break;
12769          case 2: /* dahdi show channels context <context> */
12770             if (strcasecmp(tmp->context, a->argv[4])) {
12771                tmp = tmp->next;
12772                continue;
12773             }
12774             break;
12775          default:
12776             ;
12777          }
12778       }
12779       if (tmp->channel > 0) {
12780          snprintf(tmps, sizeof(tmps), "%d", tmp->channel);
12781       } else
12782          ast_copy_string(tmps, "pseudo", sizeof(tmps));
12783 
12784       if (tmp->locallyblocked)
12785          blockstr[0] = 'L';
12786       else
12787          blockstr[0] = ' ';
12788 
12789       if (tmp->remotelyblocked)
12790          blockstr[1] = 'R';
12791       else
12792          blockstr[1] = ' ';
12793 
12794       blockstr[2] = '\0';
12795 
12796       snprintf(statestr, sizeof(statestr), "%s", "In Service");
12797 
12798       ast_cli(a->fd, FORMAT, tmps, tmp->exten, tmp->context, tmp->language, tmp->mohinterpret, blockstr, statestr);
12799       tmp = tmp->next;
12800    }
12801    ast_mutex_unlock(lock);
12802    return CLI_SUCCESS;
12803 #undef FORMAT
12804 #undef FORMAT2
12805 }
12806 
12807 static char *dahdi_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12808 {
12809    int channel;
12810    struct dahdi_pvt *tmp = NULL;
12811    struct dahdi_confinfo ci;
12812    struct dahdi_params ps;
12813    int x;
12814    ast_mutex_t *lock;
12815    struct dahdi_pvt *start;
12816 #ifdef HAVE_PRI
12817    char *c;
12818    int trunkgroup;
12819    struct dahdi_pri *pri=NULL;
12820 #endif
12821    switch (cmd) {
12822    case CLI_INIT:
12823       e->command = "dahdi show channel";
12824       e->usage = 
12825          "Usage: dahdi show channel <chan num>\n"
12826          "  Detailed information about a given channel\n";
12827       return NULL;
12828    case CLI_GENERATE:
12829       return NULL;   
12830    }
12831 
12832    lock = &iflock;
12833    start = iflist;
12834 
12835    if (a->argc != 4)
12836       return CLI_SHOWUSAGE;
12837 #ifdef HAVE_PRI
12838    if ((c = strchr(a->argv[3], ':'))) {
12839       if (sscanf(a->argv[3], "%30d:%30d", &trunkgroup, &channel) != 2)
12840          return CLI_SHOWUSAGE;
12841       if ((trunkgroup < 1) || (channel < 1))
12842          return CLI_SHOWUSAGE;
12843       for (x = 0; x < NUM_SPANS; x++) {
12844          if (pris[x].trunkgroup == trunkgroup) {
12845             pri = pris + x;
12846             break;
12847          }
12848       }
12849       if (pri) {
12850          start = pri->crvs;
12851          lock = &pri->lock;
12852       } else {
12853          ast_cli(a->fd, "No such trunk group %d\n", trunkgroup);
12854          return CLI_FAILURE;
12855       }
12856    } else
12857 #endif
12858       channel = atoi(a->argv[3]);
12859 
12860    ast_mutex_lock(lock);
12861    tmp = start;
12862    while (tmp) {
12863       if (tmp->channel == channel) {
12864 #ifdef HAVE_PRI
12865          if (pri) 
12866             ast_cli(a->fd, "Trunk/CRV: %d/%d\n", trunkgroup, tmp->channel);
12867          else
12868 #endif         
12869          ast_cli(a->fd, "Channel: %d\n", tmp->channel);
12870          ast_cli(a->fd, "File Descriptor: %d\n", tmp->subs[SUB_REAL].dfd);
12871          ast_cli(a->fd, "Span: %d\n", tmp->span);
12872          ast_cli(a->fd, "Extension: %s\n", tmp->exten);
12873          ast_cli(a->fd, "Dialing: %s\n", tmp->dialing ? "yes" : "no");
12874          ast_cli(a->fd, "Context: %s\n", tmp->context);
12875          ast_cli(a->fd, "Caller ID: %s\n", tmp->cid_num);
12876          ast_cli(a->fd, "Calling TON: %d\n", tmp->cid_ton);
12877          ast_cli(a->fd, "Caller ID name: %s\n", tmp->cid_name);
12878          ast_cli(a->fd, "Mailbox: %s\n", S_OR(tmp->mailbox, "none"));
12879          if (tmp->vars) {
12880             struct ast_variable *v;
12881             ast_cli(a->fd, "Variables:\n");
12882             for (v = tmp->vars ; v ; v = v->next)
12883                ast_cli(a->fd, "       %s = %s\n", v->name, v->value);
12884          }
12885          ast_cli(a->fd, "Destroy: %d\n", tmp->destroy);
12886          ast_cli(a->fd, "InAlarm: %d\n", tmp->inalarm);
12887          ast_cli(a->fd, "Signalling Type: %s\n", sig2str(tmp->sig));
12888          ast_cli(a->fd, "Radio: %d\n", tmp->radio);
12889          ast_cli(a->fd, "Owner: %s\n", tmp->owner ? tmp->owner->name : "<None>");
12890          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)" : "");
12891          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)" : "");
12892          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)" : "");
12893          ast_cli(a->fd, "Confno: %d\n", tmp->confno);
12894          ast_cli(a->fd, "Propagated Conference: %d\n", tmp->propconfno);
12895          ast_cli(a->fd, "Real in conference: %d\n", tmp->inconference);
12896          ast_cli(a->fd, "DSP: %s\n", tmp->dsp ? "yes" : "no");
12897          ast_cli(a->fd, "Busy Detection: %s\n", tmp->busydetect ? "yes" : "no");
12898          if (tmp->busydetect) {
12899 #if defined(BUSYDETECT_TONEONLY)
12900             ast_cli(a->fd, "    Busy Detector Helper: BUSYDETECT_TONEONLY\n");
12901 #elif defined(BUSYDETECT_COMPARE_TONE_AND_SILENCE)
12902             ast_cli(a->fd, "    Busy Detector Helper: BUSYDETECT_COMPARE_TONE_AND_SILENCE\n");
12903 #endif
12904 #ifdef BUSYDETECT_DEBUG
12905             ast_cli(a->fd, "    Busy Detector Debug: Enabled\n");
12906 #endif
12907             ast_cli(a->fd, "    Busy Count: %d\n", tmp->busycount);
12908             ast_cli(a->fd, "    Busy Pattern: %d,%d\n", tmp->busy_tonelength, tmp->busy_quietlength);
12909          }
12910          ast_cli(a->fd, "TDD: %s\n", tmp->tdd ? "yes" : "no");
12911          ast_cli(a->fd, "Relax DTMF: %s\n", tmp->dtmfrelax ? "yes" : "no");
12912          ast_cli(a->fd, "Dialing/CallwaitCAS: %d/%d\n", tmp->dialing, tmp->callwaitcas);
12913          ast_cli(a->fd, "Default law: %s\n", tmp->law == DAHDI_LAW_MULAW ? "ulaw" : tmp->law == DAHDI_LAW_ALAW ? "alaw" : "unknown");
12914          ast_cli(a->fd, "Fax Handled: %s\n", tmp->faxhandled ? "yes" : "no");
12915          ast_cli(a->fd, "Pulse phone: %s\n", tmp->pulsedial ? "yes" : "no");
12916          ast_cli(a->fd, "DND: %s\n", tmp->dnd ? "yes" : "no");
12917          ast_cli(a->fd, "Echo Cancellation:\n");
12918 
12919          if (tmp->echocancel.head.tap_length) {
12920             ast_cli(a->fd, "\t%d taps\n", tmp->echocancel.head.tap_length);
12921             for (x = 0; x < tmp->echocancel.head.param_count; x++) {
12922                ast_cli(a->fd, "\t\t%s: %ud\n", tmp->echocancel.params[x].name, tmp->echocancel.params[x].value);
12923             }
12924             ast_cli(a->fd, "\t%scurrently %s\n", tmp->echocanbridged ? "" : "(unless TDM bridged) ", tmp->echocanon ? "ON" : "OFF");
12925          } else {
12926             ast_cli(a->fd, "\tnone\n");
12927          }
12928          if (tmp->master)
12929             ast_cli(a->fd, "Master Channel: %d\n", tmp->master->channel);
12930          for (x = 0; x < MAX_SLAVES; x++) {
12931             if (tmp->slaves[x])
12932                ast_cli(a->fd, "Slave Channel: %d\n", tmp->slaves[x]->channel);
12933          }
12934 #ifdef HAVE_SS7
12935          if (tmp->ss7) {
12936             ast_cli(a->fd, "CIC: %d\n", tmp->cic);
12937          }
12938 #endif
12939 #ifdef HAVE_PRI
12940          if (tmp->pri) {
12941             ast_cli(a->fd, "PRI Flags: ");
12942             if (tmp->resetting)
12943                ast_cli(a->fd, "Resetting ");
12944             if (tmp->call)
12945                ast_cli(a->fd, "Call ");
12946             if (tmp->bearer)
12947                ast_cli(a->fd, "Bearer ");
12948             ast_cli(a->fd, "\n");
12949             if (tmp->logicalspan) 
12950                ast_cli(a->fd, "PRI Logical Span: %d\n", tmp->logicalspan);
12951             else
12952                ast_cli(a->fd, "PRI Logical Span: Implicit\n");
12953          }
12954             
12955 #endif
12956          memset(&ci, 0, sizeof(ci));
12957          ps.channo = tmp->channel;
12958          if (tmp->subs[SUB_REAL].dfd > -1) {
12959             memset(&ci, 0, sizeof(ci));
12960             if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONF, &ci)) {
12961                ast_cli(a->fd, "Actual Confinfo: Num/%d, Mode/0x%04x\n", ci.confno, ci.confmode);
12962             }
12963             if (!ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GETCONFMUTE, &x)) {
12964                ast_cli(a->fd, "Actual Confmute: %s\n", x ? "Yes" : "No");
12965             }
12966             memset(&ps, 0, sizeof(ps));
12967             if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &ps) < 0) {
12968                ast_log(LOG_WARNING, "Failed to get parameters on channel %d: %s\n", tmp->channel, strerror(errno));
12969             } else {
12970                ast_cli(a->fd, "Hookstate (FXS only): %s\n", ps.rxisoffhook ? "Offhook" : "Onhook");
12971             }
12972          }
12973          ast_mutex_unlock(lock);
12974          return CLI_SUCCESS;
12975       }
12976       tmp = tmp->next;
12977    }
12978    
12979    ast_cli(a->fd, "Unable to find given channel %d\n", channel);
12980    ast_mutex_unlock(lock);
12981    return CLI_FAILURE;
12982 }
12983 
12984 static char *handle_dahdi_show_cadences(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
12985 {
12986    int i, j;
12987    switch (cmd) {
12988    case CLI_INIT:
12989       e->command = "dahdi show cadences";
12990       e->usage = 
12991          "Usage: dahdi show cadences\n"
12992          "       Shows all cadences currently defined\n";
12993       return NULL;
12994    case CLI_GENERATE:
12995       return NULL;   
12996    }
12997    for (i = 0; i < num_cadence; i++) {
12998       char output[1024];
12999       char tmp[16], tmp2[64];
13000       snprintf(tmp, sizeof(tmp), "r%d: ", i + 1);
13001       term_color(output, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(output));
13002 
13003       for (j = 0; j < 16; j++) {
13004          if (cadences[i].ringcadence[j] == 0)
13005             break;
13006          snprintf(tmp, sizeof(tmp), "%d", cadences[i].ringcadence[j]);
13007          if (cidrings[i] * 2 - 1 == j)
13008             term_color(tmp2, tmp, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp2) - 1);
13009          else
13010             term_color(tmp2, tmp, COLOR_GREEN, COLOR_BLACK, sizeof(tmp2) - 1);
13011          if (j != 0)
13012             strncat(output, ",", sizeof(output) - strlen(output) - 1);
13013          strncat(output, tmp2, sizeof(output) - strlen(output) - 1);
13014       }
13015       ast_cli(a->fd,"%s\n",output);
13016    }
13017    return CLI_SUCCESS;
13018 }
13019 
13020 /* Based on irqmiss.c */
13021 static char *dahdi_show_status(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a) 
13022 {
13023    #define FORMAT "%-40.40s %-7.7s %-6d %-6d %-6d %-3.3s %-4.4s %-8.8s %s\n"
13024    #define FORMAT2 "%-40.40s %-7.7s %-6.6s %-6.6s %-6.6s %-3.3s %-4.4s %-8.8s %s\n"
13025    int span;
13026    int res;
13027    char alarmstr[50];
13028 
13029    int ctl;
13030    struct dahdi_spaninfo s;
13031 
13032    switch (cmd) {
13033    case CLI_INIT:
13034       e->command = "dahdi show status";
13035       e->usage = 
13036          "Usage: dahdi show status\n"
13037          "       Shows a list of DAHDI cards with status\n";
13038       return NULL;
13039    case CLI_GENERATE:
13040       return NULL;   
13041    }
13042    ctl = open("/dev/dahdi/ctl", O_RDWR);
13043    if (ctl < 0) {
13044       ast_cli(a->fd, "No DAHDI found. Unable to open /dev/dahdi/ctl: %s\n", strerror(errno));
13045       return CLI_FAILURE;
13046    }
13047    ast_cli(a->fd, FORMAT2, "Description", "Alarms", "IRQ", "bpviol", "CRC4", "Framing", "Coding", "Options", "LBO");
13048 
13049    for (span = 1; span < DAHDI_MAX_SPANS; ++span) {
13050       s.spanno = span;
13051       res = ioctl(ctl, DAHDI_SPANSTAT, &s);
13052       if (res) {
13053          continue;
13054       }
13055       alarmstr[0] = '\0';
13056       if (s.alarms > 0) {
13057          if (s.alarms & DAHDI_ALARM_BLUE)
13058             strcat(alarmstr, "BLU/");
13059          if (s.alarms & DAHDI_ALARM_YELLOW)
13060             strcat(alarmstr, "YEL/");
13061          if (s.alarms & DAHDI_ALARM_RED)
13062             strcat(alarmstr, "RED/");
13063          if (s.alarms & DAHDI_ALARM_LOOPBACK)
13064             strcat(alarmstr, "LB/");
13065          if (s.alarms & DAHDI_ALARM_RECOVER)
13066             strcat(alarmstr, "REC/");
13067          if (s.alarms & DAHDI_ALARM_NOTOPEN)
13068             strcat(alarmstr, "NOP/");
13069          if (!strlen(alarmstr))
13070             strcat(alarmstr, "UUU/");
13071          if (strlen(alarmstr)) {
13072             /* Strip trailing / */
13073             alarmstr[strlen(alarmstr) - 1] = '\0';
13074          }
13075       } else {
13076          if (s.numchans)
13077             strcpy(alarmstr, "OK");
13078          else
13079             strcpy(alarmstr, "UNCONFIGURED");
13080       }
13081 
13082       ast_cli(a->fd, FORMAT, s.desc, alarmstr, s.irqmisses, s.bpvcount, s.crc4count
13083             , s.lineconfig & DAHDI_CONFIG_D4 ? "D4" :
13084               s.lineconfig & DAHDI_CONFIG_ESF ? "ESF" :
13085               s.lineconfig & DAHDI_CONFIG_CCS ? "CCS" :
13086               "CAS"
13087             , s.lineconfig & DAHDI_CONFIG_B8ZS ? "B8ZS" :
13088               s.lineconfig & DAHDI_CONFIG_HDB3 ? "HDB3" :
13089               s.lineconfig & DAHDI_CONFIG_AMI ? "AMI" :
13090               "Unk"
13091             , s.lineconfig & DAHDI_CONFIG_CRC4 ?
13092               s.lineconfig & DAHDI_CONFIG_NOTOPEN ? "CRC4/YEL" : "CRC4" : "YEL"
13093             , lbostr[s.lbo]
13094          );
13095    }
13096    close(ctl);
13097 
13098    return CLI_SUCCESS;
13099 #undef FORMAT
13100 #undef FORMAT2
13101 }
13102 
13103 static char *dahdi_show_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13104 {
13105    int pseudo_fd = -1;
13106    struct dahdi_versioninfo vi;
13107 
13108    switch (cmd) {
13109    case CLI_INIT:
13110       e->command = "dahdi show version";
13111       e->usage = 
13112          "Usage: dahdi show version\n"
13113          "       Shows the DAHDI version in use\n";
13114       return NULL;
13115    case CLI_GENERATE:
13116       return NULL;
13117    }
13118    if ((pseudo_fd = open("/dev/dahdi/ctl", O_RDONLY)) < 0) {
13119       ast_cli(a->fd, "Failed to open control file to get version.\n");
13120       return CLI_SUCCESS;
13121    }
13122 
13123    strcpy(vi.version, "Unknown");
13124    strcpy(vi.echo_canceller, "Unknown");
13125 
13126    if (ioctl(pseudo_fd, DAHDI_GETVERSION, &vi))
13127       ast_cli(a->fd, "Failed to get DAHDI version: %s\n", strerror(errno));
13128    else
13129       ast_cli(a->fd, "DAHDI Version: %s Echo Canceller: %s\n", vi.version, vi.echo_canceller);
13130 
13131    close(pseudo_fd);
13132 
13133    return CLI_SUCCESS;
13134 }
13135 
13136 static char *dahdi_set_hwgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13137 {
13138    int channel;
13139    int gain;
13140    int tx;
13141    struct dahdi_hwgain hwgain;
13142    struct dahdi_pvt *tmp = NULL;
13143 
13144    switch (cmd) {
13145    case CLI_INIT:
13146       e->command = "dahdi set hwgain";
13147       e->usage = 
13148          "Usage: dahdi set hwgain <rx|tx> <chan#> <gain>\n"
13149          "  Sets the hardware gain on a a given channel, overriding the\n"
13150          "   value provided at module loadtime, whether the channel is in\n"
13151          "   use or not.  Changes take effect immediately.\n"
13152          "   <rx|tx> which direction do you want to change (relative to our module)\n"
13153          "   <chan num> is the channel number relative to the device\n"
13154          "   <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
13155       return NULL;
13156    case CLI_GENERATE:
13157       return NULL;   
13158    }
13159 
13160    if (a->argc != 6)
13161       return CLI_SHOWUSAGE;
13162    
13163    if (!strcasecmp("rx", a->argv[3]))
13164       tx = 0; /* rx */
13165    else if (!strcasecmp("tx", a->argv[3]))
13166       tx = 1; /* tx */
13167    else
13168       return CLI_SHOWUSAGE;
13169 
13170    channel = atoi(a->argv[4]);
13171    gain = atof(a->argv[5])*10.0;
13172 
13173    ast_mutex_lock(&iflock);
13174 
13175    for (tmp = iflist; tmp; tmp = tmp->next) {
13176 
13177       if (tmp->channel != channel)
13178          continue;
13179 
13180       if (tmp->subs[SUB_REAL].dfd == -1)
13181          break;
13182 
13183       hwgain.newgain = gain;
13184       hwgain.tx = tx;
13185       if (ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_SET_HWGAIN, &hwgain) < 0) {
13186          ast_cli(a->fd, "Unable to set the hardware gain for channel %d: %s\n", channel, strerror(errno));
13187          ast_mutex_unlock(&iflock);
13188          return CLI_FAILURE;
13189       }
13190       ast_cli(a->fd, "hardware %s gain set to %d (%.1f dB) on channel %d\n",
13191          tx ? "tx" : "rx", gain, (float)gain/10.0, channel);
13192       break;
13193    }
13194 
13195    ast_mutex_unlock(&iflock);
13196 
13197    if (tmp)
13198       return CLI_SUCCESS;
13199 
13200    ast_cli(a->fd, "Unable to find given channel %d\n", channel);
13201    return CLI_FAILURE;
13202 
13203 }
13204 
13205 static char *dahdi_set_swgain(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13206 {
13207    int channel;
13208    float gain;
13209    int tx;
13210    int res;
13211    ast_mutex_t *lock;
13212    struct dahdi_pvt *tmp = NULL;
13213 
13214    switch (cmd) {
13215    case CLI_INIT:
13216       e->command = "dahdi set swgain";
13217       e->usage = 
13218          "Usage: dahdi set swgain <rx|tx> <chan#> <gain>\n"
13219          "  Sets the software gain on a a given channel, overriding the\n"
13220          "   value provided at module loadtime, whether the channel is in\n"
13221          "   use or not.  Changes take effect immediately.\n"
13222          "   <rx|tx> which direction do you want to change (relative to our module)\n"
13223          "   <chan num> is the channel number relative to the device\n"
13224          "   <gain> is the gain in dB (e.g. -3.5 for -3.5dB)\n";
13225       return NULL;
13226    case CLI_GENERATE:
13227       return NULL;   
13228    }
13229 
13230    lock = &iflock;
13231 
13232    if (a->argc != 6)
13233       return CLI_SHOWUSAGE;
13234    
13235    if (!strcasecmp("rx", a->argv[3]))
13236       tx = 0; /* rx */
13237    else if (!strcasecmp("tx", a->argv[3]))
13238       tx = 1; /* tx */
13239    else
13240       return CLI_SHOWUSAGE;
13241 
13242    channel = atoi(a->argv[4]);
13243    gain = atof(a->argv[5]);
13244 
13245    ast_mutex_lock(lock);
13246    for (tmp = iflist; tmp; tmp = tmp->next) {
13247 
13248       if (tmp->channel != channel)
13249          continue;
13250 
13251       if (tmp->subs[SUB_REAL].dfd == -1)
13252          break;
13253 
13254       if (tx)
13255          res = set_actual_txgain(tmp->subs[SUB_REAL].dfd, channel, gain, tmp->law);
13256       else
13257          res = set_actual_rxgain(tmp->subs[SUB_REAL].dfd, channel, gain, tmp->law);
13258 
13259       if (res) {
13260          ast_cli(a->fd, "Unable to set the software gain for channel %d\n", channel);
13261          ast_mutex_unlock(lock);
13262          return CLI_FAILURE;
13263       }
13264 
13265       ast_cli(a->fd, "software %s gain set to %.1f on channel %d\n",
13266          tx ? "tx" : "rx", gain, channel);
13267       break;
13268    }
13269    ast_mutex_unlock(lock);
13270 
13271    if (tmp)
13272       return CLI_SUCCESS;
13273 
13274    ast_cli(a->fd, "Unable to find given channel %d\n", channel);
13275    return CLI_FAILURE;
13276 
13277 }
13278 
13279 static char *dahdi_set_dnd(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13280 {
13281    int channel;
13282    int on;
13283    struct dahdi_pvt *dahdi_chan = NULL;
13284 
13285    switch (cmd) {
13286    case CLI_INIT:
13287       e->command = "dahdi set dnd";
13288       e->usage = 
13289          "Usage: dahdi set dnd <chan#> <on|off>\n"
13290          "  Sets/resets DND (Do Not Disturb) mode on a channel.\n"
13291          "  Changes take effect immediately.\n"
13292          "  <chan num> is the channel number\n"
13293          "  <on|off> Enable or disable DND mode?\n"
13294          ;
13295       return NULL;
13296    case CLI_GENERATE:
13297       return NULL;   
13298    }
13299 
13300    if (a->argc != 5)
13301       return CLI_SHOWUSAGE;
13302 
13303    if ((channel = atoi(a->argv[3])) <= 0) {
13304       ast_cli(a->fd, "Expected channel number, got '%s'\n", a->argv[3]);
13305       return CLI_SHOWUSAGE;
13306    }
13307    
13308    if (ast_true(a->argv[4]))
13309       on = 1;
13310    else if (ast_false(a->argv[4]))
13311       on = 0;
13312    else {
13313       ast_cli(a->fd, "Expected 'on' or 'off', got '%s'\n", a->argv[4]);
13314       return CLI_SHOWUSAGE;
13315    }
13316 
13317    ast_mutex_lock(&iflock);
13318    for (dahdi_chan = iflist; dahdi_chan; dahdi_chan = dahdi_chan->next) {
13319       if (dahdi_chan->channel != channel)
13320          continue;
13321 
13322       /* Found the channel. Actually set it */
13323       dahdi_dnd(dahdi_chan, on);
13324       break;
13325    }
13326    ast_mutex_unlock(&iflock);
13327 
13328    if (!dahdi_chan) {
13329       ast_cli(a->fd, "Unable to find given channel %d\n", channel);
13330       return CLI_FAILURE;
13331    }
13332 
13333    return CLI_SUCCESS;
13334 }
13335 
13336 static struct ast_cli_entry dahdi_cli[] = {
13337    AST_CLI_DEFINE(handle_dahdi_show_cadences, "List cadences"),
13338    AST_CLI_DEFINE(dahdi_show_channels, "Show active DAHDI channels"),
13339    AST_CLI_DEFINE(dahdi_show_channel, "Show information on a channel"),
13340    AST_CLI_DEFINE(dahdi_destroy_channel, "Destroy a channel"),
13341    AST_CLI_DEFINE(dahdi_restart_cmd, "Fully restart DAHDI channels"),
13342    AST_CLI_DEFINE(dahdi_show_status, "Show all DAHDI cards status"),
13343    AST_CLI_DEFINE(dahdi_show_version, "Show the DAHDI version in use"),
13344    AST_CLI_DEFINE(dahdi_set_hwgain, "Set hardware gain on a channel"),
13345    AST_CLI_DEFINE(dahdi_set_swgain, "Set software gain on a channel"),
13346    AST_CLI_DEFINE(dahdi_set_dnd, "Sets/resets DND (Do Not Disturb) mode on a channel"),
13347 };
13348 
13349 #define TRANSFER  0
13350 #define HANGUP    1
13351 
13352 static int dahdi_fake_event(struct dahdi_pvt *p, int mode)
13353 {
13354    if (p) {
13355       switch (mode) {
13356          case TRANSFER:
13357             p->fake_event = DAHDI_EVENT_WINKFLASH;
13358             break;
13359          case HANGUP:
13360             p->fake_event = DAHDI_EVENT_ONHOOK;
13361             break;
13362          default:
13363             ast_log(LOG_WARNING, "I don't know how to handle transfer event with this: %d on channel %s\n",mode, p->owner->name);   
13364       }
13365    }
13366    return 0;
13367 }
13368 static struct dahdi_pvt *find_channel(int channel)
13369 {
13370    struct dahdi_pvt *p = iflist;
13371    while (p) {
13372       if (p->channel == channel) {
13373          break;
13374       }
13375       p = p->next;
13376    }
13377    return p;
13378 }
13379 
13380 static int action_dahdidndon(struct mansession *s, const struct message *m)
13381 {
13382    struct dahdi_pvt *p = NULL;
13383    const char *channel = astman_get_header(m, "DAHDIChannel");
13384 
13385    if (ast_strlen_zero(channel)) {
13386       astman_send_error(s, m, "No channel specified");
13387       return 0;
13388    }
13389    p = find_channel(atoi(channel));
13390    if (!p) {
13391       astman_send_error(s, m, "No such channel");
13392       return 0;
13393    }
13394    p->dnd = 1;
13395    astman_send_ack(s, m, "DND Enabled");
13396    return 0;
13397 }
13398 
13399 static int action_dahdidndoff(struct mansession *s, const struct message *m)
13400 {
13401    struct dahdi_pvt *p = NULL;
13402    const char *channel = astman_get_header(m, "DAHDIChannel");
13403 
13404    if (ast_strlen_zero(channel)) {
13405       astman_send_error(s, m, "No channel specified");
13406       return 0;
13407    }
13408    p = find_channel(atoi(channel));
13409    if (!p) {
13410       astman_send_error(s, m, "No such channel");
13411       return 0;
13412    }
13413    p->dnd = 0;
13414    astman_send_ack(s, m, "DND Disabled");
13415    return 0;
13416 }
13417 
13418 static int action_transfer(struct mansession *s, const struct message *m)
13419 {
13420    struct dahdi_pvt *p = NULL;
13421    const char *channel = astman_get_header(m, "DAHDIChannel");
13422 
13423    if (ast_strlen_zero(channel)) {
13424       astman_send_error(s, m, "No channel specified");
13425       return 0;
13426    }
13427    p = find_channel(atoi(channel));
13428    if (!p) {
13429       astman_send_error(s, m, "No such channel");
13430       return 0;
13431    }
13432    dahdi_fake_event(p,TRANSFER);
13433    astman_send_ack(s, m, "DAHDITransfer");
13434    return 0;
13435 }
13436 
13437 static int action_transferhangup(struct mansession *s, const struct message *m)
13438 {
13439    struct dahdi_pvt *p = NULL;
13440    const char *channel = astman_get_header(m, "DAHDIChannel");
13441 
13442    if (ast_strlen_zero(channel)) {
13443       astman_send_error(s, m, "No channel specified");
13444       return 0;
13445    }
13446    p = find_channel(atoi(channel));
13447    if (!p) {
13448       astman_send_error(s, m, "No such channel");
13449       return 0;
13450    }
13451    dahdi_fake_event(p,HANGUP);
13452    astman_send_ack(s, m, "DAHDIHangup");
13453    return 0;
13454 }
13455 
13456 static int action_dahdidialoffhook(struct mansession *s, const struct message *m)
13457 {
13458    struct dahdi_pvt *p = NULL;
13459    const char *channel = astman_get_header(m, "DAHDIChannel");
13460    const char *number = astman_get_header(m, "Number");
13461    int i;
13462 
13463    if (ast_strlen_zero(channel)) {
13464       astman_send_error(s, m, "No channel specified");
13465       return 0;
13466    }
13467    if (ast_strlen_zero(number)) {
13468       astman_send_error(s, m, "No number specified");
13469       return 0;
13470    }
13471    p = find_channel(atoi(channel));
13472    if (!p) {
13473       astman_send_error(s, m, "No such channel");
13474       return 0;
13475    }
13476    if (!p->owner) {
13477       astman_send_error(s, m, "Channel does not have it's owner");
13478       return 0;
13479    }
13480    for (i = 0; i < strlen(number); i++) {
13481       struct ast_frame f = { AST_FRAME_DTMF, number[i] };
13482       dahdi_queue_frame(p, &f, NULL); 
13483    }
13484    astman_send_ack(s, m, "DAHDIDialOffhook");
13485    return 0;
13486 }
13487 
13488 static int action_dahdishowchannels(struct mansession *s, const struct message *m)
13489 {
13490    struct dahdi_pvt *tmp = NULL;
13491    const char *id = astman_get_header(m, "ActionID");
13492    const char *dahdichannel = astman_get_header(m, "DAHDIChannel");
13493    char idText[256] = "";
13494    int channels = 0;
13495    int dahdichanquery = -1;
13496    if (!ast_strlen_zero(dahdichannel)) {
13497       dahdichanquery = atoi(dahdichannel);
13498    }
13499 
13500    astman_send_ack(s, m, "DAHDI channel status will follow");
13501    if (!ast_strlen_zero(id))
13502       snprintf(idText, sizeof(idText), "ActionID: %s\r\n", id);
13503 
13504    ast_mutex_lock(&iflock);
13505    
13506    tmp = iflist;
13507    while (tmp) {
13508       if (tmp->channel > 0) {
13509          int alm = get_alarms(tmp);
13510 
13511          /* If a specific channel is queried for, only deliver status for that channel */
13512          if (dahdichanquery > 0 && tmp->channel != dahdichanquery)
13513             continue;
13514 
13515          channels++;
13516          if (tmp->owner) {
13517             /* Add data if we have a current call */
13518             astman_append(s,
13519                "Event: DAHDIShowChannels\r\n"
13520                "DAHDIChannel: %d\r\n"
13521                "Channel: %s\r\n"
13522                "Uniqueid: %s\r\n"
13523                "AccountCode: %s\r\n"
13524                "Signalling: %s\r\n"
13525                "SignallingCode: %d\r\n"
13526                "Context: %s\r\n"
13527                "DND: %s\r\n"
13528                "Alarm: %s\r\n"
13529                "%s"
13530                "\r\n",
13531                tmp->channel, 
13532                tmp->owner->name,
13533                tmp->owner->uniqueid,
13534                tmp->owner->accountcode,
13535                sig2str(tmp->sig), 
13536                tmp->sig,
13537                tmp->context, 
13538                tmp->dnd ? "Enabled" : "Disabled",
13539                alarm2str(alm), idText);
13540          } else {
13541             astman_append(s,
13542                "Event: DAHDIShowChannels\r\n"
13543                "DAHDIChannel: %d\r\n"
13544                "Signalling: %s\r\n"
13545                "SignallingCode: %d\r\n"
13546                "Context: %s\r\n"
13547                "DND: %s\r\n"
13548                "Alarm: %s\r\n"
13549                "%s"
13550                "\r\n",
13551                tmp->channel, sig2str(tmp->sig), tmp->sig, 
13552                tmp->context, 
13553                tmp->dnd ? "Enabled" : "Disabled",
13554                alarm2str(alm), idText);
13555          }
13556       } 
13557 
13558       tmp = tmp->next;
13559    }
13560 
13561    ast_mutex_unlock(&iflock);
13562    
13563    astman_append(s, 
13564       "Event: DAHDIShowChannelsComplete\r\n"
13565       "%s"
13566       "Items: %d\r\n"
13567       "\r\n", 
13568       idText,
13569       channels);
13570    return 0;
13571 }
13572 
13573 #ifdef HAVE_SS7
13574 static int linkset_addsigchan(int sigchan)
13575 {
13576    struct dahdi_ss7 *link;
13577    int res;
13578    int curfd;
13579    struct dahdi_params p;
13580    struct dahdi_bufferinfo bi;
13581    struct dahdi_spaninfo si;
13582 
13583 
13584    link = ss7_resolve_linkset(cur_linkset);
13585    if (!link) {
13586       ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
13587       return -1;
13588    }
13589 
13590    if (cur_ss7type < 0) {
13591       ast_log(LOG_ERROR, "Unspecified or invalid ss7type\n");
13592       return -1;
13593    }
13594 
13595    if (!link->ss7)
13596       link->ss7 = ss7_new(cur_ss7type);
13597 
13598    if (!link->ss7) {
13599       ast_log(LOG_ERROR, "Can't create new SS7!\n");
13600       return -1;
13601    }
13602 
13603    link->type = cur_ss7type;
13604 
13605    if (cur_pointcode < 0) {
13606       ast_log(LOG_ERROR, "Unspecified pointcode!\n");
13607       return -1;
13608    } else
13609       ss7_set_pc(link->ss7, cur_pointcode);
13610 
13611    if (sigchan < 0) {
13612       ast_log(LOG_ERROR, "Invalid sigchan!\n");
13613       return -1;
13614    } else {
13615       if (link->numsigchans >= NUM_DCHANS) {
13616          ast_log(LOG_ERROR, "Too many sigchans on linkset %d\n", cur_linkset);
13617          return -1;
13618       }
13619       curfd = link->numsigchans;
13620 
13621       link->fds[curfd] = open("/dev/dahdi/channel", O_RDWR, 0600);
13622       if ((link->fds[curfd] < 0) || (ioctl(link->fds[curfd],DAHDI_SPECIFY,&sigchan) == -1)) {
13623          ast_log(LOG_ERROR, "Unable to open SS7 sigchan %d (%s)\n", sigchan, strerror(errno));
13624          return -1;
13625       }
13626       memset(&p, 0, sizeof(p));
13627       res = ioctl(link->fds[curfd], DAHDI_GET_PARAMS, &p);
13628       if (res) {
13629          dahdi_close_ss7_fd(link, curfd);
13630          ast_log(LOG_ERROR, "Unable to get parameters for sigchan %d (%s)\n", sigchan, strerror(errno));
13631          return -1;
13632       }
13633       if ((p.sigtype != DAHDI_SIG_HDLCFCS) && (p.sigtype != DAHDI_SIG_HARDHDLC) && (p.sigtype != DAHDI_SIG_MTP2)) {
13634          dahdi_close_ss7_fd(link, curfd);
13635          ast_log(LOG_ERROR, "sigchan %d is not in HDLC/FCS mode.\n", sigchan);
13636          return -1;
13637       }
13638 
13639       memset(&bi, 0, sizeof(bi));
13640       bi.txbufpolicy = DAHDI_POLICY_IMMEDIATE;
13641       bi.rxbufpolicy = DAHDI_POLICY_IMMEDIATE;
13642       bi.numbufs = 32;
13643       bi.bufsize = 512;
13644 
13645       if (ioctl(link->fds[curfd], DAHDI_SET_BUFINFO, &bi)) {
13646          ast_log(LOG_ERROR, "Unable to set appropriate buffering on channel %d: %s\n", sigchan, strerror(errno));
13647          dahdi_close_ss7_fd(link, curfd);
13648          return -1;
13649       }
13650 
13651       if (p.sigtype == DAHDI_SIG_MTP2)
13652          ss7_add_link(link->ss7, SS7_TRANSPORT_DAHDIMTP2, link->fds[curfd]);
13653       else
13654          ss7_add_link(link->ss7, SS7_TRANSPORT_DAHDIDCHAN, link->fds[curfd]);
13655 
13656       link->numsigchans++;
13657 
13658       memset(&si, 0, sizeof(si));
13659       res = ioctl(link->fds[curfd], DAHDI_SPANSTAT, &si);
13660       if (res) {
13661          dahdi_close_ss7_fd(link, curfd);
13662          ast_log(LOG_ERROR, "Unable to get span state for sigchan %d (%s)\n", sigchan, strerror(errno));
13663       }
13664 
13665       if (!si.alarms) {
13666          link->linkstate[curfd] = LINKSTATE_DOWN;
13667          ss7_link_noalarm(link->ss7, link->fds[curfd]);
13668       } else {
13669          link->linkstate[curfd] = LINKSTATE_DOWN | LINKSTATE_INALARM;
13670          ss7_link_alarm(link->ss7, link->fds[curfd]);
13671       }
13672    }
13673 
13674    if (cur_adjpointcode < 0) {
13675       ast_log(LOG_ERROR, "Unspecified adjpointcode!\n");
13676       return -1;
13677    } else {
13678       ss7_set_adjpc(link->ss7, link->fds[curfd], cur_adjpointcode);
13679    }
13680 
13681    if (cur_defaultdpc < 0) {
13682       ast_log(LOG_ERROR, "Unspecified defaultdpc!\n");
13683       return -1;
13684    }
13685 
13686    if (cur_networkindicator < 0) {
13687       ast_log(LOG_ERROR, "Invalid networkindicator!\n");
13688       return -1;
13689    } else
13690       ss7_set_network_ind(link->ss7, cur_networkindicator);
13691 
13692    return 0;
13693 }
13694 
13695 static char *handle_ss7_no_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13696 {
13697    int span;
13698    switch (cmd) {
13699    case CLI_INIT:
13700       e->command = "ss7 no debug linkset";
13701       e->usage = 
13702          "Usage: ss7 no debug linkset <span>\n"
13703          "       Disables debugging on a given SS7 linkset\n";
13704       return NULL;
13705    case CLI_GENERATE:
13706       return NULL;
13707    }
13708    if (a->argc < 5)
13709       return CLI_SHOWUSAGE;
13710    span = atoi(a->argv[4]);
13711    if ((span < 1) || (span > NUM_SPANS)) {
13712       ast_cli(a->fd, "Invalid linkset %s.  Should be a number from %d to %d\n", a->argv[4], 1, NUM_SPANS);
13713       return CLI_SUCCESS;
13714    }
13715    if (!linksets[span-1].ss7) {
13716       ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
13717       return CLI_SUCCESS;
13718    }
13719    if (linksets[span-1].ss7)
13720       ss7_set_debug(linksets[span-1].ss7, 0);
13721 
13722    ast_cli(a->fd, "Disabled debugging on linkset %d\n", span);
13723    return CLI_SUCCESS;
13724 }
13725 
13726 static char *handle_ss7_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13727 {
13728    int span;
13729    switch (cmd) {
13730    case CLI_INIT:
13731       e->command = "ss7 debug linkset";
13732       e->usage = 
13733          "Usage: ss7 debug linkset <linkset>\n"
13734          "       Enables debugging on a given SS7 linkset\n";
13735       return NULL;
13736    case CLI_GENERATE:
13737       return NULL;
13738    }
13739    if (a->argc < 4)
13740       return CLI_SHOWUSAGE;
13741    span = atoi(a->argv[3]);
13742    if ((span < 1) || (span > NUM_SPANS)) {
13743       ast_cli(a->fd, "Invalid linkset %s.  Should be a number from %d to %d\n", a->argv[3], 1, NUM_SPANS);
13744       return CLI_SUCCESS;
13745    }
13746    if (!linksets[span-1].ss7) {
13747       ast_cli(a->fd, "No SS7 running on linkset %d\n", span);
13748       return CLI_SUCCESS;
13749    }
13750    if (linksets[span-1].ss7)
13751       ss7_set_debug(linksets[span-1].ss7, SS7_DEBUG_MTP2 | SS7_DEBUG_MTP3 | SS7_DEBUG_ISUP);
13752 
13753    ast_cli(a->fd, "Enabled debugging on linkset %d\n", span);
13754    return CLI_SUCCESS;
13755 }
13756 
13757 static char *handle_ss7_block_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13758 {
13759    int linkset, cic;
13760    int blocked = -1, i;
13761    switch (cmd) {
13762    case CLI_INIT:
13763       e->command = "ss7 block cic";
13764       e->usage = 
13765          "Usage: ss7 block cic <linkset> <CIC>\n"
13766          "       Sends a remote blocking request for the given CIC on the specified linkset\n";
13767       return NULL;
13768    case CLI_GENERATE:
13769       return NULL;
13770    }
13771    if (a->argc == 5)
13772       linkset = atoi(a->argv[3]);
13773    else
13774       return CLI_SHOWUSAGE;
13775 
13776    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13777       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13778       return CLI_SUCCESS;
13779    }
13780 
13781    if (!linksets[linkset-1].ss7) {
13782       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13783       return CLI_SUCCESS;
13784    }
13785 
13786    cic = atoi(a->argv[4]);
13787 
13788    if (cic < 1) {
13789       ast_cli(a->fd, "Invalid CIC specified!\n");
13790       return CLI_SUCCESS;
13791    }
13792 
13793    for (i = 0; i < linksets[linkset-1].numchans; i++) {
13794       if (linksets[linkset-1].pvts[i]->cic == cic) {
13795          blocked = linksets[linkset-1].pvts[i]->locallyblocked;
13796          if (!blocked) {
13797             ast_mutex_lock(&linksets[linkset-1].lock);
13798             isup_blo(linksets[linkset-1].ss7, cic, linksets[linkset-1].pvts[i]->dpc);
13799             ast_mutex_unlock(&linksets[linkset-1].lock);
13800          }
13801       }
13802    }
13803 
13804    if (blocked < 0) {
13805       ast_cli(a->fd, "Invalid CIC specified!\n");
13806       return CLI_SUCCESS;
13807    }
13808 
13809    if (!blocked)
13810       ast_cli(a->fd, "Sent blocking request for linkset %d on CIC %d\n", linkset, cic);
13811    else
13812       ast_cli(a->fd, "CIC %d already locally blocked\n", cic);
13813 
13814    /* Break poll on the linkset so it sends our messages */
13815    pthread_kill(linksets[linkset-1].master, SIGURG);
13816 
13817    return CLI_SUCCESS;
13818 }
13819 
13820 static char *handle_ss7_block_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13821 {
13822    int linkset;
13823    int i;
13824    switch (cmd) {
13825    case CLI_INIT:
13826       e->command = "ss7 block linkset";
13827       e->usage = 
13828          "Usage: ss7 block linkset <linkset number>\n"
13829          "       Sends a remote blocking request for all CICs on the given linkset\n";
13830       return NULL;
13831    case CLI_GENERATE:
13832       return NULL;
13833    }
13834    if (a->argc == 4)
13835       linkset = atoi(a->argv[3]);
13836    else
13837       return CLI_SHOWUSAGE;
13838 
13839    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13840       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13841       return CLI_SUCCESS;
13842    }
13843 
13844    if (!linksets[linkset-1].ss7) {
13845       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13846       return CLI_SUCCESS;
13847    }
13848 
13849    for (i = 0; i < linksets[linkset-1].numchans; i++) {
13850       ast_cli(a->fd, "Sending remote blocking request on CIC %d\n", linksets[linkset-1].pvts[i]->cic);
13851       ast_mutex_lock(&linksets[linkset-1].lock);
13852       isup_blo(linksets[linkset-1].ss7, linksets[linkset-1].pvts[i]->cic, linksets[linkset-1].pvts[i]->dpc);
13853       ast_mutex_unlock(&linksets[linkset-1].lock);
13854    }
13855 
13856    /* Break poll on the linkset so it sends our messages */
13857    pthread_kill(linksets[linkset-1].master, SIGURG);
13858 
13859    return CLI_SUCCESS;
13860 }
13861 
13862 static char *handle_ss7_unblock_cic(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13863 {
13864    int linkset, cic;
13865    int i, blocked = -1;
13866    switch (cmd) {
13867    case CLI_INIT:
13868       e->command = "ss7 unblock cic";
13869       e->usage = 
13870          "Usage: ss7 unblock cic <linkset> <CIC>\n"
13871          "       Sends a remote unblocking request for the given CIC on the specified linkset\n";
13872       return NULL;
13873    case CLI_GENERATE:
13874       return NULL;
13875    }
13876 
13877    if (a->argc == 5)
13878       linkset = atoi(a->argv[3]);
13879    else
13880       return CLI_SHOWUSAGE;
13881 
13882    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13883       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13884       return CLI_SUCCESS;
13885    }
13886 
13887    if (!linksets[linkset-1].ss7) {
13888       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13889       return CLI_SUCCESS;
13890    }
13891 
13892    cic = atoi(a->argv[4]);
13893 
13894    if (cic < 1) {
13895       ast_cli(a->fd, "Invalid CIC specified!\n");
13896       return CLI_SUCCESS;
13897    }
13898 
13899    for (i = 0; i < linksets[linkset-1].numchans; i++) {
13900       if (linksets[linkset-1].pvts[i]->cic == cic) {
13901          blocked = linksets[linkset-1].pvts[i]->locallyblocked;
13902          if (blocked) {
13903             ast_mutex_lock(&linksets[linkset-1].lock);
13904             isup_ubl(linksets[linkset-1].ss7, cic, linksets[linkset-1].pvts[i]->dpc);
13905             ast_mutex_unlock(&linksets[linkset-1].lock);
13906          }
13907       }
13908    }
13909 
13910    if (blocked > 0)
13911       ast_cli(a->fd, "Sent unblocking request for linkset %d on CIC %d\n", linkset, cic);
13912 
13913    /* Break poll on the linkset so it sends our messages */
13914    pthread_kill(linksets[linkset-1].master, SIGURG);
13915 
13916    return CLI_SUCCESS;
13917 }
13918 
13919 static char *handle_ss7_unblock_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13920 {
13921    int linkset;
13922    int i;
13923    switch (cmd) {
13924    case CLI_INIT:
13925       e->command = "ss7 unblock linkset";
13926       e->usage = 
13927          "Usage: ss7 unblock linkset <linkset number>\n"
13928          "       Sends a remote unblocking request for all CICs on the specified linkset\n";
13929       return NULL;
13930    case CLI_GENERATE:
13931       return NULL;
13932    }
13933 
13934    if (a->argc == 4)
13935       linkset = atoi(a->argv[3]);
13936    else
13937       return CLI_SHOWUSAGE;
13938 
13939    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13940       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13941       return CLI_SUCCESS;
13942    }
13943 
13944    if (!linksets[linkset-1].ss7) {
13945       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13946       return CLI_SUCCESS;
13947    }
13948 
13949    for (i = 0; i < linksets[linkset-1].numchans; i++) {
13950       ast_cli(a->fd, "Sending remote unblock request on CIC %d\n", linksets[linkset-1].pvts[i]->cic);
13951       ast_mutex_lock(&linksets[linkset-1].lock);
13952       isup_ubl(linksets[linkset-1].ss7, linksets[linkset-1].pvts[i]->cic, linksets[linkset-1].pvts[i]->dpc);
13953       ast_mutex_unlock(&linksets[linkset-1].lock);
13954    }
13955 
13956    /* Break poll on the linkset so it sends our messages */
13957    pthread_kill(linksets[linkset-1].master, SIGURG);
13958 
13959    return CLI_SUCCESS;
13960 }
13961 
13962 static char *handle_ss7_show_linkset(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13963 {
13964    int linkset;
13965    struct dahdi_ss7 *ss7;
13966    switch (cmd) {
13967    case CLI_INIT:
13968       e->command = "ss7 show linkset";
13969       e->usage = 
13970          "Usage: ss7 show linkset <span>\n"
13971          "       Shows the status of an SS7 linkset.\n";
13972       return NULL;
13973    case CLI_GENERATE:
13974       return NULL;
13975    }
13976 
13977    if (a->argc < 4)
13978       return CLI_SHOWUSAGE;
13979    linkset = atoi(a->argv[3]);
13980    if ((linkset < 1) || (linkset > NUM_SPANS)) {
13981       ast_cli(a->fd, "Invalid linkset %s.  Should be a number %d to %d\n", a->argv[3], 1, NUM_SPANS);
13982       return CLI_SUCCESS;
13983    }
13984    if (!linksets[linkset-1].ss7) {
13985       ast_cli(a->fd, "No SS7 running on linkset %d\n", linkset);
13986       return CLI_SUCCESS;
13987    }
13988    if (linksets[linkset-1].ss7)
13989       ss7 = &linksets[linkset-1];
13990 
13991    ast_cli(a->fd, "SS7 linkset %d status: %s\n", linkset, (ss7->state == LINKSET_STATE_UP) ? "Up" : "Down");
13992 
13993    return CLI_SUCCESS;
13994 }
13995 
13996 static char *handle_ss7_version(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
13997 {
13998    switch (cmd) {
13999    case CLI_INIT:
14000       e->command = "ss7 show version";
14001       e->usage = 
14002          "Usage: ss7 show version\n"
14003          "  Show the libss7 version\n";
14004       return NULL;
14005    case CLI_GENERATE:
14006       return NULL;
14007    }
14008 
14009    ast_cli(a->fd, "libss7 version: %s\n", ss7_get_version());
14010 
14011    return CLI_SUCCESS;
14012 }
14013 
14014 static struct ast_cli_entry dahdi_ss7_cli[] = {
14015    AST_CLI_DEFINE(handle_ss7_debug, "Enables SS7 debugging on a linkset"), 
14016    AST_CLI_DEFINE(handle_ss7_no_debug, "Disables SS7 debugging on a linkset"), 
14017    AST_CLI_DEFINE(handle_ss7_block_cic, "Blocks the given CIC"),
14018    AST_CLI_DEFINE(handle_ss7_unblock_cic, "Unblocks the given CIC"),
14019    AST_CLI_DEFINE(handle_ss7_block_linkset, "Blocks all CICs on a linkset"),
14020    AST_CLI_DEFINE(handle_ss7_unblock_linkset, "Unblocks all CICs on a linkset"),
14021    AST_CLI_DEFINE(handle_ss7_show_linkset, "Shows the status of a linkset"),
14022    AST_CLI_DEFINE(handle_ss7_version, "Displays libss7 version"),
14023 };
14024 #endif /* HAVE_SS7 */
14025 
14026 static int __unload_module(void)
14027 {
14028    struct dahdi_pvt *p;
14029 #if defined(HAVE_PRI) || defined(HAVE_SS7)
14030    int i, j;
14031 #endif
14032 
14033 #ifdef HAVE_PRI
14034    for (i = 0; i < NUM_SPANS; i++) {
14035       if (pris[i].master != AST_PTHREADT_NULL) 
14036          pthread_cancel(pris[i].master);
14037    }
14038    ast_cli_unregister_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
14039    ast_unregister_application(dahdi_send_keypad_facility_app);
14040 #endif
14041 #if defined(HAVE_SS7)
14042    for (i = 0; i < NUM_SPANS; i++) {
14043       if (linksets[i].master != AST_PTHREADT_NULL)
14044          pthread_cancel(linksets[i].master);
14045       }
14046    ast_cli_unregister_multiple(dahdi_ss7_cli, sizeof(dahdi_ss7_cli) / sizeof(struct ast_cli_entry));
14047 #endif
14048 
14049    ast_cli_unregister_multiple(dahdi_cli, sizeof(dahdi_cli) / sizeof(struct ast_cli_entry));
14050    ast_manager_unregister( "DAHDIDialOffhook" );
14051    ast_manager_unregister( "DAHDIHangup" );
14052    ast_manager_unregister( "DAHDITransfer" );
14053    ast_manager_unregister( "DAHDIDNDoff" );
14054    ast_manager_unregister( "DAHDIDNDon" );
14055    ast_manager_unregister("DAHDIShowChannels");
14056    ast_manager_unregister("DAHDIRestart");
14057    ast_channel_unregister(&dahdi_tech);
14058    ast_mutex_lock(&iflock);
14059    /* Hangup all interfaces if they have an owner */
14060    p = iflist;
14061    while (p) {
14062       if (p->owner)
14063          ast_softhangup(p->owner, AST_SOFTHANGUP_APPUNLOAD);
14064       p = p->next;
14065    }
14066    ast_mutex_unlock(&iflock);
14067    ast_mutex_lock(&monlock);
14068    if (monitor_thread && (monitor_thread != AST_PTHREADT_STOP) && (monitor_thread != AST_PTHREADT_NULL)) {
14069       pthread_cancel(monitor_thread);
14070       pthread_kill(monitor_thread, SIGURG);
14071       pthread_join(monitor_thread, NULL);
14072    }
14073    monitor_thread = AST_PTHREADT_STOP;
14074    ast_mutex_unlock(&monlock);
14075 
14076    destroy_all_channels();
14077 
14078 #if defined(HAVE_PRI)
14079    for (i = 0; i < NUM_SPANS; i++) {
14080       if (pris[i].master && (pris[i].master != AST_PTHREADT_NULL))
14081          pthread_join(pris[i].master, NULL);
14082       for (j = 0; j < NUM_DCHANS; j++) {
14083          dahdi_close_pri_fd(&(pris[i]), j);
14084       }
14085    }
14086 #endif
14087 
14088 #if defined(HAVE_SS7)
14089    for (i = 0; i < NUM_SPANS; i++) {
14090       if (linksets[i].master && (linksets[i].master != AST_PTHREADT_NULL))
14091          pthread_join(linksets[i].master, NULL);
14092       for (j = 0; j < NUM_DCHANS; j++) {
14093          dahdi_close_ss7_fd(&(linksets[i]), j);
14094       }
14095    }
14096 #endif
14097 
14098    ast_cond_destroy(&mwi_thread_complete);
14099    ast_cond_destroy(&ss_thread_complete);
14100    return 0;
14101 }
14102 
14103 static int unload_module(void)
14104 {
14105 #if defined(HAVE_PRI) || defined(HAVE_SS7)
14106    int y;
14107 #endif
14108 #ifdef HAVE_PRI
14109    for (y = 0; y < NUM_SPANS; y++)
14110       ast_mutex_destroy(&pris[y].lock);
14111 #endif
14112 #ifdef HAVE_SS7
14113    for (y = 0; y < NUM_SPANS; y++)
14114       ast_mutex_destroy(&linksets[y].lock);
14115 #endif /* HAVE_SS7 */
14116    return __unload_module();
14117 }
14118 
14119 static int build_channels(struct dahdi_chan_conf *conf, int iscrv, const char *value, int reload, int lineno, int *found_pseudo)
14120 {
14121    char *c, *chan;
14122    int x, start, finish;
14123    struct dahdi_pvt *tmp;
14124 #ifdef HAVE_PRI
14125    struct dahdi_pri *pri;
14126    int trunkgroup, y;
14127 #endif
14128    
14129    if ((reload == 0) && (conf->chan.sig < 0) && !conf->is_sig_auto) {
14130       ast_log(LOG_ERROR, "Signalling must be specified before any channels are.\n");
14131       return -1;
14132    }
14133 
14134    c = ast_strdupa(value);
14135 
14136 #ifdef HAVE_PRI
14137    pri = NULL;
14138    if (iscrv) {
14139       if (sscanf(c, "%30d:%n", &trunkgroup, &y) != 1) {
14140          ast_log(LOG_WARNING, "CRV must begin with trunkgroup followed by a colon at line %d.\n", lineno);
14141          return -1;
14142       }
14143       if (trunkgroup < 1) {
14144          ast_log(LOG_WARNING, "CRV trunk group must be a positive number at line %d.\n", lineno);
14145          return -1;
14146       }
14147       c += y;
14148       for (y = 0; y < NUM_SPANS; y++) {
14149          if (pris[y].trunkgroup == trunkgroup) {
14150             pri = pris + y;
14151             break;
14152          }
14153       }
14154       if (!pri) {
14155          ast_log(LOG_WARNING, "No such trunk group %d at CRV declaration at line %d.\n", trunkgroup, lineno);
14156          return -1;
14157       }
14158    }
14159 #endif         
14160 
14161    while ((chan = strsep(&c, ","))) {
14162       if (sscanf(chan, "%30d-%30d", &start, &finish) == 2) {
14163          /* Range */
14164       } else if (sscanf(chan, "%30d", &start)) {
14165          /* Just one */
14166          finish = start;
14167       } else if (!strcasecmp(chan, "pseudo")) {
14168          finish = start = CHAN_PSEUDO;
14169          if (found_pseudo)
14170             *found_pseudo = 1;
14171       } else {
14172          ast_log(LOG_ERROR, "Syntax error parsing '%s' at '%s'\n", value, chan);
14173          return -1;
14174       }
14175       if (finish < start) {
14176          ast_log(LOG_WARNING, "Sillyness: %d < %d\n", start, finish);
14177          x = finish;
14178          finish = start;
14179          start = x;
14180       }
14181 
14182       for (x = start; x <= finish; x++) {
14183 #ifdef HAVE_PRI
14184          tmp = mkintf(x, conf, pri, reload);
14185 #else       
14186          tmp = mkintf(x, conf, NULL, reload);
14187 #endif         
14188 
14189          if (tmp) {
14190 #ifdef HAVE_PRI
14191                if (pri)
14192                ast_verb(3, "%s CRV %d:%d, %s signalling\n", reload ? "Reconfigured" : "Registered", trunkgroup, x, sig2str(tmp->sig));
14193                else
14194 #endif
14195                ast_verb(3, "%s channel %d, %s signalling\n", reload ? "Reconfigured" : "Registered", x, sig2str(tmp->sig));
14196          } else {
14197             ast_log(LOG_ERROR, "Unable to %s channel '%s'\n",
14198                (reload == 1) ? "reconfigure" : "register", value);
14199             return -1;
14200          }
14201       }
14202    }
14203 
14204    return 0;
14205 }
14206 
14207 /** The length of the parameters list of 'dahdichan'. 
14208  * \todo Move definition of MAX_CHANLIST_LEN to a proper place. */
14209 #define MAX_CHANLIST_LEN 80
14210 
14211 static void process_echocancel(struct dahdi_chan_conf *confp, const char *data, unsigned int line)
14212 {
14213    char *parse = ast_strdupa(data);
14214    char *params[DAHDI_MAX_ECHOCANPARAMS + 1];
14215    unsigned int param_count;
14216    unsigned int x;
14217 
14218    if (!(param_count = ast_app_separate_args(parse, ',', params, ARRAY_LEN(params))))
14219       return;
14220 
14221    memset(&confp->chan.echocancel, 0, sizeof(confp->chan.echocancel));
14222 
14223    /* first parameter is tap length, process it here */
14224 
14225    x = ast_strlen_zero(params[0]) ? 0 : atoi(params[0]);
14226    
14227    if ((x == 32) || (x == 64) || (x == 128) || (x == 256) || (x == 512) || (x == 1024))
14228       confp->chan.echocancel.head.tap_length = x;
14229    else if ((confp->chan.echocancel.head.tap_length = ast_true(params[0])))
14230       confp->chan.echocancel.head.tap_length = 128;
14231 
14232    /* now process any remaining parameters */
14233 
14234    for (x = 1; x < param_count; x++) {
14235       struct {
14236          char *name;
14237          char *value;
14238       } param;
14239 
14240       if (ast_app_separate_args(params[x], '=', (char **) &param, 2) < 1) {
14241          ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %d: '%s'\n", line, params[x]);
14242          continue;
14243       }
14244 
14245       if (ast_strlen_zero(param.name) || (strlen(param.name) > sizeof(confp->chan.echocancel.params[0].name)-1)) {
14246          ast_log(LOG_WARNING, "Invalid echocancel parameter supplied at line %d: '%s'\n", line, param.name);
14247          continue;
14248       }
14249 
14250       strcpy(confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].name, param.name);
14251 
14252       if (param.value) {
14253          if (sscanf(param.value, "%30d", &confp->chan.echocancel.params[confp->chan.echocancel.head.param_count].value) != 1) {
14254             ast_log(LOG_WARNING, "Invalid echocancel parameter value supplied at line %d: '%s'\n", line, param.value);
14255             continue;
14256          }
14257       }
14258       confp->chan.echocancel.head.param_count++;
14259    }
14260 }
14261 
14262 /*! process_dahdi() - ignore keyword 'channel' and similar */
14263 #define PROC_DAHDI_OPT_NOCHAN  (1 << 0) 
14264 /*! process_dahdi() - No warnings on non-existing cofiguration keywords */
14265 #define PROC_DAHDI_OPT_NOWARN  (1 << 1) 
14266 
14267 static int process_dahdi(struct dahdi_chan_conf *confp, const char *cat, struct ast_variable *v, int reload, int options)
14268 {
14269    struct dahdi_pvt *tmp;
14270    int y;
14271    int found_pseudo = 0;
14272    char dahdichan[MAX_CHANLIST_LEN] = {};
14273 
14274    for (; v; v = v->next) {
14275       if (!ast_jb_read_conf(&global_jbconf, v->name, v->value))
14276          continue;
14277 
14278       /* must have parkinglot in confp before build_channels is called */
14279       if (!strcasecmp(v->name, "parkinglot")) {
14280          ast_copy_string(confp->chan.parkinglot, v->value, sizeof(confp->chan.parkinglot));
14281       }
14282 
14283       /* Create the interface list */
14284       if (!strcasecmp(v->name, "channel")
14285 #ifdef HAVE_PRI
14286           || !strcasecmp(v->name, "crv")
14287 #endif         
14288          ) {
14289          int iscrv;
14290          if (options & PROC_DAHDI_OPT_NOCHAN) {
14291             ast_log(LOG_WARNING, "Channel '%s' ignored.\n", v->value);
14292             continue;
14293          }
14294          iscrv = !strcasecmp(v->name, "crv");
14295          if (build_channels(confp, iscrv, v->value, reload, v->lineno, &found_pseudo))
14296                return -1;
14297          ast_log(LOG_DEBUG, "Channel '%s' configured.\n", v->value);
14298       } else if (!strcasecmp(v->name, "buffers")) {
14299          int res;
14300          char policy[21] = "";
14301 
14302          res = sscanf(v->value, "%30d,%20s", &confp->chan.buf_no, policy);
14303          if (res != 2) {
14304             ast_log(LOG_WARNING, "Parsing buffers option data failed, using defaults.\n");
14305             confp->chan.buf_no = numbufs;
14306             continue;
14307          }
14308          if (confp->chan.buf_no < 0)
14309             confp->chan.buf_no = numbufs;
14310          if (!strcasecmp(policy, "full")) {
14311             confp->chan.buf_policy = DAHDI_POLICY_WHEN_FULL;
14312          } else if (!strcasecmp(policy, "immediate")) {
14313             confp->chan.buf_policy = DAHDI_POLICY_IMMEDIATE;
14314          } else {
14315             ast_log(LOG_WARNING, "Invalid policy name given (%s).\n", policy);
14316          }
14317       } else if (!strcasecmp(v->name, "dahdichan")) {
14318          ast_copy_string(dahdichan, v->value, sizeof(dahdichan));
14319       } else if (!strcasecmp(v->name, "usedistinctiveringdetection")) {
14320          usedistinctiveringdetection = ast_true(v->value);
14321       } else if (!strcasecmp(v->name, "distinctiveringaftercid")) {
14322          distinctiveringaftercid = ast_true(v->value);
14323       } else if (!strcasecmp(v->name, "dring1context")) {
14324          ast_copy_string(confp->chan.drings.ringContext[0].contextData,v->value,sizeof(confp->chan.drings.ringContext[0].contextData));
14325       } else if (!strcasecmp(v->name, "dring2context")) {
14326          ast_copy_string(confp->chan.drings.ringContext[1].contextData,v->value,sizeof(confp->chan.drings.ringContext[1].contextData));
14327       } else if (!strcasecmp(v->name, "dring3context")) {
14328          ast_copy_string(confp->chan.drings.ringContext[2].contextData,v->value,sizeof(confp->chan.drings.ringContext[2].contextData));
14329       } else if (!strcasecmp(v->name, "dring1range")) {
14330          confp->chan.drings.ringnum[0].range = atoi(v->value);
14331       } else if (!strcasecmp(v->name, "dring2range")) {
14332          confp->chan.drings.ringnum[1].range = atoi(v->value);
14333       } else if (!strcasecmp(v->name, "dring3range")) {
14334          confp->chan.drings.ringnum[2].range = atoi(v->value);
14335       } else if (!strcasecmp(v->name, "dring1")) {
14336          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]);
14337       } else if (!strcasecmp(v->name, "dring2")) {
14338          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]);
14339       } else if (!strcasecmp(v->name, "dring3")) {
14340          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]);
14341       } else if (!strcasecmp(v->name, "usecallerid")) {
14342          confp->chan.use_callerid = ast_true(v->value);
14343       } else if (!strcasecmp(v->name, "cidsignalling")) {
14344          if (!strcasecmp(v->value, "bell"))
14345             confp->chan.cid_signalling = CID_SIG_BELL;
14346          else if (!strcasecmp(v->value, "v23"))
14347             confp->chan.cid_signalling = CID_SIG_V23;
14348          else if (!strcasecmp(v->value, "dtmf"))
14349             confp->chan.cid_signalling = CID_SIG_DTMF;
14350          else if (!strcasecmp(v->value, "smdi"))
14351             confp->chan.cid_signalling = CID_SIG_SMDI;
14352          else if (!strcasecmp(v->value, "v23_jp"))
14353             confp->chan.cid_signalling = CID_SIG_V23_JP;
14354          else if (ast_true(v->value))
14355             confp->chan.cid_signalling = CID_SIG_BELL;
14356       } else if (!strcasecmp(v->name, "cidstart")) {
14357          if (!strcasecmp(v->value, "ring"))
14358             confp->chan.cid_start = CID_START_RING;
14359          else if (!strcasecmp(v->value, "polarity_in"))
14360             confp->chan.cid_start = CID_START_POLARITY_IN;
14361          else if (!strcasecmp(v->value, "polarity"))
14362             confp->chan.cid_start = CID_START_POLARITY;
14363          else if (ast_true(v->value))
14364             confp->chan.cid_start = CID_START_RING;
14365       } else if (!strcasecmp(v->name, "threewaycalling")) {
14366          confp->chan.threewaycalling = ast_true(v->value);
14367       } else if (!strcasecmp(v->name, "cancallforward")) {
14368          confp->chan.cancallforward = ast_true(v->value);
14369       } else if (!strcasecmp(v->name, "relaxdtmf")) {
14370          if (ast_true(v->value)) 
14371             confp->chan.dtmfrelax = DSP_DIGITMODE_RELAXDTMF;
14372          else
14373             confp->chan.dtmfrelax = 0;
14374       } else if (!strcasecmp(v->name, "mailbox")) {
14375          ast_copy_string(confp->chan.mailbox, v->value, sizeof(confp->chan.mailbox));
14376       } else if (!strcasecmp(v->name, "hasvoicemail")) {
14377          if (ast_true(v->value) && ast_strlen_zero(confp->chan.mailbox)) {
14378             ast_copy_string(confp->chan.mailbox, cat, sizeof(confp->chan.mailbox));
14379          }
14380       } else if (!strcasecmp(v->name, "adsi")) {
14381          confp->chan.adsi = ast_true(v->value);
14382       } else if (!strcasecmp(v->name, "usesmdi")) {
14383          confp->chan.use_smdi = ast_true(v->value);
14384       } else if (!strcasecmp(v->name, "smdiport")) {
14385          ast_copy_string(confp->smdi_port, v->value, sizeof(confp->smdi_port));
14386       } else if (!strcasecmp(v->name, "transfer")) {
14387          confp->chan.transfer = ast_true(v->value);
14388       } else if (!strcasecmp(v->name, "canpark")) {
14389          confp->chan.canpark = ast_true(v->value);
14390       } else if (!strcasecmp(v->name, "echocancelwhenbridged")) {
14391          confp->chan.echocanbridged = ast_true(v->value);
14392       } else if (!strcasecmp(v->name, "busydetect")) {
14393          confp->chan.busydetect = ast_true(v->value);
14394       } else if (!strcasecmp(v->name, "busycount")) {
14395          confp->chan.busycount = atoi(v->value);
14396       } else if (!strcasecmp(v->name, "busypattern")) {
14397          if (sscanf(v->value, "%30d,%30d", &confp->chan.busy_tonelength, &confp->chan.busy_quietlength) != 2) {
14398             ast_log(LOG_ERROR, "busypattern= expects busypattern=tonelength,quietlength at line %d.\n", v->lineno);
14399          }
14400       } else if (!strcasecmp(v->name, "callprogress")) {
14401          confp->chan.callprogress &= ~CALLPROGRESS_PROGRESS;
14402          if (ast_true(v->value))
14403             confp->chan.callprogress |= CALLPROGRESS_PROGRESS;
14404       } else if (!strcasecmp(v->name, "faxdetect")) {
14405          confp->chan.callprogress &= ~CALLPROGRESS_FAX;
14406          if (!strcasecmp(v->value, "incoming")) {
14407             confp->chan.callprogress |= CALLPROGRESS_FAX_INCOMING;
14408          } else if (!strcasecmp(v->value, "outgoing")) {
14409             confp->chan.callprogress |= CALLPROGRESS_FAX_OUTGOING;
14410          } else if (!strcasecmp(v->value, "both") || ast_true(v->value))
14411             confp->chan.callprogress |= CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING;
14412       } else if (!strcasecmp(v->name, "echocancel")) {
14413          process_echocancel(confp, v->value, v->lineno);
14414       } else if (!strcasecmp(v->name, "echotraining")) {
14415          if (sscanf(v->value, "%30d", &y) == 1) {
14416             if ((y < 10) || (y > 4000)) {
14417                ast_log(LOG_WARNING, "Echo training time must be within the range of 10 to 4000 ms at line %d.\n", v->lineno);             
14418             } else {
14419                confp->chan.echotraining = y;
14420             }
14421          } else if (ast_true(v->value)) {
14422             confp->chan.echotraining = 400;
14423          } else
14424             confp->chan.echotraining = 0;
14425       } else if (!strcasecmp(v->name, "hidecallerid")) {
14426          confp->chan.hidecallerid = ast_true(v->value);
14427       } else if (!strcasecmp(v->name, "hidecalleridname")) {
14428          confp->chan.hidecalleridname = ast_true(v->value);
14429       } else if (!strcasecmp(v->name, "pulsedial")) {
14430          confp->chan.pulse = ast_true(v->value);
14431       } else if (!strcasecmp(v->name, "callreturn")) {
14432          confp->chan.callreturn = ast_true(v->value);
14433       } else if (!strcasecmp(v->name, "callwaiting")) {
14434          confp->chan.callwaiting = ast_true(v->value);
14435       } else if (!strcasecmp(v->name, "callwaitingcallerid")) {
14436          confp->chan.callwaitingcallerid = ast_true(v->value);
14437       } else if (!strcasecmp(v->name, "context")) {
14438          ast_copy_string(confp->chan.context, v->value, sizeof(confp->chan.context));
14439       } else if (!strcasecmp(v->name, "language")) {
14440          ast_copy_string(confp->chan.language, v->value, sizeof(confp->chan.language));
14441       } else if (!strcasecmp(v->name, "progzone")) {
14442          ast_copy_string(progzone, v->value, sizeof(progzone));
14443       } else if (!strcasecmp(v->name, "mohinterpret") 
14444          ||!strcasecmp(v->name, "musiconhold") || !strcasecmp(v->name, "musicclass")) {
14445          ast_copy_string(confp->chan.mohinterpret, v->value, sizeof(confp->chan.mohinterpret));
14446       } else if (!strcasecmp(v->name, "mohsuggest")) {
14447          ast_copy_string(confp->chan.mohsuggest, v->value, sizeof(confp->chan.mohsuggest));
14448       } else if (!strcasecmp(v->name, "parkinglot")) {
14449          ast_copy_string(parkinglot, v->value, sizeof(parkinglot));
14450       } else if (!strcasecmp(v->name, "stripmsd")) {
14451          ast_log(LOG_NOTICE, "Configuration option \"%s\" has been deprecated. Please use dialplan instead\n", v->name);
14452          confp->chan.stripmsd = atoi(v->value);
14453       } else if (!strcasecmp(v->name, "jitterbuffers")) {
14454          numbufs = atoi(v->value);
14455       } else if (!strcasecmp(v->name, "group")) {
14456          confp->chan.group = ast_get_group(v->value);
14457       } else if (!strcasecmp(v->name, "callgroup")) {
14458          if (!strcasecmp(v->value, "none"))
14459             confp->chan.callgroup = 0;
14460          else
14461             confp->chan.callgroup = ast_get_group(v->value);
14462       } else if (!strcasecmp(v->name, "pickupgroup")) {
14463          if (!strcasecmp(v->value, "none"))
14464             confp->chan.pickupgroup = 0;
14465          else
14466             confp->chan.pickupgroup = ast_get_group(v->value);
14467       } else if (!strcasecmp(v->name, "setvar")) {
14468          char *varname = ast_strdupa(v->value), *varval = NULL;
14469          struct ast_variable *tmpvar;
14470          if (varname && (varval = strchr(varname, '='))) {
14471             *varval++ = '\0';
14472             if ((tmpvar = ast_variable_new(varname, varval, ""))) {
14473                tmpvar->next = confp->chan.vars;
14474                confp->chan.vars = tmpvar;
14475             }
14476          }
14477       } else if (!strcasecmp(v->name, "immediate")) {
14478          confp->chan.immediate = ast_true(v->value);
14479       } else if (!strcasecmp(v->name, "transfertobusy")) {
14480          confp->chan.transfertobusy = ast_true(v->value);
14481       } else if (!strcasecmp(v->name, "mwimonitor")) {
14482          confp->chan.mwimonitor_neon = 0;
14483          confp->chan.mwimonitor_fsk  = 0;
14484          confp->chan.mwimonitor_rpas = 0;
14485          if (strcasestr(v->value, "fsk")) {
14486             confp->chan.mwimonitor_fsk = 1;
14487          }
14488          if (strcasestr(v->value, "rpas")) {
14489             confp->chan.mwimonitor_rpas = 1;
14490          }
14491          if (strcasestr(v->value, "neon")) {
14492             confp->chan.mwimonitor_neon = 1;
14493          }
14494          /* If set to true or yes, assume that simple fsk is desired */
14495          if (ast_true(v->value)) {
14496             confp->chan.mwimonitor_fsk = 1;
14497          } 
14498       } else if (!strcasecmp(v->name, "cid_rxgain")) {
14499          if (sscanf(v->value, "%30f", &confp->chan.cid_rxgain) != 1) {
14500             ast_log(LOG_WARNING, "Invalid cid_rxgain: %s at line %d.\n", v->value, v->lineno);
14501          }
14502       } else if (!strcasecmp(v->name, "rxgain")) {
14503          if (sscanf(v->value, "%30f", &confp->chan.rxgain) != 1) {
14504             ast_log(LOG_WARNING, "Invalid rxgain: %s at line %d.\n", v->value, v->lineno);
14505          }
14506       } else if (!strcasecmp(v->name, "txgain")) {
14507          if (sscanf(v->value, "%30f", &confp->chan.txgain) != 1) {
14508             ast_log(LOG_WARNING, "Invalid txgain: %s at line %d.\n", v->value, v->lineno);
14509          }
14510       } else if (!strcasecmp(v->name, "tonezone")) {
14511          if (sscanf(v->value, "%30d", &confp->chan.tonezone) != 1) {
14512             ast_log(LOG_WARNING, "Invalid tonezone: %s at line %d.\n", v->value, v->lineno);
14513          }
14514       } else if (!strcasecmp(v->name, "callerid")) {
14515          if (!strcasecmp(v->value, "asreceived")) {
14516             confp->chan.cid_num[0] = '\0';
14517             confp->chan.cid_name[0] = '\0';
14518          } else {
14519             ast_callerid_split(v->value, confp->chan.cid_name, sizeof(confp->chan.cid_name), confp->chan.cid_num, sizeof(confp->chan.cid_num));
14520          } 
14521       } else if (!strcasecmp(v->name, "fullname")) {
14522          ast_copy_string(confp->chan.cid_name, v->value, sizeof(confp->chan.cid_name));
14523       } else if (!strcasecmp(v->name, "cid_number")) {
14524          ast_copy_string(confp->chan.cid_num, v->value, sizeof(confp->chan.cid_num));
14525       } else if (!strcasecmp(v->name, "useincomingcalleridondahditransfer")) {
14526          confp->chan.dahditrcallerid = ast_true(v->value);
14527       } else if (!strcasecmp(v->name, "restrictcid")) {
14528          confp->chan.restrictcid = ast_true(v->value);
14529       } else if (!strcasecmp(v->name, "usecallingpres")) {
14530          confp->chan.use_callingpres = ast_true(v->value);
14531       } else if (!strcasecmp(v->name, "accountcode")) {
14532          ast_copy_string(confp->chan.accountcode, v->value, sizeof(confp->chan.accountcode));
14533       } else if (!strcasecmp(v->name, "amaflags")) {
14534          y = ast_cdr_amaflags2int(v->value);
14535          if (y < 0) 
14536             ast_log(LOG_WARNING, "Invalid AMA flags: %s at line %d.\n", v->value, v->lineno);
14537          else
14538             confp->chan.amaflags = y;
14539       } else if (!strcasecmp(v->name, "polarityonanswerdelay")) {
14540          confp->chan.polarityonanswerdelay = atoi(v->value);
14541       } else if (!strcasecmp(v->name, "answeronpolarityswitch")) {
14542          confp->chan.answeronpolarityswitch = ast_true(v->value);
14543       } else if (!strcasecmp(v->name, "hanguponpolarityswitch")) {
14544          confp->chan.hanguponpolarityswitch = ast_true(v->value);
14545       } else if (!strcasecmp(v->name, "sendcalleridafter")) {
14546          confp->chan.sendcalleridafter = atoi(v->value);
14547       } else if (!strcasecmp(v->name, "mwimonitornotify")) {
14548          ast_copy_string(mwimonitornotify, v->value, sizeof(mwimonitornotify));
14549       } else if (!strcasecmp(v->name, "mwisendtype")) {
14550          if (!strcasecmp(v->value, "rpas")) { /* Ring Pulse Alert Signal */
14551             mwisend_rpas = 1;
14552          } else {
14553             mwisend_rpas = 0;
14554          }
14555       } else if (reload != 1) {
14556           if (!strcasecmp(v->name, "signalling") || !strcasecmp(v->name, "signaling")) {
14557             int orig_radio = confp->chan.radio;
14558             int orig_outsigmod = confp->chan.outsigmod;
14559             int orig_auto = confp->is_sig_auto;
14560 
14561             confp->chan.radio = 0;
14562             confp->chan.outsigmod = -1;
14563             confp->is_sig_auto = 0;
14564             if (!strcasecmp(v->value, "em")) {
14565                confp->chan.sig = SIG_EM;
14566             } else if (!strcasecmp(v->value, "em_e1")) {
14567                confp->chan.sig = SIG_EM_E1;
14568             } else if (!strcasecmp(v->value, "em_w")) {
14569                confp->chan.sig = SIG_EMWINK;
14570             } else if (!strcasecmp(v->value, "fxs_ls")) {
14571                confp->chan.sig = SIG_FXSLS;
14572             } else if (!strcasecmp(v->value, "fxs_gs")) {
14573                confp->chan.sig = SIG_FXSGS;
14574             } else if (!strcasecmp(v->value, "fxs_ks")) {
14575                confp->chan.sig = SIG_FXSKS;
14576             } else if (!strcasecmp(v->value, "fxo_ls")) {
14577                confp->chan.sig = SIG_FXOLS;
14578             } else if (!strcasecmp(v->value, "fxo_gs")) {
14579                confp->chan.sig = SIG_FXOGS;
14580             } else if (!strcasecmp(v->value, "fxo_ks")) {
14581                confp->chan.sig = SIG_FXOKS;
14582             } else if (!strcasecmp(v->value, "fxs_rx")) {
14583                confp->chan.sig = SIG_FXSKS;
14584                confp->chan.radio = 1;
14585             } else if (!strcasecmp(v->value, "fxo_rx")) {
14586                confp->chan.sig = SIG_FXOLS;
14587                confp->chan.radio = 1;
14588             } else if (!strcasecmp(v->value, "fxs_tx")) {
14589                confp->chan.sig = SIG_FXSLS;
14590                confp->chan.radio = 1;
14591             } else if (!strcasecmp(v->value, "fxo_tx")) {
14592                confp->chan.sig = SIG_FXOGS;
14593                confp->chan.radio = 1;
14594             } else if (!strcasecmp(v->value, "em_rx")) {
14595                confp->chan.sig = SIG_EM;
14596                confp->chan.radio = 1;
14597             } else if (!strcasecmp(v->value, "em_tx")) {
14598                confp->chan.sig = SIG_EM;
14599                confp->chan.radio = 1;
14600             } else if (!strcasecmp(v->value, "em_rxtx")) {
14601                confp->chan.sig = SIG_EM;
14602                confp->chan.radio = 2;
14603             } else if (!strcasecmp(v->value, "em_txrx")) {
14604                confp->chan.sig = SIG_EM;
14605                confp->chan.radio = 2;
14606             } else if (!strcasecmp(v->value, "sf")) {
14607                confp->chan.sig = SIG_SF;
14608             } else if (!strcasecmp(v->value, "sf_w")) {
14609                confp->chan.sig = SIG_SFWINK;
14610             } else if (!strcasecmp(v->value, "sf_featd")) {
14611                confp->chan.sig = SIG_FEATD;
14612             } else if (!strcasecmp(v->value, "sf_featdmf")) {
14613                confp->chan.sig = SIG_FEATDMF;
14614             } else if (!strcasecmp(v->value, "sf_featb")) {
14615                confp->chan.sig = SIG_SF_FEATB;
14616             } else if (!strcasecmp(v->value, "sf")) {
14617                confp->chan.sig = SIG_SF;
14618             } else if (!strcasecmp(v->value, "sf_rx")) {
14619                confp->chan.sig = SIG_SF;
14620                confp->chan.radio = 1;
14621             } else if (!strcasecmp(v->value, "sf_tx")) {
14622                confp->chan.sig = SIG_SF;
14623                confp->chan.radio = 1;
14624             } else if (!strcasecmp(v->value, "sf_rxtx")) {
14625                confp->chan.sig = SIG_SF;
14626                confp->chan.radio = 2;
14627             } else if (!strcasecmp(v->value, "sf_txrx")) {
14628                confp->chan.sig = SIG_SF;
14629                confp->chan.radio = 2;
14630             } else if (!strcasecmp(v->value, "featd")) {
14631                confp->chan.sig = SIG_FEATD;
14632             } else if (!strcasecmp(v->value, "featdmf")) {
14633                confp->chan.sig = SIG_FEATDMF;
14634             } else if (!strcasecmp(v->value, "featdmf_ta")) {
14635                confp->chan.sig = SIG_FEATDMF_TA;
14636             } else if (!strcasecmp(v->value, "e911")) {
14637                confp->chan.sig = SIG_E911;
14638             } else if (!strcasecmp(v->value, "fgccama")) {
14639                confp->chan.sig = SIG_FGC_CAMA;
14640             } else if (!strcasecmp(v->value, "fgccamamf")) {
14641                confp->chan.sig = SIG_FGC_CAMAMF;
14642             } else if (!strcasecmp(v->value, "featb")) {
14643                confp->chan.sig = SIG_FEATB;
14644 #ifdef HAVE_PRI
14645             } else if (!strcasecmp(v->value, "pri_net")) {
14646                confp->chan.sig = SIG_PRI;
14647                confp->pri.nodetype = PRI_NETWORK;
14648             } else if (!strcasecmp(v->value, "pri_cpe")) {
14649                confp->chan.sig = SIG_PRI;
14650                confp->pri.nodetype = PRI_CPE;
14651             } else if (!strcasecmp(v->value, "bri_cpe")) {
14652                confp->chan.sig = SIG_BRI;
14653                confp->pri.nodetype = PRI_CPE;
14654             } else if (!strcasecmp(v->value, "bri_net")) {
14655                confp->chan.sig = SIG_BRI;
14656                confp->pri.nodetype = PRI_NETWORK;
14657             } else if (!strcasecmp(v->value, "bri_cpe_ptmp")) {
14658                confp->chan.sig = SIG_BRI_PTMP;
14659                confp->pri.nodetype = PRI_CPE;
14660             } else if (!strcasecmp(v->value, "bri_net_ptmp")) {
14661                ast_log(LOG_WARNING, "How cool would it be if someone implemented this mode!  For now, sucks for you. (line %d)\n", v->lineno);
14662             } else if (!strcasecmp(v->value, "gr303fxoks_net")) {
14663                confp->chan.sig = SIG_GR303FXOKS;
14664                confp->pri.nodetype = PRI_NETWORK;
14665             } else if (!strcasecmp(v->value, "gr303fxsks_cpe")) {
14666                confp->chan.sig = SIG_GR303FXSKS;
14667                confp->pri.nodetype = PRI_CPE;
14668 #endif
14669 #ifdef HAVE_SS7
14670             } else if (!strcasecmp(v->value, "ss7")) {
14671                confp->chan.sig = SIG_SS7;
14672 #endif
14673             } else if (!strcasecmp(v->value, "auto")) {
14674                confp->is_sig_auto = 1;
14675             } else {
14676                confp->chan.outsigmod = orig_outsigmod;
14677                confp->chan.radio = orig_radio;
14678                confp->is_sig_auto = orig_auto;
14679                ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
14680             }
14681           } else if (!strcasecmp(v->name, "outsignalling") || !strcasecmp(v->name, "outsignaling")) {
14682             if (!strcasecmp(v->value, "em")) {
14683                confp->chan.outsigmod = SIG_EM;
14684             } else if (!strcasecmp(v->value, "em_e1")) {
14685                confp->chan.outsigmod = SIG_EM_E1;
14686             } else if (!strcasecmp(v->value, "em_w")) {
14687                confp->chan.outsigmod = SIG_EMWINK;
14688             } else if (!strcasecmp(v->value, "sf")) {
14689                confp->chan.outsigmod = SIG_SF;
14690             } else if (!strcasecmp(v->value, "sf_w")) {
14691                confp->chan.outsigmod = SIG_SFWINK;
14692             } else if (!strcasecmp(v->value, "sf_featd")) {
14693                confp->chan.outsigmod = SIG_FEATD;
14694             } else if (!strcasecmp(v->value, "sf_featdmf")) {
14695                confp->chan.outsigmod = SIG_FEATDMF;
14696             } else if (!strcasecmp(v->value, "sf_featb")) {
14697                confp->chan.outsigmod = SIG_SF_FEATB;
14698             } else if (!strcasecmp(v->value, "sf")) {
14699                confp->chan.outsigmod = SIG_SF;
14700             } else if (!strcasecmp(v->value, "featd")) {
14701                confp->chan.outsigmod = SIG_FEATD;
14702             } else if (!strcasecmp(v->value, "featdmf")) {
14703                confp->chan.outsigmod = SIG_FEATDMF;
14704             } else if (!strcasecmp(v->value, "featdmf_ta")) {
14705                confp->chan.outsigmod = SIG_FEATDMF_TA;
14706             } else if (!strcasecmp(v->value, "e911")) {
14707                confp->chan.outsigmod = SIG_E911;
14708             } else if (!strcasecmp(v->value, "fgccama")) {
14709                confp->chan.outsigmod = SIG_FGC_CAMA;
14710             } else if (!strcasecmp(v->value, "fgccamamf")) {
14711                confp->chan.outsigmod = SIG_FGC_CAMAMF;
14712             } else if (!strcasecmp(v->value, "featb")) {
14713                confp->chan.outsigmod = SIG_FEATB;
14714             } else {
14715                ast_log(LOG_ERROR, "Unknown signalling method '%s' at line %d.\n", v->value, v->lineno);
14716             }
14717 #ifdef HAVE_PRI
14718          } else if (!strcasecmp(v->name, "pridialplan")) {
14719             if (!strcasecmp(v->value, "national")) {
14720                confp->pri.dialplan = PRI_NATIONAL_ISDN + 1;
14721             } else if (!strcasecmp(v->value, "unknown")) {
14722                confp->pri.dialplan = PRI_UNKNOWN + 1;
14723             } else if (!strcasecmp(v->value, "private")) {
14724                confp->pri.dialplan = PRI_PRIVATE + 1;
14725             } else if (!strcasecmp(v->value, "international")) {
14726                confp->pri.dialplan = PRI_INTERNATIONAL_ISDN + 1;
14727             } else if (!strcasecmp(v->value, "local")) {
14728                confp->pri.dialplan = PRI_LOCAL_ISDN + 1;
14729             } else if (!strcasecmp(v->value, "dynamic")) {
14730                confp->pri.dialplan = -1;
14731             } else if (!strcasecmp(v->value, "redundant")) {
14732                confp->pri.dialplan = -2;
14733             } else {
14734                ast_log(LOG_WARNING, "Unknown PRI dialplan '%s' at line %d.\n", v->value, v->lineno);
14735             }
14736          } else if (!strcasecmp(v->name, "prilocaldialplan")) {
14737             if (!strcasecmp(v->value, "national")) {
14738                confp->pri.localdialplan = PRI_NATIONAL_ISDN + 1;
14739             } else if (!strcasecmp(v->value, "unknown")) {
14740                confp->pri.localdialplan = PRI_UNKNOWN + 1;
14741             } else if (!strcasecmp(v->value, "private")) {
14742                confp->pri.localdialplan = PRI_PRIVATE + 1;
14743             } else if (!strcasecmp(v->value, "international")) {
14744                confp->pri.localdialplan = PRI_INTERNATIONAL_ISDN + 1;
14745             } else if (!strcasecmp(v->value, "local")) {
14746                confp->pri.localdialplan = PRI_LOCAL_ISDN + 1;
14747             } else if (!strcasecmp(v->value, "dynamic")) {
14748                confp->pri.localdialplan = -1;
14749             } else if (!strcasecmp(v->value, "redundant")) {
14750                confp->pri.localdialplan = -2;
14751             } else {
14752                ast_log(LOG_WARNING, "Unknown PRI localdialplan '%s' at line %d.\n", v->value, v->lineno);
14753             }
14754          } else if (!strcasecmp(v->name, "switchtype")) {
14755             if (!strcasecmp(v->value, "national")) 
14756                confp->pri.switchtype = PRI_SWITCH_NI2;
14757             else if (!strcasecmp(v->value, "ni1"))
14758                confp->pri.switchtype = PRI_SWITCH_NI1;
14759             else if (!strcasecmp(v->value, "dms100"))
14760                confp->pri.switchtype = PRI_SWITCH_DMS100;
14761             else if (!strcasecmp(v->value, "4ess"))
14762                confp->pri.switchtype = PRI_SWITCH_ATT4ESS;
14763             else if (!strcasecmp(v->value, "5ess"))
14764                confp->pri.switchtype = PRI_SWITCH_LUCENT5E;
14765             else if (!strcasecmp(v->value, "euroisdn"))
14766                confp->pri.switchtype = PRI_SWITCH_EUROISDN_E1;
14767             else if (!strcasecmp(v->value, "qsig"))
14768                confp->pri.switchtype = PRI_SWITCH_QSIG;
14769             else {
14770                ast_log(LOG_ERROR, "Unknown switchtype '%s' at line %d.\n", v->value, v->lineno);
14771                return -1;
14772             }
14773          } else if (!strcasecmp(v->name, "nsf")) {
14774             if (!strcasecmp(v->value, "sdn"))
14775                confp->pri.nsf = PRI_NSF_SDN;
14776             else if (!strcasecmp(v->value, "megacom"))
14777                confp->pri.nsf = PRI_NSF_MEGACOM;
14778             else if (!strcasecmp(v->value, "tollfreemegacom"))
14779                confp->pri.nsf = PRI_NSF_TOLL_FREE_MEGACOM;           
14780             else if (!strcasecmp(v->value, "accunet"))
14781                confp->pri.nsf = PRI_NSF_ACCUNET;
14782             else if (!strcasecmp(v->value, "none"))
14783                confp->pri.nsf = PRI_NSF_NONE;
14784             else {
14785                ast_log(LOG_WARNING, "Unknown network-specific facility '%s' at line %d.\n", v->value, v->lineno);
14786                confp->pri.nsf = PRI_NSF_NONE;
14787             }
14788          } else if (!strcasecmp(v->name, "priindication")) {
14789             if (!strcasecmp(v->value, "outofband"))
14790                confp->chan.priindication_oob = 1;
14791             else if (!strcasecmp(v->value, "inband"))
14792                confp->chan.priindication_oob = 0;
14793             else
14794                ast_log(LOG_WARNING, "'%s' is not a valid pri indication value, should be 'inband' or 'outofband' at line %d.\n",
14795                   v->value, v->lineno);
14796          } else if (!strcasecmp(v->name, "priexclusive")) {
14797             confp->chan.priexclusive = ast_true(v->value);
14798          } else if (!strcasecmp(v->name, "internationalprefix")) {
14799             ast_copy_string(confp->pri.internationalprefix, v->value, sizeof(confp->pri.internationalprefix));
14800          } else if (!strcasecmp(v->name, "nationalprefix")) {
14801             ast_copy_string(confp->pri.nationalprefix, v->value, sizeof(confp->pri.nationalprefix));
14802          } else if (!strcasecmp(v->name, "localprefix")) {
14803             ast_copy_string(confp->pri.localprefix, v->value, sizeof(confp->pri.localprefix));
14804          } else if (!strcasecmp(v->name, "privateprefix")) {
14805             ast_copy_string(confp->pri.privateprefix, v->value, sizeof(confp->pri.privateprefix));
14806          } else if (!strcasecmp(v->name, "unknownprefix")) {
14807             ast_copy_string(confp->pri.unknownprefix, v->value, sizeof(confp->pri.unknownprefix));
14808          } else if (!strcasecmp(v->name, "resetinterval")) {
14809             if (!strcasecmp(v->value, "never"))
14810                confp->pri.resetinterval = -1;
14811             else if (atoi(v->value) >= 60)
14812                confp->pri.resetinterval = atoi(v->value);
14813             else
14814                ast_log(LOG_WARNING, "'%s' is not a valid reset interval, should be >= 60 seconds or 'never' at line %d.\n",
14815                   v->value, v->lineno);
14816          } else if (!strcasecmp(v->name, "minunused")) {
14817             confp->pri.minunused = atoi(v->value);
14818          } else if (!strcasecmp(v->name, "minidle")) {
14819             confp->pri.minidle = atoi(v->value); 
14820          } else if (!strcasecmp(v->name, "idleext")) {
14821             ast_copy_string(confp->pri.idleext, v->value, sizeof(confp->pri.idleext));
14822          } else if (!strcasecmp(v->name, "idledial")) {
14823             ast_copy_string(confp->pri.idledial, v->value, sizeof(confp->pri.idledial));
14824          } else if (!strcasecmp(v->name, "overlapdial")) {
14825             if (ast_true(v->value)) {
14826                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
14827             } else if (!strcasecmp(v->value, "incoming")) {
14828                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_INCOMING;
14829             } else if (!strcasecmp(v->value, "outgoing")) {
14830                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_OUTGOING;
14831             } else if (!strcasecmp(v->value, "both") || ast_true(v->value)) {
14832                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_BOTH;
14833             } else {
14834                confp->pri.overlapdial = DAHDI_OVERLAPDIAL_NONE;
14835             }
14836 #ifdef HAVE_PRI_INBANDDISCONNECT
14837          } else if (!strcasecmp(v->name, "inbanddisconnect")) {
14838             confp->pri.inbanddisconnect = ast_true(v->value);
14839 #endif
14840          } else if (!strcasecmp(v->name, "pritimer")) {
14841 #ifdef PRI_GETSET_TIMERS
14842             char tmp[20];
14843             char *timerc;
14844             char *c;
14845             int timer;
14846             int timeridx;
14847 
14848             ast_copy_string(tmp, v->value, sizeof(tmp));
14849             c = tmp;
14850             timerc = strsep(&c, ",");
14851             if (!ast_strlen_zero(timerc) && !ast_strlen_zero(c)) {
14852                timeridx = pri_timer2idx(timerc);
14853                timer = atoi(c);
14854                if (timeridx < 0 || PRI_MAX_TIMERS <= timeridx) {
14855                   ast_log(LOG_WARNING,
14856                      "'%s' is not a valid ISDN timer at line %d.\n", timerc,
14857                      v->lineno);
14858                } else if (!timer) {
14859                   ast_log(LOG_WARNING,
14860                      "'%s' is not a valid value for ISDN timer '%s' at line %d.\n",
14861                      c, timerc, v->lineno);
14862                } else {
14863                   pritimers[timeridx] = timer;
14864                }
14865             } else {
14866                ast_log(LOG_WARNING,
14867                   "'%s' is not a valid ISDN timer configuration string at line %d.\n",
14868                   v->value, v->lineno);
14869             }
14870 
14871          } else if (!strcasecmp(v->name, "facilityenable")) {
14872             confp->pri.facilityenable = ast_true(v->value);
14873 #endif /* PRI_GETSET_TIMERS */
14874 #endif /* HAVE_PRI */
14875 #ifdef HAVE_SS7
14876          } else if (!strcasecmp(v->name, "ss7type")) {
14877             if (!strcasecmp(v->value, "itu")) {
14878                cur_ss7type = SS7_ITU;
14879             } else if (!strcasecmp(v->value, "ansi")) {
14880                cur_ss7type = SS7_ANSI;
14881             } else
14882                ast_log(LOG_WARNING, "'%s' is an unknown ss7 switch type at line %d.!\n", v->value, v->lineno);
14883          } else if (!strcasecmp(v->name, "linkset")) {
14884             cur_linkset = atoi(v->value);
14885          } else if (!strcasecmp(v->name, "pointcode")) {
14886             cur_pointcode = parse_pointcode(v->value);
14887          } else if (!strcasecmp(v->name, "adjpointcode")) {
14888             cur_adjpointcode = parse_pointcode(v->value);
14889          } else if (!strcasecmp(v->name, "defaultdpc")) {
14890             cur_defaultdpc = parse_pointcode(v->value);
14891          } else if (!strcasecmp(v->name, "cicbeginswith")) {
14892             cur_cicbeginswith = atoi(v->value);
14893          } else if (!strcasecmp(v->name, "networkindicator")) {
14894             if (!strcasecmp(v->value, "national"))
14895                cur_networkindicator = SS7_NI_NAT;
14896             else if (!strcasecmp(v->value, "national_spare"))
14897                cur_networkindicator = SS7_NI_NAT_SPARE;
14898             else if (!strcasecmp(v->value, "international"))
14899                cur_networkindicator = SS7_NI_INT;
14900             else if (!strcasecmp(v->value, "international_spare"))
14901                cur_networkindicator = SS7_NI_INT_SPARE;
14902             else
14903                cur_networkindicator = -1;
14904          } else if (!strcasecmp(v->name, "ss7_internationalprefix")) {
14905             ast_copy_string(confp->ss7.internationalprefix, v->value, sizeof(confp->ss7.internationalprefix));
14906          } else if (!strcasecmp(v->name, "ss7_nationalprefix")) {
14907             ast_copy_string(confp->ss7.nationalprefix, v->value, sizeof(confp->ss7.nationalprefix));
14908          } else if (!strcasecmp(v->name, "ss7_subscriberprefix")) {
14909             ast_copy_string(confp->ss7.subscriberprefix, v->value, sizeof(confp->ss7.subscriberprefix));
14910          } else if (!strcasecmp(v->name, "ss7_unknownprefix")) {
14911             ast_copy_string(confp->ss7.unknownprefix, v->value, sizeof(confp->ss7.unknownprefix));
14912          } else if (!strcasecmp(v->name, "ss7_called_nai")) {
14913             if (!strcasecmp(v->value, "national")) {
14914                confp->ss7.called_nai = SS7_NAI_NATIONAL;
14915             } else if (!strcasecmp(v->value, "international")) {
14916                confp->ss7.called_nai = SS7_NAI_INTERNATIONAL;
14917             } else if (!strcasecmp(v->value, "subscriber")) {
14918                confp->ss7.called_nai = SS7_NAI_SUBSCRIBER;
14919             } else if (!strcasecmp(v->value, "dynamic")) {
14920                confp->ss7.called_nai = SS7_NAI_DYNAMIC;
14921             } else {
14922                ast_log(LOG_WARNING, "Unknown SS7 called_nai '%s' at line %d.\n", v->value, v->lineno);
14923             }
14924          } else if (!strcasecmp(v->name, "ss7_calling_nai")) {
14925             if (!strcasecmp(v->value, "national")) {
14926                confp->ss7.calling_nai = SS7_NAI_NATIONAL;
14927             } else if (!strcasecmp(v->value, "international")) {
14928                confp->ss7.calling_nai = SS7_NAI_INTERNATIONAL;
14929             } else if (!strcasecmp(v->value, "subscriber")) {
14930                confp->ss7.calling_nai = SS7_NAI_SUBSCRIBER;
14931             } else if (!strcasecmp(v->value, "dynamic")) {
14932                confp->ss7.calling_nai = SS7_NAI_DYNAMIC;
14933             } else {
14934                ast_log(LOG_WARNING, "Unknown SS7 calling_nai '%s' at line %d.\n", v->value, v->lineno);
14935             }
14936          } else if (!strcasecmp(v->name, "sigchan")) {
14937             int sigchan, res;
14938             sigchan = atoi(v->value);
14939             res = linkset_addsigchan(sigchan);
14940             if (res < 0)
14941                return -1;
14942 
14943          } else if (!strcasecmp(v->name, "ss7_explicitacm")) {
14944             struct dahdi_ss7 *link;
14945             link = ss7_resolve_linkset(cur_linkset);
14946             if (!link) {
14947                ast_log(LOG_ERROR, "Invalid linkset number.  Must be between 1 and %d\n", NUM_SPANS + 1);
14948                return -1;
14949             }
14950             if (ast_true(v->value))
14951                link->flags |= LINKSET_FLAG_EXPLICITACM;
14952 
14953 #endif /* HAVE_SS7 */
14954          } else if (!strcasecmp(v->name, "cadence")) {
14955             /* setup to scan our argument */
14956             int element_count, c[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
14957             int i;
14958             struct dahdi_ring_cadence new_cadence;
14959             int cid_location = -1;
14960             int firstcadencepos = 0;
14961             char original_args[80];
14962             int cadence_is_ok = 1;
14963 
14964             ast_copy_string(original_args, v->value, sizeof(original_args));
14965             /* 16 cadences allowed (8 pairs) */
14966             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]);
14967    
14968             /* Cadence must be even (on/off) */
14969             if (element_count % 2 == 1) {
14970                ast_log(LOG_ERROR, "Must be a silence duration for each ring duration: %s at line %d.\n", original_args, v->lineno);
14971                cadence_is_ok = 0;
14972             }
14973    
14974             /* Ring cadences cannot be negative */
14975             for (i = 0; i < element_count; i++) {
14976                if (c[i] == 0) {
14977                   ast_log(LOG_ERROR, "Ring or silence duration cannot be zero: %s at line %d.\n", original_args, v->lineno);
14978                   cadence_is_ok = 0;
14979                   break;
14980                } else if (c[i] < 0) {
14981                   if (i % 2 == 1) {
14982                      /* Silence duration, negative possibly okay */
14983                      if (cid_location == -1) {
14984                         cid_location = i;
14985                         c[i] *= -1;
14986                      } else {
14987                         ast_log(LOG_ERROR, "CID location specified twice: %s at line %d.\n", original_args, v->lineno);
14988                         cadence_is_ok = 0;
14989                         break;
14990                      }
14991                   } else {
14992                      if (firstcadencepos == 0) {
14993                         firstcadencepos = i; /* only recorded to avoid duplicate specification */
14994                                  /* duration will be passed negative to the DAHDI driver */
14995                      } else {
14996                          ast_log(LOG_ERROR, "First cadence position specified twice: %s at line %d.\n", original_args, v->lineno);
14997                         cadence_is_ok = 0;
14998                         break;
14999                      }
15000                   }
15001                }
15002             }
15003    
15004             /* Substitute our scanned cadence */
15005             for (i = 0; i < 16; i++) {
15006                new_cadence.ringcadence[i] = c[i];
15007             }
15008    
15009             if (cadence_is_ok) {
15010                /* ---we scanned it without getting annoyed; now some sanity checks--- */
15011                if (element_count < 2) {
15012                   ast_log(LOG_ERROR, "Minimum cadence is ring,pause: %s at line %d.\n", original_args, v->lineno);
15013                } else {
15014                   if (cid_location == -1) {
15015                      /* user didn't say; default to first pause */
15016                      cid_location = 1;
15017                   } else {
15018                      /* convert element_index to cidrings value */
15019                      cid_location = (cid_location + 1) / 2;
15020                   }
15021                   /* ---we like their cadence; try to install it--- */
15022                   if (!user_has_defined_cadences++)
15023                      /* this is the first user-defined cadence; clear the default user cadences */
15024                      num_cadence = 0;
15025                   if ((num_cadence+1) >= NUM_CADENCE_MAX)
15026                      ast_log(LOG_ERROR, "Already %d cadences; can't add another: %s at line %d.\n", NUM_CADENCE_MAX, original_args, v->lineno);
15027                   else {
15028                      cadences[num_cadence] = new_cadence;
15029                      cidrings[num_cadence++] = cid_location;
15030                      ast_verb(3, "cadence 'r%d' added: %s\n",num_cadence,original_args);
15031                   }
15032                }
15033             }
15034          } else if (!strcasecmp(v->name, "ringtimeout")) {
15035             ringt_base = (atoi(v->value) * 8) / READ_SIZE;
15036          } else if (!strcasecmp(v->name, "prewink")) {
15037             confp->timing.prewinktime = atoi(v->value);
15038          } else if (!strcasecmp(v->name, "preflash")) {
15039             confp->timing.preflashtime = atoi(v->value);
15040          } else if (!strcasecmp(v->name, "wink")) {
15041             confp->timing.winktime = atoi(v->value);
15042          } else if (!strcasecmp(v->name, "flash")) {
15043             confp->timing.flashtime = atoi(v->value);
15044          } else if (!strcasecmp(v->name, "start")) {
15045             confp->timing.starttime = atoi(v->value);
15046          } else if (!strcasecmp(v->name, "rxwink")) {
15047             confp->timing.rxwinktime = atoi(v->value);
15048          } else if (!strcasecmp(v->name, "rxflash")) {
15049             confp->timing.rxflashtime = atoi(v->value);
15050          } else if (!strcasecmp(v->name, "debounce")) {
15051             confp->timing.debouncetime = atoi(v->value);
15052          } else if (!strcasecmp(v->name, "toneduration")) {
15053             int toneduration;
15054             int ctlfd;
15055             int res;
15056             struct dahdi_dialparams dps;
15057 
15058             ctlfd = open("/dev/dahdi/ctl", O_RDWR);
15059             if (ctlfd == -1) {
15060                ast_log(LOG_ERROR, "Unable to open /dev/dahdi/ctl to set toneduration at line %d.\n", v->lineno);
15061                return -1;
15062             }
15063 
15064             toneduration = atoi(v->value);
15065             if (toneduration > -1) {
15066                memset(&dps, 0, sizeof(dps));
15067 
15068                dps.dtmf_tonelen = dps.mfv1_tonelen = toneduration;
15069                res = ioctl(ctlfd, DAHDI_SET_DIALPARAMS, &dps);
15070                if (res < 0) {
15071                   ast_log(LOG_ERROR, "Invalid tone duration: %d ms at line %d: %s\n", toneduration, v->lineno, strerror(errno));
15072                   return -1;
15073                }
15074             }
15075             close(ctlfd);
15076          } else if (!strcasecmp(v->name, "defaultcic")) {
15077             ast_copy_string(defaultcic, v->value, sizeof(defaultcic));
15078          } else if (!strcasecmp(v->name, "defaultozz")) {
15079             ast_copy_string(defaultozz, v->value, sizeof(defaultozz));
15080          } else if (!strcasecmp(v->name, "mwilevel")) {
15081             mwilevel = atoi(v->value);
15082          }
15083       } else if (!(options & PROC_DAHDI_OPT_NOWARN) )
15084          ast_log(LOG_WARNING, "Ignoring any changes to '%s' (on reload) at line %d.\n", v->name, v->lineno);
15085    }
15086    if (dahdichan[0]) { 
15087       /* The user has set 'dahdichan' */
15088       /*< \todo pass proper line number instead of 0 */
15089       if (build_channels(confp, 0, dahdichan, reload, 0, &found_pseudo)) {
15090          return -1;
15091       }
15092    }
15093    /*< \todo why check for the pseudo in the per-channel section.
15094     * Any actual use for manual setup of the pseudo channel? */
15095    if (!found_pseudo && reload != 1) {
15096       /* use the default configuration for a channel, so
15097          that any settings from real configured channels
15098          don't "leak" into the pseudo channel config
15099       */
15100       struct dahdi_chan_conf conf = dahdi_chan_conf_default();
15101 
15102       tmp = mkintf(CHAN_PSEUDO, &conf, NULL, reload);
15103 
15104       if (tmp) {
15105          ast_verb(3, "Automatically generated pseudo channel\n");
15106       } else {
15107          ast_log(LOG_WARNING, "Unable to register pseudo channel!\n");
15108       }
15109    }
15110    return 0;
15111 }
15112       
15113 static int setup_dahdi(int reload)
15114 {
15115    struct ast_config *cfg, *ucfg;
15116    struct ast_variable *v;
15117    struct dahdi_chan_conf base_conf = dahdi_chan_conf_default();
15118    struct dahdi_chan_conf conf;
15119    struct ast_flags config_flags = { reload == 1 ? CONFIG_FLAG_FILEUNCHANGED : 0 };
15120    const char *cat;
15121    int res;
15122 
15123 #ifdef HAVE_PRI
15124    char *c;
15125    int spanno;
15126    int i;
15127    int logicalspan;
15128    int trunkgroup;
15129    int dchannels[NUM_DCHANS];
15130 #endif
15131 
15132    cfg = ast_config_load(config, config_flags);
15133 
15134    /* Error if we have no config file */
15135    if (!cfg) {
15136       ast_log(LOG_ERROR, "Unable to load config %s\n", config);
15137       return 0;
15138    } else if (cfg == CONFIG_STATUS_FILEUNCHANGED) {
15139       ucfg = ast_config_load("users.conf", config_flags);
15140       if (ucfg == CONFIG_STATUS_FILEUNCHANGED)
15141          return 0;
15142       ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
15143       cfg = ast_config_load(config, config_flags);
15144    } else {
15145       ast_clear_flag(&config_flags, CONFIG_FLAG_FILEUNCHANGED);
15146       ucfg = ast_config_load("users.conf", config_flags);
15147    }
15148 
15149    /* It's a little silly to lock it, but we mind as well just to be sure */
15150    ast_mutex_lock(&iflock);
15151 #ifdef HAVE_PRI
15152    if (reload != 1) {
15153       /* Process trunkgroups first */
15154       v = ast_variable_browse(cfg, "trunkgroups");
15155       while (v) {
15156          if (!strcasecmp(v->name, "trunkgroup")) {
15157             trunkgroup = atoi(v->value);
15158             if (trunkgroup > 0) {
15159                if ((c = strchr(v->value, ','))) {
15160                   i = 0;
15161                   memset(dchannels, 0, sizeof(dchannels));
15162                   while (c && (i < NUM_DCHANS)) {
15163                      dchannels[i] = atoi(c + 1);
15164                      if (dchannels[i] < 0) {
15165                         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);
15166                      } else
15167                         i++;
15168                      c = strchr(c + 1, ',');
15169                   }
15170                   if (i) {
15171                      if (pri_create_trunkgroup(trunkgroup, dchannels)) {
15172                         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);
15173                   } else
15174                         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");
15175                   } else
15176                      ast_log(LOG_WARNING, "Trunk group %d lacks any valid D-channels at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
15177                } else
15178                   ast_log(LOG_WARNING, "Trunk group %d lacks a primary D-channel at line %d of chan_dahdi.conf\n", trunkgroup, v->lineno);
15179             } else
15180                ast_log(LOG_WARNING, "Trunk group identifier must be a positive integer at line %d of chan_dahdi.conf\n", v->lineno);
15181          } else if (!strcasecmp(v->name, "spanmap")) {
15182             spanno = atoi(v->value);
15183             if (spanno > 0) {
15184                if ((c = strchr(v->value, ','))) {
15185                   trunkgroup = atoi(c + 1);
15186                   if (trunkgroup > 0) {
15187                      if ((c = strchr(c + 1, ','))) 
15188                         logicalspan = atoi(c + 1);
15189                      else
15190                         logicalspan = 0;
15191                      if (logicalspan >= 0) {
15192                         if (pri_create_spanmap(spanno - 1, trunkgroup, logicalspan)) {
15193                            ast_log(LOG_WARNING, "Failed to map span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
15194                      } else
15195                            ast_verb(2, "Mapped span %d to trunk group %d (logical span %d)\n", spanno, trunkgroup, logicalspan);
15196                      } else
15197                         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);
15198                   } else
15199                      ast_log(LOG_WARNING, "Trunk group must be a postive number at line %d of chan_dahdi.conf\n", v->lineno);
15200                } else
15201                   ast_log(LOG_WARNING, "Missing trunk group for span map at line %d of chan_dahdi.conf\n", v->lineno);
15202             } else
15203                ast_log(LOG_WARNING, "Span number must be a postive integer at line %d of chan_dahdi.conf\n", v->lineno);
15204          } else {
15205             ast_log(LOG_NOTICE, "Ignoring unknown keyword '%s' in trunkgroups\n", v->name);
15206          }
15207          v = v->next;
15208       }
15209    }
15210 #endif
15211    
15212    /* Copy the default jb config over global_jbconf */
15213    memcpy(&global_jbconf, &default_jbconf, sizeof(global_jbconf));
15214 
15215    mwimonitornotify[0] = '\0';
15216 
15217    v = ast_variable_browse(cfg, "channels");
15218    if ((res = process_dahdi(&base_conf, "", v, reload, 0))) {
15219       ast_mutex_unlock(&iflock);
15220       ast_config_destroy(cfg);
15221       if (ucfg) {
15222          ast_config_destroy(ucfg);
15223       }
15224       return res;
15225    }
15226 
15227    /* Now get configuration from all normal sections in chan_dahdi.conf: */
15228    for (cat = ast_category_browse(cfg, NULL); cat ; cat = ast_category_browse(cfg, cat)) {
15229       /* [channels] and [trunkgroups] are used. Let's also reserve
15230        * [globals] and [general] for future use
15231        */
15232       if (!strcasecmp(cat, "general") || 
15233           !strcasecmp(cat, "trunkgroups") ||
15234           !strcasecmp(cat, "globals") ||
15235           !strcasecmp(cat, "channels")) {
15236          continue;
15237       }
15238 
15239       memcpy(&conf, &base_conf, sizeof(conf));
15240 
15241       if ((res = process_dahdi(&conf, cat, ast_variable_browse(cfg, cat), reload, PROC_DAHDI_OPT_NOCHAN))) {
15242          ast_mutex_unlock(&iflock);
15243          ast_config_destroy(cfg);
15244          if (ucfg) {
15245             ast_config_destroy(cfg);
15246          }
15247          return res;
15248       }
15249    }
15250 
15251    ast_config_destroy(cfg);
15252 
15253    if (ucfg) {
15254       const char *chans;
15255 
15256       process_dahdi(&base_conf, "", ast_variable_browse(ucfg, "general"), 1, 0);
15257 
15258       for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
15259          if (!strcasecmp(cat, "general")) {
15260             continue;
15261          }
15262 
15263          chans = ast_variable_retrieve(ucfg, cat, "dahdichan");
15264 
15265          if (ast_strlen_zero(chans)) {
15266             continue;
15267          }
15268 
15269          memcpy(&conf, &base_conf, sizeof(conf));
15270 
15271          if ((res = process_dahdi(&conf, cat, ast_variable_browse(ucfg, cat), reload, PROC_DAHDI_OPT_NOCHAN | PROC_DAHDI_OPT_NOWARN))) {
15272             ast_config_destroy(ucfg);
15273             ast_mutex_unlock(&iflock);
15274             return res;
15275          }
15276       }
15277       ast_config_destroy(ucfg);
15278    }
15279    ast_mutex_unlock(&iflock);
15280 
15281 #ifdef HAVE_PRI
15282    if (reload != 1) {
15283       int x;
15284       for (x = 0; x < NUM_SPANS; x++) {
15285          if (pris[x].pvts[0]) {
15286             if (start_pri(pris + x)) {
15287                ast_log(LOG_ERROR, "Unable to start D-channel on span %d\n", x + 1);
15288                return -1;
15289             } else
15290                ast_verb(2, "Starting D-Channel on span %d\n", x + 1);
15291          }
15292       }
15293    }
15294 #endif
15295 #ifdef HAVE_SS7
15296    if (reload != 1) {
15297       int x;
15298       for (x = 0; x < NUM_SPANS; x++) {
15299          if (linksets[x].ss7) {
15300             if (ast_pthread_create(&linksets[x].master, NULL, ss7_linkset, &linksets[x])) {
15301                ast_log(LOG_ERROR, "Unable to start SS7 linkset on span %d\n", x + 1);
15302                return -1;
15303             } else
15304                ast_verb(2, "Starting SS7 linkset on span %d\n", x + 1);
15305          }
15306       }
15307    }
15308 #endif
15309    /* And start the monitor for the first time */
15310    restart_monitor();
15311    return 0;
15312 }
15313 
15314 static int load_module(void)
15315 {
15316    int res;
15317 #if defined(HAVE_PRI) || defined(HAVE_SS7)
15318    int y, i;
15319 #endif
15320 
15321 #ifdef HAVE_PRI
15322    memset(pris, 0, sizeof(pris));
15323    for (y = 0; y < NUM_SPANS; y++) {
15324       ast_mutex_init(&pris[y].lock);
15325       pris[y].offset = -1;
15326       pris[y].master = AST_PTHREADT_NULL;
15327       for (i = 0; i < NUM_DCHANS; i++)
15328          pris[y].fds[i] = -1;
15329    }
15330    pri_set_error(dahdi_pri_error);
15331    pri_set_message(dahdi_pri_message);
15332    ast_register_application(dahdi_send_keypad_facility_app, dahdi_send_keypad_facility_exec,
15333          dahdi_send_keypad_facility_synopsis, dahdi_send_keypad_facility_descrip);
15334 #endif
15335 #ifdef HAVE_SS7
15336    memset(linksets, 0, sizeof(linksets));
15337    for (y = 0; y < NUM_SPANS; y++) {
15338       ast_mutex_init(&linksets[y].lock);
15339       linksets[y].master = AST_PTHREADT_NULL;
15340       for (i = 0; i < NUM_DCHANS; i++)
15341          linksets[y].fds[i] = -1;
15342    }
15343    ss7_set_error(dahdi_ss7_error);
15344    ss7_set_message(dahdi_ss7_message);
15345 #endif /* HAVE_SS7 */
15346    res = setup_dahdi(0);
15347    /* Make sure we can register our DAHDI channel type */
15348    if (res)
15349       return AST_MODULE_LOAD_DECLINE;
15350    if (ast_channel_register(&dahdi_tech)) {
15351       ast_log(LOG_ERROR, "Unable to register channel class 'DAHDI'\n");
15352       __unload_module();
15353       return AST_MODULE_LOAD_FAILURE;
15354    }
15355 #ifdef HAVE_PRI
15356    ast_string_field_init(&inuse, 16);
15357    ast_string_field_set(&inuse, name, "GR-303InUse");
15358    ast_cli_register_multiple(dahdi_pri_cli, ARRAY_LEN(dahdi_pri_cli));
15359 #endif   
15360 #ifdef HAVE_SS7
15361    ast_cli_register_multiple(dahdi_ss7_cli, ARRAY_LEN(dahdi_ss7_cli));
15362 #endif
15363 
15364    ast_cli_register_multiple(dahdi_cli, ARRAY_LEN(dahdi_cli));
15365    
15366    memset(round_robin, 0, sizeof(round_robin));
15367    ast_manager_register( "DAHDITransfer", 0, action_transfer, "Transfer DAHDI Channel" );
15368    ast_manager_register( "DAHDIHangup", 0, action_transferhangup, "Hangup DAHDI Channel" );
15369    ast_manager_register( "DAHDIDialOffhook", 0, action_dahdidialoffhook, "Dial over DAHDI channel while offhook" );
15370    ast_manager_register( "DAHDIDNDon", 0, action_dahdidndon, "Toggle DAHDI channel Do Not Disturb status ON" );
15371    ast_manager_register( "DAHDIDNDoff", 0, action_dahdidndoff, "Toggle DAHDI channel Do Not Disturb status OFF" );
15372    ast_manager_register("DAHDIShowChannels", 0, action_dahdishowchannels, "Show status DAHDI channels");
15373    ast_manager_register("DAHDIRestart", 0, action_dahdirestart, "Fully Restart DAHDI channels (terminates calls)");
15374 
15375    ast_cond_init(&mwi_thread_complete, NULL);
15376    ast_cond_init(&ss_thread_complete, NULL);
15377 
15378    return res;
15379 }
15380 
15381 static int dahdi_sendtext(struct ast_channel *c, const char *text)
15382 {
15383 #define  END_SILENCE_LEN 400
15384 #define  HEADER_MS 50
15385 #define  TRAILER_MS 5
15386 #define  HEADER_LEN ((HEADER_MS + TRAILER_MS) * 8)
15387 #define  ASCII_BYTES_PER_CHAR 80
15388 
15389    unsigned char *buf,*mybuf;
15390    struct dahdi_pvt *p = c->tech_pvt;
15391    struct pollfd fds[1];
15392    int size,res,fd,len,x;
15393    int bytes=0;
15394    /* Initial carrier (imaginary) */
15395    float cr = 1.0;
15396    float ci = 0.0;
15397    float scont = 0.0;
15398    int idx;
15399 
15400    idx = dahdi_get_index(c, p, 0);
15401    if (idx < 0) {
15402       ast_log(LOG_WARNING, "Huh?  I don't exist?\n");
15403       return -1;
15404    }
15405    if (!text[0]) return(0); /* if nothing to send, dont */
15406    if ((!p->tdd) && (!p->mate)) return(0);  /* if not in TDD mode, just return */
15407    if (p->mate) 
15408       buf = ast_malloc(((strlen(text) + 1) * ASCII_BYTES_PER_CHAR) + END_SILENCE_LEN + HEADER_LEN);
15409    else
15410       buf = ast_malloc(((strlen(text) + 1) * TDD_BYTES_PER_CHAR) + END_SILENCE_LEN);
15411    if (!buf)
15412       return -1;
15413    mybuf = buf;
15414    if (p->mate) {
15415       int codec = AST_LAW(p);
15416       for (x = 0; x < HEADER_MS; x++) {   /* 50 ms of Mark */
15417          PUT_CLID_MARKMS;
15418       }
15419       /* Put actual message */
15420       for (x = 0; text[x]; x++) {
15421          PUT_CLID(text[x]);
15422       }
15423       for (x = 0; x < TRAILER_MS; x++) {  /* 5 ms of Mark */
15424          PUT_CLID_MARKMS;
15425       }
15426       len = bytes;
15427       buf = mybuf;
15428    } else {
15429       len = tdd_generate(p->tdd, buf, text);
15430       if (len < 1) {
15431          ast_log(LOG_ERROR, "TDD generate (len %d) failed!!\n", (int)strlen(text));
15432          ast_free(mybuf);
15433          return -1;
15434       }
15435    }
15436    memset(buf + len, 0x7f, END_SILENCE_LEN);
15437    len += END_SILENCE_LEN;
15438    fd = p->subs[idx].dfd;
15439    while (len) {
15440       if (ast_check_hangup(c)) {
15441          ast_free(mybuf);
15442          return -1;
15443       }
15444       size = len;
15445       if (size > READ_SIZE)
15446          size = READ_SIZE;
15447       fds[0].fd = fd;
15448       fds[0].events = POLLOUT | POLLPRI;
15449       fds[0].revents = 0;
15450       res = poll(fds, 1, -1);
15451       if (!res) {
15452          ast_debug(1, "poll (for write) ret. 0 on channel %d\n", p->channel);
15453          continue;
15454       }
15455         /* if got exception */
15456       if (fds[0].revents & POLLPRI) {
15457          ast_free(mybuf);
15458          return -1;
15459       }
15460       if (!(fds[0].revents & POLLOUT)) {
15461          ast_debug(1, "write fd not ready on channel %d\n", p->channel);
15462          continue;
15463       }
15464       res = write(fd, buf, size);
15465       if (res != size) {
15466          if (res == -1) {
15467             ast_free(mybuf);
15468             return -1;
15469          }
15470          ast_debug(1, "Write returned %d (%s) on channel %d\n", res, strerror(errno), p->channel);
15471          break;
15472       }
15473       len -= size;
15474       buf += size;
15475    }
15476    ast_free(mybuf);
15477    return(0);
15478 }
15479 
15480 
15481 static int reload(void)
15482 {
15483    int res = 0;
15484 
15485    res = setup_dahdi(1);
15486    if (res) {
15487       ast_log(LOG_WARNING, "Reload of chan_dahdi.so is unsuccessful!\n");
15488       return -1;
15489    }
15490    return 0;
15491 }
15492 
15493 /* This is a workaround so that menuselect displays a proper description
15494  * AST_MODULE_INFO(, , "DAHDI Telephony"
15495  */
15496 
15497 #ifdef HAVE_PRI
15498 #ifdef HAVE_SS7
15499 #define tdesc "DAHDI Telephony w/PRI & SS7"
15500 #else
15501 #define tdesc "DAHDI Telephony w/PRI"
15502 #endif
15503 #else
15504 #ifdef HAVE_SS7
15505 #define tdesc "DAHDI Telephony w/SS7"
15506 #else
15507 #define tdesc "DAHDI Telephony"
15508 #endif
15509 #endif
15510 
15511 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, tdesc,
15512       .load = load_module,
15513       .unload = unload_module,
15514       .reload = reload,
15515           );
15516 
15517 

Generated on 2 Mar 2010 for Asterisk - the Open Source PBX by  doxygen 1.6.1