chan_misdn.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  *
00004  * Copyright (C) 2004 - 2006, Christian Richter
00005  *
00006  * Christian Richter <crich@beronet.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 
00020 /*!
00021  * \file
00022  *
00023  * \brief the chan_misdn channel driver for Asterisk
00024  *
00025  * \author Christian Richter <crich@beronet.com>
00026  *
00027  * MISDN http://www.misdn.org/
00028  *
00029  * \ingroup channel_drivers
00030  */
00031 
00032 /*! \li \ref chan_misdn.c uses the configuration file \ref misdn.conf
00033  * \addtogroup configuration_file
00034  */
00035 
00036 /*! \page misdn.conf misdn.conf
00037  * \verbinclude misdn.conf.sample
00038  */
00039 
00040 /*!
00041  * \note
00042  * To use the CCBS/CCNR supplementary service feature and other
00043  * supplementary services using FACILITY messages requires a
00044  * modified version of mISDN.
00045  *
00046  * \note
00047  * The latest modified mISDN v1.1.x based version is available at:
00048  * http://svn.digium.com/svn/thirdparty/mISDN/trunk
00049  * http://svn.digium.com/svn/thirdparty/mISDNuser/trunk
00050  *
00051  * \note
00052  * Taged versions of the modified mISDN code are available under:
00053  * http://svn.digium.com/svn/thirdparty/mISDN/tags
00054  * http://svn.digium.com/svn/thirdparty/mISDNuser/tags
00055  */
00056 
00057 /* Define to enable cli commands to generate canned CCBS messages. */
00058 // #define CCBS_TEST_MESSAGES 1
00059 
00060 /*
00061  * XXX The mISDN channel driver needs its native bridge code
00062  * converted to the new bridge technology scheme.  The
00063  * chan_dahdi native bridge code can be used as an example.  It
00064  * is unlikely that this will ever get done.  Support for this
00065  * channel driver is dwindling because the supported version of
00066  * mISDN does not support newer kernels.
00067  *
00068  * Without native bridge support, the following config file
00069  * parameters have no effect: bridging.
00070  *
00071  * The existing native bridge code is marked with the
00072  * mISDN_NATIVE_BRIDGING conditional.
00073  */
00074 
00075 /*** MODULEINFO
00076    <depend>isdnnet</depend>
00077    <depend>misdn</depend>
00078    <depend>suppserv</depend>
00079    <support_level>extended</support_level>
00080  ***/
00081 
00082 #include "asterisk.h"
00083 
00084 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 431000 $")
00085 
00086 #include <pthread.h>
00087 #include <sys/socket.h>
00088 #include <sys/time.h>
00089 #include <arpa/inet.h>
00090 #include <fcntl.h>
00091 #include <sys/ioctl.h>
00092 #include <signal.h>
00093 #include <sys/file.h>
00094 #include <semaphore.h>
00095 #include <ctype.h>
00096 #include <time.h>
00097 
00098 #include "asterisk/channel.h"
00099 #include "asterisk/config.h"
00100 #include "asterisk/module.h"
00101 #include "asterisk/pbx.h"
00102 #include "asterisk/io.h"
00103 #include "asterisk/frame.h"
00104 #include "asterisk/translate.h"
00105 #include "asterisk/cli.h"
00106 #include "asterisk/musiconhold.h"
00107 #include "asterisk/dsp.h"
00108 #include "asterisk/file.h"
00109 #include "asterisk/callerid.h"
00110 #include "asterisk/indications.h"
00111 #include "asterisk/app.h"
00112 #include "asterisk/features.h"
00113 #include "asterisk/term.h"
00114 #include "asterisk/sched.h"
00115 #include "asterisk/stringfields.h"
00116 #include "asterisk/abstract_jb.h"
00117 #include "asterisk/causes.h"
00118 #include "asterisk/format.h"
00119 #include "asterisk/format_cap.h"
00120 #include "asterisk/features_config.h"
00121 #include "asterisk/bridge.h"
00122 #include "asterisk/pickup.h"
00123 #include "asterisk/format_cache.h"
00124 
00125 #include "chan_misdn_config.h"
00126 #include "isdn_lib.h"
00127 
00128 static char global_tracefile[BUFFERSIZE + 1];
00129 
00130 static int g_config_initialized = 0;
00131 
00132 struct misdn_jb{
00133    int size;
00134    int upper_threshold;
00135    char *samples, *ok;
00136    int wp,rp;
00137    int state_empty;
00138    int state_full;
00139    int state_buffer;
00140    int bytes_wrote;
00141    ast_mutex_t mutexjb;
00142 };
00143 
00144 /*! \brief allocates the jb-structure and initialize the elements */
00145 struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
00146 
00147 /*! \brief frees the data and destroys the given jitterbuffer struct */
00148 void misdn_jb_destroy(struct misdn_jb *jb);
00149 
00150 /*! \brief fills the jitterbuffer with len data returns < 0 if there was an
00151 error (buffer overrun). */
00152 int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len);
00153 
00154 /*! \brief gets len bytes out of the jitterbuffer if available, else only the
00155 available data is returned and the return value indicates the number
00156 of data. */
00157 int misdn_jb_empty(struct misdn_jb *jb, char *data, int len);
00158 
00159 static char *complete_ch(struct ast_cli_args *a);
00160 static char *complete_debug_port(struct ast_cli_args *a);
00161 static char *complete_show_config(struct ast_cli_args *a);
00162 
00163 /* BEGIN: chan_misdn.h */
00164 
00165 #if defined(AST_MISDN_ENHANCEMENTS)
00166 /*
00167  * This timeout duration is to clean up any call completion records that
00168  * are forgotten about by the switch.
00169  */
00170 #define MISDN_CC_RECORD_AGE_MAX     (6UL * 60 * 60)   /* seconds */
00171 
00172 #define MISDN_CC_REQUEST_WAIT_MAX   5  /* seconds */
00173 
00174 /*!
00175  * \brief Caller that initialized call completion services
00176  *
00177  * \details
00178  * This data is the payload for a datastore that is put on the channel that
00179  * initializes call completion services.  This datastore is set to be inherited
00180  * by the outbound mISDN channel.  When one of these channels hangs up, the
00181  * channel pointer will be set to NULL.  That way, we can ensure that we do not
00182  * touch this channel after it gets destroyed.
00183  */
00184 struct misdn_cc_caller {
00185    /*! \brief The channel that initialized call completion services */
00186    struct ast_channel *chan;
00187 };
00188 
00189 struct misdn_cc_notify {
00190    /*! \brief Dialplan: Notify extension priority */
00191    int priority;
00192 
00193    /*! \brief Dialplan: Notify extension context */
00194    char context[AST_MAX_CONTEXT];
00195 
00196    /*! \brief Dialplan: Notify extension number (User-A) */
00197    char exten[AST_MAX_EXTENSION];
00198 };
00199 
00200 /*! \brief mISDN call completion record */
00201 struct misdn_cc_record {
00202    /*! \brief Call completion record linked list */
00203    AST_LIST_ENTRY(misdn_cc_record) list;
00204 
00205    /*! \brief Time the record was created. */
00206    time_t time_created;
00207 
00208    /*! \brief MISDN_CC_RECORD_ID value */
00209    long record_id;
00210 
00211    /*!
00212     * \brief Logical Layer 1 port associated with this
00213     * call completion record
00214     */
00215    int port;
00216 
00217    /*! \brief TRUE if point-to-point mode (CCBS-T/CCNR-T mode) */
00218    int ptp;
00219 
00220    /*! \brief Mode specific parameters */
00221    union {
00222       /*! \brief point-to-point specific parameters. */
00223       struct {
00224          /*!
00225           * \brief Call-completion signaling link.
00226           * NULL if signaling link not established.
00227           */
00228          struct misdn_bchannel *bc;
00229 
00230          /*!
00231           * \brief TRUE if we requested the request retention option
00232           * to be enabled.
00233           */
00234          int requested_retention;
00235 
00236          /*!
00237           * \brief TRUE if the request retention option is enabled.
00238           */
00239          int retention_enabled;
00240       } ptp;
00241 
00242       /*! \brief point-to-multi-point specific parameters. */
00243       struct {
00244          /*! \brief CallLinkageID (valid when port determined) */
00245          int linkage_id;
00246 
00247          /*! \breif CCBSReference (valid when activated is TRUE) */
00248          int reference_id;
00249 
00250          /*! \brief globalRecall(0),   specificRecall(1) */
00251          int recall_mode;
00252       } ptmp;
00253    } mode;
00254 
00255    /*! \brief TRUE if call completion activated */
00256    int activated;
00257 
00258    /*! \brief Outstanding message ID (valid when outstanding_message) */
00259    int invoke_id;
00260 
00261    /*! \brief TRUE if waiting for a response from a message (invoke_id is valid) */
00262    int outstanding_message;
00263 
00264    /*! \brief TRUE if activation has been requested */
00265    int activation_requested;
00266 
00267    /*!
00268     * \brief TRUE if User-A is free
00269     * \note PTMP - Used to answer CCBSStatusRequest.
00270     * PTP - Determines how to respond to CCBS_T_RemoteUserFree.
00271     */
00272    int party_a_free;
00273 
00274    /*! \brief Error code received from last outstanding message. */
00275    enum FacErrorCode error_code;
00276 
00277    /*! \brief Reject code received from last outstanding message. */
00278    enum FacRejectCode reject_code;
00279 
00280    /*!
00281     * \brief Saved struct misdn_bchannel call information when
00282     * attempted to call User-B
00283     */
00284    struct {
00285       /*! \brief User-A caller id information */
00286       struct misdn_party_id caller;
00287 
00288       /*! \brief User-B number information */
00289       struct misdn_party_dialing dialed;
00290 
00291       /*! \brief The BC, HLC (optional) and LLC (optional) contents from the SETUP message. */
00292       struct Q931_Bc_Hlc_Llc setup_bc_hlc_llc;
00293 
00294       /*! \brief SETUP message bearer capability field code value */
00295       int capability;
00296 
00297       /*! \brief TRUE if call made in digital HDLC mode */
00298       int hdlc;
00299    } redial;
00300 
00301    /*! \brief Dialplan location to indicate User-B free and User-A is free */
00302    struct misdn_cc_notify remote_user_free;
00303 
00304    /*! \brief Dialplan location to indicate User-B free and User-A is busy */
00305    struct misdn_cc_notify b_free;
00306 };
00307 
00308 /*! \brief mISDN call completion record database */
00309 static AST_LIST_HEAD_STATIC(misdn_cc_records_db, misdn_cc_record);
00310 /*! \brief Next call completion record ID to use */
00311 static __u16 misdn_cc_record_id;
00312 /*! \brief Next invoke ID to use */
00313 static __s16 misdn_invoke_id;
00314 
00315 static const char misdn_no_response_from_network[] = "No response from network";
00316 static const char misdn_cc_record_not_found[] = "Call completion record not found";
00317 
00318 /* mISDN channel variable names */
00319 #define MISDN_CC_RECORD_ID "MISDN_CC_RECORD_ID"
00320 #define MISDN_CC_STATUS    "MISDN_CC_STATUS"
00321 #define MISDN_ERROR_MSG    "MISDN_ERROR_MSG"
00322 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
00323 
00324 static ast_mutex_t release_lock;
00325 
00326 enum misdn_chan_state {
00327    MISDN_NOTHING = 0,         /*!< at beginning */
00328    MISDN_WAITING4DIGS,        /*!< when waiting for info */
00329    MISDN_EXTCANTMATCH,        /*!< when asterisk couldn't match our ext */
00330    MISDN_INCOMING_SETUP,      /*!< for incoming setup */
00331    MISDN_DIALING,             /*!< when pbx_start */
00332    MISDN_PROGRESS,            /*!< we have progress */
00333    MISDN_PROCEEDING,          /*!< we have progress */
00334    MISDN_CALLING,             /*!< when misdn_call is called */
00335    MISDN_CALLING_ACKNOWLEDGE, /*!< when we get SETUP_ACK */
00336    MISDN_ALERTING,            /*!< when Alerting */
00337    MISDN_BUSY,                /*!< when BUSY */
00338    MISDN_CONNECTED,           /*!< when connected */
00339    MISDN_DISCONNECTED,        /*!< when connected */
00340    MISDN_CLEANING,            /*!< when hangup from * but we were connected before */
00341 };
00342 
00343 /*! Asterisk created the channel (outgoing call) */
00344 #define ORG_AST 1
00345 /*! mISDN created the channel (incoming call) */
00346 #define ORG_MISDN 2
00347 
00348 enum misdn_hold_state {
00349    MISDN_HOLD_IDLE,     /*!< HOLD not active */
00350    MISDN_HOLD_ACTIVE,      /*!< Call is held */
00351    MISDN_HOLD_TRANSFER, /*!< Held call is being transferred */
00352    MISDN_HOLD_DISCONNECT,  /*!< Held call is being disconnected */
00353 };
00354 struct hold_info {
00355    /*!
00356     * \brief Call HOLD state.
00357     */
00358    enum misdn_hold_state state;
00359    /*!
00360     * \brief Logical port the channel call record is HELD on
00361     * because the B channel is no longer associated.
00362     */
00363    int port;
00364 
00365    /*!
00366     * \brief Original B channel number the HELD call was using.
00367     * \note Used only for debug display messages.
00368     */
00369    int channel;
00370 };
00371 
00372 #define chan_list_ref(obj, debug) (ao2_t_ref((obj), +1, (debug)), (obj))
00373 #define chan_list_unref(obj, debug) (ao2_t_ref((obj), -1, (debug)), NULL)
00374 
00375 /*!
00376  * \brief Channel call record structure
00377  */
00378 struct chan_list {
00379    /*!
00380     * \brief The "allowed_bearers" string read in from /etc/asterisk/misdn.conf
00381     */
00382    char allowed_bearers[BUFFERSIZE + 1];
00383 
00384    /*!
00385     * \brief State of the channel
00386     */
00387    enum misdn_chan_state state;
00388 
00389    /*!
00390     * \brief TRUE if a hangup needs to be queued
00391     * \note This is a debug flag only used to catch calls to hangup_chan() that are already hungup.
00392     */
00393    int need_queue_hangup;
00394 
00395    /*!
00396     * \brief TRUE if a channel can be hung up by calling asterisk directly when done.
00397     */
00398    int need_hangup;
00399 
00400    /*!
00401     * \brief TRUE if we could send an AST_CONTROL_BUSY if needed.
00402     */
00403    int need_busy;
00404 
00405    /*!
00406     * \brief Who originally created this channel. ORG_AST or ORG_MISDN
00407     */
00408    int originator;
00409 
00410    /*!
00411     * \brief TRUE of we are not to respond immediately to a SETUP message.  Check the dialplan first.
00412     * \note The "noautorespond_on_setup" boolean read in from /etc/asterisk/misdn.conf
00413     */
00414    int noautorespond_on_setup;
00415 
00416    int norxtone;  /*!< Boolean assigned values but the value is not used. */
00417 
00418    /*!
00419     * \brief TRUE if we are not to generate tones (Playtones)
00420     */
00421    int notxtone;
00422 
00423    /*!
00424     * \brief TRUE if echo canceller is enabled.  Value is toggled.
00425     */
00426    int toggle_ec;
00427 
00428    /*!
00429     * \brief TRUE if you want to send Tone Indications to an incoming
00430     * ISDN channel on a TE Port.
00431     * \note The "incoming_early_audio" boolean read in from /etc/asterisk/misdn.conf
00432     */
00433    int incoming_early_audio;
00434 
00435    /*!
00436     * \brief TRUE if DTMF digits are to be passed inband only.
00437     * \note It is settable by the misdn_set_opt() application.
00438     */
00439    int ignore_dtmf;
00440 
00441    /*!
00442     * \brief Pipe file descriptor handles array.
00443     * Read from pipe[0], write to pipe[1]
00444     */
00445    int pipe[2];
00446 
00447    /*!
00448     * \brief Read buffer for inbound audio from pipe[0]
00449     */
00450    char ast_rd_buf[4096];
00451 
00452    /*!
00453     * \brief Inbound audio frame returned by misdn_read().
00454     */
00455    struct ast_frame frame;
00456 
00457    /*!
00458     * \brief Fax detection option. (0:no 1:yes 2:yes+nojump)
00459     * \note The "faxdetect" option string read in from /etc/asterisk/misdn.conf
00460     * \note It is settable by the misdn_set_opt() application.
00461     */
00462    int faxdetect;
00463 
00464    /*!
00465     * \brief Number of seconds to detect a Fax machine when detection enabled.
00466     * \note 0 disables the timeout.
00467     * \note The "faxdetect_timeout" value read in from /etc/asterisk/misdn.conf
00468     */
00469    int faxdetect_timeout;
00470 
00471    /*!
00472     * \brief Starting time of fax detection with timeout when nonzero.
00473     */
00474    struct timeval faxdetect_tv;
00475 
00476    /*!
00477     * \brief TRUE if a fax has been detected.
00478     */
00479    int faxhandled;
00480 
00481    /*!
00482     * \brief TRUE if we will use the Asterisk DSP to detect DTMF/Fax
00483     * \note The "astdtmf" boolean read in from /etc/asterisk/misdn.conf
00484     */
00485    int ast_dsp;
00486 
00487    /*!
00488     * \brief Jitterbuffer length
00489     * \note The "jitterbuffer" value read in from /etc/asterisk/misdn.conf
00490     */
00491    int jb_len;
00492 
00493    /*!
00494     * \brief Jitterbuffer upper threshold
00495     * \note The "jitterbuffer_upper_threshold" value read in from /etc/asterisk/misdn.conf
00496     */
00497    int jb_upper_threshold;
00498 
00499    /*!
00500     * \brief Allocated jitterbuffer controller
00501     * \note misdn_jb_init() creates the jitterbuffer.
00502     * \note Must use misdn_jb_destroy() to clean up.
00503     */
00504    struct misdn_jb *jb;
00505 
00506    /*!
00507     * \brief Allocated DSP controller
00508     * \note ast_dsp_new() creates the DSP controller.
00509     * \note Must use ast_dsp_free() to clean up.
00510     */
00511    struct ast_dsp *dsp;
00512 
00513    /*!
00514     * \brief Associated Asterisk channel structure.
00515     */
00516    struct ast_channel * ast;
00517 
00518    /*!
00519     * \brief Associated B channel structure.
00520     */
00521    struct misdn_bchannel *bc;
00522 
00523 #if defined(AST_MISDN_ENHANCEMENTS)
00524    /*!
00525     * \brief Peer channel for which call completion was initialized.
00526     */
00527    struct misdn_cc_caller *peer;
00528 
00529    /*! \brief Associated call completion record ID (-1 if not associated) */
00530    long record_id;
00531 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
00532 
00533    /*!
00534     * \brief HELD channel call information
00535     */
00536    struct hold_info hold;
00537 
00538    /*!
00539     * \brief From associated B channel: Layer 3 process ID
00540     * \note Used to find the HELD channel call record when retrieving a call.
00541     */
00542    unsigned int l3id;
00543 
00544    /*!
00545     * \brief From associated B channel: B Channel mISDN driver layer ID from mISDN_get_layerid()
00546     * \note Used only for debug display messages.
00547     */
00548    int addr;
00549 
00550    /*!
00551     * \brief Incoming call dialplan context identifier.
00552     * \note The "context" string read in from /etc/asterisk/misdn.conf
00553     */
00554    char context[AST_MAX_CONTEXT];
00555 
00556    /*!
00557     * \brief The configured music-on-hold class to use for this call.
00558     * \note The "musicclass" string read in from /etc/asterisk/misdn.conf
00559     */
00560    char mohinterpret[MAX_MUSICCLASS];
00561 
00562    /*!
00563     * \brief Number of outgoing audio frames dropped since last debug gripe message.
00564     */
00565    int dropped_frame_cnt;
00566 
00567    /*!
00568     * \brief TRUE if we must do the ringback tones.
00569     * \note The "far_alerting" boolean read in from /etc/asterisk/misdn.conf
00570     */
00571    int far_alerting;
00572 
00573    /*!
00574     * \brief TRUE if NT should disconnect an overlap dialing call when a timeout occurs.
00575     * \note The "nttimeout" boolean read in from /etc/asterisk/misdn.conf
00576     */
00577    int nttimeout;
00578 
00579    /*!
00580     * \brief Tone zone sound used for dialtone generation.
00581     * \note Used as a boolean.  Non-NULL to prod generation if enabled.
00582     */
00583    struct ast_tone_zone_sound *ts;
00584 
00585    /*!
00586     * \brief Enables overlap dialing for the set amount of seconds.  (0 = Disabled)
00587     * \note The "overlapdial" value read in from /etc/asterisk/misdn.conf
00588     */
00589    int overlap_dial;
00590 
00591    /*!
00592     * \brief Overlap dialing timeout Task ID.  -1 if not running.
00593     */
00594    int overlap_dial_task;
00595 
00596    /*!
00597     * \brief overlap_tv access lock.
00598     */
00599    ast_mutex_t overlap_tv_lock;
00600 
00601    /*!
00602     * \brief Overlap timer start time.  Timer restarted for every digit received.
00603     */
00604    struct timeval overlap_tv;
00605 
00606    /*!
00607     * \brief Next channel call record in the list.
00608     */
00609    struct chan_list *next;
00610 };
00611 
00612 
00613 int MAXTICS = 8;
00614 
00615 
00616 void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
00617 void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
00618 static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame);
00619 
00620 struct robin_list {
00621    char *group;
00622    int port;
00623    int channel;
00624    struct robin_list *next;
00625    struct robin_list *prev;
00626 };
00627 static struct robin_list *robin = NULL;
00628 
00629 
00630 static void free_robin_list(void)
00631 {
00632    struct robin_list *r;
00633    struct robin_list *next;
00634 
00635    for (r = robin, robin = NULL; r; r = next) {
00636       next = r->next;
00637       ast_free(r->group);
00638       ast_free(r);
00639    }
00640 }
00641 
00642 static struct robin_list *get_robin_position(char *group)
00643 {
00644    struct robin_list *new;
00645    struct robin_list *iter = robin;
00646    for (; iter; iter = iter->next) {
00647       if (!strcasecmp(iter->group, group)) {
00648          return iter;
00649       }
00650    }
00651    new = ast_calloc(1, sizeof(*new));
00652    if (!new) {
00653       return NULL;
00654    }
00655    new->group = ast_strdup(group);
00656    if (!new->group) {
00657       ast_free(new);
00658       return NULL;
00659    }
00660    new->channel = 1;
00661    if (robin) {
00662       new->next = robin;
00663       robin->prev = new;
00664    }
00665    robin = new;
00666    return robin;
00667 }
00668 
00669 
00670 /*! \brief the main schedule context for stuff like l1 watcher, overlap dial, ... */
00671 static struct ast_sched_context *misdn_tasks = NULL;
00672 static pthread_t misdn_tasks_thread;
00673 
00674 static int *misdn_ports;
00675 
00676 static void chan_misdn_log(int level, int port, char *tmpl, ...)
00677    __attribute__((format(printf, 3, 4)));
00678 
00679 static struct ast_channel *misdn_new(struct chan_list *cl, int state,  char *exten, char *callerid, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, int port, int c);
00680 static void send_digit_to_chan(struct chan_list *cl, char digit);
00681 
00682 static int pbx_start_chan(struct chan_list *ch);
00683 
00684 #define MISDN_ASTERISK_TECH_PVT(ast) ast_channel_tech_pvt(ast)
00685 #define MISDN_ASTERISK_TECH_PVT_SET(ast, value) ast_channel_tech_pvt_set(ast, value)
00686 
00687 #include "asterisk/strings.h"
00688 
00689 /* #define MISDN_DEBUG 1 */
00690 
00691 static const char misdn_type[] = "mISDN";
00692 
00693 static int tracing = 0;
00694 
00695 static int *misdn_debug;
00696 static int *misdn_debug_only;
00697 static int max_ports;
00698 
00699 static int *misdn_in_calls;
00700 static int *misdn_out_calls;
00701 
00702 /*!
00703  * \brief Global channel call record list head.
00704  */
00705 static struct chan_list *cl_te=NULL;
00706 static ast_mutex_t cl_te_lock;
00707 
00708 static enum event_response_e
00709 cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);
00710 
00711 static int send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch);
00712 
00713 static void cl_queue_chan(struct chan_list *chan);
00714 
00715 static int dialtone_indicate(struct chan_list *cl);
00716 static void hanguptone_indicate(struct chan_list *cl);
00717 static int stop_indicate(struct chan_list *cl);
00718 
00719 static int start_bc_tones(struct chan_list *cl);
00720 static int stop_bc_tones(struct chan_list *cl);
00721 static void release_chan_early(struct chan_list *ch);
00722 static void release_chan(struct chan_list *ch, struct misdn_bchannel *bc);
00723 
00724 #if defined(AST_MISDN_ENHANCEMENTS)
00725 static const char misdn_command_name[] = "misdn_command";
00726 static int misdn_command_exec(struct ast_channel *chan, const char *data);
00727 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
00728 static int misdn_check_l2l1(struct ast_channel *chan, const char *data);
00729 static int misdn_set_opt_exec(struct ast_channel *chan, const char *data);
00730 static int misdn_facility_exec(struct ast_channel *chan, const char *data);
00731 
00732 int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
00733 
00734 void debug_numtype(int port, int numtype, char *type);
00735 
00736 int add_out_calls(int port);
00737 int add_in_calls(int port);
00738 
00739 
00740 #ifdef MISDN_1_2
00741 static int update_pipeline_config(struct misdn_bchannel *bc);
00742 #else
00743 static int update_ec_config(struct misdn_bchannel *bc);
00744 #endif
00745 
00746 
00747 
00748 /*************** Helpers *****************/
00749 
00750 static int misdn_chan_is_valid(struct chan_list *ch)
00751 {
00752    struct chan_list *list;
00753 
00754    ast_mutex_lock(&cl_te_lock);
00755    for (list = cl_te; list; list = list->next) {
00756       if (list == ch) {
00757          ast_mutex_unlock(&cl_te_lock);
00758          return 1;
00759       }
00760    }
00761    ast_mutex_unlock(&cl_te_lock);
00762 
00763    return 0;
00764 }
00765 
00766 #if defined(mISDN_NATIVE_BRIDGING)
00767 /*! Returns a reference to the found chan_list. */
00768 static struct chan_list *get_chan_by_ast(struct ast_channel *ast)
00769 {
00770    struct chan_list *tmp;
00771 
00772    ast_mutex_lock(&cl_te_lock);
00773    for (tmp = cl_te; tmp; tmp = tmp->next) {
00774       if (tmp->ast == ast) {
00775          chan_list_ref(tmp, "Found chan_list by ast");
00776          ast_mutex_unlock(&cl_te_lock);
00777          return tmp;
00778       }
00779    }
00780    ast_mutex_unlock(&cl_te_lock);
00781 
00782    return NULL;
00783 }
00784 #endif   /* defined(mISDN_NATIVE_BRIDGING) */
00785 
00786 /*! Returns a reference to the found chan_list. */
00787 static struct chan_list *get_chan_by_ast_name(const char *name)
00788 {
00789    struct chan_list *tmp;
00790 
00791    ast_mutex_lock(&cl_te_lock);
00792    for (tmp = cl_te; tmp; tmp = tmp->next) {
00793       if (tmp->ast && strcmp(ast_channel_name(tmp->ast), name) == 0) {
00794          chan_list_ref(tmp, "Found chan_list by ast name");
00795          ast_mutex_unlock(&cl_te_lock);
00796          return tmp;
00797       }
00798    }
00799    ast_mutex_unlock(&cl_te_lock);
00800 
00801    return NULL;
00802 }
00803 
00804 #if defined(AST_MISDN_ENHANCEMENTS)
00805 /*!
00806  * \internal
00807  * \brief Destroy the misdn_cc_ds_info datastore payload
00808  *
00809  * \param[in] data the datastore payload, a reference to an misdn_cc_caller
00810  *
00811  * \details
00812  * Since the payload is a reference to an astobj2 object, we just decrement its
00813  * reference count.  Before doing so, we NULL out the channel pointer inside of
00814  * the misdn_cc_caller instance.  This function will be called in one of two
00815  * cases.  In both cases, we no longer need the channel pointer:
00816  *
00817  *  - The original channel that initialized call completion services, the same
00818  *    channel that is stored here, has been destroyed early.  This could happen
00819  *    if it transferred the mISDN channel, for example.
00820  *
00821  *  - The mISDN channel that had this datastore inherited on to it is now being
00822  *    destroyed.  If this is the case, then the call completion events have
00823  *    already occurred and the appropriate channel variables have already been
00824  *    set on the original channel that requested call completion services.
00825  *
00826  * \return Nothing
00827  */
00828 static void misdn_cc_ds_destroy(void *data)
00829 {
00830    struct misdn_cc_caller *cc_caller = data;
00831 
00832    ao2_lock(cc_caller);
00833    cc_caller->chan = NULL;
00834    ao2_unlock(cc_caller);
00835 
00836    ao2_ref(cc_caller, -1);
00837 }
00838 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
00839 
00840 #if defined(AST_MISDN_ENHANCEMENTS)
00841 /*!
00842  * \internal
00843  * \brief Duplicate the misdn_cc_ds_info datastore payload
00844  *
00845  * \param[in] data the datastore payload, a reference to an misdn_cc_caller
00846  *
00847  * \details
00848  * All we need to do is bump the reference count and return the same instance.
00849  *
00850  * \return A reference to an instance of a misdn_cc_caller
00851  */
00852 static void *misdn_cc_ds_duplicate(void *data)
00853 {
00854    struct misdn_cc_caller *cc_caller = data;
00855 
00856    ao2_ref(cc_caller, +1);
00857 
00858    return cc_caller;
00859 }
00860 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
00861 
00862 #if defined(AST_MISDN_ENHANCEMENTS)
00863 static const struct ast_datastore_info misdn_cc_ds_info = {
00864    .type      = "misdn_cc",
00865    .destroy   = misdn_cc_ds_destroy,
00866    .duplicate = misdn_cc_ds_duplicate,
00867 };
00868 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
00869 
00870 #if defined(AST_MISDN_ENHANCEMENTS)
00871 /*!
00872  * \internal
00873  * \brief Set a channel var on the peer channel for call completion services
00874  *
00875  * \param[in] peer The peer that initialized call completion services
00876  * \param[in] var The variable name to set
00877  * \param[in] value The variable value to set
00878  *
00879  * This function may be called from outside of the channel thread.  It handles
00880  * the fact that the peer channel may be hung up and destroyed at any time.
00881  *
00882  * \return nothing
00883  */
00884 static void misdn_cc_set_peer_var(struct misdn_cc_caller *peer, const char *var,
00885    const char *value)
00886 {
00887    ao2_lock(peer);
00888 
00889    /*! \todo XXX This nastiness can go away once ast_channel is ref counted! */
00890    while (peer->chan && ast_channel_trylock(peer->chan)) {
00891       ao2_unlock(peer);
00892       sched_yield();
00893       ao2_lock(peer);
00894    }
00895 
00896    if (peer->chan) {
00897       pbx_builtin_setvar_helper(peer->chan, var, value);
00898       ast_channel_unlock(peer->chan);
00899    }
00900 
00901    ao2_unlock(peer);
00902 }
00903 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
00904 
00905 #if defined(AST_MISDN_ENHANCEMENTS)
00906 /*!
00907  * \internal
00908  * \brief Get a reference to the CC caller if it exists
00909  */
00910 static struct misdn_cc_caller *misdn_cc_caller_get(struct ast_channel *chan)
00911 {
00912    struct ast_datastore *datastore;
00913    struct misdn_cc_caller *cc_caller;
00914 
00915    ast_channel_lock(chan);
00916 
00917    if (!(datastore = ast_channel_datastore_find(chan, &misdn_cc_ds_info, NULL))) {
00918       ast_channel_unlock(chan);
00919       return NULL;
00920    }
00921 
00922    ao2_ref(datastore->data, +1);
00923    cc_caller = datastore->data;
00924 
00925    ast_channel_unlock(chan);
00926 
00927    return cc_caller;
00928 }
00929 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
00930 
00931 #if defined(AST_MISDN_ENHANCEMENTS)
00932 /*!
00933  * \internal
00934  * \brief Find the call completion record given the record id.
00935  *
00936  * \param record_id
00937  *
00938  * \retval pointer to found call completion record
00939  * \retval NULL if not found
00940  *
00941  * \note Assumes the misdn_cc_records_db lock is already obtained.
00942  */
00943 static struct misdn_cc_record *misdn_cc_find_by_id(long record_id)
00944 {
00945    struct misdn_cc_record *current;
00946 
00947    AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
00948       if (current->record_id == record_id) {
00949          /* Found the record */
00950          break;
00951       }
00952    }
00953 
00954    return current;
00955 }
00956 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
00957 
00958 #if defined(AST_MISDN_ENHANCEMENTS)
00959 /*!
00960  * \internal
00961  * \brief Find the call completion record given the port and call linkage id.
00962  *
00963  * \param port Logical port number
00964  * \param linkage_id Call linkage ID number from switch.
00965  *
00966  * \retval pointer to found call completion record
00967  * \retval NULL if not found
00968  *
00969  * \note Assumes the misdn_cc_records_db lock is already obtained.
00970  */
00971 static struct misdn_cc_record *misdn_cc_find_by_linkage(int port, int linkage_id)
00972 {
00973    struct misdn_cc_record *current;
00974 
00975    AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
00976       if (current->port == port
00977          && !current->ptp
00978          && current->mode.ptmp.linkage_id == linkage_id) {
00979          /* Found the record */
00980          break;
00981       }
00982    }
00983 
00984    return current;
00985 }
00986 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
00987 
00988 #if defined(AST_MISDN_ENHANCEMENTS)
00989 /*!
00990  * \internal
00991  * \brief Find the call completion record given the port and outstanding invocation id.
00992  *
00993  * \param port Logical port number
00994  * \param invoke_id Outstanding message invocation ID number.
00995  *
00996  * \retval pointer to found call completion record
00997  * \retval NULL if not found
00998  *
00999  * \note Assumes the misdn_cc_records_db lock is already obtained.
01000  */
01001 static struct misdn_cc_record *misdn_cc_find_by_invoke(int port, int invoke_id)
01002 {
01003    struct misdn_cc_record *current;
01004 
01005    AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
01006       if (current->outstanding_message
01007          && current->invoke_id == invoke_id
01008          && current->port == port) {
01009          /* Found the record */
01010          break;
01011       }
01012    }
01013 
01014    return current;
01015 }
01016 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01017 
01018 #if defined(AST_MISDN_ENHANCEMENTS)
01019 /*!
01020  * \internal
01021  * \brief Find the call completion record given the port and CCBS reference id.
01022  *
01023  * \param port Logical port number
01024  * \param reference_id CCBS reference ID number from switch.
01025  *
01026  * \retval pointer to found call completion record
01027  * \retval NULL if not found
01028  *
01029  * \note Assumes the misdn_cc_records_db lock is already obtained.
01030  */
01031 static struct misdn_cc_record *misdn_cc_find_by_reference(int port, int reference_id)
01032 {
01033    struct misdn_cc_record *current;
01034 
01035    AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
01036       if (current->activated
01037          && current->port == port
01038          && !current->ptp
01039          && current->mode.ptmp.reference_id == reference_id) {
01040          /* Found the record */
01041          break;
01042       }
01043    }
01044 
01045    return current;
01046 }
01047 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01048 
01049 #if defined(AST_MISDN_ENHANCEMENTS)
01050 /*!
01051  * \internal
01052  * \brief Find the call completion record given the B channel pointer
01053  *
01054  * \param bc B channel control structure pointer.
01055  *
01056  * \retval pointer to found call completion record
01057  * \retval NULL if not found
01058  *
01059  * \note Assumes the misdn_cc_records_db lock is already obtained.
01060  */
01061 static struct misdn_cc_record *misdn_cc_find_by_bc(const struct misdn_bchannel *bc)
01062 {
01063    struct misdn_cc_record *current;
01064 
01065    if (bc) {
01066       AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
01067          if (current->ptp
01068             && current->mode.ptp.bc == bc) {
01069             /* Found the record */
01070             break;
01071          }
01072       }
01073    } else {
01074       current = NULL;
01075    }
01076 
01077    return current;
01078 }
01079 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01080 
01081 #if defined(AST_MISDN_ENHANCEMENTS)
01082 /*!
01083  * \internal
01084  * \brief Delete the given call completion record
01085  *
01086  * \param doomed Call completion record to destroy
01087  *
01088  * \return Nothing
01089  *
01090  * \note Assumes the misdn_cc_records_db lock is already obtained.
01091  */
01092 static void misdn_cc_delete(struct misdn_cc_record *doomed)
01093 {
01094    struct misdn_cc_record *current;
01095 
01096    AST_LIST_TRAVERSE_SAFE_BEGIN(&misdn_cc_records_db, current, list) {
01097       if (current == doomed) {
01098          AST_LIST_REMOVE_CURRENT(list);
01099          ast_free(current);
01100          return;
01101       }
01102    }
01103    AST_LIST_TRAVERSE_SAFE_END;
01104 
01105    /* The doomed node is not in the call completion database */
01106 }
01107 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01108 
01109 #if defined(AST_MISDN_ENHANCEMENTS)
01110 /*!
01111  * \internal
01112  * \brief Delete all old call completion records
01113  *
01114  * \return Nothing
01115  *
01116  * \note Assumes the misdn_cc_records_db lock is already obtained.
01117  */
01118 static void misdn_cc_remove_old(void)
01119 {
01120    struct misdn_cc_record *current;
01121    time_t now;
01122 
01123    now = time(NULL);
01124    AST_LIST_TRAVERSE_SAFE_BEGIN(&misdn_cc_records_db, current, list) {
01125       if (MISDN_CC_RECORD_AGE_MAX < now - current->time_created) {
01126          if (current->ptp && current->mode.ptp.bc) {
01127             /* Close the old call-completion signaling link */
01128             current->mode.ptp.bc->fac_out.Function = Fac_None;
01129             current->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
01130             misdn_lib_send_event(current->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
01131          }
01132 
01133          /* Remove the old call completion record */
01134          AST_LIST_REMOVE_CURRENT(list);
01135          ast_free(current);
01136       }
01137    }
01138    AST_LIST_TRAVERSE_SAFE_END;
01139 }
01140 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01141 
01142 #if defined(AST_MISDN_ENHANCEMENTS)
01143 /*!
01144  * \internal
01145  * \brief Allocate the next record id.
01146  *
01147  * \retval New record id on success.
01148  * \retval -1 on error.
01149  *
01150  * \note Assumes the misdn_cc_records_db lock is already obtained.
01151  */
01152 static long misdn_cc_record_id_new(void)
01153 {
01154    long record_id;
01155    long first_id;
01156 
01157    record_id = ++misdn_cc_record_id;
01158    first_id = record_id;
01159    while (misdn_cc_find_by_id(record_id)) {
01160       record_id = ++misdn_cc_record_id;
01161       if (record_id == first_id) {
01162          /*
01163           * We have a resource leak.
01164           * We should never need to allocate 64k records.
01165           */
01166          chan_misdn_log(0, 0, " --> ERROR Too many call completion records!\n");
01167          record_id = -1;
01168          break;
01169       }
01170    }
01171 
01172    return record_id;
01173 }
01174 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01175 
01176 #if defined(AST_MISDN_ENHANCEMENTS)
01177 /*!
01178  * \internal
01179  * \brief Create a new call completion record
01180  *
01181  * \retval pointer to new call completion record
01182  * \retval NULL if failed
01183  *
01184  * \note Assumes the misdn_cc_records_db lock is already obtained.
01185  */
01186 static struct misdn_cc_record *misdn_cc_new(void)
01187 {
01188    struct misdn_cc_record *cc_record;
01189    long record_id;
01190 
01191    misdn_cc_remove_old();
01192 
01193    cc_record = ast_calloc(1, sizeof(*cc_record));
01194    if (cc_record) {
01195       record_id = misdn_cc_record_id_new();
01196       if (record_id < 0) {
01197          ast_free(cc_record);
01198          return NULL;
01199       }
01200 
01201       /* Initialize the new record */
01202       cc_record->record_id = record_id;
01203       cc_record->port = -1;/* Invalid port so it will never be found this way */
01204       cc_record->invoke_id = ++misdn_invoke_id;
01205       cc_record->party_a_free = 1;/* Default User-A as free */
01206       cc_record->error_code = FacError_None;
01207       cc_record->reject_code = FacReject_None;
01208       cc_record->time_created = time(NULL);
01209 
01210       /* Insert the new record into the database */
01211       AST_LIST_INSERT_HEAD(&misdn_cc_records_db, cc_record, list);
01212    }
01213    return cc_record;
01214 }
01215 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01216 
01217 #if defined(AST_MISDN_ENHANCEMENTS)
01218 /*!
01219  * \internal
01220  * \brief Destroy the call completion record database
01221  *
01222  * \return Nothing
01223  */
01224 static void misdn_cc_destroy(void)
01225 {
01226    struct misdn_cc_record *current;
01227 
01228    while ((current = AST_LIST_REMOVE_HEAD(&misdn_cc_records_db, list))) {
01229       /* Do a misdn_cc_delete(current) inline */
01230       ast_free(current);
01231    }
01232 }
01233 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01234 
01235 #if defined(AST_MISDN_ENHANCEMENTS)
01236 /*!
01237  * \internal
01238  * \brief Initialize the call completion record database
01239  *
01240  * \return Nothing
01241  */
01242 static void misdn_cc_init(void)
01243 {
01244    misdn_cc_record_id = 0;
01245 }
01246 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01247 
01248 #if defined(AST_MISDN_ENHANCEMENTS)
01249 /*!
01250  * \internal
01251  * \brief Check the status of an outstanding invocation request.
01252  *
01253  * \param data Points to an integer containing the call completion record id.
01254  *
01255  * \retval 0 if got a response.
01256  * \retval -1 if no response yet.
01257  */
01258 static int misdn_cc_response_check(void *data)
01259 {
01260    int not_responded;
01261    struct misdn_cc_record *cc_record;
01262 
01263    AST_LIST_LOCK(&misdn_cc_records_db);
01264    cc_record = misdn_cc_find_by_id(*(long *) data);
01265    if (cc_record) {
01266       if (cc_record->outstanding_message) {
01267          not_responded = -1;
01268       } else {
01269          not_responded = 0;
01270       }
01271    } else {
01272       /* No record so there is no response to check. */
01273       not_responded = 0;
01274    }
01275    AST_LIST_UNLOCK(&misdn_cc_records_db);
01276 
01277    return not_responded;
01278 }
01279 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01280 
01281 #if defined(AST_MISDN_ENHANCEMENTS)
01282 /*!
01283  * \internal
01284  * \brief Wait for a response from the switch for an outstanding
01285  * invocation request.
01286  *
01287  * \param chan Asterisk channel to operate upon.
01288  * \param wait_seconds Number of seconds to wait
01289  * \param record_id Call completion record ID.
01290  *
01291  * \return Nothing
01292  */
01293 static void misdn_cc_response_wait(struct ast_channel *chan, int wait_seconds, long record_id)
01294 {
01295    unsigned count;
01296 
01297    for (count = 2 * MISDN_CC_REQUEST_WAIT_MAX; count--;) {
01298       /* Sleep in 500 ms increments */
01299       if (ast_safe_sleep_conditional(chan, 500, misdn_cc_response_check, &record_id) != 0) {
01300          /* We got hung up or our response came in. */
01301          break;
01302       }
01303    }
01304 }
01305 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01306 
01307 #if defined(AST_MISDN_ENHANCEMENTS)
01308 /*!
01309  * \internal
01310  * \brief Convert the mISDN reject code to a string
01311  *
01312  * \param code mISDN reject code.
01313  *
01314  * \return The mISDN reject code as a string
01315  */
01316 static const char *misdn_to_str_reject_code(enum FacRejectCode code)
01317 {
01318    static const struct {
01319       enum FacRejectCode code;
01320       char *name;
01321    } arr[] = {
01322 /* *INDENT-OFF* */
01323       { FacReject_None,                           "No reject occurred" },
01324       { FacReject_Unknown,                        "Unknown reject code" },
01325 
01326       { FacReject_Gen_UnrecognizedComponent,      "General: Unrecognized Component" },
01327       { FacReject_Gen_MistypedComponent,          "General: Mistyped Component" },
01328       { FacReject_Gen_BadlyStructuredComponent,   "General: Badly Structured Component" },
01329 
01330       { FacReject_Inv_DuplicateInvocation,        "Invoke: Duplicate Invocation" },
01331       { FacReject_Inv_UnrecognizedOperation,      "Invoke: Unrecognized Operation" },
01332       { FacReject_Inv_MistypedArgument,           "Invoke: Mistyped Argument" },
01333       { FacReject_Inv_ResourceLimitation,         "Invoke: Resource Limitation" },
01334       { FacReject_Inv_InitiatorReleasing,         "Invoke: Initiator Releasing" },
01335       { FacReject_Inv_UnrecognizedLinkedID,       "Invoke: Unrecognized Linked ID" },
01336       { FacReject_Inv_LinkedResponseUnexpected,   "Invoke: Linked Response Unexpected" },
01337       { FacReject_Inv_UnexpectedChildOperation,   "Invoke: Unexpected Child Operation" },
01338 
01339       { FacReject_Res_UnrecognizedInvocation,     "Result: Unrecognized Invocation" },
01340       { FacReject_Res_ResultResponseUnexpected,   "Result: Result Response Unexpected" },
01341       { FacReject_Res_MistypedResult,             "Result: Mistyped Result" },
01342 
01343       { FacReject_Err_UnrecognizedInvocation,     "Error: Unrecognized Invocation" },
01344       { FacReject_Err_ErrorResponseUnexpected,    "Error: Error Response Unexpected" },
01345       { FacReject_Err_UnrecognizedError,          "Error: Unrecognized Error" },
01346       { FacReject_Err_UnexpectedError,            "Error: Unexpected Error" },
01347       { FacReject_Err_MistypedParameter,          "Error: Mistyped Parameter" },
01348 /* *INDENT-ON* */
01349    };
01350 
01351    unsigned index;
01352 
01353    for (index = 0; index < ARRAY_LEN(arr); ++index) {
01354       if (arr[index].code == code) {
01355          return arr[index].name;
01356       }
01357    }
01358 
01359    return "unknown";
01360 }
01361 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01362 
01363 #if defined(AST_MISDN_ENHANCEMENTS)
01364 /*!
01365  * \internal
01366  * \brief Convert the mISDN error code to a string
01367  *
01368  * \param code mISDN error code.
01369  *
01370  * \return The mISDN error code as a string
01371  */
01372 static const char *misdn_to_str_error_code(enum FacErrorCode code)
01373 {
01374    static const struct {
01375       enum FacErrorCode code;
01376       char *name;
01377    } arr[] = {
01378 /* *INDENT-OFF* */
01379       { FacError_None,                            "No error occurred" },
01380       { FacError_Unknown,                         "Unknown OID error code" },
01381 
01382       { FacError_Gen_NotSubscribed,               "General: Not Subscribed" },
01383       { FacError_Gen_NotAvailable,                "General: Not Available" },
01384       { FacError_Gen_NotImplemented,              "General: Not Implemented" },
01385       { FacError_Gen_InvalidServedUserNr,         "General: Invalid Served User Number" },
01386       { FacError_Gen_InvalidCallState,            "General: Invalid Call State" },
01387       { FacError_Gen_BasicServiceNotProvided,     "General: Basic Service Not Provided" },
01388       { FacError_Gen_NotIncomingCall,             "General: Not Incoming Call" },
01389       { FacError_Gen_SupplementaryServiceInteractionNotAllowed,"General: Supplementary Service Interaction Not Allowed" },
01390       { FacError_Gen_ResourceUnavailable,         "General: Resource Unavailable" },
01391 
01392       { FacError_Div_InvalidDivertedToNr,         "Diversion: Invalid Diverted To Number" },
01393       { FacError_Div_SpecialServiceNr,            "Diversion: Special Service Number" },
01394       { FacError_Div_DiversionToServedUserNr,     "Diversion: Diversion To Served User Number" },
01395       { FacError_Div_IncomingCallAccepted,        "Diversion: Incoming Call Accepted" },
01396       { FacError_Div_NumberOfDiversionsExceeded,  "Diversion: Number Of Diversions Exceeded" },
01397       { FacError_Div_NotActivated,                "Diversion: Not Activated" },
01398       { FacError_Div_RequestAlreadyAccepted,      "Diversion: Request Already Accepted" },
01399 
01400       { FacError_AOC_NoChargingInfoAvailable,     "AOC: No Charging Info Available" },
01401 
01402       { FacError_CCBS_InvalidCallLinkageID,       "CCBS: Invalid Call Linkage ID" },
01403       { FacError_CCBS_InvalidCCBSReference,       "CCBS: Invalid CCBS Reference" },
01404       { FacError_CCBS_LongTermDenial,             "CCBS: Long Term Denial" },
01405       { FacError_CCBS_ShortTermDenial,            "CCBS: Short Term Denial" },
01406       { FacError_CCBS_IsAlreadyActivated,         "CCBS: Is Already Activated" },
01407       { FacError_CCBS_AlreadyAccepted,            "CCBS: Already Accepted" },
01408       { FacError_CCBS_OutgoingCCBSQueueFull,      "CCBS: Outgoing CCBS Queue Full" },
01409       { FacError_CCBS_CallFailureReasonNotBusy,   "CCBS: Call Failure Reason Not Busy" },
01410       { FacError_CCBS_NotReadyForCall,            "CCBS: Not Ready For Call" },
01411 
01412       { FacError_CCBS_T_LongTermDenial,           "CCBS-T: Long Term Denial" },
01413       { FacError_CCBS_T_ShortTermDenial,          "CCBS-T: Short Term Denial" },
01414 
01415       { FacError_ECT_LinkIdNotAssignedByNetwork,  "ECT: Link ID Not Assigned By Network" },
01416 /* *INDENT-ON* */
01417    };
01418 
01419    unsigned index;
01420 
01421    for (index = 0; index < ARRAY_LEN(arr); ++index) {
01422       if (arr[index].code == code) {
01423          return arr[index].name;
01424       }
01425    }
01426 
01427    return "unknown";
01428 }
01429 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01430 
01431 #if defined(AST_MISDN_ENHANCEMENTS)
01432 /*!
01433  * \internal
01434  * \brief Convert mISDN redirecting reason to diversion reason.
01435  *
01436  * \param reason mISDN redirecting reason code.
01437  *
01438  * \return Supported diversion reason code.
01439  */
01440 static unsigned misdn_to_diversion_reason(enum mISDN_REDIRECTING_REASON reason)
01441 {
01442    unsigned diversion_reason;
01443 
01444    switch (reason) {
01445    case mISDN_REDIRECTING_REASON_CALL_FWD:
01446       diversion_reason = 1;/* cfu */
01447       break;
01448    case mISDN_REDIRECTING_REASON_CALL_FWD_BUSY:
01449       diversion_reason = 2;/* cfb */
01450       break;
01451    case mISDN_REDIRECTING_REASON_NO_REPLY:
01452       diversion_reason = 3;/* cfnr */
01453       break;
01454    default:
01455       diversion_reason = 0;/* unknown */
01456       break;
01457    }
01458 
01459    return diversion_reason;
01460 }
01461 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01462 
01463 #if defined(AST_MISDN_ENHANCEMENTS)
01464 /*!
01465  * \internal
01466  * \brief Convert diversion reason to mISDN redirecting reason
01467  *
01468  * \param diversion_reason Diversion reason to convert
01469  *
01470  * \return Supported redirecting reason code.
01471  */
01472 static enum mISDN_REDIRECTING_REASON diversion_reason_to_misdn(unsigned diversion_reason)
01473 {
01474    enum mISDN_REDIRECTING_REASON reason;
01475 
01476    switch (diversion_reason) {
01477    case 1:/* cfu */
01478       reason = mISDN_REDIRECTING_REASON_CALL_FWD;
01479       break;
01480    case 2:/* cfb */
01481       reason = mISDN_REDIRECTING_REASON_CALL_FWD_BUSY;
01482       break;
01483    case 3:/* cfnr */
01484       reason = mISDN_REDIRECTING_REASON_NO_REPLY;
01485       break;
01486    default:
01487       reason = mISDN_REDIRECTING_REASON_UNKNOWN;
01488       break;
01489    }
01490 
01491    return reason;
01492 }
01493 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01494 
01495 #if defined(AST_MISDN_ENHANCEMENTS)
01496 /*!
01497  * \internal
01498  * \brief Convert the mISDN presentation to PresentedNumberUnscreened type
01499  *
01500  * \param presentation mISDN presentation to convert
01501  * \param number_present TRUE if the number is present
01502  *
01503  * \return PresentedNumberUnscreened type
01504  */
01505 static unsigned misdn_to_PresentedNumberUnscreened_type(int presentation, int number_present)
01506 {
01507    unsigned type;
01508 
01509    switch (presentation) {
01510    case 0:/* allowed */
01511       if (number_present) {
01512          type = 0;/* presentationAllowedNumber */
01513       } else {
01514          type = 2;/* numberNotAvailableDueToInterworking */
01515       }
01516       break;
01517    case 1:/* restricted */
01518       if (number_present) {
01519          type = 3;/* presentationRestrictedNumber */
01520       } else {
01521          type = 1;/* presentationRestricted */
01522       }
01523       break;
01524    default:
01525       type = 2;/* numberNotAvailableDueToInterworking */
01526       break;
01527    }
01528 
01529    return type;
01530 }
01531 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01532 
01533 #if defined(AST_MISDN_ENHANCEMENTS)
01534 /*!
01535  * \internal
01536  * \brief Convert the PresentedNumberUnscreened type to mISDN presentation
01537  *
01538  * \param type PresentedNumberUnscreened type
01539  *
01540  * \return mISDN presentation
01541  */
01542 static int PresentedNumberUnscreened_to_misdn_pres(unsigned type)
01543 {
01544    int presentation;
01545 
01546    switch (type) {
01547    default:
01548    case 0:/* presentationAllowedNumber */
01549       presentation = 0;/* allowed */
01550       break;
01551 
01552    case 1:/* presentationRestricted */
01553    case 3:/* presentationRestrictedNumber */
01554       presentation = 1;/* restricted */
01555       break;
01556 
01557    case 2:/* numberNotAvailableDueToInterworking */
01558       presentation = 2;/* unavailable */
01559       break;
01560    }
01561 
01562    return presentation;
01563 }
01564 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01565 
01566 #if defined(AST_MISDN_ENHANCEMENTS)
01567 /*!
01568  * \internal
01569  * \brief Convert the mISDN numbering plan to PartyNumber numbering plan
01570  *
01571  * \param number_plan mISDN numbering plan
01572  *
01573  * \return PartyNumber numbering plan
01574  */
01575 static unsigned misdn_to_PartyNumber_plan(enum mISDN_NUMBER_PLAN number_plan)
01576 {
01577    unsigned party_plan;
01578 
01579    switch (number_plan) {
01580    default:
01581    case NUMPLAN_UNKNOWN:
01582       party_plan = 0;/* unknown */
01583       break;
01584 
01585    case NUMPLAN_ISDN:
01586       party_plan = 1;/* public */
01587       break;
01588 
01589    case NUMPLAN_DATA:
01590       party_plan = 3;/* data */
01591       break;
01592 
01593    case NUMPLAN_TELEX:
01594       party_plan = 4;/* telex */
01595       break;
01596 
01597    case NUMPLAN_NATIONAL:
01598       party_plan = 8;/* nationalStandard */
01599       break;
01600 
01601    case NUMPLAN_PRIVATE:
01602       party_plan = 5;/* private */
01603       break;
01604    }
01605 
01606    return party_plan;
01607 }
01608 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01609 
01610 #if defined(AST_MISDN_ENHANCEMENTS)
01611 /*!
01612  * \internal
01613  * \brief Convert PartyNumber numbering plan to mISDN numbering plan
01614  *
01615  * \param party_plan PartyNumber numbering plan
01616  *
01617  * \return mISDN numbering plan
01618  */
01619 static enum mISDN_NUMBER_PLAN PartyNumber_to_misdn_plan(unsigned party_plan)
01620 {
01621    enum mISDN_NUMBER_PLAN number_plan;
01622 
01623    switch (party_plan) {
01624    default:
01625    case 0:/* unknown */
01626       number_plan = NUMPLAN_UNKNOWN;
01627       break;
01628    case 1:/* public */
01629       number_plan = NUMPLAN_ISDN;
01630       break;
01631    case 3:/* data */
01632       number_plan = NUMPLAN_DATA;
01633       break;
01634    case 4:/* telex */
01635       number_plan = NUMPLAN_TELEX;
01636       break;
01637    case 8:/* nationalStandard */
01638       number_plan = NUMPLAN_NATIONAL;
01639       break;
01640    case 5:/* private */
01641       number_plan = NUMPLAN_PRIVATE;
01642       break;
01643    }
01644 
01645    return number_plan;
01646 }
01647 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01648 
01649 #if defined(AST_MISDN_ENHANCEMENTS)
01650 /*!
01651  * \internal
01652  * \brief Convert mISDN type-of-number to PartyNumber public type-of-number
01653  *
01654  * \param ton mISDN type-of-number
01655  *
01656  * \return PartyNumber public type-of-number
01657  */
01658 static unsigned misdn_to_PartyNumber_ton_public(enum mISDN_NUMBER_TYPE ton)
01659 {
01660    unsigned party_ton;
01661 
01662    switch (ton) {
01663    default:
01664    case NUMTYPE_UNKNOWN:
01665       party_ton = 0;/* unknown */
01666       break;
01667 
01668    case NUMTYPE_INTERNATIONAL:
01669       party_ton = 1;/* internationalNumber */
01670       break;
01671 
01672    case NUMTYPE_NATIONAL:
01673       party_ton = 2;/* nationalNumber */
01674       break;
01675 
01676    case NUMTYPE_NETWORK_SPECIFIC:
01677       party_ton = 3;/* networkSpecificNumber */
01678       break;
01679 
01680    case NUMTYPE_SUBSCRIBER:
01681       party_ton = 4;/* subscriberNumber */
01682       break;
01683 
01684    case NUMTYPE_ABBREVIATED:
01685       party_ton = 6;/* abbreviatedNumber */
01686       break;
01687    }
01688 
01689    return party_ton;
01690 }
01691 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01692 
01693 #if defined(AST_MISDN_ENHANCEMENTS)
01694 /*!
01695  * \internal
01696  * \brief Convert the PartyNumber public type-of-number to mISDN type-of-number
01697  *
01698  * \param party_ton PartyNumber public type-of-number
01699  *
01700  * \return mISDN type-of-number
01701  */
01702 static enum mISDN_NUMBER_TYPE PartyNumber_to_misdn_ton_public(unsigned party_ton)
01703 {
01704    enum mISDN_NUMBER_TYPE ton;
01705 
01706    switch (party_ton) {
01707    default:
01708    case 0:/* unknown */
01709       ton = NUMTYPE_UNKNOWN;
01710       break;
01711 
01712    case 1:/* internationalNumber */
01713       ton = NUMTYPE_INTERNATIONAL;
01714       break;
01715 
01716    case 2:/* nationalNumber */
01717       ton = NUMTYPE_NATIONAL;
01718       break;
01719 
01720    case 3:/* networkSpecificNumber */
01721       ton = NUMTYPE_NETWORK_SPECIFIC;
01722       break;
01723 
01724    case 4:/* subscriberNumber */
01725       ton = NUMTYPE_SUBSCRIBER;
01726       break;
01727 
01728    case 6:/* abbreviatedNumber */
01729       ton = NUMTYPE_ABBREVIATED;
01730       break;
01731    }
01732 
01733    return ton;
01734 }
01735 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01736 
01737 #if defined(AST_MISDN_ENHANCEMENTS)
01738 /*!
01739  * \internal
01740  * \brief Convert mISDN type-of-number to PartyNumber private type-of-number
01741  *
01742  * \param ton mISDN type-of-number
01743  *
01744  * \return PartyNumber private type-of-number
01745  */
01746 static unsigned misdn_to_PartyNumber_ton_private(enum mISDN_NUMBER_TYPE ton)
01747 {
01748    unsigned party_ton;
01749 
01750    switch (ton) {
01751    default:
01752    case NUMTYPE_UNKNOWN:
01753       party_ton = 0;/* unknown */
01754       break;
01755 
01756    case NUMTYPE_INTERNATIONAL:
01757       party_ton = 1;/* level2RegionalNumber */
01758       break;
01759 
01760    case NUMTYPE_NATIONAL:
01761       party_ton = 2;/* level1RegionalNumber */
01762       break;
01763 
01764    case NUMTYPE_NETWORK_SPECIFIC:
01765       party_ton = 3;/* pTNSpecificNumber */
01766       break;
01767 
01768    case NUMTYPE_SUBSCRIBER:
01769       party_ton = 4;/* localNumber */
01770       break;
01771 
01772    case NUMTYPE_ABBREVIATED:
01773       party_ton = 6;/* abbreviatedNumber */
01774       break;
01775    }
01776 
01777    return party_ton;
01778 }
01779 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01780 
01781 #if defined(AST_MISDN_ENHANCEMENTS)
01782 /*!
01783  * \internal
01784  * \brief Convert the PartyNumber private type-of-number to mISDN type-of-number
01785  *
01786  * \param party_ton PartyNumber private type-of-number
01787  *
01788  * \return mISDN type-of-number
01789  */
01790 static enum mISDN_NUMBER_TYPE PartyNumber_to_misdn_ton_private(unsigned party_ton)
01791 {
01792    enum mISDN_NUMBER_TYPE ton;
01793 
01794    switch (party_ton) {
01795    default:
01796    case 0:/* unknown */
01797       ton = NUMTYPE_UNKNOWN;
01798       break;
01799 
01800    case 1:/* level2RegionalNumber */
01801       ton = NUMTYPE_INTERNATIONAL;
01802       break;
01803 
01804    case 2:/* level1RegionalNumber */
01805       ton = NUMTYPE_NATIONAL;
01806       break;
01807 
01808    case 3:/* pTNSpecificNumber */
01809       ton = NUMTYPE_NETWORK_SPECIFIC;
01810       break;
01811 
01812    case 4:/* localNumber */
01813       ton = NUMTYPE_SUBSCRIBER;
01814       break;
01815 
01816    case 6:/* abbreviatedNumber */
01817       ton = NUMTYPE_ABBREVIATED;
01818       break;
01819    }
01820 
01821    return ton;
01822 }
01823 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
01824 
01825 /*!
01826  * \internal
01827  * \brief Convert the mISDN type of number code to a string
01828  *
01829  * \param number_type mISDN type of number code.
01830  *
01831  * \return The mISDN type of number code as a string
01832  */
01833 static const char *misdn_to_str_ton(enum mISDN_NUMBER_TYPE number_type)
01834 {
01835    const char *str;
01836 
01837    switch (number_type) {
01838    default:
01839    case NUMTYPE_UNKNOWN:
01840       str = "Unknown";
01841       break;
01842 
01843    case NUMTYPE_INTERNATIONAL:
01844       str = "International";
01845       break;
01846 
01847    case NUMTYPE_NATIONAL:
01848       str = "National";
01849       break;
01850 
01851    case NUMTYPE_NETWORK_SPECIFIC:
01852       str = "Network Specific";
01853       break;
01854 
01855    case NUMTYPE_SUBSCRIBER:
01856       str = "Subscriber";
01857       break;
01858 
01859    case NUMTYPE_ABBREVIATED:
01860       str = "Abbreviated";
01861       break;
01862    }
01863 
01864    return str;
01865 }
01866 
01867 /*!
01868  * \internal
01869  * \brief Convert the mISDN type of number code to Asterisk type of number code
01870  *
01871  * \param number_type mISDN type of number code.
01872  *
01873  * \return Asterisk type of number code
01874  */
01875 static int misdn_to_ast_ton(enum mISDN_NUMBER_TYPE number_type)
01876 {
01877    int ast_number_type;
01878 
01879    switch (number_type) {
01880    default:
01881    case NUMTYPE_UNKNOWN:
01882       ast_number_type = NUMTYPE_UNKNOWN << 4;
01883       break;
01884 
01885    case NUMTYPE_INTERNATIONAL:
01886       ast_number_type = NUMTYPE_INTERNATIONAL << 4;
01887       break;
01888 
01889    case NUMTYPE_NATIONAL:
01890       ast_number_type = NUMTYPE_NATIONAL << 4;
01891       break;
01892 
01893    case NUMTYPE_NETWORK_SPECIFIC:
01894       ast_number_type = NUMTYPE_NETWORK_SPECIFIC << 4;
01895       break;
01896 
01897    case NUMTYPE_SUBSCRIBER:
01898       ast_number_type = NUMTYPE_SUBSCRIBER << 4;
01899       break;
01900 
01901    case NUMTYPE_ABBREVIATED:
01902       ast_number_type = NUMTYPE_ABBREVIATED << 4;
01903       break;
01904    }
01905 
01906    return ast_number_type;
01907 }
01908 
01909 /*!
01910  * \internal
01911  * \brief Convert the Asterisk type of number code to mISDN type of number code
01912  *
01913  * \param ast_number_type Asterisk type of number code.
01914  *
01915  * \return mISDN type of number code
01916  */
01917 static enum mISDN_NUMBER_TYPE ast_to_misdn_ton(unsigned ast_number_type)
01918 {
01919    enum mISDN_NUMBER_TYPE number_type;
01920 
01921    switch ((ast_number_type >> 4) & 0x07) {
01922    default:
01923    case NUMTYPE_UNKNOWN:
01924       number_type = NUMTYPE_UNKNOWN;
01925       break;
01926 
01927    case NUMTYPE_INTERNATIONAL:
01928       number_type = NUMTYPE_INTERNATIONAL;
01929       break;
01930 
01931    case NUMTYPE_NATIONAL:
01932       number_type = NUMTYPE_NATIONAL;
01933       break;
01934 
01935    case NUMTYPE_NETWORK_SPECIFIC:
01936       number_type = NUMTYPE_NETWORK_SPECIFIC;
01937       break;
01938 
01939    case NUMTYPE_SUBSCRIBER:
01940       number_type = NUMTYPE_SUBSCRIBER;
01941       break;
01942 
01943    case NUMTYPE_ABBREVIATED:
01944       number_type = NUMTYPE_ABBREVIATED;
01945       break;
01946    }
01947 
01948    return number_type;
01949 }
01950 
01951 /*!
01952  * \internal
01953  * \brief Convert the mISDN numbering plan code to a string
01954  *
01955  * \param number_plan mISDN numbering plan code.
01956  *
01957  * \return The mISDN numbering plan code as a string
01958  */
01959 static const char *misdn_to_str_plan(enum mISDN_NUMBER_PLAN number_plan)
01960 {
01961    const char *str;
01962 
01963    switch (number_plan) {
01964    default:
01965    case NUMPLAN_UNKNOWN:
01966       str = "Unknown";
01967       break;
01968 
01969    case NUMPLAN_ISDN:
01970       str = "ISDN";
01971       break;
01972 
01973    case NUMPLAN_DATA:
01974       str = "Data";
01975       break;
01976 
01977    case NUMPLAN_TELEX:
01978       str = "Telex";
01979       break;
01980 
01981    case NUMPLAN_NATIONAL:
01982       str = "National";
01983       break;
01984 
01985    case NUMPLAN_PRIVATE:
01986       str = "Private";
01987       break;
01988    }
01989 
01990    return str;
01991 }
01992 
01993 /*!
01994  * \internal
01995  * \brief Convert the mISDN numbering plan code to Asterisk numbering plan code
01996  *
01997  * \param number_plan mISDN numbering plan code.
01998  *
01999  * \return Asterisk numbering plan code
02000  */
02001 static int misdn_to_ast_plan(enum mISDN_NUMBER_PLAN number_plan)
02002 {
02003    int ast_number_plan;
02004 
02005    switch (number_plan) {
02006    default:
02007    case NUMPLAN_UNKNOWN:
02008       ast_number_plan = NUMPLAN_UNKNOWN;
02009       break;
02010 
02011    case NUMPLAN_ISDN:
02012       ast_number_plan = NUMPLAN_ISDN;
02013       break;
02014 
02015    case NUMPLAN_DATA:
02016       ast_number_plan = NUMPLAN_DATA;
02017       break;
02018 
02019    case NUMPLAN_TELEX:
02020       ast_number_plan = NUMPLAN_TELEX;
02021       break;
02022 
02023    case NUMPLAN_NATIONAL:
02024       ast_number_plan = NUMPLAN_NATIONAL;
02025       break;
02026 
02027    case NUMPLAN_PRIVATE:
02028       ast_number_plan = NUMPLAN_PRIVATE;
02029       break;
02030    }
02031 
02032    return ast_number_plan;
02033 }
02034 
02035 /*!
02036  * \internal
02037  * \brief Convert the Asterisk numbering plan code to mISDN numbering plan code
02038  *
02039  * \param ast_number_plan Asterisk numbering plan code.
02040  *
02041  * \return mISDN numbering plan code
02042  */
02043 static enum mISDN_NUMBER_PLAN ast_to_misdn_plan(unsigned ast_number_plan)
02044 {
02045    enum mISDN_NUMBER_PLAN number_plan;
02046 
02047    switch (ast_number_plan & 0x0F) {
02048    default:
02049    case NUMPLAN_UNKNOWN:
02050       number_plan = NUMPLAN_UNKNOWN;
02051       break;
02052 
02053    case NUMPLAN_ISDN:
02054       number_plan = NUMPLAN_ISDN;
02055       break;
02056 
02057    case NUMPLAN_DATA:
02058       number_plan = NUMPLAN_DATA;
02059       break;
02060 
02061    case NUMPLAN_TELEX:
02062       number_plan = NUMPLAN_TELEX;
02063       break;
02064 
02065    case NUMPLAN_NATIONAL:
02066       number_plan = NUMPLAN_NATIONAL;
02067       break;
02068 
02069    case NUMPLAN_PRIVATE:
02070       number_plan = NUMPLAN_PRIVATE;
02071       break;
02072    }
02073 
02074    return number_plan;
02075 }
02076 
02077 /*!
02078  * \internal
02079  * \brief Convert the mISDN presentation code to a string
02080  *
02081  * \param presentation mISDN number presentation restriction code.
02082  *
02083  * \return The mISDN presentation code as a string
02084  */
02085 static const char *misdn_to_str_pres(int presentation)
02086 {
02087    const char *str;
02088 
02089    switch (presentation) {
02090    case 0:
02091       str = "Allowed";
02092       break;
02093 
02094    case 1:
02095       str = "Restricted";
02096       break;
02097 
02098    case 2:
02099       str = "Unavailable";
02100       break;
02101 
02102    default:
02103       str = "Unknown";
02104       break;
02105    }
02106 
02107    return str;
02108 }
02109 
02110 /*!
02111  * \internal
02112  * \brief Convert the mISDN presentation code to Asterisk presentation code
02113  *
02114  * \param presentation mISDN number presentation restriction code.
02115  *
02116  * \return Asterisk presentation code
02117  */
02118 static int misdn_to_ast_pres(int presentation)
02119 {
02120    switch (presentation) {
02121    default:
02122    case 0:
02123       presentation = AST_PRES_ALLOWED;
02124       break;
02125 
02126    case 1:
02127       presentation = AST_PRES_RESTRICTED;
02128       break;
02129 
02130    case 2:
02131       presentation = AST_PRES_UNAVAILABLE;
02132       break;
02133    }
02134 
02135    return presentation;
02136 }
02137 
02138 /*!
02139  * \internal
02140  * \brief Convert the Asterisk presentation code to mISDN presentation code
02141  *
02142  * \param presentation Asterisk number presentation restriction code.
02143  *
02144  * \return mISDN presentation code
02145  */
02146 static int ast_to_misdn_pres(int presentation)
02147 {
02148    switch (presentation & AST_PRES_RESTRICTION) {
02149    default:
02150    case AST_PRES_ALLOWED:
02151       presentation = 0;
02152       break;
02153 
02154    case AST_PRES_RESTRICTED:
02155       presentation = 1;
02156       break;
02157 
02158    case AST_PRES_UNAVAILABLE:
02159       presentation = 2;
02160       break;
02161    }
02162 
02163    return presentation;
02164 }
02165 
02166 /*!
02167  * \internal
02168  * \brief Convert the mISDN screening code to a string
02169  *
02170  * \param screening mISDN number screening code.
02171  *
02172  * \return The mISDN screening code as a string
02173  */
02174 static const char *misdn_to_str_screen(int screening)
02175 {
02176    const char *str;
02177 
02178    switch (screening) {
02179    case 0:
02180       str = "Unscreened";
02181       break;
02182 
02183    case 1:
02184       str = "Passed Screen";
02185       break;
02186 
02187    case 2:
02188       str = "Failed Screen";
02189       break;
02190 
02191    case 3:
02192       str = "Network Number";
02193       break;
02194 
02195    default:
02196       str = "Unknown";
02197       break;
02198    }
02199 
02200    return str;
02201 }
02202 
02203 /*!
02204  * \internal
02205  * \brief Convert the mISDN screening code to Asterisk screening code
02206  *
02207  * \param screening mISDN number screening code.
02208  *
02209  * \return Asterisk screening code
02210  */
02211 static int misdn_to_ast_screen(int screening)
02212 {
02213    switch (screening) {
02214    default:
02215    case 0:
02216       screening = AST_PRES_USER_NUMBER_UNSCREENED;
02217       break;
02218 
02219    case 1:
02220       screening = AST_PRES_USER_NUMBER_PASSED_SCREEN;
02221       break;
02222 
02223    case 2:
02224       screening = AST_PRES_USER_NUMBER_FAILED_SCREEN;
02225       break;
02226 
02227    case 3:
02228       screening = AST_PRES_NETWORK_NUMBER;
02229       break;
02230    }
02231 
02232    return screening;
02233 }
02234 
02235 /*!
02236  * \internal
02237  * \brief Convert the Asterisk screening code to mISDN screening code
02238  *
02239  * \param screening Asterisk number screening code.
02240  *
02241  * \return mISDN screening code
02242  */
02243 static int ast_to_misdn_screen(int screening)
02244 {
02245    switch (screening & AST_PRES_NUMBER_TYPE) {
02246    default:
02247    case AST_PRES_USER_NUMBER_UNSCREENED:
02248       screening = 0;
02249       break;
02250 
02251    case AST_PRES_USER_NUMBER_PASSED_SCREEN:
02252       screening = 1;
02253       break;
02254 
02255    case AST_PRES_USER_NUMBER_FAILED_SCREEN:
02256       screening = 2;
02257       break;
02258 
02259    case AST_PRES_NETWORK_NUMBER:
02260       screening = 3;
02261       break;
02262    }
02263 
02264    return screening;
02265 }
02266 
02267 /*!
02268  * \internal
02269  * \brief Convert Asterisk redirecting reason to mISDN redirecting reason code.
02270  *
02271  * \param ast Asterisk redirecting reason code.
02272  *
02273  * \return mISDN reason code
02274  */
02275 static enum mISDN_REDIRECTING_REASON ast_to_misdn_reason(const enum AST_REDIRECTING_REASON ast)
02276 {
02277    unsigned index;
02278 
02279    static const struct misdn_reasons {
02280       enum AST_REDIRECTING_REASON ast;
02281       enum mISDN_REDIRECTING_REASON q931;
02282    } misdn_reason_table[] = {
02283    /* *INDENT-OFF* */
02284       { AST_REDIRECTING_REASON_UNKNOWN,        mISDN_REDIRECTING_REASON_UNKNOWN },
02285       { AST_REDIRECTING_REASON_USER_BUSY,      mISDN_REDIRECTING_REASON_CALL_FWD_BUSY },
02286       { AST_REDIRECTING_REASON_NO_ANSWER,      mISDN_REDIRECTING_REASON_NO_REPLY },
02287       { AST_REDIRECTING_REASON_UNAVAILABLE,    mISDN_REDIRECTING_REASON_NO_REPLY },
02288       { AST_REDIRECTING_REASON_UNCONDITIONAL,  mISDN_REDIRECTING_REASON_CALL_FWD },
02289       { AST_REDIRECTING_REASON_TIME_OF_DAY,    mISDN_REDIRECTING_REASON_UNKNOWN },
02290       { AST_REDIRECTING_REASON_DO_NOT_DISTURB, mISDN_REDIRECTING_REASON_UNKNOWN },
02291       { AST_REDIRECTING_REASON_DEFLECTION,     mISDN_REDIRECTING_REASON_DEFLECTION },
02292       { AST_REDIRECTING_REASON_FOLLOW_ME,      mISDN_REDIRECTING_REASON_UNKNOWN },
02293       { AST_REDIRECTING_REASON_OUT_OF_ORDER,   mISDN_REDIRECTING_REASON_OUT_OF_ORDER },
02294       { AST_REDIRECTING_REASON_AWAY,           mISDN_REDIRECTING_REASON_UNKNOWN },
02295       { AST_REDIRECTING_REASON_CALL_FWD_DTE,   mISDN_REDIRECTING_REASON_CALL_FWD_DTE }
02296    /* *INDENT-ON* */
02297    };
02298 
02299    for (index = 0; index < ARRAY_LEN(misdn_reason_table); ++index) {
02300       if (misdn_reason_table[index].ast == ast) {
02301          return misdn_reason_table[index].q931;
02302       }
02303    }
02304    return mISDN_REDIRECTING_REASON_UNKNOWN;
02305 }
02306 
02307 /*!
02308  * \internal
02309  * \brief Convert the mISDN redirecting reason to Asterisk redirecting reason code
02310  *
02311  * \param q931 mISDN redirecting reason code.
02312  *
02313  * \return Asterisk redirecting reason code
02314  */
02315 static enum AST_REDIRECTING_REASON misdn_to_ast_reason(const enum mISDN_REDIRECTING_REASON q931)
02316 {
02317    enum AST_REDIRECTING_REASON ast;
02318 
02319    switch (q931) {
02320    default:
02321    case mISDN_REDIRECTING_REASON_UNKNOWN:
02322       ast = AST_REDIRECTING_REASON_UNKNOWN;
02323       break;
02324 
02325    case mISDN_REDIRECTING_REASON_CALL_FWD_BUSY:
02326       ast = AST_REDIRECTING_REASON_USER_BUSY;
02327       break;
02328 
02329    case mISDN_REDIRECTING_REASON_NO_REPLY:
02330       ast = AST_REDIRECTING_REASON_NO_ANSWER;
02331       break;
02332 
02333    case mISDN_REDIRECTING_REASON_DEFLECTION:
02334       ast = AST_REDIRECTING_REASON_DEFLECTION;
02335       break;
02336 
02337    case mISDN_REDIRECTING_REASON_OUT_OF_ORDER:
02338       ast = AST_REDIRECTING_REASON_OUT_OF_ORDER;
02339       break;
02340 
02341    case mISDN_REDIRECTING_REASON_CALL_FWD_DTE:
02342       ast = AST_REDIRECTING_REASON_CALL_FWD_DTE;
02343       break;
02344 
02345    case mISDN_REDIRECTING_REASON_CALL_FWD:
02346       ast = AST_REDIRECTING_REASON_UNCONDITIONAL;
02347       break;
02348    }
02349 
02350    return ast;
02351 }
02352 
02353 
02354 
02355 struct allowed_bearers {
02356    char *name;         /*!< Bearer capability name string used in /etc/misdn.conf allowed_bearers */
02357    char *display;      /*!< Bearer capability displayable name */
02358    int cap;            /*!< SETUP message bearer capability field code value */
02359    int deprecated;     /*!< TRUE if this entry is deprecated. (Misspelled or bad name to use) */
02360 };
02361 
02362 /* *INDENT-OFF* */
02363 static const struct allowed_bearers allowed_bearers_array[] = {
02364    /* Name,                      Displayable Name       Bearer Capability,                    Deprecated */
02365    { "speech",                  "Speech",               INFO_CAPABILITY_SPEECH,               0 },
02366    { "3_1khz",                  "3.1KHz Audio",         INFO_CAPABILITY_AUDIO_3_1K,           0 },
02367    { "digital_unrestricted",    "Unrestricted Digital", INFO_CAPABILITY_DIGITAL_UNRESTRICTED, 0 },
02368    { "digital_restricted",      "Restricted Digital",   INFO_CAPABILITY_DIGITAL_RESTRICTED,   0 },
02369    { "digital_restriced",       "Restricted Digital",   INFO_CAPABILITY_DIGITAL_RESTRICTED,   1 }, /* Allow misspelling for backwards compatibility */
02370    { "video",                   "Video",                INFO_CAPABILITY_VIDEO,                0 }
02371 };
02372 /* *INDENT-ON* */
02373 
02374 static const char *bearer2str(int cap)
02375 {
02376    unsigned index;
02377 
02378    for (index = 0; index < ARRAY_LEN(allowed_bearers_array); ++index) {
02379       if (allowed_bearers_array[index].cap == cap) {
02380          return allowed_bearers_array[index].display;
02381       }
02382    }
02383 
02384    return "Unknown Bearer";
02385 }
02386 
02387 #if defined(AST_MISDN_ENHANCEMENTS)
02388 /*!
02389  * \internal
02390  * \brief Fill in facility PartyNumber information
02391  *
02392  * \param party PartyNumber structure to fill in.
02393  * \param id Information to put in PartyNumber structure.
02394  *
02395  * \return Nothing
02396  */
02397 static void misdn_PartyNumber_fill(struct FacPartyNumber *party, const struct misdn_party_id *id)
02398 {
02399    ast_copy_string((char *) party->Number, id->number, sizeof(party->Number));
02400    party->LengthOfNumber = strlen((char *) party->Number);
02401    party->Type = misdn_to_PartyNumber_plan(id->number_plan);
02402    switch (party->Type) {
02403    case 1:/* public */
02404       party->TypeOfNumber = misdn_to_PartyNumber_ton_public(id->number_type);
02405       break;
02406    case 5:/* private */
02407       party->TypeOfNumber = misdn_to_PartyNumber_ton_private(id->number_type);
02408       break;
02409    default:
02410       party->TypeOfNumber = 0;/* Don't care */
02411       break;
02412    }
02413 }
02414 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02415 
02416 #if defined(AST_MISDN_ENHANCEMENTS)
02417 /*!
02418  * \internal
02419  * \brief Extract the information from PartyNumber
02420  *
02421  * \param id Where to put extracted PartyNumber information
02422  * \param party PartyNumber information to extract
02423  *
02424  * \return Nothing
02425  */
02426 static void misdn_PartyNumber_extract(struct misdn_party_id *id, const struct FacPartyNumber *party)
02427 {
02428    if (party->LengthOfNumber) {
02429       ast_copy_string(id->number, (char *) party->Number, sizeof(id->number));
02430       id->number_plan = PartyNumber_to_misdn_plan(party->Type);
02431       switch (party->Type) {
02432       case 1:/* public */
02433          id->number_type = PartyNumber_to_misdn_ton_public(party->TypeOfNumber);
02434          break;
02435       case 5:/* private */
02436          id->number_type = PartyNumber_to_misdn_ton_private(party->TypeOfNumber);
02437          break;
02438       default:
02439          id->number_type = NUMTYPE_UNKNOWN;
02440          break;
02441       }
02442    } else {
02443       /* Number not present */
02444       id->number_type = NUMTYPE_UNKNOWN;
02445       id->number_plan = NUMPLAN_ISDN;
02446       id->number[0] = 0;
02447    }
02448 }
02449 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02450 
02451 #if defined(AST_MISDN_ENHANCEMENTS)
02452 /*!
02453  * \internal
02454  * \brief Fill in facility Address information
02455  *
02456  * \param Address Address structure to fill in.
02457  * \param id Information to put in Address structure.
02458  *
02459  * \return Nothing
02460  */
02461 static void misdn_Address_fill(struct FacAddress *Address, const struct misdn_party_id *id)
02462 {
02463    misdn_PartyNumber_fill(&Address->Party, id);
02464 
02465    /* Subaddresses are not supported yet */
02466    Address->Subaddress.Length = 0;
02467 }
02468 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02469 
02470 #if defined(AST_MISDN_ENHANCEMENTS)
02471 /*!
02472  * \internal
02473  * \brief Fill in facility PresentedNumberUnscreened information
02474  *
02475  * \param presented PresentedNumberUnscreened structure to fill in.
02476  * \param id Information to put in PresentedNumberUnscreened structure.
02477  *
02478  * \return Nothing
02479  */
02480 static void misdn_PresentedNumberUnscreened_fill(struct FacPresentedNumberUnscreened *presented, const struct misdn_party_id *id)
02481 {
02482    presented->Type = misdn_to_PresentedNumberUnscreened_type(id->presentation, id->number[0] ? 1 : 0);
02483    misdn_PartyNumber_fill(&presented->Unscreened, id);
02484 }
02485 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02486 
02487 #if defined(AST_MISDN_ENHANCEMENTS)
02488 /*!
02489  * \internal
02490  * \brief Extract the information from PartyNumber
02491  *
02492  * \param id Where to put extracted PresentedNumberUnscreened information
02493  * \param presented PresentedNumberUnscreened information to extract
02494  *
02495  * \return Nothing
02496  */
02497 static void misdn_PresentedNumberUnscreened_extract(struct misdn_party_id *id, const struct FacPresentedNumberUnscreened *presented)
02498 {
02499    id->presentation = PresentedNumberUnscreened_to_misdn_pres(presented->Type);
02500    id->screening = 0;/* unscreened */
02501    switch (presented->Type) {
02502    case 0:/* presentationAllowedNumber */
02503    case 3:/* presentationRestrictedNumber */
02504       misdn_PartyNumber_extract(id, &presented->Unscreened);
02505       break;
02506    case 1:/* presentationRestricted */
02507    case 2:/* numberNotAvailableDueToInterworking */
02508    default:
02509       /* Number not present (And uninitialized so do not even look at it!) */
02510       id->number_type = NUMTYPE_UNKNOWN;
02511       id->number_plan = NUMPLAN_ISDN;
02512       id->number[0] = 0;
02513       break;
02514    }
02515 }
02516 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02517 
02518 #if defined(AST_MISDN_ENHANCEMENTS)
02519 static const char Level_Spacing[] = "          ";/* Work for up to 10 levels */
02520 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02521 
02522 #if defined(AST_MISDN_ENHANCEMENTS)
02523 static void print_facility_PartyNumber(unsigned Level, const struct FacPartyNumber *Party, const struct misdn_bchannel *bc)
02524 {
02525    if (Party->LengthOfNumber) {
02526       const char *Spacing;
02527 
02528       Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02529       chan_misdn_log(1, bc->port, " -->%s PartyNumber: Type:%d\n",
02530          Spacing, Party->Type);
02531       switch (Party->Type) {
02532       case 0: /* Unknown PartyNumber */
02533          chan_misdn_log(1, bc->port, " -->%s  Unknown: %s\n",
02534             Spacing, Party->Number);
02535          break;
02536       case 1: /* Public PartyNumber */
02537          chan_misdn_log(1, bc->port, " -->%s  Public TON:%d %s\n",
02538             Spacing, Party->TypeOfNumber, Party->Number);
02539          break;
02540       case 2: /* NSAP encoded PartyNumber */
02541          chan_misdn_log(1, bc->port, " -->%s  NSAP: %s\n",
02542             Spacing, Party->Number);
02543          break;
02544       case 3: /* Data PartyNumber (Not used) */
02545          chan_misdn_log(1, bc->port, " -->%s  Data: %s\n",
02546             Spacing, Party->Number);
02547          break;
02548       case 4: /* Telex PartyNumber (Not used) */
02549          chan_misdn_log(1, bc->port, " -->%s  Telex: %s\n",
02550             Spacing, Party->Number);
02551          break;
02552       case 5: /* Private PartyNumber */
02553          chan_misdn_log(1, bc->port, " -->%s  Private TON:%d %s\n",
02554             Spacing, Party->TypeOfNumber, Party->Number);
02555          break;
02556       case 8: /* National Standard PartyNumber (Not used) */
02557          chan_misdn_log(1, bc->port, " -->%s  National: %s\n",
02558             Spacing, Party->Number);
02559          break;
02560       default:
02561          break;
02562       }
02563    }
02564 }
02565 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02566 
02567 #if defined(AST_MISDN_ENHANCEMENTS)
02568 static void print_facility_Subaddress(unsigned Level, const struct FacPartySubaddress *Subaddress, const struct misdn_bchannel *bc)
02569 {
02570    if (Subaddress->Length) {
02571       const char *Spacing;
02572 
02573       Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02574       chan_misdn_log(1, bc->port, " -->%s Subaddress: Type:%d\n",
02575          Spacing, Subaddress->Type);
02576       switch (Subaddress->Type) {
02577       case 0: /* UserSpecified */
02578          if (Subaddress->u.UserSpecified.OddCountPresent) {
02579             chan_misdn_log(1, bc->port, " -->%s  User BCD OddCount:%d NumOctets:%d\n",
02580                Spacing, Subaddress->u.UserSpecified.OddCount, Subaddress->Length);
02581          } else {
02582             chan_misdn_log(1, bc->port, " -->%s  User: %s\n",
02583                Spacing, Subaddress->u.UserSpecified.Information);
02584          }
02585          break;
02586       case 1: /* NSAP */
02587          chan_misdn_log(1, bc->port, " -->%s  NSAP: %s\n",
02588             Spacing, Subaddress->u.Nsap);
02589          break;
02590       default:
02591          break;
02592       }
02593    }
02594 }
02595 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02596 
02597 #if defined(AST_MISDN_ENHANCEMENTS)
02598 static void print_facility_Address(unsigned Level, const struct FacAddress *Address, const struct misdn_bchannel *bc)
02599 {
02600    print_facility_PartyNumber(Level, &Address->Party, bc);
02601    print_facility_Subaddress(Level, &Address->Subaddress, bc);
02602 }
02603 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02604 
02605 #if defined(AST_MISDN_ENHANCEMENTS)
02606 static void print_facility_PresentedNumberUnscreened(unsigned Level, const struct FacPresentedNumberUnscreened *Presented, const struct misdn_bchannel *bc)
02607 {
02608    const char *Spacing;
02609 
02610    Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02611    chan_misdn_log(1, bc->port, " -->%s Unscreened Type:%d\n", Spacing, Presented->Type);
02612    switch (Presented->Type) {
02613    case 0: /* presentationAllowedNumber */
02614       chan_misdn_log(1, bc->port, " -->%s  Allowed:\n", Spacing);
02615       print_facility_PartyNumber(Level + 2, &Presented->Unscreened, bc);
02616       break;
02617    case 1: /* presentationRestricted */
02618       chan_misdn_log(1, bc->port, " -->%s  Restricted\n", Spacing);
02619       break;
02620    case 2: /* numberNotAvailableDueToInterworking */
02621       chan_misdn_log(1, bc->port, " -->%s  Not Available\n", Spacing);
02622       break;
02623    case 3: /* presentationRestrictedNumber */
02624       chan_misdn_log(1, bc->port, " -->%s  Restricted:\n", Spacing);
02625       print_facility_PartyNumber(Level + 2, &Presented->Unscreened, bc);
02626       break;
02627    default:
02628       break;
02629    }
02630 }
02631 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02632 
02633 #if defined(AST_MISDN_ENHANCEMENTS)
02634 static void print_facility_AddressScreened(unsigned Level, const struct FacAddressScreened *Address, const struct misdn_bchannel *bc)
02635 {
02636    const char *Spacing;
02637 
02638    Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02639    chan_misdn_log(1, bc->port, " -->%s ScreeningIndicator:%d\n", Spacing, Address->ScreeningIndicator);
02640    print_facility_PartyNumber(Level, &Address->Party, bc);
02641    print_facility_Subaddress(Level, &Address->Subaddress, bc);
02642 }
02643 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02644 
02645 #if defined(AST_MISDN_ENHANCEMENTS)
02646 static void print_facility_PresentedAddressScreened(unsigned Level, const struct FacPresentedAddressScreened *Presented, const struct misdn_bchannel *bc)
02647 {
02648    const char *Spacing;
02649 
02650    Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02651    chan_misdn_log(1, bc->port, " -->%s Screened Type:%d\n", Spacing, Presented->Type);
02652    switch (Presented->Type) {
02653    case 0: /* presentationAllowedAddress */
02654       chan_misdn_log(1, bc->port, " -->%s  Allowed:\n", Spacing);
02655       print_facility_AddressScreened(Level + 2, &Presented->Address, bc);
02656       break;
02657    case 1: /* presentationRestricted */
02658       chan_misdn_log(1, bc->port, " -->%s  Restricted\n", Spacing);
02659       break;
02660    case 2: /* numberNotAvailableDueToInterworking */
02661       chan_misdn_log(1, bc->port, " -->%s  Not Available\n", Spacing);
02662       break;
02663    case 3: /* presentationRestrictedAddress */
02664       chan_misdn_log(1, bc->port, " -->%s  Restricted:\n", Spacing);
02665       print_facility_AddressScreened(Level + 2, &Presented->Address, bc);
02666       break;
02667    default:
02668       break;
02669    }
02670 }
02671 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02672 
02673 #if defined(AST_MISDN_ENHANCEMENTS)
02674 static void print_facility_Q931_Bc_Hlc_Llc(unsigned Level, const struct Q931_Bc_Hlc_Llc *Q931ie, const struct misdn_bchannel *bc)
02675 {
02676    const char *Spacing;
02677 
02678    Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02679    chan_misdn_log(1, bc->port, " -->%s Q931ie:\n", Spacing);
02680    if (Q931ie->Bc.Length) {
02681       chan_misdn_log(1, bc->port, " -->%s  Bc Len:%d\n", Spacing, Q931ie->Bc.Length);
02682    }
02683    if (Q931ie->Hlc.Length) {
02684       chan_misdn_log(1, bc->port, " -->%s  Hlc Len:%d\n", Spacing, Q931ie->Hlc.Length);
02685    }
02686    if (Q931ie->Llc.Length) {
02687       chan_misdn_log(1, bc->port, " -->%s  Llc Len:%d\n", Spacing, Q931ie->Llc.Length);
02688    }
02689 }
02690 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02691 
02692 #if defined(AST_MISDN_ENHANCEMENTS)
02693 static void print_facility_Q931_Bc_Hlc_Llc_Uu(unsigned Level, const struct Q931_Bc_Hlc_Llc_Uu *Q931ie, const struct misdn_bchannel *bc)
02694 {
02695    const char *Spacing;
02696 
02697    Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02698    chan_misdn_log(1, bc->port, " -->%s Q931ie:\n", Spacing);
02699    if (Q931ie->Bc.Length) {
02700       chan_misdn_log(1, bc->port, " -->%s  Bc Len:%d\n", Spacing, Q931ie->Bc.Length);
02701    }
02702    if (Q931ie->Hlc.Length) {
02703       chan_misdn_log(1, bc->port, " -->%s  Hlc Len:%d\n", Spacing, Q931ie->Hlc.Length);
02704    }
02705    if (Q931ie->Llc.Length) {
02706       chan_misdn_log(1, bc->port, " -->%s  Llc Len:%d\n", Spacing, Q931ie->Llc.Length);
02707    }
02708    if (Q931ie->UserInfo.Length) {
02709       chan_misdn_log(1, bc->port, " -->%s  UserInfo Len:%d\n", Spacing, Q931ie->UserInfo.Length);
02710    }
02711 }
02712 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02713 
02714 #if defined(AST_MISDN_ENHANCEMENTS)
02715 static void print_facility_CallInformation(unsigned Level, const struct FacCallInformation *CallInfo, const struct misdn_bchannel *bc)
02716 {
02717    const char *Spacing;
02718 
02719    Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02720    chan_misdn_log(1, bc->port, " -->%s CCBSReference:%d\n",
02721       Spacing, CallInfo->CCBSReference);
02722    chan_misdn_log(1, bc->port, " -->%s AddressOfB:\n", Spacing);
02723    print_facility_Address(Level + 1, &CallInfo->AddressOfB, bc);
02724    print_facility_Q931_Bc_Hlc_Llc(Level, &CallInfo->Q931ie, bc);
02725    if (CallInfo->SubaddressOfA.Length) {
02726       chan_misdn_log(1, bc->port, " -->%s SubaddressOfA:\n", Spacing);
02727       print_facility_Subaddress(Level + 1, &CallInfo->SubaddressOfA, bc);
02728    }
02729 }
02730 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02731 
02732 #if defined(AST_MISDN_ENHANCEMENTS)
02733 static void print_facility_ServedUserNr(unsigned Level, const struct FacPartyNumber *Party, const struct misdn_bchannel *bc)
02734 {
02735    const char *Spacing;
02736 
02737    Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02738    if (Party->LengthOfNumber) {
02739       print_facility_PartyNumber(Level, Party, bc);
02740    } else {
02741       chan_misdn_log(1, bc->port, " -->%s All Numbers\n", Spacing);
02742    }
02743 }
02744 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02745 
02746 #if defined(AST_MISDN_ENHANCEMENTS)
02747 static void print_facility_IntResult(unsigned Level, const struct FacForwardingRecord *ForwardingRecord, const struct misdn_bchannel *bc)
02748 {
02749    const char *Spacing;
02750 
02751    Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
02752    chan_misdn_log(1, bc->port, " -->%s Procedure:%d BasicService:%d\n",
02753       Spacing,
02754       ForwardingRecord->Procedure,
02755       ForwardingRecord->BasicService);
02756    chan_misdn_log(1, bc->port, " -->%s ForwardedTo:\n", Spacing);
02757    print_facility_Address(Level + 1, &ForwardingRecord->ForwardedTo, bc);
02758    chan_misdn_log(1, bc->port, " -->%s ServedUserNr:\n", Spacing);
02759    print_facility_ServedUserNr(Level + 1, &ForwardingRecord->ServedUser, bc);
02760 }
02761 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02762 
02763 static void print_facility(const struct FacParm *fac, const struct misdn_bchannel *bc)
02764 {
02765 #if defined(AST_MISDN_ENHANCEMENTS)
02766    unsigned Index;
02767 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
02768 
02769    switch (fac->Function) {
02770 #if defined(AST_MISDN_ENHANCEMENTS)
02771    case Fac_ActivationDiversion:
02772       chan_misdn_log(1, bc->port, " --> ActivationDiversion: InvokeID:%d\n",
02773          fac->u.ActivationDiversion.InvokeID);
02774       switch (fac->u.ActivationDiversion.ComponentType) {
02775       case FacComponent_Invoke:
02776          chan_misdn_log(1, bc->port, " -->  Invoke: Procedure:%d BasicService:%d\n",
02777             fac->u.ActivationDiversion.Component.Invoke.Procedure,
02778             fac->u.ActivationDiversion.Component.Invoke.BasicService);
02779          chan_misdn_log(1, bc->port, " -->   ForwardedTo:\n");
02780          print_facility_Address(3, &fac->u.ActivationDiversion.Component.Invoke.ForwardedTo, bc);
02781          chan_misdn_log(1, bc->port, " -->   ServedUserNr:\n");
02782          print_facility_ServedUserNr(3, &fac->u.ActivationDiversion.Component.Invoke.ServedUser, bc);
02783          break;
02784       case FacComponent_Result:
02785          chan_misdn_log(1, bc->port, " -->  Result\n");
02786          break;
02787       default:
02788          break;
02789       }
02790       break;
02791    case Fac_DeactivationDiversion:
02792       chan_misdn_log(1, bc->port, " --> DeactivationDiversion: InvokeID:%d\n",
02793          fac->u.DeactivationDiversion.InvokeID);
02794       switch (fac->u.DeactivationDiversion.ComponentType) {
02795       case FacComponent_Invoke:
02796          chan_misdn_log(1, bc->port, " -->  Invoke: Procedure:%d BasicService:%d\n",
02797             fac->u.DeactivationDiversion.Component.Invoke.Procedure,
02798             fac->u.DeactivationDiversion.Component.Invoke.BasicService);
02799          chan_misdn_log(1, bc->port, " -->   ServedUserNr:\n");
02800          print_facility_ServedUserNr(3, &fac->u.DeactivationDiversion.Component.Invoke.ServedUser, bc);
02801          break;
02802       case FacComponent_Result:
02803          chan_misdn_log(1, bc->port, " -->  Result\n");
02804          break;
02805       default:
02806          break;
02807       }
02808       break;
02809    case Fac_ActivationStatusNotificationDiv:
02810       chan_misdn_log(1, bc->port, " --> ActivationStatusNotificationDiv: InvokeID:%d Procedure:%d BasicService:%d\n",
02811          fac->u.ActivationStatusNotificationDiv.InvokeID,
02812          fac->u.ActivationStatusNotificationDiv.Procedure,
02813          fac->u.ActivationStatusNotificationDiv.BasicService);
02814       chan_misdn_log(1, bc->port, " -->  ForwardedTo:\n");
02815       print_facility_Address(2, &fac->u.ActivationStatusNotificationDiv.ForwardedTo, bc);
02816       chan_misdn_log(1, bc->port, " -->  ServedUserNr:\n");
02817       print_facility_ServedUserNr(2, &fac->u.ActivationStatusNotificationDiv.ServedUser, bc);
02818       break;
02819    case Fac_DeactivationStatusNotificationDiv:
02820       chan_misdn_log(1, bc->port, " --> DeactivationStatusNotificationDiv: InvokeID:%d Procedure:%d BasicService:%d\n",
02821          fac->u.DeactivationStatusNotificationDiv.InvokeID,
02822          fac->u.DeactivationStatusNotificationDiv.Procedure,
02823          fac->u.DeactivationStatusNotificationDiv.BasicService);
02824       chan_misdn_log(1, bc->port, " -->  ServedUserNr:\n");
02825       print_facility_ServedUserNr(2, &fac->u.DeactivationStatusNotificationDiv.ServedUser, bc);
02826       break;
02827    case Fac_InterrogationDiversion:
02828       chan_misdn_log(1, bc->port, " --> InterrogationDiversion: InvokeID:%d\n",
02829          fac->u.InterrogationDiversion.InvokeID);
02830       switch (fac->u.InterrogationDiversion.ComponentType) {
02831       case FacComponent_Invoke:
02832          chan_misdn_log(1, bc->port, " -->  Invoke: Procedure:%d BasicService:%d\n",
02833             fac->u.InterrogationDiversion.Component.Invoke.Procedure,
02834             fac->u.InterrogationDiversion.Component.Invoke.BasicService);
02835          chan_misdn_log(1, bc->port, " -->   ServedUserNr:\n");
02836          print_facility_ServedUserNr(3, &fac->u.InterrogationDiversion.Component.Invoke.ServedUser, bc);
02837          break;
02838       case FacComponent_Result:
02839          chan_misdn_log(1, bc->port, " -->  Result:\n");
02840          if (fac->u.InterrogationDiversion.Component.Result.NumRecords) {
02841             for (Index = 0; Index < fac->u.InterrogationDiversion.Component.Result.NumRecords; ++Index) {
02842                chan_misdn_log(1, bc->port, " -->   IntResult[%d]:\n", Index);
02843                print_facility_IntResult(3, &fac->u.InterrogationDiversion.Component.Result.List[Index], bc);
02844             }
02845          }
02846          break;
02847       default:
02848          break;
02849       }
02850       break;
02851    case Fac_DiversionInformation:
02852       chan_misdn_log(1, bc->port, " --> DiversionInformation: InvokeID:%d Reason:%d BasicService:%d\n",
02853          fac->u.DiversionInformation.InvokeID,
02854          fac->u.DiversionInformation.DiversionReason,
02855          fac->u.DiversionInformation.BasicService);
02856       if (fac->u.DiversionInformation.ServedUserSubaddress.Length) {
02857          chan_misdn_log(1, bc->port, " -->  ServedUserSubaddress:\n");
02858          print_facility_Subaddress(2, &fac->u.DiversionInformation.ServedUserSubaddress, bc);
02859       }
02860       if (fac->u.DiversionInformation.CallingAddressPresent) {
02861          chan_misdn_log(1, bc->port, " -->  CallingAddress:\n");
02862          print_facility_PresentedAddressScreened(2, &fac->u.DiversionInformation.CallingAddress, bc);
02863       }
02864       if (fac->u.DiversionInformation.OriginalCalledPresent) {
02865          chan_misdn_log(1, bc->port, " -->  OriginalCalledNr:\n");
02866          print_facility_PresentedNumberUnscreened(2, &fac->u.DiversionInformation.OriginalCalled, bc);
02867       }
02868       if (fac->u.DiversionInformation.LastDivertingPresent) {
02869          chan_misdn_log(1, bc->port, " -->  LastDivertingNr:\n");
02870          print_facility_PresentedNumberUnscreened(2, &fac->u.DiversionInformation.LastDiverting, bc);
02871       }
02872       if (fac->u.DiversionInformation.LastDivertingReasonPresent) {
02873          chan_misdn_log(1, bc->port, " -->  LastDivertingReason:%d\n", fac->u.DiversionInformation.LastDivertingReason);
02874       }
02875       if (fac->u.DiversionInformation.UserInfo.Length) {
02876          chan_misdn_log(1, bc->port, " -->  UserInfo Length:%d\n", fac->u.DiversionInformation.UserInfo.Length);
02877       }
02878       break;
02879    case Fac_CallDeflection:
02880       chan_misdn_log(1, bc->port, " --> CallDeflection: InvokeID:%d\n",
02881          fac->u.CallDeflection.InvokeID);
02882       switch (fac->u.CallDeflection.ComponentType) {
02883       case FacComponent_Invoke:
02884          chan_misdn_log(1, bc->port, " -->  Invoke:\n");
02885          if (fac->u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent) {
02886             chan_misdn_log(1, bc->port, " -->   PresentationAllowed:%d\n",
02887                fac->u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser);
02888          }
02889          chan_misdn_log(1, bc->port, " -->   DeflectionAddress:\n");
02890          print_facility_Address(3, &fac->u.CallDeflection.Component.Invoke.Deflection, bc);
02891          break;
02892       case FacComponent_Result:
02893          chan_misdn_log(1, bc->port, " -->  Result\n");
02894          break;
02895       default:
02896          break;
02897       }
02898       break;
02899    case Fac_CallRerouteing:
02900       chan_misdn_log(1, bc->port, " --> CallRerouteing: InvokeID:%d\n",
02901          fac->u.CallRerouteing.InvokeID);
02902       switch (fac->u.CallRerouteing.ComponentType) {
02903       case FacComponent_Invoke:
02904          chan_misdn_log(1, bc->port, " -->  Invoke: Reason:%d Counter:%d\n",
02905             fac->u.CallRerouteing.Component.Invoke.ReroutingReason,
02906             fac->u.CallRerouteing.Component.Invoke.ReroutingCounter);
02907          chan_misdn_log(1, bc->port, " -->   CalledAddress:\n");
02908          print_facility_Address(3, &fac->u.CallRerouteing.Component.Invoke.CalledAddress, bc);
02909          print_facility_Q931_Bc_Hlc_Llc_Uu(2, &fac->u.CallRerouteing.Component.Invoke.Q931ie, bc);
02910          chan_misdn_log(1, bc->port, " -->   LastReroutingNr:\n");
02911          print_facility_PresentedNumberUnscreened(3, &fac->u.CallRerouteing.Component.Invoke.LastRerouting, bc);
02912          chan_misdn_log(1, bc->port, " -->   SubscriptionOption:%d\n",
02913             fac->u.CallRerouteing.Component.Invoke.SubscriptionOption);
02914          if (fac->u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length) {
02915             chan_misdn_log(1, bc->port, " -->   CallingParty:\n");
02916             print_facility_Subaddress(3, &fac->u.CallRerouteing.Component.Invoke.CallingPartySubaddress, bc);
02917          }
02918          break;
02919       case FacComponent_Result:
02920          chan_misdn_log(1, bc->port, " -->  Result\n");
02921          break;
02922       default:
02923          break;
02924       }
02925       break;
02926    case Fac_InterrogateServedUserNumbers:
02927       chan_misdn_log(1, bc->port, " --> InterrogateServedUserNumbers: InvokeID:%d\n",
02928          fac->u.InterrogateServedUserNumbers.InvokeID);
02929       switch (fac->u.InterrogateServedUserNumbers.ComponentType) {
02930       case FacComponent_Invoke:
02931          chan_misdn_log(1, bc->port, " -->  Invoke\n");
02932          break;
02933       case FacComponent_Result:
02934          chan_misdn_log(1, bc->port, " -->  Result:\n");
02935          if (fac->u.InterrogateServedUserNumbers.Component.Result.NumRecords) {
02936             for (Index = 0; Index < fac->u.InterrogateServedUserNumbers.Component.Result.NumRecords; ++Index) {
02937                chan_misdn_log(1, bc->port, " -->   ServedUserNr[%d]:\n", Index);
02938                print_facility_PartyNumber(3, &fac->u.InterrogateServedUserNumbers.Component.Result.List[Index], bc);
02939             }
02940          }
02941          break;
02942       default:
02943          break;
02944       }
02945       break;
02946    case Fac_DivertingLegInformation1:
02947       chan_misdn_log(1, bc->port, " --> DivertingLegInformation1: InvokeID:%d Reason:%d SubscriptionOption:%d\n",
02948          fac->u.DivertingLegInformation1.InvokeID,
02949          fac->u.DivertingLegInformation1.DiversionReason,
02950          fac->u.DivertingLegInformation1.SubscriptionOption);
02951       if (fac->u.DivertingLegInformation1.DivertedToPresent) {
02952          chan_misdn_log(1, bc->port, " -->  DivertedToNr:\n");
02953          print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation1.DivertedTo, bc);
02954       }
02955       break;
02956    case Fac_DivertingLegInformation2:
02957       chan_misdn_log(1, bc->port, " --> DivertingLegInformation2: InvokeID:%d Reason:%d Count:%d\n",
02958          fac->u.DivertingLegInformation2.InvokeID,
02959          fac->u.DivertingLegInformation2.DiversionReason,
02960          fac->u.DivertingLegInformation2.DiversionCounter);
02961       if (fac->u.DivertingLegInformation2.DivertingPresent) {
02962          chan_misdn_log(1, bc->port, " -->  DivertingNr:\n");
02963          print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation2.Diverting, bc);
02964       }
02965       if (fac->u.DivertingLegInformation2.OriginalCalledPresent) {
02966          chan_misdn_log(1, bc->port, " -->  OriginalCalledNr:\n");
02967          print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation2.OriginalCalled, bc);
02968       }
02969       break;
02970    case Fac_DivertingLegInformation3:
02971       chan_misdn_log(1, bc->port, " --> DivertingLegInformation3: InvokeID:%d PresentationAllowed:%d\n",
02972          fac->u.DivertingLegInformation3.InvokeID,
02973          fac->u.DivertingLegInformation3.PresentationAllowedIndicator);
02974       break;
02975 
02976 #else /* !defined(AST_MISDN_ENHANCEMENTS) */
02977 
02978    case Fac_CD:
02979       chan_misdn_log(1, bc->port, " --> calldeflect to: %s, presentable: %s\n", fac->u.CDeflection.DeflectedToNumber,
02980          fac->u.CDeflection.PresentationAllowed ? "yes" : "no");
02981       break;
02982 #endif   /* !defined(AST_MISDN_ENHANCEMENTS) */
02983    case Fac_AOCDCurrency:
02984       if (fac->u.AOCDcur.chargeNotAvailable) {
02985          chan_misdn_log(1, bc->port, " --> AOCD currency: charge not available\n");
02986       } else if (fac->u.AOCDcur.freeOfCharge) {
02987          chan_misdn_log(1, bc->port, " --> AOCD currency: free of charge\n");
02988       } else if (fac->u.AOCDchu.billingId >= 0) {
02989          chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s billingId:%d\n",
02990             fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
02991             (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDcur.billingId);
02992       } else {
02993          chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s\n",
02994             fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
02995             (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total");
02996       }
02997       break;
02998    case Fac_AOCDChargingUnit:
02999       if (fac->u.AOCDchu.chargeNotAvailable) {
03000          chan_misdn_log(1, bc->port, " --> AOCD charging unit: charge not available\n");
03001       } else if (fac->u.AOCDchu.freeOfCharge) {
03002          chan_misdn_log(1, bc->port, " --> AOCD charging unit: free of charge\n");
03003       } else if (fac->u.AOCDchu.billingId >= 0) {
03004          chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d\n",
03005             fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDchu.billingId);
03006       } else {
03007          chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n",
03008             fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total");
03009       }
03010       break;
03011 #if defined(AST_MISDN_ENHANCEMENTS)
03012    case Fac_ERROR:
03013       chan_misdn_log(1, bc->port, " --> ERROR: InvokeID:%d, Code:0x%02x\n",
03014          fac->u.ERROR.invokeId, fac->u.ERROR.errorValue);
03015       break;
03016    case Fac_RESULT:
03017       chan_misdn_log(1, bc->port, " --> RESULT: InvokeID:%d\n",
03018          fac->u.RESULT.InvokeID);
03019       break;
03020    case Fac_REJECT:
03021       if (fac->u.REJECT.InvokeIDPresent) {
03022          chan_misdn_log(1, bc->port, " --> REJECT: InvokeID:%d, Code:0x%02x\n",
03023             fac->u.REJECT.InvokeID, fac->u.REJECT.Code);
03024       } else {
03025          chan_misdn_log(1, bc->port, " --> REJECT: Code:0x%02x\n",
03026             fac->u.REJECT.Code);
03027       }
03028       break;
03029    case Fac_EctExecute:
03030       chan_misdn_log(1, bc->port, " --> EctExecute: InvokeID:%d\n",
03031          fac->u.EctExecute.InvokeID);
03032       break;
03033    case Fac_ExplicitEctExecute:
03034       chan_misdn_log(1, bc->port, " --> ExplicitEctExecute: InvokeID:%d LinkID:%d\n",
03035          fac->u.ExplicitEctExecute.InvokeID,
03036          fac->u.ExplicitEctExecute.LinkID);
03037       break;
03038    case Fac_RequestSubaddress:
03039       chan_misdn_log(1, bc->port, " --> RequestSubaddress: InvokeID:%d\n",
03040          fac->u.RequestSubaddress.InvokeID);
03041       break;
03042    case Fac_SubaddressTransfer:
03043       chan_misdn_log(1, bc->port, " --> SubaddressTransfer: InvokeID:%d\n",
03044          fac->u.SubaddressTransfer.InvokeID);
03045       print_facility_Subaddress(1, &fac->u.SubaddressTransfer.Subaddress, bc);
03046       break;
03047    case Fac_EctLinkIdRequest:
03048       chan_misdn_log(1, bc->port, " --> EctLinkIdRequest: InvokeID:%d\n",
03049          fac->u.EctLinkIdRequest.InvokeID);
03050       switch (fac->u.EctLinkIdRequest.ComponentType) {
03051       case FacComponent_Invoke:
03052          chan_misdn_log(1, bc->port, " -->  Invoke\n");
03053          break;
03054       case FacComponent_Result:
03055          chan_misdn_log(1, bc->port, " -->  Result: LinkID:%d\n",
03056             fac->u.EctLinkIdRequest.Component.Result.LinkID);
03057          break;
03058       default:
03059          break;
03060       }
03061       break;
03062    case Fac_EctInform:
03063       chan_misdn_log(1, bc->port, " --> EctInform: InvokeID:%d Status:%d\n",
03064          fac->u.EctInform.InvokeID,
03065          fac->u.EctInform.Status);
03066       if (fac->u.EctInform.RedirectionPresent) {
03067          chan_misdn_log(1, bc->port, " -->  Redirection Number\n");
03068          print_facility_PresentedNumberUnscreened(2, &fac->u.EctInform.Redirection, bc);
03069       }
03070       break;
03071    case Fac_EctLoopTest:
03072       chan_misdn_log(1, bc->port, " --> EctLoopTest: InvokeID:%d\n",
03073          fac->u.EctLoopTest.InvokeID);
03074       switch (fac->u.EctLoopTest.ComponentType) {
03075       case FacComponent_Invoke:
03076          chan_misdn_log(1, bc->port, " -->  Invoke: CallTransferID:%d\n",
03077             fac->u.EctLoopTest.Component.Invoke.CallTransferID);
03078          break;
03079       case FacComponent_Result:
03080          chan_misdn_log(1, bc->port, " -->  Result: LoopResult:%d\n",
03081             fac->u.EctLoopTest.Component.Result.LoopResult);
03082          break;
03083       default:
03084          break;
03085       }
03086       break;
03087    case Fac_StatusRequest:
03088       chan_misdn_log(1, bc->port, " --> StatusRequest: InvokeID:%d\n",
03089          fac->u.StatusRequest.InvokeID);
03090       switch (fac->u.StatusRequest.ComponentType) {
03091       case FacComponent_Invoke:
03092          chan_misdn_log(1, bc->port, " -->  Invoke: Compatibility:%d\n",
03093             fac->u.StatusRequest.Component.Invoke.CompatibilityMode);
03094          break;
03095       case FacComponent_Result:
03096          chan_misdn_log(1, bc->port, " -->  Result: Status:%d\n",
03097             fac->u.StatusRequest.Component.Result.Status);
03098          break;
03099       default:
03100          break;
03101       }
03102       break;
03103    case Fac_CallInfoRetain:
03104       chan_misdn_log(1, bc->port, " --> CallInfoRetain: InvokeID:%d, LinkageID:%d\n",
03105          fac->u.CallInfoRetain.InvokeID, fac->u.CallInfoRetain.CallLinkageID);
03106       break;
03107    case Fac_CCBSDeactivate:
03108       chan_misdn_log(1, bc->port, " --> CCBSDeactivate: InvokeID:%d\n",
03109          fac->u.CCBSDeactivate.InvokeID);
03110       switch (fac->u.CCBSDeactivate.ComponentType) {
03111       case FacComponent_Invoke:
03112          chan_misdn_log(1, bc->port, " -->  Invoke: CCBSReference:%d\n",
03113             fac->u.CCBSDeactivate.Component.Invoke.CCBSReference);
03114          break;
03115       case FacComponent_Result:
03116          chan_misdn_log(1, bc->port, " -->  Result\n");
03117          break;
03118       default:
03119          break;
03120       }
03121       break;
03122    case Fac_CCBSErase:
03123       chan_misdn_log(1, bc->port, " --> CCBSErase: InvokeID:%d, CCBSReference:%d RecallMode:%d, Reason:%d\n",
03124          fac->u.CCBSErase.InvokeID, fac->u.CCBSErase.CCBSReference,
03125          fac->u.CCBSErase.RecallMode, fac->u.CCBSErase.Reason);
03126       chan_misdn_log(1, bc->port, " -->  AddressOfB\n");
03127       print_facility_Address(2, &fac->u.CCBSErase.AddressOfB, bc);
03128       print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSErase.Q931ie, bc);
03129       break;
03130    case Fac_CCBSRemoteUserFree:
03131       chan_misdn_log(1, bc->port, " --> CCBSRemoteUserFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
03132          fac->u.CCBSRemoteUserFree.InvokeID, fac->u.CCBSRemoteUserFree.CCBSReference,
03133          fac->u.CCBSRemoteUserFree.RecallMode);
03134       chan_misdn_log(1, bc->port, " -->  AddressOfB\n");
03135       print_facility_Address(2, &fac->u.CCBSRemoteUserFree.AddressOfB, bc);
03136       print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSRemoteUserFree.Q931ie, bc);
03137       break;
03138    case Fac_CCBSCall:
03139       chan_misdn_log(1, bc->port, " --> CCBSCall: InvokeID:%d, CCBSReference:%d\n",
03140          fac->u.CCBSCall.InvokeID, fac->u.CCBSCall.CCBSReference);
03141       break;
03142    case Fac_CCBSStatusRequest:
03143       chan_misdn_log(1, bc->port, " --> CCBSStatusRequest: InvokeID:%d\n",
03144          fac->u.CCBSStatusRequest.InvokeID);
03145       switch (fac->u.CCBSStatusRequest.ComponentType) {
03146       case FacComponent_Invoke:
03147          chan_misdn_log(1, bc->port, " -->  Invoke: CCBSReference:%d RecallMode:%d\n",
03148             fac->u.CCBSStatusRequest.Component.Invoke.CCBSReference,
03149             fac->u.CCBSStatusRequest.Component.Invoke.RecallMode);
03150          print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCBSStatusRequest.Component.Invoke.Q931ie, bc);
03151          break;
03152       case FacComponent_Result:
03153          chan_misdn_log(1, bc->port, " -->  Result: Free:%d\n",
03154             fac->u.CCBSStatusRequest.Component.Result.Free);
03155          break;
03156       default:
03157          break;
03158       }
03159       break;
03160    case Fac_CCBSBFree:
03161       chan_misdn_log(1, bc->port, " --> CCBSBFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
03162          fac->u.CCBSBFree.InvokeID, fac->u.CCBSBFree.CCBSReference,
03163          fac->u.CCBSBFree.RecallMode);
03164       chan_misdn_log(1, bc->port, " -->  AddressOfB\n");
03165       print_facility_Address(2, &fac->u.CCBSBFree.AddressOfB, bc);
03166       print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSBFree.Q931ie, bc);
03167       break;
03168    case Fac_EraseCallLinkageID:
03169       chan_misdn_log(1, bc->port, " --> EraseCallLinkageID: InvokeID:%d, LinkageID:%d\n",
03170          fac->u.EraseCallLinkageID.InvokeID, fac->u.EraseCallLinkageID.CallLinkageID);
03171       break;
03172    case Fac_CCBSStopAlerting:
03173       chan_misdn_log(1, bc->port, " --> CCBSStopAlerting: InvokeID:%d, CCBSReference:%d\n",
03174          fac->u.CCBSStopAlerting.InvokeID, fac->u.CCBSStopAlerting.CCBSReference);
03175       break;
03176    case Fac_CCBSRequest:
03177       chan_misdn_log(1, bc->port, " --> CCBSRequest: InvokeID:%d\n",
03178          fac->u.CCBSRequest.InvokeID);
03179       switch (fac->u.CCBSRequest.ComponentType) {
03180       case FacComponent_Invoke:
03181          chan_misdn_log(1, bc->port, " -->  Invoke: LinkageID:%d\n",
03182             fac->u.CCBSRequest.Component.Invoke.CallLinkageID);
03183          break;
03184       case FacComponent_Result:
03185          chan_misdn_log(1, bc->port, " -->  Result: CCBSReference:%d RecallMode:%d\n",
03186             fac->u.CCBSRequest.Component.Result.CCBSReference,
03187             fac->u.CCBSRequest.Component.Result.RecallMode);
03188          break;
03189       default:
03190          break;
03191       }
03192       break;
03193    case Fac_CCBSInterrogate:
03194       chan_misdn_log(1, bc->port, " --> CCBSInterrogate: InvokeID:%d\n",
03195          fac->u.CCBSInterrogate.InvokeID);
03196       switch (fac->u.CCBSInterrogate.ComponentType) {
03197       case FacComponent_Invoke:
03198          chan_misdn_log(1, bc->port, " -->  Invoke\n");
03199          if (fac->u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent) {
03200             chan_misdn_log(1, bc->port, " -->   CCBSReference:%d\n",
03201                fac->u.CCBSInterrogate.Component.Invoke.CCBSReference);
03202          }
03203          if (fac->u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber) {
03204             chan_misdn_log(1, bc->port, " -->   AParty\n");
03205             print_facility_PartyNumber(3, &fac->u.CCBSInterrogate.Component.Invoke.AParty, bc);
03206          }
03207          break;
03208       case FacComponent_Result:
03209          chan_misdn_log(1, bc->port, " -->  Result: RecallMode:%d\n",
03210             fac->u.CCBSInterrogate.Component.Result.RecallMode);
03211          if (fac->u.CCBSInterrogate.Component.Result.NumRecords) {
03212             for (Index = 0; Index < fac->u.CCBSInterrogate.Component.Result.NumRecords; ++Index) {
03213                chan_misdn_log(1, bc->port, " -->   CallDetails[%d]:\n", Index);
03214                print_facility_CallInformation(3, &fac->u.CCBSInterrogate.Component.Result.CallDetails[Index], bc);
03215             }
03216          }
03217          break;
03218       default:
03219          break;
03220       }
03221       break;
03222    case Fac_CCNRRequest:
03223       chan_misdn_log(1, bc->port, " --> CCNRRequest: InvokeID:%d\n",
03224          fac->u.CCNRRequest.InvokeID);
03225       switch (fac->u.CCNRRequest.ComponentType) {
03226       case FacComponent_Invoke:
03227          chan_misdn_log(1, bc->port, " -->  Invoke: LinkageID:%d\n",
03228             fac->u.CCNRRequest.Component.Invoke.CallLinkageID);
03229          break;
03230       case FacComponent_Result:
03231          chan_misdn_log(1, bc->port, " -->  Result: CCBSReference:%d RecallMode:%d\n",
03232             fac->u.CCNRRequest.Component.Result.CCBSReference,
03233             fac->u.CCNRRequest.Component.Result.RecallMode);
03234          break;
03235       default:
03236          break;
03237       }
03238       break;
03239    case Fac_CCNRInterrogate:
03240       chan_misdn_log(1, bc->port, " --> CCNRInterrogate: InvokeID:%d\n",
03241          fac->u.CCNRInterrogate.InvokeID);
03242       switch (fac->u.CCNRInterrogate.ComponentType) {
03243       case FacComponent_Invoke:
03244          chan_misdn_log(1, bc->port, " -->  Invoke\n");
03245          if (fac->u.CCNRInterrogate.Component.Invoke.CCBSReferencePresent) {
03246             chan_misdn_log(1, bc->port, " -->   CCBSReference:%d\n",
03247                fac->u.CCNRInterrogate.Component.Invoke.CCBSReference);
03248          }
03249          if (fac->u.CCNRInterrogate.Component.Invoke.AParty.LengthOfNumber) {
03250             chan_misdn_log(1, bc->port, " -->   AParty\n");
03251             print_facility_PartyNumber(3, &fac->u.CCNRInterrogate.Component.Invoke.AParty, bc);
03252          }
03253          break;
03254       case FacComponent_Result:
03255          chan_misdn_log(1, bc->port, " -->  Result: RecallMode:%d\n",
03256             fac->u.CCNRInterrogate.Component.Result.RecallMode);
03257          if (fac->u.CCNRInterrogate.Component.Result.NumRecords) {
03258             for (Index = 0; Index < fac->u.CCNRInterrogate.Component.Result.NumRecords; ++Index) {
03259                chan_misdn_log(1, bc->port, " -->   CallDetails[%d]:\n", Index);
03260                print_facility_CallInformation(3, &fac->u.CCNRInterrogate.Component.Result.CallDetails[Index], bc);
03261             }
03262          }
03263          break;
03264       default:
03265          break;
03266       }
03267       break;
03268    case Fac_CCBS_T_Call:
03269       chan_misdn_log(1, bc->port, " --> CCBS_T_Call: InvokeID:%d\n",
03270          fac->u.CCBS_T_Call.InvokeID);
03271       break;
03272    case Fac_CCBS_T_Suspend:
03273       chan_misdn_log(1, bc->port, " --> CCBS_T_Suspend: InvokeID:%d\n",
03274          fac->u.CCBS_T_Suspend.InvokeID);
03275       break;
03276    case Fac_CCBS_T_Resume:
03277       chan_misdn_log(1, bc->port, " --> CCBS_T_Resume: InvokeID:%d\n",
03278          fac->u.CCBS_T_Resume.InvokeID);
03279       break;
03280    case Fac_CCBS_T_RemoteUserFree:
03281       chan_misdn_log(1, bc->port, " --> CCBS_T_RemoteUserFree: InvokeID:%d\n",
03282          fac->u.CCBS_T_RemoteUserFree.InvokeID);
03283       break;
03284    case Fac_CCBS_T_Available:
03285       chan_misdn_log(1, bc->port, " --> CCBS_T_Available: InvokeID:%d\n",
03286          fac->u.CCBS_T_Available.InvokeID);
03287       break;
03288    case Fac_CCBS_T_Request:
03289       chan_misdn_log(1, bc->port, " --> CCBS_T_Request: InvokeID:%d\n",
03290          fac->u.CCBS_T_Request.InvokeID);
03291       switch (fac->u.CCBS_T_Request.ComponentType) {
03292       case FacComponent_Invoke:
03293          chan_misdn_log(1, bc->port, " -->  Invoke\n");
03294          chan_misdn_log(1, bc->port, " -->   DestinationAddress:\n");
03295          print_facility_Address(3, &fac->u.CCBS_T_Request.Component.Invoke.Destination, bc);
03296          print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCBS_T_Request.Component.Invoke.Q931ie, bc);
03297          if (fac->u.CCBS_T_Request.Component.Invoke.RetentionSupported) {
03298             chan_misdn_log(1, bc->port, " -->   RetentionSupported:1\n");
03299          }
03300          if (fac->u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent) {
03301             chan_misdn_log(1, bc->port, " -->   PresentationAllowed:%d\n",
03302                fac->u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator);
03303          }
03304          if (fac->u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber) {
03305             chan_misdn_log(1, bc->port, " -->   OriginatingAddress:\n");
03306             print_facility_Address(3, &fac->u.CCBS_T_Request.Component.Invoke.Originating, bc);
03307          }
03308          break;
03309       case FacComponent_Result:
03310          chan_misdn_log(1, bc->port, " -->  Result: RetentionSupported:%d\n",
03311             fac->u.CCBS_T_Request.Component.Result.RetentionSupported);
03312          break;
03313       default:
03314          break;
03315       }
03316       break;
03317    case Fac_CCNR_T_Request:
03318       chan_misdn_log(1, bc->port, " --> CCNR_T_Request: InvokeID:%d\n",
03319          fac->u.CCNR_T_Request.InvokeID);
03320       switch (fac->u.CCNR_T_Request.ComponentType) {
03321       case FacComponent_Invoke:
03322          chan_misdn_log(1, bc->port, " -->  Invoke\n");
03323          chan_misdn_log(1, bc->port, " -->   DestinationAddress:\n");
03324          print_facility_Address(3, &fac->u.CCNR_T_Request.Component.Invoke.Destination, bc);
03325          print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCNR_T_Request.Component.Invoke.Q931ie, bc);
03326          if (fac->u.CCNR_T_Request.Component.Invoke.RetentionSupported) {
03327             chan_misdn_log(1, bc->port, " -->   RetentionSupported:1\n");
03328          }
03329          if (fac->u.CCNR_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent) {
03330             chan_misdn_log(1, bc->port, " -->   PresentationAllowed:%d\n",
03331                fac->u.CCNR_T_Request.Component.Invoke.PresentationAllowedIndicator);
03332          }
03333          if (fac->u.CCNR_T_Request.Component.Invoke.Originating.Party.LengthOfNumber) {
03334             chan_misdn_log(1, bc->port, " -->   OriginatingAddress:\n");
03335             print_facility_Address(3, &fac->u.CCNR_T_Request.Component.Invoke.Originating, bc);
03336          }
03337          break;
03338       case FacComponent_Result:
03339          chan_misdn_log(1, bc->port, " -->  Result: RetentionSupported:%d\n",
03340             fac->u.CCNR_T_Request.Component.Result.RetentionSupported);
03341          break;
03342       default:
03343          break;
03344       }
03345       break;
03346 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
03347    case Fac_None:
03348       /* No facility so print nothing */
03349       break;
03350    default:
03351       chan_misdn_log(1, bc->port, " --> unknown facility\n");
03352       break;
03353    }
03354 }
03355 
03356 static void print_bearer(struct misdn_bchannel *bc)
03357 {
03358    chan_misdn_log(2, bc->port, " --> Bearer: %s\n", bearer2str(bc->capability));
03359 
03360    switch(bc->law) {
03361    case INFO_CODEC_ALAW:
03362       chan_misdn_log(2, bc->port, " --> Codec: Alaw\n");
03363       break;
03364    case INFO_CODEC_ULAW:
03365       chan_misdn_log(2, bc->port, " --> Codec: Ulaw\n");
03366       break;
03367    }
03368 }
03369 
03370 /*!
03371  * \internal
03372  * \brief Prefix a string to another string in place.
03373  *
03374  * \param str_prefix String to prefix to the main string.
03375  * \param str_main String to get the prefix added to it.
03376  * \param size Buffer size of the main string (Includes null terminator).
03377  *
03378  * \note The str_main buffer size must be greater than one.
03379  *
03380  * \return Nothing
03381  */
03382 static void misdn_prefix_string(const char *str_prefix, char *str_main, size_t size)
03383 {
03384    size_t len_over;
03385    size_t len_total;
03386    size_t len_main;
03387    size_t len_prefix;
03388 
03389    len_prefix = strlen(str_prefix);
03390    if (!len_prefix) {
03391       /* There is no prefix to prepend. */
03392       return;
03393    }
03394    len_main = strlen(str_main);
03395    len_total = len_prefix + len_main;
03396    if (size <= len_total) {
03397       /* We need to truncate since the buffer is too small. */
03398       len_over = len_total + 1 - size;
03399       if (len_over <= len_main) {
03400          len_main -= len_over;
03401       } else {
03402          len_over -= len_main;
03403          len_main = 0;
03404          len_prefix -= len_over;
03405       }
03406    }
03407    if (len_main) {
03408       memmove(str_main + len_prefix, str_main, len_main);
03409    }
03410    memcpy(str_main, str_prefix, len_prefix);
03411    str_main[len_prefix + len_main] = '\0';
03412 }
03413 
03414 /*!
03415  * \internal
03416  * \brief Add a configured prefix to the given number.
03417  *
03418  * \param port Logical port number
03419  * \param number_type Type-of-number passed in.
03420  * \param number Given number string to add prefix
03421  * \param size Buffer size number string occupies.
03422  *
03423  * \return Nothing
03424  */
03425 static void misdn_add_number_prefix(int port, enum mISDN_NUMBER_TYPE number_type, char *number, size_t size)
03426 {
03427    enum misdn_cfg_elements type_prefix;
03428    char num_prefix[MISDN_MAX_NUMBER_LEN];
03429 
03430    /* Get prefix string. */
03431    switch (number_type) {
03432    case NUMTYPE_UNKNOWN:
03433       type_prefix = MISDN_CFG_TON_PREFIX_UNKNOWN;
03434       break;
03435    case NUMTYPE_INTERNATIONAL:
03436       type_prefix = MISDN_CFG_TON_PREFIX_INTERNATIONAL;
03437       break;
03438    case NUMTYPE_NATIONAL:
03439       type_prefix = MISDN_CFG_TON_PREFIX_NATIONAL;
03440       break;
03441    case NUMTYPE_NETWORK_SPECIFIC:
03442       type_prefix = MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC;
03443       break;
03444    case NUMTYPE_SUBSCRIBER:
03445       type_prefix = MISDN_CFG_TON_PREFIX_SUBSCRIBER;
03446       break;
03447    case NUMTYPE_ABBREVIATED:
03448       type_prefix = MISDN_CFG_TON_PREFIX_ABBREVIATED;
03449       break;
03450    default:
03451       /* Type-of-number does not have a prefix that can be added. */
03452       return;
03453    }
03454    misdn_cfg_get(port, type_prefix, num_prefix, sizeof(num_prefix));
03455 
03456    misdn_prefix_string(num_prefix, number, size);
03457 }
03458 
03459 static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc)
03460 {
03461    RAII_VAR(struct ast_channel *, chan, NULL, ast_channel_cleanup);
03462    char buf[128];
03463 
03464    if (!bc->AOCD_need_export || !ast) {
03465       return;
03466    }
03467 
03468    if (originator == ORG_AST) {
03469       chan = ast_channel_bridge_peer(ast);
03470       if (!chan) {
03471          return;
03472       }
03473    } else {
03474       chan = ast_channel_ref(ast);
03475    }
03476 
03477    switch (bc->AOCDtype) {
03478    case Fac_AOCDCurrency:
03479       pbx_builtin_setvar_helper(chan, "AOCD_Type", "currency");
03480       if (bc->AOCD.currency.chargeNotAvailable) {
03481          pbx_builtin_setvar_helper(chan, "AOCD_ChargeAvailable", "no");
03482       } else {
03483          pbx_builtin_setvar_helper(chan, "AOCD_ChargeAvailable", "yes");
03484          if (bc->AOCD.currency.freeOfCharge) {
03485             pbx_builtin_setvar_helper(chan, "AOCD_FreeOfCharge", "yes");
03486          } else {
03487             pbx_builtin_setvar_helper(chan, "AOCD_FreeOfCharge", "no");
03488             if (snprintf(buf, sizeof(buf), "%d %s", bc->AOCD.currency.currencyAmount * bc->AOCD.currency.multiplier, bc->AOCD.currency.currency) < sizeof(buf)) {
03489                pbx_builtin_setvar_helper(chan, "AOCD_Amount", buf);
03490                if (bc->AOCD.currency.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.currency.billingId) < sizeof(buf)) {
03491                   pbx_builtin_setvar_helper(chan, "AOCD_BillingId", buf);
03492                }
03493             }
03494          }
03495       }
03496       break;
03497    case Fac_AOCDChargingUnit:
03498       pbx_builtin_setvar_helper(chan, "AOCD_Type", "charging_unit");
03499       if (bc->AOCD.chargingUnit.chargeNotAvailable) {
03500          pbx_builtin_setvar_helper(chan, "AOCD_ChargeAvailable", "no");
03501       } else {
03502          pbx_builtin_setvar_helper(chan, "AOCD_ChargeAvailable", "yes");
03503          if (bc->AOCD.chargingUnit.freeOfCharge) {
03504             pbx_builtin_setvar_helper(chan, "AOCD_FreeOfCharge", "yes");
03505          } else {
03506             pbx_builtin_setvar_helper(chan, "AOCD_FreeOfCharge", "no");
03507             if (snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.recordedUnits) < sizeof(buf)) {
03508                pbx_builtin_setvar_helper(chan, "AOCD_RecordedUnits", buf);
03509                if (bc->AOCD.chargingUnit.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.billingId) < sizeof(buf)) {
03510                   pbx_builtin_setvar_helper(chan, "AOCD_BillingId", buf);
03511                }
03512             }
03513          }
03514       }
03515       break;
03516    default:
03517       break;
03518    }
03519 
03520    bc->AOCD_need_export = 0;
03521 }
03522 
03523 /*************** Helpers END *************/
03524 
03525 static void sighandler(int sig)
03526 {
03527 }
03528 
03529 static void *misdn_tasks_thread_func(void *data)
03530 {
03531    int wait;
03532    struct sigaction sa;
03533 
03534    sa.sa_handler = sighandler;
03535    sa.sa_flags = SA_NODEFER;
03536    sigemptyset(&sa.sa_mask);
03537    sigaddset(&sa.sa_mask, SIGUSR1);
03538    sigaction(SIGUSR1, &sa, NULL);
03539 
03540    sem_post((sem_t *)data);
03541 
03542    while (1) {
03543       wait = ast_sched_wait(misdn_tasks);
03544       if (wait < 0) {
03545          wait = 8000;
03546       }
03547       if (poll(NULL, 0, wait) < 0) {
03548          chan_misdn_log(4, 0, "Waking up misdn_tasks thread\n");
03549       }
03550       ast_sched_runq(misdn_tasks);
03551    }
03552    return NULL;
03553 }
03554 
03555 static void misdn_tasks_init(void)
03556 {
03557    sem_t blocker;
03558    int i = 5;
03559 
03560    if (sem_init(&blocker, 0, 0)) {
03561       perror("chan_misdn: Failed to initialize semaphore!");
03562       exit(1);
03563    }
03564 
03565    chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
03566 
03567    misdn_tasks = ast_sched_context_create();
03568    pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, &blocker);
03569 
03570    while (sem_wait(&blocker) && --i) {
03571    }
03572    sem_destroy(&blocker);
03573 }
03574 
03575 static void misdn_tasks_destroy(void)
03576 {
03577    if (misdn_tasks) {
03578       chan_misdn_log(4, 0, "Killing misdn_tasks thread\n");
03579       if (pthread_cancel(misdn_tasks_thread) == 0) {
03580          cb_log(4, 0, "Joining misdn_tasks thread\n");
03581          pthread_join(misdn_tasks_thread, NULL);
03582       }
03583       ast_sched_context_destroy(misdn_tasks);
03584    }
03585 }
03586 
03587 static inline void misdn_tasks_wakeup(void)
03588 {
03589    pthread_kill(misdn_tasks_thread, SIGUSR1);
03590 }
03591 
03592 static inline int _misdn_tasks_add_variable(int timeout, ast_sched_cb callback, const void *data, int variable)
03593 {
03594    int task_id;
03595 
03596    if (!misdn_tasks) {
03597       misdn_tasks_init();
03598    }
03599    task_id = ast_sched_add_variable(misdn_tasks, timeout, callback, data, variable);
03600    misdn_tasks_wakeup();
03601 
03602    return task_id;
03603 }
03604 
03605 static int misdn_tasks_add(int timeout, ast_sched_cb callback, const void *data)
03606 {
03607    return _misdn_tasks_add_variable(timeout, callback, data, 0);
03608 }
03609 
03610 static int misdn_tasks_add_variable(int timeout, ast_sched_cb callback, const void *data)
03611 {
03612    return _misdn_tasks_add_variable(timeout, callback, data, 1);
03613 }
03614 
03615 static void misdn_tasks_remove(int task_id)
03616 {
03617    AST_SCHED_DEL(misdn_tasks, task_id);
03618 }
03619 
03620 static int misdn_l1_task(const void *vdata)
03621 {
03622    const int *data = vdata;
03623 
03624    misdn_lib_isdn_l1watcher(*data);
03625    chan_misdn_log(5, *data, "L1watcher timeout\n");
03626    return 1;
03627 }
03628 
03629 static int misdn_overlap_dial_task(const void *data)
03630 {
03631    struct timeval tv_end, tv_now;
03632    int diff;
03633    struct chan_list *ch = (struct chan_list *) data;
03634    char *dad;
03635 
03636    chan_misdn_log(4, ch->bc->port, "overlap dial task, chan_state: %d\n", ch->state);
03637 
03638    if (ch->state != MISDN_WAITING4DIGS) {
03639       ch->overlap_dial_task = -1;
03640       return 0;
03641    }
03642 
03643    ast_mutex_lock(&ch->overlap_tv_lock);
03644    tv_end = ch->overlap_tv;
03645    ast_mutex_unlock(&ch->overlap_tv_lock);
03646 
03647    tv_end.tv_sec += ch->overlap_dial;
03648    tv_now = ast_tvnow();
03649 
03650    diff = ast_tvdiff_ms(tv_end, tv_now);
03651    if (100 < diff) {
03652       return diff;
03653    }
03654 
03655    /* if we are 100ms near the timeout, we are satisfied.. */
03656    stop_indicate(ch);
03657 
03658    if (ast_strlen_zero(ch->bc->dialed.number)) {
03659       dad = "s";
03660       ast_channel_exten_set(ch->ast, dad);
03661    } else {
03662       dad = ch->bc->dialed.number;
03663    }
03664 
03665    if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->caller.number)) {
03666       ch->state = MISDN_DIALING;
03667       if (pbx_start_chan(ch) < 0) {
03668          chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
03669          goto misdn_overlap_dial_task_disconnect;
03670       }
03671    } else {
03672 misdn_overlap_dial_task_disconnect:
03673       hanguptone_indicate(ch);
03674       ch->bc->out_cause = AST_CAUSE_UNALLOCATED;
03675       ch->state = MISDN_CLEANING;
03676       misdn_lib_send_event(ch->bc, EVENT_DISCONNECT);
03677    }
03678    ch->overlap_dial_task = -1;
03679    return 0;
03680 }
03681 
03682 static void send_digit_to_chan(struct chan_list *cl, char digit)
03683 {
03684    static const char * const dtmf_tones[] = {
03685 /* *INDENT-OFF* */
03686       "!941+1336/100,!0/100", /* 0 */
03687       "!697+1209/100,!0/100", /* 1 */
03688       "!697+1336/100,!0/100", /* 2 */
03689       "!697+1477/100,!0/100", /* 3 */
03690       "!770+1209/100,!0/100", /* 4 */
03691       "!770+1336/100,!0/100", /* 5 */
03692       "!770+1477/100,!0/100", /* 6 */
03693       "!852+1209/100,!0/100", /* 7 */
03694       "!852+1336/100,!0/100", /* 8 */
03695       "!852+1477/100,!0/100", /* 9 */
03696       "!697+1633/100,!0/100", /* A */
03697       "!770+1633/100,!0/100", /* B */
03698       "!852+1633/100,!0/100", /* C */
03699       "!941+1633/100,!0/100", /* D */
03700       "!941+1209/100,!0/100", /* * */
03701       "!941+1477/100,!0/100", /* # */
03702 /* *INDENT-ON* */
03703    };
03704    struct ast_channel *chan = cl->ast;
03705 
03706    if (digit >= '0' && digit <='9') {
03707       ast_playtones_start(chan, 0, dtmf_tones[digit - '0'], 0);
03708    } else if (digit >= 'A' && digit <= 'D') {
03709       ast_playtones_start(chan, 0, dtmf_tones[digit - 'A' + 10], 0);
03710    } else if (digit == '*') {
03711       ast_playtones_start(chan, 0, dtmf_tones[14], 0);
03712    } else if (digit == '#') {
03713       ast_playtones_start(chan, 0, dtmf_tones[15], 0);
03714    } else {
03715       /* not handled */
03716       ast_debug(1, "Unable to handle DTMF tone '%c' for '%s'\n", digit, ast_channel_name(chan));
03717    }
03718 }
03719 
03720 /*** CLI HANDLING ***/
03721 static char *handle_cli_misdn_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03722 {
03723    int level;
03724 
03725    switch (cmd) {
03726    case CLI_INIT:
03727       e->command = "misdn set debug [on|off]";
03728       e->usage =
03729          "Usage: misdn set debug {on|off|<level>} [only] | [port <port> [only]]\n"
03730          "       Set the debug level of the mISDN channel.\n";
03731       return NULL;
03732    case CLI_GENERATE:
03733       return complete_debug_port(a);
03734    }
03735 
03736    if (a->argc < 4 || a->argc > 7) {
03737       return CLI_SHOWUSAGE;
03738    }
03739 
03740    if (!strcasecmp(a->argv[3], "on")) {
03741       level = 1;
03742    } else if (!strcasecmp(a->argv[3], "off")) {
03743       level = 0;
03744    } else if (isdigit(a->argv[3][0])) {
03745       level = atoi(a->argv[3]);
03746    } else {
03747       return CLI_SHOWUSAGE;
03748    }
03749 
03750    switch (a->argc) {
03751    case 4:
03752    case 5:
03753       {
03754          int i;
03755          int only = 0;
03756          if (a->argc == 5) {
03757             if (strncasecmp(a->argv[4], "only", strlen(a->argv[4]))) {
03758                return CLI_SHOWUSAGE;
03759             } else {
03760                only = 1;
03761             }
03762          }
03763 
03764          for (i = 0; i <= max_ports; i++) {
03765             misdn_debug[i] = level;
03766             misdn_debug_only[i] = only;
03767          }
03768          ast_cli(a->fd, "changing debug level for all ports to %d%s\n", misdn_debug[0], only ? " (only)" : "");
03769       }
03770       break;
03771    case 6:
03772    case 7:
03773       {
03774          int port;
03775          if (strncasecmp(a->argv[4], "port", strlen(a->argv[4])))
03776             return CLI_SHOWUSAGE;
03777          port = atoi(a->argv[5]);
03778          if (port <= 0 || port > max_ports) {
03779             switch (max_ports) {
03780             case 0:
03781                ast_cli(a->fd, "port number not valid! no ports available so you won't get lucky with any number here...\n");
03782                break;
03783             case 1:
03784                ast_cli(a->fd, "port number not valid! only port 1 is available.\n");
03785                break;
03786             default:
03787                ast_cli(a->fd, "port number not valid! only ports 1 to %d are available.\n", max_ports);
03788             }
03789             return 0;
03790          }
03791          if (a->argc == 7) {
03792             if (strncasecmp(a->argv[6], "only", strlen(a->argv[6]))) {
03793                return CLI_SHOWUSAGE;
03794             } else {
03795                misdn_debug_only[port] = 1;
03796             }
03797          } else {
03798             misdn_debug_only[port] = 0;
03799          }
03800          misdn_debug[port] = level;
03801          ast_cli(a->fd, "changing debug level to %d%s for port %d\n", misdn_debug[port], misdn_debug_only[port] ? " (only)" : "", port);
03802       }
03803    }
03804 
03805    return CLI_SUCCESS;
03806 }
03807 
03808 static char *handle_cli_misdn_set_crypt_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03809 {
03810    switch (cmd) {
03811    case CLI_INIT:
03812       e->command = "misdn set crypt debug";
03813       e->usage =
03814          "Usage: misdn set crypt debug <level>\n"
03815          "       Set the crypt debug level of the mISDN channel. Level\n"
03816          "       must be 1 or 2.\n";
03817       return NULL;
03818    case CLI_GENERATE:
03819       return NULL;
03820    }
03821 
03822    if (a->argc != 5) {
03823       return CLI_SHOWUSAGE;
03824    }
03825 
03826    /* XXX Is this supposed to not do anything? XXX */
03827 
03828    return CLI_SUCCESS;
03829 }
03830 
03831 static char *handle_cli_misdn_port_block(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03832 {
03833    switch (cmd) {
03834    case CLI_INIT:
03835       e->command = "misdn port block";
03836       e->usage =
03837          "Usage: misdn port block <port>\n"
03838          "       Block the specified port by <port>.\n";
03839       return NULL;
03840    case CLI_GENERATE:
03841       return NULL;
03842    }
03843 
03844    if (a->argc != 4) {
03845       return CLI_SHOWUSAGE;
03846    }
03847 
03848    misdn_lib_port_block(atoi(a->argv[3]));
03849 
03850    return CLI_SUCCESS;
03851 }
03852 
03853 static char *handle_cli_misdn_port_unblock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03854 {
03855    switch (cmd) {
03856    case CLI_INIT:
03857       e->command = "misdn port unblock";
03858       e->usage =
03859          "Usage: misdn port unblock <port>\n"
03860          "       Unblock the port specified by <port>.\n";
03861       return NULL;
03862    case CLI_GENERATE:
03863       return NULL;
03864    }
03865 
03866    if (a->argc != 4) {
03867       return CLI_SHOWUSAGE;
03868    }
03869 
03870    misdn_lib_port_unblock(atoi(a->argv[3]));
03871 
03872    return CLI_SUCCESS;
03873 }
03874 
03875 static char *handle_cli_misdn_restart_port(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03876 {
03877    switch (cmd) {
03878    case CLI_INIT:
03879       e->command = "misdn restart port";
03880       e->usage =
03881          "Usage: misdn restart port <port>\n"
03882          "       Restart the given port.\n";
03883       return NULL;
03884    case CLI_GENERATE:
03885       return NULL;
03886    }
03887 
03888    if (a->argc != 4) {
03889       return CLI_SHOWUSAGE;
03890    }
03891 
03892    misdn_lib_port_restart(atoi(a->argv[3]));
03893 
03894    return CLI_SUCCESS;
03895 }
03896 
03897 static char *handle_cli_misdn_restart_pid(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03898 {
03899    switch (cmd) {
03900    case CLI_INIT:
03901       e->command = "misdn restart pid";
03902       e->usage =
03903          "Usage: misdn restart pid <pid>\n"
03904          "       Restart the given pid\n";
03905       return NULL;
03906    case CLI_GENERATE:
03907       return NULL;
03908    }
03909 
03910    if (a->argc != 4) {
03911       return CLI_SHOWUSAGE;
03912    }
03913 
03914    misdn_lib_pid_restart(atoi(a->argv[3]));
03915 
03916    return CLI_SUCCESS;
03917 }
03918 
03919 static char *handle_cli_misdn_port_up(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03920 {
03921    switch (cmd) {
03922    case CLI_INIT:
03923       e->command = "misdn port up";
03924       e->usage =
03925          "Usage: misdn port up <port>\n"
03926          "       Try to establish L1 on the given port.\n";
03927       return NULL;
03928    case CLI_GENERATE:
03929       return NULL;
03930    }
03931 
03932    if (a->argc != 4) {
03933       return CLI_SHOWUSAGE;
03934    }
03935 
03936    misdn_lib_get_port_up(atoi(a->argv[3]));
03937 
03938    return CLI_SUCCESS;
03939 }
03940 
03941 static char *handle_cli_misdn_port_down(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03942 {
03943    switch (cmd) {
03944    case CLI_INIT:
03945       e->command = "misdn port down";
03946       e->usage =
03947          "Usage: misdn port down <port>\n"
03948          "       Try to deactivate the L1 on the given port.\n";
03949       return NULL;
03950    case CLI_GENERATE:
03951       return NULL;
03952    }
03953 
03954    if (a->argc != 4) {
03955       return CLI_SHOWUSAGE;
03956    }
03957 
03958    misdn_lib_get_port_down(atoi(a->argv[3]));
03959 
03960    return CLI_SUCCESS;
03961 }
03962 
03963 static inline void show_config_description(int fd, enum misdn_cfg_elements elem)
03964 {
03965    char section[BUFFERSIZE];
03966    char name[BUFFERSIZE];
03967    char desc[BUFFERSIZE];
03968    char def[BUFFERSIZE];
03969    char tmp[BUFFERSIZE];
03970 
03971    misdn_cfg_get_name(elem, tmp, sizeof(tmp));
03972    term_color(name, tmp, COLOR_BRWHITE, 0, sizeof(tmp));
03973    misdn_cfg_get_desc(elem, desc, sizeof(desc), def, sizeof(def));
03974 
03975    if (elem < MISDN_CFG_LAST) {
03976       term_color(section, "PORTS SECTION", COLOR_YELLOW, 0, sizeof(section));
03977    } else {
03978       term_color(section, "GENERAL SECTION", COLOR_YELLOW, 0, sizeof(section));
03979    }
03980 
03981    if (*def) {
03982       ast_cli(fd, "[%s] %s   (Default: %s)\n\t%s\n", section, name, def, desc);
03983    } else {
03984       ast_cli(fd, "[%s] %s\n\t%s\n", section, name, desc);
03985    }
03986 }
03987 
03988 static char *handle_cli_misdn_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
03989 {
03990    char buffer[BUFFERSIZE];
03991    enum misdn_cfg_elements elem;
03992    int linebreak;
03993    int onlyport = -1;
03994    int ok = 0;
03995 
03996    switch (cmd) {
03997    case CLI_INIT:
03998       e->command = "misdn show config";
03999       e->usage =
04000          "Usage: misdn show config [<port> | description <config element> | descriptions [general|ports]]\n"
04001          "       Use 0 for <port> to only print the general config.\n";
04002       return NULL;
04003    case CLI_GENERATE:
04004       return complete_show_config(a);
04005    }
04006 
04007    if (a->argc >= 4) {
04008       if (!strcmp(a->argv[3], "description")) {
04009          if (a->argc == 5) {
04010             enum misdn_cfg_elements elem = misdn_cfg_get_elem(a->argv[4]);
04011             if (elem == MISDN_CFG_FIRST) {
04012                ast_cli(a->fd, "Unknown element: %s\n", a->argv[4]);
04013             } else {
04014                show_config_description(a->fd, elem);
04015             }
04016             return CLI_SUCCESS;
04017          }
04018          return CLI_SHOWUSAGE;
04019       } else if (!strcmp(a->argv[3], "descriptions")) {
04020          if ((a->argc == 4) || ((a->argc == 5) && !strcmp(a->argv[4], "general"))) {
04021             for (elem = MISDN_GEN_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) {
04022                show_config_description(a->fd, elem);
04023                ast_cli(a->fd, "\n");
04024             }
04025             ok = 1;
04026          }
04027          if ((a->argc == 4) || ((a->argc == 5) && !strcmp(a->argv[4], "ports"))) {
04028             for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_CFG_LAST - 1 /* the ptp hack, remove the -1 when ptp is gone */; ++elem) {
04029                show_config_description(a->fd, elem);
04030                ast_cli(a->fd, "\n");
04031             }
04032             ok = 1;
04033          }
04034          return ok ? CLI_SUCCESS : CLI_SHOWUSAGE;
04035       } else if (!sscanf(a->argv[3], "%5d", &onlyport) || onlyport < 0) {
04036          ast_cli(a->fd, "Unknown option: %s\n", a->argv[3]);
04037          return CLI_SHOWUSAGE;
04038       }
04039    }
04040 
04041    if (a->argc == 3 || onlyport == 0) {
04042       ast_cli(a->fd, "mISDN General-Config:\n");
04043       for (elem = MISDN_GEN_FIRST + 1, linebreak = 1; elem < MISDN_GEN_LAST; elem++, linebreak++) {
04044          misdn_cfg_get_config_string(0, elem, buffer, sizeof(buffer));
04045          ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
04046       }
04047       ast_cli(a->fd, "\n");
04048    }
04049 
04050    if (onlyport < 0) {
04051       int port = misdn_cfg_get_next_port(0);
04052 
04053       for (; port > 0; port = misdn_cfg_get_next_port(port)) {
04054          ast_cli(a->fd, "\n[PORT %d]\n", port);
04055          for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
04056             misdn_cfg_get_config_string(port, elem, buffer, sizeof(buffer));
04057             ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
04058          }
04059          ast_cli(a->fd, "\n");
04060       }
04061    }
04062 
04063    if (onlyport > 0) {
04064       if (misdn_cfg_is_port_valid(onlyport)) {
04065          ast_cli(a->fd, "[PORT %d]\n", onlyport);
04066          for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
04067             misdn_cfg_get_config_string(onlyport, elem, buffer, sizeof(buffer));
04068             ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
04069          }
04070          ast_cli(a->fd, "\n");
04071       } else {
04072          ast_cli(a->fd, "Port %d is not active!\n", onlyport);
04073       }
04074    }
04075 
04076    return CLI_SUCCESS;
04077 }
04078 
04079 struct state_struct {
04080    enum misdn_chan_state state;
04081    char txt[255];
04082 };
04083 
04084 static const struct state_struct state_array[] = {
04085 /* *INDENT-OFF* */
04086    { MISDN_NOTHING,             "NOTHING" },             /* at beginning */
04087    { MISDN_WAITING4DIGS,        "WAITING4DIGS" },        /* when waiting for infos */
04088    { MISDN_EXTCANTMATCH,        "EXTCANTMATCH" },        /* when asterisk couldn't match our ext */
04089    { MISDN_INCOMING_SETUP,      "INCOMING SETUP" },      /* when pbx_start */
04090    { MISDN_DIALING,             "DIALING" },             /* when pbx_start */
04091    { MISDN_PROGRESS,            "PROGRESS" },            /* when pbx_start */
04092    { MISDN_PROCEEDING,          "PROCEEDING" },          /* when pbx_start */
04093    { MISDN_CALLING,             "CALLING" },             /* when misdn_call is called */
04094    { MISDN_CALLING_ACKNOWLEDGE, "CALLING_ACKNOWLEDGE" }, /* when misdn_call is called */
04095    { MISDN_ALERTING,            "ALERTING" },            /* when Alerting */
04096    { MISDN_BUSY,                "BUSY" },                /* when BUSY */
04097    { MISDN_CONNECTED,           "CONNECTED" },           /* when connected */
04098    { MISDN_DISCONNECTED,        "DISCONNECTED" },        /* when connected */
04099    { MISDN_CLEANING,            "CLEANING" },            /* when hangup from * but we were connected before */
04100 /* *INDENT-ON* */
04101 };
04102 
04103 static const char *misdn_get_ch_state(struct chan_list *p)
04104 {
04105    int i;
04106    static char state[8];
04107 
04108    if (!p) {
04109       return NULL;
04110    }
04111 
04112    for (i = 0; i < ARRAY_LEN(state_array); i++) {
04113       if (state_array[i].state == p->state) {
04114          return state_array[i].txt;
04115       }
04116    }
04117 
04118    snprintf(state, sizeof(state), "%d", p->state) ;
04119 
04120    return state;
04121 }
04122 
04123 
04124 static void reload_config(void)
04125 {
04126    int i, cfg_debug;
04127 
04128    if (!g_config_initialized) {
04129       ast_log(LOG_WARNING, "chan_misdn is not initialized properly, still reloading ?\n");
04130       return ;
04131    }
04132 
04133    free_robin_list();
04134    misdn_cfg_reload();
04135    misdn_cfg_update_ptp();
04136    misdn_cfg_get(0, MISDN_GEN_TRACEFILE, global_tracefile, sizeof(global_tracefile));
04137    misdn_cfg_get(0, MISDN_GEN_DEBUG, &cfg_debug, sizeof(cfg_debug));
04138 
04139    for (i = 0;  i <= max_ports; i++) {
04140       misdn_debug[i] = cfg_debug;
04141       misdn_debug_only[i] = 0;
04142    }
04143 }
04144 
04145 static char *handle_cli_misdn_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04146 {
04147    switch (cmd) {
04148    case CLI_INIT:
04149       e->command = "misdn reload";
04150       e->usage =
04151          "Usage: misdn reload\n"
04152          "       Reload internal mISDN config, read from the config\n"
04153          "       file.\n";
04154       return NULL;
04155    case CLI_GENERATE:
04156       return NULL;
04157    }
04158 
04159    if (a->argc != 2) {
04160       return CLI_SHOWUSAGE;
04161    }
04162 
04163    ast_cli(a->fd, "Reloading mISDN configuration\n");
04164    reload_config();
04165    return CLI_SUCCESS;
04166 }
04167 
04168 static void print_bc_info(int fd, struct chan_list *help, struct misdn_bchannel *bc)
04169 {
04170    struct ast_channel *ast = help->ast;
04171 
04172    ast_cli(fd,
04173       "* Pid:%d Port:%d Ch:%d Mode:%s Orig:%s dialed:%s\n"
04174       "  --> caller:\"%s\" <%s>\n"
04175       "  --> redirecting-from:\"%s\" <%s>\n"
04176       "  --> redirecting-to:\"%s\" <%s>\n"
04177       "  --> context:%s state:%s\n",
04178       bc->pid,
04179       bc->port,
04180       bc->channel,
04181       bc->nt ? "NT" : "TE",
04182       help->originator == ORG_AST ? "*" : "I",
04183       ast ? ast_channel_exten(ast) : "",
04184       (ast && ast_channel_caller(ast)->id.name.valid && ast_channel_caller(ast)->id.name.str)
04185          ? ast_channel_caller(ast)->id.name.str : "",
04186       (ast && ast_channel_caller(ast)->id.number.valid && ast_channel_caller(ast)->id.number.str)
04187          ? ast_channel_caller(ast)->id.number.str : "",
04188       bc->redirecting.from.name,
04189       bc->redirecting.from.number,
04190       bc->redirecting.to.name,
04191       bc->redirecting.to.number,
04192       ast ? ast_channel_context(ast) : "",
04193       misdn_get_ch_state(help));
04194    if (misdn_debug[bc->port] > 0) {
04195       ast_cli(fd,
04196          "  --> astname: %s\n"
04197          "  --> ch_l3id: %x\n"
04198          "  --> ch_addr: %x\n"
04199          "  --> bc_addr: %x\n"
04200          "  --> bc_l3id: %x\n"
04201          "  --> display: %s\n"
04202          "  --> activated: %d\n"
04203          "  --> state: %s\n"
04204          "  --> capability: %s\n"
04205 #ifdef MISDN_1_2
04206          "  --> pipeline: %s\n"
04207 #else
04208          "  --> echo_cancel: %d\n"
04209 #endif
04210          "  --> notone : rx %d tx:%d\n"
04211          "  --> bc_hold: %d\n",
04212          ast ? ast_channel_name(ast) : "",
04213          help->l3id,
04214          help->addr,
04215          bc->addr,
04216          bc->l3_id,
04217          bc->display,
04218          bc->active,
04219          bc_state2str(bc->bc_state),
04220          bearer2str(bc->capability),
04221 #ifdef MISDN_1_2
04222          bc->pipeline,
04223 #else
04224          bc->ec_enable,
04225 #endif
04226          help->norxtone, help->notxtone,
04227          bc->holded);
04228    }
04229 }
04230 
04231 static char *handle_cli_misdn_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04232 {
04233    struct chan_list *help;
04234 
04235    switch (cmd) {
04236    case CLI_INIT:
04237       e->command = "misdn show channels";
04238       e->usage =
04239          "Usage: misdn show channels\n"
04240          "       Show the internal mISDN channel list\n";
04241       return NULL;
04242    case CLI_GENERATE:
04243       return NULL;
04244    }
04245 
04246    if (a->argc != 3) {
04247       return CLI_SHOWUSAGE;
04248    }
04249 
04250    ast_cli(a->fd, "Channel List: %p\n", cl_te);
04251 
04252    /*
04253     * Walking the list and dumping the channel information could
04254     * take awhile.  With the list locked for the duration, the
04255     * channel driver cannot process signaling messages.  However,
04256     * since this is a CLI command it should not be run very often.
04257     */
04258    ast_mutex_lock(&cl_te_lock);
04259    for (help = cl_te; help; help = help->next) {
04260       struct misdn_bchannel *bc = help->bc;
04261       struct ast_channel *ast = help->ast;
04262       if (!ast) {
04263          if (!bc) {
04264             ast_cli(a->fd, "chan_list obj. with l3id:%x has no bc and no ast Leg\n", help->l3id);
04265             continue;
04266          }
04267          ast_cli(a->fd, "bc with pid:%d has no Ast Leg\n", bc->pid);
04268       }
04269 
04270       if (misdn_debug[0] > 2) {
04271          ast_cli(a->fd, "Bc:%p Ast:%p\n", bc, ast);
04272       }
04273       if (bc) {
04274          print_bc_info(a->fd, help, bc);
04275       } else {
04276          if (help->hold.state != MISDN_HOLD_IDLE) {
04277             ast_cli(a->fd, "ITS A HELD CALL BC:\n");
04278             ast_cli(a->fd, " --> l3_id: %x\n"
04279                " --> dialed:%s\n"
04280                " --> caller:\"%s\" <%s>\n"
04281                " --> hold_port: %d\n"
04282                " --> hold_channel: %d\n",
04283                help->l3id,
04284                ast_channel_exten(ast),
04285                S_COR(ast_channel_caller(ast)->id.name.valid, ast_channel_caller(ast)->id.name.str, ""),
04286                S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, ""),
04287                help->hold.port,
04288                help->hold.channel
04289                );
04290          } else {
04291             ast_cli(a->fd, "* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n",
04292                ast_channel_exten(ast),
04293                S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, ""));
04294          }
04295       }
04296    }
04297    ast_mutex_unlock(&cl_te_lock);
04298 
04299    misdn_dump_chanlist();
04300 
04301    return CLI_SUCCESS;
04302 }
04303 
04304 static char *handle_cli_misdn_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04305 {
04306    struct chan_list *help;
04307 
04308    switch (cmd) {
04309    case CLI_INIT:
04310       e->command = "misdn show channel";
04311       e->usage =
04312          "Usage: misdn show channel <channel>\n"
04313          "       Show an internal mISDN channel\n.";
04314       return NULL;
04315    case CLI_GENERATE:
04316       return complete_ch(a);
04317    }
04318 
04319    if (a->argc != 4) {
04320       return CLI_SHOWUSAGE;
04321    }
04322 
04323    ast_mutex_lock(&cl_te_lock);
04324    for (help = cl_te; help; help = help->next) {
04325       struct misdn_bchannel *bc = help->bc;
04326       struct ast_channel *ast = help->ast;
04327 
04328       if (bc && ast) {
04329          if (!strcasecmp(ast_channel_name(ast), a->argv[3])) {
04330             print_bc_info(a->fd, help, bc);
04331             break;
04332          }
04333       }
04334    }
04335    ast_mutex_unlock(&cl_te_lock);
04336 
04337    return CLI_SUCCESS;
04338 }
04339 
04340 static char *handle_cli_misdn_set_tics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04341 {
04342    switch (cmd) {
04343    case CLI_INIT:
04344       e->command = "misdn set tics";
04345       e->usage =
04346          "Usage: misdn set tics <value>\n";
04347       return NULL;
04348    case CLI_GENERATE:
04349       return NULL;
04350    }
04351 
04352    if (a->argc != 4) {
04353       return CLI_SHOWUSAGE;
04354    }
04355 
04356    /* XXX Wow, this does... a whole lot of nothing... XXX */
04357    MAXTICS = atoi(a->argv[3]);
04358 
04359    return CLI_SUCCESS;
04360 }
04361 
04362 static char *handle_cli_misdn_show_stacks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04363 {
04364    int port;
04365 
04366    switch (cmd) {
04367    case CLI_INIT:
04368       e->command = "misdn show stacks";
04369       e->usage =
04370          "Usage: misdn show stacks\n"
04371          "       Show internal mISDN stack_list.\n";
04372       return NULL;
04373    case CLI_GENERATE:
04374       return NULL;
04375    }
04376 
04377    if (a->argc != 3) {
04378       return CLI_SHOWUSAGE;
04379    }
04380 
04381    ast_cli(a->fd, "BEGIN STACK_LIST:\n");
04382    for (port = misdn_cfg_get_next_port(0); port > 0;
04383       port = misdn_cfg_get_next_port(port)) {
04384       char buf[128];
04385 
04386       get_show_stack_details(port, buf);
04387       ast_cli(a->fd, "  %s  Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
04388    }
04389 
04390    return CLI_SUCCESS;
04391 }
04392 
04393 static char *handle_cli_misdn_show_ports_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04394 {
04395    int port;
04396 
04397    switch (cmd) {
04398    case CLI_INIT:
04399       e->command = "misdn show ports stats";
04400       e->usage =
04401          "Usage: misdn show ports stats\n"
04402          "       Show mISDNs channel's call statistics per port.\n";
04403       return NULL;
04404    case CLI_GENERATE:
04405       return NULL;
04406    }
04407 
04408    if (a->argc != 4) {
04409       return CLI_SHOWUSAGE;
04410    }
04411 
04412    ast_cli(a->fd, "Port\tin_calls\tout_calls\n");
04413    for (port = misdn_cfg_get_next_port(0); port > 0;
04414       port = misdn_cfg_get_next_port(port)) {
04415       ast_cli(a->fd, "%d\t%d\t\t%d\n", port, misdn_in_calls[port], misdn_out_calls[port]);
04416    }
04417    ast_cli(a->fd, "\n");
04418 
04419    return CLI_SUCCESS;
04420 }
04421 
04422 static char *handle_cli_misdn_show_port(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
04423 {
04424    int port;
04425    char buf[128];
04426 
04427    switch (cmd) {
04428    case CLI_INIT:
04429       e->command = "misdn show port";
04430       e->usage =
04431          "Usage: misdn show port <port>\n"
04432          "       Show detailed information for given port.\n";
04433       return NULL;
04434    case CLI_GENERATE:
04435       return NULL;
04436    }
04437 
04438    if (a->argc != 4) {
04439       return CLI_SHOWUSAGE;
04440    }
04441 
04442    port = atoi(a->argv[3]);
04443 
04444    ast_cli(a->fd, "BEGIN STACK_LIST:\n");
04445    get_show_stack_details(port, buf);
04446    ast_cli(a->fd, "  %s  Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
04447 
04448    return CLI_SUCCESS;
04449 }
04450 
04451 #if defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES)
04452 static const struct FacParm Fac_Msgs[] = {
04453 /* *INDENT-OFF* */
04454    [0].Function = Fac_ERROR,
04455    [0].u.ERROR.invokeId = 8,
04456    [0].u.ERROR.errorValue = FacError_CCBS_AlreadyAccepted,
04457 
04458    [1].Function = Fac_RESULT,
04459    [1].u.RESULT.InvokeID = 9,
04460 
04461    [2].Function = Fac_REJECT,
04462    [2].u.REJECT.Code = FacReject_Gen_BadlyStructuredComponent,
04463 
04464    [3].Function = Fac_REJECT,
04465    [3].u.REJECT.InvokeIDPresent = 1,
04466    [3].u.REJECT.InvokeID = 10,
04467    [3].u.REJECT.Code = FacReject_Inv_InitiatorReleasing,
04468 
04469    [4].Function = Fac_REJECT,
04470    [4].u.REJECT.InvokeIDPresent = 1,
04471    [4].u.REJECT.InvokeID = 11,
04472    [4].u.REJECT.Code = FacReject_Res_MistypedResult,
04473 
04474    [5].Function = Fac_REJECT,
04475    [5].u.REJECT.InvokeIDPresent = 1,
04476    [5].u.REJECT.InvokeID = 12,
04477    [5].u.REJECT.Code = FacReject_Err_ErrorResponseUnexpected,
04478 
04479    [6].Function = Fac_StatusRequest,
04480    [6].u.StatusRequest.InvokeID = 13,
04481    [6].u.StatusRequest.ComponentType = FacComponent_Invoke,
04482    [6].u.StatusRequest.Component.Invoke.Q931ie.Bc.Length = 2,
04483    [6].u.StatusRequest.Component.Invoke.Q931ie.Bc.Contents = "AB",
04484    [6].u.StatusRequest.Component.Invoke.Q931ie.Llc.Length = 3,
04485    [6].u.StatusRequest.Component.Invoke.Q931ie.Llc.Contents = "CDE",
04486    [6].u.StatusRequest.Component.Invoke.Q931ie.Hlc.Length = 4,
04487    [6].u.StatusRequest.Component.Invoke.Q931ie.Hlc.Contents = "FGHI",
04488    [6].u.StatusRequest.Component.Invoke.CompatibilityMode = 1,
04489 
04490    [7].Function = Fac_StatusRequest,
04491    [7].u.StatusRequest.InvokeID = 14,
04492    [7].u.StatusRequest.ComponentType = FacComponent_Result,
04493    [7].u.StatusRequest.Component.Result.Status = 2,
04494 
04495    [8].Function = Fac_CallInfoRetain,
04496    [8].u.CallInfoRetain.InvokeID = 15,
04497    [8].u.CallInfoRetain.CallLinkageID = 115,
04498 
04499    [9].Function = Fac_EraseCallLinkageID,
04500    [9].u.EraseCallLinkageID.InvokeID = 16,
04501    [9].u.EraseCallLinkageID.CallLinkageID = 105,
04502 
04503    [10].Function = Fac_CCBSDeactivate,
04504    [10].u.CCBSDeactivate.InvokeID = 17,
04505    [10].u.CCBSDeactivate.ComponentType = FacComponent_Invoke,
04506    [10].u.CCBSDeactivate.Component.Invoke.CCBSReference = 2,
04507 
04508    [11].Function = Fac_CCBSDeactivate,
04509    [11].u.CCBSDeactivate.InvokeID = 18,
04510    [11].u.CCBSDeactivate.ComponentType = FacComponent_Result,
04511 
04512    [12].Function = Fac_CCBSErase,
04513    [12].u.CCBSErase.InvokeID = 19,
04514    [12].u.CCBSErase.Q931ie.Bc.Length = 2,
04515    [12].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04516    [12].u.CCBSErase.AddressOfB.Party.Type = 0,
04517    [12].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 5,
04518    [12].u.CCBSErase.AddressOfB.Party.Number = "33403",
04519    [12].u.CCBSErase.AddressOfB.Subaddress.Type = 0,
04520    [12].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
04521    [12].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.Information = "3748",
04522    [12].u.CCBSErase.RecallMode = 1,
04523    [12].u.CCBSErase.CCBSReference = 102,
04524    [12].u.CCBSErase.Reason = 3,
04525 
04526    [13].Function = Fac_CCBSErase,
04527    [13].u.CCBSErase.InvokeID = 20,
04528    [13].u.CCBSErase.Q931ie.Bc.Length = 2,
04529    [13].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04530    [13].u.CCBSErase.AddressOfB.Party.Type = 1,
04531    [13].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 11,
04532    [13].u.CCBSErase.AddressOfB.Party.TypeOfNumber = 1,
04533    [13].u.CCBSErase.AddressOfB.Party.Number = "18003020102",
04534    [13].u.CCBSErase.AddressOfB.Subaddress.Type = 0,
04535    [13].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
04536    [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.OddCountPresent = 1,
04537    [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.OddCount = 1,
04538    [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.Information = "3748",
04539    [13].u.CCBSErase.RecallMode = 1,
04540    [13].u.CCBSErase.CCBSReference = 102,
04541    [13].u.CCBSErase.Reason = 3,
04542 
04543    [14].Function = Fac_CCBSErase,
04544    [14].u.CCBSErase.InvokeID = 21,
04545    [14].u.CCBSErase.Q931ie.Bc.Length = 2,
04546    [14].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04547    [14].u.CCBSErase.AddressOfB.Party.Type = 2,
04548    [14].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
04549    [14].u.CCBSErase.AddressOfB.Party.Number = "1803",
04550    [14].u.CCBSErase.AddressOfB.Subaddress.Type = 1,
04551    [14].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
04552    [14].u.CCBSErase.AddressOfB.Subaddress.u.Nsap = "6492",
04553    [14].u.CCBSErase.RecallMode = 1,
04554    [14].u.CCBSErase.CCBSReference = 102,
04555    [14].u.CCBSErase.Reason = 3,
04556 
04557    [15].Function = Fac_CCBSErase,
04558    [15].u.CCBSErase.InvokeID = 22,
04559    [15].u.CCBSErase.Q931ie.Bc.Length = 2,
04560    [15].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04561    [15].u.CCBSErase.AddressOfB.Party.Type = 3,
04562    [15].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
04563    [15].u.CCBSErase.AddressOfB.Party.Number = "1803",
04564    [15].u.CCBSErase.RecallMode = 1,
04565    [15].u.CCBSErase.CCBSReference = 102,
04566    [15].u.CCBSErase.Reason = 3,
04567 
04568    [16].Function = Fac_CCBSErase,
04569    [16].u.CCBSErase.InvokeID = 23,
04570    [16].u.CCBSErase.Q931ie.Bc.Length = 2,
04571    [16].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04572    [16].u.CCBSErase.AddressOfB.Party.Type = 4,
04573    [16].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
04574    [16].u.CCBSErase.AddressOfB.Party.Number = "1803",
04575    [16].u.CCBSErase.RecallMode = 1,
04576    [16].u.CCBSErase.CCBSReference = 102,
04577    [16].u.CCBSErase.Reason = 3,
04578 
04579    [17].Function = Fac_CCBSErase,
04580    [17].u.CCBSErase.InvokeID = 24,
04581    [17].u.CCBSErase.Q931ie.Bc.Length = 2,
04582    [17].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04583    [17].u.CCBSErase.AddressOfB.Party.Type = 5,
04584    [17].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 11,
04585    [17].u.CCBSErase.AddressOfB.Party.TypeOfNumber = 4,
04586    [17].u.CCBSErase.AddressOfB.Party.Number = "18003020102",
04587    [17].u.CCBSErase.RecallMode = 1,
04588    [17].u.CCBSErase.CCBSReference = 102,
04589    [17].u.CCBSErase.Reason = 3,
04590 
04591    [18].Function = Fac_CCBSErase,
04592    [18].u.CCBSErase.InvokeID = 25,
04593    [18].u.CCBSErase.Q931ie.Bc.Length = 2,
04594    [18].u.CCBSErase.Q931ie.Bc.Contents = "JK",
04595    [18].u.CCBSErase.AddressOfB.Party.Type = 8,
04596    [18].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
04597    [18].u.CCBSErase.AddressOfB.Party.Number = "1803",
04598    [18].u.CCBSErase.RecallMode = 1,
04599    [18].u.CCBSErase.CCBSReference = 102,
04600    [18].u.CCBSErase.Reason = 3,
04601 
04602    [19].Function = Fac_CCBSRemoteUserFree,
04603    [19].u.CCBSRemoteUserFree.InvokeID = 26,
04604    [19].u.CCBSRemoteUserFree.Q931ie.Bc.Length = 2,
04605    [19].u.CCBSRemoteUserFree.Q931ie.Bc.Contents = "JK",
04606    [19].u.CCBSRemoteUserFree.AddressOfB.Party.Type = 8,
04607    [19].u.CCBSRemoteUserFree.AddressOfB.Party.LengthOfNumber = 4,
04608    [19].u.CCBSRemoteUserFree.AddressOfB.Party.Number = "1803",
04609    [19].u.CCBSRemoteUserFree.RecallMode = 1,
04610    [19].u.CCBSRemoteUserFree.CCBSReference = 102,
04611 
04612    [20].Function = Fac_CCBSCall,
04613    [20].u.CCBSCall.InvokeID = 27,
04614    [20].u.CCBSCall.CCBSReference = 115,
04615 
04616    [21].Function = Fac_CCBSStatusRequest,
04617    [21].u.CCBSStatusRequest.InvokeID = 28,
04618    [21].u.CCBSStatusRequest.ComponentType = FacComponent_Invoke,
04619    [21].u.CCBSStatusRequest.Component.Invoke.Q931ie.Bc.Length = 2,
04620    [21].u.CCBSStatusRequest.Component.Invoke.Q931ie.Bc.Contents = "JK",
04621    [21].u.CCBSStatusRequest.Component.Invoke.RecallMode = 1,
04622    [21].u.CCBSStatusRequest.Component.Invoke.CCBSReference = 102,
04623 
04624    [22].Function = Fac_CCBSStatusRequest,
04625    [22].u.CCBSStatusRequest.InvokeID = 29,
04626    [22].u.CCBSStatusRequest.ComponentType = FacComponent_Result,
04627    [22].u.CCBSStatusRequest.Component.Result.Free = 1,
04628 
04629    [23].Function = Fac_CCBSBFree,
04630    [23].u.CCBSBFree.InvokeID = 30,
04631    [23].u.CCBSBFree.Q931ie.Bc.Length = 2,
04632    [23].u.CCBSBFree.Q931ie.Bc.Contents = "JK",
04633    [23].u.CCBSBFree.AddressOfB.Party.Type = 8,
04634    [23].u.CCBSBFree.AddressOfB.Party.LengthOfNumber = 4,
04635    [23].u.CCBSBFree.AddressOfB.Party.Number = "1803",
04636    [23].u.CCBSBFree.RecallMode = 1,
04637    [23].u.CCBSBFree.CCBSReference = 14,
04638 
04639    [24].Function = Fac_CCBSStopAlerting,
04640    [24].u.CCBSStopAlerting.InvokeID = 31,
04641    [24].u.CCBSStopAlerting.CCBSReference = 37,
04642 
04643    [25].Function = Fac_CCBSRequest,
04644    [25].u.CCBSRequest.InvokeID = 32,
04645    [25].u.CCBSRequest.ComponentType = FacComponent_Invoke,
04646    [25].u.CCBSRequest.Component.Invoke.CallLinkageID = 57,
04647 
04648    [26].Function = Fac_CCBSRequest,
04649    [26].u.CCBSRequest.InvokeID = 33,
04650    [26].u.CCBSRequest.ComponentType = FacComponent_Result,
04651    [26].u.CCBSRequest.Component.Result.RecallMode = 1,
04652    [26].u.CCBSRequest.Component.Result.CCBSReference = 102,
04653 
04654    [27].Function = Fac_CCBSInterrogate,
04655    [27].u.CCBSInterrogate.InvokeID = 34,
04656    [27].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
04657    [27].u.CCBSInterrogate.Component.Invoke.AParty.Type = 8,
04658    [27].u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber = 4,
04659    [27].u.CCBSInterrogate.Component.Invoke.AParty.Number = "1803",
04660    [27].u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent = 1,
04661    [27].u.CCBSInterrogate.Component.Invoke.CCBSReference = 76,
04662 
04663    [28].Function = Fac_CCBSInterrogate,
04664    [28].u.CCBSInterrogate.InvokeID = 35,
04665    [28].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
04666    [28].u.CCBSInterrogate.Component.Invoke.AParty.Type = 8,
04667    [28].u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber = 4,
04668    [28].u.CCBSInterrogate.Component.Invoke.AParty.Number = "1803",
04669 
04670    [29].Function = Fac_CCBSInterrogate,
04671    [29].u.CCBSInterrogate.InvokeID = 36,
04672    [29].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
04673    [29].u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent = 1,
04674    [29].u.CCBSInterrogate.Component.Invoke.CCBSReference = 76,
04675 
04676    [30].Function = Fac_CCBSInterrogate,
04677    [30].u.CCBSInterrogate.InvokeID = 37,
04678    [30].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
04679 
04680    [31].Function = Fac_CCBSInterrogate,
04681    [31].u.CCBSInterrogate.InvokeID = 38,
04682    [31].u.CCBSInterrogate.ComponentType = FacComponent_Result,
04683    [31].u.CCBSInterrogate.Component.Result.RecallMode = 1,
04684 
04685    [32].Function = Fac_CCBSInterrogate,
04686    [32].u.CCBSInterrogate.InvokeID = 39,
04687    [32].u.CCBSInterrogate.ComponentType = FacComponent_Result,
04688    [32].u.CCBSInterrogate.Component.Result.RecallMode = 1,
04689    [32].u.CCBSInterrogate.Component.Result.NumRecords = 1,
04690    [32].u.CCBSInterrogate.Component.Result.CallDetails[0].CCBSReference = 12,
04691    [32].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Length = 2,
04692    [32].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Contents = "JK",
04693    [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Type = 8,
04694    [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.LengthOfNumber = 4,
04695    [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Number = "1803",
04696    [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.Type = 1,
04697    [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.Length = 4,
04698    [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.u.Nsap = "6492",
04699 
04700    [33].Function = Fac_CCBSInterrogate,
04701    [33].u.CCBSInterrogate.InvokeID = 40,
04702    [33].u.CCBSInterrogate.ComponentType = FacComponent_Result,
04703    [33].u.CCBSInterrogate.Component.Result.RecallMode = 1,
04704    [33].u.CCBSInterrogate.Component.Result.NumRecords = 2,
04705    [33].u.CCBSInterrogate.Component.Result.CallDetails[0].CCBSReference = 12,
04706    [33].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Length = 2,
04707    [33].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Contents = "JK",
04708    [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Type = 8,
04709    [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.LengthOfNumber = 4,
04710    [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Number = "1803",
04711    [33].u.CCBSInterrogate.Component.Result.CallDetails[1].CCBSReference = 102,
04712    [33].u.CCBSInterrogate.Component.Result.CallDetails[1].Q931ie.Bc.Length = 2,
04713    [33].u.CCBSInterrogate.Component.Result.CallDetails[1].Q931ie.Bc.Contents = "LM",
04714    [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.Type = 8,
04715    [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.LengthOfNumber = 4,
04716    [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.Number = "6229",
04717    [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.Type = 1,
04718    [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.Length = 4,
04719    [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.u.Nsap = "8592",
04720    [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.Type = 1,
04721    [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.Length = 4,
04722    [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.u.Nsap = "6492",
04723 
04724    [34].Function = Fac_CCNRRequest,
04725    [34].u.CCNRRequest.InvokeID = 512,
04726    [34].u.CCNRRequest.ComponentType = FacComponent_Invoke,
04727    [34].u.CCNRRequest.Component.Invoke.CallLinkageID = 57,
04728 
04729    [35].Function = Fac_CCNRRequest,
04730    [35].u.CCNRRequest.InvokeID = 150,
04731    [35].u.CCNRRequest.ComponentType = FacComponent_Result,
04732    [35].u.CCNRRequest.Component.Result.RecallMode = 1,
04733    [35].u.CCNRRequest.Component.Result.CCBSReference = 102,
04734 
04735    [36].Function = Fac_CCNRInterrogate,
04736    [36].u.CCNRInterrogate.InvokeID = -129,
04737    [36].u.CCNRInterrogate.ComponentType = FacComponent_Invoke,
04738 
04739    [37].Function = Fac_CCNRInterrogate,
04740    [37].u.CCNRInterrogate.InvokeID = -3,
04741    [37].u.CCNRInterrogate.ComponentType = FacComponent_Result,
04742    [37].u.CCNRInterrogate.Component.Result.RecallMode = 1,
04743 
04744    [38].Function = Fac_CCBS_T_Call,
04745    [38].u.EctExecute.InvokeID = 41,
04746 
04747    [39].Function = Fac_CCBS_T_Suspend,
04748    [39].u.EctExecute.InvokeID = 42,
04749 
04750    [40].Function = Fac_CCBS_T_Resume,
04751    [40].u.EctExecute.InvokeID = 43,
04752 
04753    [41].Function = Fac_CCBS_T_RemoteUserFree,
04754    [41].u.EctExecute.InvokeID = 44,
04755 
04756    [42].Function = Fac_CCBS_T_Available,
04757    [42].u.EctExecute.InvokeID = 45,
04758 
04759    [43].Function = Fac_CCBS_T_Request,
04760    [43].u.CCBS_T_Request.InvokeID = 46,
04761    [43].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04762    [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04763    [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04764    [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04765    [43].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04766    [43].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04767    [43].u.CCBS_T_Request.Component.Invoke.RetentionSupported = 1,
04768    [43].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
04769    [43].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
04770    [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
04771    [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
04772    [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
04773 
04774    [44].Function = Fac_CCBS_T_Request,
04775    [44].u.CCBS_T_Request.InvokeID = 47,
04776    [44].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04777    [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04778    [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04779    [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04780    [44].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04781    [44].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04782    [44].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
04783    [44].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
04784    [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
04785    [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
04786    [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
04787 
04788    [45].Function = Fac_CCBS_T_Request,
04789    [45].u.CCBS_T_Request.InvokeID = 48,
04790    [45].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04791    [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04792    [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04793    [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04794    [45].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04795    [45].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04796    [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
04797    [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
04798    [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
04799 
04800    [46].Function = Fac_CCBS_T_Request,
04801    [46].u.CCBS_T_Request.InvokeID = 49,
04802    [46].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04803    [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04804    [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04805    [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04806    [46].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04807    [46].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04808    [46].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
04809    [46].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
04810 
04811    [47].Function = Fac_CCBS_T_Request,
04812    [47].u.CCBS_T_Request.InvokeID = 50,
04813    [47].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
04814    [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
04815    [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04816    [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04817    [47].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04818    [47].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04819 
04820    [48].Function = Fac_CCBS_T_Request,
04821    [48].u.CCBS_T_Request.InvokeID = 51,
04822    [48].u.CCBS_T_Request.ComponentType = FacComponent_Result,
04823    [48].u.CCBS_T_Request.Component.Result.RetentionSupported = 1,
04824 
04825    [49].Function = Fac_CCNR_T_Request,
04826    [49].u.CCNR_T_Request.InvokeID = 52,
04827    [49].u.CCNR_T_Request.ComponentType = FacComponent_Invoke,
04828    [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.Type = 8,
04829    [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
04830    [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.Number = "6229",
04831    [49].u.CCNR_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
04832    [49].u.CCNR_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
04833 
04834    [50].Function = Fac_CCNR_T_Request,
04835    [50].u.CCNR_T_Request.InvokeID = 53,
04836    [50].u.CCNR_T_Request.ComponentType = FacComponent_Result,
04837    [50].u.CCNR_T_Request.Component.Result.RetentionSupported = 1,
04838 
04839    [51].Function = Fac_EctExecute,
04840    [51].u.EctExecute.InvokeID = 54,
04841 
04842    [52].Function = Fac_ExplicitEctExecute,
04843    [52].u.ExplicitEctExecute.InvokeID = 55,
04844    [52].u.ExplicitEctExecute.LinkID = 23,
04845 
04846    [53].Function = Fac_RequestSubaddress,
04847    [53].u.RequestSubaddress.InvokeID = 56,
04848 
04849    [54].Function = Fac_SubaddressTransfer,
04850    [54].u.SubaddressTransfer.InvokeID = 57,
04851    [54].u.SubaddressTransfer.Subaddress.Type = 1,
04852    [54].u.SubaddressTransfer.Subaddress.Length = 4,
04853    [54].u.SubaddressTransfer.Subaddress.u.Nsap = "6492",
04854 
04855    [55].Function = Fac_EctLinkIdRequest,
04856    [55].u.EctLinkIdRequest.InvokeID = 58,
04857    [55].u.EctLinkIdRequest.ComponentType = FacComponent_Invoke,
04858 
04859    [56].Function = Fac_EctLinkIdRequest,
04860    [56].u.EctLinkIdRequest.InvokeID = 59,
04861    [56].u.EctLinkIdRequest.ComponentType = FacComponent_Result,
04862    [56].u.EctLinkIdRequest.Component.Result.LinkID = 76,
04863 
04864    [57].Function = Fac_EctInform,
04865    [57].u.EctInform.InvokeID = 60,
04866    [57].u.EctInform.Status = 1,
04867    [57].u.EctInform.RedirectionPresent = 1,
04868    [57].u.EctInform.Redirection.Type = 0,
04869    [57].u.EctInform.Redirection.Unscreened.Type = 8,
04870    [57].u.EctInform.Redirection.Unscreened.LengthOfNumber = 4,
04871    [57].u.EctInform.Redirection.Unscreened.Number = "6229",
04872 
04873    [58].Function = Fac_EctInform,
04874    [58].u.EctInform.InvokeID = 61,
04875    [58].u.EctInform.Status = 1,
04876    [58].u.EctInform.RedirectionPresent = 1,
04877    [58].u.EctInform.Redirection.Type = 1,
04878 
04879    [59].Function = Fac_EctInform,
04880    [59].u.EctInform.InvokeID = 62,
04881    [59].u.EctInform.Status = 1,
04882    [59].u.EctInform.RedirectionPresent = 1,
04883    [59].u.EctInform.Redirection.Type = 2,
04884 
04885    [60].Function = Fac_EctInform,
04886    [60].u.EctInform.InvokeID = 63,
04887    [60].u.EctInform.Status = 1,
04888    [60].u.EctInform.RedirectionPresent = 1,
04889    [60].u.EctInform.Redirection.Type = 3,
04890    [60].u.EctInform.Redirection.Unscreened.Type = 8,
04891    [60].u.EctInform.Redirection.Unscreened.LengthOfNumber = 4,
04892    [60].u.EctInform.Redirection.Unscreened.Number = "3340",
04893 
04894    [61].Function = Fac_EctInform,
04895    [61].u.EctInform.InvokeID = 64,
04896    [61].u.EctInform.Status = 1,
04897    [61].u.EctInform.RedirectionPresent = 0,
04898 
04899    [62].Function = Fac_EctLoopTest,
04900    [62].u.EctLoopTest.InvokeID = 65,
04901    [62].u.EctLoopTest.ComponentType = FacComponent_Invoke,
04902    [62].u.EctLoopTest.Component.Invoke.CallTransferID = 7,
04903 
04904    [63].Function = Fac_EctLoopTest,
04905    [63].u.EctLoopTest.InvokeID = 66,
04906    [63].u.EctLoopTest.ComponentType = FacComponent_Result,
04907    [63].u.EctLoopTest.Component.Result.LoopResult = 2,
04908 
04909    [64].Function = Fac_ActivationDiversion,
04910    [64].u.ActivationDiversion.InvokeID = 67,
04911    [64].u.ActivationDiversion.ComponentType = FacComponent_Invoke,
04912    [64].u.ActivationDiversion.Component.Invoke.Procedure = 2,
04913    [64].u.ActivationDiversion.Component.Invoke.BasicService = 3,
04914    [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 4,
04915    [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber = 4,
04916    [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number = "1803",
04917    [64].u.ActivationDiversion.Component.Invoke.ServedUser.Type = 4,
04918    [64].u.ActivationDiversion.Component.Invoke.ServedUser.LengthOfNumber = 4,
04919    [64].u.ActivationDiversion.Component.Invoke.ServedUser.Number = "5398",
04920 
04921    [65].Function = Fac_ActivationDiversion,
04922    [65].u.ActivationDiversion.InvokeID = 68,
04923    [65].u.ActivationDiversion.ComponentType = FacComponent_Invoke,
04924    [65].u.ActivationDiversion.Component.Invoke.Procedure = 1,
04925    [65].u.ActivationDiversion.Component.Invoke.BasicService = 5,
04926    [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 4,
04927    [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber = 4,
04928    [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number = "1803",
04929 
04930    [66].Function = Fac_ActivationDiversion,
04931    [66].u.ActivationDiversion.InvokeID = 69,
04932    [66].u.ActivationDiversion.ComponentType = FacComponent_Result,
04933 
04934    [67].Function = Fac_DeactivationDiversion,
04935    [67].u.DeactivationDiversion.InvokeID = 70,
04936    [67].u.DeactivationDiversion.ComponentType = FacComponent_Invoke,
04937    [67].u.DeactivationDiversion.Component.Invoke.Procedure = 1,
04938    [67].u.DeactivationDiversion.Component.Invoke.BasicService = 5,
04939 
04940    [68].Function = Fac_DeactivationDiversion,
04941    [68].u.DeactivationDiversion.InvokeID = 71,
04942    [68].u.DeactivationDiversion.ComponentType = FacComponent_Result,
04943 
04944    [69].Function = Fac_ActivationStatusNotificationDiv,
04945    [69].u.ActivationStatusNotificationDiv.InvokeID = 72,
04946    [69].u.ActivationStatusNotificationDiv.Procedure = 1,
04947    [69].u.ActivationStatusNotificationDiv.BasicService = 5,
04948    [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.Type = 4,
04949    [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.LengthOfNumber = 4,
04950    [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.Number = "1803",
04951 
04952    [70].Function = Fac_DeactivationStatusNotificationDiv,
04953    [70].u.DeactivationStatusNotificationDiv.InvokeID = 73,
04954    [70].u.DeactivationStatusNotificationDiv.Procedure = 1,
04955    [70].u.DeactivationStatusNotificationDiv.BasicService = 5,
04956 
04957    [71].Function = Fac_InterrogationDiversion,
04958    [71].u.InterrogationDiversion.InvokeID = 74,
04959    [71].u.InterrogationDiversion.ComponentType = FacComponent_Invoke,
04960    [71].u.InterrogationDiversion.Component.Invoke.Procedure = 1,
04961    [71].u.InterrogationDiversion.Component.Invoke.BasicService = 5,
04962 
04963    [72].Function = Fac_InterrogationDiversion,
04964    [72].u.InterrogationDiversion.InvokeID = 75,
04965    [72].u.InterrogationDiversion.ComponentType = FacComponent_Invoke,
04966    [72].u.InterrogationDiversion.Component.Invoke.Procedure = 1,
04967 
04968    [73].Function = Fac_InterrogationDiversion,
04969    [73].u.InterrogationDiversion.InvokeID = 76,
04970    [73].u.InterrogationDiversion.ComponentType = FacComponent_Result,
04971    [73].u.InterrogationDiversion.Component.Result.NumRecords = 2,
04972    [73].u.InterrogationDiversion.Component.Result.List[0].Procedure = 2,
04973    [73].u.InterrogationDiversion.Component.Result.List[0].BasicService = 5,
04974    [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.Type = 4,
04975    [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.LengthOfNumber = 4,
04976    [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.Number = "1803",
04977    [73].u.InterrogationDiversion.Component.Result.List[1].Procedure = 1,
04978    [73].u.InterrogationDiversion.Component.Result.List[1].BasicService = 3,
04979    [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.Type = 4,
04980    [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.LengthOfNumber = 4,
04981    [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.Number = "1903",
04982    [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.Type = 4,
04983    [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.LengthOfNumber = 4,
04984    [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.Number = "5398",
04985 
04986    [74].Function = Fac_DiversionInformation,
04987    [74].u.DiversionInformation.InvokeID = 77,
04988    [74].u.DiversionInformation.DiversionReason = 3,
04989    [74].u.DiversionInformation.BasicService = 5,
04990    [74].u.DiversionInformation.ServedUserSubaddress.Type = 1,
04991    [74].u.DiversionInformation.ServedUserSubaddress.Length = 4,
04992    [74].u.DiversionInformation.ServedUserSubaddress.u.Nsap = "6492",
04993    [74].u.DiversionInformation.CallingAddressPresent = 1,
04994    [74].u.DiversionInformation.CallingAddress.Type = 0,
04995    [74].u.DiversionInformation.CallingAddress.Address.ScreeningIndicator = 3,
04996    [74].u.DiversionInformation.CallingAddress.Address.Party.Type = 4,
04997    [74].u.DiversionInformation.CallingAddress.Address.Party.LengthOfNumber = 4,
04998    [74].u.DiversionInformation.CallingAddress.Address.Party.Number = "1803",
04999    [74].u.DiversionInformation.OriginalCalledPresent = 1,
05000    [74].u.DiversionInformation.OriginalCalled.Type = 1,
05001    [74].u.DiversionInformation.LastDivertingPresent = 1,
05002    [74].u.DiversionInformation.LastDiverting.Type = 2,
05003    [74].u.DiversionInformation.LastDivertingReasonPresent = 1,
05004    [74].u.DiversionInformation.LastDivertingReason = 3,
05005    [74].u.DiversionInformation.UserInfo.Length = 5,
05006    [74].u.DiversionInformation.UserInfo.Contents = "79828",
05007 
05008    [75].Function = Fac_DiversionInformation,
05009    [75].u.DiversionInformation.InvokeID = 78,
05010    [75].u.DiversionInformation.DiversionReason = 3,
05011    [75].u.DiversionInformation.BasicService = 5,
05012    [75].u.DiversionInformation.CallingAddressPresent = 1,
05013    [75].u.DiversionInformation.CallingAddress.Type = 1,
05014    [75].u.DiversionInformation.OriginalCalledPresent = 1,
05015    [75].u.DiversionInformation.OriginalCalled.Type = 2,
05016    [75].u.DiversionInformation.LastDivertingPresent = 1,
05017    [75].u.DiversionInformation.LastDiverting.Type = 1,
05018 
05019    [76].Function = Fac_DiversionInformation,
05020    [76].u.DiversionInformation.InvokeID = 79,
05021    [76].u.DiversionInformation.DiversionReason = 2,
05022    [76].u.DiversionInformation.BasicService = 3,
05023    [76].u.DiversionInformation.CallingAddressPresent = 1,
05024    [76].u.DiversionInformation.CallingAddress.Type = 2,
05025 
05026    [77].Function = Fac_DiversionInformation,
05027    [77].u.DiversionInformation.InvokeID = 80,
05028    [77].u.DiversionInformation.DiversionReason = 3,
05029    [77].u.DiversionInformation.BasicService = 5,
05030    [77].u.DiversionInformation.CallingAddressPresent = 1,
05031    [77].u.DiversionInformation.CallingAddress.Type = 3,
05032    [77].u.DiversionInformation.CallingAddress.Address.ScreeningIndicator = 2,
05033    [77].u.DiversionInformation.CallingAddress.Address.Party.Type = 4,
05034    [77].u.DiversionInformation.CallingAddress.Address.Party.LengthOfNumber = 4,
05035    [77].u.DiversionInformation.CallingAddress.Address.Party.Number = "1803",
05036 
05037    [78].Function = Fac_DiversionInformation,
05038    [78].u.DiversionInformation.InvokeID = 81,
05039    [78].u.DiversionInformation.DiversionReason = 2,
05040    [78].u.DiversionInformation.BasicService = 4,
05041    [78].u.DiversionInformation.UserInfo.Length = 5,
05042    [78].u.DiversionInformation.UserInfo.Contents = "79828",
05043 
05044    [79].Function = Fac_DiversionInformation,
05045    [79].u.DiversionInformation.InvokeID = 82,
05046    [79].u.DiversionInformation.DiversionReason = 2,
05047    [79].u.DiversionInformation.BasicService = 4,
05048 
05049    [80].Function = Fac_CallDeflection,
05050    [80].u.CallDeflection.InvokeID = 83,
05051    [80].u.CallDeflection.ComponentType = FacComponent_Invoke,
05052    [80].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
05053    [80].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
05054    [80].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
05055    [80].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1,
05056    [80].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 1,
05057 
05058    [81].Function = Fac_CallDeflection,
05059    [81].u.CallDeflection.InvokeID = 84,
05060    [81].u.CallDeflection.ComponentType = FacComponent_Invoke,
05061    [81].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
05062    [81].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
05063    [81].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
05064    [81].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1,
05065    [81].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0,
05066 
05067    [82].Function = Fac_CallDeflection,
05068    [82].u.CallDeflection.InvokeID = 85,
05069    [82].u.CallDeflection.ComponentType = FacComponent_Invoke,
05070    [82].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
05071    [82].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
05072    [82].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
05073 
05074    [83].Function = Fac_CallDeflection,
05075    [83].u.CallDeflection.InvokeID = 86,
05076    [83].u.CallDeflection.ComponentType = FacComponent_Result,
05077 
05078    [84].Function = Fac_CallRerouteing,
05079    [84].u.CallRerouteing.InvokeID = 87,
05080    [84].u.CallRerouteing.ComponentType = FacComponent_Invoke,
05081    [84].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
05082    [84].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
05083    [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
05084    [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
05085    [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
05086    [84].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
05087    [84].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
05088    [84].u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Length = 3,
05089    [84].u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Contents = "RTG",
05090    [84].u.CallRerouteing.Component.Invoke.Q931ie.Llc.Length = 2,
05091    [84].u.CallRerouteing.Component.Invoke.Q931ie.Llc.Contents = "MY",
05092    [84].u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Length = 5,
05093    [84].u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Contents = "YEHAW",
05094    [84].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1,
05095    [84].u.CallRerouteing.Component.Invoke.SubscriptionOption = 2,
05096    [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Type = 1,
05097    [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length = 4,
05098    [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.u.Nsap = "6492",
05099 
05100    [85].Function = Fac_CallRerouteing,
05101    [85].u.CallRerouteing.InvokeID = 88,
05102    [85].u.CallRerouteing.ComponentType = FacComponent_Invoke,
05103    [85].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
05104    [85].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
05105    [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
05106    [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
05107    [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
05108    [85].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
05109    [85].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
05110    [85].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1,
05111    [85].u.CallRerouteing.Component.Invoke.SubscriptionOption = 2,
05112 
05113    [86].Function = Fac_CallRerouteing,
05114    [86].u.CallRerouteing.InvokeID = 89,
05115    [86].u.CallRerouteing.ComponentType = FacComponent_Invoke,
05116    [86].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
05117    [86].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
05118    [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
05119    [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
05120    [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
05121    [86].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
05122    [86].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
05123    [86].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 2,
05124 
05125    [87].Function = Fac_CallRerouteing,
05126    [87].u.CallRerouteing.InvokeID = 90,
05127    [87].u.CallRerouteing.ComponentType = FacComponent_Result,
05128 
05129    [88].Function = Fac_InterrogateServedUserNumbers,
05130    [88].u.InterrogateServedUserNumbers.InvokeID = 91,
05131    [88].u.InterrogateServedUserNumbers.ComponentType = FacComponent_Invoke,
05132 
05133    [89].Function = Fac_InterrogateServedUserNumbers,
05134    [89].u.InterrogateServedUserNumbers.InvokeID = 92,
05135    [89].u.InterrogateServedUserNumbers.ComponentType = FacComponent_Result,
05136    [89].u.InterrogateServedUserNumbers.Component.Result.NumRecords = 2,
05137    [89].u.InterrogateServedUserNumbers.Component.Result.List[0].Type = 4,
05138    [89].u.InterrogateServedUserNumbers.Component.Result.List[0].LengthOfNumber = 4,
05139    [89].u.InterrogateServedUserNumbers.Component.Result.List[0].Number = "1803",
05140    [89].u.InterrogateServedUserNumbers.Component.Result.List[1].Type = 4,
05141    [89].u.InterrogateServedUserNumbers.Component.Result.List[1].LengthOfNumber = 4,
05142    [89].u.InterrogateServedUserNumbers.Component.Result.List[1].Number = "5786",
05143 
05144    [90].Function = Fac_DivertingLegInformation1,
05145    [90].u.DivertingLegInformation1.InvokeID = 93,
05146    [90].u.DivertingLegInformation1.DiversionReason = 4,
05147    [90].u.DivertingLegInformation1.SubscriptionOption = 1,
05148    [90].u.DivertingLegInformation1.DivertedToPresent = 1,
05149    [90].u.DivertingLegInformation1.DivertedTo.Type = 2,
05150 
05151    [91].Function = Fac_DivertingLegInformation1,
05152    [91].u.DivertingLegInformation1.InvokeID = 94,
05153    [91].u.DivertingLegInformation1.DiversionReason = 4,
05154    [91].u.DivertingLegInformation1.SubscriptionOption = 1,
05155 
05156    [92].Function = Fac_DivertingLegInformation2,
05157    [92].u.DivertingLegInformation2.InvokeID = 95,
05158    [92].u.DivertingLegInformation2.DiversionCounter = 3,
05159    [92].u.DivertingLegInformation2.DiversionReason = 2,
05160    [92].u.DivertingLegInformation2.DivertingPresent = 1,
05161    [92].u.DivertingLegInformation2.Diverting.Type = 2,
05162    [92].u.DivertingLegInformation2.OriginalCalledPresent = 1,
05163    [92].u.DivertingLegInformation2.OriginalCalled.Type = 1,
05164 
05165    [93].Function = Fac_DivertingLegInformation2,
05166    [93].u.DivertingLegInformation2.InvokeID = 96,
05167    [93].u.DivertingLegInformation2.DiversionCounter = 3,
05168    [93].u.DivertingLegInformation2.DiversionReason = 2,
05169    [93].u.DivertingLegInformation2.OriginalCalledPresent = 1,
05170    [93].u.DivertingLegInformation2.OriginalCalled.Type = 1,
05171 
05172    [94].Function = Fac_DivertingLegInformation2,
05173    [94].u.DivertingLegInformation2.InvokeID = 97,
05174    [94].u.DivertingLegInformation2.DiversionCounter = 1,
05175    [94].u.DivertingLegInformation2.DiversionReason = 2,
05176 
05177    [95].Function = Fac_DivertingLegInformation3,
05178    [95].u.DivertingLegInformation3.InvokeID = 98,
05179    [95].u.DivertingLegInformation3.PresentationAllowedIndicator = 1,
05180 /* *INDENT-ON* */
05181 };
05182 #endif   /* defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES) */
05183 
05184 static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05185 {
05186    const char *channame;
05187    const char *nr;
05188    struct chan_list *tmp;
05189    int port;
05190    const char *served_nr;
05191    struct misdn_bchannel dummy, *bc=&dummy;
05192    unsigned max_len;
05193 
05194    switch (cmd) {
05195    case CLI_INIT:
05196       e->command = "misdn send facility";
05197       e->usage = "Usage: misdn send facility <type> <channel|port> \"<args>\" \n"
05198       "\t type is one of:\n"
05199       "\t - calldeflect\n"
05200 #if defined(AST_MISDN_ENHANCEMENTS)
05201       "\t - callrerouting\n"
05202 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
05203       "\t - CFActivate\n"
05204       "\t - CFDeactivate\n";
05205 
05206       return NULL;
05207    case CLI_GENERATE:
05208       return complete_ch(a);
05209    }
05210 
05211    if (a->argc < 5) {
05212       return CLI_SHOWUSAGE;
05213    }
05214 
05215    if (strstr(a->argv[3], "calldeflect")) {
05216       if (a->argc < 6) {
05217          ast_verbose("calldeflect requires 1 arg: ToNumber\n\n");
05218          return 0;
05219       }
05220       channame = a->argv[4];
05221       nr = a->argv[5];
05222 
05223       ast_verbose("Sending Calldeflection (%s) to %s\n", nr, channame);
05224       tmp = get_chan_by_ast_name(channame);
05225       if (!tmp) {
05226          ast_verbose("Sending CD with nr %s to %s failed: Channel does not exist.\n", nr, channame);
05227          return 0;
05228       }
05229       ao2_lock(tmp);
05230 
05231 #if defined(AST_MISDN_ENHANCEMENTS)
05232       max_len = sizeof(tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number) - 1;
05233       if (max_len < strlen(nr)) {
05234          ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
05235             nr, channame, max_len);
05236          ao2_unlock(tmp);
05237          chan_list_unref(tmp, "Number too long");
05238          return 0;
05239       }
05240       tmp->bc->fac_out.Function = Fac_CallDeflection;
05241       tmp->bc->fac_out.u.CallDeflection.InvokeID = ++misdn_invoke_id;
05242       tmp->bc->fac_out.u.CallDeflection.ComponentType = FacComponent_Invoke;
05243       tmp->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1;
05244       tmp->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0;
05245       tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Type = 0;/* unknown */
05246       tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = strlen(nr);
05247       strcpy((char *) tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number, nr);
05248       tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Subaddress.Length = 0;
05249 
05250 #else /* !defined(AST_MISDN_ENHANCEMENTS) */
05251 
05252       max_len = sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber) - 1;
05253       if (max_len < strlen(nr)) {
05254          ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
05255             nr, channame, max_len);
05256          ao2_unlock(tmp);
05257          chan_list_unref(tmp, "Number too long");
05258          return 0;
05259       }
05260       tmp->bc->fac_out.Function = Fac_CD;
05261       tmp->bc->fac_out.u.CDeflection.PresentationAllowed = 0;
05262       //tmp->bc->fac_out.u.CDeflection.DeflectedToSubaddress[0] = 0;
05263       strcpy((char *) tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr);
05264 #endif   /* !defined(AST_MISDN_ENHANCEMENTS) */
05265 
05266       /* Send message */
05267       print_facility(&tmp->bc->fac_out, tmp->bc);
05268       ao2_unlock(tmp);
05269       misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
05270       chan_list_unref(tmp, "Send facility complete");
05271 #if defined(AST_MISDN_ENHANCEMENTS)
05272    } else if (strstr(a->argv[3], "callrerouteing") || strstr(a->argv[3], "callrerouting")) {
05273       if (a->argc < 6) {
05274          ast_verbose("callrerouting requires 1 arg: ToNumber\n\n");
05275          return 0;
05276       }
05277       channame = a->argv[4];
05278       nr = a->argv[5];
05279 
05280       ast_verbose("Sending Callrerouting (%s) to %s\n", nr, channame);
05281       tmp = get_chan_by_ast_name(channame);
05282       if (!tmp) {
05283          ast_verbose("Sending Call Rerouting with nr %s to %s failed: Channel does not exist.\n", nr, channame);
05284          return 0;
05285       }
05286       ao2_lock(tmp);
05287 
05288       max_len = sizeof(tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number) - 1;
05289       if (max_len < strlen(nr)) {
05290          ast_verbose("Sending Call Rerouting with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
05291             nr, channame, max_len);
05292          ao2_unlock(tmp);
05293          chan_list_unref(tmp, "Number too long");
05294          return 0;
05295       }
05296       tmp->bc->fac_out.Function = Fac_CallRerouteing;
05297       tmp->bc->fac_out.u.CallRerouteing.InvokeID = ++misdn_invoke_id;
05298       tmp->bc->fac_out.u.CallRerouteing.ComponentType = FacComponent_Invoke;
05299 
05300       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingReason = 0;/* unknown */
05301       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingCounter = 1;
05302 
05303       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 0;/* unknown */
05304       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = strlen(nr);
05305       strcpy((char *) tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number, nr);
05306       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Subaddress.Length = 0;
05307 
05308       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length = 0;
05309 
05310       /* 0x90 0x90 0xa3 3.1 kHz audio, circuit mode, 64kbit/sec, level1/a-Law */
05311       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 3;
05312       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[0] = 0x90;
05313       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[1] = 0x90;
05314       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[2] = 0xa3;
05315       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Length = 0;
05316       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Llc.Length = 0;
05317       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Length = 0;
05318 
05319       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1;/* presentationRestricted */
05320       tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.SubscriptionOption = 0;/* no notification to caller */
05321 
05322       /* Send message */
05323       print_facility(&tmp->bc->fac_out, tmp->bc);
05324       ao2_unlock(tmp);
05325       misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
05326       chan_list_unref(tmp, "Send facility complete");
05327 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
05328    } else if (strstr(a->argv[3], "CFActivate")) {
05329       if (a->argc < 7) {
05330          ast_verbose("CFActivate requires 2 args: 1.FromNumber, 2.ToNumber\n\n");
05331          return 0;
05332       }
05333       port = atoi(a->argv[4]);
05334       served_nr = a->argv[5];
05335       nr = a->argv[6];
05336 
05337       misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
05338 
05339       ast_verbose("Sending CFActivate  Port:(%d) FromNr. (%s) to Nr. (%s)\n", port, served_nr, nr);
05340 
05341 #if defined(AST_MISDN_ENHANCEMENTS)
05342       bc->fac_out.Function = Fac_ActivationDiversion;
05343       bc->fac_out.u.ActivationDiversion.InvokeID = ++misdn_invoke_id;
05344       bc->fac_out.u.ActivationDiversion.ComponentType = FacComponent_Invoke;
05345       bc->fac_out.u.ActivationDiversion.Component.Invoke.BasicService = 0;/* allServices */
05346       bc->fac_out.u.ActivationDiversion.Component.Invoke.Procedure = 0;/* cfu (Call Forward Unconditional) */
05347       ast_copy_string((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number,
05348          served_nr, sizeof(bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number));
05349       bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.LengthOfNumber =
05350          strlen((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number);
05351       bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Type = 0;/* unknown */
05352       ast_copy_string((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number,
05353          nr, sizeof(bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number));
05354       bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber =
05355          strlen((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number);
05356       bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 0;/* unknown */
05357       bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Subaddress.Length = 0;
05358 
05359 #else /* !defined(AST_MISDN_ENHANCEMENTS) */
05360 
05361       bc->fac_out.Function = Fac_CFActivate;
05362       bc->fac_out.u.CFActivate.BasicService = 0; /* All Services */
05363       bc->fac_out.u.CFActivate.Procedure = 0; /* Unconditional */
05364       ast_copy_string((char *) bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
05365       ast_copy_string((char *) bc->fac_out.u.CFActivate.ForwardedToNumber, nr, sizeof(bc->fac_out.u.CFActivate.ForwardedToNumber));
05366 #endif   /* !defined(AST_MISDN_ENHANCEMENTS) */
05367 
05368       /* Send message */
05369       print_facility(&bc->fac_out, bc);
05370       misdn_lib_send_event(bc, EVENT_FACILITY);
05371    } else if (strstr(a->argv[3], "CFDeactivate")) {
05372       if (a->argc < 6) {
05373          ast_verbose("CFDeactivate requires 1 arg: FromNumber\n\n");
05374          return 0;
05375       }
05376       port = atoi(a->argv[4]);
05377       served_nr = a->argv[5];
05378 
05379       misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
05380       ast_verbose("Sending CFDeactivate  Port:(%d) FromNr. (%s)\n", port, served_nr);
05381 
05382 #if defined(AST_MISDN_ENHANCEMENTS)
05383       bc->fac_out.Function = Fac_DeactivationDiversion;
05384       bc->fac_out.u.DeactivationDiversion.InvokeID = ++misdn_invoke_id;
05385       bc->fac_out.u.DeactivationDiversion.ComponentType = FacComponent_Invoke;
05386       bc->fac_out.u.DeactivationDiversion.Component.Invoke.BasicService = 0;/* allServices */
05387       bc->fac_out.u.DeactivationDiversion.Component.Invoke.Procedure = 0;/* cfu (Call Forward Unconditional) */
05388       ast_copy_string((char *) bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number,
05389          served_nr, sizeof(bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number));
05390       bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.LengthOfNumber =
05391          strlen((char *) bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number);
05392       bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Type = 0;/* unknown */
05393 
05394 #else /* !defined(AST_MISDN_ENHANCEMENTS) */
05395 
05396       bc->fac_out.Function = Fac_CFDeactivate;
05397       bc->fac_out.u.CFDeactivate.BasicService = 0; /* All Services */
05398       bc->fac_out.u.CFDeactivate.Procedure = 0; /* Unconditional */
05399       ast_copy_string((char *) bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
05400 #endif   /* !defined(AST_MISDN_ENHANCEMENTS) */
05401 
05402       /* Send message */
05403       print_facility(&bc->fac_out, bc);
05404       misdn_lib_send_event(bc, EVENT_FACILITY);
05405 #if defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES)
05406    } else if (strstr(a->argv[3], "test")) {
05407       int msg_number;
05408 
05409       if (a->argc < 5) {
05410          ast_verbose("test (<port> [<msg#>]) | (<channel-name> <msg#>)\n\n");
05411          return 0;
05412       }
05413       port = atoi(a->argv[4]);
05414 
05415       channame = a->argv[4];
05416       tmp = get_chan_by_ast_name(channame);
05417       if (tmp) {
05418          /* We are going to send this FACILITY message out on an existing connection */
05419          msg_number = atoi(a->argv[5]);
05420          if (msg_number < ARRAY_LEN(Fac_Msgs)) {
05421             ao2_lock(tmp);
05422             tmp->bc->fac_out = Fac_Msgs[msg_number];
05423 
05424             /* Send message */
05425             print_facility(&tmp->bc->fac_out, tmp->bc);
05426             ao2_unlock(tmp);
05427             misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
05428          } else {
05429             ast_verbose("test <channel-name> <msg#>\n\n");
05430          }
05431          chan_list_unref(tmp, "Facility test done");
05432       } else if (a->argc < 6) {
05433          for (msg_number = 0; msg_number < ARRAY_LEN(Fac_Msgs); ++msg_number) {
05434             misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
05435             bc->fac_out = Fac_Msgs[msg_number];
05436 
05437             /* Send message */
05438             print_facility(&bc->fac_out, bc);
05439             misdn_lib_send_event(bc, EVENT_FACILITY);
05440             sleep(1);
05441          }
05442       } else {
05443          msg_number = atoi(a->argv[5]);
05444          if (msg_number < ARRAY_LEN(Fac_Msgs)) {
05445             misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
05446             bc->fac_out = Fac_Msgs[msg_number];
05447 
05448             /* Send message */
05449             print_facility(&bc->fac_out, bc);
05450             misdn_lib_send_event(bc, EVENT_FACILITY);
05451          } else {
05452             ast_verbose("test <port> [<msg#>]\n\n");
05453          }
05454       }
05455    } else if (strstr(a->argv[3], "register")) {
05456       if (a->argc < 5) {
05457          ast_verbose("register <port>\n\n");
05458          return 0;
05459       }
05460       port = atoi(a->argv[4]);
05461 
05462       bc = misdn_lib_get_register_bc(port);
05463       if (!bc) {
05464          ast_verbose("Could not allocate REGISTER bc struct\n\n");
05465          return 0;
05466       }
05467       bc->fac_out = Fac_Msgs[45];
05468 
05469       /* Send message */
05470       print_facility(&bc->fac_out, bc);
05471       misdn_lib_send_event(bc, EVENT_REGISTER);
05472 #endif   /* defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES) */
05473    }
05474 
05475    return CLI_SUCCESS;
05476 }
05477 
05478 static char *handle_cli_misdn_send_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05479 {
05480    int port;
05481    int channel;
05482 
05483    switch (cmd) {
05484    case CLI_INIT:
05485       e->command = "misdn send restart";
05486       e->usage =
05487          "Usage: misdn send restart [port [channel]]\n"
05488          "       Send a restart for every bchannel on the given port.\n";
05489       return NULL;
05490    case CLI_GENERATE:
05491       return NULL;
05492    }
05493 
05494    if (a->argc < 4 || a->argc > 5) {
05495       return CLI_SHOWUSAGE;
05496    }
05497 
05498    port = atoi(a->argv[3]);
05499 
05500    if (a->argc == 5) {
05501       channel = atoi(a->argv[4]);
05502       misdn_lib_send_restart(port, channel);
05503    } else {
05504       misdn_lib_send_restart(port, -1);
05505    }
05506 
05507    return CLI_SUCCESS;
05508 }
05509 
05510 static char *handle_cli_misdn_send_digit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05511 {
05512    const char *channame;
05513    const char *msg;
05514    struct chan_list *tmp;
05515    int i, msglen;
05516 
05517    switch (cmd) {
05518    case CLI_INIT:
05519       e->command = "misdn send digit";
05520       e->usage =
05521          "Usage: misdn send digit <channel> \"<msg>\" \n"
05522          "       Send <digit> to <channel> as DTMF Tone\n"
05523          "       when channel is a mISDN channel\n";
05524       return NULL;
05525    case CLI_GENERATE:
05526       return complete_ch(a);
05527    }
05528 
05529    if (a->argc != 5) {
05530       return CLI_SHOWUSAGE;
05531    }
05532 
05533    channame = a->argv[3];
05534    msg = a->argv[4];
05535    msglen = strlen(msg);
05536 
05537    ast_cli(a->fd, "Sending %s to %s\n", msg, channame);
05538 
05539    tmp = get_chan_by_ast_name(channame);
05540    if (!tmp) {
05541       ast_cli(a->fd, "Sending %s to %s failed Channel does not exist\n", msg, channame);
05542       return CLI_SUCCESS;
05543    }
05544 #if 1
05545    for (i = 0; i < msglen; i++) {
05546       if (!tmp->ast) {
05547          break;
05548       }
05549       ast_cli(a->fd, "Sending: %c\n", msg[i]);
05550       send_digit_to_chan(tmp, msg[i]);
05551       /* res = ast_safe_sleep(tmp->ast, 250); */
05552       usleep(250000);
05553       /* res = ast_waitfor(tmp->ast,100); */
05554    }
05555 #else
05556    if (tmp->ast) {
05557       ast_dtmf_stream(tmp->ast, NULL, msg, 250);
05558    }
05559 #endif
05560    chan_list_unref(tmp, "Digit(s) sent");
05561 
05562    return CLI_SUCCESS;
05563 }
05564 
05565 static char *handle_cli_misdn_toggle_echocancel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05566 {
05567    const char *channame;
05568    struct chan_list *tmp;
05569 
05570    switch (cmd) {
05571    case CLI_INIT:
05572       e->command = "misdn toggle echocancel";
05573       e->usage =
05574          "Usage: misdn toggle echocancel <channel>\n"
05575          "       Toggle EchoCancel on mISDN Channel.\n";
05576       return NULL;
05577    case CLI_GENERATE:
05578       return complete_ch(a);
05579    }
05580 
05581    if (a->argc != 4) {
05582       return CLI_SHOWUSAGE;
05583    }
05584 
05585    channame = a->argv[3];
05586 
05587    ast_cli(a->fd, "Toggling EchoCancel on %s\n", channame);
05588 
05589    tmp = get_chan_by_ast_name(channame);
05590    if (!tmp) {
05591       ast_cli(a->fd, "Toggling EchoCancel %s failed Channel does not exist\n", channame);
05592       return CLI_SUCCESS;
05593    }
05594 
05595    tmp->toggle_ec = tmp->toggle_ec ? 0 : 1;
05596 
05597    if (tmp->toggle_ec) {
05598 #ifdef MISDN_1_2
05599       update_pipeline_config(tmp->bc);
05600 #else
05601       update_ec_config(tmp->bc);
05602 #endif
05603       manager_ec_enable(tmp->bc);
05604    } else {
05605       manager_ec_disable(tmp->bc);
05606    }
05607    chan_list_unref(tmp, "Done toggling echo cancel");
05608 
05609    return CLI_SUCCESS;
05610 }
05611 
05612 static char *handle_cli_misdn_send_display(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
05613 {
05614    const char *channame;
05615    const char *msg;
05616    struct chan_list *tmp;
05617 
05618    switch (cmd) {
05619    case CLI_INIT:
05620       e->command = "misdn send display";
05621       e->usage =
05622          "Usage: misdn send display <channel> \"<msg>\" \n"
05623          "       Send <msg> to <channel> as Display Message\n"
05624          "       when channel is a mISDN channel\n";
05625       return NULL;
05626    case CLI_GENERATE:
05627       return complete_ch(a);
05628    }
05629 
05630    if (a->argc != 5) {
05631       return CLI_SHOWUSAGE;
05632    }
05633 
05634    channame = a->argv[3];
05635    msg = a->argv[4];
05636 
05637    ast_cli(a->fd, "Sending %s to %s\n", msg, channame);
05638 
05639    tmp = get_chan_by_ast_name(channame);
05640    if (tmp && tmp->bc) {
05641       ast_copy_string(tmp->bc->display, msg, sizeof(tmp->bc->display));
05642       misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
05643       chan_list_unref(tmp, "Done sending display");
05644    } else {
05645       if (tmp) {
05646          chan_list_unref(tmp, "Display failed");
05647       }
05648       ast_cli(a->fd, "No such channel %s\n", channame);
05649       return CLI_SUCCESS;
05650    }
05651 
05652    return CLI_SUCCESS;
05653 }
05654 
05655 static char *complete_ch(struct ast_cli_args *a)
05656 {
05657    return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
05658 }
05659 
05660 static char *complete_debug_port(struct ast_cli_args *a)
05661 {
05662    if (a->n) {
05663       return NULL;
05664    }
05665 
05666    switch (a->pos) {
05667    case 4:
05668       if (a->word[0] == 'p') {
05669          return ast_strdup("port");
05670       } else if (a->word[0] == 'o') {
05671          return ast_strdup("only");
05672       }
05673       break;
05674    case 6:
05675       if (a->word[0] == 'o') {
05676          return ast_strdup("only");
05677       }
05678       break;
05679    }
05680    return NULL;
05681 }
05682 
05683 static char *complete_show_config(struct ast_cli_args *a)
05684 {
05685    char buffer[BUFFERSIZE];
05686    enum misdn_cfg_elements elem;
05687    int wordlen = strlen(a->word);
05688    int which = 0;
05689    int port = 0;
05690 
05691    switch (a->pos) {
05692    case 3:
05693       if ((!strncmp(a->word, "description", wordlen)) && (++which > a->n)) {
05694          return ast_strdup("description");
05695       }
05696       if ((!strncmp(a->word, "descriptions", wordlen)) && (++which > a->n)) {
05697          return ast_strdup("descriptions");
05698       }
05699       if ((!strncmp(a->word, "0", wordlen)) && (++which > a->n)) {
05700          return ast_strdup("0");
05701       }
05702       while ((port = misdn_cfg_get_next_port(port)) != -1) {
05703          snprintf(buffer, sizeof(buffer), "%d", port);
05704          if ((!strncmp(a->word, buffer, wordlen)) && (++which > a->n)) {
05705             return ast_strdup(buffer);
05706          }
05707       }
05708       break;
05709    case 4:
05710       if (strstr(a->line, "description ")) {
05711          for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) {
05712             if ((elem == MISDN_CFG_LAST) || (elem == MISDN_GEN_FIRST)) {
05713                continue;
05714             }
05715             misdn_cfg_get_name(elem, buffer, sizeof(buffer));
05716             if (!wordlen || !strncmp(a->word, buffer, wordlen)) {
05717                if (++which > a->n) {
05718                   return ast_strdup(buffer);
05719                }
05720             }
05721          }
05722       } else if (strstr(a->line, "descriptions ")) {
05723          if ((!wordlen || !strncmp(a->word, "general", wordlen)) && (++which > a->n)) {
05724             return ast_strdup("general");
05725          }
05726          if ((!wordlen || !strncmp(a->word, "ports", wordlen)) && (++which > a->n)) {
05727             return ast_strdup("ports");
05728          }
05729       }
05730       break;
05731    }
05732    return NULL;
05733 }
05734 
05735 static struct ast_cli_entry chan_misdn_clis[] = {
05736 /* *INDENT-OFF* */
05737    AST_CLI_DEFINE(handle_cli_misdn_port_block,        "Block the given port"),
05738    AST_CLI_DEFINE(handle_cli_misdn_port_down,         "Try to deactivate the L1 on the given port"),
05739    AST_CLI_DEFINE(handle_cli_misdn_port_unblock,      "Unblock the given port"),
05740    AST_CLI_DEFINE(handle_cli_misdn_port_up,           "Try to establish L1 on the given port"),
05741    AST_CLI_DEFINE(handle_cli_misdn_reload,            "Reload internal mISDN config, read from the config file"),
05742    AST_CLI_DEFINE(handle_cli_misdn_restart_pid,       "Restart the given pid"),
05743    AST_CLI_DEFINE(handle_cli_misdn_restart_port,      "Restart the given port"),
05744    AST_CLI_DEFINE(handle_cli_misdn_show_channel,      "Show an internal mISDN channel"),
05745    AST_CLI_DEFINE(handle_cli_misdn_show_channels,     "Show the internal mISDN channel list"),
05746    AST_CLI_DEFINE(handle_cli_misdn_show_config,       "Show internal mISDN config, read from the config file"),
05747    AST_CLI_DEFINE(handle_cli_misdn_show_port,         "Show detailed information for given port"),
05748    AST_CLI_DEFINE(handle_cli_misdn_show_ports_stats,  "Show mISDNs channel's call statistics per port"),
05749    AST_CLI_DEFINE(handle_cli_misdn_show_stacks,       "Show internal mISDN stack_list"),
05750    AST_CLI_DEFINE(handle_cli_misdn_send_facility,     "Sends a Facility Message to the mISDN Channel"),
05751    AST_CLI_DEFINE(handle_cli_misdn_send_digit,        "Send DTMF digit to mISDN Channel"),
05752    AST_CLI_DEFINE(handle_cli_misdn_send_display,      "Send Text to mISDN Channel"),
05753    AST_CLI_DEFINE(handle_cli_misdn_send_restart,      "Send a restart for every bchannel on the given port"),
05754    AST_CLI_DEFINE(handle_cli_misdn_set_crypt_debug,   "Set CryptDebuglevel of chan_misdn, at the moment, level={1,2}"),
05755    AST_CLI_DEFINE(handle_cli_misdn_set_debug,         "Set Debuglevel of chan_misdn"),
05756    AST_CLI_DEFINE(handle_cli_misdn_set_tics,          "???"),
05757    AST_CLI_DEFINE(handle_cli_misdn_toggle_echocancel, "Toggle EchoCancel on mISDN Channel"),
05758 /* *INDENT-ON* */
05759 };
05760 
05761 /*! \brief Updates caller ID information from config */
05762 static void update_config(struct chan_list *ch)
05763 {
05764    struct ast_channel *ast;
05765    struct misdn_bchannel *bc;
05766    int port;
05767    int hdlc = 0;
05768    int pres;
05769    int screen;
05770 
05771    if (!ch) {
05772       ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
05773       return;
05774    }
05775 
05776    ast = ch->ast;
05777    bc = ch->bc;
05778    if (! ast || ! bc) {
05779       ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
05780       return;
05781    }
05782 
05783    port = bc->port;
05784 
05785    chan_misdn_log(7, port, "update_config: Getting Config\n");
05786 
05787    misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(int));
05788    if (hdlc) {
05789       switch (bc->capability) {
05790       case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
05791       case INFO_CAPABILITY_DIGITAL_RESTRICTED:
05792          chan_misdn_log(1, bc->port, " --> CONF HDLC\n");
05793          bc->hdlc = 1;
05794          break;
05795       }
05796    }
05797 
05798 
05799    misdn_cfg_get(port, MISDN_CFG_PRES, &pres, sizeof(pres));
05800    misdn_cfg_get(port, MISDN_CFG_SCREEN, &screen, sizeof(screen));
05801    chan_misdn_log(2, port, " --> pres: %d screen: %d\n", pres, screen);
05802 
05803    if (pres < 0 || screen < 0) {
05804       chan_misdn_log(2, port, " --> pres: %x\n", ast_channel_connected(ast)->id.number.presentation);
05805 
05806       bc->caller.presentation = ast_to_misdn_pres(ast_channel_connected(ast)->id.number.presentation);
05807       chan_misdn_log(2, port, " --> PRES: %s(%d)\n", misdn_to_str_pres(bc->caller.presentation), bc->caller.presentation);
05808 
05809       bc->caller.screening = ast_to_misdn_screen(ast_channel_connected(ast)->id.number.presentation);
05810       chan_misdn_log(2, port, " --> SCREEN: %s(%d)\n", misdn_to_str_screen(bc->caller.screening), bc->caller.screening);
05811    } else {
05812       bc->caller.screening = screen;
05813       bc->caller.presentation = pres;
05814    }
05815 }
05816 
05817 
05818 static void config_jitterbuffer(struct chan_list *ch)
05819 {
05820    struct misdn_bchannel *bc = ch->bc;
05821    int len = ch->jb_len;
05822    int threshold = ch->jb_upper_threshold;
05823 
05824    chan_misdn_log(5, bc->port, "config_jb: Called\n");
05825 
05826    if (!len) {
05827       chan_misdn_log(1, bc->port, "config_jb: Deactivating Jitterbuffer\n");
05828       bc->nojitter = 1;
05829    } else {
05830       if (len <= 100 || len > 8000) {
05831          chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer out of Bounds, setting to 1000\n");
05832          len = 1000;
05833       }
05834 
05835       if (threshold > len) {
05836          chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer Threshold > Jitterbuffer setting to Jitterbuffer -1\n");
05837       }
05838 
05839       if (ch->jb) {
05840          cb_log(0, bc->port, "config_jb: We've got a Jitterbuffer Already on this port.\n");
05841          misdn_jb_destroy(ch->jb);
05842          ch->jb = NULL;
05843       }
05844 
05845       ch->jb = misdn_jb_init(len, threshold);
05846 
05847       if (!ch->jb) {
05848          bc->nojitter = 1;
05849       }
05850    }
05851 }
05852 
05853 
05854 void debug_numtype(int port, int numtype, char *type)
05855 {
05856    switch (numtype) {
05857    case NUMTYPE_UNKNOWN:
05858       chan_misdn_log(2, port, " --> %s: Unknown\n", type);
05859       break;
05860    case NUMTYPE_INTERNATIONAL:
05861       chan_misdn_log(2, port, " --> %s: International\n", type);
05862       break;
05863    case NUMTYPE_NATIONAL:
05864       chan_misdn_log(2, port, " --> %s: National\n", type);
05865       break;
05866    case NUMTYPE_NETWORK_SPECIFIC:
05867       chan_misdn_log(2, port, " --> %s: Network Specific\n", type);
05868       break;
05869    case NUMTYPE_SUBSCRIBER:
05870       chan_misdn_log(2, port, " --> %s: Subscriber\n", type);
05871       break;
05872    case NUMTYPE_ABBREVIATED:
05873       chan_misdn_log(2, port, " --> %s: Abbreviated\n", type);
05874       break;
05875       /* Maybe we should cut off the prefix if present ? */
05876    default:
05877       chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n ");
05878       break;
05879    }
05880 }
05881 
05882 
05883 #ifdef MISDN_1_2
05884 static int update_pipeline_config(struct misdn_bchannel *bc)
05885 {
05886    int ec;
05887 
05888    misdn_cfg_get(bc->port, MISDN_CFG_PIPELINE, bc->pipeline, sizeof(bc->pipeline));
05889 
05890    if (*bc->pipeline) {
05891       return 0;
05892    }
05893 
05894    misdn_cfg_get(bc->port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(ec));
05895    if (ec == 1) {
05896       ast_copy_string(bc->pipeline, "mg2ec", sizeof(bc->pipeline));
05897    } else if (ec > 1) {
05898       snprintf(bc->pipeline, sizeof(bc->pipeline), "mg2ec(deftaps=%d)", ec);
05899    }
05900 
05901    return 0;
05902 }
05903 #else
05904 static int update_ec_config(struct misdn_bchannel *bc)
05905 {
05906    int ec;
05907    int port = bc->port;
05908 
05909    misdn_cfg_get(port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(ec));
05910 
05911    if (ec == 1) {
05912       bc->ec_enable = 1;
05913    } else if (ec > 1) {
05914       bc->ec_enable = 1;
05915       bc->ec_deftaps = ec;
05916    }
05917 
05918    return 0;
05919 }
05920 #endif
05921 
05922 
05923 static int read_config(struct chan_list *ch)
05924 {
05925    struct ast_channel *ast;
05926    struct misdn_bchannel *bc;
05927    int port;
05928    int hdlc = 0;
05929    char lang[BUFFERSIZE + 1];
05930    char faxdetect[BUFFERSIZE + 1];
05931    char buf[256];
05932    char buf2[256];
05933    ast_group_t pg;
05934    ast_group_t cg;
05935    struct ast_namedgroups *npg;
05936    struct ast_namedgroups *ncg;
05937    struct ast_str *tmp_str;
05938 
05939    if (!ch) {
05940       ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
05941       return -1;
05942    }
05943 
05944    ast = ch->ast;
05945    bc = ch->bc;
05946    if (! ast || ! bc) {
05947       ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
05948       return -1;
05949    }
05950 
05951    port = bc->port;
05952    chan_misdn_log(1, port, "read_config: Getting Config\n");
05953 
05954    misdn_cfg_get(port, MISDN_CFG_LANGUAGE, lang, sizeof(lang));
05955    ast_channel_lock(ast);
05956    ast_channel_language_set(ast, lang);
05957    ast_channel_unlock(ast);
05958 
05959    misdn_cfg_get(port, MISDN_CFG_MUSICCLASS, ch->mohinterpret, sizeof(ch->mohinterpret));
05960 
05961    misdn_cfg_get(port, MISDN_CFG_TXGAIN, &bc->txgain, sizeof(bc->txgain));
05962    misdn_cfg_get(port, MISDN_CFG_RXGAIN, &bc->rxgain, sizeof(bc->rxgain));
05963 
05964    misdn_cfg_get(port, MISDN_CFG_INCOMING_EARLY_AUDIO, &ch->incoming_early_audio, sizeof(ch->incoming_early_audio));
05965 
05966    misdn_cfg_get(port, MISDN_CFG_SENDDTMF, &bc->send_dtmf, sizeof(bc->send_dtmf));
05967 
05968    misdn_cfg_get(port, MISDN_CFG_ASTDTMF, &ch->ast_dsp, sizeof(int));
05969    if (ch->ast_dsp) {
05970       ch->ignore_dtmf = 1;
05971    }
05972 
05973    misdn_cfg_get(port, MISDN_CFG_NEED_MORE_INFOS, &bc->need_more_infos, sizeof(bc->need_more_infos));
05974    misdn_cfg_get(port, MISDN_CFG_NTTIMEOUT, &ch->nttimeout, sizeof(ch->nttimeout));
05975 
05976    misdn_cfg_get(port, MISDN_CFG_NOAUTORESPOND_ON_SETUP, &ch->noautorespond_on_setup, sizeof(ch->noautorespond_on_setup));
05977 
05978    misdn_cfg_get(port, MISDN_CFG_FAR_ALERTING, &ch->far_alerting, sizeof(ch->far_alerting));
05979 
05980    misdn_cfg_get(port, MISDN_CFG_ALLOWED_BEARERS, &ch->allowed_bearers, sizeof(ch->allowed_bearers));
05981 
05982    misdn_cfg_get(port, MISDN_CFG_FAXDETECT, faxdetect, sizeof(faxdetect));
05983 
05984    misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(hdlc));
05985    if (hdlc) {
05986       switch (bc->capability) {
05987       case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
05988       case INFO_CAPABILITY_DIGITAL_RESTRICTED:
05989          chan_misdn_log(1, bc->port, " --> CONF HDLC\n");
05990          bc->hdlc = 1;
05991          break;
05992       }
05993 
05994    }
05995    /*Initialize new Jitterbuffer*/
05996    misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER, &ch->jb_len, sizeof(ch->jb_len));
05997    misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, &ch->jb_upper_threshold, sizeof(ch->jb_upper_threshold));
05998 
05999    config_jitterbuffer(ch);
06000 
06001    misdn_cfg_get(bc->port, MISDN_CFG_CONTEXT, ch->context, sizeof(ch->context));
06002 
06003    ast_channel_lock(ast);
06004    ast_channel_context_set(ast, ch->context);
06005    ast_channel_unlock(ast);
06006 
06007 #ifdef MISDN_1_2
06008    update_pipeline_config(bc);
06009 #else
06010    update_ec_config(bc);
06011 #endif
06012 
06013    misdn_cfg_get(bc->port, MISDN_CFG_EARLY_BCONNECT, &bc->early_bconnect, sizeof(bc->early_bconnect));
06014 
06015    misdn_cfg_get(port, MISDN_CFG_DISPLAY_CONNECTED, &bc->display_connected, sizeof(bc->display_connected));
06016    misdn_cfg_get(port, MISDN_CFG_DISPLAY_SETUP, &bc->display_setup, sizeof(bc->display_setup));
06017    misdn_cfg_get(port, MISDN_CFG_OUTGOING_COLP, &bc->outgoing_colp, sizeof(bc->outgoing_colp));
06018 
06019    misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg));
06020    misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg));
06021    chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n", ast_print_group(buf, sizeof(buf), cg), ast_print_group(buf2, sizeof(buf2), pg));
06022    ast_channel_lock(ast);
06023    ast_channel_pickupgroup_set(ast, pg);
06024    ast_channel_callgroup_set(ast, cg);
06025    ast_channel_unlock(ast);
06026 
06027    misdn_cfg_get(port, MISDN_CFG_NAMEDPICKUPGROUP, &npg, sizeof(npg));
06028    misdn_cfg_get(port, MISDN_CFG_NAMEDCALLGROUP, &ncg, sizeof(ncg));
06029 
06030    tmp_str = ast_str_create(1024);
06031    if (tmp_str) {
06032       chan_misdn_log(5, port, " --> * NamedCallGrp:%s\n", ast_print_namedgroups(&tmp_str, ncg));
06033       ast_str_reset(tmp_str);
06034       chan_misdn_log(5, port, " --> * NamedPickupGrp:%s\n", ast_print_namedgroups(&tmp_str, npg));
06035       ast_free(tmp_str);
06036    }
06037 
06038    ast_channel_lock(ast);
06039    ast_channel_named_pickupgroups_set(ast, npg);
06040    ast_channel_named_callgroups_set(ast, ncg);
06041    ast_channel_unlock(ast);
06042 
06043    if (ch->originator == ORG_AST) {
06044       char callerid[BUFFERSIZE + 1];
06045 
06046       /* ORIGINATOR Asterisk (outgoing call) */
06047 
06048       misdn_cfg_get(port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(bc->te_choose_channel), sizeof(bc->te_choose_channel));
06049 
06050       if (strstr(faxdetect, "outgoing") || strstr(faxdetect, "both")) {
06051          ch->faxdetect = strstr(faxdetect, "nojump") ? 2 : 1;
06052       }
06053 
06054       misdn_cfg_get(port, MISDN_CFG_CALLERID, callerid, sizeof(callerid));
06055       if (!ast_strlen_zero(callerid)) {
06056          char *cid_name = NULL;
06057          char *cid_num = NULL;
06058 
06059          ast_callerid_parse(callerid, &cid_name, &cid_num);
06060          if (cid_name) {
06061             ast_copy_string(bc->caller.name, cid_name, sizeof(bc->caller.name));
06062          } else {
06063             bc->caller.name[0] = '\0';
06064          }
06065          if (cid_num) {
06066             ast_copy_string(bc->caller.number, cid_num, sizeof(bc->caller.number));
06067          } else {
06068             bc->caller.number[0] = '\0';
06069          }
06070          chan_misdn_log(1, port, " --> * Setting caller to \"%s\" <%s>\n", bc->caller.name, bc->caller.number);
06071       }
06072 
06073       misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dialed.number_type, sizeof(bc->dialed.number_type));
06074       bc->dialed.number_plan = NUMPLAN_ISDN;
06075       debug_numtype(port, bc->dialed.number_type, "TON");
06076 
06077       ch->overlap_dial = 0;
06078    } else {
06079       /* ORIGINATOR MISDN (incoming call) */
06080 
06081       if (strstr(faxdetect, "incoming") || strstr(faxdetect, "both")) {
06082          ch->faxdetect = (strstr(faxdetect, "nojump")) ? 2 : 1;
06083       }
06084 
06085       /* Add configured prefix to caller.number */
06086       misdn_add_number_prefix(bc->port, bc->caller.number_type, bc->caller.number, sizeof(bc->caller.number));
06087 
06088       if (ast_strlen_zero(bc->dialed.number) && !ast_strlen_zero(bc->keypad)) {
06089          ast_copy_string(bc->dialed.number, bc->keypad, sizeof(bc->dialed.number));
06090       }
06091 
06092       /* Add configured prefix to dialed.number */
06093       misdn_add_number_prefix(bc->port, bc->dialed.number_type, bc->dialed.number, sizeof(bc->dialed.number));
06094 
06095       ast_channel_lock(ast);
06096       ast_channel_exten_set(ast, bc->dialed.number);
06097       ast_channel_unlock(ast);
06098 
06099       misdn_cfg_get(bc->port, MISDN_CFG_OVERLAP_DIAL, &ch->overlap_dial, sizeof(ch->overlap_dial));
06100       ast_mutex_init(&ch->overlap_tv_lock);
06101    } /* ORIG MISDN END */
06102 
06103    misdn_cfg_get(port, MISDN_CFG_INCOMING_CALLERID_TAG, bc->incoming_cid_tag, sizeof(bc->incoming_cid_tag));
06104    if (!ast_strlen_zero(bc->incoming_cid_tag)) {
06105       chan_misdn_log(1, port, " --> * Setting incoming caller id tag to \"%s\"\n", bc->incoming_cid_tag);
06106    }
06107    ch->overlap_dial_task = -1;
06108 
06109    if (ch->faxdetect  || ch->ast_dsp) {
06110       misdn_cfg_get(port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
06111       if (!ch->dsp) {
06112          ch->dsp = ast_dsp_new();
06113       }
06114       if (ch->dsp) {
06115          ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT | (ch->faxdetect ? DSP_FEATURE_FAX_DETECT : 0));
06116       }
06117    }
06118 
06119    /* AOCD initialization */
06120    bc->AOCDtype = Fac_None;
06121 
06122    return 0;
06123 }
06124 
06125 /*!
06126  * \internal
06127  * \brief Send a connected line update to the other channel
06128  *
06129  * \param ast Current Asterisk channel
06130  * \param id Party id information to send to the other side
06131  * \param source Why are we sending this update
06132  * \param cid_tag User tag to apply to the party id.
06133  *
06134  * \return Nothing
06135  */
06136 static void misdn_queue_connected_line_update(struct ast_channel *ast, const struct misdn_party_id *id, enum AST_CONNECTED_LINE_UPDATE_SOURCE source, char *cid_tag)
06137 {
06138    struct ast_party_connected_line connected;
06139    struct ast_set_party_connected_line update_connected;
06140 
06141    ast_party_connected_line_init(&connected);
06142    memset(&update_connected, 0, sizeof(update_connected));
06143    update_connected.id.number = 1;
06144    connected.id.number.valid = 1;
06145    connected.id.number.str = (char *) id->number;
06146    connected.id.number.plan = misdn_to_ast_ton(id->number_type)
06147       | misdn_to_ast_plan(id->number_plan);
06148    connected.id.number.presentation = misdn_to_ast_pres(id->presentation)
06149       | misdn_to_ast_screen(id->screening);
06150 
06151    /*
06152     * Make sure that any earlier private connected id
06153     * representation at the remote end is invalidated
06154     */
06155    ast_set_party_id_all(&update_connected.priv);
06156 
06157    connected.id.tag = cid_tag;
06158    connected.source = source;
06159    ast_channel_queue_connected_line_update(ast, &connected, &update_connected);
06160 }
06161 
06162 /*!
06163  * \internal
06164  * \brief Update the caller id party on this channel.
06165  *
06166  * \param ast Current Asterisk channel
06167  * \param id Remote party id information to update.
06168  * \param cid_tag User tag to apply to the party id.
06169  *
06170  * \return Nothing
06171  */
06172 static void misdn_update_caller_id(struct ast_channel *ast, const struct misdn_party_id *id, char *cid_tag)
06173 {
06174    struct ast_party_caller caller;
06175    struct ast_set_party_caller update_caller;
06176 
06177    memset(&update_caller, 0, sizeof(update_caller));
06178    update_caller.id.number = 1;
06179    update_caller.ani.number = 1;
06180 
06181    ast_channel_lock(ast);
06182    ast_party_caller_set_init(&caller, ast_channel_caller(ast));
06183 
06184    caller.id.number.valid = 1;
06185    caller.id.number.str = (char *) id->number;
06186    caller.id.number.plan = misdn_to_ast_ton(id->number_type)
06187       | misdn_to_ast_plan(id->number_plan);
06188    caller.id.number.presentation = misdn_to_ast_pres(id->presentation)
06189       | misdn_to_ast_screen(id->screening);
06190 
06191    caller.ani.number = caller.id.number;
06192 
06193    caller.id.tag = cid_tag;
06194    caller.ani.tag = cid_tag;
06195 
06196    ast_channel_set_caller_event(ast, &caller, &update_caller);
06197    ast_channel_unlock(ast);
06198 }
06199 
06200 /*!
06201  * \internal
06202  * \brief Update the remote party id information.
06203  *
06204  * \param ast Current Asterisk channel
06205  * \param id Remote party id information to update.
06206  * \param source Why are we sending this update
06207  * \param cid_tag User tag to apply to the party id.
06208  *
06209  * \return Nothing
06210  */
06211 static void misdn_update_remote_party(struct ast_channel *ast, const struct misdn_party_id *id, enum AST_CONNECTED_LINE_UPDATE_SOURCE source, char *cid_tag)
06212 {
06213    misdn_update_caller_id(ast, id, cid_tag);
06214    misdn_queue_connected_line_update(ast, id, source, cid_tag);
06215 }
06216 
06217 /*!
06218  * \internal
06219  * \brief Get the connected line information out of the Asterisk channel.
06220  *
06221  * \param ast Current Asterisk channel
06222  * \param bc Associated B channel
06223  * \param originator Who originally created this channel. ORG_AST or ORG_MISDN
06224  *
06225  * \return Nothing
06226  */
06227 static void misdn_get_connected_line(struct ast_channel *ast, struct misdn_bchannel *bc, int originator)
06228 {
06229    int number_type;
06230    struct ast_party_id connected_id = ast_channel_connected_effective_id(ast);
06231 
06232    if (originator == ORG_MISDN) {
06233       /* ORIGINATOR MISDN (incoming call) */
06234 
06235       ast_copy_string(bc->connected.name,
06236          S_COR(connected_id.name.valid, connected_id.name.str, ""),
06237          sizeof(bc->connected.name));
06238       if (connected_id.number.valid) {
06239          ast_copy_string(bc->connected.number, S_OR(connected_id.number.str, ""),
06240             sizeof(bc->connected.number));
06241          bc->connected.presentation = ast_to_misdn_pres(connected_id.number.presentation);
06242          bc->connected.screening = ast_to_misdn_screen(connected_id.number.presentation);
06243          bc->connected.number_type = ast_to_misdn_ton(connected_id.number.plan);
06244          bc->connected.number_plan = ast_to_misdn_plan(connected_id.number.plan);
06245       } else {
06246          bc->connected.number[0] = '\0';
06247          bc->connected.presentation = 0;/* Allowed */
06248          bc->connected.screening = 0;/* Unscreened */
06249          bc->connected.number_type = NUMTYPE_UNKNOWN;
06250          bc->connected.number_plan = NUMPLAN_UNKNOWN;
06251       }
06252 
06253       misdn_cfg_get(bc->port, MISDN_CFG_CPNDIALPLAN, &number_type, sizeof(number_type));
06254       if (0 <= number_type) {
06255          /* Force us to send in CONNECT message */
06256          bc->connected.number_type = number_type;
06257          bc->connected.number_plan = NUMPLAN_ISDN;
06258       }
06259       debug_numtype(bc->port, bc->connected.number_type, "CTON");
06260    } else {
06261       /* ORIGINATOR Asterisk (outgoing call) */
06262 
06263       ast_copy_string(bc->caller.name,
06264          S_COR(connected_id.name.valid, connected_id.name.str, ""),
06265          sizeof(bc->caller.name));
06266       if (connected_id.number.valid) {
06267          ast_copy_string(bc->caller.number, S_OR(connected_id.number.str, ""),
06268             sizeof(bc->caller.number));
06269          bc->caller.presentation = ast_to_misdn_pres(connected_id.number.presentation);
06270          bc->caller.screening = ast_to_misdn_screen(connected_id.number.presentation);
06271          bc->caller.number_type = ast_to_misdn_ton(connected_id.number.plan);
06272          bc->caller.number_plan = ast_to_misdn_plan(connected_id.number.plan);
06273       } else {
06274          bc->caller.number[0] = '\0';
06275          bc->caller.presentation = 0;/* Allowed */
06276          bc->caller.screening = 0;/* Unscreened */
06277          bc->caller.number_type = NUMTYPE_UNKNOWN;
06278          bc->caller.number_plan = NUMPLAN_UNKNOWN;
06279       }
06280 
06281       misdn_cfg_get(bc->port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type));
06282       if (0 <= number_type) {
06283          /* Force us to send in SETUP message */
06284          bc->caller.number_type = number_type;
06285          bc->caller.number_plan = NUMPLAN_ISDN;
06286       }
06287       debug_numtype(bc->port, bc->caller.number_type, "LTON");
06288    }
06289 }
06290 
06291 /*!
06292  * \internal
06293  * \brief Notify peer that the connected line has changed.
06294  *
06295  * \param ast Current Asterisk channel
06296  * \param bc Associated B channel
06297  * \param originator Who originally created this channel. ORG_AST or ORG_MISDN
06298  *
06299  * \return Nothing
06300  */
06301 static void misdn_update_connected_line(struct ast_channel *ast, struct misdn_bchannel *bc, int originator)
06302 {
06303    struct chan_list *ch;
06304 
06305    misdn_get_connected_line(ast, bc, originator);
06306    if (originator == ORG_MISDN) {
06307       bc->redirecting.to = bc->connected;
06308    } else {
06309       bc->redirecting.to = bc->caller;
06310    }
06311    switch (bc->outgoing_colp) {
06312    case 1:/* restricted */
06313       bc->redirecting.to.presentation = 1;/* restricted */
06314       break;
06315    case 2:/* blocked */
06316       /* Don't tell the remote party that the call was transferred. */
06317       return;
06318    default:
06319       break;
06320    }
06321 
06322    ch = MISDN_ASTERISK_TECH_PVT(ast);
06323    if (ch->state == MISDN_CONNECTED
06324       || originator != ORG_MISDN) {
06325       int is_ptmp;
06326 
06327       is_ptmp = !misdn_lib_is_ptp(bc->port);
06328       if (is_ptmp) {
06329          /*
06330           * We should not send these messages to the network if we are
06331           * the CPE side since phones do not transfer calls within
06332           * themselves.  Well... If you consider handing the handset to
06333           * someone else a transfer then how is the network to know?
06334           */
06335          if (!misdn_lib_port_is_nt(bc->port)) {
06336             return;
06337          }
06338          if (ch->state != MISDN_CONNECTED) {
06339             /* Send NOTIFY(Nie(transfer-active), RDNie(redirecting.to data)) */
06340             bc->redirecting.to_changed = 1;
06341             bc->notify_description_code = mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE;
06342             misdn_lib_send_event(bc, EVENT_NOTIFY);
06343 #if defined(AST_MISDN_ENHANCEMENTS)
06344          } else {
06345             /* Send FACILITY(Fie(RequestSubaddress), Nie(transfer-active), RDNie(redirecting.to data)) */
06346             bc->redirecting.to_changed = 1;
06347             bc->notify_description_code = mISDN_NOTIFY_CODE_CALL_TRANSFER_ACTIVE;
06348             bc->fac_out.Function = Fac_RequestSubaddress;
06349             bc->fac_out.u.RequestSubaddress.InvokeID = ++misdn_invoke_id;
06350 
06351             /* Send message */
06352             print_facility(&bc->fac_out, bc);
06353             misdn_lib_send_event(bc, EVENT_FACILITY);
06354 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
06355          }
06356 #if defined(AST_MISDN_ENHANCEMENTS)
06357       } else {
06358          /* Send FACILITY(Fie(EctInform(transfer-active, redirecting.to data))) */
06359          bc->fac_out.Function = Fac_EctInform;
06360          bc->fac_out.u.EctInform.InvokeID = ++misdn_invoke_id;
06361          bc->fac_out.u.EctInform.Status = 1;/* active */
06362          bc->fac_out.u.EctInform.RedirectionPresent = 1;/* Must be present when status is active */
06363          misdn_PresentedNumberUnscreened_fill(&bc->fac_out.u.EctInform.Redirection,
06364             &bc->redirecting.to);
06365 
06366          /* Send message */
06367          print_facility(&bc->fac_out, bc);
06368          misdn_lib_send_event(bc, EVENT_FACILITY);
06369 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
06370       }
06371    }
06372 }
06373 
06374 /*!
06375  * \internal
06376  * \brief Copy the redirecting information out of the Asterisk channel
06377  *
06378  * \param bc Associated B channel
06379  * \param ast Current Asterisk channel
06380  *
06381  * \return Nothing
06382  */
06383 static void misdn_copy_redirecting_from_ast(struct misdn_bchannel *bc, struct ast_channel *ast)
06384 {
06385    struct ast_party_id from_id = ast_channel_redirecting_effective_from(ast);
06386    struct ast_party_id to_id = ast_channel_redirecting_effective_to(ast);
06387 
06388    ast_copy_string(bc->redirecting.from.name,
06389       S_COR(from_id.name.valid, from_id.name.str, ""),
06390       sizeof(bc->redirecting.from.name));
06391    if (from_id.number.valid) {
06392       ast_copy_string(bc->redirecting.from.number, S_OR(from_id.number.str, ""),
06393          sizeof(bc->redirecting.from.number));
06394       bc->redirecting.from.presentation = ast_to_misdn_pres(from_id.number.presentation);
06395       bc->redirecting.from.screening = ast_to_misdn_screen(from_id.number.presentation);
06396       bc->redirecting.from.number_type = ast_to_misdn_ton(from_id.number.plan);
06397       bc->redirecting.from.number_plan = ast_to_misdn_plan(from_id.number.plan);
06398    } else {
06399       bc->redirecting.from.number[0] = '\0';
06400       bc->redirecting.from.presentation = 0;/* Allowed */
06401       bc->redirecting.from.screening = 0;/* Unscreened */
06402       bc->redirecting.from.number_type = NUMTYPE_UNKNOWN;
06403       bc->redirecting.from.number_plan = NUMPLAN_UNKNOWN;
06404    }
06405 
06406    ast_copy_string(bc->redirecting.to.name,
06407       S_COR(to_id.name.valid, to_id.name.str, ""),
06408       sizeof(bc->redirecting.to.name));
06409    if (to_id.number.valid) {
06410       ast_copy_string(bc->redirecting.to.number, S_OR(to_id.number.str, ""),
06411          sizeof(bc->redirecting.to.number));
06412       bc->redirecting.to.presentation = ast_to_misdn_pres(to_id.number.presentation);
06413       bc->redirecting.to.screening = ast_to_misdn_screen(to_id.number.presentation);
06414       bc->redirecting.to.number_type = ast_to_misdn_ton(to_id.number.plan);
06415       bc->redirecting.to.number_plan = ast_to_misdn_plan(to_id.number.plan);
06416    } else {
06417       bc->redirecting.to.number[0] = '\0';
06418       bc->redirecting.to.presentation = 0;/* Allowed */
06419       bc->redirecting.to.screening = 0;/* Unscreened */
06420       bc->redirecting.to.number_type = NUMTYPE_UNKNOWN;
06421       bc->redirecting.to.number_plan = NUMPLAN_UNKNOWN;
06422    }
06423 
06424    bc->redirecting.reason = ast_to_misdn_reason(ast_channel_redirecting(ast)->reason.code);
06425    bc->redirecting.count = ast_channel_redirecting(ast)->count;
06426 }
06427 
06428 /*!
06429  * \internal
06430  * \brief Copy the redirecting info into the Asterisk channel
06431  *
06432  * \param ast Current Asterisk channel
06433  * \param redirect Associated B channel redirecting info
06434  * \param tag Caller ID tag to set in the redirecting party fields
06435  *
06436  * \return Nothing
06437  */
06438 static void misdn_copy_redirecting_to_ast(struct ast_channel *ast, const struct misdn_party_redirecting *redirect, char *tag)
06439 {
06440    struct ast_party_redirecting redirecting;
06441    struct ast_set_party_redirecting update_redirecting;
06442 
06443    ast_party_redirecting_set_init(&redirecting, ast_channel_redirecting(ast));
06444    memset(&update_redirecting, 0, sizeof(update_redirecting));
06445 
06446    update_redirecting.from.number = 1;
06447    redirecting.from.number.valid = 1;
06448    redirecting.from.number.str = (char *) redirect->from.number;
06449    redirecting.from.number.plan =
06450       misdn_to_ast_ton(redirect->from.number_type)
06451       | misdn_to_ast_plan(redirect->from.number_plan);
06452    redirecting.from.number.presentation =
06453       misdn_to_ast_pres(redirect->from.presentation)
06454       | misdn_to_ast_screen(redirect->from.screening);
06455    redirecting.from.tag = tag;
06456 
06457    update_redirecting.to.number = 1;
06458    redirecting.to.number.valid = 1;
06459    redirecting.to.number.str = (char *) redirect->to.number;
06460    redirecting.to.number.plan =
06461       misdn_to_ast_ton(redirect->to.number_type)
06462       | misdn_to_ast_plan(redirect->to.number_plan);
06463    redirecting.to.number.presentation =
06464       misdn_to_ast_pres(redirect->to.presentation)
06465       | misdn_to_ast_screen(redirect->to.screening);
06466    redirecting.to.tag = tag;
06467 
06468    redirecting.reason.code = misdn_to_ast_reason(redirect->reason);
06469    redirecting.count = redirect->count;
06470 
06471    ast_channel_set_redirecting(ast, &redirecting, &update_redirecting);
06472 }
06473 
06474 /*!
06475  * \internal
06476  * \brief Notify peer that the redirecting information has changed.
06477  *
06478  * \param ast Current Asterisk channel
06479  * \param bc Associated B channel
06480  * \param originator Who originally created this channel. ORG_AST or ORG_MISDN
06481  *
06482  * \return Nothing
06483  */
06484 static void misdn_update_redirecting(struct ast_channel *ast, struct misdn_bchannel *bc, int originator)
06485 {
06486    int is_ptmp;
06487 
06488    misdn_copy_redirecting_from_ast(bc, ast);
06489    switch (bc->outgoing_colp) {
06490    case 1:/* restricted */
06491       bc->redirecting.to.presentation = 1;/* restricted */
06492       break;
06493    case 2:/* blocked */
06494       /* Don't tell the remote party that the call was redirected. */
06495       return;
06496    default:
06497       break;
06498    }
06499 
06500    if (originator != ORG_MISDN) {
06501       return;
06502    }
06503 
06504    is_ptmp = !misdn_lib_is_ptp(bc->port);
06505    if (is_ptmp) {
06506       /*
06507        * We should not send these messages to the network if we are
06508        * the CPE side since phones do not redirect calls within
06509        * themselves.  Well... If you consider someone else picking up
06510        * the handset a redirection then how is the network to know?
06511        */
06512       if (!misdn_lib_port_is_nt(bc->port)) {
06513          return;
06514       }
06515       /* Send NOTIFY(call-is-diverting, redirecting.to data) */
06516       bc->redirecting.to_changed = 1;
06517       bc->notify_description_code = mISDN_NOTIFY_CODE_CALL_IS_DIVERTING;
06518       misdn_lib_send_event(bc, EVENT_NOTIFY);
06519 #if defined(AST_MISDN_ENHANCEMENTS)
06520    } else {
06521       int match;  /* TRUE if the dialed number matches the redirecting to number */
06522 
06523       match = (strcmp(ast_channel_exten(ast), bc->redirecting.to.number) == 0) ? 1 : 0;
06524       if (!bc->div_leg_3_tx_pending
06525          || !match) {
06526          /* Send DivertingLegInformation1 */
06527          bc->fac_out.Function = Fac_DivertingLegInformation1;
06528          bc->fac_out.u.DivertingLegInformation1.InvokeID = ++misdn_invoke_id;
06529          bc->fac_out.u.DivertingLegInformation1.DiversionReason =
06530             misdn_to_diversion_reason(bc->redirecting.reason);
06531          bc->fac_out.u.DivertingLegInformation1.SubscriptionOption = 2;/* notificationWithDivertedToNr */
06532          bc->fac_out.u.DivertingLegInformation1.DivertedToPresent = 1;
06533          misdn_PresentedNumberUnscreened_fill(&bc->fac_out.u.DivertingLegInformation1.DivertedTo, &bc->redirecting.to);
06534          print_facility(&bc->fac_out, bc);
06535          misdn_lib_send_event(bc, EVENT_FACILITY);
06536       }
06537       bc->div_leg_3_tx_pending = 0;
06538 
06539       /* Send DivertingLegInformation3 */
06540       bc->fac_out.Function = Fac_DivertingLegInformation3;
06541       bc->fac_out.u.DivertingLegInformation3.InvokeID = ++misdn_invoke_id;
06542       bc->fac_out.u.DivertingLegInformation3.PresentationAllowedIndicator =
06543          bc->redirecting.to.presentation == 0 ? 1 : 0;
06544       print_facility(&bc->fac_out, bc);
06545       misdn_lib_send_event(bc, EVENT_FACILITY);
06546 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
06547    }
06548 }
06549 
06550 
06551 /*****************************/
06552 /*** AST Indications Start ***/
06553 /*****************************/
06554 
06555 static int misdn_call(struct ast_channel *ast, const char *dest, int timeout)
06556 {
06557    int port = 0;
06558    int r;
06559    int exceed;
06560    int number_type;
06561    struct chan_list *ch;
06562    struct misdn_bchannel *newbc;
06563    char *dest_cp;
06564    int append_msn = 0;
06565 
06566    AST_DECLARE_APP_ARGS(args,
06567       AST_APP_ARG(intf);   /* The interface token is discarded. */
06568       AST_APP_ARG(ext); /* extension token */
06569       AST_APP_ARG(opts);   /* options token */
06570    );
06571 
06572    if (!ast) {
06573       ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n");
06574       return -1;
06575    }
06576 
06577    if (((ast_channel_state(ast) != AST_STATE_DOWN) && (ast_channel_state(ast) != AST_STATE_RESERVED)) || !dest) {
06578       ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast_channel_name(ast));
06579       ast_channel_hangupcause_set(ast, AST_CAUSE_NORMAL_TEMPORARY_FAILURE);
06580       ast_setstate(ast, AST_STATE_DOWN);
06581       return -1;
06582    }
06583 
06584    ch = MISDN_ASTERISK_TECH_PVT(ast);
06585    if (!ch) {
06586       ast_log(LOG_WARNING, " --> ! misdn_call called on %s, chan_list *ch==NULL\n", ast_channel_name(ast));
06587       ast_channel_hangupcause_set(ast, AST_CAUSE_NORMAL_TEMPORARY_FAILURE);
06588       ast_setstate(ast, AST_STATE_DOWN);
06589       return -1;
06590    }
06591 
06592    newbc = ch->bc;
06593    if (!newbc) {
06594       ast_log(LOG_WARNING, " --> ! misdn_call called on %s, newbc==NULL\n", ast_channel_name(ast));
06595       ast_channel_hangupcause_set(ast, AST_CAUSE_NORMAL_TEMPORARY_FAILURE);
06596       ast_setstate(ast, AST_STATE_DOWN);
06597       return -1;
06598    }
06599 
06600    port = newbc->port;
06601 
06602 #if defined(AST_MISDN_ENHANCEMENTS)
06603    if ((ch->peer = misdn_cc_caller_get(ast))) {
06604       chan_misdn_log(3, port, " --> Found CC caller data, peer:%s\n",
06605          ch->peer->chan ? "available" : "NULL");
06606    }
06607 
06608    if (ch->record_id != -1) {
06609       struct misdn_cc_record *cc_record;
06610 
06611       /* This is a call completion retry call */
06612       AST_LIST_LOCK(&misdn_cc_records_db);
06613       cc_record = misdn_cc_find_by_id(ch->record_id);
06614       if (!cc_record) {
06615          AST_LIST_UNLOCK(&misdn_cc_records_db);
06616          ast_log(LOG_WARNING, " --> ! misdn_call called on %s, cc_record==NULL\n", ast_channel_name(ast));
06617          ast_channel_hangupcause_set(ast, AST_CAUSE_NORMAL_TEMPORARY_FAILURE);
06618          ast_setstate(ast, AST_STATE_DOWN);
06619          return -1;
06620       }
06621 
06622       /* Setup calling parameters to retry the call. */
06623       newbc->dialed = cc_record->redial.dialed;
06624       newbc->caller = cc_record->redial.caller;
06625       memset(&newbc->redirecting, 0, sizeof(newbc->redirecting));
06626       newbc->capability = cc_record->redial.capability;
06627       newbc->hdlc = cc_record->redial.hdlc;
06628       newbc->sending_complete = 1;
06629 
06630       if (cc_record->ptp) {
06631          newbc->fac_out.Function = Fac_CCBS_T_Call;
06632          newbc->fac_out.u.CCBS_T_Call.InvokeID = ++misdn_invoke_id;
06633       } else {
06634          newbc->fac_out.Function = Fac_CCBSCall;
06635          newbc->fac_out.u.CCBSCall.InvokeID = ++misdn_invoke_id;
06636          newbc->fac_out.u.CCBSCall.CCBSReference = cc_record->mode.ptmp.reference_id;
06637       }
06638       AST_LIST_UNLOCK(&misdn_cc_records_db);
06639 
06640       ast_channel_exten_set(ast, newbc->dialed.number);
06641 
06642       chan_misdn_log(1, port, "* Call completion to: %s\n", newbc->dialed.number);
06643       chan_misdn_log(2, port, " --> * tech:%s context:%s\n", ast_channel_name(ast), ast_channel_context(ast));
06644    } else
06645 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
06646    {
06647       struct ast_party_id connected_id = ast_channel_connected_effective_id(ast);
06648 
06649       /*
06650        * dest is ---v
06651        * Dial(mISDN/g:group_name[/extension[/options]])
06652        * Dial(mISDN/port[:preselected_channel][/extension[/options]])
06653        *
06654        * The dial extension could be empty if you are using MISDN_KEYPAD
06655        * to control ISDN provider features.
06656        */
06657       dest_cp = ast_strdupa(dest);
06658       AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');
06659       if (!args.ext) {
06660          args.ext = "";
06661       }
06662 
06663       chan_misdn_log(1, port, "* CALL: %s\n", dest);
06664       chan_misdn_log(2, port, " --> * dialed:%s tech:%s context:%s\n", args.ext, ast_channel_name(ast), ast_channel_context(ast));
06665 
06666       ast_channel_exten_set(ast, args.ext);
06667       ast_copy_string(newbc->dialed.number, args.ext, sizeof(newbc->dialed.number));
06668 
06669       if (ast_strlen_zero(newbc->caller.name)
06670          && connected_id.name.valid
06671          && !ast_strlen_zero(connected_id.name.str)) {
06672          ast_copy_string(newbc->caller.name, connected_id.name.str, sizeof(newbc->caller.name));
06673          chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number);
06674       }
06675       if (ast_strlen_zero(newbc->caller.number)
06676          && connected_id.number.valid
06677          && !ast_strlen_zero(connected_id.number.str)) {
06678          ast_copy_string(newbc->caller.number, connected_id.number.str, sizeof(newbc->caller.number));
06679          chan_misdn_log(3, port, " --> * set caller:\"%s\" <%s>\n", newbc->caller.name, newbc->caller.number);
06680       }
06681 
06682       misdn_cfg_get(port, MISDN_CFG_APPEND_MSN_TO_CALLERID_TAG, &append_msn, sizeof(append_msn));
06683       if (append_msn) {
06684          strncat(newbc->incoming_cid_tag, "_", sizeof(newbc->incoming_cid_tag) - strlen(newbc->incoming_cid_tag) - 1);
06685          strncat(newbc->incoming_cid_tag, newbc->caller.number, sizeof(newbc->incoming_cid_tag) - strlen(newbc->incoming_cid_tag) - 1);
06686       }
06687 
06688       ast_channel_caller(ast)->id.tag = ast_strdup(newbc->incoming_cid_tag);
06689 
06690       misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &number_type, sizeof(number_type));
06691       if (number_type < 0) {
06692          if (connected_id.number.valid) {
06693             newbc->caller.number_type = ast_to_misdn_ton(connected_id.number.plan);
06694             newbc->caller.number_plan = ast_to_misdn_plan(connected_id.number.plan);
06695          } else {
06696             newbc->caller.number_type = NUMTYPE_UNKNOWN;
06697             newbc->caller.number_plan = NUMPLAN_ISDN;
06698          }
06699       } else {
06700          /* Force us to send in SETUP message */
06701          newbc->caller.number_type = number_type;
06702          newbc->caller.number_plan = NUMPLAN_ISDN;
06703       }
06704       debug_numtype(port, newbc->caller.number_type, "LTON");
06705 
06706       newbc->capability = ast_channel_transfercapability(ast);
06707       pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY", ast_transfercapability2str(newbc->capability));
06708       if (ast_channel_transfercapability(ast) == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) {
06709          chan_misdn_log(2, port, " --> * Call with flag Digital\n");
06710       }
06711 
06712       /* update caller screening and presentation */
06713       update_config(ch);
06714 
06715       /* fill in some ies from channel dialplan variables */
06716       import_ch(ast, newbc, ch);
06717 
06718       /* Finally The Options Override Everything */
06719       if (!ast_strlen_zero(args.opts)) {
06720          misdn_set_opt_exec(ast, args.opts);
06721       } else {
06722          chan_misdn_log(2, port, "NO OPTS GIVEN\n");
06723       }
06724       if (newbc->set_presentation) {
06725          newbc->caller.presentation = newbc->presentation;
06726       }
06727 
06728       misdn_copy_redirecting_from_ast(newbc, ast);
06729       switch (newbc->outgoing_colp) {
06730       case 1:/* restricted */
06731       case 2:/* blocked */
06732          newbc->redirecting.from.presentation = 1;/* restricted */
06733          break;
06734       default:
06735          break;
06736       }
06737 #if defined(AST_MISDN_ENHANCEMENTS)
06738       if (newbc->redirecting.from.number[0] && misdn_lib_is_ptp(port)) {
06739          if (newbc->redirecting.count < 1) {
06740             newbc->redirecting.count = 1;
06741          }
06742 
06743          /* Create DivertingLegInformation2 facility */
06744          newbc->fac_out.Function = Fac_DivertingLegInformation2;
06745          newbc->fac_out.u.DivertingLegInformation2.InvokeID = ++misdn_invoke_id;
06746          newbc->fac_out.u.DivertingLegInformation2.DivertingPresent = 1;
06747          misdn_PresentedNumberUnscreened_fill(
06748             &newbc->fac_out.u.DivertingLegInformation2.Diverting,
06749             &newbc->redirecting.from);
06750          switch (newbc->outgoing_colp) {
06751          case 2:/* blocked */
06752             /* Block the number going out */
06753             newbc->fac_out.u.DivertingLegInformation2.Diverting.Type = 1;/* presentationRestricted */
06754 
06755             /* Don't tell about any previous diversions or why for that matter. */
06756             newbc->fac_out.u.DivertingLegInformation2.DiversionCounter = 1;
06757             newbc->fac_out.u.DivertingLegInformation2.DiversionReason = 0;/* unknown */
06758             break;
06759          default:
06760             newbc->fac_out.u.DivertingLegInformation2.DiversionCounter =
06761                newbc->redirecting.count;
06762             newbc->fac_out.u.DivertingLegInformation2.DiversionReason =
06763                misdn_to_diversion_reason(newbc->redirecting.reason);
06764             break;
06765          }
06766          newbc->fac_out.u.DivertingLegInformation2.OriginalCalledPresent = 0;
06767          if (1 < newbc->fac_out.u.DivertingLegInformation2.DiversionCounter) {
06768             newbc->fac_out.u.DivertingLegInformation2.OriginalCalledPresent = 1;
06769             newbc->fac_out.u.DivertingLegInformation2.OriginalCalled.Type = 2;/* numberNotAvailableDueToInterworking */
06770          }
06771 
06772          /*
06773           * Expect a DivertingLegInformation3 to update the COLR of the
06774           * redirecting-to party we are attempting to call now.
06775           */
06776          newbc->div_leg_3_rx_wanted = 1;
06777       }
06778 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
06779    }
06780 
06781    exceed = add_out_calls(port);
06782    if (exceed != 0) {
06783       char tmp[16];
06784 
06785       snprintf(tmp, sizeof(tmp), "%d", exceed);
06786       pbx_builtin_setvar_helper(ast, "MAX_OVERFLOW", tmp);
06787       ast_channel_hangupcause_set(ast, AST_CAUSE_NORMAL_TEMPORARY_FAILURE);
06788       ast_setstate(ast, AST_STATE_DOWN);
06789       return -1;
06790    }
06791 
06792 #if defined(AST_MISDN_ENHANCEMENTS)
06793    if (newbc->fac_out.Function != Fac_None) {
06794       print_facility(&newbc->fac_out, newbc);
06795    }
06796 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
06797    r = misdn_lib_send_event(newbc, EVENT_SETUP);
06798 
06799    /** we should have l3id after sending setup **/
06800    ch->l3id = newbc->l3_id;
06801 
06802    if (r == -ENOCHAN) {
06803       chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n");
06804       chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n", newbc ? newbc->pid : -1);
06805       ast_channel_hangupcause_set(ast, AST_CAUSE_NORMAL_CIRCUIT_CONGESTION);
06806       ast_setstate(ast, AST_STATE_DOWN);
06807       return -1;
06808    }
06809 
06810    chan_misdn_log(2, port, " --> * SEND: State Dialing pid:%d\n", newbc ? newbc->pid : 1);
06811 
06812    ast_setstate(ast, AST_STATE_DIALING);
06813    ast_channel_hangupcause_set(ast, AST_CAUSE_NORMAL_CLEARING);
06814 
06815    if (newbc->nt) {
06816       stop_bc_tones(ch);
06817    }
06818 
06819    ch->state = MISDN_CALLING;
06820 
06821    return 0;
06822 }
06823 
06824 
06825 static int misdn_answer(struct ast_channel *ast)
06826 {
06827    struct chan_list *p;
06828    const char *tmp;
06829 
06830    if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
06831       return -1;
06832    }
06833 
06834    chan_misdn_log(1, p ? (p->bc ? p->bc->port : 0) : 0, "* ANSWER:\n");
06835 
06836    if (!p) {
06837       ast_log(LOG_WARNING, " --> Channel not connected ??\n");
06838       ast_queue_hangup_with_cause(ast, AST_CAUSE_NETWORK_OUT_OF_ORDER);
06839    }
06840 
06841    if (!p->bc) {
06842       chan_misdn_log(1, 0, " --> Got Answer, but there is no bc obj ??\n");
06843 
06844       ast_queue_hangup_with_cause(ast, AST_CAUSE_PROTOCOL_ERROR);
06845    }
06846 
06847    ast_channel_lock(ast);
06848    tmp = pbx_builtin_getvar_helper(ast, "CRYPT_KEY");
06849    if (!ast_strlen_zero(tmp)) {
06850       chan_misdn_log(1, p->bc->port, " --> Connection will be BF crypted\n");
06851       ast_copy_string(p->bc->crypt_key, tmp, sizeof(p->bc->crypt_key));
06852    } else {
06853       chan_misdn_log(3, p->bc->port, " --> Connection is without BF encryption\n");
06854    }
06855 
06856    tmp = pbx_builtin_getvar_helper(ast, "MISDN_DIGITAL_TRANS");
06857    if (!ast_strlen_zero(tmp) && ast_true(tmp)) {
06858       chan_misdn_log(1, p->bc->port, " --> Connection is transparent digital\n");
06859       p->bc->nodsp = 1;
06860       p->bc->hdlc = 0;
06861       p->bc->nojitter = 1;
06862    }
06863    ast_channel_unlock(ast);
06864 
06865    p->state = MISDN_CONNECTED;
06866    stop_indicate(p);
06867 
06868    if (ast_strlen_zero(p->bc->connected.number)) {
06869       chan_misdn_log(2,p->bc->port," --> empty connected number using dialed number\n");
06870       ast_copy_string(p->bc->connected.number, p->bc->dialed.number, sizeof(p->bc->connected.number));
06871 
06872       /*
06873        * Use the misdn_set_opt() application to set the presentation
06874        * before we answer or you can use the CONECTEDLINE() function
06875        * to set everything before using the Answer() application.
06876        */
06877       p->bc->connected.presentation = p->bc->presentation;
06878       p->bc->connected.screening = 0;  /* unscreened */
06879       p->bc->connected.number_type = p->bc->dialed.number_type;
06880       p->bc->connected.number_plan = p->bc->dialed.number_plan;
06881    }
06882 
06883    switch (p->bc->outgoing_colp) {
06884    case 1:/* restricted */
06885    case 2:/* blocked */
06886       p->bc->connected.presentation = 1;/* restricted */
06887       break;
06888    default:
06889       break;
06890    }
06891 
06892 #if defined(AST_MISDN_ENHANCEMENTS)
06893    if (p->bc->div_leg_3_tx_pending) {
06894       p->bc->div_leg_3_tx_pending = 0;
06895 
06896       /* Send DivertingLegInformation3 */
06897       p->bc->fac_out.Function = Fac_DivertingLegInformation3;
06898       p->bc->fac_out.u.DivertingLegInformation3.InvokeID = ++misdn_invoke_id;
06899       p->bc->fac_out.u.DivertingLegInformation3.PresentationAllowedIndicator =
06900          (p->bc->connected.presentation == 0) ? 1 : 0;
06901       print_facility(&p->bc->fac_out, p->bc);
06902    }
06903 #endif   /* defined(AST_MISDN_ENHANCEMENTS) */
06904    misdn_lib_send_event(p->bc, EVENT_CONNECT);
06905    start_bc_tones(p);
06906 
06907    return 0;
06908 }
06909 
06910 static int misdn_digit_begin(struct ast_channel *chan, char digit)
06911 {
06912    /* XXX Modify this callback to support Asterisk controlling the length of DTMF */
06913    return 0;
06914 }
06915 
06916 static int misdn_digit_end(struct ast_channel *ast, char digit, unsigned int duration)
06917 {
06918    struct chan_list *p;
06919    struct misdn_bchannel *bc;
06920    char buf[2] = { digit, 0 };
06921 
06922    if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
06923       return -1;
06924    }
06925 
06926    bc = p->bc;
06927    chan_misdn_log(1, bc ? bc->port : 0, "* IND : Digit %c\n", digit);
06928 
06929    if (!bc) {
06930       ast_log(LOG_WARNING, " --> !! Got Digit Event without having bchannel Object\n");
06931       return -1;
06932    }
06933 
06934    switch (p->state) {
06935    case MISDN_CALLING:
06936       if (strlen(bc->infos_pending) < sizeof(bc->infos_pending) - 1) {
06937          strncat(bc->infos_pending, buf, sizeof(bc->infos_pending) - strlen(bc->infos_pending) - 1);
06938       }
06939       break;
06940    case MISDN_CALLING_ACKNOWLEDGE:
06941       ast_copy_string(bc->info_dad, buf, sizeof(bc->info_dad));
06942       if (strlen(bc->dialed.number) < sizeof(bc->dialed.number) - 1) {
06943          strncat(bc->dialed.number, buf, sizeof(bc->dialed.number) - strlen(bc->dialed.number) - 1);
06944       }
06945       ast_channel_exten_set(p->ast, bc->dialed.number);
06946       misdn_lib_send_event(bc, EVENT_INFORMATION);
06947       break;
06948    default:
06949       if (bc->send_dtmf) {
06950          send_digit_to_chan(p, digit);
06951       }
06952       break;
06953    }
06954 
06955    return 0;
06956 }
06957 
06958 
06959 static int misdn_fixup(struct ast_channel *oldast, struct ast_channel *ast)
06960 {
06961    struct chan_list *p;
06962 
06963    if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
06964       return -1;
06965    }
06966 
06967    chan_misdn_log(1, p->bc ? p->bc->port : 0, "* IND: Got Fixup State:%s L3id:%x\n", misdn_get_ch_state(p), p->l3id);
06968 
06969    p->ast = ast;
06970 
06971    return 0;
06972 }
06973 
06974 
06975 
06976 static int misdn_indication(struct ast_channel *ast, int cond, const void *data, size_t datalen)
06977 {
06978    struct chan_list *p;
06979 
06980    if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
06981       ast_log(LOG_WARNING, "Returned -1 in misdn_indication\n");
06982       return -1;
06983    }
06984 
06985    if (!p->bc) {
06986       if (p->hold.state == MISDN_HOLD_IDLE) {
06987          chan_misdn_log(1, 0, "* IND : Indication [%d] ignored on %s\n", cond,
06988             ast_channel_name(ast));
06989          ast_log(LOG_WARNING, "Private Pointer but no bc ?\n");
06990       } else {
06991          chan_misdn_log(1, 0, "* IND : Indication [%d] ignored on hold %s\n",
06992             cond, ast_channel_name(ast));
06993       }
06994       return -1;
06995    }
06996 
06997    chan_misdn_log(5, p->bc->port, "* IND : Indication [%d] on %s\n", cond, ast_channel_name(ast));
06998 
06999    switch (cond) {
07000    case AST_CONTROL_BUSY:
07001       chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc->pid);
07002       ast_setstate(ast, AST_STATE_BUSY);
07003 
07004       p->bc->out_cause