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