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