Asterisk - The Open Source Telephony Project  GIT-master-0190e70
chan_misdn.c
Go to the documentation of this file.
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  * MISDN http://www.misdn.org/
28  *
29  * \ingroup channel_drivers
30  */
31 
32 /*! \li \ref chan_misdn.c uses the configuration file \ref misdn.conf
33  * \addtogroup configuration_file
34  */
35 
36 /*! \page misdn.conf misdn.conf
37  * \verbinclude misdn.conf.sample
38  */
39 
40 /*!
41  * \note
42  * To use the CCBS/CCNR supplementary service feature and other
43  * supplementary services using FACILITY messages requires a
44  * modified version of mISDN.
45  *
46  * \note
47  * The latest modified mISDN v1.1.x based version is available at:
48  * http://svn.digium.com/svn/thirdparty/mISDN/trunk
49  * http://svn.digium.com/svn/thirdparty/mISDNuser/trunk
50  *
51  * \note
52  * Taged versions of the modified mISDN code are available under:
53  * http://svn.digium.com/svn/thirdparty/mISDN/tags
54  * http://svn.digium.com/svn/thirdparty/mISDNuser/tags
55  */
56 
57 /* Define to enable cli commands to generate canned CCBS messages. */
58 // #define CCBS_TEST_MESSAGES 1
59 
60 /*
61  * XXX The mISDN channel driver needs its native bridge code
62  * converted to the new bridge technology scheme. The
63  * chan_dahdi native bridge code can be used as an example. It
64  * is unlikely that this will ever get done. Support for this
65  * channel driver is dwindling because the supported version of
66  * mISDN does not support newer kernels.
67  *
68  * Without native bridge support, the following config file
69  * parameters have no effect: bridging.
70  *
71  * The existing native bridge code is marked with the
72  * mISDN_NATIVE_BRIDGING conditional.
73  */
74 
75 /*** MODULEINFO
76  <depend>isdnnet</depend>
77  <depend>misdn</depend>
78  <depend>suppserv</depend>
79  <support_level>deprecated</support_level>
80  <replacement>chan_dahdi</replacement>
81  ***/
82 
83 #include "asterisk.h"
84 
85 #include <pthread.h>
86 #include <sys/socket.h>
87 #include <sys/time.h>
88 #include <arpa/inet.h>
89 #include <fcntl.h>
90 #include <sys/ioctl.h>
91 #include <signal.h>
92 #include <sys/file.h>
93 #include <semaphore.h>
94 #include <ctype.h>
95 #include <time.h>
96 
97 #include "asterisk/channel.h"
98 #include "asterisk/config.h"
99 #include "asterisk/module.h"
100 #include "asterisk/pbx.h"
101 #include "asterisk/io.h"
102 #include "asterisk/frame.h"
103 #include "asterisk/translate.h"
104 #include "asterisk/cli.h"
105 #include "asterisk/musiconhold.h"
106 #include "asterisk/dsp.h"
107 #include "asterisk/file.h"
108 #include "asterisk/callerid.h"
109 #include "asterisk/indications.h"
110 #include "asterisk/app.h"
111 #include "asterisk/features.h"
112 #include "asterisk/term.h"
113 #include "asterisk/sched.h"
114 #include "asterisk/stringfields.h"
115 #include "asterisk/abstract_jb.h"
116 #include "asterisk/causes.h"
117 #include "asterisk/format.h"
118 #include "asterisk/format_cap.h"
120 #include "asterisk/bridge.h"
121 #include "asterisk/pickup.h"
122 #include "asterisk/format_cache.h"
123 
124 #include "chan_misdn_config.h"
125 #include "isdn_lib.h"
126 
127 static char global_tracefile[BUFFERSIZE + 1];
128 
129 static int g_config_initialized = 0;
130 
131 struct misdn_jb{
132  int size;
134  char *samples, *ok;
135  int wp,rp;
141 };
142 
143 /*! \brief allocates the jb-structure and initialize the elements */
144 struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
145 
146 /*! \brief frees the data and destroys the given jitterbuffer struct */
147 void misdn_jb_destroy(struct misdn_jb *jb);
148 
149 /*! \brief fills the jitterbuffer with len data returns < 0 if there was an
150 error (buffer overrun). */
151 int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len);
152 
153 /*! \brief gets len bytes out of the jitterbuffer if available, else only the
154 available data is returned and the return value indicates the number
155 of data. */
156 int misdn_jb_empty(struct misdn_jb *jb, char *data, int len);
157 
158 static char *complete_ch(struct ast_cli_args *a);
159 static char *complete_debug_port(struct ast_cli_args *a);
160 static char *complete_show_config(struct ast_cli_args *a);
161 
162 /* BEGIN: chan_misdn.h */
163 
164 #if defined(AST_MISDN_ENHANCEMENTS)
165 /*
166  * This timeout duration is to clean up any call completion records that
167  * are forgotten about by the switch.
168  */
169 #define MISDN_CC_RECORD_AGE_MAX (6UL * 60 * 60) /* seconds */
170 
171 #define MISDN_CC_REQUEST_WAIT_MAX 5 /* seconds */
172 
173 /*!
174  * \brief Caller that initialized call completion services
175  *
176  * \details
177  * This data is the payload for a datastore that is put on the channel that
178  * initializes call completion services. This datastore is set to be inherited
179  * by the outbound mISDN channel. When one of these channels hangs up, the
180  * channel pointer will be set to NULL. That way, we can ensure that we do not
181  * touch this channel after it gets destroyed.
182  */
183 struct misdn_cc_caller {
184  /*! \brief The channel that initialized call completion services */
185  struct ast_channel *chan;
186 };
187 
188 struct misdn_cc_notify {
189  /*! \brief Dialplan: Notify extension priority */
190  int priority;
191 
192  /*! \brief Dialplan: Notify extension context */
193  char context[AST_MAX_CONTEXT];
194 
195  /*! \brief Dialplan: Notify extension number (User-A) */
196  char exten[AST_MAX_EXTENSION];
197 };
198 
199 /*! \brief mISDN call completion record */
200 struct misdn_cc_record {
201  /*! \brief Call completion record linked list */
202  AST_LIST_ENTRY(misdn_cc_record) list;
203 
204  /*! \brief Time the record was created. */
205  time_t time_created;
206 
207  /*! \brief MISDN_CC_RECORD_ID value */
208  long record_id;
209 
210  /*!
211  * \brief Logical Layer 1 port associated with this
212  * call completion record
213  */
214  int port;
215 
216  /*! \brief TRUE if point-to-point mode (CCBS-T/CCNR-T mode) */
217  int ptp;
218 
219  /*! \brief Mode specific parameters */
220  union {
221  /*! \brief point-to-point specific parameters. */
222  struct {
223  /*!
224  * \brief Call-completion signaling link.
225  * NULL if signaling link not established.
226  */
227  struct misdn_bchannel *bc;
228 
229  /*!
230  * \brief TRUE if we requested the request retention option
231  * to be enabled.
232  */
233  int requested_retention;
234 
235  /*!
236  * \brief TRUE if the request retention option is enabled.
237  */
238  int retention_enabled;
239  } ptp;
240 
241  /*! \brief point-to-multi-point specific parameters. */
242  struct {
243  /*! \brief CallLinkageID (valid when port determined) */
244  int linkage_id;
245 
246  /*! \breif CCBSReference (valid when activated is TRUE) */
247  int reference_id;
248 
249  /*! \brief globalRecall(0), specificRecall(1) */
250  int recall_mode;
251  } ptmp;
252  } mode;
253 
254  /*! \brief TRUE if call completion activated */
255  int activated;
256 
257  /*! \brief Outstanding message ID (valid when outstanding_message) */
258  int invoke_id;
259 
260  /*! \brief TRUE if waiting for a response from a message (invoke_id is valid) */
261  int outstanding_message;
262 
263  /*! \brief TRUE if activation has been requested */
264  int activation_requested;
265 
266  /*!
267  * \brief TRUE if User-A is free
268  * \note PTMP - Used to answer CCBSStatusRequest.
269  * PTP - Determines how to respond to CCBS_T_RemoteUserFree.
270  */
271  int party_a_free;
272 
273  /*! \brief Error code received from last outstanding message. */
274  enum FacErrorCode error_code;
275 
276  /*! \brief Reject code received from last outstanding message. */
277  enum FacRejectCode reject_code;
278 
279  /*!
280  * \brief Saved struct misdn_bchannel call information when
281  * attempted to call User-B
282  */
283  struct {
284  /*! \brief User-A caller id information */
285  struct misdn_party_id caller;
286 
287  /*! \brief User-B number information */
288  struct misdn_party_dialing dialed;
289 
290  /*! \brief The BC, HLC (optional) and LLC (optional) contents from the SETUP message. */
291  struct Q931_Bc_Hlc_Llc setup_bc_hlc_llc;
292 
293  /*! \brief SETUP message bearer capability field code value */
294  int capability;
295 
296  /*! \brief TRUE if call made in digital HDLC mode */
297  int hdlc;
298  } redial;
299 
300  /*! \brief Dialplan location to indicate User-B free and User-A is free */
301  struct misdn_cc_notify remote_user_free;
302 
303  /*! \brief Dialplan location to indicate User-B free and User-A is busy */
304  struct misdn_cc_notify b_free;
305 };
306 
307 /*! \brief mISDN call completion record database */
308 static AST_LIST_HEAD_STATIC(misdn_cc_records_db, misdn_cc_record);
309 /*! \brief Next call completion record ID to use */
310 static __u16 misdn_cc_record_id;
311 /*! \brief Next invoke ID to use */
312 static __s16 misdn_invoke_id;
313 
314 static const char misdn_no_response_from_network[] = "No response from network";
315 static const char misdn_cc_record_not_found[] = "Call completion record not found";
316 
317 /* mISDN channel variable names */
318 #define MISDN_CC_RECORD_ID "MISDN_CC_RECORD_ID"
319 #define MISDN_CC_STATUS "MISDN_CC_STATUS"
320 #define MISDN_ERROR_MSG "MISDN_ERROR_MSG"
321 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
322 
324 
326  MISDN_NOTHING = 0, /*!< at beginning */
327  MISDN_WAITING4DIGS, /*!< when waiting for info */
328  MISDN_EXTCANTMATCH, /*!< when asterisk couldn't match our ext */
329  MISDN_INCOMING_SETUP, /*!< for incoming setup */
330  MISDN_DIALING, /*!< when pbx_start */
331  MISDN_PROGRESS, /*!< we have progress */
332  MISDN_PROCEEDING, /*!< we have progress */
333  MISDN_CALLING, /*!< when misdn_call is called */
334  MISDN_CALLING_ACKNOWLEDGE, /*!< when we get SETUP_ACK */
335  MISDN_ALERTING, /*!< when Alerting */
336  MISDN_BUSY, /*!< when BUSY */
337  MISDN_CONNECTED, /*!< when connected */
338  MISDN_DISCONNECTED, /*!< when connected */
339  MISDN_CLEANING, /*!< when hangup from * but we were connected before */
340 };
341 
342 /*! Asterisk created the channel (outgoing call) */
343 #define ORG_AST 1
344 /*! mISDN created the channel (incoming call) */
345 #define ORG_MISDN 2
346 
348  MISDN_HOLD_IDLE, /*!< HOLD not active */
349  MISDN_HOLD_ACTIVE, /*!< Call is held */
350  MISDN_HOLD_TRANSFER, /*!< Held call is being transferred */
351  MISDN_HOLD_DISCONNECT, /*!< Held call is being disconnected */
352 };
353 struct hold_info {
354  /*!
355  * \brief Call HOLD state.
356  */
358  /*!
359  * \brief Logical port the channel call record is HELD on
360  * because the B channel is no longer associated.
361  */
362  int port;
363 
364  /*!
365  * \brief Original B channel number the HELD call was using.
366  * \note Used only for debug display messages.
367  */
368  int channel;
369 };
370 
371 #define chan_list_ref(obj, debug) ao2_t_ref((obj), +1, (debug))
372 #define chan_list_unref(obj, debug) ao2_t_ref((obj), -1, (debug))
373 
374 /*!
375  * \brief Channel call record structure
376  */
377 struct chan_list {
378  /*!
379  * \brief The "allowed_bearers" string read in from /etc/asterisk/misdn.conf
380  */
382 
383  /*!
384  * \brief State of the channel
385  */
387 
388  /*!
389  * \brief TRUE if a hangup needs to be queued
390  * \note This is a debug flag only used to catch calls to hangup_chan() that are already hungup.
391  */
393 
394  /*!
395  * \brief TRUE if a channel can be hung up by calling asterisk directly when done.
396  */
398 
399  /*!
400  * \brief TRUE if we could send an AST_CONTROL_BUSY if needed.
401  */
403 
404  /*!
405  * \brief Who originally created this channel. ORG_AST or ORG_MISDN
406  */
408 
409  /*!
410  * \brief TRUE of we are not to respond immediately to a SETUP message. Check the dialplan first.
411  * \note The "noautorespond_on_setup" boolean read in from /etc/asterisk/misdn.conf
412  */
414 
415  int norxtone; /*!< Boolean assigned values but the value is not used. */
416 
417  /*!
418  * \brief TRUE if we are not to generate tones (Playtones)
419  */
420  int notxtone;
421 
422  /*!
423  * \brief TRUE if echo canceller is enabled. Value is toggled.
424  */
426 
427  /*!
428  * \brief TRUE if you want to send Tone Indications to an incoming
429  * ISDN channel on a TE Port.
430  * \note The "incoming_early_audio" boolean read in from /etc/asterisk/misdn.conf
431  */
433 
434  /*!
435  * \brief TRUE if DTMF digits are to be passed inband only.
436  * \note It is settable by the misdn_set_opt() application.
437  */
439 
440  /*!
441  * \brief Pipe file descriptor handles array.
442  * Read from pipe[0], write to pipe[1]
443  */
444  int pipe[2];
445 
446  /*!
447  * \brief Read buffer for inbound audio from pipe[0]
448  */
449  char ast_rd_buf[4096];
450 
451  /*!
452  * \brief Inbound audio frame returned by misdn_read().
453  */
454  struct ast_frame frame;
455 
456  /*!
457  * \brief Fax detection option. (0:no 1:yes 2:yes+nojump)
458  * \note The "faxdetect" option string read in from /etc/asterisk/misdn.conf
459  * \note It is settable by the misdn_set_opt() application.
460  */
462 
463  /*!
464  * \brief Number of seconds to detect a Fax machine when detection enabled.
465  * \note 0 disables the timeout.
466  * \note The "faxdetect_timeout" value read in from /etc/asterisk/misdn.conf
467  */
469 
470  /*!
471  * \brief Starting time of fax detection with timeout when nonzero.
472  */
473  struct timeval faxdetect_tv;
474 
475  /*!
476  * \brief TRUE if a fax has been detected.
477  */
479 
480  /*!
481  * \brief TRUE if we will use the Asterisk DSP to detect DTMF/Fax
482  * \note The "astdtmf" boolean read in from /etc/asterisk/misdn.conf
483  */
484  int ast_dsp;
485 
486  /*!
487  * \brief Jitterbuffer length
488  * \note The "jitterbuffer" value read in from /etc/asterisk/misdn.conf
489  */
490  int jb_len;
491 
492  /*!
493  * \brief Jitterbuffer upper threshold
494  * \note The "jitterbuffer_upper_threshold" value read in from /etc/asterisk/misdn.conf
495  */
497 
498  /*!
499  * \brief Allocated jitterbuffer controller
500  * \note misdn_jb_init() creates the jitterbuffer.
501  * \note Must use misdn_jb_destroy() to clean up.
502  */
503  struct misdn_jb *jb;
504 
505  /*!
506  * \brief Allocated DSP controller
507  * \note ast_dsp_new() creates the DSP controller.
508  * \note Must use ast_dsp_free() to clean up.
509  */
510  struct ast_dsp *dsp;
511 
512  /*!
513  * \brief Associated Asterisk channel structure.
514  */
515  struct ast_channel * ast;
516 
517  /*!
518  * \brief Associated B channel structure.
519  */
521 
522 #if defined(AST_MISDN_ENHANCEMENTS)
523  /*!
524  * \brief Peer channel for which call completion was initialized.
525  */
526  struct misdn_cc_caller *peer;
527 
528  /*! \brief Associated call completion record ID (-1 if not associated) */
529  long record_id;
530 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
531 
532  /*!
533  * \brief HELD channel call information
534  */
535  struct hold_info hold;
536 
537  /*!
538  * \brief From associated B channel: Layer 3 process ID
539  * \note Used to find the HELD channel call record when retrieving a call.
540  */
541  unsigned int l3id;
542 
543  /*!
544  * \brief From associated B channel: B Channel mISDN driver layer ID from mISDN_get_layerid()
545  * \note Used only for debug display messages.
546  */
547  int addr;
548 
549  /*!
550  * \brief Incoming call dialplan context identifier.
551  * \note The "context" string read in from /etc/asterisk/misdn.conf
552  */
554 
555  /*!
556  * \brief The configured music-on-hold class to use for this call.
557  * \note The "musicclass" string read in from /etc/asterisk/misdn.conf
558  */
560 
561  /*!
562  * \brief Number of outgoing audio frames dropped since last debug gripe message.
563  */
565 
566  /*!
567  * \brief TRUE if we must do the ringback tones.
568  * \note The "far_alerting" boolean read in from /etc/asterisk/misdn.conf
569  */
571 
572  /*!
573  * \brief TRUE if NT should disconnect an overlap dialing call when a timeout occurs.
574  * \note The "nttimeout" boolean read in from /etc/asterisk/misdn.conf
575  */
577 
578  /*!
579  * \brief Tone zone sound used for dialtone generation.
580  * \note Used as a boolean. Non-NULL to prod generation if enabled.
581  */
583 
584  /*!
585  * \brief Enables overlap dialing for the set amount of seconds. (0 = Disabled)
586  * \note The "overlapdial" value read in from /etc/asterisk/misdn.conf
587  */
589 
590  /*!
591  * \brief Overlap dialing timeout Task ID. -1 if not running.
592  */
594 
595  /*!
596  * \brief overlap_tv access lock.
597  */
599 
600  /*!
601  * \brief Overlap timer start time. Timer restarted for every digit received.
602  */
603  struct timeval overlap_tv;
604 
605  /*!
606  * \brief Next channel call record in the list.
607  */
608  struct chan_list *next;
609 };
610 
611 
612 int MAXTICS = 8;
613 
614 
615 void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
616 void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
617 static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame);
618 
619 struct robin_list {
620  char *group;
621  int port;
622  int channel;
623  struct robin_list *next;
624  struct robin_list *prev;
625 };
626 static struct robin_list *robin = NULL;
627 
628 
629 static void free_robin_list(void)
630 {
631  struct robin_list *r;
632  struct robin_list *next;
633 
634  for (r = robin, robin = NULL; r; r = next) {
635  next = r->next;
636  ast_free(r->group);
637  ast_free(r);
638  }
639 }
640 
641 static struct robin_list *get_robin_position(char *group)
642 {
643  struct robin_list *new;
644  struct robin_list *iter = robin;
645  for (; iter; iter = iter->next) {
646  if (!strcasecmp(iter->group, group)) {
647  return iter;
648  }
649  }
650  new = ast_calloc(1, sizeof(*new));
651  if (!new) {
652  return NULL;
653  }
654  new->group = ast_strdup(group);
655  if (!new->group) {
656  ast_free(new);
657  return NULL;
658  }
659  new->channel = 1;
660  if (robin) {
661  new->next = robin;
662  robin->prev = new;
663  }
664  robin = new;
665  return robin;
666 }
667 
668 
669 /*! \brief the main schedule context for stuff like l1 watcher, overlap dial, ... */
671 static pthread_t misdn_tasks_thread;
672 
673 static int *misdn_ports;
674 
675 static void chan_misdn_log(int level, int port, char *tmpl, ...)
676  __attribute__((format(printf, 3, 4)));
677 
678 static struct ast_channel *misdn_new(struct chan_list *cl, int state, char *exten, char *callerid, struct ast_format_cap *cap, const struct ast_assigned_ids *assignedids, const struct ast_channel *requestor, int port, int c);
679 static void send_digit_to_chan(struct chan_list *cl, char digit);
680 
681 static int pbx_start_chan(struct chan_list *ch);
682 
683 #define MISDN_ASTERISK_TECH_PVT(ast) ast_channel_tech_pvt(ast)
684 #define MISDN_ASTERISK_TECH_PVT_SET(ast, value) ast_channel_tech_pvt_set(ast, value)
685 
686 #include "asterisk/strings.h"
687 
688 /* #define MISDN_DEBUG 1 */
689 
690 static const char misdn_type[] = "mISDN";
691 
692 static int tracing = 0;
693 
694 static int *misdn_debug;
695 static int *misdn_debug_only;
696 static int max_ports;
697 
698 static int *misdn_in_calls;
699 static int *misdn_out_calls;
700 
701 /*!
702  * \brief Global channel call record list head.
703  */
704 static struct chan_list *cl_te=NULL;
706 
707 static enum event_response_e
708 cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);
709 
710 static int send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch);
711 
712 static void cl_queue_chan(struct chan_list *chan);
713 
714 static int dialtone_indicate(struct chan_list *cl);
715 static void hanguptone_indicate(struct chan_list *cl);
716 static int stop_indicate(struct chan_list *cl);
717 
718 static int start_bc_tones(struct chan_list *cl);
719 static int stop_bc_tones(struct chan_list *cl);
720 static void release_chan_early(struct chan_list *ch);
721 static void release_chan(struct chan_list *ch, struct misdn_bchannel *bc);
722 
723 #if defined(AST_MISDN_ENHANCEMENTS)
724 static const char misdn_command_name[] = "misdn_command";
725 static int misdn_command_exec(struct ast_channel *chan, const char *data);
726 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
727 static int misdn_check_l2l1(struct ast_channel *chan, const char *data);
728 static int misdn_set_opt_exec(struct ast_channel *chan, const char *data);
729 static int misdn_facility_exec(struct ast_channel *chan, const char *data);
730 
731 int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
732 
733 void debug_numtype(int port, int numtype, char *type);
734 
735 int add_out_calls(int port);
736 int add_in_calls(int port);
737 
738 
739 #ifdef MISDN_1_2
740 static int update_pipeline_config(struct misdn_bchannel *bc);
741 #else
742 static int update_ec_config(struct misdn_bchannel *bc);
743 #endif
744 
745 
746 
747 /*************** Helpers *****************/
748 
749 static int misdn_chan_is_valid(struct chan_list *ch)
750 {
751  struct chan_list *list;
752 
753  ast_mutex_lock(&cl_te_lock);
754  for (list = cl_te; list; list = list->next) {
755  if (list == ch) {
756  ast_mutex_unlock(&cl_te_lock);
757  return 1;
758  }
759  }
760  ast_mutex_unlock(&cl_te_lock);
761 
762  return 0;
763 }
764 
765 #if defined(mISDN_NATIVE_BRIDGING)
766 /*! Returns a reference to the found chan_list. */
767 static struct chan_list *get_chan_by_ast(struct ast_channel *ast)
768 {
769  struct chan_list *tmp;
770 
771  ast_mutex_lock(&cl_te_lock);
772  for (tmp = cl_te; tmp; tmp = tmp->next) {
773  if (tmp->ast == ast) {
774  chan_list_ref(tmp, "Found chan_list by ast");
775  ast_mutex_unlock(&cl_te_lock);
776  return tmp;
777  }
778  }
779  ast_mutex_unlock(&cl_te_lock);
780 
781  return NULL;
782 }
783 #endif /* defined(mISDN_NATIVE_BRIDGING) */
784 
785 /*! Returns a reference to the found chan_list. */
786 static struct chan_list *get_chan_by_ast_name(const char *name)
787 {
788  struct chan_list *tmp;
789 
790  ast_mutex_lock(&cl_te_lock);
791  for (tmp = cl_te; tmp; tmp = tmp->next) {
792  if (tmp->ast && strcmp(ast_channel_name(tmp->ast), name) == 0) {
793  chan_list_ref(tmp, "Found chan_list by ast name");
794  ast_mutex_unlock(&cl_te_lock);
795  return tmp;
796  }
797  }
798  ast_mutex_unlock(&cl_te_lock);
799 
800  return NULL;
801 }
802 
803 #if defined(AST_MISDN_ENHANCEMENTS)
804 /*!
805  * \internal
806  * \brief Destroy the misdn_cc_ds_info datastore payload
807  *
808  * \param[in] data the datastore payload, a reference to an misdn_cc_caller
809  *
810  * \details
811  * Since the payload is a reference to an astobj2 object, we just decrement its
812  * reference count. Before doing so, we NULL out the channel pointer inside of
813  * the misdn_cc_caller instance. This function will be called in one of two
814  * cases. In both cases, we no longer need the channel pointer:
815  *
816  * - The original channel that initialized call completion services, the same
817  * channel that is stored here, has been destroyed early. This could happen
818  * if it transferred the mISDN channel, for example.
819  *
820  * - The mISDN channel that had this datastore inherited on to it is now being
821  * destroyed. If this is the case, then the call completion events have
822  * already occurred and the appropriate channel variables have already been
823  * set on the original channel that requested call completion services.
824  *
825  * \return Nothing
826  */
827 static void misdn_cc_ds_destroy(void *data)
828 {
829  struct misdn_cc_caller *cc_caller = data;
830 
831  ao2_lock(cc_caller);
832  cc_caller->chan = NULL;
833  ao2_unlock(cc_caller);
834 
835  ao2_ref(cc_caller, -1);
836 }
837 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
838 
839 #if defined(AST_MISDN_ENHANCEMENTS)
840 /*!
841  * \internal
842  * \brief Duplicate the misdn_cc_ds_info datastore payload
843  *
844  * \param[in] data the datastore payload, a reference to an misdn_cc_caller
845  *
846  * \details
847  * All we need to do is bump the reference count and return the same instance.
848  *
849  * \return A reference to an instance of a misdn_cc_caller
850  */
851 static void *misdn_cc_ds_duplicate(void *data)
852 {
853  struct misdn_cc_caller *cc_caller = data;
854 
855  ao2_ref(cc_caller, +1);
856 
857  return cc_caller;
858 }
859 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
860 
861 #if defined(AST_MISDN_ENHANCEMENTS)
862 static const struct ast_datastore_info misdn_cc_ds_info = {
863  .type = "misdn_cc",
864  .destroy = misdn_cc_ds_destroy,
865  .duplicate = misdn_cc_ds_duplicate,
866 };
867 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
868 
869 #if defined(AST_MISDN_ENHANCEMENTS)
870 /*!
871  * \internal
872  * \brief Set a channel var on the peer channel for call completion services
873  *
874  * \param[in] peer The peer that initialized call completion services
875  * \param[in] var The variable name to set
876  * \param[in] value The variable value to set
877  *
878  * This function may be called from outside of the channel thread. It handles
879  * the fact that the peer channel may be hung up and destroyed at any time.
880  *
881  * \return nothing
882  */
883 static void misdn_cc_set_peer_var(struct misdn_cc_caller *peer, const char *var,
884  const char *value)
885 {
886  ao2_lock(peer);
887 
888  /*! \todo XXX This nastiness can go away once ast_channel is ref counted! */
889  while (peer->chan && ast_channel_trylock(peer->chan)) {
890  ao2_unlock(peer);
891  sched_yield();
892  ao2_lock(peer);
893  }
894 
895  if (peer->chan) {
896  pbx_builtin_setvar_helper(peer->chan, var, value);
897  ast_channel_unlock(peer->chan);
898  }
899 
900  ao2_unlock(peer);
901 }
902 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
903 
904 #if defined(AST_MISDN_ENHANCEMENTS)
905 /*!
906  * \internal
907  * \brief Get a reference to the CC caller if it exists
908  */
909 static struct misdn_cc_caller *misdn_cc_caller_get(struct ast_channel *chan)
910 {
911  struct ast_datastore *datastore;
912  struct misdn_cc_caller *cc_caller;
913 
914  ast_channel_lock(chan);
915 
916  if (!(datastore = ast_channel_datastore_find(chan, &misdn_cc_ds_info, NULL))) {
917  ast_channel_unlock(chan);
918  return NULL;
919  }
920 
921  ao2_ref(datastore->data, +1);
922  cc_caller = datastore->data;
923 
924  ast_channel_unlock(chan);
925 
926  return cc_caller;
927 }
928 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
929 
930 #if defined(AST_MISDN_ENHANCEMENTS)
931 /*!
932  * \internal
933  * \brief Find the call completion record given the record id.
934  *
935  * \param record_id
936  *
937  * \retval pointer to found call completion record
938  * \retval NULL if not found
939  *
940  * \note Assumes the misdn_cc_records_db lock is already obtained.
941  */
942 static struct misdn_cc_record *misdn_cc_find_by_id(long record_id)
943 {
944  struct misdn_cc_record *current;
945 
946  AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
947  if (current->record_id == record_id) {
948  /* Found the record */
949  break;
950  }
951  }
952 
953  return current;
954 }
955 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
956 
957 #if defined(AST_MISDN_ENHANCEMENTS)
958 /*!
959  * \internal
960  * \brief Find the call completion record given the port and call linkage id.
961  *
962  * \param port Logical port number
963  * \param linkage_id Call linkage ID number from switch.
964  *
965  * \retval pointer to found call completion record
966  * \retval NULL if not found
967  *
968  * \note Assumes the misdn_cc_records_db lock is already obtained.
969  */
970 static struct misdn_cc_record *misdn_cc_find_by_linkage(int port, int linkage_id)
971 {
972  struct misdn_cc_record *current;
973 
974  AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
975  if (current->port == port
976  && !current->ptp
977  && current->mode.ptmp.linkage_id == linkage_id) {
978  /* Found the record */
979  break;
980  }
981  }
982 
983  return current;
984 }
985 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
986 
987 #if defined(AST_MISDN_ENHANCEMENTS)
988 /*!
989  * \internal
990  * \brief Find the call completion record given the port and outstanding invocation id.
991  *
992  * \param port Logical port number
993  * \param invoke_id Outstanding message invocation ID number.
994  *
995  * \retval pointer to found call completion record
996  * \retval NULL if not found
997  *
998  * \note Assumes the misdn_cc_records_db lock is already obtained.
999  */
1000 static struct misdn_cc_record *misdn_cc_find_by_invoke(int port, int invoke_id)
1001 {
1002  struct misdn_cc_record *current;
1003 
1004  AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
1005  if (current->outstanding_message
1006  && current->invoke_id == invoke_id
1007  && current->port == port) {
1008  /* Found the record */
1009  break;
1010  }
1011  }
1012 
1013  return current;
1014 }
1015 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1016 
1017 #if defined(AST_MISDN_ENHANCEMENTS)
1018 /*!
1019  * \internal
1020  * \brief Find the call completion record given the port and CCBS reference id.
1021  *
1022  * \param port Logical port number
1023  * \param reference_id CCBS reference ID number from switch.
1024  *
1025  * \retval pointer to found call completion record
1026  * \retval NULL if not found
1027  *
1028  * \note Assumes the misdn_cc_records_db lock is already obtained.
1029  */
1030 static struct misdn_cc_record *misdn_cc_find_by_reference(int port, int reference_id)
1031 {
1032  struct misdn_cc_record *current;
1033 
1034  AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
1035  if (current->activated
1036  && current->port == port
1037  && !current->ptp
1038  && current->mode.ptmp.reference_id == reference_id) {
1039  /* Found the record */
1040  break;
1041  }
1042  }
1043 
1044  return current;
1045 }
1046 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1047 
1048 #if defined(AST_MISDN_ENHANCEMENTS)
1049 /*!
1050  * \internal
1051  * \brief Find the call completion record given the B channel pointer
1052  *
1053  * \param bc B channel control structure pointer.
1054  *
1055  * \retval pointer to found call completion record
1056  * \retval NULL if not found
1057  *
1058  * \note Assumes the misdn_cc_records_db lock is already obtained.
1059  */
1060 static struct misdn_cc_record *misdn_cc_find_by_bc(const struct misdn_bchannel *bc)
1061 {
1062  struct misdn_cc_record *current;
1063 
1064  if (bc) {
1065  AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
1066  if (current->ptp
1067  && current->mode.ptp.bc == bc) {
1068  /* Found the record */
1069  break;
1070  }
1071  }
1072  } else {
1073  current = NULL;
1074  }
1075 
1076  return current;
1077 }
1078 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1079 
1080 #if defined(AST_MISDN_ENHANCEMENTS)
1081 /*!
1082  * \internal
1083  * \brief Delete the given call completion record
1084  *
1085  * \param doomed Call completion record to destroy
1086  *
1087  * \return Nothing
1088  *
1089  * \note Assumes the misdn_cc_records_db lock is already obtained.
1090  */
1091 static void misdn_cc_delete(struct misdn_cc_record *doomed)
1092 {
1093  struct misdn_cc_record *current;
1094 
1095  AST_LIST_TRAVERSE_SAFE_BEGIN(&misdn_cc_records_db, current, list) {
1096  if (current == doomed) {
1098  ast_free(current);
1099  return;
1100  }
1101  }
1103 
1104  /* The doomed node is not in the call completion database */
1105 }
1106 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1107 
1108 #if defined(AST_MISDN_ENHANCEMENTS)
1109 /*!
1110  * \internal
1111  * \brief Delete all old call completion records
1112  *
1113  * \return Nothing
1114  *
1115  * \note Assumes the misdn_cc_records_db lock is already obtained.
1116  */
1117 static void misdn_cc_remove_old(void)
1118 {
1119  struct misdn_cc_record *current;
1120  time_t now;
1121 
1122  now = time(NULL);
1123  AST_LIST_TRAVERSE_SAFE_BEGIN(&misdn_cc_records_db, current, list) {
1124  if (MISDN_CC_RECORD_AGE_MAX < now - current->time_created) {
1125  if (current->ptp && current->mode.ptp.bc) {
1126  /* Close the old call-completion signaling link */
1127  current->mode.ptp.bc->fac_out.Function = Fac_None;
1128  current->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
1129  misdn_lib_send_event(current->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
1130  }
1131 
1132  /* Remove the old call completion record */
1134  ast_free(current);
1135  }
1136  }
1138 }
1139 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1140 
1141 #if defined(AST_MISDN_ENHANCEMENTS)
1142 /*!
1143  * \internal
1144  * \brief Allocate the next record id.
1145  *
1146  * \retval New record id on success.
1147  * \retval -1 on error.
1148  *
1149  * \note Assumes the misdn_cc_records_db lock is already obtained.
1150  */
1151 static long misdn_cc_record_id_new(void)
1152 {
1153  long record_id;
1154  long first_id;
1155 
1156  record_id = ++misdn_cc_record_id;
1157  first_id = record_id;
1158  while (misdn_cc_find_by_id(record_id)) {
1159  record_id = ++misdn_cc_record_id;
1160  if (record_id == first_id) {
1161  /*
1162  * We have a resource leak.
1163  * We should never need to allocate 64k records.
1164  */
1165  chan_misdn_log(0, 0, " --> ERROR Too many call completion records!\n");
1166  record_id = -1;
1167  break;
1168  }
1169  }
1170 
1171  return record_id;
1172 }
1173 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1174 
1175 #if defined(AST_MISDN_ENHANCEMENTS)
1176 /*!
1177  * \internal
1178  * \brief Create a new call completion record
1179  *
1180  * \retval pointer to new call completion record
1181  * \retval NULL if failed
1182  *
1183  * \note Assumes the misdn_cc_records_db lock is already obtained.
1184  */
1185 static struct misdn_cc_record *misdn_cc_new(void)
1186 {
1187  struct misdn_cc_record *cc_record;
1188  long record_id;
1189 
1190  misdn_cc_remove_old();
1191 
1192  cc_record = ast_calloc(1, sizeof(*cc_record));
1193  if (cc_record) {
1194  record_id = misdn_cc_record_id_new();
1195  if (record_id < 0) {
1196  ast_free(cc_record);
1197  return NULL;
1198  }
1199 
1200  /* Initialize the new record */
1201  cc_record->record_id = record_id;
1202  cc_record->port = -1;/* Invalid port so it will never be found this way */
1203  cc_record->invoke_id = ++misdn_invoke_id;
1204  cc_record->party_a_free = 1;/* Default User-A as free */
1205  cc_record->error_code = FacError_None;
1206  cc_record->reject_code = FacReject_None;
1207  cc_record->time_created = time(NULL);
1208 
1209  /* Insert the new record into the database */
1210  AST_LIST_INSERT_HEAD(&misdn_cc_records_db, cc_record, list);
1211  }
1212  return cc_record;
1213 }
1214 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1215 
1216 #if defined(AST_MISDN_ENHANCEMENTS)
1217 /*!
1218  * \internal
1219  * \brief Destroy the call completion record database
1220  *
1221  * \return Nothing
1222  */
1223 static void misdn_cc_destroy(void)
1224 {
1225  struct misdn_cc_record *current;
1226 
1227  while ((current = AST_LIST_REMOVE_HEAD(&misdn_cc_records_db, list))) {
1228  /* Do a misdn_cc_delete(current) inline */
1229  ast_free(current);
1230  }
1231 }
1232 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1233 
1234 #if defined(AST_MISDN_ENHANCEMENTS)
1235 /*!
1236  * \internal
1237  * \brief Initialize the call completion record database
1238  *
1239  * \return Nothing
1240  */
1241 static void misdn_cc_init(void)
1242 {
1243  misdn_cc_record_id = 0;
1244 }
1245 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1246 
1247 #if defined(AST_MISDN_ENHANCEMENTS)
1248 /*!
1249  * \internal
1250  * \brief Check the status of an outstanding invocation request.
1251  *
1252  * \param data Points to an integer containing the call completion record id.
1253  *
1254  * \retval 0 if got a response.
1255  * \retval -1 if no response yet.
1256  */
1257 static int misdn_cc_response_check(void *data)
1258 {
1259  int not_responded;
1260  struct misdn_cc_record *cc_record;
1261 
1262  AST_LIST_LOCK(&misdn_cc_records_db);
1263  cc_record = misdn_cc_find_by_id(*(long *) data);
1264  if (cc_record) {
1265  if (cc_record->outstanding_message) {
1266  not_responded = -1;
1267  } else {
1268  not_responded = 0;
1269  }
1270  } else {
1271  /* No record so there is no response to check. */
1272  not_responded = 0;
1273  }
1274  AST_LIST_UNLOCK(&misdn_cc_records_db);
1275 
1276  return not_responded;
1277 }
1278 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1279 
1280 #if defined(AST_MISDN_ENHANCEMENTS)
1281 /*!
1282  * \internal
1283  * \brief Wait for a response from the switch for an outstanding
1284  * invocation request.
1285  *
1286  * \param chan Asterisk channel to operate upon.
1287  * \param wait_seconds Number of seconds to wait
1288  * \param record_id Call completion record ID.
1289  *
1290  * \return Nothing
1291  */
1292 static void misdn_cc_response_wait(struct ast_channel *chan, int wait_seconds, long record_id)
1293 {
1294  unsigned count;
1295 
1296  for (count = 2 * MISDN_CC_REQUEST_WAIT_MAX; count--;) {
1297  /* Sleep in 500 ms increments */
1298  if (ast_safe_sleep_conditional(chan, 500, misdn_cc_response_check, &record_id) != 0) {
1299  /* We got hung up or our response came in. */
1300  break;
1301  }
1302  }
1303 }
1304 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1305 
1306 #if defined(AST_MISDN_ENHANCEMENTS)
1307 /*!
1308  * \internal
1309  * \brief Convert the mISDN reject code to a string
1310  *
1311  * \param code mISDN reject code.
1312  *
1313  * \return The mISDN reject code as a string
1314  */
1315 static const char *misdn_to_str_reject_code(enum FacRejectCode code)
1316 {
1317  static const struct {
1318  enum FacRejectCode code;
1319  char *name;
1320  } arr[] = {
1321 /* *INDENT-OFF* */
1322  { FacReject_None, "No reject occurred" },
1323  { FacReject_Unknown, "Unknown reject code" },
1324 
1325  { FacReject_Gen_UnrecognizedComponent, "General: Unrecognized Component" },
1326  { FacReject_Gen_MistypedComponent, "General: Mistyped Component" },
1327  { FacReject_Gen_BadlyStructuredComponent, "General: Badly Structured Component" },
1328 
1329  { FacReject_Inv_DuplicateInvocation, "Invoke: Duplicate Invocation" },
1330  { FacReject_Inv_UnrecognizedOperation, "Invoke: Unrecognized Operation" },
1331  { FacReject_Inv_MistypedArgument, "Invoke: Mistyped Argument" },
1332  { FacReject_Inv_ResourceLimitation, "Invoke: Resource Limitation" },
1333  { FacReject_Inv_InitiatorReleasing, "Invoke: Initiator Releasing" },
1334  { FacReject_Inv_UnrecognizedLinkedID, "Invoke: Unrecognized Linked ID" },
1335  { FacReject_Inv_LinkedResponseUnexpected, "Invoke: Linked Response Unexpected" },
1336  { FacReject_Inv_UnexpectedChildOperation, "Invoke: Unexpected Child Operation" },
1337 
1338  { FacReject_Res_UnrecognizedInvocation, "Result: Unrecognized Invocation" },
1339  { FacReject_Res_ResultResponseUnexpected, "Result: Result Response Unexpected" },
1340  { FacReject_Res_MistypedResult, "Result: Mistyped Result" },
1341 
1342  { FacReject_Err_UnrecognizedInvocation, "Error: Unrecognized Invocation" },
1343  { FacReject_Err_ErrorResponseUnexpected, "Error: Error Response Unexpected" },
1344  { FacReject_Err_UnrecognizedError, "Error: Unrecognized Error" },
1345  { FacReject_Err_UnexpectedError, "Error: Unexpected Error" },
1346  { FacReject_Err_MistypedParameter, "Error: Mistyped Parameter" },
1347 /* *INDENT-ON* */
1348  };
1349 
1350  unsigned index;
1351 
1352  for (index = 0; index < ARRAY_LEN(arr); ++index) {
1353  if (arr[index].code == code) {
1354  return arr[index].name;
1355  }
1356  }
1357 
1358  return "unknown";
1359 }
1360 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1361 
1362 #if defined(AST_MISDN_ENHANCEMENTS)
1363 /*!
1364  * \internal
1365  * \brief Convert the mISDN error code to a string
1366  *
1367  * \param code mISDN error code.
1368  *
1369  * \return The mISDN error code as a string
1370  */
1371 static const char *misdn_to_str_error_code(enum FacErrorCode code)
1372 {
1373  static const struct {
1374  enum FacErrorCode code;
1375  char *name;
1376  } arr[] = {
1377 /* *INDENT-OFF* */
1378  { FacError_None, "No error occurred" },
1379  { FacError_Unknown, "Unknown OID error code" },
1380 
1381  { FacError_Gen_NotSubscribed, "General: Not Subscribed" },
1382  { FacError_Gen_NotAvailable, "General: Not Available" },
1383  { FacError_Gen_NotImplemented, "General: Not Implemented" },
1384  { FacError_Gen_InvalidServedUserNr, "General: Invalid Served User Number" },
1385  { FacError_Gen_InvalidCallState, "General: Invalid Call State" },
1386  { FacError_Gen_BasicServiceNotProvided, "General: Basic Service Not Provided" },
1387  { FacError_Gen_NotIncomingCall, "General: Not Incoming Call" },
1388  { FacError_Gen_SupplementaryServiceInteractionNotAllowed,"General: Supplementary Service Interaction Not Allowed" },
1389  { FacError_Gen_ResourceUnavailable, "General: Resource Unavailable" },
1390 
1391  { FacError_Div_InvalidDivertedToNr, "Diversion: Invalid Diverted To Number" },
1392  { FacError_Div_SpecialServiceNr, "Diversion: Special Service Number" },
1393  { FacError_Div_DiversionToServedUserNr, "Diversion: Diversion To Served User Number" },
1394  { FacError_Div_IncomingCallAccepted, "Diversion: Incoming Call Accepted" },
1395  { FacError_Div_NumberOfDiversionsExceeded, "Diversion: Number Of Diversions Exceeded" },
1396  { FacError_Div_NotActivated, "Diversion: Not Activated" },
1397  { FacError_Div_RequestAlreadyAccepted, "Diversion: Request Already Accepted" },
1398 
1399  { FacError_AOC_NoChargingInfoAvailable, "AOC: No Charging Info Available" },
1400 
1401  { FacError_CCBS_InvalidCallLinkageID, "CCBS: Invalid Call Linkage ID" },
1402  { FacError_CCBS_InvalidCCBSReference, "CCBS: Invalid CCBS Reference" },
1403  { FacError_CCBS_LongTermDenial, "CCBS: Long Term Denial" },
1404  { FacError_CCBS_ShortTermDenial, "CCBS: Short Term Denial" },
1405  { FacError_CCBS_IsAlreadyActivated, "CCBS: Is Already Activated" },
1406  { FacError_CCBS_AlreadyAccepted, "CCBS: Already Accepted" },
1407  { FacError_CCBS_OutgoingCCBSQueueFull, "CCBS: Outgoing CCBS Queue Full" },
1408  { FacError_CCBS_CallFailureReasonNotBusy, "CCBS: Call Failure Reason Not Busy" },
1409  { FacError_CCBS_NotReadyForCall, "CCBS: Not Ready For Call" },
1410 
1411  { FacError_CCBS_T_LongTermDenial, "CCBS-T: Long Term Denial" },
1412  { FacError_CCBS_T_ShortTermDenial, "CCBS-T: Short Term Denial" },
1413 
1414  { FacError_ECT_LinkIdNotAssignedByNetwork, "ECT: Link ID Not Assigned By Network" },
1415 /* *INDENT-ON* */
1416  };
1417 
1418  unsigned index;
1419 
1420  for (index = 0; index < ARRAY_LEN(arr); ++index) {
1421  if (arr[index].code == code) {
1422  return arr[index].name;
1423  }
1424  }
1425 
1426  return "unknown";
1427 }
1428 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1429 
1430 #if defined(AST_MISDN_ENHANCEMENTS)
1431 /*!
1432  * \internal
1433  * \brief Convert mISDN redirecting reason to diversion reason.
1434  *
1435  * \param reason mISDN redirecting reason code.
1436  *
1437  * \return Supported diversion reason code.
1438  */
1439 static unsigned misdn_to_diversion_reason(enum mISDN_REDIRECTING_REASON reason)
1440 {
1441  unsigned diversion_reason;
1442 
1443  switch (reason) {
1445  diversion_reason = 1;/* cfu */
1446  break;
1448  diversion_reason = 2;/* cfb */
1449  break;
1451  diversion_reason = 3;/* cfnr */
1452  break;
1453  default:
1454  diversion_reason = 0;/* unknown */
1455  break;
1456  }
1457 
1458  return diversion_reason;
1459 }
1460 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1461 
1462 #if defined(AST_MISDN_ENHANCEMENTS)
1463 /*!
1464  * \internal
1465  * \brief Convert diversion reason to mISDN redirecting reason
1466  *
1467  * \param diversion_reason Diversion reason to convert
1468  *
1469  * \return Supported redirecting reason code.
1470  */
1471 static enum mISDN_REDIRECTING_REASON diversion_reason_to_misdn(unsigned diversion_reason)
1472 {
1473  enum mISDN_REDIRECTING_REASON reason;
1474 
1475  switch (diversion_reason) {
1476  case 1:/* cfu */
1478  break;
1479  case 2:/* cfb */
1481  break;
1482  case 3:/* cfnr */
1484  break;
1485  default:
1487  break;
1488  }
1489 
1490  return reason;
1491 }
1492 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1493 
1494 #if defined(AST_MISDN_ENHANCEMENTS)
1495 /*!
1496  * \internal
1497  * \brief Convert the mISDN presentation to PresentedNumberUnscreened type
1498  *
1499  * \param presentation mISDN presentation to convert
1500  * \param number_present TRUE if the number is present
1501  *
1502  * \return PresentedNumberUnscreened type
1503  */
1504 static unsigned misdn_to_PresentedNumberUnscreened_type(int presentation, int number_present)
1505 {
1506  unsigned type;
1507 
1508  switch (presentation) {
1509  case 0:/* allowed */
1510  if (number_present) {
1511  type = 0;/* presentationAllowedNumber */
1512  } else {
1513  type = 2;/* numberNotAvailableDueToInterworking */
1514  }
1515  break;
1516  case 1:/* restricted */
1517  if (number_present) {
1518  type = 3;/* presentationRestrictedNumber */
1519  } else {
1520  type = 1;/* presentationRestricted */
1521  }
1522  break;
1523  default:
1524  type = 2;/* numberNotAvailableDueToInterworking */
1525  break;
1526  }
1527 
1528  return type;
1529 }
1530 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1531 
1532 #if defined(AST_MISDN_ENHANCEMENTS)
1533 /*!
1534  * \internal
1535  * \brief Convert the PresentedNumberUnscreened type to mISDN presentation
1536  *
1537  * \param type PresentedNumberUnscreened type
1538  *
1539  * \return mISDN presentation
1540  */
1541 static int PresentedNumberUnscreened_to_misdn_pres(unsigned type)
1542 {
1543  int presentation;
1544 
1545  switch (type) {
1546  default:
1547  case 0:/* presentationAllowedNumber */
1548  presentation = 0;/* allowed */
1549  break;
1550 
1551  case 1:/* presentationRestricted */
1552  case 3:/* presentationRestrictedNumber */
1553  presentation = 1;/* restricted */
1554  break;
1555 
1556  case 2:/* numberNotAvailableDueToInterworking */
1557  presentation = 2;/* unavailable */
1558  break;
1559  }
1560 
1561  return presentation;
1562 }
1563 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1564 
1565 #if defined(AST_MISDN_ENHANCEMENTS)
1566 /*!
1567  * \internal
1568  * \brief Convert the mISDN numbering plan to PartyNumber numbering plan
1569  *
1570  * \param number_plan mISDN numbering plan
1571  *
1572  * \return PartyNumber numbering plan
1573  */
1574 static unsigned misdn_to_PartyNumber_plan(enum mISDN_NUMBER_PLAN number_plan)
1575 {
1576  unsigned party_plan;
1577 
1578  switch (number_plan) {
1579  default:
1580  case NUMPLAN_UNKNOWN:
1581  party_plan = 0;/* unknown */
1582  break;
1583 
1584  case NUMPLAN_ISDN:
1585  party_plan = 1;/* public */
1586  break;
1587 
1588  case NUMPLAN_DATA:
1589  party_plan = 3;/* data */
1590  break;
1591 
1592  case NUMPLAN_TELEX:
1593  party_plan = 4;/* telex */
1594  break;
1595 
1596  case NUMPLAN_NATIONAL:
1597  party_plan = 8;/* nationalStandard */
1598  break;
1599 
1600  case NUMPLAN_PRIVATE:
1601  party_plan = 5;/* private */
1602  break;
1603  }
1604 
1605  return party_plan;
1606 }
1607 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1608 
1609 #if defined(AST_MISDN_ENHANCEMENTS)
1610 /*!
1611  * \internal
1612  * \brief Convert PartyNumber numbering plan to mISDN numbering plan
1613  *
1614  * \param party_plan PartyNumber numbering plan
1615  *
1616  * \return mISDN numbering plan
1617  */
1618 static enum mISDN_NUMBER_PLAN PartyNumber_to_misdn_plan(unsigned party_plan)
1619 {
1620  enum mISDN_NUMBER_PLAN number_plan;
1621 
1622  switch (party_plan) {
1623  default:
1624  case 0:/* unknown */
1625  number_plan = NUMPLAN_UNKNOWN;
1626  break;
1627  case 1:/* public */
1628  number_plan = NUMPLAN_ISDN;
1629  break;
1630  case 3:/* data */
1631  number_plan = NUMPLAN_DATA;
1632  break;
1633  case 4:/* telex */
1634  number_plan = NUMPLAN_TELEX;
1635  break;
1636  case 8:/* nationalStandard */
1637  number_plan = NUMPLAN_NATIONAL;
1638  break;
1639  case 5:/* private */
1640  number_plan = NUMPLAN_PRIVATE;
1641  break;
1642  }
1643 
1644  return number_plan;
1645 }
1646 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1647 
1648 #if defined(AST_MISDN_ENHANCEMENTS)
1649 /*!
1650  * \internal
1651  * \brief Convert mISDN type-of-number to PartyNumber public type-of-number
1652  *
1653  * \param ton mISDN type-of-number
1654  *
1655  * \return PartyNumber public type-of-number
1656  */
1657 static unsigned misdn_to_PartyNumber_ton_public(enum mISDN_NUMBER_TYPE ton)
1658 {
1659  unsigned party_ton;
1660 
1661  switch (ton) {
1662  default:
1663  case NUMTYPE_UNKNOWN:
1664  party_ton = 0;/* unknown */
1665  break;
1666 
1667  case NUMTYPE_INTERNATIONAL:
1668  party_ton = 1;/* internationalNumber */
1669  break;
1670 
1671  case NUMTYPE_NATIONAL:
1672  party_ton = 2;/* nationalNumber */
1673  break;
1674 
1676  party_ton = 3;/* networkSpecificNumber */
1677  break;
1678 
1679  case NUMTYPE_SUBSCRIBER:
1680  party_ton = 4;/* subscriberNumber */
1681  break;
1682 
1683  case NUMTYPE_ABBREVIATED:
1684  party_ton = 6;/* abbreviatedNumber */
1685  break;
1686  }
1687 
1688  return party_ton;
1689 }
1690 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1691 
1692 #if defined(AST_MISDN_ENHANCEMENTS)
1693 /*!
1694  * \internal
1695  * \brief Convert the PartyNumber public type-of-number to mISDN type-of-number
1696  *
1697  * \param party_ton PartyNumber public type-of-number
1698  *
1699  * \return mISDN type-of-number
1700  */
1701 static enum mISDN_NUMBER_TYPE PartyNumber_to_misdn_ton_public(unsigned party_ton)
1702 {
1703  enum mISDN_NUMBER_TYPE ton;
1704 
1705  switch (party_ton) {
1706  default:
1707  case 0:/* unknown */
1708  ton = NUMTYPE_UNKNOWN;
1709  break;
1710 
1711  case 1:/* internationalNumber */
1712  ton = NUMTYPE_INTERNATIONAL;
1713  break;
1714 
1715  case 2:/* nationalNumber */
1716  ton = NUMTYPE_NATIONAL;
1717  break;
1718 
1719  case 3:/* networkSpecificNumber */
1721  break;
1722 
1723  case 4:/* subscriberNumber */
1724  ton = NUMTYPE_SUBSCRIBER;
1725  break;
1726 
1727  case 6:/* abbreviatedNumber */
1728  ton = NUMTYPE_ABBREVIATED;
1729  break;
1730  }
1731 
1732  return ton;
1733 }
1734 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1735 
1736 #if defined(AST_MISDN_ENHANCEMENTS)
1737 /*!
1738  * \internal
1739  * \brief Convert mISDN type-of-number to PartyNumber private type-of-number
1740  *
1741  * \param ton mISDN type-of-number
1742  *
1743  * \return PartyNumber private type-of-number
1744  */
1745 static unsigned misdn_to_PartyNumber_ton_private(enum mISDN_NUMBER_TYPE ton)
1746 {
1747  unsigned party_ton;
1748 
1749  switch (ton) {
1750  default:
1751  case NUMTYPE_UNKNOWN:
1752  party_ton = 0;/* unknown */
1753  break;
1754 
1755  case NUMTYPE_INTERNATIONAL:
1756  party_ton = 1;/* level2RegionalNumber */
1757  break;
1758 
1759  case NUMTYPE_NATIONAL:
1760  party_ton = 2;/* level1RegionalNumber */
1761  break;
1762 
1764  party_ton = 3;/* pTNSpecificNumber */
1765  break;
1766 
1767  case NUMTYPE_SUBSCRIBER:
1768  party_ton = 4;/* localNumber */
1769  break;
1770 
1771  case NUMTYPE_ABBREVIATED:
1772  party_ton = 6;/* abbreviatedNumber */
1773  break;
1774  }
1775 
1776  return party_ton;
1777 }
1778 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1779 
1780 #if defined(AST_MISDN_ENHANCEMENTS)
1781 /*!
1782  * \internal
1783  * \brief Convert the PartyNumber private type-of-number to mISDN type-of-number
1784  *
1785  * \param party_ton PartyNumber private type-of-number
1786  *
1787  * \return mISDN type-of-number
1788  */
1789 static enum mISDN_NUMBER_TYPE PartyNumber_to_misdn_ton_private(unsigned party_ton)
1790 {
1791  enum mISDN_NUMBER_TYPE ton;
1792 
1793  switch (party_ton) {
1794  default:
1795  case 0:/* unknown */
1796  ton = NUMTYPE_UNKNOWN;
1797  break;
1798 
1799  case 1:/* level2RegionalNumber */
1800  ton = NUMTYPE_INTERNATIONAL;
1801  break;
1802 
1803  case 2:/* level1RegionalNumber */
1804  ton = NUMTYPE_NATIONAL;
1805  break;
1806 
1807  case 3:/* pTNSpecificNumber */
1809  break;
1810 
1811  case 4:/* localNumber */
1812  ton = NUMTYPE_SUBSCRIBER;
1813  break;
1814 
1815  case 6:/* abbreviatedNumber */
1816  ton = NUMTYPE_ABBREVIATED;
1817  break;
1818  }
1819 
1820  return ton;
1821 }
1822 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1823 
1824 /*!
1825  * \internal
1826  * \brief Convert the mISDN type of number code to a string
1827  *
1828  * \param number_type mISDN type of number code.
1829  *
1830  * \return The mISDN type of number code as a string
1831  */
1832 static const char *misdn_to_str_ton(enum mISDN_NUMBER_TYPE number_type)
1833 {
1834  const char *str;
1835 
1836  switch (number_type) {
1837  default:
1838  case NUMTYPE_UNKNOWN:
1839  str = "Unknown";
1840  break;
1841 
1842  case NUMTYPE_INTERNATIONAL:
1843  str = "International";
1844  break;
1845 
1846  case NUMTYPE_NATIONAL:
1847  str = "National";
1848  break;
1849 
1851  str = "Network Specific";
1852  break;
1853 
1854  case NUMTYPE_SUBSCRIBER:
1855  str = "Subscriber";
1856  break;
1857 
1858  case NUMTYPE_ABBREVIATED:
1859  str = "Abbreviated";
1860  break;
1861  }
1862 
1863  return str;
1864 }
1865 
1866 /*!
1867  * \internal
1868  * \brief Convert the mISDN type of number code to Asterisk type of number code
1869  *
1870  * \param number_type mISDN type of number code.
1871  *
1872  * \return Asterisk type of number code
1873  */
1874 static int misdn_to_ast_ton(enum mISDN_NUMBER_TYPE number_type)
1875 {
1876  int ast_number_type;
1877 
1878  switch (number_type) {
1879  default:
1880  case NUMTYPE_UNKNOWN:
1881  ast_number_type = NUMTYPE_UNKNOWN << 4;
1882  break;
1883 
1884  case NUMTYPE_INTERNATIONAL:
1885  ast_number_type = NUMTYPE_INTERNATIONAL << 4;
1886  break;
1887 
1888  case NUMTYPE_NATIONAL:
1889  ast_number_type = NUMTYPE_NATIONAL << 4;
1890  break;
1891 
1893  ast_number_type = NUMTYPE_NETWORK_SPECIFIC << 4;
1894  break;
1895 
1896  case NUMTYPE_SUBSCRIBER:
1897  ast_number_type = NUMTYPE_SUBSCRIBER << 4;
1898  break;
1899 
1900  case NUMTYPE_ABBREVIATED:
1901  ast_number_type = NUMTYPE_ABBREVIATED << 4;
1902  break;
1903  }
1904 
1905  return ast_number_type;
1906 }
1907 
1908 /*!
1909  * \internal
1910  * \brief Convert the Asterisk type of number code to mISDN type of number code
1911  *
1912  * \param ast_number_type Asterisk type of number code.
1913  *
1914  * \return mISDN type of number code
1915  */
1916 static enum mISDN_NUMBER_TYPE ast_to_misdn_ton(unsigned ast_number_type)
1917 {
1918  enum mISDN_NUMBER_TYPE number_type;
1919 
1920  switch ((ast_number_type >> 4) & 0x07) {
1921  default:
1922  case NUMTYPE_UNKNOWN:
1923  number_type = NUMTYPE_UNKNOWN;
1924  break;
1925 
1926  case NUMTYPE_INTERNATIONAL:
1927  number_type = NUMTYPE_INTERNATIONAL;
1928  break;
1929 
1930  case NUMTYPE_NATIONAL:
1931  number_type = NUMTYPE_NATIONAL;
1932  break;
1933 
1935  number_type = NUMTYPE_NETWORK_SPECIFIC;
1936  break;
1937 
1938  case NUMTYPE_SUBSCRIBER:
1939  number_type = NUMTYPE_SUBSCRIBER;
1940  break;
1941 
1942  case NUMTYPE_ABBREVIATED:
1943  number_type = NUMTYPE_ABBREVIATED;
1944  break;
1945  }
1946 
1947  return number_type;
1948 }
1949 
1950 /*!
1951  * \internal
1952  * \brief Convert the mISDN numbering plan code to a string
1953  *
1954  * \param number_plan mISDN numbering plan code.
1955  *
1956  * \return The mISDN numbering plan code as a string
1957  */
1958 static const char *misdn_to_str_plan(enum mISDN_NUMBER_PLAN number_plan)
1959 {
1960  const char *str;
1961 
1962  switch (number_plan) {
1963  default:
1964  case NUMPLAN_UNKNOWN:
1965  str = "Unknown";
1966  break;
1967 
1968  case NUMPLAN_ISDN:
1969  str = "ISDN";
1970  break;
1971 
1972  case NUMPLAN_DATA:
1973  str = "Data";
1974  break;
1975 
1976  case NUMPLAN_TELEX:
1977  str = "Telex";
1978  break;
1979 
1980  case NUMPLAN_NATIONAL:
1981  str = "National";
1982  break;
1983 
1984  case NUMPLAN_PRIVATE:
1985  str = "Private";
1986  break;
1987  }
1988 
1989  return str;
1990 }
1991 
1992 /*!
1993  * \internal
1994  * \brief Convert the mISDN numbering plan code to Asterisk numbering plan code
1995  *
1996  * \param number_plan mISDN numbering plan code.
1997  *
1998  * \return Asterisk numbering plan code
1999  */
2000 static int misdn_to_ast_plan(enum mISDN_NUMBER_PLAN number_plan)
2001 {
2002  int ast_number_plan;
2003 
2004  switch (number_plan) {
2005  default:
2006  case NUMPLAN_UNKNOWN:
2007  ast_number_plan = NUMPLAN_UNKNOWN;
2008  break;
2009 
2010  case NUMPLAN_ISDN:
2011  ast_number_plan = NUMPLAN_ISDN;
2012  break;
2013 
2014  case NUMPLAN_DATA:
2015  ast_number_plan = NUMPLAN_DATA;
2016  break;
2017 
2018  case NUMPLAN_TELEX:
2019  ast_number_plan = NUMPLAN_TELEX;
2020  break;
2021 
2022  case NUMPLAN_NATIONAL:
2023  ast_number_plan = NUMPLAN_NATIONAL;
2024  break;
2025 
2026  case NUMPLAN_PRIVATE:
2027  ast_number_plan = NUMPLAN_PRIVATE;
2028  break;
2029  }
2030 
2031  return ast_number_plan;
2032 }
2033 
2034 /*!
2035  * \internal
2036  * \brief Convert the Asterisk numbering plan code to mISDN numbering plan code
2037  *
2038  * \param ast_number_plan Asterisk numbering plan code.
2039  *
2040  * \return mISDN numbering plan code
2041  */
2042 static enum mISDN_NUMBER_PLAN ast_to_misdn_plan(unsigned ast_number_plan)
2043 {
2044  enum mISDN_NUMBER_PLAN number_plan;
2045 
2046  switch (ast_number_plan & 0x0F) {
2047  default:
2048  case NUMPLAN_UNKNOWN:
2049  number_plan = NUMPLAN_UNKNOWN;
2050  break;
2051 
2052  case NUMPLAN_ISDN:
2053  number_plan = NUMPLAN_ISDN;
2054  break;
2055 
2056  case NUMPLAN_DATA:
2057  number_plan = NUMPLAN_DATA;
2058  break;
2059 
2060  case NUMPLAN_TELEX:
2061  number_plan = NUMPLAN_TELEX;
2062  break;
2063 
2064  case NUMPLAN_NATIONAL:
2065  number_plan = NUMPLAN_NATIONAL;
2066  break;
2067 
2068  case NUMPLAN_PRIVATE:
2069  number_plan = NUMPLAN_PRIVATE;
2070  break;
2071  }
2072 
2073  return number_plan;
2074 }
2075 
2076 /*!
2077  * \internal
2078  * \brief Convert the mISDN presentation code to a string
2079  *
2080  * \param presentation mISDN number presentation restriction code.
2081  *
2082  * \return The mISDN presentation code as a string
2083  */
2084 static const char *misdn_to_str_pres(int presentation)
2085 {
2086  const char *str;
2087 
2088  switch (presentation) {
2089  case 0:
2090  str = "Allowed";
2091  break;
2092 
2093  case 1:
2094  str = "Restricted";
2095  break;
2096 
2097  case 2:
2098  str = "Unavailable";
2099  break;
2100 
2101  default:
2102  str = "Unknown";
2103  break;
2104  }
2105 
2106  return str;
2107 }
2108 
2109 /*!
2110  * \internal
2111  * \brief Convert the mISDN presentation code to Asterisk presentation code
2112  *
2113  * \param presentation mISDN number presentation restriction code.
2114  *
2115  * \return Asterisk presentation code
2116  */
2117 static int misdn_to_ast_pres(int presentation)
2118 {
2119  switch (presentation) {
2120  default:
2121  case 0:
2122  presentation = AST_PRES_ALLOWED;
2123  break;
2124 
2125  case 1:
2126  presentation = AST_PRES_RESTRICTED;
2127  break;
2128 
2129  case 2:
2130  presentation = AST_PRES_UNAVAILABLE;
2131  break;
2132  }
2133 
2134  return presentation;
2135 }
2136 
2137 /*!
2138  * \internal
2139  * \brief Convert the Asterisk presentation code to mISDN presentation code
2140  *
2141  * \param presentation Asterisk number presentation restriction code.
2142  *
2143  * \return mISDN presentation code
2144  */
2145 static int ast_to_misdn_pres(int presentation)
2146 {
2147  switch (presentation & AST_PRES_RESTRICTION) {
2148  default:
2149  case AST_PRES_ALLOWED:
2150  presentation = 0;
2151  break;
2152 
2153  case AST_PRES_RESTRICTED:
2154  presentation = 1;
2155  break;
2156 
2157  case AST_PRES_UNAVAILABLE:
2158  presentation = 2;
2159  break;
2160  }
2161 
2162  return presentation;
2163 }
2164 
2165 /*!
2166  * \internal
2167  * \brief Convert the mISDN screening code to a string
2168  *
2169  * \param screening mISDN number screening code.
2170  *
2171  * \return The mISDN screening code as a string
2172  */
2173 static const char *misdn_to_str_screen(int screening)
2174 {
2175  const char *str;
2176 
2177  switch (screening) {
2178  case 0:
2179  str = "Unscreened";
2180  break;
2181 
2182  case 1:
2183  str = "Passed Screen";
2184  break;
2185 
2186  case 2:
2187  str = "Failed Screen";
2188  break;
2189 
2190  case 3:
2191  str = "Network Number";
2192  break;
2193 
2194  default:
2195  str = "Unknown";
2196  break;
2197  }
2198 
2199  return str;
2200 }
2201 
2202 /*!
2203  * \internal
2204  * \brief Convert the mISDN screening code to Asterisk screening code
2205  *
2206  * \param screening mISDN number screening code.
2207  *
2208  * \return Asterisk screening code
2209  */
2210 static int misdn_to_ast_screen(int screening)
2211 {
2212  switch (screening) {
2213  default:
2214  case 0:
2215  screening = AST_PRES_USER_NUMBER_UNSCREENED;
2216  break;
2217 
2218  case 1:
2220  break;
2221 
2222  case 2:
2224  break;
2225 
2226  case 3:
2227  screening = AST_PRES_NETWORK_NUMBER;
2228  break;
2229  }
2230 
2231  return screening;
2232 }
2233 
2234 /*!
2235  * \internal
2236  * \brief Convert the Asterisk screening code to mISDN screening code
2237  *
2238  * \param screening Asterisk number screening code.
2239  *
2240  * \return mISDN screening code
2241  */
2242 static int ast_to_misdn_screen(int screening)
2243 {
2244  switch (screening & AST_PRES_NUMBER_TYPE) {
2245  default:
2247  screening = 0;
2248  break;
2249 
2251  screening = 1;
2252  break;
2253 
2255  screening = 2;
2256  break;
2257 
2259  screening = 3;
2260  break;
2261  }
2262 
2263  return screening;
2264 }
2265 
2266 /*!
2267  * \internal
2268  * \brief Convert Asterisk redirecting reason to mISDN redirecting reason code.
2269  *
2270  * \param ast Asterisk redirecting reason code.
2271  *
2272  * \return mISDN reason code
2273  */
2275 {
2276  unsigned index;
2277 
2278  static const struct misdn_reasons {
2279  enum AST_REDIRECTING_REASON ast;
2280  enum mISDN_REDIRECTING_REASON q931;
2281  } misdn_reason_table[] = {
2282  /* *INDENT-OFF* */
2286  { AST_REDIRECTING_REASON_UNAVAILABLE, mISDN_REDIRECTING_REASON_NO_REPLY },
2288  { AST_REDIRECTING_REASON_TIME_OF_DAY, mISDN_REDIRECTING_REASON_UNKNOWN },
2289  { AST_REDIRECTING_REASON_DO_NOT_DISTURB, mISDN_REDIRECTING_REASON_UNKNOWN },
2291  { AST_REDIRECTING_REASON_FOLLOW_ME, mISDN_REDIRECTING_REASON_UNKNOWN },
2293  { AST_REDIRECTING_REASON_AWAY, mISDN_REDIRECTING_REASON_UNKNOWN },
2295  /* *INDENT-ON* */
2296  };
2297 
2298  for (index = 0; index < ARRAY_LEN(misdn_reason_table); ++index) {
2299  if (misdn_reason_table[index].ast == ast) {
2300  return misdn_reason_table[index].q931;
2301  }
2302  }
2304 }
2305 
2306 /*!
2307  * \internal
2308  * \brief Convert the mISDN redirecting reason to Asterisk redirecting reason code
2309  *
2310  * \param q931 mISDN redirecting reason code.
2311  *
2312  * \return Asterisk redirecting reason code
2313  */
2315 {
2316  enum AST_REDIRECTING_REASON ast;
2317 
2318  switch (q931) {
2319  default:
2322  break;
2323 
2326  break;
2327 
2330  break;
2331 
2334  break;
2335 
2338  break;
2339 
2342  break;
2343 
2346  break;
2347  }
2348 
2349  return ast;
2350 }
2351 
2352 
2353 
2355  char *name; /*!< Bearer capability name string used in /etc/misdn.conf allowed_bearers */
2356  char *display; /*!< Bearer capability displayable name */
2357  int cap; /*!< SETUP message bearer capability field code value */
2358  int deprecated; /*!< TRUE if this entry is deprecated. (Misspelled or bad name to use) */
2359 };
2360 
2361 /* *INDENT-OFF* */
2362 static const struct allowed_bearers allowed_bearers_array[] = {
2363  /* Name, Displayable Name Bearer Capability, Deprecated */
2364  { "speech", "Speech", INFO_CAPABILITY_SPEECH, 0 },
2365  { "3_1khz", "3.1KHz Audio", INFO_CAPABILITY_AUDIO_3_1K, 0 },
2366  { "digital_unrestricted", "Unrestricted Digital", INFO_CAPABILITY_DIGITAL_UNRESTRICTED, 0 },
2367  { "digital_restricted", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 0 },
2368  { "digital_restriced", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 1 }, /* Allow misspelling for backwards compatibility */
2369  { "video", "Video", INFO_CAPABILITY_VIDEO, 0 }
2370 };
2371 /* *INDENT-ON* */
2372 
2373 static const char *bearer2str(int cap)
2374 {
2375  unsigned index;
2376 
2377  for (index = 0; index < ARRAY_LEN(allowed_bearers_array); ++index) {
2378  if (allowed_bearers_array[index].cap == cap) {
2379  return allowed_bearers_array[index].display;
2380  }
2381  }
2382 
2383  return "Unknown Bearer";
2384 }
2385 
2386 #if defined(AST_MISDN_ENHANCEMENTS)
2387 /*!
2388  * \internal
2389  * \brief Fill in facility PartyNumber information
2390  *
2391  * \param party PartyNumber structure to fill in.
2392  * \param id Information to put in PartyNumber structure.
2393  *
2394  * \return Nothing
2395  */
2396 static void misdn_PartyNumber_fill(struct FacPartyNumber *party, const struct misdn_party_id *id)
2397 {
2398  ast_copy_string((char *) party->Number, id->number, sizeof(party->Number));
2399  party->LengthOfNumber = strlen((char *) party->Number);
2400  party->Type = misdn_to_PartyNumber_plan(id->number_plan);
2401  switch (party->Type) {
2402  case 1:/* public */
2403  party->TypeOfNumber = misdn_to_PartyNumber_ton_public(id->number_type);
2404  break;
2405  case 5:/* private */
2406  party->TypeOfNumber = misdn_to_PartyNumber_ton_private(id->number_type);
2407  break;
2408  default:
2409  party->TypeOfNumber = 0;/* Don't care */
2410  break;
2411  }
2412 }
2413 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2414 
2415 #if defined(AST_MISDN_ENHANCEMENTS)
2416 /*!
2417  * \internal
2418  * \brief Extract the information from PartyNumber
2419  *
2420  * \param id Where to put extracted PartyNumber information
2421  * \param party PartyNumber information to extract
2422  *
2423  * \return Nothing
2424  */
2425 static void misdn_PartyNumber_extract(struct misdn_party_id *id, const struct FacPartyNumber *party)
2426 {
2427  if (party->LengthOfNumber) {
2428  ast_copy_string(id->number, (char *) party->Number, sizeof(id->number));
2429  id->number_plan = PartyNumber_to_misdn_plan(party->Type);
2430  switch (party->Type) {
2431  case 1:/* public */
2432  id->number_type = PartyNumber_to_misdn_ton_public(party->TypeOfNumber);
2433  break;
2434  case 5:/* private */
2435  id->number_type = PartyNumber_to_misdn_ton_private(party->TypeOfNumber);
2436  break;
2437  default:
2438  id->number_type = NUMTYPE_UNKNOWN;
2439  break;
2440  }
2441  } else {
2442  /* Number not present */
2443  id->number_type = NUMTYPE_UNKNOWN;
2444  id->number_plan = NUMPLAN_ISDN;
2445  id->number[0] = 0;
2446  }
2447 }
2448 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2449 
2450 #if defined(AST_MISDN_ENHANCEMENTS)
2451 /*!
2452  * \internal
2453  * \brief Fill in facility Address information
2454  *
2455  * \param Address Address structure to fill in.
2456  * \param id Information to put in Address structure.
2457  *
2458  * \return Nothing
2459  */
2460 static void misdn_Address_fill(struct FacAddress *Address, const struct misdn_party_id *id)
2461 {
2462  misdn_PartyNumber_fill(&Address->Party, id);
2463 
2464  /* Subaddresses are not supported yet */
2465  Address->Subaddress.Length = 0;
2466 }
2467 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2468 
2469 #if defined(AST_MISDN_ENHANCEMENTS)
2470 /*!
2471  * \internal
2472  * \brief Fill in facility PresentedNumberUnscreened information
2473  *
2474  * \param presented PresentedNumberUnscreened structure to fill in.
2475  * \param id Information to put in PresentedNumberUnscreened structure.
2476  *
2477  * \return Nothing
2478  */
2479 static void misdn_PresentedNumberUnscreened_fill(struct FacPresentedNumberUnscreened *presented, const struct misdn_party_id *id)
2480 {
2481  presented->Type = misdn_to_PresentedNumberUnscreened_type(id->presentation, id->number[0] ? 1 : 0);
2482  misdn_PartyNumber_fill(&presented->Unscreened, id);
2483 }
2484 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2485 
2486 #if defined(AST_MISDN_ENHANCEMENTS)
2487 /*!
2488  * \internal
2489  * \brief Extract the information from PartyNumber
2490  *
2491  * \param id Where to put extracted PresentedNumberUnscreened information
2492  * \param presented PresentedNumberUnscreened information to extract
2493  *
2494  * \return Nothing
2495  */
2496 static void misdn_PresentedNumberUnscreened_extract(struct misdn_party_id *id, const struct FacPresentedNumberUnscreened *presented)
2497 {
2498  id->presentation = PresentedNumberUnscreened_to_misdn_pres(presented->Type);
2499  id->screening = 0;/* unscreened */
2500  switch (presented->Type) {
2501  case 0:/* presentationAllowedNumber */
2502  case 3:/* presentationRestrictedNumber */
2503  misdn_PartyNumber_extract(id, &presented->Unscreened);
2504  break;
2505  case 1:/* presentationRestricted */
2506  case 2:/* numberNotAvailableDueToInterworking */
2507  default:
2508  /* Number not present (And uninitialized so do not even look at it!) */
2509  id->number_type = NUMTYPE_UNKNOWN;
2510  id->number_plan = NUMPLAN_ISDN;
2511  id->number[0] = 0;
2512  break;
2513  }
2514 }
2515 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2516 
2517 #if defined(AST_MISDN_ENHANCEMENTS)
2518 static const char Level_Spacing[] = " ";/* Work for up to 10 levels */
2519 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2520 
2521 #if defined(AST_MISDN_ENHANCEMENTS)
2522 static void print_facility_PartyNumber(unsigned Level, const struct FacPartyNumber *Party, const struct misdn_bchannel *bc)
2523 {
2524  if (Party->LengthOfNumber) {
2525  const char *Spacing;
2526 
2527  Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2528  chan_misdn_log(1, bc->port, " -->%s PartyNumber: Type:%d\n",
2529  Spacing, Party->Type);
2530  switch (Party->Type) {
2531  case 0: /* Unknown PartyNumber */
2532  chan_misdn_log(1, bc->port, " -->%s Unknown: %s\n",
2533  Spacing, Party->Number);
2534  break;
2535  case 1: /* Public PartyNumber */
2536  chan_misdn_log(1, bc->port, " -->%s Public TON:%d %s\n",
2537  Spacing, Party->TypeOfNumber, Party->Number);
2538  break;
2539  case 2: /* NSAP encoded PartyNumber */
2540  chan_misdn_log(1, bc->port, " -->%s NSAP: %s\n",
2541  Spacing, Party->Number);
2542  break;
2543  case 3: /* Data PartyNumber (Not used) */
2544  chan_misdn_log(1, bc->port, " -->%s Data: %s\n",
2545  Spacing, Party->Number);
2546  break;
2547  case 4: /* Telex PartyNumber (Not used) */
2548  chan_misdn_log(1, bc->port, " -->%s Telex: %s\n",
2549  Spacing, Party->Number);
2550  break;
2551  case 5: /* Private PartyNumber */
2552  chan_misdn_log(1, bc->port, " -->%s Private TON:%d %s\n",
2553  Spacing, Party->TypeOfNumber, Party->Number);
2554  break;
2555  case 8: /* National Standard PartyNumber (Not used) */
2556  chan_misdn_log(1, bc->port, " -->%s National: %s\n",
2557  Spacing, Party->Number);
2558  break;
2559  default:
2560  break;
2561  }
2562  }
2563 }
2564 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2565 
2566 #if defined(AST_MISDN_ENHANCEMENTS)
2567 static void print_facility_Subaddress(unsigned Level, const struct FacPartySubaddress *Subaddress, const struct misdn_bchannel *bc)
2568 {
2569  if (Subaddress->Length) {
2570  const char *Spacing;
2571 
2572  Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2573  chan_misdn_log(1, bc->port, " -->%s Subaddress: Type:%d\n",
2574  Spacing, Subaddress->Type);
2575  switch (Subaddress->Type) {
2576  case 0: /* UserSpecified */
2577  if (Subaddress->u.UserSpecified.OddCountPresent) {
2578  chan_misdn_log(1, bc->port, " -->%s User BCD OddCount:%d NumOctets:%d\n",
2579  Spacing, Subaddress->u.UserSpecified.OddCount, Subaddress->Length);
2580  } else {
2581  chan_misdn_log(1, bc->port, " -->%s User: %s\n",
2582  Spacing, Subaddress->u.UserSpecified.Information);
2583  }
2584  break;
2585  case 1: /* NSAP */
2586  chan_misdn_log(1, bc->port, " -->%s NSAP: %s\n",
2587  Spacing, Subaddress->u.Nsap);
2588  break;
2589  default:
2590  break;
2591  }
2592  }
2593 }
2594 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2595 
2596 #if defined(AST_MISDN_ENHANCEMENTS)
2597 static void print_facility_Address(unsigned Level, const struct FacAddress *Address, const struct misdn_bchannel *bc)
2598 {
2599  print_facility_PartyNumber(Level, &Address->Party, bc);
2600  print_facility_Subaddress(Level, &Address->Subaddress, bc);
2601 }
2602 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2603 
2604 #if defined(AST_MISDN_ENHANCEMENTS)
2605 static void print_facility_PresentedNumberUnscreened(unsigned Level, const struct FacPresentedNumberUnscreened *Presented, const struct misdn_bchannel *bc)
2606 {
2607  const char *Spacing;
2608 
2609  Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2610  chan_misdn_log(1, bc->port, " -->%s Unscreened Type:%d\n", Spacing, Presented->Type);
2611  switch (Presented->Type) {
2612  case 0: /* presentationAllowedNumber */
2613  chan_misdn_log(1, bc->port, " -->%s Allowed:\n", Spacing);
2614  print_facility_PartyNumber(Level + 2, &Presented->Unscreened, bc);
2615  break;
2616  case 1: /* presentationRestricted */
2617  chan_misdn_log(1, bc->port, " -->%s Restricted\n", Spacing);
2618  break;
2619  case 2: /* numberNotAvailableDueToInterworking */
2620  chan_misdn_log(1, bc->port, " -->%s Not Available\n", Spacing);
2621  break;
2622  case 3: /* presentationRestrictedNumber */
2623  chan_misdn_log(1, bc->port, " -->%s Restricted:\n", Spacing);
2624  print_facility_PartyNumber(Level + 2, &Presented->Unscreened, bc);
2625  break;
2626  default:
2627  break;
2628  }
2629 }
2630 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2631 
2632 #if defined(AST_MISDN_ENHANCEMENTS)
2633 static void print_facility_AddressScreened(unsigned Level, const struct FacAddressScreened *Address, const struct misdn_bchannel *bc)
2634 {
2635  const char *Spacing;
2636 
2637  Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2638  chan_misdn_log(1, bc->port, " -->%s ScreeningIndicator:%d\n", Spacing, Address->ScreeningIndicator);
2639  print_facility_PartyNumber(Level, &Address->Party, bc);
2640  print_facility_Subaddress(Level, &Address->Subaddress, bc);
2641 }
2642 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2643 
2644 #if defined(AST_MISDN_ENHANCEMENTS)
2645 static void print_facility_PresentedAddressScreened(unsigned Level, const struct FacPresentedAddressScreened *Presented, const struct misdn_bchannel *bc)
2646 {
2647  const char *Spacing;
2648 
2649  Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2650  chan_misdn_log(1, bc->port, " -->%s Screened Type:%d\n", Spacing, Presented->Type);
2651  switch (Presented->Type) {
2652  case 0: /* presentationAllowedAddress */
2653  chan_misdn_log(1, bc->port, " -->%s Allowed:\n", Spacing);
2654  print_facility_AddressScreened(Level + 2, &Presented->Address, bc);
2655  break;
2656  case 1: /* presentationRestricted */
2657  chan_misdn_log(1, bc->port, " -->%s Restricted\n", Spacing);
2658  break;
2659  case 2: /* numberNotAvailableDueToInterworking */
2660  chan_misdn_log(1, bc->port, " -->%s Not Available\n", Spacing);
2661  break;
2662  case 3: /* presentationRestrictedAddress */
2663  chan_misdn_log(1, bc->port, " -->%s Restricted:\n", Spacing);
2664  print_facility_AddressScreened(Level + 2, &Presented->Address, bc);
2665  break;
2666  default:
2667  break;
2668  }
2669 }
2670 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2671 
2672 #if defined(AST_MISDN_ENHANCEMENTS)
2673 static void print_facility_Q931_Bc_Hlc_Llc(unsigned Level, const struct Q931_Bc_Hlc_Llc *Q931ie, const struct misdn_bchannel *bc)
2674 {
2675  const char *Spacing;
2676 
2677  Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2678  chan_misdn_log(1, bc->port, " -->%s Q931ie:\n", Spacing);
2679  if (Q931ie->Bc.Length) {
2680  chan_misdn_log(1, bc->port, " -->%s Bc Len:%d\n", Spacing, Q931ie->Bc.Length);
2681  }
2682  if (Q931ie->Hlc.Length) {
2683  chan_misdn_log(1, bc->port, " -->%s Hlc Len:%d\n", Spacing, Q931ie->Hlc.Length);
2684  }
2685  if (Q931ie->Llc.Length) {
2686  chan_misdn_log(1, bc->port, " -->%s Llc Len:%d\n", Spacing, Q931ie->Llc.Length);
2687  }
2688 }
2689 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2690 
2691 #if defined(AST_MISDN_ENHANCEMENTS)
2692 static void print_facility_Q931_Bc_Hlc_Llc_Uu(unsigned Level, const struct Q931_Bc_Hlc_Llc_Uu *Q931ie, const struct misdn_bchannel *bc)
2693 {
2694  const char *Spacing;
2695 
2696  Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2697  chan_misdn_log(1, bc->port, " -->%s Q931ie:\n", Spacing);
2698  if (Q931ie->Bc.Length) {
2699  chan_misdn_log(1, bc->port, " -->%s Bc Len:%d\n", Spacing, Q931ie->Bc.Length);
2700  }
2701  if (Q931ie->Hlc.Length) {
2702  chan_misdn_log(1, bc->port, " -->%s Hlc Len:%d\n", Spacing, Q931ie->Hlc.Length);
2703  }
2704  if (Q931ie->Llc.Length) {
2705  chan_misdn_log(1, bc->port, " -->%s Llc Len:%d\n", Spacing, Q931ie->Llc.Length);
2706  }
2707  if (Q931ie->UserInfo.Length) {
2708  chan_misdn_log(1, bc->port, " -->%s UserInfo Len:%d\n", Spacing, Q931ie->UserInfo.Length);
2709  }
2710 }
2711 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2712 
2713 #if defined(AST_MISDN_ENHANCEMENTS)
2714 static void print_facility_CallInformation(unsigned Level, const struct FacCallInformation *CallInfo, const struct misdn_bchannel *bc)
2715 {
2716  const char *Spacing;
2717 
2718  Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2719  chan_misdn_log(1, bc->port, " -->%s CCBSReference:%d\n",
2720  Spacing, CallInfo->CCBSReference);
2721  chan_misdn_log(1, bc->port, " -->%s AddressOfB:\n", Spacing);
2722  print_facility_Address(Level + 1, &CallInfo->AddressOfB, bc);
2723  print_facility_Q931_Bc_Hlc_Llc(Level, &CallInfo->Q931ie, bc);
2724  if (CallInfo->SubaddressOfA.Length) {
2725  chan_misdn_log(1, bc->port, " -->%s SubaddressOfA:\n", Spacing);
2726  print_facility_Subaddress(Level + 1, &CallInfo->SubaddressOfA, bc);
2727  }
2728 }
2729 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2730 
2731 #if defined(AST_MISDN_ENHANCEMENTS)
2732 static void print_facility_ServedUserNr(unsigned Level, const struct FacPartyNumber *Party, const struct misdn_bchannel *bc)
2733 {
2734  const char *Spacing;
2735 
2736  Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2737  if (Party->LengthOfNumber) {
2738  print_facility_PartyNumber(Level, Party, bc);
2739  } else {
2740  chan_misdn_log(1, bc->port, " -->%s All Numbers\n", Spacing);
2741  }
2742 }
2743 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2744 
2745 #if defined(AST_MISDN_ENHANCEMENTS)
2746 static void print_facility_IntResult(unsigned Level, const struct FacForwardingRecord *ForwardingRecord, const struct misdn_bchannel *bc)
2747 {
2748  const char *Spacing;
2749 
2750  Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2751  chan_misdn_log(1, bc->port, " -->%s Procedure:%d BasicService:%d\n",
2752  Spacing,
2753  ForwardingRecord->Procedure,
2754  ForwardingRecord->BasicService);
2755  chan_misdn_log(1, bc->port, " -->%s ForwardedTo:\n", Spacing);
2756  print_facility_Address(Level + 1, &ForwardingRecord->ForwardedTo, bc);
2757  chan_misdn_log(1, bc->port, " -->%s ServedUserNr:\n", Spacing);
2758  print_facility_ServedUserNr(Level + 1, &ForwardingRecord->ServedUser, bc);
2759 }
2760 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2761 
2762 static void print_facility(const struct FacParm *fac, const struct misdn_bchannel *bc)
2763 {
2764 #if defined(AST_MISDN_ENHANCEMENTS)
2765  unsigned Index;
2766 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2767 
2768  switch (fac->Function) {
2769 #if defined(AST_MISDN_ENHANCEMENTS)
2770  case Fac_ActivationDiversion:
2771  chan_misdn_log(1, bc->port, " --> ActivationDiversion: InvokeID:%d\n",
2772  fac->u.ActivationDiversion.InvokeID);
2773  switch (fac->u.ActivationDiversion.ComponentType) {
2774  case FacComponent_Invoke:
2775  chan_misdn_log(1, bc->port, " --> Invoke: Procedure:%d BasicService:%d\n",
2776  fac->u.ActivationDiversion.Component.Invoke.Procedure,
2777  fac->u.ActivationDiversion.Component.Invoke.BasicService);
2778  chan_misdn_log(1, bc->port, " --> ForwardedTo:\n");
2779  print_facility_Address(3, &fac->u.ActivationDiversion.Component.Invoke.ForwardedTo, bc);
2780  chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
2781  print_facility_ServedUserNr(3, &fac->u.ActivationDiversion.Component.Invoke.ServedUser, bc);
2782  break;
2783  case FacComponent_Result:
2784  chan_misdn_log(1, bc->port, " --> Result\n");
2785  break;
2786  default:
2787  break;
2788  }
2789  break;
2790  case Fac_DeactivationDiversion:
2791  chan_misdn_log(1, bc->port, " --> DeactivationDiversion: InvokeID:%d\n",
2792  fac->u.DeactivationDiversion.InvokeID);
2793  switch (fac->u.DeactivationDiversion.ComponentType) {
2794  case FacComponent_Invoke:
2795  chan_misdn_log(1, bc->port, " --> Invoke: Procedure:%d BasicService:%d\n",
2796  fac->u.DeactivationDiversion.Component.Invoke.Procedure,
2797  fac->u.DeactivationDiversion.Component.Invoke.BasicService);
2798  chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
2799  print_facility_ServedUserNr(3, &fac->u.DeactivationDiversion.Component.Invoke.ServedUser, bc);
2800  break;
2801  case FacComponent_Result:
2802  chan_misdn_log(1, bc->port, " --> Result\n");
2803  break;
2804  default:
2805  break;
2806  }
2807  break;
2808  case Fac_ActivationStatusNotificationDiv:
2809  chan_misdn_log(1, bc->port, " --> ActivationStatusNotificationDiv: InvokeID:%d Procedure:%d BasicService:%d\n",
2810  fac->u.ActivationStatusNotificationDiv.InvokeID,
2811  fac->u.ActivationStatusNotificationDiv.Procedure,
2812  fac->u.ActivationStatusNotificationDiv.BasicService);
2813  chan_misdn_log(1, bc->port, " --> ForwardedTo:\n");
2814  print_facility_Address(2, &fac->u.ActivationStatusNotificationDiv.ForwardedTo, bc);
2815  chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
2816  print_facility_ServedUserNr(2, &fac->u.ActivationStatusNotificationDiv.ServedUser, bc);
2817  break;
2818  case Fac_DeactivationStatusNotificationDiv:
2819  chan_misdn_log(1, bc->port, " --> DeactivationStatusNotificationDiv: InvokeID:%d Procedure:%d BasicService:%d\n",
2820  fac->u.DeactivationStatusNotificationDiv.InvokeID,
2821  fac->u.DeactivationStatusNotificationDiv.Procedure,
2822  fac->u.DeactivationStatusNotificationDiv.BasicService);
2823  chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
2824  print_facility_ServedUserNr(2, &fac->u.DeactivationStatusNotificationDiv.ServedUser, bc);
2825  break;
2826  case Fac_InterrogationDiversion:
2827  chan_misdn_log(1, bc->port, " --> InterrogationDiversion: InvokeID:%d\n",
2828  fac->u.InterrogationDiversion.InvokeID);
2829  switch (fac->u.InterrogationDiversion.ComponentType) {
2830  case FacComponent_Invoke:
2831  chan_misdn_log(1, bc->port, " --> Invoke: Procedure:%d BasicService:%d\n",
2832  fac->u.InterrogationDiversion.Component.Invoke.Procedure,
2833  fac->u.InterrogationDiversion.Component.Invoke.BasicService);
2834  chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
2835  print_facility_ServedUserNr(3, &fac->u.InterrogationDiversion.Component.Invoke.ServedUser, bc);
2836  break;
2837  case FacComponent_Result:
2838  chan_misdn_log(1, bc->port, " --> Result:\n");
2839  if (fac->u.InterrogationDiversion.Component.Result.NumRecords) {
2840  for (Index = 0; Index < fac->u.InterrogationDiversion.Component.Result.NumRecords; ++Index) {
2841  chan_misdn_log(1, bc->port, " --> IntResult[%d]:\n", Index);
2842  print_facility_IntResult(3, &fac->u.InterrogationDiversion.Component.Result.List[Index], bc);
2843  }
2844  }
2845  break;
2846  default:
2847  break;
2848  }
2849  break;
2850  case Fac_DiversionInformation:
2851  chan_misdn_log(1, bc->port, " --> DiversionInformation: InvokeID:%d Reason:%d BasicService:%d\n",
2852  fac->u.DiversionInformation.InvokeID,
2853  fac->u.DiversionInformation.DiversionReason,
2854  fac->u.DiversionInformation.BasicService);
2855  if (fac->u.DiversionInformation.ServedUserSubaddress.Length) {
2856  chan_misdn_log(1, bc->port, " --> ServedUserSubaddress:\n");
2857  print_facility_Subaddress(2, &fac->u.DiversionInformation.ServedUserSubaddress, bc);
2858  }
2859  if (fac->u.DiversionInformation.CallingAddressPresent) {
2860  chan_misdn_log(1, bc->port, " --> CallingAddress:\n");
2861  print_facility_PresentedAddressScreened(2, &fac->u.DiversionInformation.CallingAddress, bc);
2862  }
2863  if (fac->u.DiversionInformation.OriginalCalledPresent) {
2864  chan_misdn_log(1, bc->port, " --> OriginalCalledNr:\n");
2865  print_facility_PresentedNumberUnscreened(2, &fac->u.DiversionInformation.OriginalCalled, bc);
2866  }
2867  if (fac->u.DiversionInformation.LastDivertingPresent) {
2868  chan_misdn_log(1, bc->port, " --> LastDivertingNr:\n");
2869  print_facility_PresentedNumberUnscreened(2, &fac->u.DiversionInformation.LastDiverting, bc);
2870  }
2871  if (fac->u.DiversionInformation.LastDivertingReasonPresent) {
2872  chan_misdn_log(1, bc->port, " --> LastDivertingReason:%d\n", fac->u.DiversionInformation.LastDivertingReason);
2873  }
2874  if (fac->u.DiversionInformation.UserInfo.Length) {
2875  chan_misdn_log(1, bc->port, " --> UserInfo Length:%d\n", fac->u.DiversionInformation.UserInfo.Length);
2876  }
2877  break;
2878  case Fac_CallDeflection:
2879  chan_misdn_log(1, bc->port, " --> CallDeflection: InvokeID:%d\n",
2880  fac->u.CallDeflection.InvokeID);
2881  switch (fac->u.CallDeflection.ComponentType) {
2882  case FacComponent_Invoke:
2883  chan_misdn_log(1, bc->port, " --> Invoke:\n");
2884  if (fac->u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent) {
2885  chan_misdn_log(1, bc->port, " --> PresentationAllowed:%d\n",
2886  fac->u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser);
2887  }
2888  chan_misdn_log(1, bc->port, " --> DeflectionAddress:\n");
2889  print_facility_Address(3, &fac->u.CallDeflection.Component.Invoke.Deflection, bc);
2890  break;
2891  case FacComponent_Result:
2892  chan_misdn_log(1, bc->port, " --> Result\n");
2893  break;
2894  default:
2895  break;
2896  }
2897  break;
2898  case Fac_CallRerouteing:
2899  chan_misdn_log(1, bc->port, " --> CallRerouteing: InvokeID:%d\n",
2900  fac->u.CallRerouteing.InvokeID);
2901  switch (fac->u.CallRerouteing.ComponentType) {
2902  case FacComponent_Invoke:
2903  chan_misdn_log(1, bc->port, " --> Invoke: Reason:%d Counter:%d\n",
2904  fac->u.CallRerouteing.Component.Invoke.ReroutingReason,
2905  fac->u.CallRerouteing.Component.Invoke.ReroutingCounter);
2906  chan_misdn_log(1, bc->port, " --> CalledAddress:\n");
2907  print_facility_Address(3, &fac->u.CallRerouteing.Component.Invoke.CalledAddress, bc);
2908  print_facility_Q931_Bc_Hlc_Llc_Uu(2, &fac->u.CallRerouteing.Component.Invoke.Q931ie, bc);
2909  chan_misdn_log(1, bc->port, " --> LastReroutingNr:\n");
2910  print_facility_PresentedNumberUnscreened(3, &fac->u.CallRerouteing.Component.Invoke.LastRerouting, bc);
2911  chan_misdn_log(1, bc->port, " --> SubscriptionOption:%d\n",
2912  fac->u.CallRerouteing.Component.Invoke.SubscriptionOption);
2913  if (fac->u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length) {
2914  chan_misdn_log(1, bc->port, " --> CallingParty:\n");
2915  print_facility_Subaddress(3, &fac->u.CallRerouteing.Component.Invoke.CallingPartySubaddress, bc);
2916  }
2917  break;
2918  case FacComponent_Result:
2919  chan_misdn_log(1, bc->port, " --> Result\n");
2920  break;
2921  default:
2922  break;
2923  }
2924  break;
2925  case Fac_InterrogateServedUserNumbers:
2926  chan_misdn_log(1, bc->port, " --> InterrogateServedUserNumbers: InvokeID:%d\n",
2927  fac->u.InterrogateServedUserNumbers.InvokeID);
2928  switch (fac->u.InterrogateServedUserNumbers.ComponentType) {
2929  case FacComponent_Invoke:
2930  chan_misdn_log(1, bc->port, " --> Invoke\n");
2931  break;
2932  case FacComponent_Result:
2933  chan_misdn_log(1, bc->port, " --> Result:\n");
2934  if (fac->u.InterrogateServedUserNumbers.Component.Result.NumRecords) {
2935  for (Index = 0; Index < fac->u.InterrogateServedUserNumbers.Component.Result.NumRecords; ++Index) {
2936  chan_misdn_log(1, bc->port, " --> ServedUserNr[%d]:\n", Index);
2937  print_facility_PartyNumber(3, &fac->u.InterrogateServedUserNumbers.Component.Result.List[Index], bc);
2938  }
2939  }
2940  break;
2941  default:
2942  break;
2943  }
2944  break;
2945  case Fac_DivertingLegInformation1:
2946  chan_misdn_log(1, bc->port, " --> DivertingLegInformation1: InvokeID:%d Reason:%d SubscriptionOption:%d\n",
2947  fac->u.DivertingLegInformation1.InvokeID,
2948  fac->u.DivertingLegInformation1.DiversionReason,
2949  fac->u.DivertingLegInformation1.SubscriptionOption);
2950  if (fac->u.DivertingLegInformation1.DivertedToPresent) {
2951  chan_misdn_log(1, bc->port, " --> DivertedToNr:\n");
2952  print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation1.DivertedTo, bc);
2953  }
2954  break;
2955  case Fac_DivertingLegInformation2:
2956  chan_misdn_log(1, bc->port, " --> DivertingLegInformation2: InvokeID:%d Reason:%d Count:%d\n",
2957  fac->u.DivertingLegInformation2.InvokeID,
2958  fac->u.DivertingLegInformation2.DiversionReason,
2959  fac->u.DivertingLegInformation2.DiversionCounter);
2960  if (fac->u.DivertingLegInformation2.DivertingPresent) {
2961  chan_misdn_log(1, bc->port, " --> DivertingNr:\n");
2962  print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation2.Diverting, bc);
2963  }
2964  if (fac->u.DivertingLegInformation2.OriginalCalledPresent) {
2965  chan_misdn_log(1, bc->port, " --> OriginalCalledNr:\n");
2966  print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation2.OriginalCalled, bc);
2967  }
2968  break;
2969  case Fac_DivertingLegInformation3:
2970  chan_misdn_log(1, bc->port, " --> DivertingLegInformation3: InvokeID:%d PresentationAllowed:%d\n",
2971  fac->u.DivertingLegInformation3.InvokeID,
2972  fac->u.DivertingLegInformation3.PresentationAllowedIndicator);
2973  break;
2974 
2975 #else /* !defined(AST_MISDN_ENHANCEMENTS) */
2976 
2977  case Fac_CD:
2978  chan_misdn_log(1, bc->port, " --> calldeflect to: %s, presentable: %s\n", fac->u.CDeflection.DeflectedToNumber,
2979  fac->u.CDeflection.PresentationAllowed ? "yes" : "no");
2980  break;
2981 #endif /* !defined(AST_MISDN_ENHANCEMENTS) */
2982  case Fac_AOCDCurrency:
2983  if (fac->u.AOCDcur.chargeNotAvailable) {
2984  chan_misdn_log(1, bc->port, " --> AOCD currency: charge not available\n");
2985  } else if (fac->u.AOCDcur.freeOfCharge) {
2986  chan_misdn_log(1, bc->port, " --> AOCD currency: free of charge\n");
2987  } else if (fac->u.AOCDchu.billingId >= 0) {
2988  chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s billingId:%d\n",
2989  fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
2990  (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDcur.billingId);
2991  } else {
2992  chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s\n",
2993  fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
2994  (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total");
2995  }
2996  break;
2997  case Fac_AOCDChargingUnit:
2998  if (fac->u.AOCDchu.chargeNotAvailable) {
2999  chan_misdn_log(1, bc->port, " --> AOCD charging unit: charge not available\n");
3000  } else if (fac->u.AOCDchu.freeOfCharge) {
3001  chan_misdn_log(1, bc->port, " --> AOCD charging unit: free of charge\n");
3002  } else if (fac->u.AOCDchu.billingId >= 0) {
3003  chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d\n",
3004  fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDchu.billingId);
3005  } else {
3006  chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n",
3007  fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total");
3008  }
3009  break;
3010 #if defined(AST_MISDN_ENHANCEMENTS)
3011  case Fac_ERROR:
3012  chan_misdn_log(1, bc->port, " --> ERROR: InvokeID:%d, Code:0x%02x\n",
3013  fac->u.ERROR.invokeId, fac->u.ERROR.errorValue);
3014  break;
3015  case Fac_RESULT:
3016  chan_misdn_log(1, bc->port, " --> RESULT: InvokeID:%d\n",
3017  fac->u.RESULT.InvokeID);
3018  break;
3019  case Fac_REJECT:
3020  if (fac->u.REJECT.InvokeIDPresent) {
3021  chan_misdn_log(1, bc->port, " --> REJECT: InvokeID:%d, Code:0x%02x\n",
3022  fac->u.REJECT.InvokeID, fac->u.REJECT.Code);
3023  } else {
3024  chan_misdn_log(1, bc->port, " --> REJECT: Code:0x%02x\n",
3025  fac->u.REJECT.Code);
3026  }
3027  break;
3028  case Fac_EctExecute:
3029  chan_misdn_log(1, bc->port, " --> EctExecute: InvokeID:%d\n",
3030  fac->u.EctExecute.InvokeID);
3031  break;
3032  case Fac_ExplicitEctExecute:
3033  chan_misdn_log(1, bc->port, " --> ExplicitEctExecute: InvokeID:%d LinkID:%d\n",
3034  fac->u.ExplicitEctExecute.InvokeID,
3035  fac->u.ExplicitEctExecute.LinkID);
3036  break;
3037  case Fac_RequestSubaddress:
3038  chan_misdn_log(1, bc->port, " --> RequestSubaddress: InvokeID:%d\n",
3039  fac->u.RequestSubaddress.InvokeID);
3040  break;
3041  case Fac_SubaddressTransfer:
3042  chan_misdn_log(1, bc->port, " --> SubaddressTransfer: InvokeID:%d\n",
3043  fac->u.SubaddressTransfer.InvokeID);
3044  print_facility_Subaddress(1, &fac->u.SubaddressTransfer.Subaddress, bc);
3045  break;
3046  case Fac_EctLinkIdRequest:
3047  chan_misdn_log(1, bc->port, " --> EctLinkIdRequest: InvokeID:%d\n",
3048  fac->u.EctLinkIdRequest.InvokeID);
3049  switch (fac->u.EctLinkIdRequest.ComponentType) {
3050  case FacComponent_Invoke:
3051  chan_misdn_log(1, bc->port, " --> Invoke\n");
3052  break;
3053  case FacComponent_Result:
3054  chan_misdn_log(1, bc->port, " --> Result: LinkID:%d\n",
3055  fac->u.EctLinkIdRequest.Component.Result.LinkID);
3056  break;
3057  default:
3058  break;
3059  }
3060  break;
3061  case Fac_EctInform:
3062  chan_misdn_log(1, bc->port, " --> EctInform: InvokeID:%d Status:%d\n",
3063  fac->u.EctInform.InvokeID,
3064  fac->u.EctInform.Status);
3065  if (fac->u.EctInform.RedirectionPresent) {
3066  chan_misdn_log(1, bc->port, " --> Redirection Number\n");
3067  print_facility_PresentedNumberUnscreened(2, &fac->u.EctInform.Redirection, bc);
3068  }
3069  break;
3070  case Fac_EctLoopTest:
3071  chan_misdn_log(1, bc->port, " --> EctLoopTest: InvokeID:%d\n",
3072  fac->u.EctLoopTest.InvokeID);
3073  switch (fac->u.EctLoopTest.ComponentType) {
3074  case FacComponent_Invoke:
3075  chan_misdn_log(1, bc->port, " --> Invoke: CallTransferID:%d\n",
3076  fac->u.EctLoopTest.Component.Invoke.CallTransferID);
3077  break;
3078  case FacComponent_Result:
3079  chan_misdn_log(1, bc->port, " --> Result: LoopResult:%d\n",
3080  fac->u.EctLoopTest.Component.Result.LoopResult);
3081  break;
3082  default:
3083  break;
3084  }
3085  break;
3086  case Fac_StatusRequest:
3087  chan_misdn_log(1, bc->port, " --> StatusRequest: InvokeID:%d\n",
3088  fac->u.StatusRequest.InvokeID);
3089  switch (fac->u.StatusRequest.ComponentType) {
3090  case FacComponent_Invoke:
3091  chan_misdn_log(1, bc->port, " --> Invoke: Compatibility:%d\n",
3092  fac->u.StatusRequest.Component.Invoke.CompatibilityMode);
3093  break;
3094  case FacComponent_Result:
3095  chan_misdn_log(1, bc->port, " --> Result: Status:%d\n",
3096  fac->u.StatusRequest.Component.Result.Status);
3097  break;
3098  default:
3099  break;
3100  }
3101  break;
3102  case Fac_CallInfoRetain:
3103  chan_misdn_log(1, bc->port, " --> CallInfoRetain: InvokeID:%d, LinkageID:%d\n",
3104  fac->u.CallInfoRetain.InvokeID, fac->u.CallInfoRetain.CallLinkageID);
3105  break;
3106  case Fac_CCBSDeactivate:
3107  chan_misdn_log(1, bc->port, " --> CCBSDeactivate: InvokeID:%d\n",
3108  fac->u.CCBSDeactivate.InvokeID);
3109  switch (fac->u.CCBSDeactivate.ComponentType) {
3110  case FacComponent_Invoke:
3111  chan_misdn_log(1, bc->port, " --> Invoke: CCBSReference:%d\n",
3112  fac->u.CCBSDeactivate.Component.Invoke.CCBSReference);
3113  break;
3114  case FacComponent_Result:
3115  chan_misdn_log(1, bc->port, " --> Result\n");
3116  break;
3117  default:
3118  break;
3119  }
3120  break;
3121  case Fac_CCBSErase:
3122  chan_misdn_log(1, bc->port, " --> CCBSErase: InvokeID:%d, CCBSReference:%d RecallMode:%d, Reason:%d\n",
3123  fac->u.CCBSErase.InvokeID, fac->u.CCBSErase.CCBSReference,
3124  fac->u.CCBSErase.RecallMode, fac->u.CCBSErase.Reason);
3125  chan_misdn_log(1, bc->port, " --> AddressOfB\n");
3126  print_facility_Address(2, &fac->u.CCBSErase.AddressOfB, bc);
3127  print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSErase.Q931ie, bc);
3128  break;
3129  case Fac_CCBSRemoteUserFree:
3130  chan_misdn_log(1, bc->port, " --> CCBSRemoteUserFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
3131  fac->u.CCBSRemoteUserFree.InvokeID, fac->u.CCBSRemoteUserFree.CCBSReference,
3132  fac->u.CCBSRemoteUserFree.RecallMode);
3133  chan_misdn_log(1, bc->port, " --> AddressOfB\n");
3134  print_facility_Address(2, &fac->u.CCBSRemoteUserFree.AddressOfB, bc);
3135  print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSRemoteUserFree.Q931ie, bc);
3136  break;
3137  case Fac_CCBSCall:
3138  chan_misdn_log(1, bc->port, " --> CCBSCall: InvokeID:%d, CCBSReference:%d\n",
3139  fac->u.CCBSCall.InvokeID, fac->u.CCBSCall.CCBSReference);
3140  break;
3141  case Fac_CCBSStatusRequest:
3142  chan_misdn_log(1, bc->port, " --> CCBSStatusRequest: InvokeID:%d\n",
3143  fac->u.CCBSStatusRequest.InvokeID);
3144  switch (fac->u.CCBSStatusRequest.ComponentType) {
3145  case FacComponent_Invoke:
3146  chan_misdn_log(1, bc->port, " --> Invoke: CCBSReference:%d RecallMode:%d\n",
3147  fac->u.CCBSStatusRequest.Component.Invoke.CCBSReference,
3148  fac->u.CCBSStatusRequest.Component.Invoke.RecallMode);
3149  print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCBSStatusRequest.Component.Invoke.Q931ie, bc);
3150  break;
3151  case FacComponent_Result:
3152  chan_misdn_log(1, bc->port, " --> Result: Free:%d\n",
3153  fac->u.CCBSStatusRequest.Component.Result.Free);
3154  break;
3155  default:
3156  break;
3157  }
3158  break;
3159  case Fac_CCBSBFree:
3160  chan_misdn_log(1, bc->port, " --> CCBSBFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
3161  fac->u.CCBSBFree.InvokeID, fac->u.CCBSBFree.CCBSReference,
3162  fac->u.CCBSBFree.RecallMode);
3163  chan_misdn_log(1, bc->port, " --> AddressOfB\n");
3164  print_facility_Address(2, &fac->u.CCBSBFree.AddressOfB, bc);
3165  print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSBFree.Q931ie, bc);
3166  break;
3167  case Fac_EraseCallLinkageID:
3168  chan_misdn_log(1, bc->port, " --> EraseCallLinkageID: InvokeID:%d, LinkageID:%d\n",
3169  fac->u.EraseCallLinkageID.InvokeID, fac->u.EraseCallLinkageID.CallLinkageID);
3170  break;
3171  case Fac_CCBSStopAlerting:
3172  chan_misdn_log(1, bc->port, " --> CCBSStopAlerting: InvokeID:%d, CCBSReference:%d\n",
3173  fac->u.CCBSStopAlerting.InvokeID, fac->u.CCBSStopAlerting.CCBSReference);
3174  break;
3175  case Fac_CCBSRequest:
3176  chan_misdn_log(1, bc->port, " --> CCBSRequest: InvokeID:%d\n",
3177  fac->u.CCBSRequest.InvokeID);
3178  switch (fac->u.CCBSRequest.ComponentType) {
3179  case FacComponent_Invoke:
3180  chan_misdn_log(1, bc->port, " --> Invoke: LinkageID:%d\n",
3181  fac->u.CCBSRequest.Component.Invoke.CallLinkageID);
3182  break;
3183  case FacComponent_Result:
3184  chan_misdn_log(1, bc->port, " --> Result: CCBSReference:%d RecallMode:%d\n",
3185  fac->u.CCBSRequest.Component.Result.CCBSReference,
3186  fac->u.CCBSRequest.Component.Result.RecallMode);
3187  break;
3188  default:
3189  break;
3190  }
3191  break;
3192  case Fac_CCBSInterrogate:
3193  chan_misdn_log(1, bc->port, " --> CCBSInterrogate: InvokeID:%d\n",
3194  fac->u.CCBSInterrogate.InvokeID);
3195  switch (fac->u.CCBSInterrogate.ComponentType) {
3196  case FacComponent_Invoke:
3197  chan_misdn_log(1, bc->port, " --> Invoke\n");
3198  if (fac->u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent) {
3199  chan_misdn_log(1, bc->port, " --> CCBSReference:%d\n",
3200  fac->u.CCBSInterrogate.Component.Invoke.CCBSReference);
3201  }
3202  if (fac->u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber) {
3203  chan_misdn_log(1, bc->port, " --> AParty\n");
3204  print_facility_PartyNumber(3, &fac->u.CCBSInterrogate.Component.Invoke.AParty, bc);
3205  }
3206  break;
3207  case FacComponent_Result:
3208  chan_misdn_log(1, bc->port, " --> Result: RecallMode:%d\n",
3209  fac->u.CCBSInterrogate.Component.Result.RecallMode);
3210  if (fac->u.CCBSInterrogate.Component.Result.NumRecords) {
3211  for (Index = 0; Index < fac->u.CCBSInterrogate.Component.Result.NumRecords; ++Index) {
3212  chan_misdn_log(1, bc->port, " --> CallDetails[%d]:\n", Index);
3213  print_facility_CallInformation(3, &fac->u.CCBSInterrogate.Component.Result.CallDetails[Index], bc);
3214  }
3215  }
3216  break;
3217  default:
3218  break;
3219  }
3220  break;
3221  case Fac_CCNRRequest:
3222  chan_misdn_log(1, bc->port, " --> CCNRRequest: InvokeID:%d\n",
3223  fac->u.CCNRRequest.InvokeID);
3224  switch (fac->u.CCNRRequest.ComponentType) {
3225  case FacComponent_Invoke:
3226  chan_misdn_log(1, bc->port, " --> Invoke: LinkageID:%d\n",
3227  fac->u.CCNRRequest.Component.Invoke.CallLinkageID);
3228  break;
3229  case FacComponent_Result:
3230  chan_misdn_log(1, bc->port, " --> Result: CCBSReference:%d RecallMode:%d\n",
3231  fac->u.CCNRRequest.Component.Result.CCBSReference,
3232  fac->u.CCNRRequest.Component.Result.RecallMode);
3233  break;
3234  default:
3235  break;
3236  }
3237  break;
3238  case Fac_CCNRInterrogate:
3239  chan_misdn_log(1, bc->port, " --> CCNRInterrogate: InvokeID:%d\n",
3240  fac->u.CCNRInterrogate.InvokeID);
3241  switch (fac->u.CCNRInterrogate.ComponentType) {
3242  case FacComponent_Invoke:
3243  chan_misdn_log(1, bc->port, " --> Invoke\n");
3244  if (fac->u.CCNRInterrogate.Component.Invoke.CCBSReferencePresent) {
3245  chan_misdn_log(1, bc->port, " --> CCBSReference:%d\n",
3246  fac->u.CCNRInterrogate.Component.Invoke.CCBSReference);
3247  }
3248  if (fac->u.CCNRInterrogate.Component.Invoke.AParty.LengthOfNumber) {
3249  chan_misdn_log(1, bc->port, " --> AParty\n");
3250  print_facility_PartyNumber(3, &fac->u.CCNRInterrogate.Component.Invoke.AParty, bc);
3251  }
3252  break;
3253  case FacComponent_Result:
3254  chan_misdn_log(1, bc->port, " --> Result: RecallMode:%d\n",
3255  fac->u.CCNRInterrogate.Component.Result.RecallMode);
3256  if (fac->u.CCNRInterrogate.Component.Result.NumRecords) {
3257  for (Index = 0; Index < fac->u.CCNRInterrogate.Component.Result.NumRecords; ++Index) {
3258  chan_misdn_log(1, bc->port, " --> CallDetails[%d]:\n", Index);
3259  print_facility_CallInformation(3, &fac->u.CCNRInterrogate.Component.Result.CallDetails[Index], bc);
3260  }
3261  }
3262  break;
3263  default:
3264  break;
3265  }
3266  break;
3267  case Fac_CCBS_T_Call:
3268  chan_misdn_log(1, bc->port, " --> CCBS_T_Call: InvokeID:%d\n",
3269  fac->u.CCBS_T_Call.InvokeID);
3270  break;
3271  case Fac_CCBS_T_Suspend:
3272  chan_misdn_log(1, bc->port, " --> CCBS_T_Suspend: InvokeID:%d\n",
3273  fac->u.CCBS_T_Suspend.InvokeID);
3274  break;
3275  case Fac_CCBS_T_Resume:
3276  chan_misdn_log(1, bc->port, " --> CCBS_T_Resume: InvokeID:%d\n",
3277  fac->u.CCBS_T_Resume.InvokeID);
3278  break;
3279  case Fac_CCBS_T_RemoteUserFree:
3280  chan_misdn_log(1, bc->port, " --> CCBS_T_RemoteUserFree: InvokeID:%d\n",
3281  fac->u.CCBS_T_RemoteUserFree.InvokeID);
3282  break;
3283  case Fac_CCBS_T_Available:
3284  chan_misdn_log(1, bc->port, " --> CCBS_T_Available: InvokeID:%d\n",
3285  fac->u.CCBS_T_Available.InvokeID);
3286  break;
3287  case Fac_CCBS_T_Request:
3288  chan_misdn_log(1, bc->port, " --> CCBS_T_Request: InvokeID:%d\n",
3289  fac->u.CCBS_T_Request.InvokeID);
3290  switch (fac->u.CCBS_T_Request.ComponentType) {
3291  case FacComponent_Invoke:
3292  chan_misdn_log(1, bc->port, " --> Invoke\n");
3293  chan_misdn_log(1, bc->port, " --> DestinationAddress:\n");
3294  print_facility_Address(3, &fac->u.CCBS_T_Request.Component.Invoke.Destination, bc);
3295  print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCBS_T_Request.Component.Invoke.Q931ie, bc);
3296  if (fac->u.CCBS_T_Request.Component.Invoke.RetentionSupported) {
3297  chan_misdn_log(1, bc->port, " --> RetentionSupported:1\n");
3298  }
3299  if (fac->u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent) {
3300  chan_misdn_log(1, bc->port, " --> PresentationAllowed:%d\n",
3301  fac->u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator);
3302  }
3303  if (fac->u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber) {
3304  chan_misdn_log(1, bc->port, " --> OriginatingAddress:\n");
3305  print_facility_Address(3, &fac->u.CCBS_T_Request.Component.Invoke.Originating, bc);
3306  }
3307  break;
3308  case FacComponent_Result:
3309  chan_misdn_log(1, bc->port, " --> Result: RetentionSupported:%d\n",
3310  fac->u.CCBS_T_Request.Component.Result.RetentionSupported);
3311  break;
3312  default:
3313  break;
3314  }
3315  break;
3316  case Fac_CCNR_T_Request:
3317  chan_misdn_log(1, bc->port, " --> CCNR_T_Request: InvokeID:%d\n",
3318  fac->u.CCNR_T_Request.InvokeID);
3319  switch (fac->u.CCNR_T_Request.ComponentType) {
3320  case FacComponent_Invoke:
3321  chan_misdn_log(1, bc->port, " --> Invoke\n");
3322  chan_misdn_log(1, bc->port, " --> DestinationAddress:\n");
3323  print_facility_Address(3, &fac->u.CCNR_T_Request.Component.Invoke.Destination, bc);
3324  print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCNR_T_Request.Component.Invoke.Q931ie, bc);
3325  if (fac->u.CCNR_T_Request.Component.Invoke.RetentionSupported) {
3326  chan_misdn_log(1, bc->port, " --> RetentionSupported:1\n");
3327  }
3328  if (fac->u.CCNR_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent) {
3329  chan_misdn_log(1, bc->port, " --> PresentationAllowed:%d\n",
3330  fac->u.CCNR_T_Request.Component.Invoke.PresentationAllowedIndicator);
3331  }
3332  if (fac->u.CCNR_T_Request.Component.Invoke.Originating.Party.LengthOfNumber) {
3333  chan_misdn_log(1, bc->port, " --> OriginatingAddress:\n");
3334  print_facility_Address(3, &fac->u.CCNR_T_Request.Component.Invoke.Originating, bc);
3335  }
3336  break;
3337  case FacComponent_Result:
3338  chan_misdn_log(1, bc->port, " --> Result: RetentionSupported:%d\n",
3339  fac->u.CCNR_T_Request.Component.Result.RetentionSupported);
3340  break;
3341  default:
3342  break;
3343  }
3344  break;
3345 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
3346  case Fac_None:
3347  /* No facility so print nothing */
3348  break;
3349  default:
3350  chan_misdn_log(1, bc->port, " --> unknown facility\n");
3351  break;
3352  }
3353 }
3354 
3355 static void print_bearer(struct misdn_bchannel *bc)
3356 {
3357  chan_misdn_log(2, bc->port, " --> Bearer: %s\n", bearer2str(bc->capability));
3358 
3359  switch(bc->law) {
3360  case INFO_CODEC_ALAW:
3361  chan_misdn_log(2, bc->port, " --> Codec: Alaw\n");
3362  break;
3363  case INFO_CODEC_ULAW:
3364  chan_misdn_log(2, bc->port, " --> Codec: Ulaw\n");
3365  break;
3366  }
3367 }
3368 
3369 /*!
3370  * \internal
3371  * \brief Prefix a string to another string in place.
3372  *
3373  * \param str_prefix String to prefix to the main string.
3374  * \param str_main String to get the prefix added to it.
3375  * \param size Buffer size of the main string (Includes null terminator).
3376  *
3377  * \note The str_main buffer size must be greater than one.
3378  *
3379  * \return Nothing
3380  */
3381 static void misdn_prefix_string(const char *str_prefix, char *str_main, size_t size)
3382 {
3383  size_t len_over;
3384  size_t len_total;
3385  size_t len_main;
3386  size_t len_prefix;
3387 
3388  len_prefix = strlen(str_prefix);
3389  if (!len_prefix) {
3390  /* There is no prefix to prepend. */
3391  return;
3392  }
3393  len_main = strlen(str_main);
3394  len_total = len_prefix + len_main;
3395  if (size <= len_total) {
3396  /* We need to truncate since the buffer is too small. */
3397  len_over = len_total + 1 - size;
3398  if (len_over <= len_main) {
3399  len_main -= len_over;
3400  } else {
3401  len_over -= len_main;
3402  len_main = 0;
3403  len_prefix -= len_over;
3404  }
3405  }
3406  if (len_main) {
3407  memmove(str_main + len_prefix, str_main, len_main);
3408  }
3409  memcpy(str_main, str_prefix, len_prefix);
3410  str_main[len_prefix + len_main] = '\0';
3411 }
3412 
3413 /*!
3414  * \internal
3415  * \brief Add a configured prefix to the given number.
3416  *
3417  * \param port Logical port number
3418  * \param number_type Type-of-number passed in.
3419  * \param number Given number string to add prefix
3420  * \param size Buffer size number string occupies.
3421  *
3422  * \return Nothing
3423  */
3424 static void misdn_add_number_prefix(int port, enum mISDN_NUMBER_TYPE number_type, char *number, size_t size)
3425 {
3426  enum misdn_cfg_elements type_prefix;
3427  char num_prefix[MISDN_MAX_NUMBER_LEN];
3428 
3429  /* Get prefix string. */
3430  switch (number_type) {
3431  case NUMTYPE_UNKNOWN:
3432  type_prefix = MISDN_CFG_TON_PREFIX_UNKNOWN;
3433  break;
3434  case NUMTYPE_INTERNATIONAL:
3435  type_prefix = MISDN_CFG_TON_PREFIX_INTERNATIONAL;
3436  break;
3437  case NUMTYPE_NATIONAL:
3438  type_prefix = MISDN_CFG_TON_PREFIX_NATIONAL;
3439  break;
3442  break;
3443  case NUMTYPE_SUBSCRIBER:
3444  type_prefix = MISDN_CFG_TON_PREFIX_SUBSCRIBER;
3445  break;
3446  case NUMTYPE_ABBREVIATED:
3447  type_prefix = MISDN_CFG_TON_PREFIX_ABBREVIATED;
3448  break;
3449  default:
3450  /* Type-of-number does not have a prefix that can be added. */
3451  return;
3452  }
3453  misdn_cfg_get(port, type_prefix, num_prefix, sizeof(num_prefix));
3454 
3455  misdn_prefix_string(num_prefix, number, size);
3456 }
3457 
3458 static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc)
3459 {
3460  RAII_VAR(struct ast_channel *, chan, NULL, ast_channel_cleanup);
3461  char buf[128];
3462 
3463  if (!bc->AOCD_need_export || !ast) {
3464  return;
3465  }
3466 
3467  if (originator == ORG_AST) {
3468  chan = ast_channel_bridge_peer(ast);
3469  if (!chan) {
3470  return;
3471  }
3472  } else {
3473  chan = ast_channel_ref(ast);
3474  }
3475 
3476  switch (bc->AOCDtype) {
3477  case Fac_AOCDCurrency:
3478  pbx_builtin_setvar_helper(chan, "AOCD_Type", "currency");
3479  if (bc->AOCD.currency.chargeNotAvailable) {
3480  pbx_builtin_setvar_helper(chan, "AOCD_ChargeAvailable", "no");
3481  } else {
3482  pbx_builtin_setvar_helper(chan, "AOCD_ChargeAvailable", "yes");
3483  if (bc->AOCD.currency.freeOfCharge) {
3484  pbx_builtin_setvar_helper(chan, "AOCD_FreeOfCharge", "yes");
3485  } else {
3486  pbx_builtin_setvar_helper(chan, "AOCD_FreeOfCharge", "no");
3487  if (snprintf(buf, sizeof(buf), "%d %s", bc->AOCD.currency.currencyAmount * bc->AOCD.currency.multiplier, bc->AOCD.currency.currency) < sizeof(buf)) {
3488  pbx_builtin_setvar_helper(chan, "AOCD_Amount", buf);
3489  if (bc->AOCD.currency.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.currency.billingId) < sizeof(buf)) {
3490  pbx_builtin_setvar_helper(chan, "AOCD_BillingId", buf);
3491  }
3492  }
3493  }
3494  }
3495  break;
3496  case Fac_AOCDChargingUnit:
3497  pbx_builtin_setvar_helper(chan, "AOCD_Type", "charging_unit");
3498  if (bc->AOCD.chargingUnit.chargeNotAvailable) {
3499  pbx_builtin_setvar_helper(chan, "AOCD_ChargeAvailable", "no");
3500  } else {
3501  pbx_builtin_setvar_helper(chan, "AOCD_ChargeAvailable", "yes");
3502  if (bc->AOCD.chargingUnit.freeOfCharge) {
3503  pbx_builtin_setvar_helper(chan, "AOCD_FreeOfCharge", "yes");
3504  } else {
3505  pbx_builtin_setvar_helper(chan, "AOCD_FreeOfCharge", "no");
3506  if (snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.recordedUnits) < sizeof(buf)) {
3507  pbx_builtin_setvar_helper(chan, "AOCD_RecordedUnits", buf);
3508  if (bc->AOCD.chargingUnit.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.billingId) < sizeof(buf)) {
3509  pbx_builtin_setvar_helper(chan, "AOCD_BillingId", buf);
3510  }
3511  }
3512  }
3513  }
3514  break;
3515  default:
3516  break;
3517  }
3518 
3519  bc->AOCD_need_export = 0;
3520 }
3521 
3522 /*************** Helpers END *************/
3523 
3524 static void sighandler(int sig)
3525 {
3526 }
3527 
3528 static void *misdn_tasks_thread_func(void *data)
3529 {
3530  int wait;
3531  struct sigaction sa;
3532 
3533  sa.sa_handler = sighandler;
3534  sa.sa_flags = SA_NODEFER;
3535  sigemptyset(&sa.sa_mask);
3536  sigaddset(&sa.sa_mask, SIGUSR1);
3537  sigaction(SIGUSR1, &sa, NULL);
3538 
3539  sem_post((sem_t *)data);
3540 
3541  while (1) {
3542  wait = ast_sched_wait(misdn_tasks);
3543  if (wait < 0) {
3544  wait = 8000;
3545  }
3546  if (poll(NULL, 0, wait) < 0) {
3547  chan_misdn_log(4, 0, "Waking up misdn_tasks thread\n");
3548  }
3549  ast_sched_runq(misdn_tasks);
3550  }
3551  return NULL;
3552 }
3553 
3554 static void misdn_tasks_init(void)
3555 {
3556  sem_t blocker;
3557  int i = 5;
3558 
3559  if (sem_init(&blocker, 0, 0)) {
3560  perror("chan_misdn: Failed to initialize semaphore!");
3561  exit(1);
3562  }
3563 
3564  chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
3565 
3566  misdn_tasks = ast_sched_context_create();
3568 
3569  while (sem_wait(&blocker) && --i) {
3570  }
3571  sem_destroy(&blocker);
3572 }
3573 
3574 static void misdn_tasks_destroy(void)
3575 {
3576  if (misdn_tasks) {
3577  chan_misdn_log(4, 0, "Killing misdn_tasks thread\n");
3578  if (pthread_cancel(misdn_tasks_thread) == 0) {
3579  cb_log(4, 0, "Joining misdn_tasks thread\n");
3580  pthread_join(misdn_tasks_thread, NULL);
3581  }
3582  ast_sched_context_destroy(misdn_tasks);
3583  }
3584 }
3585 
3586 static inline void misdn_tasks_wakeup(void)
3587 {
3588  pthread_kill(misdn_tasks_thread, SIGUSR1);
3589 }
3590 
3591 static inline int _misdn_tasks_add_variable(int timeout, ast_sched_cb callback, const void *data, int variable)
3592 {
3593  int task_id;
3594 
3595  if (!misdn_tasks) {
3596  misdn_tasks_init();
3597  }
3598  task_id = ast_sched_add_variable(misdn_tasks, timeout, callback, data, variable);
3600 
3601  return task_id;
3602 }
3603 
3604 static int misdn_tasks_add(int timeout, ast_sched_cb callback, const void *data)
3605 {
3606  return _misdn_tasks_add_variable(timeout, callback, data, 0);
3607 }
3608 
3609 static int misdn_tasks_add_variable(int timeout, ast_sched_cb callback, const void *data)
3610 {
3611  return _misdn_tasks_add_variable(timeout, callback, data, 1);
3612 }
3613 
3614 static void misdn_tasks_remove(int task_id)
3615 {
3616  AST_SCHED_DEL(misdn_tasks, task_id);
3617 }
3618 
3619 static int misdn_l1_task(const void *vdata)
3620 {
3621  const int *data = vdata;
3622 
3623  misdn_lib_isdn_l1watcher(*data);
3624  chan_misdn_log(5, *data, "L1watcher timeout\n");
3625  return 1;
3626 }
3627 
3628 static int misdn_overlap_dial_task(const void *data)
3629 {
3630  struct timeval tv_end, tv_now;
3631  int diff;
3632  struct chan_list *ch = (struct chan_list *) data;
3633  char *dad;
3634 
3635  chan_misdn_log(4, ch->bc->port, "overlap dial task, chan_state: %d\n", ch->state);
3636 
3637  if (ch->state != MISDN_WAITING4DIGS) {
3638  ch->overlap_dial_task = -1;
3639  return 0;
3640  }
3641 
3643  tv_end = ch->overlap_tv;
3645 
3646  tv_end.tv_sec += ch->overlap_dial;
3647  tv_now = ast_tvnow();
3648 
3649  diff = ast_tvdiff_ms(tv_end, tv_now);
3650  if (100 < diff) {
3651  return diff;
3652  }
3653 
3654  /* if we are 100ms near the timeout, we are satisfied.. */
3655  stop_indicate(ch);
3656 
3657  if (ast_strlen_zero(ch->bc->dialed.number)) {
3658  dad = "s";
3659  ast_channel_exten_set(ch->ast, dad);
3660  } else {
3661  dad = ch->bc->dialed.number;
3662  }
3663 
3664  if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->caller.number)) {
3665  ch->state = MISDN_DIALING;
3666  if (pbx_start_chan(ch) < 0) {
3667  chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
3668  goto misdn_overlap_dial_task_disconnect;
3669  }
3670  } else {
3671 misdn_overlap_dial_task_disconnect:
3672  hanguptone_indicate(ch);
3674  ch->state = MISDN_CLEANING;
3676  }
3677  ch->overlap_dial_task = -1;
3678  return 0;
3679 }
3680 
3681 static void send_digit_to_chan(struct chan_list *cl, char digit)
3682 {
3683  static const char * const dtmf_tones[] = {
3684 /* *INDENT-OFF* */
3685  "!941+1336/100,!0/100", /* 0 */
3686  "!697+1209/100,!0/100", /* 1 */
3687  "!697+1336/100,!0/100", /* 2 */
3688  "!697+1477/100,!0/100", /* 3 */
3689  "!770+1209/100,!0/100", /* 4 */
3690  "!770+1336/100,!0/100", /* 5 */
3691  "!770+1477/100,!0/100", /* 6 */
3692  "!852+1209/100,!0/100", /* 7 */
3693  "!852+1336/100,!0/100", /* 8 */
3694  "!852+1477/100,!0/100", /* 9 */
3695  "!697+1633/100,!0/100", /* A */
3696  "!770+1633/100,!0/100", /* B */
3697  "!852+1633/100,!0/100", /* C */
3698  "!941+1633/100,!0/100", /* D */
3699  "!941+1209/100,!0/100", /* * */
3700  "!941+1477/100,!0/100", /* # */
3701 /* *INDENT-ON* */
3702  };
3703  struct ast_channel *chan = cl->ast;
3704 
3705  if (digit >= '0' && digit <='9') {
3706  ast_playtones_start(chan, 0, dtmf_tones[digit - '0'], 0);
3707  } else if (digit >= 'A' && digit <= 'D') {
3708  ast_playtones_start(chan, 0, dtmf_tones[digit - 'A' + 10], 0);
3709  } else if (digit == '*') {
3710  ast_playtones_start(chan, 0, dtmf_tones[14], 0);
3711  } else if (digit == '#') {
3712  ast_playtones_start(chan, 0, dtmf_tones[15], 0);
3713  } else {
3714  /* not handled */
3715  ast_debug(1, "Unable to handle DTMF tone '%c' for '%s'\n", digit, ast_channel_name(chan));
3716  }
3717 }
3718 
3719 /*** CLI HANDLING ***/
3720 static char *handle_cli_misdn_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3721 {
3722  int level;
3723 
3724  switch (cmd) {
3725  case CLI_INIT:
3726  e->command = "misdn set debug [on|off]";
3727  e->usage =
3728  "Usage: misdn set debug {on|off|<level>} [only] | [port <port> [only]]\n"
3729  " Set the debug level of the mISDN channel.\n";
3730  return NULL;
3731  case CLI_GENERATE:
3732  return complete_debug_port(a);
3733  }
3734 
3735  if (a->argc < 4 || a->argc > 7) {
3736  return CLI_SHOWUSAGE;
3737  }
3738 
3739  if (!strcasecmp(a->argv[3], "on")) {
3740  level = 1;
3741  } else if (!strcasecmp(a->argv[3], "off")) {
3742  level = 0;
3743  } else if (isdigit(a->argv[3][0])) {
3744  level = atoi(a->argv[3]);
3745  } else {
3746  return CLI_SHOWUSAGE;
3747  }
3748 
3749  switch (a->argc) {
3750  case 4:
3751  case 5:
3752  {
3753  int i;
3754  int only = 0;
3755  if (a->argc == 5) {
3756  if (strncasecmp(a->argv[4], "only", strlen(a->argv[4]))) {
3757  return CLI_SHOWUSAGE;
3758  } else {
3759  only = 1;
3760  }
3761  }
3762 
3763  for (i = 0; i <= max_ports; i++) {
3764  misdn_debug[i] = level;
3765  misdn_debug_only[i] = only;
3766  }
3767  ast_cli(a->fd, "changing debug level for all ports to %d%s\n", misdn_debug[0], only ? " (only)" : "");
3768  }
3769  break;
3770  case 6:
3771  case 7:
3772  {
3773  int port;
3774  if (strncasecmp(a->argv[4], "port", strlen(a->argv[4])))
3775  return CLI_SHOWUSAGE;
3776  port = atoi(a->argv[5]);
3777  if (port <= 0 || port > max_ports) {
3778  switch (max_ports) {
3779  case 0:
3780  ast_cli(a->fd, "port number not valid! no ports available so you won't get lucky with any number here...\n");
3781  break;
3782  case 1:
3783  ast_cli(a->fd, "port number not valid! only port 1 is available.\n");
3784  break;
3785  default:
3786  ast_cli(a->fd, "port number not valid! only ports 1 to %d are available.\n", max_ports);
3787  }
3788  return 0;
3789  }
3790  if (a->argc == 7) {
3791  if (strncasecmp(a->argv[6], "only", strlen(a->argv[6]))) {
3792  return CLI_SHOWUSAGE;
3793  } else {
3794  misdn_debug_only[port] = 1;
3795  }
3796  } else {
3797  misdn_debug_only[port] = 0;
3798  }
3799  misdn_debug[port] = level;
3800  ast_cli(a->fd, "changing debug level to %d%s for port %d\n", misdn_debug[port], misdn_debug_only[port] ? " (only)" : "", port);
3801  }
3802  }
3803 
3804  return CLI_SUCCESS;
3805 }
3806 
3807 static char *handle_cli_misdn_set_crypt_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3808 {
3809  switch (cmd) {
3810  case CLI_INIT:
3811  e->command = "misdn set crypt debug";
3812  e->usage =
3813  "Usage: misdn set crypt debug <level>\n"
3814  " Set the crypt debug level of the mISDN channel. Level\n"
3815  " must be 1 or 2.\n";
3816  return NULL;
3817  case CLI_GENERATE:
3818  return NULL;
3819  }
3820 
3821  if (a->argc != 5) {
3822  return CLI_SHOWUSAGE;
3823  }
3824 
3825  /* XXX Is this supposed to not do anything? XXX */
3826 
3827  return CLI_SUCCESS;
3828 }
3829 
3830 static char *handle_cli_misdn_port_block(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3831 {
3832  switch (cmd) {
3833  case CLI_INIT:
3834  e->command = "misdn port block";
3835  e->usage =
3836  "Usage: misdn port block <port>\n"
3837  " Block the specified port by <port>.\n";
3838  return NULL;
3839  case CLI_GENERATE:
3840  return NULL;
3841  }
3842 
3843  if (a->argc != 4) {
3844  return CLI_SHOWUSAGE;
3845  }
3846 
3847  misdn_lib_port_block(atoi(a->argv[3]));
3848 
3849  return CLI_SUCCESS;
3850 }
3851 
3852 static char *handle_cli_misdn_port_unblock(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3853 {
3854  switch (cmd) {
3855  case CLI_INIT:
3856  e->command = "misdn port unblock";
3857  e->usage =
3858  "Usage: misdn port unblock <port>\n"
3859  " Unblock the port specified by <port>.\n";
3860  return NULL;
3861  case CLI_GENERATE:
3862  return NULL;
3863  }
3864 
3865  if (a->argc != 4) {
3866  return CLI_SHOWUSAGE;
3867  }
3868 
3869  misdn_lib_port_unblock(atoi(a->argv[3]));
3870 
3871  return CLI_SUCCESS;
3872 }
3873 
3874 static char *handle_cli_misdn_restart_port(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3875 {
3876  switch (cmd) {
3877  case CLI_INIT:
3878  e->command = "misdn restart port";
3879  e->usage =
3880  "Usage: misdn restart port <port>\n"
3881  " Restart the given port.\n";
3882  return NULL;
3883  case CLI_GENERATE:
3884  return NULL;
3885  }
3886 
3887  if (a->argc != 4) {
3888  return CLI_SHOWUSAGE;
3889  }
3890 
3891  misdn_lib_port_restart(atoi(a->argv[3]));
3892 
3893  return CLI_SUCCESS;
3894 }
3895 
3896 static char *handle_cli_misdn_restart_pid(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3897 {
3898  switch (cmd) {
3899  case CLI_INIT:
3900  e->command = "misdn restart pid";
3901  e->usage =
3902  "Usage: misdn restart pid <pid>\n"
3903  " Restart the given pid\n";
3904  return NULL;
3905  case CLI_GENERATE:
3906  return NULL;
3907  }
3908 
3909  if (a->argc != 4) {
3910  return CLI_SHOWUSAGE;
3911  }
3912 
3913  misdn_lib_pid_restart(atoi(a->argv[3]));
3914 
3915  return CLI_SUCCESS;
3916 }
3917 
3918 static char *handle_cli_misdn_port_up(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3919 {
3920  switch (cmd) {
3921  case CLI_INIT:
3922  e->command = "misdn port up";
3923  e->usage =
3924  "Usage: misdn port up <port>\n"
3925  " Try to establish L1 on the given port.\n";
3926  return NULL;
3927  case CLI_GENERATE:
3928  return NULL;
3929  }
3930 
3931  if (a->argc != 4) {
3932  return CLI_SHOWUSAGE;
3933  }
3934 
3935  misdn_lib_get_port_up(atoi(a->argv[3]));
3936 
3937  return CLI_SUCCESS;
3938 }
3939 
3940 static char *handle_cli_misdn_port_down(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3941 {
3942  switch (cmd) {
3943  case CLI_INIT:
3944  e->command = "misdn port down";
3945  e->usage =
3946  "Usage: misdn port down <port>\n"
3947  " Try to deactivate the L1 on the given port.\n";
3948  return NULL;
3949  case CLI_GENERATE:
3950  return NULL;
3951  }
3952 
3953  if (a->argc != 4) {
3954  return CLI_SHOWUSAGE;
3955  }
3956 
3957  misdn_lib_get_port_down(atoi(a->argv[3]));
3958 
3959  return CLI_SUCCESS;
3960 }
3961 
3962 static inline void show_config_description(int fd, enum misdn_cfg_elements elem)
3963 {
3964  char section[BUFFERSIZE];
3965  char name[BUFFERSIZE];
3966  char desc[BUFFERSIZE];
3967  char def[BUFFERSIZE];
3968  char tmp[BUFFERSIZE];
3969 
3970  misdn_cfg_get_name(elem, tmp, sizeof(tmp));
3971  term_color(name, tmp, COLOR_BRWHITE, 0, sizeof(tmp));
3972  misdn_cfg_get_desc(elem, desc, sizeof(desc), def, sizeof(def));
3973 
3974  if (elem < MISDN_CFG_LAST) {
3975  term_color(section, "PORTS SECTION", COLOR_YELLOW, 0, sizeof(section));
3976  } else {
3977  term_color(section, "GENERAL SECTION", COLOR_YELLOW, 0, sizeof(section));
3978  }
3979 
3980  if (*def) {
3981  ast_cli(fd, "[%s] %s (Default: %s)\n\t%s\n", section, name, def, desc);
3982  } else {
3983  ast_cli(fd, "[%s] %s\n\t%s\n", section, name, desc);
3984  }
3985 }
3986 
3987 static char *handle_cli_misdn_show_config(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3988 {
3989  char buffer[BUFFERSIZE];
3990  enum misdn_cfg_elements elem;
3991  int linebreak;
3992  int onlyport = -1;
3993  int ok = 0;
3994 
3995  switch (cmd) {
3996  case CLI_INIT:
3997  e->command = "misdn show config";
3998  e->usage =
3999  "Usage: misdn show config [<port> | description <config element> | descriptions [general|ports]]\n"
4000  " Use 0 for <port> to only print the general config.\n";
4001  return NULL;
4002  case CLI_GENERATE:
4003  return complete_show_config(a);
4004  }
4005 
4006  if (a->argc >= 4) {
4007  if (!strcmp(a->argv[3], "description")) {
4008  if (a->argc == 5) {
4009  enum misdn_cfg_elements elem = misdn_cfg_get_elem(a->argv[4]);
4010  if (elem == MISDN_CFG_FIRST) {
4011  ast_cli(a->fd, "Unknown element: %s\n", a->argv[4]);
4012  } else {
4013  show_config_description(a->fd, elem);
4014  }
4015  return CLI_SUCCESS;
4016  }
4017  return CLI_SHOWUSAGE;
4018  } else if (!strcmp(a->argv[3], "descriptions")) {
4019  if ((a->argc == 4) || ((a->argc == 5) && !strcmp(a->argv[4], "general"))) {
4020  for (elem = MISDN_GEN_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) {
4021  show_config_description(a->fd, elem);
4022  ast_cli(a->fd, "\n");
4023  }
4024  ok = 1;
4025  }
4026  if ((a->argc == 4) || ((a->argc == 5) && !strcmp(a->argv[4], "ports"))) {
4027  for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_CFG_LAST - 1 /* the ptp hack, remove the -1 when ptp is gone */; ++elem) {
4028  show_config_description(a->fd, elem);
4029  ast_cli(a->fd, "\n");
4030  }
4031  ok = 1;
4032  }
4033  return ok ? CLI_SUCCESS : CLI_SHOWUSAGE;
4034  } else if (!sscanf(a->argv[3], "%5d", &onlyport) || onlyport < 0) {
4035  ast_cli(a->fd, "Unknown option: %s\n", a->argv[3]);
4036  return CLI_SHOWUSAGE;
4037  }
4038  }
4039 
4040  if (a->argc == 3 || onlyport == 0) {
4041  ast_cli(a->fd, "mISDN General-Config:\n");
4042  for (elem = MISDN_GEN_FIRST + 1, linebreak = 1; elem < MISDN_GEN_LAST; elem++, linebreak++) {
4043  misdn_cfg_get_config_string(0, elem, buffer, sizeof(buffer));
4044  ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
4045  }
4046  ast_cli(a->fd, "\n");
4047  }
4048 
4049  if (onlyport < 0) {
4050  int port = misdn_cfg_get_next_port(0);
4051 
4052  for (; port > 0; port = misdn_cfg_get_next_port(port)) {
4053  ast_cli(a->fd, "\n[PORT %d]\n", port);
4054  for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
4055  misdn_cfg_get_config_string(port, elem, buffer, sizeof(buffer));
4056  ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
4057  }
4058  ast_cli(a->fd, "\n");
4059  }
4060  }
4061 
4062  if (onlyport > 0) {
4063  if (misdn_cfg_is_port_valid(onlyport)) {
4064  ast_cli(a->fd, "[PORT %d]\n", onlyport);
4065  for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
4066  misdn_cfg_get_config_string(onlyport, elem, buffer, sizeof(buffer));
4067  ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
4068  }
4069  ast_cli(a->fd, "\n");
4070  } else {
4071  ast_cli(a->fd, "Port %d is not active!\n", onlyport);
4072  }
4073  }
4074 
4075  return CLI_SUCCESS;
4076 }
4077 
4080  char txt[255];
4081 };
4082 
4083 static const struct state_struct state_array[] = {
4084 /* *INDENT-OFF* */
4085  { MISDN_NOTHING, "NOTHING" }, /* at beginning */
4086  { MISDN_WAITING4DIGS, "WAITING4DIGS" }, /* when waiting for infos */
4087  { MISDN_EXTCANTMATCH, "EXTCANTMATCH" }, /* when asterisk couldn't match our ext */
4088  { MISDN_INCOMING_SETUP, "INCOMING SETUP" }, /* when pbx_start */
4089  { MISDN_DIALING, "DIALING" }, /* when pbx_start */
4090  { MISDN_PROGRESS, "PROGRESS" }, /* when pbx_start */
4091  { MISDN_PROCEEDING, "PROCEEDING" }, /* when pbx_start */
4092  { MISDN_CALLING, "CALLING" }, /* when misdn_call is called */
4093  { MISDN_CALLING_ACKNOWLEDGE, "CALLING_ACKNOWLEDGE" }, /* when misdn_call is called */
4094  { MISDN_ALERTING, "ALERTING" }, /* when Alerting */
4095  { MISDN_BUSY, "BUSY" }, /* when BUSY */
4096  { MISDN_CONNECTED, "CONNECTED" }, /* when connected */
4097  { MISDN_DISCONNECTED, "DISCONNECTED" }, /* when connected */
4098  { MISDN_CLEANING, "CLEANING" }, /* when hangup from * but we were connected before */
4099 /* *INDENT-ON* */
4100 };
4101 
4102 static const char *misdn_get_ch_state(struct chan_list *p)
4103 {
4104  int i;
4105  static char state[8];
4106 
4107  if (!p) {
4108  return NULL;
4109  }
4110 
4111  for (i = 0; i < ARRAY_LEN(state_array); i++) {
4112  if (state_array[i].state == p->state) {
4113  return state_array[i].txt;
4114  }
4115  }
4116 
4117  snprintf(state, sizeof(state), "%d", p->state) ;
4118 
4119  return state;
4120 }
4121 
4122 
4123 static void reload_config(void)
4124 {
4125  int i, cfg_debug;
4126 
4127  if (!g_config_initialized) {
4128  ast_log(LOG_WARNING, "chan_misdn is not initialized properly, still reloading ?\n");
4129  return ;
4130  }
4131 
4132  free_robin_list();
4133  misdn_cfg_reload();
4136  misdn_cfg_get(0, MISDN_GEN_DEBUG, &cfg_debug, sizeof(cfg_debug));
4137 
4138  for (i = 0; i <= max_ports; i++) {
4139  misdn_debug[i] = cfg_debug;
4140  misdn_debug_only[i] = 0;
4141  }
4142 }
4143 
4144 static char *handle_cli_misdn_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4145 {
4146  switch (cmd) {
4147  case CLI_INIT:
4148  e->command = "misdn reload";
4149  e->usage =
4150  "Usage: misdn reload\n"
4151  " Reload internal mISDN config, read from the config\n"
4152  " file.\n";
4153  return NULL;
4154  case CLI_GENERATE:
4155  return NULL;
4156  }
4157 
4158  if (a->argc != 2) {
4159  return CLI_SHOWUSAGE;
4160  }
4161 
4162  ast_cli(a->fd, "Reloading mISDN configuration\n");
4163  reload_config();
4164  return CLI_SUCCESS;
4165 }
4166 
4167 static void print_bc_info(int fd, struct chan_list *help, struct misdn_bchannel *bc)
4168 {
4169  struct ast_channel *ast = help->ast;
4170 
4171  ast_cli(fd,
4172  "* Pid:%d Port:%d Ch:%d Mode:%s Orig:%s dialed:%s\n"
4173  " --> caller:\"%s\" <%s>\n"
4174  " --> redirecting-from:\"%s\" <%s>\n"
4175  " --> redirecting-to:\"%s\" <%s>\n"
4176  " --> context:%s state:%s\n",
4177  bc->pid,
4178  bc->port,
4179  bc->channel,
4180  bc->nt ? "NT" : "TE",
4181  help->originator == ORG_AST ? "*" : "I",
4182  ast ? ast_channel_exten(ast) : "",
4183  (ast && ast_channel_caller(ast)->id.name.valid && ast_channel_caller(ast)->id.name.str)
4184  ? ast_channel_caller(ast)->id.name.str : "",
4185  (ast && ast_channel_caller(ast)->id.number.valid && ast_channel_caller(ast)->id.number.str)
4186  ? ast_channel_caller(ast)->id.number.str : "",
4187  bc->redirecting.from.name,
4188  bc->redirecting.from.number,
4189  bc->redirecting.to.name,
4190  bc->redirecting.to.number,
4191  ast ? ast_channel_context(ast) : "",
4192  misdn_get_ch_state(help));
4193  if (misdn_debug[bc->port] > 0) {
4194  ast_cli(fd,
4195  " --> astname: %s\n"
4196  " --> ch_l3id: %x\n"
4197  " --> ch_addr: %x\n"
4198  " --> bc_addr: %x\n"
4199  " --> bc_l3id: %x\n"
4200  " --> display: %s\n"
4201  " --> activated: %d\n"
4202  " --> state: %s\n"
4203  " --> capability: %s\n"
4204 #ifdef MISDN_1_2
4205  " --> pipeline: %s\n"
4206 #else
4207  " --> echo_cancel: %d\n"
4208 #endif
4209  " --> notone : rx %d tx:%d\n"
4210  " --> bc_hold: %d\n",
4211  ast ? ast_channel_name(ast) : "",
4212  help->l3id,
4213  help->addr,
4214  bc->addr,
4215  bc->l3_id,
4216  bc->display,
4217  bc->active,
4218  bc_state2str(bc->bc_state),
4219  bearer2str(bc->capability),
4220 #ifdef MISDN_1_2
4221  bc->pipeline,
4222 #else
4223  bc->ec_enable,
4224 #endif
4225  help->norxtone, help->notxtone,
4226  bc->holded);
4227  }
4228 }
4229 
4230 static char *handle_cli_misdn_show_channels(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4231 {
4232  struct chan_list *help;
4233 
4234  switch (cmd) {
4235  case CLI_INIT:
4236  e->command = "misdn show channels";
4237  e->usage =
4238  "Usage: misdn show channels\n"
4239  " Show the internal mISDN channel list\n";
4240  return NULL;
4241  case CLI_GENERATE:
4242  return NULL;
4243  }
4244 
4245  if (a->argc != 3) {
4246  return CLI_SHOWUSAGE;
4247  }
4248 
4249  ast_cli(a->fd, "Channel List: %p\n", cl_te);
4250 
4251  /*
4252  * Walking the list and dumping the channel information could
4253  * take awhile. With the list locked for the duration, the
4254  * channel driver cannot process signaling messages. However,
4255  * since this is a CLI command it should not be run very often.
4256  */
4257  ast_mutex_lock(&cl_te_lock);
4258  for (help = cl_te; help; help = help->next) {
4259  struct misdn_bchannel *bc = help->bc;
4260  struct ast_channel *ast = help->ast;
4261  if (!ast) {
4262  if (!bc) {
4263  ast_cli(a->fd, "chan_list obj. with l3id:%x has no bc and no ast Leg\n", help->l3id);
4264  continue;
4265  }
4266  ast_cli(a->fd, "bc with pid:%d has no Ast Leg\n", bc->pid);
4267  }
4268 
4269  if (misdn_debug[0] > 2) {
4270  ast_cli(a->fd, "Bc:%p Ast:%p\n", bc, ast);
4271  }
4272  if (bc) {
4273  print_bc_info(a->fd, help, bc);
4274  } else {
4275  if (help->hold.state != MISDN_HOLD_IDLE) {
4276  ast_cli(a->fd, "ITS A HELD CALL BC:\n");
4277  ast_cli(a->fd, " --> l3_id: %x\n"
4278  " --> dialed:%s\n"
4279  " --> caller:\"%s\" <%s>\n"
4280  " --> hold_port: %d\n"
4281  " --> hold_channel: %d\n",
4282  help->l3id,
4283  ast_channel_exten(ast),
4284  S_COR(ast_channel_caller(ast)->id.name.valid, ast_channel_caller(ast)->id.name.str, ""),
4285  S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, ""),
4286  help->hold.port,
4287  help->hold.channel
4288  );
4289  } else {
4290  ast_cli(a->fd, "* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n",
4291  ast_channel_exten(ast),
4292  S_COR(ast_channel_caller(ast)->id.number.valid, ast_channel_caller(ast)->id.number.str, ""));
4293  }
4294  }
4295  }
4296  ast_mutex_unlock(&cl_te_lock);
4297 
4299 
4300  return CLI_SUCCESS;
4301 }
4302 
4303 static char *handle_cli_misdn_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4304 {
4305  struct chan_list *help;
4306 
4307  switch (cmd) {
4308  case CLI_INIT:
4309  e->command = "misdn show channel";
4310  e->usage =
4311  "Usage: misdn show channel <channel>\n"
4312  " Show an internal mISDN channel\n.";
4313  return NULL;
4314  case CLI_GENERATE:
4315  return complete_ch(a);
4316  }
4317 
4318  if (a->argc != 4) {
4319  return CLI_SHOWUSAGE;
4320  }
4321 
4322  ast_mutex_lock(&cl_te_lock);
4323  for (help = cl_te; help; help = help->next) {
4324  struct misdn_bchannel *bc = help->bc;
4325  struct ast_channel *ast = help->ast;
4326 
4327  if (bc && ast) {
4328  if (!strcasecmp(ast_channel_name(ast), a->argv[3])) {
4329  print_bc_info(a->fd, help, bc);
4330  break;
4331  }
4332  }
4333  }
4334  ast_mutex_unlock(&cl_te_lock);
4335 
4336  return CLI_SUCCESS;
4337 }
4338 
4339 static char *handle_cli_misdn_set_tics(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4340 {
4341  switch (cmd) {
4342  case CLI_INIT:
4343  e->command = "misdn set tics";
4344  e->usage =
4345  "Usage: misdn set tics <value>\n";
4346  return NULL;
4347  case CLI_GENERATE:
4348  return NULL;
4349  }
4350 
4351  if (a->argc != 4) {
4352  return CLI_SHOWUSAGE;
4353  }
4354 
4355  /* XXX Wow, this does... a whole lot of nothing... XXX */
4356  MAXTICS = atoi(a->argv[3]);
4357 
4358  return CLI_SUCCESS;
4359 }
4360 
4361 static char *handle_cli_misdn_show_stacks(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4362 {
4363  int port;
4364 
4365  switch (cmd) {
4366  case CLI_INIT:
4367  e->command = "misdn show stacks";
4368  e->usage =
4369  "Usage: misdn show stacks\n"
4370  " Show internal mISDN stack_list.\n";
4371  return NULL;
4372  case CLI_GENERATE:
4373  return NULL;
4374  }
4375 
4376  if (a->argc != 3) {
4377  return CLI_SHOWUSAGE;
4378  }
4379 
4380  ast_cli(a->fd, "BEGIN STACK_LIST:\n");
4381  for (port = misdn_cfg_get_next_port(0); port > 0;
4382  port = misdn_cfg_get_next_port(port)) {
4383  char buf[128];
4384 
4385  get_show_stack_details(port, buf);
4386  ast_cli(a->fd, " %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
4387  }
4388 
4389  return CLI_SUCCESS;
4390 }
4391 
4392 static char *handle_cli_misdn_show_ports_stats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4393 {
4394  int port;
4395 
4396  switch (cmd) {
4397  case CLI_INIT:
4398  e->command = "misdn show ports stats";
4399  e->usage =
4400  "Usage: misdn show ports stats\n"
4401  " Show mISDNs channel's call statistics per port.\n";
4402  return NULL;
4403  case CLI_GENERATE:
4404  return NULL;
4405  }
4406 
4407  if (a->argc != 4) {
4408  return CLI_SHOWUSAGE;
4409  }
4410 
4411  ast_cli(a->fd, "Port\tin_calls\tout_calls\n");
4412  for (port = misdn_cfg_get_next_port(0); port > 0;
4413  port = misdn_cfg_get_next_port(port)) {
4414  ast_cli(a->fd, "%d\t%d\t\t%d\n", port, misdn_in_calls[port], misdn_out_calls[port]);
4415  }
4416  ast_cli(a->fd, "\n");
4417 
4418  return CLI_SUCCESS;
4419 }
4420 
4421 static char *handle_cli_misdn_show_port(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
4422 {
4423  int port;
4424  char buf[128];
4425 
4426  switch (cmd) {
4427  case CLI_INIT:
4428  e->command = "misdn show port";
4429  e->usage =
4430  "Usage: misdn show port <port>\n"
4431  " Show detailed information for given port.\n";
4432  return NULL;
4433  case CLI_GENERATE:
4434  return NULL;
4435  }
4436 
4437  if (a->argc != 4) {
4438  return CLI_SHOWUSAGE;
4439  }
4440 
4441  port = atoi(a->argv[3]);
4442 
4443  ast_cli(a->fd, "BEGIN STACK_LIST:\n");
4444  get_show_stack_details(port, buf);
4445  ast_cli(a->fd, " %s Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
4446 
4447  return CLI_SUCCESS;
4448 }
4449 
4450 #if defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES)
4451 static const struct FacParm Fac_Msgs[] = {
4452 /* *INDENT-OFF* */
4453  [0].Function = Fac_ERROR,
4454  [0].u.ERROR.invokeId = 8,
4455  [0].u.ERROR.errorValue = FacError_CCBS_AlreadyAccepted,
4456 
4457  [1].Function = Fac_RESULT,
4458  [1].u.RESULT.InvokeID = 9,
4459 
4460  [2].Function = Fac_REJECT,
4461  [2].u.REJECT.Code = FacReject_Gen_BadlyStructuredComponent,
4462 
4463  [3].Function = Fac_REJECT,
4464  [3].u.REJECT.InvokeIDPresent = 1,
4465  [3].u.REJECT.InvokeID = 10,
4466  [3].u.REJECT.Code = FacReject_Inv_InitiatorReleasing,
4467 
4468  [4].Function = Fac_REJECT,
4469  [4].u.REJECT.InvokeIDPresent = 1,
4470  [4].u.REJECT.InvokeID = 11,
4471  [4].u.REJECT.Code = FacReject_Res_MistypedResult,
4472 
4473  [5].Function = Fac_REJECT,
4474  [5].u.REJECT.InvokeIDPresent = 1,
4475  [5].u.REJECT.InvokeID = 12,
4476  [5].u.REJECT.Code = FacReject_Err_ErrorResponseUnexpected,
4477 
4478  [6].Function = Fac_StatusRequest,
4479  [6].u.StatusRequest.InvokeID = 13,
4480  [6].u.StatusRequest.ComponentType = FacComponent_Invoke,
4481  [6].u.StatusRequest.Component.Invoke.Q931ie.Bc.Length = 2,
4482  [6].u.StatusRequest.Component.Invoke.Q931ie.Bc.Contents = "AB",
4483  [6].u.StatusRequest.Component.Invoke.Q931ie.Llc.Length = 3,
4484  [6].u.StatusRequest.Component.Invoke.Q931ie.Llc.Contents = "CDE",
4485  [6].u.StatusRequest.Component.Invoke.Q931ie.Hlc.Length = 4,
4486  [6].u.StatusRequest.Component.Invoke.Q931ie.Hlc.Contents = "FGHI",
4487  [6].u.StatusRequest.Component.Invoke.CompatibilityMode = 1,
4488 
4489  [7].Function = Fac_StatusRequest,
4490  [7].u.StatusRequest.InvokeID = 14,
4491  [7].u.StatusRequest.ComponentType = FacComponent_Result,
4492  [7].u.StatusRequest.Component.Result.Status = 2,
4493 
4494  [8].Function = Fac_CallInfoRetain,
4495  [8].u.CallInfoRetain.InvokeID = 15,
4496  [8].u.CallInfoRetain.CallLinkageID = 115,
4497 
4498  [9].Function = Fac_EraseCallLinkageID,
4499  [9].u.EraseCallLinkageID.InvokeID = 16,
4500  [9].u.EraseCallLinkageID.CallLinkageID = 105,
4501 
4502  [10].Function = Fac_CCBSDeactivate,
4503  [10].u.CCBSDeactivate.InvokeID = 17,
4504  [10].u.CCBSDeactivate.ComponentType = FacComponent_Invoke,
4505  [10].u.CCBSDeactivate.Component.Invoke.CCBSReference = 2,
4506 
4507  [11].Function = Fac_CCBSDeactivate,
4508  [11].u.CCBSDeactivate.InvokeID = 18,
4509  [11].u.CCBSDeactivate.ComponentType = FacComponent_Result,
4510 
4511  [12].Function = Fac_CCBSErase,
4512  [12].u.CCBSErase.InvokeID = 19,
4513  [12].u.CCBSErase.Q931ie.Bc.Length = 2,
4514  [12].u.CCBSErase.Q931ie.Bc.Contents = "JK",
4515  [12].u.CCBSErase.AddressOfB.Party.Type = 0,
4516  [12].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 5,
4517  [12].u.CCBSErase.AddressOfB.Party.Number = "33403",
4518  [12].u.CCBSErase.AddressOfB.Subaddress.Type = 0,
4519  [12].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
4520  [12].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.Information = "3748",
4521  [12].u.CCBSErase.RecallMode = 1,
4522  [12].u.CCBSErase.CCBSReference = 102,
4523  [12].u.CCBSErase.Reason = 3,
4524 
4525  [13].Function = Fac_CCBSErase,
4526  [13].u.CCBSErase.InvokeID = 20,
4527  [13].u.CCBSErase.Q931ie.Bc.Length = 2,
4528  [13].u.CCBSErase.Q931ie.Bc.Contents = "JK",
4529  [13].u.CCBSErase.AddressOfB.Party.Type = 1,
4530  [13].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 11,
4531  [13].u.CCBSErase.AddressOfB.Party.TypeOfNumber = 1,
4532  [13].u.CCBSErase.AddressOfB.Party.Number = "18003020102",
4533  [13].u.CCBSErase.AddressOfB.Subaddress.Type = 0,
4534  [13].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
4535  [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.OddCountPresent = 1,
4536  [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.OddCount = 1,
4537  [13].u.CCBSErase.AddressOfB.Subaddress.u.UserSpecified.Information = "3748",
4538  [13].u.CCBSErase.RecallMode = 1,
4539  [13].u.CCBSErase.CCBSReference = 102,
4540  [13].u.CCBSErase.Reason = 3,
4541 
4542  [14].Function = Fac_CCBSErase,
4543  [14].u.CCBSErase.InvokeID = 21,
4544  [14].u.CCBSErase.Q931ie.Bc.Length = 2,
4545  [14].u.CCBSErase.Q931ie.Bc.Contents = "JK",
4546  [14].u.CCBSErase.AddressOfB.Party.Type = 2,
4547  [14].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
4548  [14].u.CCBSErase.AddressOfB.Party.Number = "1803",
4549  [14].u.CCBSErase.AddressOfB.Subaddress.Type = 1,
4550  [14].u.CCBSErase.AddressOfB.Subaddress.Length = 4,
4551  [14].u.CCBSErase.AddressOfB.Subaddress.u.Nsap = "6492",
4552  [14].u.CCBSErase.RecallMode = 1,
4553  [14].u.CCBSErase.CCBSReference = 102,
4554  [14].u.CCBSErase.Reason = 3,
4555 
4556  [15].Function = Fac_CCBSErase,
4557  [15].u.CCBSErase.InvokeID = 22,
4558  [15].u.CCBSErase.Q931ie.Bc.Length = 2,
4559  [15].u.CCBSErase.Q931ie.Bc.Contents = "JK",
4560  [15].u.CCBSErase.AddressOfB.Party.Type = 3,
4561  [15].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
4562  [15].u.CCBSErase.AddressOfB.Party.Number = "1803",
4563  [15].u.CCBSErase.RecallMode = 1,
4564  [15].u.CCBSErase.CCBSReference = 102,
4565  [15].u.CCBSErase.Reason = 3,
4566 
4567  [16].Function = Fac_CCBSErase,
4568  [16].u.CCBSErase.InvokeID = 23,
4569  [16].u.CCBSErase.Q931ie.Bc.Length = 2,
4570  [16].u.CCBSErase.Q931ie.Bc.Contents = "JK",
4571  [16].u.CCBSErase.AddressOfB.Party.Type = 4,
4572  [16].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
4573  [16].u.CCBSErase.AddressOfB.Party.Number = "1803",
4574  [16].u.CCBSErase.RecallMode = 1,
4575  [16].u.CCBSErase.CCBSReference = 102,
4576  [16].u.CCBSErase.Reason = 3,
4577 
4578  [17].Function = Fac_CCBSErase,
4579  [17].u.CCBSErase.InvokeID = 24,
4580  [17].u.CCBSErase.Q931ie.Bc.Length = 2,
4581  [17].u.CCBSErase.Q931ie.Bc.Contents = "JK",
4582  [17].u.CCBSErase.AddressOfB.Party.Type = 5,
4583  [17].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 11,
4584  [17].u.CCBSErase.AddressOfB.Party.TypeOfNumber = 4,
4585  [17].u.CCBSErase.AddressOfB.Party.Number = "18003020102",
4586  [17].u.CCBSErase.RecallMode = 1,
4587  [17].u.CCBSErase.CCBSReference = 102,
4588  [17].u.CCBSErase.Reason = 3,
4589 
4590  [18].Function = Fac_CCBSErase,
4591  [18].u.CCBSErase.InvokeID = 25,
4592  [18].u.CCBSErase.Q931ie.Bc.Length = 2,
4593  [18].u.CCBSErase.Q931ie.Bc.Contents = "JK",
4594  [18].u.CCBSErase.AddressOfB.Party.Type = 8,
4595  [18].u.CCBSErase.AddressOfB.Party.LengthOfNumber = 4,
4596  [18].u.CCBSErase.AddressOfB.Party.Number = "1803",
4597  [18].u.CCBSErase.RecallMode = 1,
4598  [18].u.CCBSErase.CCBSReference = 102,
4599  [18].u.CCBSErase.Reason = 3,
4600 
4601  [19].Function = Fac_CCBSRemoteUserFree,
4602  [19].u.CCBSRemoteUserFree.InvokeID = 26,
4603  [19].u.CCBSRemoteUserFree.Q931ie.Bc.Length = 2,
4604  [19].u.CCBSRemoteUserFree.Q931ie.Bc.Contents = "JK",
4605  [19].u.CCBSRemoteUserFree.AddressOfB.Party.Type = 8,
4606  [19].u.CCBSRemoteUserFree.AddressOfB.Party.LengthOfNumber = 4,
4607  [19].u.CCBSRemoteUserFree.AddressOfB.Party.Number = "1803",
4608  [19].u.CCBSRemoteUserFree.RecallMode = 1,
4609  [19].u.CCBSRemoteUserFree.CCBSReference = 102,
4610 
4611  [20].Function = Fac_CCBSCall,
4612  [20].u.CCBSCall.InvokeID = 27,
4613  [20].u.CCBSCall.CCBSReference = 115,
4614 
4615  [21].Function = Fac_CCBSStatusRequest,
4616  [21].u.CCBSStatusRequest.InvokeID = 28,
4617  [21].u.CCBSStatusRequest.ComponentType = FacComponent_Invoke,
4618  [21].u.CCBSStatusRequest.Component.Invoke.Q931ie.Bc.Length = 2,
4619  [21].u.CCBSStatusRequest.Component.Invoke.Q931ie.Bc.Contents = "JK",
4620  [21].u.CCBSStatusRequest.Component.Invoke.RecallMode = 1,
4621  [21].u.CCBSStatusRequest.Component.Invoke.CCBSReference = 102,
4622 
4623  [22].Function = Fac_CCBSStatusRequest,
4624  [22].u.CCBSStatusRequest.InvokeID = 29,
4625  [22].u.CCBSStatusRequest.ComponentType = FacComponent_Result,
4626  [22].u.CCBSStatusRequest.Component.Result.Free = 1,
4627 
4628  [23].Function = Fac_CCBSBFree,
4629  [23].u.CCBSBFree.InvokeID = 30,
4630  [23].u.CCBSBFree.Q931ie.Bc.Length = 2,
4631  [23].u.CCBSBFree.Q931ie.Bc.Contents = "JK",
4632  [23].u.CCBSBFree.AddressOfB.Party.Type = 8,
4633  [23].u.CCBSBFree.AddressOfB.Party.LengthOfNumber = 4,
4634  [23].u.CCBSBFree.AddressOfB.Party.Number = "1803",
4635  [23].u.CCBSBFree.RecallMode = 1,
4636  [23].u.CCBSBFree.CCBSReference = 14,
4637 
4638  [24].Function = Fac_CCBSStopAlerting,
4639  [24].u.CCBSStopAlerting.InvokeID = 31,
4640  [24].u.CCBSStopAlerting.CCBSReference = 37,
4641 
4642  [25].Function = Fac_CCBSRequest,
4643  [25].u.CCBSRequest.InvokeID = 32,
4644  [25].u.CCBSRequest.ComponentType = FacComponent_Invoke,
4645  [25].u.CCBSRequest.Component.Invoke.CallLinkageID = 57,
4646 
4647  [26].Function = Fac_CCBSRequest,
4648  [26].u.CCBSRequest.InvokeID = 33,
4649  [26].u.CCBSRequest.ComponentType = FacComponent_Result,
4650  [26].u.CCBSRequest.Component.Result.RecallMode = 1,
4651  [26].u.CCBSRequest.Component.Result.CCBSReference = 102,
4652 
4653  [27].Function = Fac_CCBSInterrogate,
4654  [27].u.CCBSInterrogate.InvokeID = 34,
4655  [27].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
4656  [27].u.CCBSInterrogate.Component.Invoke.AParty.Type = 8,
4657  [27].u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber = 4,
4658  [27].u.CCBSInterrogate.Component.Invoke.AParty.Number = "1803",
4659  [27].u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent = 1,
4660  [27].u.CCBSInterrogate.Component.Invoke.CCBSReference = 76,
4661 
4662  [28].Function = Fac_CCBSInterrogate,
4663  [28].u.CCBSInterrogate.InvokeID = 35,
4664  [28].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
4665  [28].u.CCBSInterrogate.Component.Invoke.AParty.Type = 8,
4666  [28].u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber = 4,
4667  [28].u.CCBSInterrogate.Component.Invoke.AParty.Number = "1803",
4668 
4669  [29].Function = Fac_CCBSInterrogate,
4670  [29].u.CCBSInterrogate.InvokeID = 36,
4671  [29].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
4672  [29].u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent = 1,
4673  [29].u.CCBSInterrogate.Component.Invoke.CCBSReference = 76,
4674 
4675  [30].Function = Fac_CCBSInterrogate,
4676  [30].u.CCBSInterrogate.InvokeID = 37,
4677  [30].u.CCBSInterrogate.ComponentType = FacComponent_Invoke,
4678 
4679  [31].Function = Fac_CCBSInterrogate,
4680  [31].u.CCBSInterrogate.InvokeID = 38,
4681  [31].u.CCBSInterrogate.ComponentType = FacComponent_Result,
4682  [31].u.CCBSInterrogate.Component.Result.RecallMode = 1,
4683 
4684  [32].Function = Fac_CCBSInterrogate,
4685  [32].u.CCBSInterrogate.InvokeID = 39,
4686  [32].u.CCBSInterrogate.ComponentType = FacComponent_Result,
4687  [32].u.CCBSInterrogate.Component.Result.RecallMode = 1,
4688  [32].u.CCBSInterrogate.Component.Result.NumRecords = 1,
4689  [32].u.CCBSInterrogate.Component.Result.CallDetails[0].CCBSReference = 12,
4690  [32].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Length = 2,
4691  [32].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Contents = "JK",
4692  [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Type = 8,
4693  [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.LengthOfNumber = 4,
4694  [32].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Number = "1803",
4695  [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.Type = 1,
4696  [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.Length = 4,
4697  [32].u.CCBSInterrogate.Component.Result.CallDetails[0].SubaddressOfA.u.Nsap = "6492",
4698 
4699  [33].Function = Fac_CCBSInterrogate,
4700  [33].u.CCBSInterrogate.InvokeID = 40,
4701  [33].u.CCBSInterrogate.ComponentType = FacComponent_Result,
4702  [33].u.CCBSInterrogate.Component.Result.RecallMode = 1,
4703  [33].u.CCBSInterrogate.Component.Result.NumRecords = 2,
4704  [33].u.CCBSInterrogate.Component.Result.CallDetails[0].CCBSReference = 12,
4705  [33].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Length = 2,
4706  [33].u.CCBSInterrogate.Component.Result.CallDetails[0].Q931ie.Bc.Contents = "JK",
4707  [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Type = 8,
4708  [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.LengthOfNumber = 4,
4709  [33].u.CCBSInterrogate.Component.Result.CallDetails[0].AddressOfB.Party.Number = "1803",
4710  [33].u.CCBSInterrogate.Component.Result.CallDetails[1].CCBSReference = 102,
4711  [33].u.CCBSInterrogate.Component.Result.CallDetails[1].Q931ie.Bc.Length = 2,
4712  [33].u.CCBSInterrogate.Component.Result.CallDetails[1].Q931ie.Bc.Contents = "LM",
4713  [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.Type = 8,
4714  [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.LengthOfNumber = 4,
4715  [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Party.Number = "6229",
4716  [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.Type = 1,
4717  [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.Length = 4,
4718  [33].u.CCBSInterrogate.Component.Result.CallDetails[1].AddressOfB.Subaddress.u.Nsap = "8592",
4719  [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.Type = 1,
4720  [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.Length = 4,
4721  [33].u.CCBSInterrogate.Component.Result.CallDetails[1].SubaddressOfA.u.Nsap = "6492",
4722 
4723  [34].Function = Fac_CCNRRequest,
4724  [34].u.CCNRRequest.InvokeID = 512,
4725  [34].u.CCNRRequest.ComponentType = FacComponent_Invoke,
4726  [34].u.CCNRRequest.Component.Invoke.CallLinkageID = 57,
4727 
4728  [35].Function = Fac_CCNRRequest,
4729  [35].u.CCNRRequest.InvokeID = 150,
4730  [35].u.CCNRRequest.ComponentType = FacComponent_Result,
4731  [35].u.CCNRRequest.Component.Result.RecallMode = 1,
4732  [35].u.CCNRRequest.Component.Result.CCBSReference = 102,
4733 
4734  [36].Function = Fac_CCNRInterrogate,
4735  [36].u.CCNRInterrogate.InvokeID = -129,
4736  [36].u.CCNRInterrogate.ComponentType = FacComponent_Invoke,
4737 
4738  [37].Function = Fac_CCNRInterrogate,
4739  [37].u.CCNRInterrogate.InvokeID = -3,
4740  [37].u.CCNRInterrogate.ComponentType = FacComponent_Result,
4741  [37].u.CCNRInterrogate.Component.Result.RecallMode = 1,
4742 
4743  [38].Function = Fac_CCBS_T_Call,
4744  [38].u.EctExecute.InvokeID = 41,
4745 
4746  [39].Function = Fac_CCBS_T_Suspend,
4747  [39].u.EctExecute.InvokeID = 42,
4748 
4749  [40].Function = Fac_CCBS_T_Resume,
4750  [40].u.EctExecute.InvokeID = 43,
4751 
4752  [41].Function = Fac_CCBS_T_RemoteUserFree,
4753  [41].u.EctExecute.InvokeID = 44,
4754 
4755  [42].Function = Fac_CCBS_T_Available,
4756  [42].u.EctExecute.InvokeID = 45,
4757 
4758  [43].Function = Fac_CCBS_T_Request,
4759  [43].u.CCBS_T_Request.InvokeID = 46,
4760  [43].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
4761  [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
4762  [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
4763  [43].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
4764  [43].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
4765  [43].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
4766  [43].u.CCBS_T_Request.Component.Invoke.RetentionSupported = 1,
4767  [43].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
4768  [43].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
4769  [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
4770  [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
4771  [43].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
4772 
4773  [44].Function = Fac_CCBS_T_Request,
4774  [44].u.CCBS_T_Request.InvokeID = 47,
4775  [44].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
4776  [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
4777  [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
4778  [44].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
4779  [44].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
4780  [44].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
4781  [44].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
4782  [44].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
4783  [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
4784  [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
4785  [44].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
4786 
4787  [45].Function = Fac_CCBS_T_Request,
4788  [45].u.CCBS_T_Request.InvokeID = 48,
4789  [45].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
4790  [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
4791  [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
4792  [45].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
4793  [45].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
4794  [45].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
4795  [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.Type = 8,
4796  [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber = 4,
4797  [45].u.CCBS_T_Request.Component.Invoke.Originating.Party.Number = "9864",
4798 
4799  [46].Function = Fac_CCBS_T_Request,
4800  [46].u.CCBS_T_Request.InvokeID = 49,
4801  [46].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
4802  [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
4803  [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
4804  [46].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
4805  [46].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
4806  [46].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
4807  [46].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent = 1,
4808  [46].u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator = 1,
4809 
4810  [47].Function = Fac_CCBS_T_Request,
4811  [47].u.CCBS_T_Request.InvokeID = 50,
4812  [47].u.CCBS_T_Request.ComponentType = FacComponent_Invoke,
4813  [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.Type = 8,
4814  [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
4815  [47].u.CCBS_T_Request.Component.Invoke.Destination.Party.Number = "6229",
4816  [47].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
4817  [47].u.CCBS_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
4818 
4819  [48].Function = Fac_CCBS_T_Request,
4820  [48].u.CCBS_T_Request.InvokeID = 51,
4821  [48].u.CCBS_T_Request.ComponentType = FacComponent_Result,
4822  [48].u.CCBS_T_Request.Component.Result.RetentionSupported = 1,
4823 
4824  [49].Function = Fac_CCNR_T_Request,
4825  [49].u.CCNR_T_Request.InvokeID = 52,
4826  [49].u.CCNR_T_Request.ComponentType = FacComponent_Invoke,
4827  [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.Type = 8,
4828  [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.LengthOfNumber = 4,
4829  [49].u.CCNR_T_Request.Component.Invoke.Destination.Party.Number = "6229",
4830  [49].u.CCNR_T_Request.Component.Invoke.Q931ie.Bc.Length = 2,
4831  [49].u.CCNR_T_Request.Component.Invoke.Q931ie.Bc.Contents = "LM",
4832 
4833  [50].Function = Fac_CCNR_T_Request,
4834  [50].u.CCNR_T_Request.InvokeID = 53,
4835  [50].u.CCNR_T_Request.ComponentType = FacComponent_Result,
4836  [50].u.CCNR_T_Request.Component.Result.RetentionSupported = 1,
4837 
4838  [51].Function = Fac_EctExecute,
4839  [51].u.EctExecute.InvokeID = 54,
4840 
4841  [52].Function = Fac_ExplicitEctExecute,
4842  [52].u.ExplicitEctExecute.InvokeID = 55,
4843  [52].u.ExplicitEctExecute.LinkID = 23,
4844 
4845  [53].Function = Fac_RequestSubaddress,
4846  [53].u.RequestSubaddress.InvokeID = 56,
4847 
4848  [54].Function = Fac_SubaddressTransfer,
4849  [54].u.SubaddressTransfer.InvokeID = 57,
4850  [54].u.SubaddressTransfer.Subaddress.Type = 1,
4851  [54].u.SubaddressTransfer.Subaddress.Length = 4,
4852  [54].u.SubaddressTransfer.Subaddress.u.Nsap = "6492",
4853 
4854  [55].Function = Fac_EctLinkIdRequest,
4855  [55].u.EctLinkIdRequest.InvokeID = 58,
4856  [55].u.EctLinkIdRequest.ComponentType = FacComponent_Invoke,
4857 
4858  [56].Function = Fac_EctLinkIdRequest,
4859  [56].u.EctLinkIdRequest.InvokeID = 59,
4860  [56].u.EctLinkIdRequest.ComponentType = FacComponent_Result,
4861  [56].u.EctLinkIdRequest.Component.Result.LinkID = 76,
4862 
4863  [57].Function = Fac_EctInform,
4864  [57].u.EctInform.InvokeID = 60,
4865  [57].u.EctInform.Status = 1,
4866  [57].u.EctInform.RedirectionPresent = 1,
4867  [57].u.EctInform.Redirection.Type = 0,
4868  [57].u.EctInform.Redirection.Unscreened.Type = 8,
4869  [57].u.EctInform.Redirection.Unscreened.LengthOfNumber = 4,
4870  [57].u.EctInform.Redirection.Unscreened.Number = "6229",
4871 
4872  [58].Function = Fac_EctInform,
4873  [58].u.EctInform.InvokeID = 61,
4874  [58].u.EctInform.Status = 1,
4875  [58].u.EctInform.RedirectionPresent = 1,
4876  [58].u.EctInform.Redirection.Type = 1,
4877 
4878  [59].Function = Fac_EctInform,
4879  [59].u.EctInform.InvokeID = 62,
4880  [59].u.EctInform.Status = 1,
4881  [59].u.EctInform.RedirectionPresent = 1,
4882  [59].u.EctInform.Redirection.Type = 2,
4883 
4884  [60].Function = Fac_EctInform,
4885  [60].u.EctInform.InvokeID = 63,
4886  [60].u.EctInform.Status = 1,
4887  [60].u.EctInform.RedirectionPresent = 1,
4888  [60].u.EctInform.Redirection.Type = 3,
4889  [60].u.EctInform.Redirection.Unscreened.Type = 8,
4890  [60].u.EctInform.Redirection.Unscreened.LengthOfNumber = 4,
4891  [60].u.EctInform.Redirection.Unscreened.Number = "3340",
4892 
4893  [61].Function = Fac_EctInform,
4894  [61].u.EctInform.InvokeID = 64,
4895  [61].u.EctInform.Status = 1,
4896  [61].u.EctInform.RedirectionPresent = 0,
4897 
4898  [62].Function = Fac_EctLoopTest,
4899  [62].u.EctLoopTest.InvokeID = 65,
4900  [62].u.EctLoopTest.ComponentType = FacComponent_Invoke,
4901  [62].u.EctLoopTest.Component.Invoke.CallTransferID = 7,
4902 
4903  [63].Function = Fac_EctLoopTest,
4904  [63].u.EctLoopTest.InvokeID = 66,
4905  [63].u.EctLoopTest.ComponentType = FacComponent_Result,
4906  [63].u.EctLoopTest.Component.Result.LoopResult = 2,
4907 
4908  [64].Function = Fac_ActivationDiversion,
4909  [64].u.ActivationDiversion.InvokeID = 67,
4910  [64].u.ActivationDiversion.ComponentType = FacComponent_Invoke,
4911  [64].u.ActivationDiversion.Component.Invoke.Procedure = 2,
4912  [64].u.ActivationDiversion.Component.Invoke.BasicService = 3,
4913  [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 4,
4914  [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber = 4,
4915  [64].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number = "1803",
4916  [64].u.ActivationDiversion.Component.Invoke.ServedUser.Type = 4,
4917  [64].u.ActivationDiversion.Component.Invoke.ServedUser.LengthOfNumber = 4,
4918  [64].u.ActivationDiversion.Component.Invoke.ServedUser.Number = "5398",
4919 
4920  [65].Function = Fac_ActivationDiversion,
4921  [65].u.ActivationDiversion.InvokeID = 68,
4922  [65].u.ActivationDiversion.ComponentType = FacComponent_Invoke,
4923  [65].u.ActivationDiversion.Component.Invoke.Procedure = 1,
4924  [65].u.ActivationDiversion.Component.Invoke.BasicService = 5,
4925  [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 4,
4926  [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber = 4,
4927  [65].u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number = "1803",
4928 
4929  [66].Function = Fac_ActivationDiversion,
4930  [66].u.ActivationDiversion.InvokeID = 69,
4931  [66].u.ActivationDiversion.ComponentType = FacComponent_Result,
4932 
4933  [67].Function = Fac_DeactivationDiversion,
4934  [67].u.DeactivationDiversion.InvokeID = 70,
4935  [67].u.DeactivationDiversion.ComponentType = FacComponent_Invoke,
4936  [67].u.DeactivationDiversion.Component.Invoke.Procedure = 1,
4937  [67].u.DeactivationDiversion.Component.Invoke.BasicService = 5,
4938 
4939  [68].Function = Fac_DeactivationDiversion,
4940  [68].u.DeactivationDiversion.InvokeID = 71,
4941  [68].u.DeactivationDiversion.ComponentType = FacComponent_Result,
4942 
4943  [69].Function = Fac_ActivationStatusNotificationDiv,
4944  [69].u.ActivationStatusNotificationDiv.InvokeID = 72,
4945  [69].u.ActivationStatusNotificationDiv.Procedure = 1,
4946  [69].u.ActivationStatusNotificationDiv.BasicService = 5,
4947  [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.Type = 4,
4948  [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.LengthOfNumber = 4,
4949  [69].u.ActivationStatusNotificationDiv.ForwardedTo.Party.Number = "1803",
4950 
4951  [70].Function = Fac_DeactivationStatusNotificationDiv,
4952  [70].u.DeactivationStatusNotificationDiv.InvokeID = 73,
4953  [70].u.DeactivationStatusNotificationDiv.Procedure = 1,
4954  [70].u.DeactivationStatusNotificationDiv.BasicService = 5,
4955 
4956  [71].Function = Fac_InterrogationDiversion,
4957  [71].u.InterrogationDiversion.InvokeID = 74,
4958  [71].u.InterrogationDiversion.ComponentType = FacComponent_Invoke,
4959  [71].u.InterrogationDiversion.Component.Invoke.Procedure = 1,
4960  [71].u.InterrogationDiversion.Component.Invoke.BasicService = 5,
4961 
4962  [72].Function = Fac_InterrogationDiversion,
4963  [72].u.InterrogationDiversion.InvokeID = 75,
4964  [72].u.InterrogationDiversion.ComponentType = FacComponent_Invoke,
4965  [72].u.InterrogationDiversion.Component.Invoke.Procedure = 1,
4966 
4967  [73].Function = Fac_InterrogationDiversion,
4968  [73].u.InterrogationDiversion.InvokeID = 76,
4969  [73].u.InterrogationDiversion.ComponentType = FacComponent_Result,
4970  [73].u.InterrogationDiversion.Component.Result.NumRecords = 2,
4971  [73].u.InterrogationDiversion.Component.Result.List[0].Procedure = 2,
4972  [73].u.InterrogationDiversion.Component.Result.List[0].BasicService = 5,
4973  [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.Type = 4,
4974  [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.LengthOfNumber = 4,
4975  [73].u.InterrogationDiversion.Component.Result.List[0].ForwardedTo.Party.Number = "1803",
4976  [73].u.InterrogationDiversion.Component.Result.List[1].Procedure = 1,
4977  [73].u.InterrogationDiversion.Component.Result.List[1].BasicService = 3,
4978  [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.Type = 4,
4979  [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.LengthOfNumber = 4,
4980  [73].u.InterrogationDiversion.Component.Result.List[1].ForwardedTo.Party.Number = "1903",
4981  [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.Type = 4,
4982  [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.LengthOfNumber = 4,
4983  [73].u.InterrogationDiversion.Component.Result.List[1].ServedUser.Number = "5398",
4984 
4985  [74].Function = Fac_DiversionInformation,
4986  [74].u.DiversionInformation.InvokeID = 77,
4987  [74].u.DiversionInformation.DiversionReason = 3,
4988  [74].u.DiversionInformation.BasicService = 5,
4989  [74].u.DiversionInformation.ServedUserSubaddress.Type = 1,
4990  [74].u.DiversionInformation.ServedUserSubaddress.Length = 4,
4991  [74].u.DiversionInformation.ServedUserSubaddress.u.Nsap = "6492",
4992  [74].u.DiversionInformation.CallingAddressPresent = 1,
4993  [74].u.DiversionInformation.CallingAddress.Type = 0,
4994  [74].u.DiversionInformation.CallingAddress.Address.ScreeningIndicator = 3,
4995  [74].u.DiversionInformation.CallingAddress.Address.Party.Type = 4,
4996  [74].u.DiversionInformation.CallingAddress.Address.Party.LengthOfNumber = 4,
4997  [74].u.DiversionInformation.CallingAddress.Address.Party.Number = "1803",
4998  [74].u.DiversionInformation.OriginalCalledPresent = 1,
4999  [74].u.DiversionInformation.OriginalCalled.Type = 1,
5000  [74].u.DiversionInformation.LastDivertingPresent = 1,
5001  [74].u.DiversionInformation.LastDiverting.Type = 2,
5002  [74].u.DiversionInformation.LastDivertingReasonPresent = 1,
5003  [74].u.DiversionInformation.LastDivertingReason = 3,
5004  [74].u.DiversionInformation.UserInfo.Length = 5,
5005  [74].u.DiversionInformation.UserInfo.Contents = "79828",
5006 
5007  [75].Function = Fac_DiversionInformation,
5008  [75].u.DiversionInformation.InvokeID = 78,
5009  [75].u.DiversionInformation.DiversionReason = 3,
5010  [75].u.DiversionInformation.BasicService = 5,
5011  [75].u.DiversionInformation.CallingAddressPresent = 1,
5012  [75].u.DiversionInformation.CallingAddress.Type = 1,
5013  [75].u.DiversionInformation.OriginalCalledPresent = 1,
5014  [75].u.DiversionInformation.OriginalCalled.Type = 2,
5015  [75].u.DiversionInformation.LastDivertingPresent = 1,
5016  [75].u.DiversionInformation.LastDiverting.Type = 1,
5017 
5018  [76].Function = Fac_DiversionInformation,
5019  [76].u.DiversionInformation.InvokeID = 79,
5020  [76].u.DiversionInformation.DiversionReason = 2,
5021  [76].u.DiversionInformation.BasicService = 3,
5022  [76].u.DiversionInformation.CallingAddressPresent = 1,
5023  [76].u.DiversionInformation.CallingAddress.Type = 2,
5024 
5025  [77].Function = Fac_DiversionInformation,
5026  [77].u.DiversionInformation.InvokeID = 80,
5027  [77].u.DiversionInformation.DiversionReason = 3,
5028  [77].u.DiversionInformation.BasicService = 5,
5029  [77].u.DiversionInformation.CallingAddressPresent = 1,
5030  [77].u.DiversionInformation.CallingAddress.Type = 3,
5031  [77].u.DiversionInformation.CallingAddress.Address.ScreeningIndicator = 2,
5032  [77].u.DiversionInformation.CallingAddress.Address.Party.Type = 4,
5033  [77].u.DiversionInformation.CallingAddress.Address.Party.LengthOfNumber = 4,
5034  [77].u.DiversionInformation.CallingAddress.Address.Party.Number = "1803",
5035 
5036  [78].Function = Fac_DiversionInformation,
5037  [78].u.DiversionInformation.InvokeID = 81,
5038  [78].u.DiversionInformation.DiversionReason = 2,
5039  [78].u.DiversionInformation.BasicService = 4,
5040  [78].u.DiversionInformation.UserInfo.Length = 5,
5041  [78].u.DiversionInformation.UserInfo.Contents = "79828",
5042 
5043  [79].Function = Fac_DiversionInformation,
5044  [79].u.DiversionInformation.InvokeID = 82,
5045  [79].u.DiversionInformation.DiversionReason = 2,
5046  [79].u.DiversionInformation.BasicService = 4,
5047 
5048  [80].Function = Fac_CallDeflection,
5049  [80].u.CallDeflection.InvokeID = 83,
5050  [80].u.CallDeflection.ComponentType = FacComponent_Invoke,
5051  [80].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
5052  [80].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
5053  [80].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
5054  [80].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1,
5055  [80].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 1,
5056 
5057  [81].Function = Fac_CallDeflection,
5058  [81].u.CallDeflection.InvokeID = 84,
5059  [81].u.CallDeflection.ComponentType = FacComponent_Invoke,
5060  [81].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
5061  [81].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
5062  [81].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
5063  [81].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1,
5064  [81].u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0,
5065 
5066  [82].Function = Fac_CallDeflection,
5067  [82].u.CallDeflection.InvokeID = 85,
5068  [82].u.CallDeflection.ComponentType = FacComponent_Invoke,
5069  [82].u.CallDeflection.Component.Invoke.Deflection.Party.Type = 4,
5070  [82].u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = 4,
5071  [82].u.CallDeflection.Component.Invoke.Deflection.Party.Number = "1803",
5072 
5073  [83].Function = Fac_CallDeflection,
5074  [83].u.CallDeflection.InvokeID = 86,
5075  [83].u.CallDeflection.ComponentType = FacComponent_Result,
5076 
5077  [84].Function = Fac_CallRerouteing,
5078  [84].u.CallRerouteing.InvokeID = 87,
5079  [84].u.CallRerouteing.ComponentType = FacComponent_Invoke,
5080  [84].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
5081  [84].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
5082  [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
5083  [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
5084  [84].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
5085  [84].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
5086  [84].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
5087  [84].u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Length = 3,
5088  [84].u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Contents = "RTG",
5089  [84].u.CallRerouteing.Component.Invoke.Q931ie.Llc.Length = 2,
5090  [84].u.CallRerouteing.Component.Invoke.Q931ie.Llc.Contents = "MY",
5091  [84].u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Length = 5,
5092  [84].u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Contents = "YEHAW",
5093  [84].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1,
5094  [84].u.CallRerouteing.Component.Invoke.SubscriptionOption = 2,
5095  [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Type = 1,
5096  [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length = 4,
5097  [84].u.CallRerouteing.Component.Invoke.CallingPartySubaddress.u.Nsap = "6492",
5098 
5099  [85].Function = Fac_CallRerouteing,
5100  [85].u.CallRerouteing.InvokeID = 88,
5101  [85].u.CallRerouteing.ComponentType = FacComponent_Invoke,
5102  [85].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
5103  [85].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
5104  [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
5105  [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
5106  [85].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
5107  [85].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
5108  [85].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
5109  [85].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1,
5110  [85].u.CallRerouteing.Component.Invoke.SubscriptionOption = 2,
5111 
5112  [86].Function = Fac_CallRerouteing,
5113  [86].u.CallRerouteing.InvokeID = 89,
5114  [86].u.CallRerouteing.ComponentType = FacComponent_Invoke,
5115  [86].u.CallRerouteing.Component.Invoke.ReroutingReason = 3,
5116  [86].u.CallRerouteing.Component.Invoke.ReroutingCounter = 2,
5117  [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 4,
5118  [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = 4,
5119  [86].u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number = "1803",
5120  [86].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 2,
5121  [86].u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents = "RT",
5122  [86].u.CallRerouteing.Component.Invoke.LastRerouting.Type = 2,
5123 
5124  [87].Function = Fac_CallRerouteing,
5125  [87].u.CallRerouteing.InvokeID = 90,
5126  [87].u.CallRerouteing.ComponentType = FacComponent_Result,
5127 
5128  [88].Function = Fac_InterrogateServedUserNumbers,
5129  [88].u.InterrogateServedUserNumbers.InvokeID = 91,
5130  [88].u.InterrogateServedUserNumbers.ComponentType = FacComponent_Invoke,
5131 
5132  [89].Function = Fac_InterrogateServedUserNumbers,
5133  [89].u.InterrogateServedUserNumbers.InvokeID = 92,
5134  [89].u.InterrogateServedUserNumbers.ComponentType = FacComponent_Result,
5135  [89].u.InterrogateServedUserNumbers.Component.Result.NumRecords = 2,
5136  [89].u.InterrogateServedUserNumbers.Component.Result.List[0].Type = 4,
5137  [89].u.InterrogateServedUserNumbers.Component.Result.List[0].LengthOfNumber = 4,
5138  [89].u.InterrogateServedUserNumbers.Component.Result.List[0].Number = "1803",
5139  [89].u.InterrogateServedUserNumbers.Component.Result.List[1].Type = 4,
5140  [89].u.InterrogateServedUserNumbers.Component.Result.List[1].LengthOfNumber = 4,
5141  [89].u.InterrogateServedUserNumbers.Component.Result.List[1].Number = "5786",
5142 
5143  [90].Function = Fac_DivertingLegInformation1,
5144  [90].u.DivertingLegInformation1.InvokeID = 93,
5145  [90].u.DivertingLegInformation1.DiversionReason = 4,
5146  [90].u.DivertingLegInformation1.SubscriptionOption = 1,
5147  [90].u.DivertingLegInformation1.DivertedToPresent = 1,
5148  [90].u.DivertingLegInformation1.DivertedTo.Type = 2,
5149 
5150  [91].Function = Fac_DivertingLegInformation1,
5151  [91].u.DivertingLegInformation1.InvokeID = 94,
5152  [91].u.DivertingLegInformation1.DiversionReason = 4,
5153  [91].u.DivertingLegInformation1.SubscriptionOption = 1,
5154 
5155  [92].Function = Fac_DivertingLegInformation2,
5156  [92].u.DivertingLegInformation2.InvokeID = 95,
5157  [92].u.DivertingLegInformation2.DiversionCounter = 3,
5158  [92].u.DivertingLegInformation2.DiversionReason = 2,
5159  [92].u.DivertingLegInformation2.DivertingPresent = 1,
5160  [92].u.DivertingLegInformation2.Diverting.Type = 2,
5161  [92].u.DivertingLegInformation2.OriginalCalledPresent = 1,
5162  [92].u.DivertingLegInformation2.OriginalCalled.Type = 1,
5163 
5164  [93].Function = Fac_DivertingLegInformation2,
5165  [93].u.DivertingLegInformation2.InvokeID = 96,
5166  [93].u.DivertingLegInformation2.DiversionCounter = 3,
5167  [93].u.DivertingLegInformation2.DiversionReason = 2,
5168  [93].u.DivertingLegInformation2.OriginalCalledPresent = 1,
5169  [93].u.DivertingLegInformation2.OriginalCalled.Type = 1,
5170 
5171  [94].Function = Fac_DivertingLegInformation2,
5172  [94].u.DivertingLegInformation2.InvokeID = 97,
5173  [94].u.DivertingLegInformation2.DiversionCounter = 1,
5174  [94].u.DivertingLegInformation2.DiversionReason = 2,
5175 
5176  [95].Function = Fac_DivertingLegInformation3,
5177  [95].u.DivertingLegInformation3.InvokeID = 98,
5178  [95].u.DivertingLegInformation3.PresentationAllowedIndicator = 1,
5179 /* *INDENT-ON* */
5180 };
5181 #endif /* defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES) */
5182 
5183 static char *handle_cli_misdn_send_facility(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5184 {
5185  const char *channame;
5186  const char *nr;
5187  struct chan_list *tmp;
5188  int port;
5189  const char *served_nr;
5190  struct misdn_bchannel dummy, *bc=&dummy;
5191  unsigned max_len;
5192 
5193  switch (cmd) {
5194  case CLI_INIT:
5195  e->command = "misdn send facility";
5196  e->usage = "Usage: misdn send facility <type> <channel|port> \"<args>\" \n"
5197  "\t type is one of:\n"
5198  "\t - calldeflect\n"
5199 #if defined(AST_MISDN_ENHANCEMENTS)
5200  "\t - callrerouting\n"
5201 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
5202  "\t - CFActivate\n"
5203  "\t - CFDeactivate\n";
5204 
5205  return NULL;
5206  case CLI_GENERATE:
5207  return complete_ch(a);
5208  }
5209 
5210  if (a->argc < 5) {
5211  return CLI_SHOWUSAGE;
5212  }
5213 
5214  if (strstr(a->argv[3], "calldeflect")) {
5215  if (a->argc < 6) {
5216  ast_verbose("calldeflect requires 1 arg: ToNumber\n\n");
5217  return 0;
5218  }
5219  channame = a->argv[4];
5220  nr = a->argv[5];
5221 
5222  ast_verbose("Sending Calldeflection (%s) to %s\n", nr, channame);
5223  tmp = get_chan_by_ast_name(channame);
5224  if (!tmp) {
5225  ast_verbose("Sending CD with nr %s to %s failed: Channel does not exist.\n", nr, channame);
5226  return 0;
5227  }
5228  ao2_lock(tmp);
5229 
5230 #if defined(AST_MISDN_ENHANCEMENTS)
5231  max_len = sizeof(tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number) - 1;
5232  if (max_len < strlen(nr)) {
5233  ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
5234  nr, channame, max_len);
5235  ao2_unlock(tmp);
5236  chan_list_unref(tmp, "Number too long");
5237  return 0;
5238  }
5239  tmp->bc->fac_out.Function = Fac_CallDeflection;
5240  tmp->bc->fac_out.u.CallDeflection.InvokeID = ++misdn_invoke_id;
5241  tmp->bc->fac_out.u.CallDeflection.ComponentType = FacComponent_Invoke;
5242  tmp->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent = 1;
5243  tmp->bc->fac_out.u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser = 0;
5244  tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Type = 0;/* unknown */
5245  tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.LengthOfNumber = strlen(nr);
5246  strcpy((char *) tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Party.Number, nr);
5247  tmp->bc->fac_out.u.CallDeflection.Component.Invoke.Deflection.Subaddress.Length = 0;
5248 
5249 #else /* !defined(AST_MISDN_ENHANCEMENTS) */
5250 
5251  max_len = sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber) - 1;
5252  if (max_len < strlen(nr)) {
5253  ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
5254  nr, channame, max_len);
5255  ao2_unlock(tmp);
5256  chan_list_unref(tmp, "Number too long");
5257  return 0;
5258  }
5259  tmp->bc->fac_out.Function = Fac_CD;
5260  tmp->bc->fac_out.u.CDeflection.PresentationAllowed = 0;
5261  //tmp->bc->fac_out.u.CDeflection.DeflectedToSubaddress[0] = 0;
5262  strcpy((char *) tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr);
5263 #endif /* !defined(AST_MISDN_ENHANCEMENTS) */
5264 
5265  /* Send message */
5266  print_facility(&tmp->bc->fac_out, tmp->bc);
5267  ao2_unlock(tmp);
5269  chan_list_unref(tmp, "Send facility complete");
5270 #if defined(AST_MISDN_ENHANCEMENTS)
5271  } else if (strstr(a->argv[3], "callrerouteing") || strstr(a->argv[3], "callrerouting")) {
5272  if (a->argc < 6) {
5273  ast_verbose("callrerouting requires 1 arg: ToNumber\n\n");
5274  return 0;
5275  }
5276  channame = a->argv[4];
5277  nr = a->argv[5];
5278 
5279  ast_verbose("Sending Callrerouting (%s) to %s\n", nr, channame);
5280  tmp = get_chan_by_ast_name(channame);
5281  if (!tmp) {
5282  ast_verbose("Sending Call Rerouting with nr %s to %s failed: Channel does not exist.\n", nr, channame);
5283  return 0;
5284  }
5285  ao2_lock(tmp);
5286 
5287  max_len = sizeof(tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number) - 1;
5288  if (max_len < strlen(nr)) {
5289  ast_verbose("Sending Call Rerouting with nr %s to %s failed: Number too long (up to %u digits are allowed).\n",
5290  nr, channame, max_len);
5291  ao2_unlock(tmp);
5292  chan_list_unref(tmp, "Number too long");
5293  return 0;
5294  }
5295  tmp->bc->fac_out.Function = Fac_CallRerouteing;
5296  tmp->bc->fac_out.u.CallRerouteing.InvokeID = ++misdn_invoke_id;
5297  tmp->bc->fac_out.u.CallRerouteing.ComponentType = FacComponent_Invoke;
5298 
5299  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingReason = 0;/* unknown */
5300  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.ReroutingCounter = 1;
5301 
5302  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Type = 0;/* unknown */
5303  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.LengthOfNumber = strlen(nr);
5304  strcpy((char *) tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Party.Number, nr);
5305  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CalledAddress.Subaddress.Length = 0;
5306 
5307  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length = 0;
5308 
5309  /* 0x90 0x90 0xa3 3.1 kHz audio, circuit mode, 64kbit/sec, level1/a-Law */
5310  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Length = 3;
5311  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[0] = 0x90;
5312  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[1] = 0x90;
5313  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Bc.Contents[2] = 0xa3;
5314  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Hlc.Length = 0;
5315  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.Llc.Length = 0;
5316  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.Q931ie.UserInfo.Length = 0;
5317 
5318  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.LastRerouting.Type = 1;/* presentationRestricted */
5319  tmp->bc->fac_out.u.CallRerouteing.Component.Invoke.SubscriptionOption = 0;/* no notification to caller */
5320 
5321  /* Send message */
5322  print_facility(&tmp->bc->fac_out, tmp->bc);
5323  ao2_unlock(tmp);
5325  chan_list_unref(tmp, "Send facility complete");
5326 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
5327  } else if (strstr(a->argv[3], "CFActivate")) {
5328  if (a->argc < 7) {
5329  ast_verbose("CFActivate requires 2 args: 1.FromNumber, 2.ToNumber\n\n");
5330  return 0;
5331  }
5332  port = atoi(a->argv[4]);
5333  served_nr = a->argv[5];
5334  nr = a->argv[6];
5335 
5336  misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
5337 
5338  ast_verbose("Sending CFActivate Port:(%d) FromNr. (%s) to Nr. (%s)\n", port, served_nr, nr);
5339 
5340 #if defined(AST_MISDN_ENHANCEMENTS)
5341  bc->fac_out.Function = Fac_ActivationDiversion;
5342  bc->fac_out.u.ActivationDiversion.InvokeID = ++misdn_invoke_id;
5343  bc->fac_out.u.ActivationDiversion.ComponentType = FacComponent_Invoke;
5344  bc->fac_out.u.ActivationDiversion.Component.Invoke.BasicService = 0;/* allServices */
5345  bc->fac_out.u.ActivationDiversion.Component.Invoke.Procedure = 0;/* cfu (Call Forward Unconditional) */
5346  ast_copy_string((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number,
5347  served_nr, sizeof(bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number));
5348  bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.LengthOfNumber =
5349  strlen((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Number);
5350  bc->fac_out.u.ActivationDiversion.Component.Invoke.ServedUser.Type = 0;/* unknown */
5351  ast_copy_string((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number,
5352  nr, sizeof(bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number));
5353  bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.LengthOfNumber =
5354  strlen((char *) bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Number);
5355  bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Party.Type = 0;/* unknown */
5356  bc->fac_out.u.ActivationDiversion.Component.Invoke.ForwardedTo.Subaddress.Length = 0;
5357 
5358 #else /* !defined(AST_MISDN_ENHANCEMENTS) */
5359 
5360  bc->fac_out.Function = Fac_CFActivate;
5361  bc->fac_out.u.CFActivate.BasicService = 0; /* All Services */
5362  bc->fac_out.u.CFActivate.Procedure = 0; /* Unconditional */
5363  ast_copy_string((char *) bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
5364  ast_copy_string((char *) bc->fac_out.u.CFActivate.ForwardedToNumber, nr, sizeof(bc->fac_out.u.CFActivate.ForwardedToNumber));
5365 #endif /* !defined(AST_MISDN_ENHANCEMENTS) */
5366 
5367  /* Send message */
5368  print_facility(&bc->fac_out, bc);
5370  } else if (strstr(a->argv[3], "CFDeactivate")) {
5371  if (a->argc < 6) {
5372  ast_verbose("CFDeactivate requires 1 arg: FromNumber\n\n");
5373  return 0;
5374  }
5375  port = atoi(a->argv[4]);
5376  served_nr = a->argv[5];
5377 
5378  misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
5379  ast_verbose("Sending CFDeactivate Port:(%d) FromNr. (%s)\n", port, served_nr);
5380 
5381 #if defined(AST_MISDN_ENHANCEMENTS)
5382  bc->fac_out.Function = Fac_DeactivationDiversion;
5383  bc->fac_out.u.DeactivationDiversion.InvokeID = ++misdn_invoke_id;
5384  bc->fac_out.u.DeactivationDiversion.ComponentType = FacComponent_Invoke;
5385  bc->fac_out.u.DeactivationDiversion.Component.Invoke.BasicService = 0;/* allServices */
5386  bc->fac_out.u.DeactivationDiversion.Component.Invoke.Procedure = 0;/* cfu (Call Forward Unconditional) */
5387  ast_copy_string((char *) bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number,
5388  served_nr, sizeof(bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number));
5389  bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.LengthOfNumber =
5390  strlen((char *) bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Number);
5391  bc->fac_out.u.DeactivationDiversion.Component.Invoke.ServedUser.Type = 0;/* unknown */
5392 
5393 #else /* !defined(AST_MISDN_ENHANCEMENTS) */
5394 
5395  bc->fac_out.Function = Fac_CFDeactivate;
5396  bc->fac_out.u.CFDeactivate.BasicService = 0; /* All Services */
5397  bc->fac_out.u.CFDeactivate.Procedure = 0; /* Unconditional */
5398  ast_copy_string((char *) bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
5399 #endif /* !defined(AST_MISDN_ENHANCEMENTS) */
5400 
5401  /* Send message */
5402  print_facility(&bc->fac_out, bc);
5404 #if defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES)
5405  } else if (strstr(a->argv[3], "test")) {
5406  int msg_number;
5407 
5408  if (a->argc < 5) {
5409  ast_verbose("test (<port> [<msg#>]) | (<channel-name> <msg#>)\n\n");
5410  return 0;
5411  }
5412  port = atoi(a->argv[4]);
5413 
5414  channame = a->argv[4];
5415  tmp = get_chan_by_ast_name(channame);
5416  if (tmp) {
5417  /* We are going to send this FACILITY message out on an existing connection */
5418  msg_number = atoi(a->argv[5]);
5419  if (msg_number < ARRAY_LEN(Fac_Msgs)) {
5420  ao2_lock(tmp);
5421  tmp->bc->fac_out = Fac_Msgs[msg_number];
5422 
5423  /* Send message */
5424  print_facility(&tmp->bc->fac_out, tmp->bc);
5425  ao2_unlock(tmp);
5427  } else {
5428  ast_verbose("test <channel-name> <msg#>\n\n");
5429  }
5430  chan_list_unref(tmp, "Facility test done");
5431  } else if (a->argc < 6) {
5432  for (msg_number = 0; msg_number < ARRAY_LEN(Fac_Msgs); ++msg_number) {
5433  misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
5434  bc->fac_out = Fac_Msgs[msg_number];
5435 
5436  /* Send message */
5437  print_facility(&bc->fac_out, bc);
5439  sleep(1);
5440  }
5441  } else {
5442  msg_number = atoi(a->argv[5]);
5443  if (msg_number < ARRAY_LEN(Fac_Msgs)) {
5444  misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
5445  bc->fac_out = Fac_Msgs[msg_number];
5446 
5447  /* Send message */
5448  print_facility(&bc->fac_out, bc);
5450  } else {
5451  ast_verbose("test <port> [<msg#>]\n\n");
5452  }
5453  }
5454  } else if (strstr(a->argv[3], "register")) {
5455  if (a->argc < 5) {
5456  ast_verbose("register <port>\n\n");
5457  return 0;
5458  }
5459  port = atoi(a->argv[4]);
5460 
5461  bc = misdn_lib_get_register_bc(port);
5462  if (!bc) {
5463  ast_verbose("Could not allocate REGISTER bc struct\n\n");
5464  return 0;
5465  }
5466  bc->fac_out = Fac_Msgs[45];
5467 
5468  /* Send message */
5469  print_facility(&bc->fac_out, bc);
5471 #endif /* defined(AST_MISDN_ENHANCEMENTS) && defined(CCBS_TEST_MESSAGES) */
5472  }
5473 
5474  return CLI_SUCCESS;
5475 }
5476 
5477 static char *handle_cli_misdn_send_restart(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5478 {
5479  int port;
5480  int channel;
5481 
5482  switch (cmd) {
5483  case CLI_INIT:
5484  e->command = "misdn send restart";
5485  e->usage =
5486  "Usage: misdn send restart [port [channel]]\n"
5487  " Send a restart for every bchannel on the given port.\n";
5488  return NULL;
5489  case CLI_GENERATE:
5490  return NULL;
5491  }
5492 
5493  if (a->argc < 4 || a->argc > 5) {
5494  return CLI_SHOWUSAGE;
5495  }
5496 
5497  port = atoi(a->argv[3]);
5498 
5499  if (a->argc == 5) {
5500  channel = atoi(a->argv[4]);
5501  misdn_lib_send_restart(port, channel);
5502  } else {
5503  misdn_lib_send_restart(port, -1);
5504  }
5505 
5506  return CLI_SUCCESS;
5507 }
5508 
5509 static char *handle_cli_misdn_send_digit(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5510 {
5511  const char *channame;
5512  const char *msg;
5513  struct chan_list *tmp;
5514  int i, msglen;
5515 
5516  switch (cmd) {
5517  case CLI_INIT:
5518  e->command = "misdn send digit";
5519  e->usage =
5520  "Usage: misdn send digit <channel> \"<msg>\" \n"
5521  " Send <digit> to <channel> as DTMF Tone\n"
5522  " when channel is a mISDN channel\n";
5523  return NULL;
5524  case CLI_GENERATE:
5525  return complete_ch(a);
5526  }
5527 
5528  if (a->argc != 5) {
5529  return CLI_SHOWUSAGE;
5530  }
5531 
5532  channame = a->argv[3];
5533  msg = a->argv[4];
5534  msglen = strlen(msg);
5535 
5536  ast_cli(a->fd, "Sending %s to %s\n", msg, channame);
5537 
5538  tmp = get_chan_by_ast_name(channame);
5539  if (!tmp) {
5540  ast_cli(a->fd, "Sending %s to %s failed Channel does not exist\n", msg, channame);
5541  return CLI_SUCCESS;
5542  }
5543 #if 1
5544  for (i = 0; i < msglen; i++) {
5545  if (!tmp->ast) {
5546  break;
5547  }
5548  ast_cli(a->fd, "Sending: %c\n", msg[i]);
5549  send_digit_to_chan(tmp, msg[i]);
5550  /* res = ast_safe_sleep(tmp->ast, 250); */
5551  usleep(250000);
5552  /* res = ast_waitfor(tmp->ast,100); */
5553  }
5554 #else
5555  if (tmp->ast) {
5556  ast_dtmf_stream(tmp->ast, NULL, msg, 250);
5557  }
5558 #endif
5559  chan_list_unref(tmp, "Digit(s) sent");
5560 
5561  return CLI_SUCCESS;
5562 }
5563 
5564 static char *handle_cli_misdn_toggle_echocancel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5565 {
5566  const char *channame;
5567  struct chan_list *tmp;
5568 
5569  switch (cmd) {
5570  case CLI_INIT:
5571  e->command = "misdn toggle echocancel";
5572  e->usage =
5573  "Usage: misdn toggle echocancel <channel>\n"
5574  " Toggle EchoCancel on mISDN Channel.\n";
5575  return NULL;
5576  case CLI_GENERATE:
5577  return complete_ch(a);
5578  }
5579 
5580  if (a->argc != 4) {
5581  return CLI_SHOWUSAGE;
5582  }
5583 
5584  channame = a->argv[3];
5585 
5586  ast_cli(a->fd, "Toggling EchoCancel on %s\n", channame);
5587 
5588  tmp = get_chan_by_ast_name(channame);
5589  if (!tmp) {
5590  ast_cli(a->fd, "Toggling EchoCancel %s failed Channel does not exist\n", channame);
5591  return CLI_SUCCESS;
5592  }
5593 
5594  tmp->toggle_ec = tmp->toggle_ec ? 0 : 1;
5595 
5596  if (tmp->toggle_ec) {
5597 #ifdef MISDN_1_2
5598  update_pipeline_config(tmp->bc);
5599 #else
5600  update_ec_config(tmp->bc);
5601 #endif
5602  manager_ec_enable(tmp->bc);
5603  } else {
5604  manager_ec_disable(tmp->bc);
5605  }
5606  chan_list_unref(tmp, "Done toggling echo cancel");
5607 
5608  return CLI_SUCCESS;
5609 }
5610 
5611 static char *handle_cli_misdn_send_display(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
5612 {
5613  const char *channame;
5614  const char *msg;
5615  struct chan_list *tmp;
5616 
5617  switch (cmd) {
5618  case CLI_INIT:
5619  e->command = "misdn send display";
5620  e->usage =
5621  "Usage: misdn send display <channel> \"<msg>\" \n"
5622  " Send <msg> to <channel> as Display Message\n"
5623  " when channel is a mISDN channel\n";
5624  return NULL;
5625  case CLI_GENERATE:
5626  return complete_ch(a);
5627  }
5628 
5629  if (a->argc != 5) {
5630  return CLI_SHOWUSAGE;
5631  }
5632 
5633  channame = a->argv[3];
5634  msg = a->argv[4];
5635 
5636  ast_cli(a->fd, "Sending %s to %s\n", msg, channame);
5637 
5638  tmp = get_chan_by_ast_name(channame);
5639  if (tmp && tmp->bc) {
5640  ast_copy_string(tmp->bc->display, msg, sizeof(tmp->bc->display));
5642  chan_list_unref(tmp, "Done sending display");
5643  } else {
5644  if (tmp) {
5645  chan_list_unref(tmp, "Display failed");
5646  }
5647  ast_cli(a->fd, "No such channel %s\n", channame);
5648  return CLI_SUCCESS;
5649  }
5650 
5651  return CLI_SUCCESS;
5652 }
5653 
5654 static char *complete_ch(struct ast_cli_args *a)
5655 {
5656  return ast_complete_channels(a->line, a->word, a->pos, a->n, 3);
5657 }
5658 
5659 static char *complete_debug_port(struct ast_cli_args *a)
5660 {
5661  if (a->n) {
5662  return NULL;
5663  }
5664 
5665  switch (a->pos) {
5666  case 4:
5667  if (a->word[0] == 'p') {
5668  return ast_strdup("port");
5669  } else if (a->word[0] == 'o') {
5670  return ast_strdup("only");
5671  }
5672  break;
5673  case 6:
5674  if (a->word[0] == 'o') {
5675  return ast_strdup("only");
5676  }
5677  break;
5678  }
5679  return NULL;
5680 }
5681 
5682 static char *complete_show_config(struct ast_cli_args *a)
5683 {
5684  char buffer[BUFFERSIZE];
5685  enum misdn_cfg_elements elem;
5686  int wordlen = strlen(a->word);
5687  int which = 0;
5688  int port = 0;
5689 
5690  switch (a->pos) {
5691  case 3:
5692  if ((!strncmp(a->word, "description", wordlen)) && (++which > a->n)) {
5693  return ast_strdup("description");
5694  }
5695  if ((!strncmp(a->word, "descriptions", wordlen)) && (++which > a->n)) {
5696  return ast_strdup("descriptions");
5697  }
5698  if ((!strncmp(a->word, "0", wordlen)) && (++which > a->n)) {
5699  return ast_strdup("0");
5700  }
5701  while ((port = misdn_cfg_get_next_port(port)) != -1) {
5702  snprintf(buffer, sizeof(buffer), "%d", port);
5703  if ((!strncmp(a->word, buffer, wordlen)) && (++which > a->n)) {
5704  return ast_strdup(buffer);
5705  }
5706  }
5707  break;
5708  case 4:
5709  if (strstr(a->line, "description ")) {
5710  for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) {
5711  if ((elem == MISDN_CFG_LAST) || (elem == MISDN_GEN_FIRST)) {
5712  continue;
5713  }
5714  misdn_cfg_get_name(elem, buffer, sizeof(buffer));
5715  if (!wordlen || !strncmp(a->word, buffer, wordlen)) {
5716  if (++which > a->n) {
5717  return ast_strdup(buffer);
5718  }
5719  }
5720  }
5721  } else if (strstr(a->line, "descriptions ")) {
5722  if ((!wordlen || !strncmp(a->word, "general", wordlen)) && (++which > a->n)) {
5723  return ast_strdup("general");
5724  }
5725  if ((!wordlen || !strncmp(a->word, "ports", wordlen)) && (++which > a->n)) {
5726  return ast_strdup("ports");
5727  }
5728  }
5729  break;
5730  }
5731  return NULL;
5732 }
5733 
5734 static struct ast_cli_entry chan_misdn_clis[] = {
5735 /* *INDENT-OFF* */
5736  AST_CLI_DEFINE(handle_cli_misdn_port_block, "Block the given port"),
5737  AST_CLI_DEFINE(handle_cli_misdn_port_down, "Try to deactivate the L1 on the given port"),
5738  AST_CLI_DEFINE(handle_cli_misdn_port_unblock, "Unblock the given port"),
5739  AST_CLI_DEFINE(handle_cli_misdn_port_up, "Try to establish L1 on the given port"),
5740  AST_CLI_DEFINE(handle_cli_misdn_reload, "Reload internal mISDN config, read from the config file"),
5741  AST_CLI_DEFINE(handle_cli_misdn_restart_pid, "Restart the given pid"),
5742  AST_CLI_DEFINE(handle_cli_misdn_restart_port, "Restart the given port"),
5743  AST_CLI_DEFINE(handle_cli_misdn_show_channel, "Show an internal mISDN channel"),
5744  AST_CLI_DEFINE(handle_cli_misdn_show_channels, "Show the internal mISDN channel list"),
5745  AST_CLI_DEFINE(handle_cli_misdn_show_config, "Show internal mISDN config, read from the config file"),
5746  AST_CLI_DEFINE(handle_cli_misdn_show_port, "Show detailed information for given port"),
5747  AST_CLI_DEFI