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