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