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