Opaquify ast_channel structs and lists
[asterisk/asterisk.git] / channels / chan_misdn.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 2004 - 2006, Christian Richter
5  *
6  * Christian Richter <crich@beronet.com>
7  *
8  * See http://www.asterisk.org for more information about
9  * the Asterisk project. Please do not directly contact
10  * any of the maintainers of this project for assistance;
11  * the project provides a web site, mailing lists and IRC
12  * channels for your use.
13  *
14  * This program is free software, distributed under the terms of
15  * the GNU General Public License Version 2. See the LICENSE file
16  * at the top of the source tree.
17  *
18  */
19
20 /*!
21  * \file
22  *
23  * \brief the chan_misdn channel driver for Asterisk
24  *
25  * \author Christian Richter <crich@beronet.com>
26  *
27  * \extref MISDN http://www.misdn.org/
28  *
29  * \ingroup channel_drivers
30  */
31
32 /*!
33  * \note
34  * To use the CCBS/CCNR supplementary service feature and other
35  * supplementary services using FACILITY messages requires a
36  * modified version of mISDN.
37  *
38  * \note
39  * The latest modified mISDN v1.1.x based version is available at:
40  * http://svn.digium.com/svn/thirdparty/mISDN/trunk
41  * http://svn.digium.com/svn/thirdparty/mISDNuser/trunk
42  *
43  * \note
44  * Taged versions of the modified mISDN code are available under:
45  * http://svn.digium.com/svn/thirdparty/mISDN/tags
46  * http://svn.digium.com/svn/thirdparty/mISDNuser/tags
47  */
48
49 /* Define to enable cli commands to generate canned CCBS messages. */
50 // #define CCBS_TEST_MESSAGES   1
51
52 /*** MODULEINFO
53         <depend>isdnnet</depend>
54         <depend>misdn</depend>
55         <depend>suppserv</depend>
56         <support_level>extended</support_level>
57  ***/
58 #include "asterisk.h"
59
60 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
61
62 #include <pthread.h>
63 #include <sys/socket.h>
64 #include <sys/time.h>
65 #include <arpa/inet.h>
66 #include <fcntl.h>
67 #include <sys/ioctl.h>
68 #include <signal.h>
69 #include <sys/file.h>
70 #include <semaphore.h>
71 #include <ctype.h>
72 #include <time.h>
73
74 #include "asterisk/channel.h"
75 #include "asterisk/config.h"
76 #include "asterisk/module.h"
77 #include "asterisk/pbx.h"
78 #include "asterisk/io.h"
79 #include "asterisk/frame.h"
80 #include "asterisk/translate.h"
81 #include "asterisk/cli.h"
82 #include "asterisk/musiconhold.h"
83 #include "asterisk/dsp.h"
84 #include "asterisk/file.h"
85 #include "asterisk/callerid.h"
86 #include "asterisk/indications.h"
87 #include "asterisk/app.h"
88 #include "asterisk/features.h"
89 #include "asterisk/term.h"
90 #include "asterisk/sched.h"
91 #include "asterisk/stringfields.h"
92 #include "asterisk/abstract_jb.h"
93 #include "asterisk/causes.h"
94 #include "asterisk/format.h"
95 #include "asterisk/format_cap.h"
96
97 #include "chan_misdn_config.h"
98 #include "isdn_lib.h"
99
100 static char global_tracefile[BUFFERSIZE + 1];
101
102 static int g_config_initialized = 0;
103
104 struct misdn_jb{
105         int size;
106         int upper_threshold;
107         char *samples, *ok;
108         int wp,rp;
109         int state_empty;
110         int state_full;
111         int state_buffer;
112         int bytes_wrote;
113         ast_mutex_t mutexjb;
114 };
115
116 /*! \brief allocates the jb-structure and initialize the elements */
117 struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
118
119 /*! \brief frees the data and destroys the given jitterbuffer struct */
120 void misdn_jb_destroy(struct misdn_jb *jb);
121
122 /*! \brief fills the jitterbuffer with len data returns < 0 if there was an
123 error (buffer overrun). */
124 int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len);
125
126 /*! \brief gets len bytes out of the jitterbuffer if available, else only the
127 available data is returned and the return value indicates the number
128 of data. */
129 int misdn_jb_empty(struct misdn_jb *jb, char *data, int len);
130
131 static char *complete_ch(struct ast_cli_args *a);
132 static char *complete_debug_port(struct ast_cli_args *a);
133 static char *complete_show_config(struct ast_cli_args *a);
134
135 /* BEGIN: chan_misdn.h */
136
137 #if defined(AST_MISDN_ENHANCEMENTS)
138 /*
139  * This timeout duration is to clean up any call completion records that
140  * are forgotten about by the switch.
141  */
142 #define MISDN_CC_RECORD_AGE_MAX         (6UL * 60 * 60) /* seconds */
143
144 #define MISDN_CC_REQUEST_WAIT_MAX       5       /* seconds */
145
146 /*!
147  * \brief Caller that initialized call completion services
148  *
149  * \details
150  * This data is the payload for a datastore that is put on the channel that
151  * initializes call completion services.  This datastore is set to be inherited
152  * by the outbound mISDN channel.  When one of these channels hangs up, the
153  * channel pointer will be set to NULL.  That way, we can ensure that we do not
154  * touch this channel after it gets destroyed.
155  */
156 struct misdn_cc_caller {
157         /*! \brief The channel that initialized call completion services */
158         struct ast_channel *chan;
159 };
160
161 struct misdn_cc_notify {
162         /*! \brief Dialplan: Notify extension priority */
163         int priority;
164
165         /*! \brief Dialplan: Notify extension context */
166         char context[AST_MAX_CONTEXT];
167
168         /*! \brief Dialplan: Notify extension number (User-A) */
169         char exten[AST_MAX_EXTENSION];
170 };
171
172 /*! \brief mISDN call completion record */
173 struct misdn_cc_record {
174         /*! \brief Call completion record linked list */
175         AST_LIST_ENTRY(misdn_cc_record) list;
176
177         /*! \brief Time the record was created. */
178         time_t time_created;
179
180         /*! \brief MISDN_CC_RECORD_ID value */
181         long record_id;
182
183         /*!
184          * \brief Logical Layer 1 port associated with this
185          * call completion record
186          */
187         int port;
188
189         /*! \brief TRUE if point-to-point mode (CCBS-T/CCNR-T mode) */
190         int ptp;
191
192         /*! \brief Mode specific parameters */
193         union {
194                 /*! \brief point-to-point specific parameters. */
195                 struct {
196                         /*!
197                          * \brief Call-completion signaling link.
198                          * NULL if signaling link not established.
199                          */
200                         struct misdn_bchannel *bc;
201
202                         /*!
203                          * \brief TRUE if we requested the request retention option
204                          * to be enabled.
205                          */
206                         int requested_retention;
207
208                         /*!
209                          * \brief TRUE if the request retention option is enabled.
210                          */
211                         int retention_enabled;
212                 } ptp;
213
214                 /*! \brief point-to-multi-point specific parameters. */
215                 struct {
216                         /*! \brief CallLinkageID (valid when port determined) */
217                         int linkage_id;
218
219                         /*! \breif CCBSReference (valid when activated is TRUE) */
220                         int reference_id;
221
222                         /*! \brief globalRecall(0),     specificRecall(1) */
223                         int recall_mode;
224                 } ptmp;
225         } mode;
226
227         /*! \brief TRUE if call completion activated */
228         int activated;
229
230         /*! \brief Outstanding message ID (valid when outstanding_message) */
231         int invoke_id;
232
233         /*! \brief TRUE if waiting for a response from a message (invoke_id is valid) */
234         int outstanding_message;
235
236         /*! \brief TRUE if activation has been requested */
237         int activation_requested;
238
239         /*!
240          * \brief TRUE if User-A is free
241          * \note PTMP - Used to answer CCBSStatusRequest.
242          * PTP - Determines how to respond to CCBS_T_RemoteUserFree.
243          */
244         int party_a_free;
245
246         /*! \brief Error code received from last outstanding message. */
247         enum FacErrorCode error_code;
248
249         /*! \brief Reject code received from last outstanding message. */
250         enum FacRejectCode reject_code;
251
252         /*!
253          * \brief Saved struct misdn_bchannel call information when
254          * attempted to call User-B
255          */
256         struct {
257                 /*! \brief User-A caller id information */
258                 struct misdn_party_id caller;
259
260                 /*! \brief User-B number information */
261                 struct misdn_party_dialing dialed;
262
263                 /*! \brief The BC, HLC (optional) and LLC (optional) contents from the SETUP message. */
264                 struct Q931_Bc_Hlc_Llc setup_bc_hlc_llc;
265
266                 /*! \brief SETUP message bearer capability field code value */
267                 int capability;
268
269                 /*! \brief TRUE if call made in digital HDLC mode */
270                 int hdlc;
271         } redial;
272
273         /*! \brief Dialplan location to indicate User-B free and User-A is free */
274         struct misdn_cc_notify remote_user_free;
275
276         /*! \brief Dialplan location to indicate User-B free and User-A is busy */
277         struct misdn_cc_notify b_free;
278 };
279
280 /*! \brief mISDN call completion record database */
281 static AST_LIST_HEAD_STATIC(misdn_cc_records_db, misdn_cc_record);
282 /*! \brief Next call completion record ID to use */
283 static __u16 misdn_cc_record_id;
284 /*! \brief Next invoke ID to use */
285 static __s16 misdn_invoke_id;
286
287 static const char misdn_no_response_from_network[] = "No response from network";
288 static const char misdn_cc_record_not_found[] = "Call completion record not found";
289
290 /* mISDN channel variable names */
291 #define MISDN_CC_RECORD_ID      "MISDN_CC_RECORD_ID"
292 #define MISDN_CC_STATUS         "MISDN_CC_STATUS"
293 #define MISDN_ERROR_MSG         "MISDN_ERROR_MSG"
294 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
295
296 static ast_mutex_t release_lock;
297
298 enum misdn_chan_state {
299         MISDN_NOTHING = 0,         /*!< at beginning */
300         MISDN_WAITING4DIGS,        /*!< when waiting for info */
301         MISDN_EXTCANTMATCH,        /*!< when asterisk couldn't match our ext */
302         MISDN_INCOMING_SETUP,      /*!< for incoming setup */
303         MISDN_DIALING,             /*!< when pbx_start */
304         MISDN_PROGRESS,            /*!< we have progress */
305         MISDN_PROCEEDING,          /*!< we have progress */
306         MISDN_CALLING,             /*!< when misdn_call is called */
307         MISDN_CALLING_ACKNOWLEDGE, /*!< when we get SETUP_ACK */
308         MISDN_ALERTING,            /*!< when Alerting */
309         MISDN_BUSY,                /*!< when BUSY */
310         MISDN_CONNECTED,           /*!< when connected */
311         MISDN_DISCONNECTED,        /*!< when connected */
312         MISDN_CLEANING,            /*!< when hangup from * but we were connected before */
313 };
314
315 /*! Asterisk created the channel (outgoing call) */
316 #define ORG_AST 1
317 /*! mISDN created the channel (incoming call) */
318 #define ORG_MISDN 2
319
320 enum misdn_hold_state {
321         MISDN_HOLD_IDLE,                /*!< HOLD not active */
322         MISDN_HOLD_ACTIVE,              /*!< Call is held */
323         MISDN_HOLD_TRANSFER,    /*!< Held call is being transferred */
324         MISDN_HOLD_DISCONNECT,  /*!< Held call is being disconnected */
325 };
326 struct hold_info {
327         /*!
328          * \brief Call HOLD state.
329          */
330         enum misdn_hold_state state;
331         /*!
332          * \brief Logical port the channel call record is HELD on
333          * because the B channel is no longer associated.
334          */
335         int port;
336
337         /*!
338          * \brief Original B channel number the HELD call was using.
339          * \note Used only for debug display messages.
340          */
341         int channel;
342 };
343
344 #define chan_list_ref(obj, debug) (ao2_t_ref((obj), +1, (debug)), (obj))
345 #define chan_list_unref(obj, debug) (ao2_t_ref((obj), -1, (debug)), NULL)
346
347 /*!
348  * \brief Channel call record structure
349  */
350 struct chan_list {
351         /*!
352          * \brief The "allowed_bearers" string read in from /etc/asterisk/misdn.conf
353          */
354         char allowed_bearers[BUFFERSIZE + 1];
355
356         /*!
357          * \brief State of the channel
358          */
359         enum misdn_chan_state state;
360
361         /*!
362          * \brief TRUE if a hangup needs to be queued
363          * \note This is a debug flag only used to catch calls to hangup_chan() that are already hungup.
364          */
365         int need_queue_hangup;
366
367         /*!
368          * \brief TRUE if a channel can be hung up by calling asterisk directly when done.
369          */
370         int need_hangup;
371
372         /*!
373          * \brief TRUE if we could send an AST_CONTROL_BUSY if needed.
374          */
375         int need_busy;
376
377         /*!
378          * \brief Who originally created this channel. ORG_AST or ORG_MISDN
379          */
380         int originator;
381
382         /*!
383          * \brief TRUE of we are not to respond immediately to a SETUP message.  Check the dialplan first.
384          * \note The "noautorespond_on_setup" boolean read in from /etc/asterisk/misdn.conf
385          */
386         int noautorespond_on_setup;
387
388         int norxtone;   /*!< Boolean assigned values but the value is not used. */
389
390         /*!
391          * \brief TRUE if we are not to generate tones (Playtones)
392          */
393         int notxtone;
394
395         /*!
396          * \brief TRUE if echo canceller is enabled.  Value is toggled.
397          */
398         int toggle_ec;
399
400         /*!
401          * \brief TRUE if you want to send Tone Indications to an incoming
402          * ISDN channel on a TE Port.
403          * \note The "incoming_early_audio" boolean read in from /etc/asterisk/misdn.conf
404          */
405         int incoming_early_audio;
406
407         /*!
408          * \brief TRUE if DTMF digits are to be passed inband only.
409          * \note It is settable by the misdn_set_opt() application.
410          */
411         int ignore_dtmf;
412
413         /*!
414          * \brief Pipe file descriptor handles array.
415          * Read from pipe[0], write to pipe[1]
416          */
417         int pipe[2];
418
419         /*!
420          * \brief Read buffer for inbound audio from pipe[0]
421          */
422         char ast_rd_buf[4096];
423
424         /*!
425          * \brief Inbound audio frame returned by misdn_read().
426          */
427         struct ast_frame frame;
428
429         /*!
430          * \brief Fax detection option. (0:no 1:yes 2:yes+nojump)
431          * \note The "faxdetect" option string read in from /etc/asterisk/misdn.conf
432          * \note It is settable by the misdn_set_opt() application.
433          */
434         int faxdetect;
435
436         /*!
437          * \brief Number of seconds to detect a Fax machine when detection enabled.
438          * \note 0 disables the timeout.
439          * \note The "faxdetect_timeout" value read in from /etc/asterisk/misdn.conf
440          */
441         int faxdetect_timeout;
442
443         /*!
444          * \brief Starting time of fax detection with timeout when nonzero.
445          */
446         struct timeval faxdetect_tv;
447
448         /*!
449          * \brief TRUE if a fax has been detected.
450          */
451         int faxhandled;
452
453         /*!
454          * \brief TRUE if we will use the Asterisk DSP to detect DTMF/Fax
455          * \note The "astdtmf" boolean read in from /etc/asterisk/misdn.conf
456          */
457         int ast_dsp;
458
459         /*!
460          * \brief Jitterbuffer length
461          * \note The "jitterbuffer" value read in from /etc/asterisk/misdn.conf
462          */
463         int jb_len;
464
465         /*!
466          * \brief Jitterbuffer upper threshold
467          * \note The "jitterbuffer_upper_threshold" value read in from /etc/asterisk/misdn.conf
468          */
469         int jb_upper_threshold;
470
471         /*!
472          * \brief Allocated jitterbuffer controller
473          * \note misdn_jb_init() creates the jitterbuffer.
474          * \note Must use misdn_jb_destroy() to clean up.
475          */
476         struct misdn_jb *jb;
477
478         /*!
479          * \brief Allocated DSP controller
480          * \note ast_dsp_new() creates the DSP controller.
481          * \note Must use ast_dsp_free() to clean up.
482          */
483         struct ast_dsp *dsp;
484
485         /*!
486          * \brief Associated Asterisk channel structure.
487          */
488         struct ast_channel * ast;
489
490         /*!
491          * \brief Associated B channel structure.
492          */
493         struct misdn_bchannel *bc;
494
495 #if defined(AST_MISDN_ENHANCEMENTS)
496         /*!
497          * \brief Peer channel for which call completion was initialized.
498          */
499         struct misdn_cc_caller *peer;
500
501         /*! \brief Associated call completion record ID (-1 if not associated) */
502         long record_id;
503 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
504
505         /*!
506          * \brief HELD channel call information
507          */
508         struct hold_info hold;
509
510         /*!
511          * \brief From associated B channel: Layer 3 process ID
512          * \note Used to find the HELD channel call record when retrieving a call.
513          */
514         unsigned int l3id;
515
516         /*!
517          * \brief From associated B channel: B Channel mISDN driver layer ID from mISDN_get_layerid()
518          * \note Used only for debug display messages.
519          */
520         int addr;
521
522         /*!
523          * \brief Incoming call dialplan context identifier.
524          * \note The "context" string read in from /etc/asterisk/misdn.conf
525          */
526         char context[AST_MAX_CONTEXT];
527
528         /*!
529          * \brief The configured music-on-hold class to use for this call.
530          * \note The "musicclass" string read in from /etc/asterisk/misdn.conf
531          */
532         char mohinterpret[MAX_MUSICCLASS];
533
534         /*!
535          * \brief Number of outgoing audio frames dropped since last debug gripe message.
536          */
537         int dropped_frame_cnt;
538
539         /*!
540          * \brief TRUE if we must do the ringback tones.
541          * \note The "far_alerting" boolean read in from /etc/asterisk/misdn.conf
542          */
543         int far_alerting;
544
545         /*!
546          * \brief TRUE if NT should disconnect an overlap dialing call when a timeout occurs.
547          * \note The "nttimeout" boolean read in from /etc/asterisk/misdn.conf
548          */
549         int nttimeout;
550
551         /*!
552          * \brief Tone zone sound used for dialtone generation.
553          * \note Used as a boolean.  Non-NULL to prod generation if enabled.
554          */
555         struct ast_tone_zone_sound *ts;
556
557         /*!
558          * \brief Enables overlap dialing for the set amount of seconds.  (0 = Disabled)
559          * \note The "overlapdial" value read in from /etc/asterisk/misdn.conf
560          */
561         int overlap_dial;
562
563         /*!
564          * \brief Overlap dialing timeout Task ID.  -1 if not running.
565          */
566         int overlap_dial_task;
567
568         /*!
569          * \brief overlap_tv access lock.
570          */
571         ast_mutex_t overlap_tv_lock;
572
573         /*!
574          * \brief Overlap timer start time.  Timer restarted for every digit received.
575          */
576         struct timeval overlap_tv;
577
578         /*!
579          * \brief Next channel call record in the list.
580          */
581         struct chan_list *next;
582 };
583
584
585 int MAXTICS = 8;
586
587
588 void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
589 void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
590 static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame);
591
592 struct robin_list {
593         char *group;
594         int port;
595         int channel;
596         struct robin_list *next;
597         struct robin_list *prev;
598 };
599 static struct robin_list *robin = NULL;
600
601
602 static void free_robin_list(void)
603 {
604         struct robin_list *r;
605         struct robin_list *next;
606
607         for (r = robin, robin = NULL; r; r = next) {
608                 next = r->next;
609                 ast_free(r->group);
610                 ast_free(r);
611         }
612 }
613
614 static struct robin_list *get_robin_position(char *group)
615 {
616         struct robin_list *new;
617         struct robin_list *iter = robin;
618         for (; iter; iter = iter->next) {
619                 if (!strcasecmp(iter->group, group)) {
620                         return iter;
621                 }
622         }
623         new = ast_calloc(1, sizeof(*new));
624         if (!new) {
625                 return NULL;
626         }
627         new->group = ast_strdup(group);
628         if (!new->group) {
629                 ast_free(new);
630                 return NULL;
631         }
632         new->channel = 1;
633         if (robin) {
634                 new->next = robin;
635                 robin->prev = new;
636         }
637         robin = new;
638         return robin;
639 }
640
641
642 /*! \brief the main schedule context for stuff like l1 watcher, overlap dial, ... */
643 static struct ast_sched_context *misdn_tasks = NULL;
644 static pthread_t misdn_tasks_thread;
645
646 static int *misdn_ports;
647
648 static void chan_misdn_log(int level, int port, char *tmpl, ...)
649         __attribute__((format(printf, 3, 4)));
650
651 static struct ast_channel *misdn_new(struct chan_list *cl, int state,  char *exten, char *callerid, struct ast_format_cap *cap, const char *linkedid, int port, int c);
652 static void send_digit_to_chan(struct chan_list *cl, char digit);
653
654 static int pbx_start_chan(struct chan_list *ch);
655
656 #define MISDN_ASTERISK_TECH_PVT(ast) ast_channel_tech_pvt(ast)
657 #define MISDN_ASTERISK_TECH_PVT_SET(ast, value) ast_channel_tech_pvt_set(ast, value)
658
659 #include "asterisk/strings.h"
660
661 /* #define MISDN_DEBUG 1 */
662
663 static const char misdn_type[] = "mISDN";
664
665 static int tracing = 0;
666
667 /*! \brief Only alaw and mulaw is allowed for now */
668 static struct ast_format prefformat; /*  AST_FORMAT_SLINEAR ;  AST_FORMAT_ULAW | */
669
670 static int *misdn_debug;
671 static int *misdn_debug_only;
672 static int max_ports;
673
674 static int *misdn_in_calls;
675 static int *misdn_out_calls;
676
677 /*!
678  * \brief Global channel call record list head.
679  */
680 static struct chan_list *cl_te=NULL;
681 static ast_mutex_t cl_te_lock;
682
683 static enum event_response_e
684 cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);
685
686 static int send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch);
687
688 static void cl_queue_chan(struct chan_list *chan);
689
690 static int dialtone_indicate(struct chan_list *cl);
691 static void hanguptone_indicate(struct chan_list *cl);
692 static int stop_indicate(struct chan_list *cl);
693
694 static int start_bc_tones(struct chan_list *cl);
695 static int stop_bc_tones(struct chan_list *cl);
696 static void release_chan_early(struct chan_list *ch);
697 static void release_chan(struct chan_list *ch, struct misdn_bchannel *bc);
698
699 #if defined(AST_MISDN_ENHANCEMENTS)
700 static const char misdn_command_name[] = "misdn_command";
701 static int misdn_command_exec(struct ast_channel *chan, const char *data);
702 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
703 static int misdn_check_l2l1(struct ast_channel *chan, const char *data);
704 static int misdn_set_opt_exec(struct ast_channel *chan, const char *data);
705 static int misdn_facility_exec(struct ast_channel *chan, const char *data);
706
707 int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
708
709 void debug_numtype(int port, int numtype, char *type);
710
711 int add_out_calls(int port);
712 int add_in_calls(int port);
713
714
715 #ifdef MISDN_1_2
716 static int update_pipeline_config(struct misdn_bchannel *bc);
717 #else
718 static int update_ec_config(struct misdn_bchannel *bc);
719 #endif
720
721
722
723 /*************** Helpers *****************/
724
725 static int misdn_chan_is_valid(struct chan_list *ch)
726 {
727         struct chan_list *list;
728
729         ast_mutex_lock(&cl_te_lock);
730         for (list = cl_te; list; list = list->next) {
731                 if (list == ch) {
732                         ast_mutex_unlock(&cl_te_lock);
733                         return 1;
734                 }
735         }
736         ast_mutex_unlock(&cl_te_lock);
737
738         return 0;
739 }
740
741 /*! Returns a reference to the found chan_list. */
742 static struct chan_list *get_chan_by_ast(struct ast_channel *ast)
743 {
744         struct chan_list *tmp;
745
746         ast_mutex_lock(&cl_te_lock);
747         for (tmp = cl_te; tmp; tmp = tmp->next) {
748                 if (tmp->ast == ast) {
749                         chan_list_ref(tmp, "Found chan_list by ast");
750                         ast_mutex_unlock(&cl_te_lock);
751                         return tmp;
752                 }
753         }
754         ast_mutex_unlock(&cl_te_lock);
755
756         return NULL;
757 }
758
759 /*! Returns a reference to the found chan_list. */
760 static struct chan_list *get_chan_by_ast_name(const char *name)
761 {
762         struct chan_list *tmp;
763
764         ast_mutex_lock(&cl_te_lock);
765         for (tmp = cl_te; tmp; tmp = tmp->next) {
766                 if (tmp->ast && strcmp(ast_channel_name(tmp->ast), name) == 0) {
767                         chan_list_ref(tmp, "Found chan_list by ast name");
768                         ast_mutex_unlock(&cl_te_lock);
769                         return tmp;
770                 }
771         }
772         ast_mutex_unlock(&cl_te_lock);
773
774         return NULL;
775 }
776
777 #if defined(AST_MISDN_ENHANCEMENTS)
778 /*!
779  * \internal
780  * \brief Destroy the misdn_cc_ds_info datastore payload
781  *
782  * \param[in] data the datastore payload, a reference to an misdn_cc_caller
783  *
784  * \details
785  * Since the payload is a reference to an astobj2 object, we just decrement its
786  * reference count.  Before doing so, we NULL out the channel pointer inside of
787  * the misdn_cc_caller instance.  This function will be called in one of two
788  * cases.  In both cases, we no longer need the channel pointer:
789  *
790  *  - The original channel that initialized call completion services, the same
791  *    channel that is stored here, has been destroyed early.  This could happen
792  *    if it transferred the mISDN channel, for example.
793  *
794  *  - The mISDN channel that had this datastore inherited on to it is now being
795  *    destroyed.  If this is the case, then the call completion events have
796  *    already occurred and the appropriate channel variables have already been
797  *    set on the original channel that requested call completion services.
798  *
799  * \return Nothing
800  */
801 static void misdn_cc_ds_destroy(void *data)
802 {
803         struct misdn_cc_caller *cc_caller = data;
804
805         ao2_lock(cc_caller);
806         cc_caller->chan = NULL;
807         ao2_unlock(cc_caller);
808
809         ao2_ref(cc_caller, -1);
810 }
811 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
812
813 #if defined(AST_MISDN_ENHANCEMENTS)
814 /*!
815  * \internal
816  * \brief Duplicate the misdn_cc_ds_info datastore payload
817  *
818  * \param[in] data the datastore payload, a reference to an misdn_cc_caller
819  *
820  * \details
821  * All we need to do is bump the reference count and return the same instance.
822  *
823  * \return A reference to an instance of a misdn_cc_caller
824  */
825 static void *misdn_cc_ds_duplicate(void *data)
826 {
827         struct misdn_cc_caller *cc_caller = data;
828
829         ao2_ref(cc_caller, +1);
830
831         return cc_caller;
832 }
833 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
834
835 #if defined(AST_MISDN_ENHANCEMENTS)
836 static const struct ast_datastore_info misdn_cc_ds_info = {
837         .type      = "misdn_cc",
838         .destroy   = misdn_cc_ds_destroy,
839         .duplicate = misdn_cc_ds_duplicate,
840 };
841 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
842
843 #if defined(AST_MISDN_ENHANCEMENTS)
844 /*!
845  * \internal
846  * \brief Set a channel var on the peer channel for call completion services
847  *
848  * \param[in] peer The peer that initialized call completion services
849  * \param[in] var The variable name to set
850  * \param[in] value The variable value to set
851  *
852  * This function may be called from outside of the channel thread.  It handles
853  * the fact that the peer channel may be hung up and destroyed at any time.
854  *
855  * \return nothing
856  */
857 static void misdn_cc_set_peer_var(struct misdn_cc_caller *peer, const char *var,
858         const char *value)
859 {
860         ao2_lock(peer);
861
862         /*! \todo XXX This nastiness can go away once ast_channel is ref counted! */
863         while (peer->chan && ast_channel_trylock(peer->chan)) {
864                 ao2_unlock(peer);
865                 sched_yield();
866                 ao2_lock(peer);
867         }
868
869         if (peer->chan) {
870                 pbx_builtin_setvar_helper(peer->chan, var, value);
871                 ast_channel_unlock(peer->chan);
872         }
873
874         ao2_unlock(peer);
875 }
876 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
877
878 #if defined(AST_MISDN_ENHANCEMENTS)
879 /*!
880  * \internal
881  * \brief Get a reference to the CC caller if it exists
882  */
883 static struct misdn_cc_caller *misdn_cc_caller_get(struct ast_channel *chan)
884 {
885         struct ast_datastore *datastore;
886         struct misdn_cc_caller *cc_caller;
887
888         ast_channel_lock(chan);
889
890         if (!(datastore = ast_channel_datastore_find(chan, &misdn_cc_ds_info, NULL))) {
891                 ast_channel_unlock(chan);
892                 return NULL;
893         }
894
895         ao2_ref(datastore->data, +1);
896         cc_caller = datastore->data;
897
898         ast_channel_unlock(chan);
899
900         return cc_caller;
901 }
902 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
903
904 #if defined(AST_MISDN_ENHANCEMENTS)
905 /*!
906  * \internal
907  * \brief Find the call completion record given the record id.
908  *
909  * \param record_id
910  *
911  * \retval pointer to found call completion record
912  * \retval NULL if not found
913  *
914  * \note Assumes the misdn_cc_records_db lock is already obtained.
915  */
916 static struct misdn_cc_record *misdn_cc_find_by_id(long record_id)
917 {
918         struct misdn_cc_record *current;
919
920         AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
921                 if (current->record_id == record_id) {
922                         /* Found the record */
923                         break;
924                 }
925         }
926
927         return current;
928 }
929 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
930
931 #if defined(AST_MISDN_ENHANCEMENTS)
932 /*!
933  * \internal
934  * \brief Find the call completion record given the port and call linkage id.
935  *
936  * \param port Logical port number
937  * \param linkage_id Call linkage ID number from switch.
938  *
939  * \retval pointer to found call completion record
940  * \retval NULL if not found
941  *
942  * \note Assumes the misdn_cc_records_db lock is already obtained.
943  */
944 static struct misdn_cc_record *misdn_cc_find_by_linkage(int port, int linkage_id)
945 {
946         struct misdn_cc_record *current;
947
948         AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
949                 if (current->port == port
950                         && !current->ptp
951                         && current->mode.ptmp.linkage_id == linkage_id) {
952                         /* Found the record */
953                         break;
954                 }
955         }
956
957         return current;
958 }
959 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
960
961 #if defined(AST_MISDN_ENHANCEMENTS)
962 /*!
963  * \internal
964  * \brief Find the call completion record given the port and outstanding invocation id.
965  *
966  * \param port Logical port number
967  * \param invoke_id Outstanding message invocation ID number.
968  *
969  * \retval pointer to found call completion record
970  * \retval NULL if not found
971  *
972  * \note Assumes the misdn_cc_records_db lock is already obtained.
973  */
974 static struct misdn_cc_record *misdn_cc_find_by_invoke(int port, int invoke_id)
975 {
976         struct misdn_cc_record *current;
977
978         AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
979                 if (current->outstanding_message
980                         && current->invoke_id == invoke_id
981                         && current->port == port) {
982                         /* Found the record */
983                         break;
984                 }
985         }
986
987         return current;
988 }
989 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
990
991 #if defined(AST_MISDN_ENHANCEMENTS)
992 /*!
993  * \internal
994  * \brief Find the call completion record given the port and CCBS reference id.
995  *
996  * \param port Logical port number
997  * \param reference_id CCBS reference ID number from switch.
998  *
999  * \retval pointer to found call completion record
1000  * \retval NULL if not found
1001  *
1002  * \note Assumes the misdn_cc_records_db lock is already obtained.
1003  */
1004 static struct misdn_cc_record *misdn_cc_find_by_reference(int port, int reference_id)
1005 {
1006         struct misdn_cc_record *current;
1007
1008         AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
1009                 if (current->activated
1010                         && current->port == port
1011                         && !current->ptp
1012                         && current->mode.ptmp.reference_id == reference_id) {
1013                         /* Found the record */
1014                         break;
1015                 }
1016         }
1017
1018         return current;
1019 }
1020 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1021
1022 #if defined(AST_MISDN_ENHANCEMENTS)
1023 /*!
1024  * \internal
1025  * \brief Find the call completion record given the B channel pointer
1026  *
1027  * \param bc B channel control structure pointer.
1028  *
1029  * \retval pointer to found call completion record
1030  * \retval NULL if not found
1031  *
1032  * \note Assumes the misdn_cc_records_db lock is already obtained.
1033  */
1034 static struct misdn_cc_record *misdn_cc_find_by_bc(const struct misdn_bchannel *bc)
1035 {
1036         struct misdn_cc_record *current;
1037
1038         if (bc) {
1039                 AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
1040                         if (current->ptp
1041                                 && current->mode.ptp.bc == bc) {
1042                                 /* Found the record */
1043                                 break;
1044                         }
1045                 }
1046         } else {
1047                 current = NULL;
1048         }
1049
1050         return current;
1051 }
1052 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1053
1054 #if defined(AST_MISDN_ENHANCEMENTS)
1055 /*!
1056  * \internal
1057  * \brief Delete the given call completion record
1058  *
1059  * \param doomed Call completion record to destroy
1060  *
1061  * \return Nothing
1062  *
1063  * \note Assumes the misdn_cc_records_db lock is already obtained.
1064  */
1065 static void misdn_cc_delete(struct misdn_cc_record *doomed)
1066 {
1067         struct misdn_cc_record *current;
1068
1069         AST_LIST_TRAVERSE_SAFE_BEGIN(&misdn_cc_records_db, current, list) {
1070                 if (current == doomed) {
1071                         AST_LIST_REMOVE_CURRENT(list);
1072                         ast_free(current);
1073                         return;
1074                 }
1075         }
1076         AST_LIST_TRAVERSE_SAFE_END;
1077
1078         /* The doomed node is not in the call completion database */
1079 }
1080 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1081
1082 #if defined(AST_MISDN_ENHANCEMENTS)
1083 /*!
1084  * \internal
1085  * \brief Delete all old call completion records
1086  *
1087  * \return Nothing
1088  *
1089  * \note Assumes the misdn_cc_records_db lock is already obtained.
1090  */
1091 static void misdn_cc_remove_old(void)
1092 {
1093         struct misdn_cc_record *current;
1094         time_t now;
1095
1096         now = time(NULL);
1097         AST_LIST_TRAVERSE_SAFE_BEGIN(&misdn_cc_records_db, current, list) {
1098                 if (MISDN_CC_RECORD_AGE_MAX < now - current->time_created) {
1099                         if (current->ptp && current->mode.ptp.bc) {
1100                                 /* Close the old call-completion signaling link */
1101                                 current->mode.ptp.bc->fac_out.Function = Fac_None;
1102                                 current->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
1103                                 misdn_lib_send_event(current->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
1104                         }
1105
1106                         /* Remove the old call completion record */
1107                         AST_LIST_REMOVE_CURRENT(list);
1108                         ast_free(current);
1109                 }
1110         }
1111         AST_LIST_TRAVERSE_SAFE_END;
1112 }
1113 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1114
1115 #if defined(AST_MISDN_ENHANCEMENTS)
1116 /*!
1117  * \internal
1118  * \brief Allocate the next record id.
1119  *
1120  * \retval New record id on success.
1121  * \retval -1 on error.
1122  *
1123  * \note Assumes the misdn_cc_records_db lock is already obtained.
1124  */
1125 static long misdn_cc_record_id_new(void)
1126 {
1127         long record_id;
1128         long first_id;
1129
1130         record_id = ++misdn_cc_record_id;
1131         first_id = record_id;
1132         while (misdn_cc_find_by_id(record_id)) {
1133                 record_id = ++misdn_cc_record_id;
1134                 if (record_id == first_id) {
1135                         /*
1136                          * We have a resource leak.
1137                          * We should never need to allocate 64k records.
1138                          */
1139                         chan_misdn_log(0, 0, " --> ERROR Too many call completion records!\n");
1140                         record_id = -1;
1141                         break;
1142                 }
1143         }
1144
1145         return record_id;
1146 }
1147 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1148
1149 #if defined(AST_MISDN_ENHANCEMENTS)
1150 /*!
1151  * \internal
1152  * \brief Create a new call completion record
1153  *
1154  * \retval pointer to new call completion record
1155  * \retval NULL if failed
1156  *
1157  * \note Assumes the misdn_cc_records_db lock is already obtained.
1158  */
1159 static struct misdn_cc_record *misdn_cc_new(void)
1160 {
1161         struct misdn_cc_record *cc_record;
1162         long record_id;
1163
1164         misdn_cc_remove_old();
1165
1166         cc_record = ast_calloc(1, sizeof(*cc_record));
1167         if (cc_record) {
1168                 record_id = misdn_cc_record_id_new();
1169                 if (record_id < 0) {
1170                         ast_free(cc_record);
1171                         return NULL;
1172                 }
1173
1174                 /* Initialize the new record */
1175                 cc_record->record_id = record_id;
1176                 cc_record->port = -1;/* Invalid port so it will never be found this way */
1177                 cc_record->invoke_id = ++misdn_invoke_id;
1178                 cc_record->party_a_free = 1;/* Default User-A as free */
1179                 cc_record->error_code = FacError_None;
1180                 cc_record->reject_code = FacReject_None;
1181                 cc_record->time_created = time(NULL);
1182
1183                 /* Insert the new record into the database */
1184                 AST_LIST_INSERT_HEAD(&misdn_cc_records_db, cc_record, list);
1185         }
1186         return cc_record;
1187 }
1188 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1189
1190 #if defined(AST_MISDN_ENHANCEMENTS)
1191 /*!
1192  * \internal
1193  * \brief Destroy the call completion record database
1194  *
1195  * \return Nothing
1196  */
1197 static void misdn_cc_destroy(void)
1198 {
1199         struct misdn_cc_record *current;
1200
1201         while ((current = AST_LIST_REMOVE_HEAD(&misdn_cc_records_db, list))) {
1202                 /* Do a misdn_cc_delete(current) inline */
1203                 ast_free(current);
1204         }
1205 }
1206 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1207
1208 #if defined(AST_MISDN_ENHANCEMENTS)
1209 /*!
1210  * \internal
1211  * \brief Initialize the call completion record database
1212  *
1213  * \return Nothing
1214  */
1215 static void misdn_cc_init(void)
1216 {
1217         misdn_cc_record_id = 0;
1218 }
1219 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1220
1221 #if defined(AST_MISDN_ENHANCEMENTS)
1222 /*!
1223  * \internal
1224  * \brief Check the status of an outstanding invocation request.
1225  *
1226  * \param data Points to an integer containing the call completion record id.
1227  *
1228  * \retval 0 if got a response.
1229  * \retval -1 if no response yet.
1230  */
1231 static int misdn_cc_response_check(void *data)
1232 {
1233         int not_responded;
1234         struct misdn_cc_record *cc_record;
1235
1236         AST_LIST_LOCK(&misdn_cc_records_db);
1237         cc_record = misdn_cc_find_by_id(*(long *) data);
1238         if (cc_record) {
1239                 if (cc_record->outstanding_message) {
1240                         not_responded = -1;
1241                 } else {
1242                         not_responded = 0;
1243                 }
1244         } else {
1245                 /* No record so there is no response to check. */
1246                 not_responded = 0;
1247         }
1248         AST_LIST_UNLOCK(&misdn_cc_records_db);
1249
1250         return not_responded;
1251 }
1252 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1253
1254 #if defined(AST_MISDN_ENHANCEMENTS)
1255 /*!
1256  * \internal
1257  * \brief Wait for a response from the switch for an outstanding
1258  * invocation request.
1259  *
1260  * \param chan Asterisk channel to operate upon.
1261  * \param wait_seconds Number of seconds to wait
1262  * \param record_id Call completion record ID.
1263  *
1264  * \return Nothing
1265  */
1266 static void misdn_cc_response_wait(struct ast_channel *chan, int wait_seconds, long record_id)
1267 {
1268         unsigned count;
1269
1270         for (count = 2 * MISDN_CC_REQUEST_WAIT_MAX; count--;) {
1271                 /* Sleep in 500 ms increments */
1272                 if (ast_safe_sleep_conditional(chan, 500, misdn_cc_response_check, &record_id) != 0) {
1273                         /* We got hung up or our response came in. */
1274                         break;
1275                 }
1276         }
1277 }
1278 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1279
1280 #if defined(AST_MISDN_ENHANCEMENTS)
1281 /*!
1282  * \internal
1283  * \brief Convert the mISDN reject code to a string
1284  *
1285  * \param code mISDN reject code.
1286  *
1287  * \return The mISDN reject code as a string
1288  */
1289 static const char *misdn_to_str_reject_code(enum FacRejectCode code)
1290 {
1291         static const struct {
1292                 enum FacRejectCode code;
1293                 char *name;
1294         } arr[] = {
1295 /* *INDENT-OFF* */
1296                 { FacReject_None,                           "No reject occurred" },
1297                 { FacReject_Unknown,                        "Unknown reject code" },
1298
1299                 { FacReject_Gen_UnrecognizedComponent,      "General: Unrecognized Component" },
1300                 { FacReject_Gen_MistypedComponent,          "General: Mistyped Component" },
1301                 { FacReject_Gen_BadlyStructuredComponent,   "General: Badly Structured Component" },
1302
1303                 { FacReject_Inv_DuplicateInvocation,        "Invoke: Duplicate Invocation" },
1304                 { FacReject_Inv_UnrecognizedOperation,      "Invoke: Unrecognized Operation" },
1305                 { FacReject_Inv_MistypedArgument,           "Invoke: Mistyped Argument" },
1306                 { FacReject_Inv_ResourceLimitation,         "Invoke: Resource Limitation" },
1307                 { FacReject_Inv_InitiatorReleasing,         "Invoke: Initiator Releasing" },
1308                 { FacReject_Inv_UnrecognizedLinkedID,       "Invoke: Unrecognized Linked ID" },
1309                 { FacReject_Inv_LinkedResponseUnexpected,   "Invoke: Linked Response Unexpected" },
1310                 { FacReject_Inv_UnexpectedChildOperation,   "Invoke: Unexpected Child Operation" },
1311
1312                 { FacReject_Res_UnrecognizedInvocation,     "Result: Unrecognized Invocation" },
1313                 { FacReject_Res_ResultResponseUnexpected,   "Result: Result Response Unexpected" },
1314                 { FacReject_Res_MistypedResult,             "Result: Mistyped Result" },
1315
1316                 { FacReject_Err_UnrecognizedInvocation,     "Error: Unrecognized Invocation" },
1317                 { FacReject_Err_ErrorResponseUnexpected,    "Error: Error Response Unexpected" },
1318                 { FacReject_Err_UnrecognizedError,          "Error: Unrecognized Error" },
1319                 { FacReject_Err_UnexpectedError,            "Error: Unexpected Error" },
1320                 { FacReject_Err_MistypedParameter,          "Error: Mistyped Parameter" },
1321 /* *INDENT-ON* */
1322         };
1323
1324         unsigned index;
1325
1326         for (index = 0; index < ARRAY_LEN(arr); ++index) {
1327                 if (arr[index].code == code) {
1328                         return arr[index].name;
1329                 }
1330         }
1331
1332         return "unknown";
1333 }
1334 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1335
1336 #if defined(AST_MISDN_ENHANCEMENTS)
1337 /*!
1338  * \internal
1339  * \brief Convert the mISDN error code to a string
1340  *
1341  * \param code mISDN error code.
1342  *
1343  * \return The mISDN error code as a string
1344  */
1345 static const char *misdn_to_str_error_code(enum FacErrorCode code)
1346 {
1347         static const struct {
1348                 enum FacErrorCode code;
1349                 char *name;
1350         } arr[] = {
1351 /* *INDENT-OFF* */
1352                 { FacError_None,                            "No error occurred" },
1353                 { FacError_Unknown,                         "Unknown OID error code" },
1354
1355                 { FacError_Gen_NotSubscribed,               "General: Not Subscribed" },
1356                 { FacError_Gen_NotAvailable,                "General: Not Available" },
1357                 { FacError_Gen_NotImplemented,              "General: Not Implemented" },
1358                 { FacError_Gen_InvalidServedUserNr,         "General: Invalid Served User Number" },
1359                 { FacError_Gen_InvalidCallState,            "General: Invalid Call State" },
1360                 { FacError_Gen_BasicServiceNotProvided,     "General: Basic Service Not Provided" },
1361                 { FacError_Gen_NotIncomingCall,             "General: Not Incoming Call" },
1362                 { FacError_Gen_SupplementaryServiceInteractionNotAllowed,"General: Supplementary Service Interaction Not Allowed" },
1363                 { FacError_Gen_ResourceUnavailable,         "General: Resource Unavailable" },
1364
1365                 { FacError_Div_InvalidDivertedToNr,         "Diversion: Invalid Diverted To Number" },
1366                 { FacError_Div_SpecialServiceNr,            "Diversion: Special Service Number" },
1367                 { FacError_Div_DiversionToServedUserNr,     "Diversion: Diversion To Served User Number" },
1368                 { FacError_Div_IncomingCallAccepted,        "Diversion: Incoming Call Accepted" },
1369                 { FacError_Div_NumberOfDiversionsExceeded,  "Diversion: Number Of Diversions Exceeded" },
1370                 { FacError_Div_NotActivated,                "Diversion: Not Activated" },
1371                 { FacError_Div_RequestAlreadyAccepted,      "Diversion: Request Already Accepted" },
1372
1373                 { FacError_AOC_NoChargingInfoAvailable,     "AOC: No Charging Info Available" },
1374
1375                 { FacError_CCBS_InvalidCallLinkageID,       "CCBS: Invalid Call Linkage ID" },
1376                 { FacError_CCBS_InvalidCCBSReference,       "CCBS: Invalid CCBS Reference" },
1377                 { FacError_CCBS_LongTermDenial,             "CCBS: Long Term Denial" },
1378                 { FacError_CCBS_ShortTermDenial,            "CCBS: Short Term Denial" },
1379                 { FacError_CCBS_IsAlreadyActivated,         "CCBS: Is Already Activated" },
1380                 { FacError_CCBS_AlreadyAccepted,            "CCBS: Already Accepted" },
1381                 { FacError_CCBS_OutgoingCCBSQueueFull,      "CCBS: Outgoing CCBS Queue Full" },
1382                 { FacError_CCBS_CallFailureReasonNotBusy,   "CCBS: Call Failure Reason Not Busy" },
1383                 { FacError_CCBS_NotReadyForCall,            "CCBS: Not Ready For Call" },
1384
1385                 { FacError_CCBS_T_LongTermDenial,           "CCBS-T: Long Term Denial" },
1386                 { FacError_CCBS_T_ShortTermDenial,          "CCBS-T: Short Term Denial" },
1387
1388                 { FacError_ECT_LinkIdNotAssignedByNetwork,  "ECT: Link ID Not Assigned By Network" },
1389 /* *INDENT-ON* */
1390         };
1391
1392         unsigned index;
1393
1394         for (index = 0; index < ARRAY_LEN(arr); ++index) {
1395                 if (arr[index].code == code) {
1396                         return arr[index].name;
1397                 }
1398         }
1399
1400         return "unknown";
1401 }
1402 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1403
1404 #if defined(AST_MISDN_ENHANCEMENTS)
1405 /*!
1406  * \internal
1407  * \brief Convert mISDN redirecting reason to diversion reason.
1408  *
1409  * \param reason mISDN redirecting reason code.
1410  *
1411  * \return Supported diversion reason code.
1412  */
1413 static unsigned misdn_to_diversion_reason(enum mISDN_REDIRECTING_REASON reason)
1414 {
1415         unsigned diversion_reason;
1416
1417         switch (reason) {
1418         case mISDN_REDIRECTING_REASON_CALL_FWD:
1419                 diversion_reason = 1;/* cfu */
1420                 break;
1421         case mISDN_REDIRECTING_REASON_CALL_FWD_BUSY:
1422                 diversion_reason = 2;/* cfb */
1423                 break;
1424         case mISDN_REDIRECTING_REASON_NO_REPLY:
1425                 diversion_reason = 3;/* cfnr */
1426                 break;
1427         default:
1428                 diversion_reason = 0;/* unknown */
1429                 break;
1430         }
1431
1432         return diversion_reason;
1433 }
1434 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1435
1436 #if defined(AST_MISDN_ENHANCEMENTS)
1437 /*!
1438  * \internal
1439  * \brief Convert diversion reason to mISDN redirecting reason
1440  *
1441  * \param diversion_reason Diversion reason to convert
1442  *
1443  * \return Supported redirecting reason code.
1444  */
1445 static enum mISDN_REDIRECTING_REASON diversion_reason_to_misdn(unsigned diversion_reason)
1446 {
1447         enum mISDN_REDIRECTING_REASON reason;
1448
1449         switch (diversion_reason) {
1450         case 1:/* cfu */
1451                 reason = mISDN_REDIRECTING_REASON_CALL_FWD;
1452                 break;
1453         case 2:/* cfb */
1454                 reason = mISDN_REDIRECTING_REASON_CALL_FWD_BUSY;
1455                 break;
1456         case 3:/* cfnr */
1457                 reason = mISDN_REDIRECTING_REASON_NO_REPLY;
1458                 break;
1459         default:
1460                 reason = mISDN_REDIRECTING_REASON_UNKNOWN;
1461                 break;
1462         }
1463
1464         return reason;
1465 }
1466 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1467
1468 #if defined(AST_MISDN_ENHANCEMENTS)
1469 /*!
1470  * \internal
1471  * \brief Convert the mISDN presentation to PresentedNumberUnscreened type
1472  *
1473  * \param presentation mISDN presentation to convert
1474  * \param number_present TRUE if the number is present
1475  *
1476  * \return PresentedNumberUnscreened type
1477  */
1478 static unsigned misdn_to_PresentedNumberUnscreened_type(int presentation, int number_present)
1479 {
1480         unsigned type;
1481
1482         switch (presentation) {
1483         case 0:/* allowed */
1484                 if (number_present) {
1485                         type = 0;/* presentationAllowedNumber */
1486                 } else {
1487                         type = 2;/* numberNotAvailableDueToInterworking */
1488                 }
1489                 break;
1490         case 1:/* restricted */
1491                 if (number_present) {
1492                         type = 3;/* presentationRestrictedNumber */
1493                 } else {
1494                         type = 1;/* presentationRestricted */
1495                 }
1496                 break;
1497         default:
1498                 type = 2;/* numberNotAvailableDueToInterworking */
1499                 break;
1500         }
1501
1502         return type;
1503 }
1504 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1505
1506 #if defined(AST_MISDN_ENHANCEMENTS)
1507 /*!
1508  * \internal
1509  * \brief Convert the PresentedNumberUnscreened type to mISDN presentation
1510  *
1511  * \param type PresentedNumberUnscreened type
1512  *
1513  * \return mISDN presentation
1514  */
1515 static int PresentedNumberUnscreened_to_misdn_pres(unsigned type)
1516 {
1517         int presentation;
1518
1519         switch (type) {
1520         default:
1521         case 0:/* presentationAllowedNumber */
1522                 presentation = 0;/* allowed */
1523                 break;
1524
1525         case 1:/* presentationRestricted */
1526         case 3:/* presentationRestrictedNumber */
1527                 presentation = 1;/* restricted */
1528                 break;
1529
1530         case 2:/* numberNotAvailableDueToInterworking */
1531                 presentation = 2;/* unavailable */
1532                 break;
1533         }
1534
1535         return presentation;
1536 }
1537 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1538
1539 #if defined(AST_MISDN_ENHANCEMENTS)
1540 /*!
1541  * \internal
1542  * \brief Convert the mISDN numbering plan to PartyNumber numbering plan
1543  *
1544  * \param number_plan mISDN numbering plan
1545  *
1546  * \return PartyNumber numbering plan
1547  */
1548 static unsigned misdn_to_PartyNumber_plan(enum mISDN_NUMBER_PLAN number_plan)
1549 {
1550         unsigned party_plan;
1551
1552         switch (number_plan) {
1553         default:
1554         case NUMPLAN_UNKNOWN:
1555                 party_plan = 0;/* unknown */
1556                 break;
1557
1558         case NUMPLAN_ISDN:
1559                 party_plan = 1;/* public */
1560                 break;
1561
1562         case NUMPLAN_DATA:
1563                 party_plan = 3;/* data */
1564                 break;
1565
1566         case NUMPLAN_TELEX:
1567                 party_plan = 4;/* telex */
1568                 break;
1569
1570         case NUMPLAN_NATIONAL:
1571                 party_plan = 8;/* nationalStandard */
1572                 break;
1573
1574         case NUMPLAN_PRIVATE:
1575                 party_plan = 5;/* private */
1576                 break;
1577         }
1578
1579         return party_plan;
1580 }
1581 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1582
1583 #if defined(AST_MISDN_ENHANCEMENTS)
1584 /*!
1585  * \internal
1586  * \brief Convert PartyNumber numbering plan to mISDN numbering plan
1587  *
1588  * \param party_plan PartyNumber numbering plan
1589  *
1590  * \return mISDN numbering plan
1591  */
1592 static enum mISDN_NUMBER_PLAN PartyNumber_to_misdn_plan(unsigned party_plan)
1593 {
1594         enum mISDN_NUMBER_PLAN number_plan;
1595
1596         switch (party_plan) {
1597         default:
1598         case 0:/* unknown */
1599                 number_plan = NUMPLAN_UNKNOWN;
1600                 break;
1601         case 1:/* public */
1602                 number_plan = NUMPLAN_ISDN;
1603                 break;
1604         case 3:/* data */
1605                 number_plan = NUMPLAN_DATA;
1606                 break;
1607         case 4:/* telex */
1608                 number_plan = NUMPLAN_TELEX;
1609                 break;
1610         case 8:/* nationalStandard */
1611                 number_plan = NUMPLAN_NATIONAL;
1612                 break;
1613         case 5:/* private */
1614                 number_plan = NUMPLAN_PRIVATE;
1615                 break;
1616         }
1617
1618         return number_plan;
1619 }
1620 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1621
1622 #if defined(AST_MISDN_ENHANCEMENTS)
1623 /*!
1624  * \internal
1625  * \brief Convert mISDN type-of-number to PartyNumber public type-of-number
1626  *
1627  * \param ton mISDN type-of-number
1628  *
1629  * \return PartyNumber public type-of-number
1630  */
1631 static unsigned misdn_to_PartyNumber_ton_public(enum mISDN_NUMBER_TYPE ton)
1632 {
1633         unsigned party_ton;
1634
1635         switch (ton) {
1636         default:
1637         case NUMTYPE_UNKNOWN:
1638                 party_ton = 0;/* unknown */
1639                 break;
1640
1641         case NUMTYPE_INTERNATIONAL:
1642                 party_ton = 1;/* internationalNumber */
1643                 break;
1644
1645         case NUMTYPE_NATIONAL:
1646                 party_ton = 2;/* nationalNumber */
1647                 break;
1648
1649         case NUMTYPE_NETWORK_SPECIFIC:
1650                 party_ton = 3;/* networkSpecificNumber */
1651                 break;
1652
1653         case NUMTYPE_SUBSCRIBER:
1654                 party_ton = 4;/* subscriberNumber */
1655                 break;
1656
1657         case NUMTYPE_ABBREVIATED:
1658                 party_ton = 6;/* abbreviatedNumber */
1659                 break;
1660         }
1661
1662         return party_ton;
1663 }
1664 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1665
1666 #if defined(AST_MISDN_ENHANCEMENTS)
1667 /*!
1668  * \internal
1669  * \brief Convert the PartyNumber public type-of-number to mISDN type-of-number
1670  *
1671  * \param party_ton PartyNumber public type-of-number
1672  *
1673  * \return mISDN type-of-number
1674  */
1675 static enum mISDN_NUMBER_TYPE PartyNumber_to_misdn_ton_public(unsigned party_ton)
1676 {
1677         enum mISDN_NUMBER_TYPE ton;
1678
1679         switch (party_ton) {
1680         default:
1681         case 0:/* unknown */
1682                 ton = NUMTYPE_UNKNOWN;
1683                 break;
1684
1685         case 1:/* internationalNumber */
1686                 ton = NUMTYPE_INTERNATIONAL;
1687                 break;
1688
1689         case 2:/* nationalNumber */
1690                 ton = NUMTYPE_NATIONAL;
1691                 break;
1692
1693         case 3:/* networkSpecificNumber */
1694                 ton = NUMTYPE_NETWORK_SPECIFIC;
1695                 break;
1696
1697         case 4:/* subscriberNumber */
1698                 ton = NUMTYPE_SUBSCRIBER;
1699                 break;
1700
1701         case 6:/* abbreviatedNumber */
1702                 ton = NUMTYPE_ABBREVIATED;
1703                 break;
1704         }
1705
1706         return ton;
1707 }
1708 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1709
1710 #if defined(AST_MISDN_ENHANCEMENTS)
1711 /*!
1712  * \internal
1713  * \brief Convert mISDN type-of-number to PartyNumber private type-of-number
1714  *
1715  * \param ton mISDN type-of-number
1716  *
1717  * \return PartyNumber private type-of-number
1718  */
1719 static unsigned misdn_to_PartyNumber_ton_private(enum mISDN_NUMBER_TYPE ton)
1720 {
1721         unsigned party_ton;
1722
1723         switch (ton) {
1724         default:
1725         case NUMTYPE_UNKNOWN:
1726                 party_ton = 0;/* unknown */
1727                 break;
1728
1729         case NUMTYPE_INTERNATIONAL:
1730                 party_ton = 1;/* level2RegionalNumber */
1731                 break;
1732
1733         case NUMTYPE_NATIONAL:
1734                 party_ton = 2;/* level1RegionalNumber */
1735                 break;
1736
1737         case NUMTYPE_NETWORK_SPECIFIC:
1738                 party_ton = 3;/* pTNSpecificNumber */
1739                 break;
1740
1741         case NUMTYPE_SUBSCRIBER:
1742                 party_ton = 4;/* localNumber */
1743                 break;
1744
1745         case NUMTYPE_ABBREVIATED:
1746                 party_ton = 6;/* abbreviatedNumber */
1747                 break;
1748         }
1749
1750         return party_ton;
1751 }
1752 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1753
1754 #if defined(AST_MISDN_ENHANCEMENTS)
1755 /*!
1756  * \internal
1757  * \brief Convert the PartyNumber private type-of-number to mISDN type-of-number
1758  *
1759  * \param party_ton PartyNumber private type-of-number
1760  *
1761  * \return mISDN type-of-number
1762  */
1763 static enum mISDN_NUMBER_TYPE PartyNumber_to_misdn_ton_private(unsigned party_ton)
1764 {
1765         enum mISDN_NUMBER_TYPE ton;
1766
1767         switch (party_ton) {
1768         default:
1769         case 0:/* unknown */
1770                 ton = NUMTYPE_UNKNOWN;
1771                 break;
1772
1773         case 1:/* level2RegionalNumber */
1774                 ton = NUMTYPE_INTERNATIONAL;
1775                 break;
1776
1777         case 2:/* level1RegionalNumber */
1778                 ton = NUMTYPE_NATIONAL;
1779                 break;
1780
1781         case 3:/* pTNSpecificNumber */
1782                 ton = NUMTYPE_NETWORK_SPECIFIC;
1783                 break;
1784
1785         case 4:/* localNumber */
1786                 ton = NUMTYPE_SUBSCRIBER;
1787                 break;
1788
1789         case 6:/* abbreviatedNumber */
1790                 ton = NUMTYPE_ABBREVIATED;
1791                 break;
1792         }
1793
1794         return ton;
1795 }
1796 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
1797
1798 /*!
1799  * \internal
1800  * \brief Convert the mISDN type of number code to a string
1801  *
1802  * \param number_type mISDN type of number code.
1803  *
1804  * \return The mISDN type of number code as a string
1805  */
1806 static const char *misdn_to_str_ton(enum mISDN_NUMBER_TYPE number_type)
1807 {
1808         const char *str;
1809
1810         switch (number_type) {
1811         default:
1812         case NUMTYPE_UNKNOWN:
1813                 str = "Unknown";
1814                 break;
1815
1816         case NUMTYPE_INTERNATIONAL:
1817                 str = "International";
1818                 break;
1819
1820         case NUMTYPE_NATIONAL:
1821                 str = "National";
1822                 break;
1823
1824         case NUMTYPE_NETWORK_SPECIFIC:
1825                 str = "Network Specific";
1826                 break;
1827
1828         case NUMTYPE_SUBSCRIBER:
1829                 str = "Subscriber";
1830                 break;
1831
1832         case NUMTYPE_ABBREVIATED:
1833                 str = "Abbreviated";
1834                 break;
1835         }
1836
1837         return str;
1838 }
1839
1840 /*!
1841  * \internal
1842  * \brief Convert the mISDN type of number code to Asterisk type of number code
1843  *
1844  * \param number_type mISDN type of number code.
1845  *
1846  * \return Asterisk type of number code
1847  */
1848 static int misdn_to_ast_ton(enum mISDN_NUMBER_TYPE number_type)
1849 {
1850         int ast_number_type;
1851
1852         switch (number_type) {
1853         default:
1854         case NUMTYPE_UNKNOWN:
1855                 ast_number_type = NUMTYPE_UNKNOWN << 4;
1856                 break;
1857
1858         case NUMTYPE_INTERNATIONAL:
1859                 ast_number_type = NUMTYPE_INTERNATIONAL << 4;
1860                 break;
1861
1862         case NUMTYPE_NATIONAL:
1863                 ast_number_type = NUMTYPE_NATIONAL << 4;
1864                 break;
1865
1866         case NUMTYPE_NETWORK_SPECIFIC:
1867                 ast_number_type = NUMTYPE_NETWORK_SPECIFIC << 4;
1868                 break;
1869
1870         case NUMTYPE_SUBSCRIBER:
1871                 ast_number_type = NUMTYPE_SUBSCRIBER << 4;
1872                 break;
1873
1874         case NUMTYPE_ABBREVIATED:
1875                 ast_number_type = NUMTYPE_ABBREVIATED << 4;
1876                 break;
1877         }
1878
1879         return ast_number_type;
1880 }
1881
1882 /*!
1883  * \internal
1884  * \brief Convert the Asterisk type of number code to mISDN type of number code
1885  *
1886  * \param ast_number_type Asterisk type of number code.
1887  *
1888  * \return mISDN type of number code
1889  */
1890 static enum mISDN_NUMBER_TYPE ast_to_misdn_ton(unsigned ast_number_type)
1891 {
1892         enum mISDN_NUMBER_TYPE number_type;
1893
1894         switch ((ast_number_type >> 4) & 0x07) {
1895         default:
1896         case NUMTYPE_UNKNOWN:
1897                 number_type = NUMTYPE_UNKNOWN;
1898                 break;
1899
1900         case NUMTYPE_INTERNATIONAL:
1901                 number_type = NUMTYPE_INTERNATIONAL;
1902                 break;
1903
1904         case NUMTYPE_NATIONAL:
1905                 number_type = NUMTYPE_NATIONAL;
1906                 break;
1907
1908         case NUMTYPE_NETWORK_SPECIFIC:
1909                 number_type = NUMTYPE_NETWORK_SPECIFIC;
1910                 break;
1911
1912         case NUMTYPE_SUBSCRIBER:
1913                 number_type = NUMTYPE_SUBSCRIBER;
1914                 break;
1915
1916         case NUMTYPE_ABBREVIATED:
1917                 number_type = NUMTYPE_ABBREVIATED;
1918                 break;
1919         }
1920
1921         return number_type;
1922 }
1923
1924 /*!
1925  * \internal
1926  * \brief Convert the mISDN numbering plan code to a string
1927  *
1928  * \param number_plan mISDN numbering plan code.
1929  *
1930  * \return The mISDN numbering plan code as a string
1931  */
1932 static const char *misdn_to_str_plan(enum mISDN_NUMBER_PLAN number_plan)
1933 {
1934         const char *str;
1935
1936         switch (number_plan) {
1937         default:
1938         case NUMPLAN_UNKNOWN:
1939                 str = "Unknown";
1940                 break;
1941
1942         case NUMPLAN_ISDN:
1943                 str = "ISDN";
1944                 break;
1945
1946         case NUMPLAN_DATA:
1947                 str = "Data";
1948                 break;
1949
1950         case NUMPLAN_TELEX:
1951                 str = "Telex";
1952                 break;
1953
1954         case NUMPLAN_NATIONAL:
1955                 str = "National";
1956                 break;
1957
1958         case NUMPLAN_PRIVATE:
1959                 str = "Private";
1960                 break;
1961         }
1962
1963         return str;
1964 }
1965
1966 /*!
1967  * \internal
1968  * \brief Convert the mISDN numbering plan code to Asterisk numbering plan code
1969  *
1970  * \param number_plan mISDN numbering plan code.
1971  *
1972  * \return Asterisk numbering plan code
1973  */
1974 static int misdn_to_ast_plan(enum mISDN_NUMBER_PLAN number_plan)
1975 {
1976         int ast_number_plan;
1977
1978         switch (number_plan) {
1979         default:
1980         case NUMPLAN_UNKNOWN:
1981                 ast_number_plan = NUMPLAN_UNKNOWN;
1982                 break;
1983
1984         case NUMPLAN_ISDN:
1985                 ast_number_plan = NUMPLAN_ISDN;
1986                 break;
1987
1988         case NUMPLAN_DATA:
1989                 ast_number_plan = NUMPLAN_DATA;
1990                 break;
1991
1992         case NUMPLAN_TELEX:
1993                 ast_number_plan = NUMPLAN_TELEX;
1994                 break;
1995
1996         case NUMPLAN_NATIONAL:
1997                 ast_number_plan = NUMPLAN_NATIONAL;
1998                 break;
1999
2000         case NUMPLAN_PRIVATE:
2001                 ast_number_plan = NUMPLAN_PRIVATE;
2002                 break;
2003         }
2004
2005         return ast_number_plan;
2006 }
2007
2008 /*!
2009  * \internal
2010  * \brief Convert the Asterisk numbering plan code to mISDN numbering plan code
2011  *
2012  * \param ast_number_plan Asterisk numbering plan code.
2013  *
2014  * \return mISDN numbering plan code
2015  */
2016 static enum mISDN_NUMBER_PLAN ast_to_misdn_plan(unsigned ast_number_plan)
2017 {
2018         enum mISDN_NUMBER_PLAN number_plan;
2019
2020         switch (ast_number_plan & 0x0F) {
2021         default:
2022         case NUMPLAN_UNKNOWN:
2023                 number_plan = NUMPLAN_UNKNOWN;
2024                 break;
2025
2026         case NUMPLAN_ISDN:
2027                 number_plan = NUMPLAN_ISDN;
2028                 break;
2029
2030         case NUMPLAN_DATA:
2031                 number_plan = NUMPLAN_DATA;
2032                 break;
2033
2034         case NUMPLAN_TELEX:
2035                 number_plan = NUMPLAN_TELEX;
2036                 break;
2037
2038         case NUMPLAN_NATIONAL:
2039                 number_plan = NUMPLAN_NATIONAL;
2040                 break;
2041
2042         case NUMPLAN_PRIVATE:
2043                 number_plan = NUMPLAN_PRIVATE;
2044                 break;
2045         }
2046
2047         return number_plan;
2048 }
2049
2050 /*!
2051  * \internal
2052  * \brief Convert the mISDN presentation code to a string
2053  *
2054  * \param presentation mISDN number presentation restriction code.
2055  *
2056  * \return The mISDN presentation code as a string
2057  */
2058 static const char *misdn_to_str_pres(int presentation)
2059 {
2060         const char *str;
2061
2062         switch (presentation) {
2063         case 0:
2064                 str = "Allowed";
2065                 break;
2066
2067         case 1:
2068                 str = "Restricted";
2069                 break;
2070
2071         case 2:
2072                 str = "Unavailable";
2073                 break;
2074
2075         default:
2076                 str = "Unknown";
2077                 break;
2078         }
2079
2080         return str;
2081 }
2082
2083 /*!
2084  * \internal
2085  * \brief Convert the mISDN presentation code to Asterisk presentation code
2086  *
2087  * \param presentation mISDN number presentation restriction code.
2088  *
2089  * \return Asterisk presentation code
2090  */
2091 static int misdn_to_ast_pres(int presentation)
2092 {
2093         switch (presentation) {
2094         default:
2095         case 0:
2096                 presentation = AST_PRES_ALLOWED;
2097                 break;
2098
2099         case 1:
2100                 presentation = AST_PRES_RESTRICTED;
2101                 break;
2102
2103         case 2:
2104                 presentation = AST_PRES_UNAVAILABLE;
2105                 break;
2106         }
2107
2108         return presentation;
2109 }
2110
2111 /*!
2112  * \internal
2113  * \brief Convert the Asterisk presentation code to mISDN presentation code
2114  *
2115  * \param presentation Asterisk number presentation restriction code.
2116  *
2117  * \return mISDN presentation code
2118  */
2119 static int ast_to_misdn_pres(int presentation)
2120 {
2121         switch (presentation & AST_PRES_RESTRICTION) {
2122         default:
2123         case AST_PRES_ALLOWED:
2124                 presentation = 0;
2125                 break;
2126
2127         case AST_PRES_RESTRICTED:
2128                 presentation = 1;
2129                 break;
2130
2131         case AST_PRES_UNAVAILABLE:
2132                 presentation = 2;
2133                 break;
2134         }
2135
2136         return presentation;
2137 }
2138
2139 /*!
2140  * \internal
2141  * \brief Convert the mISDN screening code to a string
2142  *
2143  * \param screening mISDN number screening code.
2144  *
2145  * \return The mISDN screening code as a string
2146  */
2147 static const char *misdn_to_str_screen(int screening)
2148 {
2149         const char *str;
2150
2151         switch (screening) {
2152         case 0:
2153                 str = "Unscreened";
2154                 break;
2155
2156         case 1:
2157                 str = "Passed Screen";
2158                 break;
2159
2160         case 2:
2161                 str = "Failed Screen";
2162                 break;
2163
2164         case 3:
2165                 str = "Network Number";
2166                 break;
2167
2168         default:
2169                 str = "Unknown";
2170                 break;
2171         }
2172
2173         return str;
2174 }
2175
2176 /*!
2177  * \internal
2178  * \brief Convert the mISDN screening code to Asterisk screening code
2179  *
2180  * \param screening mISDN number screening code.
2181  *
2182  * \return Asterisk screening code
2183  */
2184 static int misdn_to_ast_screen(int screening)
2185 {
2186         switch (screening) {
2187         default:
2188         case 0:
2189                 screening = AST_PRES_USER_NUMBER_UNSCREENED;
2190                 break;
2191
2192         case 1:
2193                 screening = AST_PRES_USER_NUMBER_PASSED_SCREEN;
2194                 break;
2195
2196         case 2:
2197                 screening = AST_PRES_USER_NUMBER_FAILED_SCREEN;
2198                 break;
2199
2200         case 3:
2201                 screening = AST_PRES_NETWORK_NUMBER;
2202                 break;
2203         }
2204
2205         return screening;
2206 }
2207
2208 /*!
2209  * \internal
2210  * \brief Convert the Asterisk screening code to mISDN screening code
2211  *
2212  * \param screening Asterisk number screening code.
2213  *
2214  * \return mISDN screening code
2215  */
2216 static int ast_to_misdn_screen(int screening)
2217 {
2218         switch (screening & AST_PRES_NUMBER_TYPE) {
2219         default:
2220         case AST_PRES_USER_NUMBER_UNSCREENED:
2221                 screening = 0;
2222                 break;
2223
2224         case AST_PRES_USER_NUMBER_PASSED_SCREEN:
2225                 screening = 1;
2226                 break;
2227
2228         case AST_PRES_USER_NUMBER_FAILED_SCREEN:
2229                 screening = 2;
2230                 break;
2231
2232         case AST_PRES_NETWORK_NUMBER:
2233                 screening = 3;
2234                 break;
2235         }
2236
2237         return screening;
2238 }
2239
2240 /*!
2241  * \internal
2242  * \brief Convert Asterisk redirecting reason to mISDN redirecting reason code.
2243  *
2244  * \param ast Asterisk redirecting reason code.
2245  *
2246  * \return mISDN reason code
2247  */
2248 static enum mISDN_REDIRECTING_REASON ast_to_misdn_reason(const enum AST_REDIRECTING_REASON ast)
2249 {
2250         unsigned index;
2251
2252         static const struct misdn_reasons {
2253                 enum AST_REDIRECTING_REASON ast;
2254                 enum mISDN_REDIRECTING_REASON q931;
2255         } misdn_reason_table[] = {
2256         /* *INDENT-OFF* */
2257                 { AST_REDIRECTING_REASON_UNKNOWN,        mISDN_REDIRECTING_REASON_UNKNOWN },
2258                 { AST_REDIRECTING_REASON_USER_BUSY,      mISDN_REDIRECTING_REASON_CALL_FWD_BUSY },
2259                 { AST_REDIRECTING_REASON_NO_ANSWER,      mISDN_REDIRECTING_REASON_NO_REPLY },
2260                 { AST_REDIRECTING_REASON_UNAVAILABLE,    mISDN_REDIRECTING_REASON_NO_REPLY },
2261                 { AST_REDIRECTING_REASON_UNCONDITIONAL,  mISDN_REDIRECTING_REASON_CALL_FWD },
2262                 { AST_REDIRECTING_REASON_TIME_OF_DAY,    mISDN_REDIRECTING_REASON_UNKNOWN },
2263                 { AST_REDIRECTING_REASON_DO_NOT_DISTURB, mISDN_REDIRECTING_REASON_UNKNOWN },
2264                 { AST_REDIRECTING_REASON_DEFLECTION,     mISDN_REDIRECTING_REASON_DEFLECTION },
2265                 { AST_REDIRECTING_REASON_FOLLOW_ME,      mISDN_REDIRECTING_REASON_UNKNOWN },
2266                 { AST_REDIRECTING_REASON_OUT_OF_ORDER,   mISDN_REDIRECTING_REASON_OUT_OF_ORDER },
2267                 { AST_REDIRECTING_REASON_AWAY,           mISDN_REDIRECTING_REASON_UNKNOWN },
2268                 { AST_REDIRECTING_REASON_CALL_FWD_DTE,   mISDN_REDIRECTING_REASON_CALL_FWD_DTE }
2269         /* *INDENT-ON* */
2270         };
2271
2272         for (index = 0; index < ARRAY_LEN(misdn_reason_table); ++index) {
2273                 if (misdn_reason_table[index].ast == ast) {
2274                         return misdn_reason_table[index].q931;
2275                 }
2276         }
2277         return mISDN_REDIRECTING_REASON_UNKNOWN;
2278 }
2279
2280 /*!
2281  * \internal
2282  * \brief Convert the mISDN redirecting reason to Asterisk redirecting reason code
2283  *
2284  * \param q931 mISDN redirecting reason code.
2285  *
2286  * \return Asterisk redirecting reason code
2287  */
2288 static enum AST_REDIRECTING_REASON misdn_to_ast_reason(const enum mISDN_REDIRECTING_REASON q931)
2289 {
2290         enum AST_REDIRECTING_REASON ast;
2291
2292         switch (q931) {
2293         default:
2294         case mISDN_REDIRECTING_REASON_UNKNOWN:
2295                 ast = AST_REDIRECTING_REASON_UNKNOWN;
2296                 break;
2297
2298         case mISDN_REDIRECTING_REASON_CALL_FWD_BUSY:
2299                 ast = AST_REDIRECTING_REASON_USER_BUSY;
2300                 break;
2301
2302         case mISDN_REDIRECTING_REASON_NO_REPLY:
2303                 ast = AST_REDIRECTING_REASON_NO_ANSWER;
2304                 break;
2305
2306         case mISDN_REDIRECTING_REASON_DEFLECTION:
2307                 ast = AST_REDIRECTING_REASON_DEFLECTION;
2308                 break;
2309
2310         case mISDN_REDIRECTING_REASON_OUT_OF_ORDER:
2311                 ast = AST_REDIRECTING_REASON_OUT_OF_ORDER;
2312                 break;
2313
2314         case mISDN_REDIRECTING_REASON_CALL_FWD_DTE:
2315                 ast = AST_REDIRECTING_REASON_CALL_FWD_DTE;
2316                 break;
2317
2318         case mISDN_REDIRECTING_REASON_CALL_FWD:
2319                 ast = AST_REDIRECTING_REASON_UNCONDITIONAL;
2320                 break;
2321         }
2322
2323         return ast;
2324 }
2325
2326
2327
2328 struct allowed_bearers {
2329         char *name;         /*!< Bearer capability name string used in /etc/misdn.conf allowed_bearers */
2330         char *display;      /*!< Bearer capability displayable name */
2331         int cap;            /*!< SETUP message bearer capability field code value */
2332         int deprecated;     /*!< TRUE if this entry is deprecated. (Misspelled or bad name to use) */
2333 };
2334
2335 /* *INDENT-OFF* */
2336 static const struct allowed_bearers allowed_bearers_array[] = {
2337         /* Name,                      Displayable Name       Bearer Capability,                    Deprecated */
2338         { "speech",                  "Speech",               INFO_CAPABILITY_SPEECH,               0 },
2339         { "3_1khz",                  "3.1KHz Audio",         INFO_CAPABILITY_AUDIO_3_1K,           0 },
2340         { "digital_unrestricted",    "Unrestricted Digital", INFO_CAPABILITY_DIGITAL_UNRESTRICTED, 0 },
2341         { "digital_restricted",      "Restricted Digital",   INFO_CAPABILITY_DIGITAL_RESTRICTED,   0 },
2342         { "digital_restriced",       "Restricted Digital",   INFO_CAPABILITY_DIGITAL_RESTRICTED,   1 }, /* Allow misspelling for backwards compatibility */
2343         { "video",                   "Video",                INFO_CAPABILITY_VIDEO,                0 }
2344 };
2345 /* *INDENT-ON* */
2346
2347 static const char *bearer2str(int cap)
2348 {
2349         unsigned index;
2350
2351         for (index = 0; index < ARRAY_LEN(allowed_bearers_array); ++index) {
2352                 if (allowed_bearers_array[index].cap == cap) {
2353                         return allowed_bearers_array[index].display;
2354                 }
2355         }
2356
2357         return "Unknown Bearer";
2358 }
2359
2360 #if defined(AST_MISDN_ENHANCEMENTS)
2361 /*!
2362  * \internal
2363  * \brief Fill in facility PartyNumber information
2364  *
2365  * \param party PartyNumber structure to fill in.
2366  * \param id Information to put in PartyNumber structure.
2367  *
2368  * \return Nothing
2369  */
2370 static void misdn_PartyNumber_fill(struct FacPartyNumber *party, const struct misdn_party_id *id)
2371 {
2372         ast_copy_string((char *) party->Number, id->number, sizeof(party->Number));
2373         party->LengthOfNumber = strlen((char *) party->Number);
2374         party->Type = misdn_to_PartyNumber_plan(id->number_plan);
2375         switch (party->Type) {
2376         case 1:/* public */
2377                 party->TypeOfNumber = misdn_to_PartyNumber_ton_public(id->number_type);
2378                 break;
2379         case 5:/* private */
2380                 party->TypeOfNumber = misdn_to_PartyNumber_ton_private(id->number_type);
2381                 break;
2382         default:
2383                 party->TypeOfNumber = 0;/* Don't care */
2384                 break;
2385         }
2386 }
2387 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2388
2389 #if defined(AST_MISDN_ENHANCEMENTS)
2390 /*!
2391  * \internal
2392  * \brief Extract the information from PartyNumber
2393  *
2394  * \param id Where to put extracted PartyNumber information
2395  * \param party PartyNumber information to extract
2396  *
2397  * \return Nothing
2398  */
2399 static void misdn_PartyNumber_extract(struct misdn_party_id *id, const struct FacPartyNumber *party)
2400 {
2401         if (party->LengthOfNumber) {
2402                 ast_copy_string(id->number, (char *) party->Number, sizeof(id->number));
2403                 id->number_plan = PartyNumber_to_misdn_plan(party->Type);
2404                 switch (party->Type) {
2405                 case 1:/* public */
2406                         id->number_type = PartyNumber_to_misdn_ton_public(party->TypeOfNumber);
2407                         break;
2408                 case 5:/* private */
2409                         id->number_type = PartyNumber_to_misdn_ton_private(party->TypeOfNumber);
2410                         break;
2411                 default:
2412                         id->number_type = NUMTYPE_UNKNOWN;
2413                         break;
2414                 }
2415         } else {
2416                 /* Number not present */
2417                 id->number_type = NUMTYPE_UNKNOWN;
2418                 id->number_plan = NUMPLAN_ISDN;
2419                 id->number[0] = 0;
2420         }
2421 }
2422 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2423
2424 #if defined(AST_MISDN_ENHANCEMENTS)
2425 /*!
2426  * \internal
2427  * \brief Fill in facility Address information
2428  *
2429  * \param Address Address structure to fill in.
2430  * \param id Information to put in Address structure.
2431  *
2432  * \return Nothing
2433  */
2434 static void misdn_Address_fill(struct FacAddress *Address, const struct misdn_party_id *id)
2435 {
2436         misdn_PartyNumber_fill(&Address->Party, id);
2437
2438         /* Subaddresses are not supported yet */
2439         Address->Subaddress.Length = 0;
2440 }
2441 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2442
2443 #if defined(AST_MISDN_ENHANCEMENTS)
2444 /*!
2445  * \internal
2446  * \brief Fill in facility PresentedNumberUnscreened information
2447  *
2448  * \param presented PresentedNumberUnscreened structure to fill in.
2449  * \param id Information to put in PresentedNumberUnscreened structure.
2450  *
2451  * \return Nothing
2452  */
2453 static void misdn_PresentedNumberUnscreened_fill(struct FacPresentedNumberUnscreened *presented, const struct misdn_party_id *id)
2454 {
2455         presented->Type = misdn_to_PresentedNumberUnscreened_type(id->presentation, id->number[0] ? 1 : 0);
2456         misdn_PartyNumber_fill(&presented->Unscreened, id);
2457 }
2458 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2459
2460 #if defined(AST_MISDN_ENHANCEMENTS)
2461 /*!
2462  * \internal
2463  * \brief Extract the information from PartyNumber
2464  *
2465  * \param id Where to put extracted PresentedNumberUnscreened information
2466  * \param presented PresentedNumberUnscreened information to extract
2467  *
2468  * \return Nothing
2469  */
2470 static void misdn_PresentedNumberUnscreened_extract(struct misdn_party_id *id, const struct FacPresentedNumberUnscreened *presented)
2471 {
2472         id->presentation = PresentedNumberUnscreened_to_misdn_pres(presented->Type);
2473         id->screening = 0;/* unscreened */
2474         switch (presented->Type) {
2475         case 0:/* presentationAllowedNumber */
2476         case 3:/* presentationRestrictedNumber */
2477                 misdn_PartyNumber_extract(id, &presented->Unscreened);
2478                 break;
2479         case 1:/* presentationRestricted */
2480         case 2:/* numberNotAvailableDueToInterworking */
2481         default:
2482                 /* Number not present (And uninitialized so do not even look at it!) */
2483                 id->number_type = NUMTYPE_UNKNOWN;
2484                 id->number_plan = NUMPLAN_ISDN;
2485                 id->number[0] = 0;
2486                 break;
2487         }
2488 }
2489 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2490
2491 #if defined(AST_MISDN_ENHANCEMENTS)
2492 static const char Level_Spacing[] = "          ";/* Work for up to 10 levels */
2493 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2494
2495 #if defined(AST_MISDN_ENHANCEMENTS)
2496 static void print_facility_PartyNumber(unsigned Level, const struct FacPartyNumber *Party, const struct misdn_bchannel *bc)
2497 {
2498         if (Party->LengthOfNumber) {
2499                 const char *Spacing;
2500
2501                 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2502                 chan_misdn_log(1, bc->port, " -->%s PartyNumber: Type:%d\n",
2503                         Spacing, Party->Type);
2504                 switch (Party->Type) {
2505                 case 0: /* Unknown PartyNumber */
2506                         chan_misdn_log(1, bc->port, " -->%s  Unknown: %s\n",
2507                                 Spacing, Party->Number);
2508                         break;
2509                 case 1: /* Public PartyNumber */
2510                         chan_misdn_log(1, bc->port, " -->%s  Public TON:%d %s\n",
2511                                 Spacing, Party->TypeOfNumber, Party->Number);
2512                         break;
2513                 case 2: /* NSAP encoded PartyNumber */
2514                         chan_misdn_log(1, bc->port, " -->%s  NSAP: %s\n",
2515                                 Spacing, Party->Number);
2516                         break;
2517                 case 3: /* Data PartyNumber (Not used) */
2518                         chan_misdn_log(1, bc->port, " -->%s  Data: %s\n",
2519                                 Spacing, Party->Number);
2520                         break;
2521                 case 4: /* Telex PartyNumber (Not used) */
2522                         chan_misdn_log(1, bc->port, " -->%s  Telex: %s\n",
2523                                 Spacing, Party->Number);
2524                         break;
2525                 case 5: /* Private PartyNumber */
2526                         chan_misdn_log(1, bc->port, " -->%s  Private TON:%d %s\n",
2527                                 Spacing, Party->TypeOfNumber, Party->Number);
2528                         break;
2529                 case 8: /* National Standard PartyNumber (Not used) */
2530                         chan_misdn_log(1, bc->port, " -->%s  National: %s\n",
2531                                 Spacing, Party->Number);
2532                         break;
2533                 default:
2534                         break;
2535                 }
2536         }
2537 }
2538 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2539
2540 #if defined(AST_MISDN_ENHANCEMENTS)
2541 static void print_facility_Subaddress(unsigned Level, const struct FacPartySubaddress *Subaddress, const struct misdn_bchannel *bc)
2542 {
2543         if (Subaddress->Length) {
2544                 const char *Spacing;
2545
2546                 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2547                 chan_misdn_log(1, bc->port, " -->%s Subaddress: Type:%d\n",
2548                         Spacing, Subaddress->Type);
2549                 switch (Subaddress->Type) {
2550                 case 0: /* UserSpecified */
2551                         if (Subaddress->u.UserSpecified.OddCountPresent) {
2552                                 chan_misdn_log(1, bc->port, " -->%s  User BCD OddCount:%d NumOctets:%d\n",
2553                                         Spacing, Subaddress->u.UserSpecified.OddCount, Subaddress->Length);
2554                         } else {
2555                                 chan_misdn_log(1, bc->port, " -->%s  User: %s\n",
2556                                         Spacing, Subaddress->u.UserSpecified.Information);
2557                         }
2558                         break;
2559                 case 1: /* NSAP */
2560                         chan_misdn_log(1, bc->port, " -->%s  NSAP: %s\n",
2561                                 Spacing, Subaddress->u.Nsap);
2562                         break;
2563                 default:
2564                         break;
2565                 }
2566         }
2567 }
2568 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2569
2570 #if defined(AST_MISDN_ENHANCEMENTS)
2571 static void print_facility_Address(unsigned Level, const struct FacAddress *Address, const struct misdn_bchannel *bc)
2572 {
2573         print_facility_PartyNumber(Level, &Address->Party, bc);
2574         print_facility_Subaddress(Level, &Address->Subaddress, bc);
2575 }
2576 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2577
2578 #if defined(AST_MISDN_ENHANCEMENTS)
2579 static void print_facility_PresentedNumberUnscreened(unsigned Level, const struct FacPresentedNumberUnscreened *Presented, const struct misdn_bchannel *bc)
2580 {
2581         const char *Spacing;
2582
2583         Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2584         chan_misdn_log(1, bc->port, " -->%s Unscreened Type:%d\n", Spacing, Presented->Type);
2585         switch (Presented->Type) {
2586         case 0: /* presentationAllowedNumber */
2587                 chan_misdn_log(1, bc->port, " -->%s  Allowed:\n", Spacing);
2588                 print_facility_PartyNumber(Level + 2, &Presented->Unscreened, bc);
2589                 break;
2590         case 1: /* presentationRestricted */
2591                 chan_misdn_log(1, bc->port, " -->%s  Restricted\n", Spacing);
2592                 break;
2593         case 2: /* numberNotAvailableDueToInterworking */
2594                 chan_misdn_log(1, bc->port, " -->%s  Not Available\n", Spacing);
2595                 break;
2596         case 3: /* presentationRestrictedNumber */
2597                 chan_misdn_log(1, bc->port, " -->%s  Restricted:\n", Spacing);
2598                 print_facility_PartyNumber(Level + 2, &Presented->Unscreened, bc);
2599                 break;
2600         default:
2601                 break;
2602         }
2603 }
2604 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2605
2606 #if defined(AST_MISDN_ENHANCEMENTS)
2607 static void print_facility_AddressScreened(unsigned Level, const struct FacAddressScreened *Address, const struct misdn_bchannel *bc)
2608 {
2609         const char *Spacing;
2610
2611         Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2612         chan_misdn_log(1, bc->port, " -->%s ScreeningIndicator:%d\n", Spacing, Address->ScreeningIndicator);
2613         print_facility_PartyNumber(Level, &Address->Party, bc);
2614         print_facility_Subaddress(Level, &Address->Subaddress, bc);
2615 }
2616 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2617
2618 #if defined(AST_MISDN_ENHANCEMENTS)
2619 static void print_facility_PresentedAddressScreened(unsigned Level, const struct FacPresentedAddressScreened *Presented, const struct misdn_bchannel *bc)
2620 {
2621         const char *Spacing;
2622
2623         Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2624         chan_misdn_log(1, bc->port, " -->%s Screened Type:%d\n", Spacing, Presented->Type);
2625         switch (Presented->Type) {
2626         case 0: /* presentationAllowedAddress */
2627                 chan_misdn_log(1, bc->port, " -->%s  Allowed:\n", Spacing);
2628                 print_facility_AddressScreened(Level + 2, &Presented->Address, bc);
2629                 break;
2630         case 1: /* presentationRestricted */
2631                 chan_misdn_log(1, bc->port, " -->%s  Restricted\n", Spacing);
2632                 break;
2633         case 2: /* numberNotAvailableDueToInterworking */
2634                 chan_misdn_log(1, bc->port, " -->%s  Not Available\n", Spacing);
2635                 break;
2636         case 3: /* presentationRestrictedAddress */
2637                 chan_misdn_log(1, bc->port, " -->%s  Restricted:\n", Spacing);
2638                 print_facility_AddressScreened(Level + 2, &Presented->Address, bc);
2639                 break;
2640         default:
2641                 break;
2642         }
2643 }
2644 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2645
2646 #if defined(AST_MISDN_ENHANCEMENTS)
2647 static void print_facility_Q931_Bc_Hlc_Llc(unsigned Level, const struct Q931_Bc_Hlc_Llc *Q931ie, const struct misdn_bchannel *bc)
2648 {
2649         const char *Spacing;
2650
2651         Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2652         chan_misdn_log(1, bc->port, " -->%s Q931ie:\n", Spacing);
2653         if (Q931ie->Bc.Length) {
2654                 chan_misdn_log(1, bc->port, " -->%s  Bc Len:%d\n", Spacing, Q931ie->Bc.Length);
2655         }
2656         if (Q931ie->Hlc.Length) {
2657                 chan_misdn_log(1, bc->port, " -->%s  Hlc Len:%d\n", Spacing, Q931ie->Hlc.Length);
2658         }
2659         if (Q931ie->Llc.Length) {
2660                 chan_misdn_log(1, bc->port, " -->%s  Llc Len:%d\n", Spacing, Q931ie->Llc.Length);
2661         }
2662 }
2663 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2664
2665 #if defined(AST_MISDN_ENHANCEMENTS)
2666 static void print_facility_Q931_Bc_Hlc_Llc_Uu(unsigned Level, const struct Q931_Bc_Hlc_Llc_Uu *Q931ie, const struct misdn_bchannel *bc)
2667 {
2668         const char *Spacing;
2669
2670         Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2671         chan_misdn_log(1, bc->port, " -->%s Q931ie:\n", Spacing);
2672         if (Q931ie->Bc.Length) {
2673                 chan_misdn_log(1, bc->port, " -->%s  Bc Len:%d\n", Spacing, Q931ie->Bc.Length);
2674         }
2675         if (Q931ie->Hlc.Length) {
2676                 chan_misdn_log(1, bc->port, " -->%s  Hlc Len:%d\n", Spacing, Q931ie->Hlc.Length);
2677         }
2678         if (Q931ie->Llc.Length) {
2679                 chan_misdn_log(1, bc->port, " -->%s  Llc Len:%d\n", Spacing, Q931ie->Llc.Length);
2680         }
2681         if (Q931ie->UserInfo.Length) {
2682                 chan_misdn_log(1, bc->port, " -->%s  UserInfo Len:%d\n", Spacing, Q931ie->UserInfo.Length);
2683         }
2684 }
2685 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2686
2687 #if defined(AST_MISDN_ENHANCEMENTS)
2688 static void print_facility_CallInformation(unsigned Level, const struct FacCallInformation *CallInfo, const struct misdn_bchannel *bc)
2689 {
2690         const char *Spacing;
2691
2692         Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2693         chan_misdn_log(1, bc->port, " -->%s CCBSReference:%d\n",
2694                 Spacing, CallInfo->CCBSReference);
2695         chan_misdn_log(1, bc->port, " -->%s AddressOfB:\n", Spacing);
2696         print_facility_Address(Level + 1, &CallInfo->AddressOfB, bc);
2697         print_facility_Q931_Bc_Hlc_Llc(Level, &CallInfo->Q931ie, bc);
2698         if (CallInfo->SubaddressOfA.Length) {
2699                 chan_misdn_log(1, bc->port, " -->%s SubaddressOfA:\n", Spacing);
2700                 print_facility_Subaddress(Level + 1, &CallInfo->SubaddressOfA, bc);
2701         }
2702 }
2703 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2704
2705 #if defined(AST_MISDN_ENHANCEMENTS)
2706 static void print_facility_ServedUserNr(unsigned Level, const struct FacPartyNumber *Party, const struct misdn_bchannel *bc)
2707 {
2708         const char *Spacing;
2709
2710         Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2711         if (Party->LengthOfNumber) {
2712                 print_facility_PartyNumber(Level, Party, bc);
2713         } else {
2714                 chan_misdn_log(1, bc->port, " -->%s All Numbers\n", Spacing);
2715         }
2716 }
2717 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2718
2719 #if defined(AST_MISDN_ENHANCEMENTS)
2720 static void print_facility_IntResult(unsigned Level, const struct FacForwardingRecord *ForwardingRecord, const struct misdn_bchannel *bc)
2721 {
2722         const char *Spacing;
2723
2724         Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2725         chan_misdn_log(1, bc->port, " -->%s Procedure:%d BasicService:%d\n",
2726                 Spacing,
2727                 ForwardingRecord->Procedure,
2728                 ForwardingRecord->BasicService);
2729         chan_misdn_log(1, bc->port, " -->%s ForwardedTo:\n", Spacing);
2730         print_facility_Address(Level + 1, &ForwardingRecord->ForwardedTo, bc);
2731         chan_misdn_log(1, bc->port, " -->%s ServedUserNr:\n", Spacing);
2732         print_facility_ServedUserNr(Level + 1, &ForwardingRecord->ServedUser, bc);
2733 }
2734 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2735
2736 static void print_facility(const struct FacParm *fac, const const struct misdn_bchannel *bc)
2737 {
2738 #if defined(AST_MISDN_ENHANCEMENTS)
2739         unsigned Index;
2740 #endif  /* defined(AST_MISDN_ENHANCEMENTS) */
2741
2742         switch (fac->Function) {
2743 #if defined(AST_MISDN_ENHANCEMENTS)
2744         case Fac_ActivationDiversion:
2745                 chan_misdn_log(1, bc->port, " --> ActivationDiversion: InvokeID:%d\n",
2746                         fac->u.ActivationDiversion.InvokeID);
2747                 switch (fac->u.ActivationDiversion.ComponentType) {
2748                 case FacComponent_Invoke:
2749                         chan_misdn_log(1, bc->port, " -->  Invoke: Procedure:%d BasicService:%d\n",
2750                                 fac->u.ActivationDiversion.Component.Invoke.Procedure,
2751                                 fac->u.ActivationDiversion.Component.Invoke.BasicService);
2752                         chan_misdn_log(1, bc->port, " -->   ForwardedTo:\n");
2753                         print_facility_Address(3, &fac->u.ActivationDiversion.Component.Invoke.ForwardedTo, bc);
2754                         chan_misdn_log(1, bc->port, " -->   ServedUserNr:\n");
2755                         print_facility_ServedUserNr(3, &fac->u.ActivationDiversion.Component.Invoke.ServedUser, bc);
2756                         break;
2757                 case FacComponent_Result:
2758                         chan_misdn_log(1, bc->port, " -->  Result\n");
2759                         break;
2760                 default:
2761                         break;
2762                 }
2763                 break;
2764         case Fac_DeactivationDiversion:
2765                 chan_misdn_log(1, bc->port, " --> DeactivationDiversion: InvokeID:%d\n",
2766                         fac->u.DeactivationDiversion.InvokeID);
2767                 switch (fac->u.DeactivationDiversion.ComponentType) {
2768                 case FacComponent_Invoke:
2769                         chan_misdn_log(1, bc->port, " -->  Invoke: Procedure:%d BasicService:%d\n",
2770                                 fac->u.DeactivationDiversion.Component.Invoke.Procedure,
2771                                 fac->u.DeactivationDiversion.Component.Invoke.BasicService);
2772                         chan_misdn_log(1, bc->port, " -->   ServedUserNr:\n");
2773                         print_facility_ServedUserNr(3, &fac->u.DeactivationDiversion.Component.Invoke.ServedUser, bc);
2774                         break;
2775                 case FacComponent_Result:
2776                         chan_misdn_log(1, bc->port, " -->  Result\n");
2777                         break;
2778                 default:
2779                         break;
2780                 }
2781                 break;
2782         case Fac_ActivationStatusNotificationDiv:
2783                 chan_misdn_log(1, bc->port, " --> ActivationStatusNotificationDiv: InvokeID:%d Procedure:%d BasicService:%d\n",
2784                         fac->u.ActivationStatusNotificationDiv.InvokeID,
2785                         fac->u.ActivationStatusNotificationDiv.Procedure,
2786                         fac->u.ActivationStatusNotificationDiv.BasicService);
2787                 chan_misdn_log(1, bc->port, " -->  ForwardedTo:\n");
2788                 print_facility_Address(2, &fac->u.ActivationStatusNotificationDiv.ForwardedTo, bc);
2789                 chan_misdn_log(1, bc->port, " -->  ServedUserNr:\n");
2790                 print_facility_ServedUserNr(2, &fac->u.ActivationStatusNotificationDiv.ServedUser, bc);
2791                 break;
2792         case Fac_DeactivationStatusNotificationDiv:
2793                 chan_misdn_log(1, bc->port, " --> DeactivationStatusNotificationDiv: InvokeID:%d Procedure:%d BasicService:%d\n",
2794                         fac->u.DeactivationStatusNotificationDiv.InvokeID,
2795                         fac->u.DeactivationStatusNotificationDiv.Procedure,
2796                         fac->u.DeactivationStatusNotificationDiv.BasicService);
2797                 chan_misdn_log(1, bc->port, " -->  ServedUserNr:\n");
2798                 print_facility_ServedUserNr(2, &fac->u.DeactivationStatusNotificationDiv.ServedUser, bc);
2799                 break;
2800         case Fac_InterrogationDiversion:
2801                 chan_misdn_log(1, bc->port, " --> InterrogationDiversion: InvokeID:%d\n",
2802                         fac->u.InterrogationDiversion.InvokeID);
2803                 switch (fac->u.InterrogationDiversion.ComponentType) {
2804                 case FacComponent_Invoke:
2805                         chan_misdn_log(1, bc->port, " -->  Invoke: Procedure:%d BasicService:%d\n",
2806                                 fac->u.InterrogationDiversion.Component.Invoke.Procedure,
2807                                 fac->u.InterrogationDiversion.Component.Invoke.BasicService);
2808                         chan_misdn_log(1, bc->port, " -->   ServedUserNr:\n");
2809                         print_facility_ServedUserNr(3, &fac->u.InterrogationDiversion.Component.Invoke.ServedUser, bc);
2810                         break;
2811                 case FacComponent_Result:
2812                         chan_misdn_log(1, bc->port, " -->  Result:\n");
2813                         if (fac->u.InterrogationDiversion.Component.Result.NumRecords) {
2814                                 for (Index = 0; Index < fac->u.InterrogationDiversion.Component.Result.NumRecords; ++Index) {
2815                                         chan_misdn_log(1, bc->port, " -->   IntResult[%d]:\n", Index);
2816                                         print_facility_IntResult(3, &fac->u.InterrogationDiversion.Component.Result.List[Index], bc);
2817                                 }
2818                         }
2819                         break;
2820                 default:
2821                         break;
2822                 }
2823                 break;
2824         case Fac_DiversionInformation:
2825                 chan_misdn_log(1, bc->port, " --> DiversionInformation: InvokeID:%d Reason:%d BasicService:%d\n",
2826                         fac->u.DiversionInformation.InvokeID,
2827                         fac->u.DiversionInformation.DiversionReason,
2828                         fac->u.DiversionInformation.BasicService);
2829                 if (fac->u.DiversionInformation.ServedUserSubaddress.Length) {
2830                         chan_misdn_log(1, bc->port, " -->  ServedUserSubaddress:\n");
2831                         print_facility_Subaddress(2, &fac->u.DiversionInformation.ServedUserSubaddress, bc);
2832                 }
2833                 if (fac->u.DiversionInformation.CallingAddressPresent) {
2834                         chan_misdn_log(1, bc->port, " -->  CallingAddress:\n");
2835                         print_facility_PresentedAddressScreened(2, &fac->u.DiversionInformation.CallingAddress, bc);
2836                 }
2837                 if (fac->u.DiversionInformation.OriginalCalledPresent) {
2838                         chan_misdn_log(1, bc->port, " -->  OriginalCalledNr:\n");
2839                         print_facility_PresentedNumberUnscreened(2, &fac->u.DiversionInformation.OriginalCalled, bc);
2840                 }
2841                 if (fac->u.DiversionInformation.LastDivertingPresent) {
2842                         chan_misdn_log(1, bc->port, " -->  LastDivertingNr:\n");
2843                         print_facility_PresentedNumberUnscreened(2, &fac->u.DiversionInformation.LastDiverting, bc);
2844                 }
2845                 if (fac->u.DiversionInformation.LastDivertingReasonPresent) {
2846                         chan_misdn_log(1, bc->port, " -->  LastDivertingReason:%d\n", fac->u.DiversionInformation.LastDivertingReason);
2847                 }
2848                 if (fac->u.DiversionInformation.UserInfo.Length) {
2849                         chan_misdn_log(1, bc->port, " -->  UserInfo Length:%d\n", fac->u.DiversionInformation.UserInfo.Length);
2850                 }
2851                 break;
2852         case Fac_CallDeflection:
2853                 chan_misdn_log(1, bc->port, " --> CallDeflection: InvokeID:%d\n",
2854                         fac->u.CallDeflection.InvokeID);
2855                 switch (fac->u.CallDeflection.ComponentType) {
2856                 case FacComponent_Invoke:
2857                         chan_misdn_log(1, bc->port, " -->  Invoke:\n");
2858                         if (fac->u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent) {
2859                                 chan_misdn_log(1, bc->port, " -->   PresentationAllowed:%d\n",
2860                                         fac->u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser);
2861                         }
2862                         chan_misdn_log(1, bc->port, " -->   DeflectionAddress:\n");
2863                         print_facility_Address(3, &fac->u.CallDeflection.Component.Invoke.Deflection, bc);
2864                         break;
2865                 case FacComponent_Result:
2866                         chan_misdn_log(1, bc->port, " -->  Result\n");
2867                         break;
2868                 default:
2869                         break;
2870                 }
2871                 break;
2872         case Fac_CallRerouteing:
2873                 chan_misdn_log(1, bc->port, " --> CallRerouteing: InvokeID:%d\n",
2874                         fac->u.CallRerouteing.InvokeID);
2875                 switch (fac->u.CallRerouteing.ComponentType) {
2876                 case FacComponent_Invoke:
2877                         chan_misdn_log(1, bc->port, " -->  Invoke: Reason:%d Counter:%d\n",
2878                                 fac->u.CallRerouteing.Component.Invoke.ReroutingReason,
2879                                 fac->u.CallRerouteing.Component.Invoke.ReroutingCounter);
2880                         chan_misdn_log(1, bc->port, " -->   CalledAddress:\n");
2881                         print_facility_Address(3, &fac->u.CallRerouteing.Component.Invoke.CalledAddress, bc);
2882                         print_facility_Q931_Bc_Hlc_Llc_Uu(2, &fac->u.CallRerouteing.Component.Invoke.Q931ie, bc);
2883                         chan_misdn_log(1, bc->port, " -->   LastReroutingNr:\n");
2884                         print_facility_PresentedNumberUnscreened(3, &fac->u.CallRerouteing.Component.Invoke.LastRerouting, bc);
2885                         chan_misdn_log(1, bc->port, " -->   SubscriptionOption:%d\n",
2886                                 fac->u.CallRerouteing.Component.Invoke.SubscriptionOption);
2887                         if (fac->u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length) {
2888                                 chan_misdn_log(1, bc->port, " -->   CallingParty:\n");
2889                                 print_facility_Subaddress(3, &fac->u.CallRerouteing.Component.Invoke.CallingPartySubaddress, bc);
2890                         }
2891                         break;
2892                 case FacComponent_Result:
2893                         chan_misdn_log(1, bc->port, " -->  Result\n");
2894                         break;
2895                 default:
2896                         break;
2897                 }
2898                 break;
2899         case Fac_InterrogateServedUserNumbers:
2900                 chan_misdn_log(1, bc->port, " --> InterrogateServedUserNumbers: InvokeID:%d\n",
2901                         fac->u.InterrogateServedUserNumbers.InvokeID);
2902                 switch (fac->u.InterrogateServedUserNumbers.ComponentType) {
2903                 case FacComponent_Invoke:
2904                         chan_misdn_log(1, bc->port, " -->  Invoke\n");
2905                         break;
2906                 case FacComponent_Result:
2907                         chan_misdn_log(1, bc->port, " -->  Result:\n");
2908                         if (fac->u.InterrogateServedUserNumbers.Component.Result.NumRecords) {
2909                                 for (Index = 0; Index < fac->u.InterrogateServedUserNumbers.Component.Result.NumRecords; ++Index) {
2910                                         chan_misdn_log(1, bc->port, " -->   ServedUserNr[%d]:\n", Index);
2911                                         print_facility_PartyNumber(3, &fac->u.InterrogateServedUserNumbers.Component.Result.List[Index], bc);
2912                                 }
2913                         }
2914                         break;
2915                 default:
2916                         break;
2917                 }
2918                 break;
2919         case Fac_DivertingLegInformation1:
2920                 chan_misdn_log(1, bc->port, " --> DivertingLegInformation1: InvokeID:%d Reason:%d SubscriptionOption:%d\n",
2921                         fac->u.DivertingLegInformation1.InvokeID,
2922                         fac->u.DivertingLegInformation1.DiversionReason,
2923                         fac->u.DivertingLegInformation1.SubscriptionOption);
2924                 if (fac->u.DivertingLegInformation1.DivertedToPresent) {
2925                         chan_misdn_log(1, bc->port, " -->  DivertedToNr:\n");
2926                         print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation1.DivertedTo, bc);
2927                 }
2928                 break;
2929         case Fac_DivertingLegInformation2:
2930                 chan_misdn_log(1, bc->port, " --> DivertingLegInformation2: InvokeID:%d Reason:%d Count:%d\n",
2931                         fac->u.DivertingLegInformation2.InvokeID,
2932                         fac->u.DivertingLegInformation2.DiversionReason,
2933                         fac->u.DivertingLegInformation2.DiversionCounter);
2934                 if (fac->u.DivertingLegInformation2.DivertingPresent) {
2935                         chan_misdn_log(1, bc->port, " -->  DivertingNr:\n");
2936                         print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation2.Diverting, bc);
2937                 }
2938                 if (fac->u.DivertingLegInformation2.OriginalCalledPresent) {
2939                         chan_misdn_log(1, bc->port, " -->  OriginalCalledNr:\n");
2940                         print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation2.OriginalCalled, bc);
2941                 }
2942                 break;
2943         case Fac_DivertingLegInformation3:
2944                 chan_misdn_log(1, bc->port, " --> DivertingLegInformation3: InvokeID:%d PresentationAllowed:%d\n",
2945                         fac->u.DivertingLegInformation3.InvokeID,
2946                         fac->u.DivertingLegInformation3.PresentationAllowedIndicator);
2947                 break;
2948
2949 #else   /* !defined(AST_MISDN_ENHANCEMENTS) */
2950
2951         case Fac_CD:
2952                 chan_misdn_log(1, bc->port, " --> calldeflect to: %s, presentable: %s\n", fac->u.CDeflection.DeflectedToNumber,
2953                         fac->u.CDeflection.PresentationAllowed ? "yes" : "no");
2954                 break;
2955 #endif  /* !defined(AST_MISDN_ENHANCEMENTS) */
2956         case Fac_AOCDCurrency:
2957                 if (fac->u.AOCDcur.chargeNotAvailable) {
2958                         chan_misdn_log(1, bc->port, " --> AOCD currency: charge not available\n");
2959                 } else if (fac->u.AOCDcur.freeOfCharge) {
2960                         chan_misdn_log(1, bc->port, " --> AOCD currency: free of charge\n");
2961                 } else if (fac->u.AOCDchu.billingId >= 0) {
2962                         chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s billingId:%d\n",
2963                                 fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
2964                                 (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDcur.billingId);
2965                 } else {
2966                         chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s\n",
2967                                 fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
2968                                 (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total");
2969                 }
2970                 break;
2971         case Fac_AOCDChargingUnit:
2972                 if (fac->u.AOCDchu.chargeNotAvailable) {
2973                         chan_misdn_log(1, bc->port, " --> AOCD charging unit: charge not available\n");
2974                 } else if (fac->u.AOCDchu.freeOfCharge) {
2975                         chan_misdn_log(1, bc->port, " --> AOCD charging unit: free of charge\n");
2976                 } else if (fac->u.AOCDchu.billingId >= 0) {
2977                         chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d\n",
2978                                 fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDchu.billingId);
2979                 } else {
2980                         chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n",
2981                                 fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total");
2982                 }
2983                 break;
2984 #if defined(AST_MISDN_ENHANCEMENTS)
2985         case Fac_ERROR:
2986                 chan_misdn_log(1, bc->port, " --> ERROR: InvokeID:%d, Code:0x%02x\n",
2987                         fac->u.ERROR.invokeId, fac->u.ERROR.errorValue);
2988                 break;
2989         case Fac_RESULT:
2990                 chan_misdn_log(1, bc->port, " --> RESULT: InvokeID:%d\n",
2991                         fac->u.RESULT.InvokeID);
2992                 break;
2993         case Fac_REJECT:
2994                 if (fac->u.REJECT.InvokeIDPresent) {
2995                         chan_misdn_log(1, bc->port, " --> REJECT: InvokeID:%d, Code:0x%02x\n",
2996                                 fac->u.REJECT.InvokeID, fac->u.REJECT.Code);
2997                 } else {
2998                         chan_misdn_log(1, bc->port, " --> REJECT: Code:0x%02x\n",
2999                                 fac->u.REJECT.Code);
3000                 }
3001                 break;
3002         case Fac_EctExecute:
3003                 chan_misdn_log(1, bc->port, " --> EctExecute: InvokeID:%d\n",
3004                         fac->u.EctExecute.InvokeID);
3005                 break;
3006         case Fac_ExplicitEctExecute:
3007                 chan_misdn_log(1, bc->port, " --> ExplicitEctExecute: InvokeID:%d LinkID:%d\n",
3008                         fac->u.ExplicitEctExecute.InvokeID,
3009                         fac->u.ExplicitEctExecute.LinkID);
3010                 break;
3011         case Fac_RequestSubaddress:
3012                 chan_misdn_log(1, bc->port, " --> RequestSubaddress: InvokeID:%d\n",
3013                         fac->u.RequestSubaddress.InvokeID);
3014                 break;
3015         case Fac_SubaddressTransfer:
3016                 chan_misdn_log(1, bc->port, " --> SubaddressTransfer: InvokeID:%d\n",
3017                         fac->u.SubaddressTransfer.InvokeID);
3018                 print_facility_Subaddress(1, &fac->u.SubaddressTransfer.Subaddress, bc);
3019                 break;
3020         case Fac_EctLinkIdRequest:
3021                 chan_misdn_log(1, bc->port, " --> EctLinkIdRequest: InvokeID:%d\n",
3022                         fac->u.EctLinkIdRequest.InvokeID);
3023                 switch (fac->u.EctLinkIdRequest.ComponentType) {
3024                 case FacComponent_Invoke:
3025                         chan_misdn_log(1, bc->port, " -->  Invoke\n");
3026                         break;
3027                 case FacComponent_Result:
3028                         chan_misdn_log(1, bc->port, " -->  Result: LinkID:%d\n",
3029                                 fac->u.EctLinkIdRequest.Component.Result.LinkID);
3030                         break;
3031                 default:
3032                         break;
3033                 }
3034                 break;
3035         case Fac_EctInform:
3036                 chan_misdn_log(1, bc->port, " --> EctInform: InvokeID:%d Status:%d\n",
3037                         fac->u.EctInform.InvokeID,
3038                         fac->u.EctInform.Status);
3039                 if (fac->u.EctInform.RedirectionPresent) {
3040                         chan_misdn_log(1, bc->port, " -->  Redirection Number\n");
3041                         print_facility_PresentedNumberUnscreened(2, &fac->u.EctInform.Redirection, bc);
3042                 }
3043                 break;
3044         case Fac_EctLoopTest:
3045                 chan_misdn_log(1, bc->port, " --> EctLoopTest: InvokeID:%d\n",
3046                         fac->u.EctLoopTest.InvokeID);
3047                 switch (fac->u.EctLoopTest.ComponentType) {
3048                 case FacComponent_Invoke:
3049                         chan_misdn_log(1, bc->port, " -->  Invoke: CallTransferID:%d\n",
3050                                 fac->u.EctLoopTest.Component.Invoke.CallTransferID);
3051                         break;
3052                 case FacComponent_Result:
3053                         chan_misdn_log(1, bc->port, " -->  Result: LoopResult:%d\n",
3054                                 fac->u.EctLoopTest.Component.Result.LoopResult);
3055                         break;
3056                 default:
3057                         break;
3058                 }
3059                 break;
3060         case Fac_StatusRequest:
3061                 chan_misdn_log(1, bc->port, " --> StatusRequest: InvokeID:%d\n",
3062                         fac->u.StatusRequest.InvokeID);
3063                 switch (fac->u.StatusRequest.ComponentType) {
3064                 case FacComponent_Invoke:
3065                         chan_misdn_log(1, bc->port, " -->  Invoke: Compatibility:%d\n",
3066                                 fac->u.StatusRequest.Component.Invoke.CompatibilityMode);
3067                         break;
3068                 case FacComponent_Result:
3069                         chan_misdn_log(1, bc->port, " -->  Result: Status:%d\n",
3070                                 fac->u.StatusRequest.Component.Result.Status);
3071                         break;
3072                 default:
3073                         break;
3074                 }
3075                 break;
3076         case Fac_CallInfoRetain:
3077                 chan_misdn_log(1, bc->port, " --> CallInfoRetain: InvokeID:%d, LinkageID:%d\n",
3078                         fac->u.CallInfoRetain.InvokeID, fac->u.CallInfoRetain.CallLinkageID);
3079                 break;
3080         case Fac_CCBSDeactivate:
3081                 chan_misdn_log(1, bc->port, " --> CCBSDeactivate: InvokeID:%d\n",
3082                         fac->u.CCBSDeactivate.InvokeID);
3083                 switch (fac->u.CCBSDeactivate.ComponentType) {
3084                 case FacComponent_Invoke:
3085                         chan_misdn_log(1, bc->port, " -->  Invoke: CCBSReference:%d\n",
3086                                 fac->u.CCBSDeactivate.Component.Invoke.CCBSReference);
3087                         break;
3088                 case FacComponent_Result:
3089                         chan_misdn_log(1, bc->port, " -->  Result\n");
3090                         break;
3091                 default:
3092                         break;
3093                 }
3094                 break;
3095         case Fac_CCBSErase:
3096                 chan_misdn_log(1, bc->port, " --> CCBSErase: InvokeID:%d, CCBSReference:%d RecallMode:%d, Reason:%d\n",
3097                         fac->u.CCBSErase.InvokeID, fac->u.CCBSErase.CCBSReference,
3098                         fac->u.CCBSErase.RecallMode, fac->u.CCBSErase.Reason);
3099                 chan_misdn_log(1, bc->port, " -->  AddressOfB\n");
3100                 print_facility_Address(2, &fac->u.CCBSErase.AddressOfB, bc);
3101                 print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSErase.Q931ie, bc);
3102                 break;
3103         case Fac_CCBSRemoteUserFree:
3104                 chan_misdn_log(1, bc->port, " --> CCBSRemoteUserFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
3105                         fac->u.CCBSRemoteUserFree.InvokeID, fac->u.CCBSRemoteUserFree.CCBSReference,
3106                         fac->u.CCBSRemoteUserFree.RecallMode);
3107                 chan_misdn_log(1, bc->port, " -->  AddressOfB\n");
3108                 print_facility_Address(2, &fac->u.CCBSRemoteUserFree.AddressOfB, bc);
3109                 print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSRemoteUserFree.Q931ie, bc);
3110                 break;
3111         case Fac_CCBSCall:
3112                 chan_misdn_log(1, bc->port, " --> CCBSCall: InvokeID:%d, CCBSReference:%d\n",
3113                         fac->u.CCBSCall.InvokeID, fac->u.CCBSCall.CCBSReference);
3114                 break;
3115         case Fac_CCBSStatusRequest:
3116                 chan_misdn_log(1, bc->port, " --> CCBSStatusRequest: InvokeID:%d\n",
3117                         fac->u.CCBSStatusRequest.InvokeID);
3118                 switch (fac->u.CCBSStatusRequest.ComponentType) {
3119                 case FacComponent_Invoke:
3120                         chan_misdn_log(1, bc->port, " -->  Invoke: CCBSReference:%d RecallMode:%d\n",
3121                                 fac->u.CCBSStatusRequest.Component.Invoke.CCBSReference,
3122                                 fac->u.CCBSStatusRequest.Component.Invoke.RecallMode);
3123                         print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCBSStatusRequest.Component.Invoke.Q931ie, bc);
3124                         break;
3125                 case FacComponent_Result:
3126                         chan_misdn_log(1, bc->port, " -->  Result: Free:%d\n",
3127                                 fac->u.CCBSStatusRequest.Component.Result.Free);
3128                         break;
3129                 default:
3130                         break;
3131                 }
3132                 break;
3133         case Fac_CCBSBFree:
3134                 chan_misdn_log(1, bc->port, " --> CCBSBFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
3135                         fac->u.CCBSBFree.InvokeID, fac->u.CCBSBFree.CCBSReference,
3136                         fac->u.CCBSBFree.RecallMode);
3137                 chan_misdn_log(1, bc->port, " -->  AddressOfB\n");
3138                 print_facility_Address(2, &fac->u.CCBSBFree.AddressOfB, bc);
3139                 print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSBFree.Q931ie, bc);
3140                 break;
3141         case Fac_EraseCallLinkageID:
3142                 chan_misdn_log(1, bc->port, " --> EraseCallLinkageID: InvokeID:%d, LinkageID:%d\n",
3143                         fac->u.EraseCallLinkageID.InvokeID, fac->u.EraseCallLinkageID.CallLinkageID);
3144                 break;
3145         case Fac_CCBSStopAlerting:
3146                 chan_misdn_log(1, bc->port, " --> CCBSStopAlerting: InvokeID:%d, CCBSReference:%d\n",
3147                         fac->u.CCBSStopAlerting.InvokeID, fac->u.CCBSStopAlerting.CCBSReference);
3148                 break;
3149         case Fac_CCBSRequest:
3150                 chan_misdn_log(1, bc->port, " --> CCBSRequest: InvokeID:%d\n",
3151                         fac->u.CCBSRequest.InvokeID);
3152                 switch (fac->u.CCBSRequest.ComponentType) {
3153                 case FacComponent_Invoke:
3154                         chan_misdn_log(1, bc->port, " -->  Invoke: LinkageID:%d\n",
3155                                 fac->u.CCBSRequest.Component.Invoke.CallLinkageID);
3156                         break;
3157                 case FacComponent_Result:
3158                         chan_misdn_log(1, bc->port, " -->  Result: CCBSReference:%d RecallMode:%d\n",
3159                                 fac->u.CCBSRequest.Component.Result.CCBSReference,
3160                                 fac->u.CCBSRequest.Component.Result.RecallMode);
3161                         break;
3162                 default:
3163                         break;
3164                 }
3165                 break;
3166         case Fac_CCBSInterrogate:
3167                 chan_misdn_log(1, bc->port, " --> CCBSInterrogate: InvokeID:%d\n",
3168                         fac->u.CCBSInterrogate.InvokeID);
3169                 switch (fac->u.CCBSInterrogate.ComponentType) {
3170                 case FacComponent_Invoke:
3171                         chan_misdn_log(1, bc->port, " -->  Invoke\n");
3172                         if (fac->u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent) {
3173                                 chan_misdn_log(1, bc->port, " -->   CCBSReference:%d\n",
3174                                         fac->u.CCBSInterrogate.Component.Invoke.CCBSReference);
3175                         }
3176                         if (fac->u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber) {
3177                                 chan_misdn_log(1, bc->port, " -->   AParty\n");
3178                                 print_facility_PartyNumber(3, &fac->u.CCBSInterrogate.Component.Invoke.AParty, bc);
3179                         }
3180                         break;
3181                 case FacComponent_Result:
3182                         chan_misdn_log(1, bc->port, " -->  Result: RecallMode:%d\n",
3183                                 fac->u.CCBSInterrogate.Component.Result.RecallMode);
3184                         if (fac->u.CCBSInterrogate.Component.Result.NumRecords) {
3185                                 for (Index = 0; Index < fac->u.CCBSInterrogate.Component.Result.NumRecords; ++Index) {
3186                                         chan_misdn_log(1, bc->port, " -->   CallDetails[%d]:\n", Index);
3187                                         print_facility_CallInformation(3, &fac->u.CCBSInterrogate.Component.Result.CallDetails[Index], bc);
3188                                 }
3189                         }
3190                         break;
3191                 default:
3192                         break;
3193                 }
3194                 break;
3195         case Fac_CCNRRequest:
3196                 chan_misdn_log(1, bc->port, " --> CCNRRequest: InvokeID:%d\n",
3197                         fac->u.CCNRRequest.InvokeID);
3198                 switch (fac->u.CCNRRequest.ComponentType) {
3199                 case FacComponent_Invoke:
3200                         chan_misdn_log(1, bc->port, " -->  Invoke: LinkageID:%d\n",
3201                                 fac->u.CCNRRequest.Component.Invoke.CallLinkageID);
3202                         break;
3203                 case FacComponent_Result:
3204                         chan_misdn_log(1, bc->port, " -->  Result: CCBSReference:%d RecallMode:%d\n",
3205                                 fac->u.CCNRRequest.Component.Result.CCBSReference,
3206                                 fac->u.CCNRRequest.Component.Result.RecallMode);
3207                         break;
3208                 default:
3209                         break;
3210                 }
3211                 break;
3212         case Fac_CCNRInterrogate:
3213                 chan_misdn_log(1, bc->port, " --> CCNRInterrogate: InvokeID:%d\n",
3214                         fac->u.CCNRInterrogate.InvokeID);
3215                 switch (fac->u.CCNRInterrogate.ComponentType) {
3216                 case FacComponent_Invoke:
3217                         chan_misdn_log(1, bc->port, " -->  Invoke\n");
3218                         if (fac->u.CCNRInterrogate.Component.Invoke.CCBSReferencePresent) {
3219                                 chan_misdn_log(1, bc->port, " -->   CCBSReference:%d\n",
3220                                         fac->u.CCNRInterrogate.Component.Invoke.CCBSReference);
3221                         }
3222                         if (fac->u.CCNRInterrogate.Component.Invoke.AParty.LengthOfNumber) {
3223                                 chan_misdn_log(1, bc->port, " -->   AParty\n");
3224                                 print_facility_PartyNumber(3, &fac->u.CCNRInterrogate.Component.Invoke.AParty, bc);
3225                         }
3226                         break;
3227                 case FacComponent_Result:
3228                         chan_misdn_log(1, bc->port, " -->  Result: RecallMode:%d\n",
3229                                 fac->u.CCNRInterrogate.Component.Result.RecallMode);
3230                         if (fac->u.CCNRInterrogate.Component.Result.NumRecords) {
3231                                 for (Index = 0; Index < fac->u.CCNRInterrogate.Component.Result.NumRecords; ++Index) {
3232                                         chan_misdn_log(1, bc->port, " -->   CallDetails[%d]:\n", Index);
3233                                         print_facility_CallInformation(3, &fac->u.CCNRInterrogate.Component.Result.CallDetails[Index], bc);
3234                                 }
3235                         }
3236                         break;
3237                 default:
3238                         break;
3239                 }
3240                 break;
3241         case Fac_CCBS_T_Call:
3242                 chan_misdn_log(1, bc->port, " --> CCBS_T_Call: InvokeID:%d\n",
3243                         fac->u.CCBS_T_Call.InvokeID);
3244                 break;
3245         case Fac_CCBS_T_Suspend:
3246                 chan_misdn_log(1, bc->port, " --> CCBS_T_Suspend: InvokeID:%d\n",
3247                         fac->u.CCBS_T_Suspend.InvokeID);
3248                 break;
3249         case Fac_CCBS_T_Resume:
3250                 chan_misdn_log(1, bc->port, " --> CCBS_T_Resume: InvokeID:%d\n",
3251                         fac->u.CCBS_T_Resume.InvokeID);
3252                 break;
3253         case Fac_CCBS_T_RemoteUserFree:
3254                 chan_misdn_log(1, bc->port, " --> CCBS_T_RemoteUserFree: InvokeID:%d\n",
3255                         fac->u.CCBS_T_RemoteUserFree.InvokeID);
3256                 break;
3257         case Fac_CCBS_T_Available:
3258                 chan_misdn_log(1, bc->port, " --> CCBS_T_Available: InvokeID:%d\n",
3259                         fac->u.CCBS_T_Available.InvokeID);
3260                 break;
3261         case Fac_CCBS_T_Request:
3262                 chan_misdn_log(1, bc->port, " --> CCBS_T_Request: InvokeID:%d\n",
3263                         fac->u.CCBS_T_Request.InvokeID);
3264                 switch (fac->u.CCBS_T_Request.ComponentType) {
3265                 case FacComponent_Invoke:
3266                         chan_misdn_log(1, bc->port, " -->  Invoke\n");
3267                         chan_misdn_log(1, bc->port, " -->   DestinationAddress:\n");
3268                         print_facility_Address(3, &fac->u.CCBS_T_Request.Component.Invoke.Destination, bc);
3269                         print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCBS_T_Request.Component.Invoke.Q931ie, bc);
3270                         if (fac->u.CCBS_T_Request.Component.Invoke.RetentionSupported) {
3271                                 chan_misdn_log(1, bc->port, " -->   RetentionSupported:1\n");
3272                         }
3273                         if (fac->u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent) {
3274                                 chan_misdn_log(1, bc->port, " -->   PresentationAllowed:%d\n",
3275                                         fac->u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator);
3276     &n