2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 2004 - 2006, Christian Richter
6 * Christian Richter <crich@beronet.com>
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.
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.
23 * \brief the chan_misdn channel driver for Asterisk
25 * \author Christian Richter <crich@beronet.com>
27 * MISDN http://www.misdn.org/
29 * \ingroup channel_drivers
32 /*! \li \ref chan_misdn.c uses the configuration file \ref misdn.conf
33 * \addtogroup configuration_file
36 /*! \page misdn.conf misdn.conf
37 * \verbinclude misdn.conf.sample
42 * To use the CCBS/CCNR supplementary service feature and other
43 * supplementary services using FACILITY messages requires a
44 * modified version of mISDN.
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
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
57 /* Define to enable cli commands to generate canned CCBS messages. */
58 // #define CCBS_TEST_MESSAGES 1
61 <depend>isdnnet</depend>
62 <depend>misdn</depend>
63 <depend>suppserv</depend>
64 <support_level>extended</support_level>
69 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
72 #include <sys/socket.h>
74 #include <arpa/inet.h>
76 #include <sys/ioctl.h>
79 #include <semaphore.h>
83 #include "asterisk/channel.h"
84 #include "asterisk/config.h"
85 #include "asterisk/module.h"
86 #include "asterisk/pbx.h"
87 #include "asterisk/io.h"
88 #include "asterisk/frame.h"
89 #include "asterisk/translate.h"
90 #include "asterisk/cli.h"
91 #include "asterisk/musiconhold.h"
92 #include "asterisk/dsp.h"
93 #include "asterisk/file.h"
94 #include "asterisk/callerid.h"
95 #include "asterisk/indications.h"
96 #include "asterisk/app.h"
97 #include "asterisk/features.h"
98 #include "asterisk/term.h"
99 #include "asterisk/sched.h"
100 #include "asterisk/stringfields.h"
101 #include "asterisk/abstract_jb.h"
102 #include "asterisk/causes.h"
103 #include "asterisk/format.h"
104 #include "asterisk/format_cap.h"
105 #include "asterisk/features_config.h"
107 #include "chan_misdn_config.h"
108 #include "isdn_lib.h"
110 static char global_tracefile[BUFFERSIZE + 1];
112 static int g_config_initialized = 0;
126 /*! \brief allocates the jb-structure and initialize the elements */
127 struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
129 /*! \brief frees the data and destroys the given jitterbuffer struct */
130 void misdn_jb_destroy(struct misdn_jb *jb);
132 /*! \brief fills the jitterbuffer with len data returns < 0 if there was an
133 error (buffer overrun). */
134 int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len);
136 /*! \brief gets len bytes out of the jitterbuffer if available, else only the
137 available data is returned and the return value indicates the number
139 int misdn_jb_empty(struct misdn_jb *jb, char *data, int len);
141 static char *complete_ch(struct ast_cli_args *a);
142 static char *complete_debug_port(struct ast_cli_args *a);
143 static char *complete_show_config(struct ast_cli_args *a);
145 /* BEGIN: chan_misdn.h */
147 #if defined(AST_MISDN_ENHANCEMENTS)
149 * This timeout duration is to clean up any call completion records that
150 * are forgotten about by the switch.
152 #define MISDN_CC_RECORD_AGE_MAX (6UL * 60 * 60) /* seconds */
154 #define MISDN_CC_REQUEST_WAIT_MAX 5 /* seconds */
157 * \brief Caller that initialized call completion services
160 * This data is the payload for a datastore that is put on the channel that
161 * initializes call completion services. This datastore is set to be inherited
162 * by the outbound mISDN channel. When one of these channels hangs up, the
163 * channel pointer will be set to NULL. That way, we can ensure that we do not
164 * touch this channel after it gets destroyed.
166 struct misdn_cc_caller {
167 /*! \brief The channel that initialized call completion services */
168 struct ast_channel *chan;
171 struct misdn_cc_notify {
172 /*! \brief Dialplan: Notify extension priority */
175 /*! \brief Dialplan: Notify extension context */
176 char context[AST_MAX_CONTEXT];
178 /*! \brief Dialplan: Notify extension number (User-A) */
179 char exten[AST_MAX_EXTENSION];
182 /*! \brief mISDN call completion record */
183 struct misdn_cc_record {
184 /*! \brief Call completion record linked list */
185 AST_LIST_ENTRY(misdn_cc_record) list;
187 /*! \brief Time the record was created. */
190 /*! \brief MISDN_CC_RECORD_ID value */
194 * \brief Logical Layer 1 port associated with this
195 * call completion record
199 /*! \brief TRUE if point-to-point mode (CCBS-T/CCNR-T mode) */
202 /*! \brief Mode specific parameters */
204 /*! \brief point-to-point specific parameters. */
207 * \brief Call-completion signaling link.
208 * NULL if signaling link not established.
210 struct misdn_bchannel *bc;
213 * \brief TRUE if we requested the request retention option
216 int requested_retention;
219 * \brief TRUE if the request retention option is enabled.
221 int retention_enabled;
224 /*! \brief point-to-multi-point specific parameters. */
226 /*! \brief CallLinkageID (valid when port determined) */
229 /*! \breif CCBSReference (valid when activated is TRUE) */
232 /*! \brief globalRecall(0), specificRecall(1) */
237 /*! \brief TRUE if call completion activated */
240 /*! \brief Outstanding message ID (valid when outstanding_message) */
243 /*! \brief TRUE if waiting for a response from a message (invoke_id is valid) */
244 int outstanding_message;
246 /*! \brief TRUE if activation has been requested */
247 int activation_requested;
250 * \brief TRUE if User-A is free
251 * \note PTMP - Used to answer CCBSStatusRequest.
252 * PTP - Determines how to respond to CCBS_T_RemoteUserFree.
256 /*! \brief Error code received from last outstanding message. */
257 enum FacErrorCode error_code;
259 /*! \brief Reject code received from last outstanding message. */
260 enum FacRejectCode reject_code;
263 * \brief Saved struct misdn_bchannel call information when
264 * attempted to call User-B
267 /*! \brief User-A caller id information */
268 struct misdn_party_id caller;
270 /*! \brief User-B number information */
271 struct misdn_party_dialing dialed;
273 /*! \brief The BC, HLC (optional) and LLC (optional) contents from the SETUP message. */
274 struct Q931_Bc_Hlc_Llc setup_bc_hlc_llc;
276 /*! \brief SETUP message bearer capability field code value */
279 /*! \brief TRUE if call made in digital HDLC mode */
283 /*! \brief Dialplan location to indicate User-B free and User-A is free */
284 struct misdn_cc_notify remote_user_free;
286 /*! \brief Dialplan location to indicate User-B free and User-A is busy */
287 struct misdn_cc_notify b_free;
290 /*! \brief mISDN call completion record database */
291 static AST_LIST_HEAD_STATIC(misdn_cc_records_db, misdn_cc_record);
292 /*! \brief Next call completion record ID to use */
293 static __u16 misdn_cc_record_id;
294 /*! \brief Next invoke ID to use */
295 static __s16 misdn_invoke_id;
297 static const char misdn_no_response_from_network[] = "No response from network";
298 static const char misdn_cc_record_not_found[] = "Call completion record not found";
300 /* mISDN channel variable names */
301 #define MISDN_CC_RECORD_ID "MISDN_CC_RECORD_ID"
302 #define MISDN_CC_STATUS "MISDN_CC_STATUS"
303 #define MISDN_ERROR_MSG "MISDN_ERROR_MSG"
304 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
306 static ast_mutex_t release_lock;
308 enum misdn_chan_state {
309 MISDN_NOTHING = 0, /*!< at beginning */
310 MISDN_WAITING4DIGS, /*!< when waiting for info */
311 MISDN_EXTCANTMATCH, /*!< when asterisk couldn't match our ext */
312 MISDN_INCOMING_SETUP, /*!< for incoming setup */
313 MISDN_DIALING, /*!< when pbx_start */
314 MISDN_PROGRESS, /*!< we have progress */
315 MISDN_PROCEEDING, /*!< we have progress */
316 MISDN_CALLING, /*!< when misdn_call is called */
317 MISDN_CALLING_ACKNOWLEDGE, /*!< when we get SETUP_ACK */
318 MISDN_ALERTING, /*!< when Alerting */
319 MISDN_BUSY, /*!< when BUSY */
320 MISDN_CONNECTED, /*!< when connected */
321 MISDN_DISCONNECTED, /*!< when connected */
322 MISDN_CLEANING, /*!< when hangup from * but we were connected before */
325 /*! Asterisk created the channel (outgoing call) */
327 /*! mISDN created the channel (incoming call) */
330 enum misdn_hold_state {
331 MISDN_HOLD_IDLE, /*!< HOLD not active */
332 MISDN_HOLD_ACTIVE, /*!< Call is held */
333 MISDN_HOLD_TRANSFER, /*!< Held call is being transferred */
334 MISDN_HOLD_DISCONNECT, /*!< Held call is being disconnected */
338 * \brief Call HOLD state.
340 enum misdn_hold_state state;
342 * \brief Logical port the channel call record is HELD on
343 * because the B channel is no longer associated.
348 * \brief Original B channel number the HELD call was using.
349 * \note Used only for debug display messages.
354 #define chan_list_ref(obj, debug) (ao2_t_ref((obj), +1, (debug)), (obj))
355 #define chan_list_unref(obj, debug) (ao2_t_ref((obj), -1, (debug)), NULL)
358 * \brief Channel call record structure
362 * \brief The "allowed_bearers" string read in from /etc/asterisk/misdn.conf
364 char allowed_bearers[BUFFERSIZE + 1];
367 * \brief State of the channel
369 enum misdn_chan_state state;
372 * \brief TRUE if a hangup needs to be queued
373 * \note This is a debug flag only used to catch calls to hangup_chan() that are already hungup.
375 int need_queue_hangup;
378 * \brief TRUE if a channel can be hung up by calling asterisk directly when done.
383 * \brief TRUE if we could send an AST_CONTROL_BUSY if needed.
388 * \brief Who originally created this channel. ORG_AST or ORG_MISDN
393 * \brief TRUE of we are not to respond immediately to a SETUP message. Check the dialplan first.
394 * \note The "noautorespond_on_setup" boolean read in from /etc/asterisk/misdn.conf
396 int noautorespond_on_setup;
398 int norxtone; /*!< Boolean assigned values but the value is not used. */
401 * \brief TRUE if we are not to generate tones (Playtones)
406 * \brief TRUE if echo canceller is enabled. Value is toggled.
411 * \brief TRUE if you want to send Tone Indications to an incoming
412 * ISDN channel on a TE Port.
413 * \note The "incoming_early_audio" boolean read in from /etc/asterisk/misdn.conf
415 int incoming_early_audio;
418 * \brief TRUE if DTMF digits are to be passed inband only.
419 * \note It is settable by the misdn_set_opt() application.
424 * \brief Pipe file descriptor handles array.
425 * Read from pipe[0], write to pipe[1]
430 * \brief Read buffer for inbound audio from pipe[0]
432 char ast_rd_buf[4096];
435 * \brief Inbound audio frame returned by misdn_read().
437 struct ast_frame frame;
440 * \brief Fax detection option. (0:no 1:yes 2:yes+nojump)
441 * \note The "faxdetect" option string read in from /etc/asterisk/misdn.conf
442 * \note It is settable by the misdn_set_opt() application.
447 * \brief Number of seconds to detect a Fax machine when detection enabled.
448 * \note 0 disables the timeout.
449 * \note The "faxdetect_timeout" value read in from /etc/asterisk/misdn.conf
451 int faxdetect_timeout;
454 * \brief Starting time of fax detection with timeout when nonzero.
456 struct timeval faxdetect_tv;
459 * \brief TRUE if a fax has been detected.
464 * \brief TRUE if we will use the Asterisk DSP to detect DTMF/Fax
465 * \note The "astdtmf" boolean read in from /etc/asterisk/misdn.conf
470 * \brief Jitterbuffer length
471 * \note The "jitterbuffer" value read in from /etc/asterisk/misdn.conf
476 * \brief Jitterbuffer upper threshold
477 * \note The "jitterbuffer_upper_threshold" value read in from /etc/asterisk/misdn.conf
479 int jb_upper_threshold;
482 * \brief Allocated jitterbuffer controller
483 * \note misdn_jb_init() creates the jitterbuffer.
484 * \note Must use misdn_jb_destroy() to clean up.
489 * \brief Allocated DSP controller
490 * \note ast_dsp_new() creates the DSP controller.
491 * \note Must use ast_dsp_free() to clean up.
496 * \brief Associated Asterisk channel structure.
498 struct ast_channel * ast;
501 * \brief Associated B channel structure.
503 struct misdn_bchannel *bc;
505 #if defined(AST_MISDN_ENHANCEMENTS)
507 * \brief Peer channel for which call completion was initialized.
509 struct misdn_cc_caller *peer;
511 /*! \brief Associated call completion record ID (-1 if not associated) */
513 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
516 * \brief HELD channel call information
518 struct hold_info hold;
521 * \brief From associated B channel: Layer 3 process ID
522 * \note Used to find the HELD channel call record when retrieving a call.
527 * \brief From associated B channel: B Channel mISDN driver layer ID from mISDN_get_layerid()
528 * \note Used only for debug display messages.
533 * \brief Incoming call dialplan context identifier.
534 * \note The "context" string read in from /etc/asterisk/misdn.conf
536 char context[AST_MAX_CONTEXT];
539 * \brief The configured music-on-hold class to use for this call.
540 * \note The "musicclass" string read in from /etc/asterisk/misdn.conf
542 char mohinterpret[MAX_MUSICCLASS];
545 * \brief Number of outgoing audio frames dropped since last debug gripe message.
547 int dropped_frame_cnt;
550 * \brief TRUE if we must do the ringback tones.
551 * \note The "far_alerting" boolean read in from /etc/asterisk/misdn.conf
556 * \brief TRUE if NT should disconnect an overlap dialing call when a timeout occurs.
557 * \note The "nttimeout" boolean read in from /etc/asterisk/misdn.conf
562 * \brief Tone zone sound used for dialtone generation.
563 * \note Used as a boolean. Non-NULL to prod generation if enabled.
565 struct ast_tone_zone_sound *ts;
568 * \brief Enables overlap dialing for the set amount of seconds. (0 = Disabled)
569 * \note The "overlapdial" value read in from /etc/asterisk/misdn.conf
574 * \brief Overlap dialing timeout Task ID. -1 if not running.
576 int overlap_dial_task;
579 * \brief overlap_tv access lock.
581 ast_mutex_t overlap_tv_lock;
584 * \brief Overlap timer start time. Timer restarted for every digit received.
586 struct timeval overlap_tv;
589 * \brief Next channel call record in the list.
591 struct chan_list *next;
598 void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
599 void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
600 static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame);
606 struct robin_list *next;
607 struct robin_list *prev;
609 static struct robin_list *robin = NULL;
612 static void free_robin_list(void)
614 struct robin_list *r;
615 struct robin_list *next;
617 for (r = robin, robin = NULL; r; r = next) {
624 static struct robin_list *get_robin_position(char *group)
626 struct robin_list *new;
627 struct robin_list *iter = robin;
628 for (; iter; iter = iter->next) {
629 if (!strcasecmp(iter->group, group)) {
633 new = ast_calloc(1, sizeof(*new));
637 new->group = ast_strdup(group);
652 /*! \brief the main schedule context for stuff like l1 watcher, overlap dial, ... */
653 static struct ast_sched_context *misdn_tasks = NULL;
654 static pthread_t misdn_tasks_thread;
656 static int *misdn_ports;
658 static void chan_misdn_log(int level, int port, char *tmpl, ...)
659 __attribute__((format(printf, 3, 4)));
661 static struct ast_channel *misdn_new(struct chan_list *cl, int state, char *exten, char *callerid, struct ast_format_cap *cap, const char *linkedid, int port, int c);
662 static void send_digit_to_chan(struct chan_list *cl, char digit);
664 static int pbx_start_chan(struct chan_list *ch);
666 #define MISDN_ASTERISK_TECH_PVT(ast) ast_channel_tech_pvt(ast)
667 #define MISDN_ASTERISK_TECH_PVT_SET(ast, value) ast_channel_tech_pvt_set(ast, value)
669 #include "asterisk/strings.h"
671 /* #define MISDN_DEBUG 1 */
673 static const char misdn_type[] = "mISDN";
675 static int tracing = 0;
677 /*! \brief Only alaw and mulaw is allowed for now */
678 static struct ast_format prefformat; /* AST_FORMAT_SLINEAR ; AST_FORMAT_ULAW | */
680 static int *misdn_debug;
681 static int *misdn_debug_only;
682 static int max_ports;
684 static int *misdn_in_calls;
685 static int *misdn_out_calls;
688 * \brief Global channel call record list head.
690 static struct chan_list *cl_te=NULL;
691 static ast_mutex_t cl_te_lock;
693 static enum event_response_e
694 cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);
696 static int send_cause2ast(struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch);
698 static void cl_queue_chan(struct chan_list *chan);
700 static int dialtone_indicate(struct chan_list *cl);
701 static void hanguptone_indicate(struct chan_list *cl);
702 static int stop_indicate(struct chan_list *cl);
704 static int start_bc_tones(struct chan_list *cl);
705 static int stop_bc_tones(struct chan_list *cl);
706 static void release_chan_early(struct chan_list *ch);
707 static void release_chan(struct chan_list *ch, struct misdn_bchannel *bc);
709 #if defined(AST_MISDN_ENHANCEMENTS)
710 static const char misdn_command_name[] = "misdn_command";
711 static int misdn_command_exec(struct ast_channel *chan, const char *data);
712 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
713 static int misdn_check_l2l1(struct ast_channel *chan, const char *data);
714 static int misdn_set_opt_exec(struct ast_channel *chan, const char *data);
715 static int misdn_facility_exec(struct ast_channel *chan, const char *data);
717 int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
719 void debug_numtype(int port, int numtype, char *type);
721 int add_out_calls(int port);
722 int add_in_calls(int port);
726 static int update_pipeline_config(struct misdn_bchannel *bc);
728 static int update_ec_config(struct misdn_bchannel *bc);
733 /*************** Helpers *****************/
735 static int misdn_chan_is_valid(struct chan_list *ch)
737 struct chan_list *list;
739 ast_mutex_lock(&cl_te_lock);
740 for (list = cl_te; list; list = list->next) {
742 ast_mutex_unlock(&cl_te_lock);
746 ast_mutex_unlock(&cl_te_lock);
751 /*! Returns a reference to the found chan_list. */
752 static struct chan_list *get_chan_by_ast(struct ast_channel *ast)
754 struct chan_list *tmp;
756 ast_mutex_lock(&cl_te_lock);
757 for (tmp = cl_te; tmp; tmp = tmp->next) {
758 if (tmp->ast == ast) {
759 chan_list_ref(tmp, "Found chan_list by ast");
760 ast_mutex_unlock(&cl_te_lock);
764 ast_mutex_unlock(&cl_te_lock);
769 /*! Returns a reference to the found chan_list. */
770 static struct chan_list *get_chan_by_ast_name(const char *name)
772 struct chan_list *tmp;
774 ast_mutex_lock(&cl_te_lock);
775 for (tmp = cl_te; tmp; tmp = tmp->next) {
776 if (tmp->ast && strcmp(ast_channel_name(tmp->ast), name) == 0) {
777 chan_list_ref(tmp, "Found chan_list by ast name");
778 ast_mutex_unlock(&cl_te_lock);
782 ast_mutex_unlock(&cl_te_lock);
787 #if defined(AST_MISDN_ENHANCEMENTS)
790 * \brief Destroy the misdn_cc_ds_info datastore payload
792 * \param[in] data the datastore payload, a reference to an misdn_cc_caller
795 * Since the payload is a reference to an astobj2 object, we just decrement its
796 * reference count. Before doing so, we NULL out the channel pointer inside of
797 * the misdn_cc_caller instance. This function will be called in one of two
798 * cases. In both cases, we no longer need the channel pointer:
800 * - The original channel that initialized call completion services, the same
801 * channel that is stored here, has been destroyed early. This could happen
802 * if it transferred the mISDN channel, for example.
804 * - The mISDN channel that had this datastore inherited on to it is now being
805 * destroyed. If this is the case, then the call completion events have
806 * already occurred and the appropriate channel variables have already been
807 * set on the original channel that requested call completion services.
811 static void misdn_cc_ds_destroy(void *data)
813 struct misdn_cc_caller *cc_caller = data;
816 cc_caller->chan = NULL;
817 ao2_unlock(cc_caller);
819 ao2_ref(cc_caller, -1);
821 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
823 #if defined(AST_MISDN_ENHANCEMENTS)
826 * \brief Duplicate the misdn_cc_ds_info datastore payload
828 * \param[in] data the datastore payload, a reference to an misdn_cc_caller
831 * All we need to do is bump the reference count and return the same instance.
833 * \return A reference to an instance of a misdn_cc_caller
835 static void *misdn_cc_ds_duplicate(void *data)
837 struct misdn_cc_caller *cc_caller = data;
839 ao2_ref(cc_caller, +1);
843 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
845 #if defined(AST_MISDN_ENHANCEMENTS)
846 static const struct ast_datastore_info misdn_cc_ds_info = {
848 .destroy = misdn_cc_ds_destroy,
849 .duplicate = misdn_cc_ds_duplicate,
851 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
853 #if defined(AST_MISDN_ENHANCEMENTS)
856 * \brief Set a channel var on the peer channel for call completion services
858 * \param[in] peer The peer that initialized call completion services
859 * \param[in] var The variable name to set
860 * \param[in] value The variable value to set
862 * This function may be called from outside of the channel thread. It handles
863 * the fact that the peer channel may be hung up and destroyed at any time.
867 static void misdn_cc_set_peer_var(struct misdn_cc_caller *peer, const char *var,
872 /*! \todo XXX This nastiness can go away once ast_channel is ref counted! */
873 while (peer->chan && ast_channel_trylock(peer->chan)) {
880 pbx_builtin_setvar_helper(peer->chan, var, value);
881 ast_channel_unlock(peer->chan);
886 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
888 #if defined(AST_MISDN_ENHANCEMENTS)
891 * \brief Get a reference to the CC caller if it exists
893 static struct misdn_cc_caller *misdn_cc_caller_get(struct ast_channel *chan)
895 struct ast_datastore *datastore;
896 struct misdn_cc_caller *cc_caller;
898 ast_channel_lock(chan);
900 if (!(datastore = ast_channel_datastore_find(chan, &misdn_cc_ds_info, NULL))) {
901 ast_channel_unlock(chan);
905 ao2_ref(datastore->data, +1);
906 cc_caller = datastore->data;
908 ast_channel_unlock(chan);
912 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
914 #if defined(AST_MISDN_ENHANCEMENTS)
917 * \brief Find the call completion record given the record id.
921 * \retval pointer to found call completion record
922 * \retval NULL if not found
924 * \note Assumes the misdn_cc_records_db lock is already obtained.
926 static struct misdn_cc_record *misdn_cc_find_by_id(long record_id)
928 struct misdn_cc_record *current;
930 AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
931 if (current->record_id == record_id) {
932 /* Found the record */
939 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
941 #if defined(AST_MISDN_ENHANCEMENTS)
944 * \brief Find the call completion record given the port and call linkage id.
946 * \param port Logical port number
947 * \param linkage_id Call linkage ID number from switch.
949 * \retval pointer to found call completion record
950 * \retval NULL if not found
952 * \note Assumes the misdn_cc_records_db lock is already obtained.
954 static struct misdn_cc_record *misdn_cc_find_by_linkage(int port, int linkage_id)
956 struct misdn_cc_record *current;
958 AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
959 if (current->port == port
961 && current->mode.ptmp.linkage_id == linkage_id) {
962 /* Found the record */
969 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
971 #if defined(AST_MISDN_ENHANCEMENTS)
974 * \brief Find the call completion record given the port and outstanding invocation id.
976 * \param port Logical port number
977 * \param invoke_id Outstanding message invocation ID number.
979 * \retval pointer to found call completion record
980 * \retval NULL if not found
982 * \note Assumes the misdn_cc_records_db lock is already obtained.
984 static struct misdn_cc_record *misdn_cc_find_by_invoke(int port, int invoke_id)
986 struct misdn_cc_record *current;
988 AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
989 if (current->outstanding_message
990 && current->invoke_id == invoke_id
991 && current->port == port) {
992 /* Found the record */
999 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1001 #if defined(AST_MISDN_ENHANCEMENTS)
1004 * \brief Find the call completion record given the port and CCBS reference id.
1006 * \param port Logical port number
1007 * \param reference_id CCBS reference ID number from switch.
1009 * \retval pointer to found call completion record
1010 * \retval NULL if not found
1012 * \note Assumes the misdn_cc_records_db lock is already obtained.
1014 static struct misdn_cc_record *misdn_cc_find_by_reference(int port, int reference_id)
1016 struct misdn_cc_record *current;
1018 AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
1019 if (current->activated
1020 && current->port == port
1022 && current->mode.ptmp.reference_id == reference_id) {
1023 /* Found the record */
1030 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1032 #if defined(AST_MISDN_ENHANCEMENTS)
1035 * \brief Find the call completion record given the B channel pointer
1037 * \param bc B channel control structure pointer.
1039 * \retval pointer to found call completion record
1040 * \retval NULL if not found
1042 * \note Assumes the misdn_cc_records_db lock is already obtained.
1044 static struct misdn_cc_record *misdn_cc_find_by_bc(const struct misdn_bchannel *bc)
1046 struct misdn_cc_record *current;
1049 AST_LIST_TRAVERSE(&misdn_cc_records_db, current, list) {
1051 && current->mode.ptp.bc == bc) {
1052 /* Found the record */
1062 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1064 #if defined(AST_MISDN_ENHANCEMENTS)
1067 * \brief Delete the given call completion record
1069 * \param doomed Call completion record to destroy
1073 * \note Assumes the misdn_cc_records_db lock is already obtained.
1075 static void misdn_cc_delete(struct misdn_cc_record *doomed)
1077 struct misdn_cc_record *current;
1079 AST_LIST_TRAVERSE_SAFE_BEGIN(&misdn_cc_records_db, current, list) {
1080 if (current == doomed) {
1081 AST_LIST_REMOVE_CURRENT(list);
1086 AST_LIST_TRAVERSE_SAFE_END;
1088 /* The doomed node is not in the call completion database */
1090 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1092 #if defined(AST_MISDN_ENHANCEMENTS)
1095 * \brief Delete all old call completion records
1099 * \note Assumes the misdn_cc_records_db lock is already obtained.
1101 static void misdn_cc_remove_old(void)
1103 struct misdn_cc_record *current;
1107 AST_LIST_TRAVERSE_SAFE_BEGIN(&misdn_cc_records_db, current, list) {
1108 if (MISDN_CC_RECORD_AGE_MAX < now - current->time_created) {
1109 if (current->ptp && current->mode.ptp.bc) {
1110 /* Close the old call-completion signaling link */
1111 current->mode.ptp.bc->fac_out.Function = Fac_None;
1112 current->mode.ptp.bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
1113 misdn_lib_send_event(current->mode.ptp.bc, EVENT_RELEASE_COMPLETE);
1116 /* Remove the old call completion record */
1117 AST_LIST_REMOVE_CURRENT(list);
1121 AST_LIST_TRAVERSE_SAFE_END;
1123 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1125 #if defined(AST_MISDN_ENHANCEMENTS)
1128 * \brief Allocate the next record id.
1130 * \retval New record id on success.
1131 * \retval -1 on error.
1133 * \note Assumes the misdn_cc_records_db lock is already obtained.
1135 static long misdn_cc_record_id_new(void)
1140 record_id = ++misdn_cc_record_id;
1141 first_id = record_id;
1142 while (misdn_cc_find_by_id(record_id)) {
1143 record_id = ++misdn_cc_record_id;
1144 if (record_id == first_id) {
1146 * We have a resource leak.
1147 * We should never need to allocate 64k records.
1149 chan_misdn_log(0, 0, " --> ERROR Too many call completion records!\n");
1157 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1159 #if defined(AST_MISDN_ENHANCEMENTS)
1162 * \brief Create a new call completion record
1164 * \retval pointer to new call completion record
1165 * \retval NULL if failed
1167 * \note Assumes the misdn_cc_records_db lock is already obtained.
1169 static struct misdn_cc_record *misdn_cc_new(void)
1171 struct misdn_cc_record *cc_record;
1174 misdn_cc_remove_old();
1176 cc_record = ast_calloc(1, sizeof(*cc_record));
1178 record_id = misdn_cc_record_id_new();
1179 if (record_id < 0) {
1180 ast_free(cc_record);
1184 /* Initialize the new record */
1185 cc_record->record_id = record_id;
1186 cc_record->port = -1;/* Invalid port so it will never be found this way */
1187 cc_record->invoke_id = ++misdn_invoke_id;
1188 cc_record->party_a_free = 1;/* Default User-A as free */
1189 cc_record->error_code = FacError_None;
1190 cc_record->reject_code = FacReject_None;
1191 cc_record->time_created = time(NULL);
1193 /* Insert the new record into the database */
1194 AST_LIST_INSERT_HEAD(&misdn_cc_records_db, cc_record, list);
1198 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1200 #if defined(AST_MISDN_ENHANCEMENTS)
1203 * \brief Destroy the call completion record database
1207 static void misdn_cc_destroy(void)
1209 struct misdn_cc_record *current;
1211 while ((current = AST_LIST_REMOVE_HEAD(&misdn_cc_records_db, list))) {
1212 /* Do a misdn_cc_delete(current) inline */
1216 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1218 #if defined(AST_MISDN_ENHANCEMENTS)
1221 * \brief Initialize the call completion record database
1225 static void misdn_cc_init(void)
1227 misdn_cc_record_id = 0;
1229 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1231 #if defined(AST_MISDN_ENHANCEMENTS)
1234 * \brief Check the status of an outstanding invocation request.
1236 * \param data Points to an integer containing the call completion record id.
1238 * \retval 0 if got a response.
1239 * \retval -1 if no response yet.
1241 static int misdn_cc_response_check(void *data)
1244 struct misdn_cc_record *cc_record;
1246 AST_LIST_LOCK(&misdn_cc_records_db);
1247 cc_record = misdn_cc_find_by_id(*(long *) data);
1249 if (cc_record->outstanding_message) {
1255 /* No record so there is no response to check. */
1258 AST_LIST_UNLOCK(&misdn_cc_records_db);
1260 return not_responded;
1262 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1264 #if defined(AST_MISDN_ENHANCEMENTS)
1267 * \brief Wait for a response from the switch for an outstanding
1268 * invocation request.
1270 * \param chan Asterisk channel to operate upon.
1271 * \param wait_seconds Number of seconds to wait
1272 * \param record_id Call completion record ID.
1276 static void misdn_cc_response_wait(struct ast_channel *chan, int wait_seconds, long record_id)
1280 for (count = 2 * MISDN_CC_REQUEST_WAIT_MAX; count--;) {
1281 /* Sleep in 500 ms increments */
1282 if (ast_safe_sleep_conditional(chan, 500, misdn_cc_response_check, &record_id) != 0) {
1283 /* We got hung up or our response came in. */
1288 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1290 #if defined(AST_MISDN_ENHANCEMENTS)
1293 * \brief Convert the mISDN reject code to a string
1295 * \param code mISDN reject code.
1297 * \return The mISDN reject code as a string
1299 static const char *misdn_to_str_reject_code(enum FacRejectCode code)
1301 static const struct {
1302 enum FacRejectCode code;
1306 { FacReject_None, "No reject occurred" },
1307 { FacReject_Unknown, "Unknown reject code" },
1309 { FacReject_Gen_UnrecognizedComponent, "General: Unrecognized Component" },
1310 { FacReject_Gen_MistypedComponent, "General: Mistyped Component" },
1311 { FacReject_Gen_BadlyStructuredComponent, "General: Badly Structured Component" },
1313 { FacReject_Inv_DuplicateInvocation, "Invoke: Duplicate Invocation" },
1314 { FacReject_Inv_UnrecognizedOperation, "Invoke: Unrecognized Operation" },
1315 { FacReject_Inv_MistypedArgument, "Invoke: Mistyped Argument" },
1316 { FacReject_Inv_ResourceLimitation, "Invoke: Resource Limitation" },
1317 { FacReject_Inv_InitiatorReleasing, "Invoke: Initiator Releasing" },
1318 { FacReject_Inv_UnrecognizedLinkedID, "Invoke: Unrecognized Linked ID" },
1319 { FacReject_Inv_LinkedResponseUnexpected, "Invoke: Linked Response Unexpected" },
1320 { FacReject_Inv_UnexpectedChildOperation, "Invoke: Unexpected Child Operation" },
1322 { FacReject_Res_UnrecognizedInvocation, "Result: Unrecognized Invocation" },
1323 { FacReject_Res_ResultResponseUnexpected, "Result: Result Response Unexpected" },
1324 { FacReject_Res_MistypedResult, "Result: Mistyped Result" },
1326 { FacReject_Err_UnrecognizedInvocation, "Error: Unrecognized Invocation" },
1327 { FacReject_Err_ErrorResponseUnexpected, "Error: Error Response Unexpected" },
1328 { FacReject_Err_UnrecognizedError, "Error: Unrecognized Error" },
1329 { FacReject_Err_UnexpectedError, "Error: Unexpected Error" },
1330 { FacReject_Err_MistypedParameter, "Error: Mistyped Parameter" },
1336 for (index = 0; index < ARRAY_LEN(arr); ++index) {
1337 if (arr[index].code == code) {
1338 return arr[index].name;
1344 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1346 #if defined(AST_MISDN_ENHANCEMENTS)
1349 * \brief Convert the mISDN error code to a string
1351 * \param code mISDN error code.
1353 * \return The mISDN error code as a string
1355 static const char *misdn_to_str_error_code(enum FacErrorCode code)
1357 static const struct {
1358 enum FacErrorCode code;
1362 { FacError_None, "No error occurred" },
1363 { FacError_Unknown, "Unknown OID error code" },
1365 { FacError_Gen_NotSubscribed, "General: Not Subscribed" },
1366 { FacError_Gen_NotAvailable, "General: Not Available" },
1367 { FacError_Gen_NotImplemented, "General: Not Implemented" },
1368 { FacError_Gen_InvalidServedUserNr, "General: Invalid Served User Number" },
1369 { FacError_Gen_InvalidCallState, "General: Invalid Call State" },
1370 { FacError_Gen_BasicServiceNotProvided, "General: Basic Service Not Provided" },
1371 { FacError_Gen_NotIncomingCall, "General: Not Incoming Call" },
1372 { FacError_Gen_SupplementaryServiceInteractionNotAllowed,"General: Supplementary Service Interaction Not Allowed" },
1373 { FacError_Gen_ResourceUnavailable, "General: Resource Unavailable" },
1375 { FacError_Div_InvalidDivertedToNr, "Diversion: Invalid Diverted To Number" },
1376 { FacError_Div_SpecialServiceNr, "Diversion: Special Service Number" },
1377 { FacError_Div_DiversionToServedUserNr, "Diversion: Diversion To Served User Number" },
1378 { FacError_Div_IncomingCallAccepted, "Diversion: Incoming Call Accepted" },
1379 { FacError_Div_NumberOfDiversionsExceeded, "Diversion: Number Of Diversions Exceeded" },
1380 { FacError_Div_NotActivated, "Diversion: Not Activated" },
1381 { FacError_Div_RequestAlreadyAccepted, "Diversion: Request Already Accepted" },
1383 { FacError_AOC_NoChargingInfoAvailable, "AOC: No Charging Info Available" },
1385 { FacError_CCBS_InvalidCallLinkageID, "CCBS: Invalid Call Linkage ID" },
1386 { FacError_CCBS_InvalidCCBSReference, "CCBS: Invalid CCBS Reference" },
1387 { FacError_CCBS_LongTermDenial, "CCBS: Long Term Denial" },
1388 { FacError_CCBS_ShortTermDenial, "CCBS: Short Term Denial" },
1389 { FacError_CCBS_IsAlreadyActivated, "CCBS: Is Already Activated" },
1390 { FacError_CCBS_AlreadyAccepted, "CCBS: Already Accepted" },
1391 { FacError_CCBS_OutgoingCCBSQueueFull, "CCBS: Outgoing CCBS Queue Full" },
1392 { FacError_CCBS_CallFailureReasonNotBusy, "CCBS: Call Failure Reason Not Busy" },
1393 { FacError_CCBS_NotReadyForCall, "CCBS: Not Ready For Call" },
1395 { FacError_CCBS_T_LongTermDenial, "CCBS-T: Long Term Denial" },
1396 { FacError_CCBS_T_ShortTermDenial, "CCBS-T: Short Term Denial" },
1398 { FacError_ECT_LinkIdNotAssignedByNetwork, "ECT: Link ID Not Assigned By Network" },
1404 for (index = 0; index < ARRAY_LEN(arr); ++index) {
1405 if (arr[index].code == code) {
1406 return arr[index].name;
1412 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1414 #if defined(AST_MISDN_ENHANCEMENTS)
1417 * \brief Convert mISDN redirecting reason to diversion reason.
1419 * \param reason mISDN redirecting reason code.
1421 * \return Supported diversion reason code.
1423 static unsigned misdn_to_diversion_reason(enum mISDN_REDIRECTING_REASON reason)
1425 unsigned diversion_reason;
1428 case mISDN_REDIRECTING_REASON_CALL_FWD:
1429 diversion_reason = 1;/* cfu */
1431 case mISDN_REDIRECTING_REASON_CALL_FWD_BUSY:
1432 diversion_reason = 2;/* cfb */
1434 case mISDN_REDIRECTING_REASON_NO_REPLY:
1435 diversion_reason = 3;/* cfnr */
1438 diversion_reason = 0;/* unknown */
1442 return diversion_reason;
1444 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1446 #if defined(AST_MISDN_ENHANCEMENTS)
1449 * \brief Convert diversion reason to mISDN redirecting reason
1451 * \param diversion_reason Diversion reason to convert
1453 * \return Supported redirecting reason code.
1455 static enum mISDN_REDIRECTING_REASON diversion_reason_to_misdn(unsigned diversion_reason)
1457 enum mISDN_REDIRECTING_REASON reason;
1459 switch (diversion_reason) {
1461 reason = mISDN_REDIRECTING_REASON_CALL_FWD;
1464 reason = mISDN_REDIRECTING_REASON_CALL_FWD_BUSY;
1467 reason = mISDN_REDIRECTING_REASON_NO_REPLY;
1470 reason = mISDN_REDIRECTING_REASON_UNKNOWN;
1476 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1478 #if defined(AST_MISDN_ENHANCEMENTS)
1481 * \brief Convert the mISDN presentation to PresentedNumberUnscreened type
1483 * \param presentation mISDN presentation to convert
1484 * \param number_present TRUE if the number is present
1486 * \return PresentedNumberUnscreened type
1488 static unsigned misdn_to_PresentedNumberUnscreened_type(int presentation, int number_present)
1492 switch (presentation) {
1493 case 0:/* allowed */
1494 if (number_present) {
1495 type = 0;/* presentationAllowedNumber */
1497 type = 2;/* numberNotAvailableDueToInterworking */
1500 case 1:/* restricted */
1501 if (number_present) {
1502 type = 3;/* presentationRestrictedNumber */
1504 type = 1;/* presentationRestricted */
1508 type = 2;/* numberNotAvailableDueToInterworking */
1514 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1516 #if defined(AST_MISDN_ENHANCEMENTS)
1519 * \brief Convert the PresentedNumberUnscreened type to mISDN presentation
1521 * \param type PresentedNumberUnscreened type
1523 * \return mISDN presentation
1525 static int PresentedNumberUnscreened_to_misdn_pres(unsigned type)
1531 case 0:/* presentationAllowedNumber */
1532 presentation = 0;/* allowed */
1535 case 1:/* presentationRestricted */
1536 case 3:/* presentationRestrictedNumber */
1537 presentation = 1;/* restricted */
1540 case 2:/* numberNotAvailableDueToInterworking */
1541 presentation = 2;/* unavailable */
1545 return presentation;
1547 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1549 #if defined(AST_MISDN_ENHANCEMENTS)
1552 * \brief Convert the mISDN numbering plan to PartyNumber numbering plan
1554 * \param number_plan mISDN numbering plan
1556 * \return PartyNumber numbering plan
1558 static unsigned misdn_to_PartyNumber_plan(enum mISDN_NUMBER_PLAN number_plan)
1560 unsigned party_plan;
1562 switch (number_plan) {
1564 case NUMPLAN_UNKNOWN:
1565 party_plan = 0;/* unknown */
1569 party_plan = 1;/* public */
1573 party_plan = 3;/* data */
1577 party_plan = 4;/* telex */
1580 case NUMPLAN_NATIONAL:
1581 party_plan = 8;/* nationalStandard */
1584 case NUMPLAN_PRIVATE:
1585 party_plan = 5;/* private */
1591 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1593 #if defined(AST_MISDN_ENHANCEMENTS)
1596 * \brief Convert PartyNumber numbering plan to mISDN numbering plan
1598 * \param party_plan PartyNumber numbering plan
1600 * \return mISDN numbering plan
1602 static enum mISDN_NUMBER_PLAN PartyNumber_to_misdn_plan(unsigned party_plan)
1604 enum mISDN_NUMBER_PLAN number_plan;
1606 switch (party_plan) {
1608 case 0:/* unknown */
1609 number_plan = NUMPLAN_UNKNOWN;
1612 number_plan = NUMPLAN_ISDN;
1615 number_plan = NUMPLAN_DATA;
1618 number_plan = NUMPLAN_TELEX;
1620 case 8:/* nationalStandard */
1621 number_plan = NUMPLAN_NATIONAL;
1623 case 5:/* private */
1624 number_plan = NUMPLAN_PRIVATE;
1630 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1632 #if defined(AST_MISDN_ENHANCEMENTS)
1635 * \brief Convert mISDN type-of-number to PartyNumber public type-of-number
1637 * \param ton mISDN type-of-number
1639 * \return PartyNumber public type-of-number
1641 static unsigned misdn_to_PartyNumber_ton_public(enum mISDN_NUMBER_TYPE ton)
1647 case NUMTYPE_UNKNOWN:
1648 party_ton = 0;/* unknown */
1651 case NUMTYPE_INTERNATIONAL:
1652 party_ton = 1;/* internationalNumber */
1655 case NUMTYPE_NATIONAL:
1656 party_ton = 2;/* nationalNumber */
1659 case NUMTYPE_NETWORK_SPECIFIC:
1660 party_ton = 3;/* networkSpecificNumber */
1663 case NUMTYPE_SUBSCRIBER:
1664 party_ton = 4;/* subscriberNumber */
1667 case NUMTYPE_ABBREVIATED:
1668 party_ton = 6;/* abbreviatedNumber */
1674 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1676 #if defined(AST_MISDN_ENHANCEMENTS)
1679 * \brief Convert the PartyNumber public type-of-number to mISDN type-of-number
1681 * \param party_ton PartyNumber public type-of-number
1683 * \return mISDN type-of-number
1685 static enum mISDN_NUMBER_TYPE PartyNumber_to_misdn_ton_public(unsigned party_ton)
1687 enum mISDN_NUMBER_TYPE ton;
1689 switch (party_ton) {
1691 case 0:/* unknown */
1692 ton = NUMTYPE_UNKNOWN;
1695 case 1:/* internationalNumber */
1696 ton = NUMTYPE_INTERNATIONAL;
1699 case 2:/* nationalNumber */
1700 ton = NUMTYPE_NATIONAL;
1703 case 3:/* networkSpecificNumber */
1704 ton = NUMTYPE_NETWORK_SPECIFIC;
1707 case 4:/* subscriberNumber */
1708 ton = NUMTYPE_SUBSCRIBER;
1711 case 6:/* abbreviatedNumber */
1712 ton = NUMTYPE_ABBREVIATED;
1718 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1720 #if defined(AST_MISDN_ENHANCEMENTS)
1723 * \brief Convert mISDN type-of-number to PartyNumber private type-of-number
1725 * \param ton mISDN type-of-number
1727 * \return PartyNumber private type-of-number
1729 static unsigned misdn_to_PartyNumber_ton_private(enum mISDN_NUMBER_TYPE ton)
1735 case NUMTYPE_UNKNOWN:
1736 party_ton = 0;/* unknown */
1739 case NUMTYPE_INTERNATIONAL:
1740 party_ton = 1;/* level2RegionalNumber */
1743 case NUMTYPE_NATIONAL:
1744 party_ton = 2;/* level1RegionalNumber */
1747 case NUMTYPE_NETWORK_SPECIFIC:
1748 party_ton = 3;/* pTNSpecificNumber */
1751 case NUMTYPE_SUBSCRIBER:
1752 party_ton = 4;/* localNumber */
1755 case NUMTYPE_ABBREVIATED:
1756 party_ton = 6;/* abbreviatedNumber */
1762 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1764 #if defined(AST_MISDN_ENHANCEMENTS)
1767 * \brief Convert the PartyNumber private type-of-number to mISDN type-of-number
1769 * \param party_ton PartyNumber private type-of-number
1771 * \return mISDN type-of-number
1773 static enum mISDN_NUMBER_TYPE PartyNumber_to_misdn_ton_private(unsigned party_ton)
1775 enum mISDN_NUMBER_TYPE ton;
1777 switch (party_ton) {
1779 case 0:/* unknown */
1780 ton = NUMTYPE_UNKNOWN;
1783 case 1:/* level2RegionalNumber */
1784 ton = NUMTYPE_INTERNATIONAL;
1787 case 2:/* level1RegionalNumber */
1788 ton = NUMTYPE_NATIONAL;
1791 case 3:/* pTNSpecificNumber */
1792 ton = NUMTYPE_NETWORK_SPECIFIC;
1795 case 4:/* localNumber */
1796 ton = NUMTYPE_SUBSCRIBER;
1799 case 6:/* abbreviatedNumber */
1800 ton = NUMTYPE_ABBREVIATED;
1806 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
1810 * \brief Convert the mISDN type of number code to a string
1812 * \param number_type mISDN type of number code.
1814 * \return The mISDN type of number code as a string
1816 static const char *misdn_to_str_ton(enum mISDN_NUMBER_TYPE number_type)
1820 switch (number_type) {
1822 case NUMTYPE_UNKNOWN:
1826 case NUMTYPE_INTERNATIONAL:
1827 str = "International";
1830 case NUMTYPE_NATIONAL:
1834 case NUMTYPE_NETWORK_SPECIFIC:
1835 str = "Network Specific";
1838 case NUMTYPE_SUBSCRIBER:
1842 case NUMTYPE_ABBREVIATED:
1843 str = "Abbreviated";
1852 * \brief Convert the mISDN type of number code to Asterisk type of number code
1854 * \param number_type mISDN type of number code.
1856 * \return Asterisk type of number code
1858 static int misdn_to_ast_ton(enum mISDN_NUMBER_TYPE number_type)
1860 int ast_number_type;
1862 switch (number_type) {
1864 case NUMTYPE_UNKNOWN:
1865 ast_number_type = NUMTYPE_UNKNOWN << 4;
1868 case NUMTYPE_INTERNATIONAL:
1869 ast_number_type = NUMTYPE_INTERNATIONAL << 4;
1872 case NUMTYPE_NATIONAL:
1873 ast_number_type = NUMTYPE_NATIONAL << 4;
1876 case NUMTYPE_NETWORK_SPECIFIC:
1877 ast_number_type = NUMTYPE_NETWORK_SPECIFIC << 4;
1880 case NUMTYPE_SUBSCRIBER:
1881 ast_number_type = NUMTYPE_SUBSCRIBER << 4;
1884 case NUMTYPE_ABBREVIATED:
1885 ast_number_type = NUMTYPE_ABBREVIATED << 4;
1889 return ast_number_type;
1894 * \brief Convert the Asterisk type of number code to mISDN type of number code
1896 * \param ast_number_type Asterisk type of number code.
1898 * \return mISDN type of number code
1900 static enum mISDN_NUMBER_TYPE ast_to_misdn_ton(unsigned ast_number_type)
1902 enum mISDN_NUMBER_TYPE number_type;
1904 switch ((ast_number_type >> 4) & 0x07) {
1906 case NUMTYPE_UNKNOWN:
1907 number_type = NUMTYPE_UNKNOWN;
1910 case NUMTYPE_INTERNATIONAL:
1911 number_type = NUMTYPE_INTERNATIONAL;
1914 case NUMTYPE_NATIONAL:
1915 number_type = NUMTYPE_NATIONAL;
1918 case NUMTYPE_NETWORK_SPECIFIC:
1919 number_type = NUMTYPE_NETWORK_SPECIFIC;
1922 case NUMTYPE_SUBSCRIBER:
1923 number_type = NUMTYPE_SUBSCRIBER;
1926 case NUMTYPE_ABBREVIATED:
1927 number_type = NUMTYPE_ABBREVIATED;
1936 * \brief Convert the mISDN numbering plan code to a string
1938 * \param number_plan mISDN numbering plan code.
1940 * \return The mISDN numbering plan code as a string
1942 static const char *misdn_to_str_plan(enum mISDN_NUMBER_PLAN number_plan)
1946 switch (number_plan) {
1948 case NUMPLAN_UNKNOWN:
1964 case NUMPLAN_NATIONAL:
1968 case NUMPLAN_PRIVATE:
1978 * \brief Convert the mISDN numbering plan code to Asterisk numbering plan code
1980 * \param number_plan mISDN numbering plan code.
1982 * \return Asterisk numbering plan code
1984 static int misdn_to_ast_plan(enum mISDN_NUMBER_PLAN number_plan)
1986 int ast_number_plan;
1988 switch (number_plan) {
1990 case NUMPLAN_UNKNOWN:
1991 ast_number_plan = NUMPLAN_UNKNOWN;
1995 ast_number_plan = NUMPLAN_ISDN;
1999 ast_number_plan = NUMPLAN_DATA;
2003 ast_number_plan = NUMPLAN_TELEX;
2006 case NUMPLAN_NATIONAL:
2007 ast_number_plan = NUMPLAN_NATIONAL;
2010 case NUMPLAN_PRIVATE:
2011 ast_number_plan = NUMPLAN_PRIVATE;
2015 return ast_number_plan;
2020 * \brief Convert the Asterisk numbering plan code to mISDN numbering plan code
2022 * \param ast_number_plan Asterisk numbering plan code.
2024 * \return mISDN numbering plan code
2026 static enum mISDN_NUMBER_PLAN ast_to_misdn_plan(unsigned ast_number_plan)
2028 enum mISDN_NUMBER_PLAN number_plan;
2030 switch (ast_number_plan & 0x0F) {
2032 case NUMPLAN_UNKNOWN:
2033 number_plan = NUMPLAN_UNKNOWN;
2037 number_plan = NUMPLAN_ISDN;
2041 number_plan = NUMPLAN_DATA;
2045 number_plan = NUMPLAN_TELEX;
2048 case NUMPLAN_NATIONAL:
2049 number_plan = NUMPLAN_NATIONAL;
2052 case NUMPLAN_PRIVATE:
2053 number_plan = NUMPLAN_PRIVATE;
2062 * \brief Convert the mISDN presentation code to a string
2064 * \param presentation mISDN number presentation restriction code.
2066 * \return The mISDN presentation code as a string
2068 static const char *misdn_to_str_pres(int presentation)
2072 switch (presentation) {
2082 str = "Unavailable";
2095 * \brief Convert the mISDN presentation code to Asterisk presentation code
2097 * \param presentation mISDN number presentation restriction code.
2099 * \return Asterisk presentation code
2101 static int misdn_to_ast_pres(int presentation)
2103 switch (presentation) {
2106 presentation = AST_PRES_ALLOWED;
2110 presentation = AST_PRES_RESTRICTED;
2114 presentation = AST_PRES_UNAVAILABLE;
2118 return presentation;
2123 * \brief Convert the Asterisk presentation code to mISDN presentation code
2125 * \param presentation Asterisk number presentation restriction code.
2127 * \return mISDN presentation code
2129 static int ast_to_misdn_pres(int presentation)
2131 switch (presentation & AST_PRES_RESTRICTION) {
2133 case AST_PRES_ALLOWED:
2137 case AST_PRES_RESTRICTED:
2141 case AST_PRES_UNAVAILABLE:
2146 return presentation;
2151 * \brief Convert the mISDN screening code to a string
2153 * \param screening mISDN number screening code.
2155 * \return The mISDN screening code as a string
2157 static const char *misdn_to_str_screen(int screening)
2161 switch (screening) {
2167 str = "Passed Screen";
2171 str = "Failed Screen";
2175 str = "Network Number";
2188 * \brief Convert the mISDN screening code to Asterisk screening code
2190 * \param screening mISDN number screening code.
2192 * \return Asterisk screening code
2194 static int misdn_to_ast_screen(int screening)
2196 switch (screening) {
2199 screening = AST_PRES_USER_NUMBER_UNSCREENED;
2203 screening = AST_PRES_USER_NUMBER_PASSED_SCREEN;
2207 screening = AST_PRES_USER_NUMBER_FAILED_SCREEN;
2211 screening = AST_PRES_NETWORK_NUMBER;
2220 * \brief Convert the Asterisk screening code to mISDN screening code
2222 * \param screening Asterisk number screening code.
2224 * \return mISDN screening code
2226 static int ast_to_misdn_screen(int screening)
2228 switch (screening & AST_PRES_NUMBER_TYPE) {
2230 case AST_PRES_USER_NUMBER_UNSCREENED:
2234 case AST_PRES_USER_NUMBER_PASSED_SCREEN:
2238 case AST_PRES_USER_NUMBER_FAILED_SCREEN:
2242 case AST_PRES_NETWORK_NUMBER:
2252 * \brief Convert Asterisk redirecting reason to mISDN redirecting reason code.
2254 * \param ast Asterisk redirecting reason code.
2256 * \return mISDN reason code
2258 static enum mISDN_REDIRECTING_REASON ast_to_misdn_reason(const enum AST_REDIRECTING_REASON ast)
2262 static const struct misdn_reasons {
2263 enum AST_REDIRECTING_REASON ast;
2264 enum mISDN_REDIRECTING_REASON q931;
2265 } misdn_reason_table[] = {
2267 { AST_REDIRECTING_REASON_UNKNOWN, mISDN_REDIRECTING_REASON_UNKNOWN },
2268 { AST_REDIRECTING_REASON_USER_BUSY, mISDN_REDIRECTING_REASON_CALL_FWD_BUSY },
2269 { AST_REDIRECTING_REASON_NO_ANSWER, mISDN_REDIRECTING_REASON_NO_REPLY },
2270 { AST_REDIRECTING_REASON_UNAVAILABLE, mISDN_REDIRECTING_REASON_NO_REPLY },
2271 { AST_REDIRECTING_REASON_UNCONDITIONAL, mISDN_REDIRECTING_REASON_CALL_FWD },
2272 { AST_REDIRECTING_REASON_TIME_OF_DAY, mISDN_REDIRECTING_REASON_UNKNOWN },
2273 { AST_REDIRECTING_REASON_DO_NOT_DISTURB, mISDN_REDIRECTING_REASON_UNKNOWN },
2274 { AST_REDIRECTING_REASON_DEFLECTION, mISDN_REDIRECTING_REASON_DEFLECTION },
2275 { AST_REDIRECTING_REASON_FOLLOW_ME, mISDN_REDIRECTING_REASON_UNKNOWN },
2276 { AST_REDIRECTING_REASON_OUT_OF_ORDER, mISDN_REDIRECTING_REASON_OUT_OF_ORDER },
2277 { AST_REDIRECTING_REASON_AWAY, mISDN_REDIRECTING_REASON_UNKNOWN },
2278 { AST_REDIRECTING_REASON_CALL_FWD_DTE, mISDN_REDIRECTING_REASON_CALL_FWD_DTE }
2282 for (index = 0; index < ARRAY_LEN(misdn_reason_table); ++index) {
2283 if (misdn_reason_table[index].ast == ast) {
2284 return misdn_reason_table[index].q931;
2287 return mISDN_REDIRECTING_REASON_UNKNOWN;
2292 * \brief Convert the mISDN redirecting reason to Asterisk redirecting reason code
2294 * \param q931 mISDN redirecting reason code.
2296 * \return Asterisk redirecting reason code
2298 static enum AST_REDIRECTING_REASON misdn_to_ast_reason(const enum mISDN_REDIRECTING_REASON q931)
2300 enum AST_REDIRECTING_REASON ast;
2304 case mISDN_REDIRECTING_REASON_UNKNOWN:
2305 ast = AST_REDIRECTING_REASON_UNKNOWN;
2308 case mISDN_REDIRECTING_REASON_CALL_FWD_BUSY:
2309 ast = AST_REDIRECTING_REASON_USER_BUSY;
2312 case mISDN_REDIRECTING_REASON_NO_REPLY:
2313 ast = AST_REDIRECTING_REASON_NO_ANSWER;
2316 case mISDN_REDIRECTING_REASON_DEFLECTION:
2317 ast = AST_REDIRECTING_REASON_DEFLECTION;
2320 case mISDN_REDIRECTING_REASON_OUT_OF_ORDER:
2321 ast = AST_REDIRECTING_REASON_OUT_OF_ORDER;
2324 case mISDN_REDIRECTING_REASON_CALL_FWD_DTE:
2325 ast = AST_REDIRECTING_REASON_CALL_FWD_DTE;
2328 case mISDN_REDIRECTING_REASON_CALL_FWD:
2329 ast = AST_REDIRECTING_REASON_UNCONDITIONAL;
2338 struct allowed_bearers {
2339 char *name; /*!< Bearer capability name string used in /etc/misdn.conf allowed_bearers */
2340 char *display; /*!< Bearer capability displayable name */
2341 int cap; /*!< SETUP message bearer capability field code value */
2342 int deprecated; /*!< TRUE if this entry is deprecated. (Misspelled or bad name to use) */
2346 static const struct allowed_bearers allowed_bearers_array[] = {
2347 /* Name, Displayable Name Bearer Capability, Deprecated */
2348 { "speech", "Speech", INFO_CAPABILITY_SPEECH, 0 },
2349 { "3_1khz", "3.1KHz Audio", INFO_CAPABILITY_AUDIO_3_1K, 0 },
2350 { "digital_unrestricted", "Unrestricted Digital", INFO_CAPABILITY_DIGITAL_UNRESTRICTED, 0 },
2351 { "digital_restricted", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 0 },
2352 { "digital_restriced", "Restricted Digital", INFO_CAPABILITY_DIGITAL_RESTRICTED, 1 }, /* Allow misspelling for backwards compatibility */
2353 { "video", "Video", INFO_CAPABILITY_VIDEO, 0 }
2357 static const char *bearer2str(int cap)
2361 for (index = 0; index < ARRAY_LEN(allowed_bearers_array); ++index) {
2362 if (allowed_bearers_array[index].cap == cap) {
2363 return allowed_bearers_array[index].display;
2367 return "Unknown Bearer";
2370 #if defined(AST_MISDN_ENHANCEMENTS)
2373 * \brief Fill in facility PartyNumber information
2375 * \param party PartyNumber structure to fill in.
2376 * \param id Information to put in PartyNumber structure.
2380 static void misdn_PartyNumber_fill(struct FacPartyNumber *party, const struct misdn_party_id *id)
2382 ast_copy_string((char *) party->Number, id->number, sizeof(party->Number));
2383 party->LengthOfNumber = strlen((char *) party->Number);
2384 party->Type = misdn_to_PartyNumber_plan(id->number_plan);
2385 switch (party->Type) {
2387 party->TypeOfNumber = misdn_to_PartyNumber_ton_public(id->number_type);
2389 case 5:/* private */
2390 party->TypeOfNumber = misdn_to_PartyNumber_ton_private(id->number_type);
2393 party->TypeOfNumber = 0;/* Don't care */
2397 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2399 #if defined(AST_MISDN_ENHANCEMENTS)
2402 * \brief Extract the information from PartyNumber
2404 * \param id Where to put extracted PartyNumber information
2405 * \param party PartyNumber information to extract
2409 static void misdn_PartyNumber_extract(struct misdn_party_id *id, const struct FacPartyNumber *party)
2411 if (party->LengthOfNumber) {
2412 ast_copy_string(id->number, (char *) party->Number, sizeof(id->number));
2413 id->number_plan = PartyNumber_to_misdn_plan(party->Type);
2414 switch (party->Type) {
2416 id->number_type = PartyNumber_to_misdn_ton_public(party->TypeOfNumber);
2418 case 5:/* private */
2419 id->number_type = PartyNumber_to_misdn_ton_private(party->TypeOfNumber);
2422 id->number_type = NUMTYPE_UNKNOWN;
2426 /* Number not present */
2427 id->number_type = NUMTYPE_UNKNOWN;
2428 id->number_plan = NUMPLAN_ISDN;
2432 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2434 #if defined(AST_MISDN_ENHANCEMENTS)
2437 * \brief Fill in facility Address information
2439 * \param Address Address structure to fill in.
2440 * \param id Information to put in Address structure.
2444 static void misdn_Address_fill(struct FacAddress *Address, const struct misdn_party_id *id)
2446 misdn_PartyNumber_fill(&Address->Party, id);
2448 /* Subaddresses are not supported yet */
2449 Address->Subaddress.Length = 0;
2451 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2453 #if defined(AST_MISDN_ENHANCEMENTS)
2456 * \brief Fill in facility PresentedNumberUnscreened information
2458 * \param presented PresentedNumberUnscreened structure to fill in.
2459 * \param id Information to put in PresentedNumberUnscreened structure.
2463 static void misdn_PresentedNumberUnscreened_fill(struct FacPresentedNumberUnscreened *presented, const struct misdn_party_id *id)
2465 presented->Type = misdn_to_PresentedNumberUnscreened_type(id->presentation, id->number[0] ? 1 : 0);
2466 misdn_PartyNumber_fill(&presented->Unscreened, id);
2468 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2470 #if defined(AST_MISDN_ENHANCEMENTS)
2473 * \brief Extract the information from PartyNumber
2475 * \param id Where to put extracted PresentedNumberUnscreened information
2476 * \param presented PresentedNumberUnscreened information to extract
2480 static void misdn_PresentedNumberUnscreened_extract(struct misdn_party_id *id, const struct FacPresentedNumberUnscreened *presented)
2482 id->presentation = PresentedNumberUnscreened_to_misdn_pres(presented->Type);
2483 id->screening = 0;/* unscreened */
2484 switch (presented->Type) {
2485 case 0:/* presentationAllowedNumber */
2486 case 3:/* presentationRestrictedNumber */
2487 misdn_PartyNumber_extract(id, &presented->Unscreened);
2489 case 1:/* presentationRestricted */
2490 case 2:/* numberNotAvailableDueToInterworking */
2492 /* Number not present (And uninitialized so do not even look at it!) */
2493 id->number_type = NUMTYPE_UNKNOWN;
2494 id->number_plan = NUMPLAN_ISDN;
2499 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2501 #if defined(AST_MISDN_ENHANCEMENTS)
2502 static const char Level_Spacing[] = " ";/* Work for up to 10 levels */
2503 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2505 #if defined(AST_MISDN_ENHANCEMENTS)
2506 static void print_facility_PartyNumber(unsigned Level, const struct FacPartyNumber *Party, const struct misdn_bchannel *bc)
2508 if (Party->LengthOfNumber) {
2509 const char *Spacing;
2511 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2512 chan_misdn_log(1, bc->port, " -->%s PartyNumber: Type:%d\n",
2513 Spacing, Party->Type);
2514 switch (Party->Type) {
2515 case 0: /* Unknown PartyNumber */
2516 chan_misdn_log(1, bc->port, " -->%s Unknown: %s\n",
2517 Spacing, Party->Number);
2519 case 1: /* Public PartyNumber */
2520 chan_misdn_log(1, bc->port, " -->%s Public TON:%d %s\n",
2521 Spacing, Party->TypeOfNumber, Party->Number);
2523 case 2: /* NSAP encoded PartyNumber */
2524 chan_misdn_log(1, bc->port, " -->%s NSAP: %s\n",
2525 Spacing, Party->Number);
2527 case 3: /* Data PartyNumber (Not used) */
2528 chan_misdn_log(1, bc->port, " -->%s Data: %s\n",
2529 Spacing, Party->Number);
2531 case 4: /* Telex PartyNumber (Not used) */
2532 chan_misdn_log(1, bc->port, " -->%s Telex: %s\n",
2533 Spacing, Party->Number);
2535 case 5: /* Private PartyNumber */
2536 chan_misdn_log(1, bc->port, " -->%s Private TON:%d %s\n",
2537 Spacing, Party->TypeOfNumber, Party->Number);
2539 case 8: /* National Standard PartyNumber (Not used) */
2540 chan_misdn_log(1, bc->port, " -->%s National: %s\n",
2541 Spacing, Party->Number);
2548 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2550 #if defined(AST_MISDN_ENHANCEMENTS)
2551 static void print_facility_Subaddress(unsigned Level, const struct FacPartySubaddress *Subaddress, const struct misdn_bchannel *bc)
2553 if (Subaddress->Length) {
2554 const char *Spacing;
2556 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2557 chan_misdn_log(1, bc->port, " -->%s Subaddress: Type:%d\n",
2558 Spacing, Subaddress->Type);
2559 switch (Subaddress->Type) {
2560 case 0: /* UserSpecified */
2561 if (Subaddress->u.UserSpecified.OddCountPresent) {
2562 chan_misdn_log(1, bc->port, " -->%s User BCD OddCount:%d NumOctets:%d\n",
2563 Spacing, Subaddress->u.UserSpecified.OddCount, Subaddress->Length);
2565 chan_misdn_log(1, bc->port, " -->%s User: %s\n",
2566 Spacing, Subaddress->u.UserSpecified.Information);
2570 chan_misdn_log(1, bc->port, " -->%s NSAP: %s\n",
2571 Spacing, Subaddress->u.Nsap);
2578 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2580 #if defined(AST_MISDN_ENHANCEMENTS)
2581 static void print_facility_Address(unsigned Level, const struct FacAddress *Address, const struct misdn_bchannel *bc)
2583 print_facility_PartyNumber(Level, &Address->Party, bc);
2584 print_facility_Subaddress(Level, &Address->Subaddress, bc);
2586 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2588 #if defined(AST_MISDN_ENHANCEMENTS)
2589 static void print_facility_PresentedNumberUnscreened(unsigned Level, const struct FacPresentedNumberUnscreened *Presented, const struct misdn_bchannel *bc)
2591 const char *Spacing;
2593 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2594 chan_misdn_log(1, bc->port, " -->%s Unscreened Type:%d\n", Spacing, Presented->Type);
2595 switch (Presented->Type) {
2596 case 0: /* presentationAllowedNumber */
2597 chan_misdn_log(1, bc->port, " -->%s Allowed:\n", Spacing);
2598 print_facility_PartyNumber(Level + 2, &Presented->Unscreened, bc);
2600 case 1: /* presentationRestricted */
2601 chan_misdn_log(1, bc->port, " -->%s Restricted\n", Spacing);
2603 case 2: /* numberNotAvailableDueToInterworking */
2604 chan_misdn_log(1, bc->port, " -->%s Not Available\n", Spacing);
2606 case 3: /* presentationRestrictedNumber */
2607 chan_misdn_log(1, bc->port, " -->%s Restricted:\n", Spacing);
2608 print_facility_PartyNumber(Level + 2, &Presented->Unscreened, bc);
2614 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2616 #if defined(AST_MISDN_ENHANCEMENTS)
2617 static void print_facility_AddressScreened(unsigned Level, const struct FacAddressScreened *Address, const struct misdn_bchannel *bc)
2619 const char *Spacing;
2621 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2622 chan_misdn_log(1, bc->port, " -->%s ScreeningIndicator:%d\n", Spacing, Address->ScreeningIndicator);
2623 print_facility_PartyNumber(Level, &Address->Party, bc);
2624 print_facility_Subaddress(Level, &Address->Subaddress, bc);
2626 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2628 #if defined(AST_MISDN_ENHANCEMENTS)
2629 static void print_facility_PresentedAddressScreened(unsigned Level, const struct FacPresentedAddressScreened *Presented, const struct misdn_bchannel *bc)
2631 const char *Spacing;
2633 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2634 chan_misdn_log(1, bc->port, " -->%s Screened Type:%d\n", Spacing, Presented->Type);
2635 switch (Presented->Type) {
2636 case 0: /* presentationAllowedAddress */
2637 chan_misdn_log(1, bc->port, " -->%s Allowed:\n", Spacing);
2638 print_facility_AddressScreened(Level + 2, &Presented->Address, bc);
2640 case 1: /* presentationRestricted */
2641 chan_misdn_log(1, bc->port, " -->%s Restricted\n", Spacing);
2643 case 2: /* numberNotAvailableDueToInterworking */
2644 chan_misdn_log(1, bc->port, " -->%s Not Available\n", Spacing);
2646 case 3: /* presentationRestrictedAddress */
2647 chan_misdn_log(1, bc->port, " -->%s Restricted:\n", Spacing);
2648 print_facility_AddressScreened(Level + 2, &Presented->Address, bc);
2654 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2656 #if defined(AST_MISDN_ENHANCEMENTS)
2657 static void print_facility_Q931_Bc_Hlc_Llc(unsigned Level, const struct Q931_Bc_Hlc_Llc *Q931ie, const struct misdn_bchannel *bc)
2659 const char *Spacing;
2661 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2662 chan_misdn_log(1, bc->port, " -->%s Q931ie:\n", Spacing);
2663 if (Q931ie->Bc.Length) {
2664 chan_misdn_log(1, bc->port, " -->%s Bc Len:%d\n", Spacing, Q931ie->Bc.Length);
2666 if (Q931ie->Hlc.Length) {
2667 chan_misdn_log(1, bc->port, " -->%s Hlc Len:%d\n", Spacing, Q931ie->Hlc.Length);
2669 if (Q931ie->Llc.Length) {
2670 chan_misdn_log(1, bc->port, " -->%s Llc Len:%d\n", Spacing, Q931ie->Llc.Length);
2673 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2675 #if defined(AST_MISDN_ENHANCEMENTS)
2676 static void print_facility_Q931_Bc_Hlc_Llc_Uu(unsigned Level, const struct Q931_Bc_Hlc_Llc_Uu *Q931ie, const struct misdn_bchannel *bc)
2678 const char *Spacing;
2680 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2681 chan_misdn_log(1, bc->port, " -->%s Q931ie:\n", Spacing);
2682 if (Q931ie->Bc.Length) {
2683 chan_misdn_log(1, bc->port, " -->%s Bc Len:%d\n", Spacing, Q931ie->Bc.Length);
2685 if (Q931ie->Hlc.Length) {
2686 chan_misdn_log(1, bc->port, " -->%s Hlc Len:%d\n", Spacing, Q931ie->Hlc.Length);
2688 if (Q931ie->Llc.Length) {
2689 chan_misdn_log(1, bc->port, " -->%s Llc Len:%d\n", Spacing, Q931ie->Llc.Length);
2691 if (Q931ie->UserInfo.Length) {
2692 chan_misdn_log(1, bc->port, " -->%s UserInfo Len:%d\n", Spacing, Q931ie->UserInfo.Length);
2695 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2697 #if defined(AST_MISDN_ENHANCEMENTS)
2698 static void print_facility_CallInformation(unsigned Level, const struct FacCallInformation *CallInfo, const struct misdn_bchannel *bc)
2700 const char *Spacing;
2702 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2703 chan_misdn_log(1, bc->port, " -->%s CCBSReference:%d\n",
2704 Spacing, CallInfo->CCBSReference);
2705 chan_misdn_log(1, bc->port, " -->%s AddressOfB:\n", Spacing);
2706 print_facility_Address(Level + 1, &CallInfo->AddressOfB, bc);
2707 print_facility_Q931_Bc_Hlc_Llc(Level, &CallInfo->Q931ie, bc);
2708 if (CallInfo->SubaddressOfA.Length) {
2709 chan_misdn_log(1, bc->port, " -->%s SubaddressOfA:\n", Spacing);
2710 print_facility_Subaddress(Level + 1, &CallInfo->SubaddressOfA, bc);
2713 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2715 #if defined(AST_MISDN_ENHANCEMENTS)
2716 static void print_facility_ServedUserNr(unsigned Level, const struct FacPartyNumber *Party, const struct misdn_bchannel *bc)
2718 const char *Spacing;
2720 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2721 if (Party->LengthOfNumber) {
2722 print_facility_PartyNumber(Level, Party, bc);
2724 chan_misdn_log(1, bc->port, " -->%s All Numbers\n", Spacing);
2727 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2729 #if defined(AST_MISDN_ENHANCEMENTS)
2730 static void print_facility_IntResult(unsigned Level, const struct FacForwardingRecord *ForwardingRecord, const struct misdn_bchannel *bc)
2732 const char *Spacing;
2734 Spacing = &Level_Spacing[sizeof(Level_Spacing) - 1 - Level];
2735 chan_misdn_log(1, bc->port, " -->%s Procedure:%d BasicService:%d\n",
2737 ForwardingRecord->Procedure,
2738 ForwardingRecord->BasicService);
2739 chan_misdn_log(1, bc->port, " -->%s ForwardedTo:\n", Spacing);
2740 print_facility_Address(Level + 1, &ForwardingRecord->ForwardedTo, bc);
2741 chan_misdn_log(1, bc->port, " -->%s ServedUserNr:\n", Spacing);
2742 print_facility_ServedUserNr(Level + 1, &ForwardingRecord->ServedUser, bc);
2744 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2746 static void print_facility(const struct FacParm *fac, const struct misdn_bchannel *bc)
2748 #if defined(AST_MISDN_ENHANCEMENTS)
2750 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
2752 switch (fac->Function) {
2753 #if defined(AST_MISDN_ENHANCEMENTS)
2754 case Fac_ActivationDiversion:
2755 chan_misdn_log(1, bc->port, " --> ActivationDiversion: InvokeID:%d\n",
2756 fac->u.ActivationDiversion.InvokeID);
2757 switch (fac->u.ActivationDiversion.ComponentType) {
2758 case FacComponent_Invoke:
2759 chan_misdn_log(1, bc->port, " --> Invoke: Procedure:%d BasicService:%d\n",
2760 fac->u.ActivationDiversion.Component.Invoke.Procedure,
2761 fac->u.ActivationDiversion.Component.Invoke.BasicService);
2762 chan_misdn_log(1, bc->port, " --> ForwardedTo:\n");
2763 print_facility_Address(3, &fac->u.ActivationDiversion.Component.Invoke.ForwardedTo, bc);
2764 chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
2765 print_facility_ServedUserNr(3, &fac->u.ActivationDiversion.Component.Invoke.ServedUser, bc);
2767 case FacComponent_Result:
2768 chan_misdn_log(1, bc->port, " --> Result\n");
2774 case Fac_DeactivationDiversion:
2775 chan_misdn_log(1, bc->port, " --> DeactivationDiversion: InvokeID:%d\n",
2776 fac->u.DeactivationDiversion.InvokeID);
2777 switch (fac->u.DeactivationDiversion.ComponentType) {
2778 case FacComponent_Invoke:
2779 chan_misdn_log(1, bc->port, " --> Invoke: Procedure:%d BasicService:%d\n",
2780 fac->u.DeactivationDiversion.Component.Invoke.Procedure,
2781 fac->u.DeactivationDiversion.Component.Invoke.BasicService);
2782 chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
2783 print_facility_ServedUserNr(3, &fac->u.DeactivationDiversion.Component.Invoke.ServedUser, bc);
2785 case FacComponent_Result:
2786 chan_misdn_log(1, bc->port, " --> Result\n");
2792 case Fac_ActivationStatusNotificationDiv:
2793 chan_misdn_log(1, bc->port, " --> ActivationStatusNotificationDiv: InvokeID:%d Procedure:%d BasicService:%d\n",
2794 fac->u.ActivationStatusNotificationDiv.InvokeID,
2795 fac->u.ActivationStatusNotificationDiv.Procedure,
2796 fac->u.ActivationStatusNotificationDiv.BasicService);
2797 chan_misdn_log(1, bc->port, " --> ForwardedTo:\n");
2798 print_facility_Address(2, &fac->u.ActivationStatusNotificationDiv.ForwardedTo, bc);
2799 chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
2800 print_facility_ServedUserNr(2, &fac->u.ActivationStatusNotificationDiv.ServedUser, bc);
2802 case Fac_DeactivationStatusNotificationDiv:
2803 chan_misdn_log(1, bc->port, " --> DeactivationStatusNotificationDiv: InvokeID:%d Procedure:%d BasicService:%d\n",
2804 fac->u.DeactivationStatusNotificationDiv.InvokeID,
2805 fac->u.DeactivationStatusNotificationDiv.Procedure,
2806 fac->u.DeactivationStatusNotificationDiv.BasicService);
2807 chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
2808 print_facility_ServedUserNr(2, &fac->u.DeactivationStatusNotificationDiv.ServedUser, bc);
2810 case Fac_InterrogationDiversion:
2811 chan_misdn_log(1, bc->port, " --> InterrogationDiversion: InvokeID:%d\n",
2812 fac->u.InterrogationDiversion.InvokeID);
2813 switch (fac->u.InterrogationDiversion.ComponentType) {
2814 case FacComponent_Invoke:
2815 chan_misdn_log(1, bc->port, " --> Invoke: Procedure:%d BasicService:%d\n",
2816 fac->u.InterrogationDiversion.Component.Invoke.Procedure,
2817 fac->u.InterrogationDiversion.Component.Invoke.BasicService);
2818 chan_misdn_log(1, bc->port, " --> ServedUserNr:\n");
2819 print_facility_ServedUserNr(3, &fac->u.InterrogationDiversion.Component.Invoke.ServedUser, bc);
2821 case FacComponent_Result:
2822 chan_misdn_log(1, bc->port, " --> Result:\n");
2823 if (fac->u.InterrogationDiversion.Component.Result.NumRecords) {
2824 for (Index = 0; Index < fac->u.InterrogationDiversion.Component.Result.NumRecords; ++Index) {
2825 chan_misdn_log(1, bc->port, " --> IntResult[%d]:\n", Index);
2826 print_facility_IntResult(3, &fac->u.InterrogationDiversion.Component.Result.List[Index], bc);
2834 case Fac_DiversionInformation:
2835 chan_misdn_log(1, bc->port, " --> DiversionInformation: InvokeID:%d Reason:%d BasicService:%d\n",
2836 fac->u.DiversionInformation.InvokeID,
2837 fac->u.DiversionInformation.DiversionReason,
2838 fac->u.DiversionInformation.BasicService);
2839 if (fac->u.DiversionInformation.ServedUserSubaddress.Length) {
2840 chan_misdn_log(1, bc->port, " --> ServedUserSubaddress:\n");
2841 print_facility_Subaddress(2, &fac->u.DiversionInformation.ServedUserSubaddress, bc);
2843 if (fac->u.DiversionInformation.CallingAddressPresent) {
2844 chan_misdn_log(1, bc->port, " --> CallingAddress:\n");
2845 print_facility_PresentedAddressScreened(2, &fac->u.DiversionInformation.CallingAddress, bc);
2847 if (fac->u.DiversionInformation.OriginalCalledPresent) {
2848 chan_misdn_log(1, bc->port, " --> OriginalCalledNr:\n");
2849 print_facility_PresentedNumberUnscreened(2, &fac->u.DiversionInformation.OriginalCalled, bc);
2851 if (fac->u.DiversionInformation.LastDivertingPresent) {
2852 chan_misdn_log(1, bc->port, " --> LastDivertingNr:\n");
2853 print_facility_PresentedNumberUnscreened(2, &fac->u.DiversionInformation.LastDiverting, bc);
2855 if (fac->u.DiversionInformation.LastDivertingReasonPresent) {
2856 chan_misdn_log(1, bc->port, " --> LastDivertingReason:%d\n", fac->u.DiversionInformation.LastDivertingReason);
2858 if (fac->u.DiversionInformation.UserInfo.Length) {
2859 chan_misdn_log(1, bc->port, " --> UserInfo Length:%d\n", fac->u.DiversionInformation.UserInfo.Length);
2862 case Fac_CallDeflection:
2863 chan_misdn_log(1, bc->port, " --> CallDeflection: InvokeID:%d\n",
2864 fac->u.CallDeflection.InvokeID);
2865 switch (fac->u.CallDeflection.ComponentType) {
2866 case FacComponent_Invoke:
2867 chan_misdn_log(1, bc->port, " --> Invoke:\n");
2868 if (fac->u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUserPresent) {
2869 chan_misdn_log(1, bc->port, " --> PresentationAllowed:%d\n",
2870 fac->u.CallDeflection.Component.Invoke.PresentationAllowedToDivertedToUser);
2872 chan_misdn_log(1, bc->port, " --> DeflectionAddress:\n");
2873 print_facility_Address(3, &fac->u.CallDeflection.Component.Invoke.Deflection, bc);
2875 case FacComponent_Result:
2876 chan_misdn_log(1, bc->port, " --> Result\n");
2882 case Fac_CallRerouteing:
2883 chan_misdn_log(1, bc->port, " --> CallRerouteing: InvokeID:%d\n",
2884 fac->u.CallRerouteing.InvokeID);
2885 switch (fac->u.CallRerouteing.ComponentType) {
2886 case FacComponent_Invoke:
2887 chan_misdn_log(1, bc->port, " --> Invoke: Reason:%d Counter:%d\n",
2888 fac->u.CallRerouteing.Component.Invoke.ReroutingReason,
2889 fac->u.CallRerouteing.Component.Invoke.ReroutingCounter);
2890 chan_misdn_log(1, bc->port, " --> CalledAddress:\n");
2891 print_facility_Address(3, &fac->u.CallRerouteing.Component.Invoke.CalledAddress, bc);
2892 print_facility_Q931_Bc_Hlc_Llc_Uu(2, &fac->u.CallRerouteing.Component.Invoke.Q931ie, bc);
2893 chan_misdn_log(1, bc->port, " --> LastReroutingNr:\n");
2894 print_facility_PresentedNumberUnscreened(3, &fac->u.CallRerouteing.Component.Invoke.LastRerouting, bc);
2895 chan_misdn_log(1, bc->port, " --> SubscriptionOption:%d\n",
2896 fac->u.CallRerouteing.Component.Invoke.SubscriptionOption);
2897 if (fac->u.CallRerouteing.Component.Invoke.CallingPartySubaddress.Length) {
2898 chan_misdn_log(1, bc->port, " --> CallingParty:\n");
2899 print_facility_Subaddress(3, &fac->u.CallRerouteing.Component.Invoke.CallingPartySubaddress, bc);
2902 case FacComponent_Result:
2903 chan_misdn_log(1, bc->port, " --> Result\n");
2909 case Fac_InterrogateServedUserNumbers:
2910 chan_misdn_log(1, bc->port, " --> InterrogateServedUserNumbers: InvokeID:%d\n",
2911 fac->u.InterrogateServedUserNumbers.InvokeID);
2912 switch (fac->u.InterrogateServedUserNumbers.ComponentType) {
2913 case FacComponent_Invoke:
2914 chan_misdn_log(1, bc->port, " --> Invoke\n");
2916 case FacComponent_Result:
2917 chan_misdn_log(1, bc->port, " --> Result:\n");
2918 if (fac->u.InterrogateServedUserNumbers.Component.Result.NumRecords) {
2919 for (Index = 0; Index < fac->u.InterrogateServedUserNumbers.Component.Result.NumRecords; ++Index) {
2920 chan_misdn_log(1, bc->port, " --> ServedUserNr[%d]:\n", Index);
2921 print_facility_PartyNumber(3, &fac->u.InterrogateServedUserNumbers.Component.Result.List[Index], bc);
2929 case Fac_DivertingLegInformation1:
2930 chan_misdn_log(1, bc->port, " --> DivertingLegInformation1: InvokeID:%d Reason:%d SubscriptionOption:%d\n",
2931 fac->u.DivertingLegInformation1.InvokeID,
2932 fac->u.DivertingLegInformation1.DiversionReason,
2933 fac->u.DivertingLegInformation1.SubscriptionOption);
2934 if (fac->u.DivertingLegInformation1.DivertedToPresent) {
2935 chan_misdn_log(1, bc->port, " --> DivertedToNr:\n");
2936 print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation1.DivertedTo, bc);
2939 case Fac_DivertingLegInformation2:
2940 chan_misdn_log(1, bc->port, " --> DivertingLegInformation2: InvokeID:%d Reason:%d Count:%d\n",
2941 fac->u.DivertingLegInformation2.InvokeID,
2942 fac->u.DivertingLegInformation2.DiversionReason,
2943 fac->u.DivertingLegInformation2.DiversionCounter);
2944 if (fac->u.DivertingLegInformation2.DivertingPresent) {
2945 chan_misdn_log(1, bc->port, " --> DivertingNr:\n");
2946 print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation2.Diverting, bc);
2948 if (fac->u.DivertingLegInformation2.OriginalCalledPresent) {
2949 chan_misdn_log(1, bc->port, " --> OriginalCalledNr:\n");
2950 print_facility_PresentedNumberUnscreened(2, &fac->u.DivertingLegInformation2.OriginalCalled, bc);
2953 case Fac_DivertingLegInformation3:
2954 chan_misdn_log(1, bc->port, " --> DivertingLegInformation3: InvokeID:%d PresentationAllowed:%d\n",
2955 fac->u.DivertingLegInformation3.InvokeID,
2956 fac->u.DivertingLegInformation3.PresentationAllowedIndicator);
2959 #else /* !defined(AST_MISDN_ENHANCEMENTS) */
2962 chan_misdn_log(1, bc->port, " --> calldeflect to: %s, presentable: %s\n", fac->u.CDeflection.DeflectedToNumber,
2963 fac->u.CDeflection.PresentationAllowed ? "yes" : "no");
2965 #endif /* !defined(AST_MISDN_ENHANCEMENTS) */
2966 case Fac_AOCDCurrency:
2967 if (fac->u.AOCDcur.chargeNotAvailable) {
2968 chan_misdn_log(1, bc->port, " --> AOCD currency: charge not available\n");
2969 } else if (fac->u.AOCDcur.freeOfCharge) {
2970 chan_misdn_log(1, bc->port, " --> AOCD currency: free of charge\n");
2971 } else if (fac->u.AOCDchu.billingId >= 0) {
2972 chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s billingId:%d\n",
2973 fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
2974 (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDcur.billingId);
2976 chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s\n",
2977 fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
2978 (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total");
2981 case Fac_AOCDChargingUnit:
2982 if (fac->u.AOCDchu.chargeNotAvailable) {
2983 chan_misdn_log(1, bc->port, " --> AOCD charging unit: charge not available\n");
2984 } else if (fac->u.AOCDchu.freeOfCharge) {
2985 chan_misdn_log(1, bc->port, " --> AOCD charging unit: free of charge\n");
2986 } else if (fac->u.AOCDchu.billingId >= 0) {
2987 chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d\n",
2988 fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDchu.billingId);
2990 chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n",
2991 fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total");
2994 #if defined(AST_MISDN_ENHANCEMENTS)
2996 chan_misdn_log(1, bc->port, " --> ERROR: InvokeID:%d, Code:0x%02x\n",
2997 fac->u.ERROR.invokeId, fac->u.ERROR.errorValue);
3000 chan_misdn_log(1, bc->port, " --> RESULT: InvokeID:%d\n",
3001 fac->u.RESULT.InvokeID);
3004 if (fac->u.REJECT.InvokeIDPresent) {
3005 chan_misdn_log(1, bc->port, " --> REJECT: InvokeID:%d, Code:0x%02x\n",
3006 fac->u.REJECT.InvokeID, fac->u.REJECT.Code);
3008 chan_misdn_log(1, bc->port, " --> REJECT: Code:0x%02x\n",
3009 fac->u.REJECT.Code);
3012 case Fac_EctExecute:
3013 chan_misdn_log(1, bc->port, " --> EctExecute: InvokeID:%d\n",
3014 fac->u.EctExecute.InvokeID);
3016 case Fac_ExplicitEctExecute:
3017 chan_misdn_log(1, bc->port, " --> ExplicitEctExecute: InvokeID:%d LinkID:%d\n",
3018 fac->u.ExplicitEctExecute.InvokeID,
3019 fac->u.ExplicitEctExecute.LinkID);
3021 case Fac_RequestSubaddress:
3022 chan_misdn_log(1, bc->port, " --> RequestSubaddress: InvokeID:%d\n",
3023 fac->u.RequestSubaddress.InvokeID);
3025 case Fac_SubaddressTransfer:
3026 chan_misdn_log(1, bc->port, " --> SubaddressTransfer: InvokeID:%d\n",
3027 fac->u.SubaddressTransfer.InvokeID);
3028 print_facility_Subaddress(1, &fac->u.SubaddressTransfer.Subaddress, bc);
3030 case Fac_EctLinkIdRequest:
3031 chan_misdn_log(1, bc->port, " --> EctLinkIdRequest: InvokeID:%d\n",
3032 fac->u.EctLinkIdRequest.InvokeID);
3033 switch (fac->u.EctLinkIdRequest.ComponentType) {
3034 case FacComponent_Invoke:
3035 chan_misdn_log(1, bc->port, " --> Invoke\n");
3037 case FacComponent_Result:
3038 chan_misdn_log(1, bc->port, " --> Result: LinkID:%d\n",
3039 fac->u.EctLinkIdRequest.Component.Result.LinkID);
3046 chan_misdn_log(1, bc->port, " --> EctInform: InvokeID:%d Status:%d\n",
3047 fac->u.EctInform.InvokeID,
3048 fac->u.EctInform.Status);
3049 if (fac->u.EctInform.RedirectionPresent) {
3050 chan_misdn_log(1, bc->port, " --> Redirection Number\n");
3051 print_facility_PresentedNumberUnscreened(2, &fac->u.EctInform.Redirection, bc);
3054 case Fac_EctLoopTest:
3055 chan_misdn_log(1, bc->port, " --> EctLoopTest: InvokeID:%d\n",
3056 fac->u.EctLoopTest.InvokeID);
3057 switch (fac->u.EctLoopTest.ComponentType) {
3058 case FacComponent_Invoke:
3059 chan_misdn_log(1, bc->port, " --> Invoke: CallTransferID:%d\n",
3060 fac->u.EctLoopTest.Component.Invoke.CallTransferID);
3062 case FacComponent_Result:
3063 chan_misdn_log(1, bc->port, " --> Result: LoopResult:%d\n",
3064 fac->u.EctLoopTest.Component.Result.LoopResult);
3070 case Fac_StatusRequest:
3071 chan_misdn_log(1, bc->port, " --> StatusRequest: InvokeID:%d\n",
3072 fac->u.StatusRequest.InvokeID);
3073 switch (fac->u.StatusRequest.ComponentType) {
3074 case FacComponent_Invoke:
3075 chan_misdn_log(1, bc->port, " --> Invoke: Compatibility:%d\n",
3076 fac->u.StatusRequest.Component.Invoke.CompatibilityMode);
3078 case FacComponent_Result:
3079 chan_misdn_log(1, bc->port, " --> Result: Status:%d\n",
3080 fac->u.StatusRequest.Component.Result.Status);
3086 case Fac_CallInfoRetain:
3087 chan_misdn_log(1, bc->port, " --> CallInfoRetain: InvokeID:%d, LinkageID:%d\n",
3088 fac->u.CallInfoRetain.InvokeID, fac->u.CallInfoRetain.CallLinkageID);
3090 case Fac_CCBSDeactivate:
3091 chan_misdn_log(1, bc->port, " --> CCBSDeactivate: InvokeID:%d\n",
3092 fac->u.CCBSDeactivate.InvokeID);
3093 switch (fac->u.CCBSDeactivate.ComponentType) {
3094 case FacComponent_Invoke:
3095 chan_misdn_log(1, bc->port, " --> Invoke: CCBSReference:%d\n",
3096 fac->u.CCBSDeactivate.Component.Invoke.CCBSReference);
3098 case FacComponent_Result:
3099 chan_misdn_log(1, bc->port, " --> Result\n");
3106 chan_misdn_log(1, bc->port, " --> CCBSErase: InvokeID:%d, CCBSReference:%d RecallMode:%d, Reason:%d\n",
3107 fac->u.CCBSErase.InvokeID, fac->u.CCBSErase.CCBSReference,
3108 fac->u.CCBSErase.RecallMode, fac->u.CCBSErase.Reason);
3109 chan_misdn_log(1, bc->port, " --> AddressOfB\n");
3110 print_facility_Address(2, &fac->u.CCBSErase.AddressOfB, bc);
3111 print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSErase.Q931ie, bc);
3113 case Fac_CCBSRemoteUserFree:
3114 chan_misdn_log(1, bc->port, " --> CCBSRemoteUserFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
3115 fac->u.CCBSRemoteUserFree.InvokeID, fac->u.CCBSRemoteUserFree.CCBSReference,
3116 fac->u.CCBSRemoteUserFree.RecallMode);
3117 chan_misdn_log(1, bc->port, " --> AddressOfB\n");
3118 print_facility_Address(2, &fac->u.CCBSRemoteUserFree.AddressOfB, bc);
3119 print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSRemoteUserFree.Q931ie, bc);
3122 chan_misdn_log(1, bc->port, " --> CCBSCall: InvokeID:%d, CCBSReference:%d\n",
3123 fac->u.CCBSCall.InvokeID, fac->u.CCBSCall.CCBSReference);
3125 case Fac_CCBSStatusRequest:
3126 chan_misdn_log(1, bc->port, " --> CCBSStatusRequest: InvokeID:%d\n",
3127 fac->u.CCBSStatusRequest.InvokeID);
3128 switch (fac->u.CCBSStatusRequest.ComponentType) {
3129 case FacComponent_Invoke:
3130 chan_misdn_log(1, bc->port, " --> Invoke: CCBSReference:%d RecallMode:%d\n",
3131 fac->u.CCBSStatusRequest.Component.Invoke.CCBSReference,
3132 fac->u.CCBSStatusRequest.Component.Invoke.RecallMode);
3133 print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCBSStatusRequest.Component.Invoke.Q931ie, bc);
3135 case FacComponent_Result:
3136 chan_misdn_log(1, bc->port, " --> Result: Free:%d\n",
3137 fac->u.CCBSStatusRequest.Component.Result.Free);
3144 chan_misdn_log(1, bc->port, " --> CCBSBFree: InvokeID:%d, CCBSReference:%d RecallMode:%d\n",
3145 fac->u.CCBSBFree.InvokeID, fac->u.CCBSBFree.CCBSReference,
3146 fac->u.CCBSBFree.RecallMode);
3147 chan_misdn_log(1, bc->port, " --> AddressOfB\n");
3148 print_facility_Address(2, &fac->u.CCBSBFree.AddressOfB, bc);
3149 print_facility_Q931_Bc_Hlc_Llc(1, &fac->u.CCBSBFree.Q931ie, bc);
3151 case Fac_EraseCallLinkageID:
3152 chan_misdn_log(1, bc->port, " --> EraseCallLinkageID: InvokeID:%d, LinkageID:%d\n",
3153 fac->u.EraseCallLinkageID.InvokeID, fac->u.EraseCallLinkageID.CallLinkageID);
3155 case Fac_CCBSStopAlerting:
3156 chan_misdn_log(1, bc->port, " --> CCBSStopAlerting: InvokeID:%d, CCBSReference:%d\n",
3157 fac->u.CCBSStopAlerting.InvokeID, fac->u.CCBSStopAlerting.CCBSReference);
3159 case Fac_CCBSRequest:
3160 chan_misdn_log(1, bc->port, " --> CCBSRequest: InvokeID:%d\n",
3161 fac->u.CCBSRequest.InvokeID);
3162 switch (fac->u.CCBSRequest.ComponentType) {
3163 case FacComponent_Invoke:
3164 chan_misdn_log(1, bc->port, " --> Invoke: LinkageID:%d\n",
3165 fac->u.CCBSRequest.Component.Invoke.CallLinkageID);
3167 case FacComponent_Result:
3168 chan_misdn_log(1, bc->port, " --> Result: CCBSReference:%d RecallMode:%d\n",
3169 fac->u.CCBSRequest.Component.Result.CCBSReference,
3170 fac->u.CCBSRequest.Component.Result.RecallMode);
3176 case Fac_CCBSInterrogate:
3177 chan_misdn_log(1, bc->port, " --> CCBSInterrogate: InvokeID:%d\n",
3178 fac->u.CCBSInterrogate.InvokeID);
3179 switch (fac->u.CCBSInterrogate.ComponentType) {
3180 case FacComponent_Invoke:
3181 chan_misdn_log(1, bc->port, " --> Invoke\n");
3182 if (fac->u.CCBSInterrogate.Component.Invoke.CCBSReferencePresent) {
3183 chan_misdn_log(1, bc->port, " --> CCBSReference:%d\n",
3184 fac->u.CCBSInterrogate.Component.Invoke.CCBSReference);
3186 if (fac->u.CCBSInterrogate.Component.Invoke.AParty.LengthOfNumber) {
3187 chan_misdn_log(1, bc->port, " --> AParty\n");
3188 print_facility_PartyNumber(3, &fac->u.CCBSInterrogate.Component.Invoke.AParty, bc);
3191 case FacComponent_Result:
3192 chan_misdn_log(1, bc->port, " --> Result: RecallMode:%d\n",
3193 fac->u.CCBSInterrogate.Component.Result.RecallMode);
3194 if (fac->u.CCBSInterrogate.Component.Result.NumRecords) {
3195 for (Index = 0; Index < fac->u.CCBSInterrogate.Component.Result.NumRecords; ++Index) {
3196 chan_misdn_log(1, bc->port, " --> CallDetails[%d]:\n", Index);
3197 print_facility_CallInformation(3, &fac->u.CCBSInterrogate.Component.Result.CallDetails[Index], bc);
3205 case Fac_CCNRRequest:
3206 chan_misdn_log(1, bc->port, " --> CCNRRequest: InvokeID:%d\n",
3207 fac->u.CCNRRequest.InvokeID);
3208 switch (fac->u.CCNRRequest.ComponentType) {
3209 case FacComponent_Invoke:
3210 chan_misdn_log(1, bc->port, " --> Invoke: LinkageID:%d\n",
3211 fac->u.CCNRRequest.Component.Invoke.CallLinkageID);
3213 case FacComponent_Result:
3214 chan_misdn_log(1, bc->port, " --> Result: CCBSReference:%d RecallMode:%d\n",
3215 fac->u.CCNRRequest.Component.Result.CCBSReference,
3216 fac->u.CCNRRequest.Component.Result.RecallMode);
3222 case Fac_CCNRInterrogate:
3223 chan_misdn_log(1, bc->port, " --> CCNRInterrogate: InvokeID:%d\n",
3224 fac->u.CCNRInterrogate.InvokeID);
3225 switch (fac->u.CCNRInterrogate.ComponentType) {
3226 case FacComponent_Invoke:
3227 chan_misdn_log(1, bc->port, " --> Invoke\n");
3228 if (fac->u.CCNRInterrogate.Component.Invoke.CCBSReferencePresent) {
3229 chan_misdn_log(1, bc->port, " --> CCBSReference:%d\n",
3230 fac->u.CCNRInterrogate.Component.Invoke.CCBSReference);
3232 if (fac->u.CCNRInterrogate.Component.Invoke.AParty.LengthOfNumber) {
3233 chan_misdn_log(1, bc->port, " --> AParty\n");
3234 print_facility_PartyNumber(3, &fac->u.CCNRInterrogate.Component.Invoke.AParty, bc);
3237 case FacComponent_Result:
3238 chan_misdn_log(1, bc->port, " --> Result: RecallMode:%d\n",
3239 fac->u.CCNRInterrogate.Component.Result.RecallMode);
3240 if (fac->u.CCNRInterrogate.Component.Result.NumRecords) {
3241 for (Index = 0; Index < fac->u.CCNRInterrogate.Component.Result.NumRecords; ++Index) {
3242 chan_misdn_log(1, bc->port, " --> CallDetails[%d]:\n", Index);
3243 print_facility_CallInformation(3, &fac->u.CCNRInterrogate.Component.Result.CallDetails[Index], bc);
3251 case Fac_CCBS_T_Call:
3252 chan_misdn_log(1, bc->port, " --> CCBS_T_Call: InvokeID:%d\n",
3253 fac->u.CCBS_T_Call.InvokeID);
3255 case Fac_CCBS_T_Suspend:
3256 chan_misdn_log(1, bc->port, " --> CCBS_T_Suspend: InvokeID:%d\n",
3257 fac->u.CCBS_T_Suspend.InvokeID);
3259 case Fac_CCBS_T_Resume:
3260 chan_misdn_log(1, bc->port, " --> CCBS_T_Resume: InvokeID:%d\n",
3261 fac->u.CCBS_T_Resume.InvokeID);
3263 case Fac_CCBS_T_RemoteUserFree:
3264 chan_misdn_log(1, bc->port, " --> CCBS_T_RemoteUserFree: InvokeID:%d\n",
3265 fac->u.CCBS_T_RemoteUserFree.InvokeID);
3267 case Fac_CCBS_T_Available:
3268 chan_misdn_log(1, bc->port, " --> CCBS_T_Available: InvokeID:%d\n",
3269 fac->u.CCBS_T_Available.InvokeID);
3271 case Fac_CCBS_T_Request:
3272 chan_misdn_log(1, bc->port, " --> CCBS_T_Request: InvokeID:%d\n",
3273 fac->u.CCBS_T_Request.InvokeID);
3274 switch (fac->u.CCBS_T_Request.ComponentType) {
3275 case FacComponent_Invoke:
3276 chan_misdn_log(1, bc->port, " --> Invoke\n");
3277 chan_misdn_log(1, bc->port, " --> DestinationAddress:\n");
3278 print_facility_Address(3, &fac->u.CCBS_T_Request.Component.Invoke.Destination, bc);
3279 print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCBS_T_Request.Component.Invoke.Q931ie, bc);
3280 if (fac->u.CCBS_T_Request.Component.Invoke.RetentionSupported) {
3281 chan_misdn_log(1, bc->port, " --> RetentionSupported:1\n");
3283 if (fac->u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent) {
3284 chan_misdn_log(1, bc->port, " --> PresentationAllowed:%d\n",
3285 fac->u.CCBS_T_Request.Component.Invoke.PresentationAllowedIndicator);
3287 if (fac->u.CCBS_T_Request.Component.Invoke.Originating.Party.LengthOfNumber) {
3288 chan_misdn_log(1, bc->port, " --> OriginatingAddress:\n");
3289 print_facility_Address(3, &fac->u.CCBS_T_Request.Component.Invoke.Originating, bc);
3292 case FacComponent_Result:
3293 chan_misdn_log(1, bc->port, " --> Result: RetentionSupported:%d\n",
3294 fac->u.CCBS_T_Request.Component.Result.RetentionSupported);
3300 case Fac_CCNR_T_Request:
3301 chan_misdn_log(1, bc->port, " --> CCNR_T_Request: InvokeID:%d\n",
3302 fac->u.CCNR_T_Request.InvokeID);
3303 switch (fac->u.CCNR_T_Request.ComponentType) {
3304 case FacComponent_Invoke:
3305 chan_misdn_log(1, bc->port, " --> Invoke\n");
3306 chan_misdn_log(1, bc->port, " --> DestinationAddress:\n");
3307 print_facility_Address(3, &fac->u.CCNR_T_Request.Component.Invoke.Destination, bc);
3308 print_facility_Q931_Bc_Hlc_Llc(2, &fac->u.CCNR_T_Request.Component.Invoke.Q931ie, bc);
3309 if (fac->u.CCNR_T_Request.Component.Invoke.RetentionSupported) {
3310 chan_misdn_log(1, bc->port, " --> RetentionSupported:1\n");
3312 if (fac->u.CCNR_T_Request.Component.Invoke.PresentationAllowedIndicatorPresent) {
3313 chan_misdn_log(1, bc->port, " --> PresentationAllowed:%d\n",
3314 fac->u.CCNR_T_Request.Component.Invoke.PresentationAllowedIndicator);
3316 if (fac->u.CCNR_T_Request.Component.Invoke.Originating.Party.LengthOfNumber) {
3317 chan_misdn_log(1, bc->port, " --> OriginatingAddress:\n");
3318 print_facility_Address(3, &fac->u.CCNR_T_Request.Component.Invoke.Originating, bc);
3321 case FacComponent_Result:
3322 chan_misdn_log(1, bc->port, " --> Result: RetentionSupported:%d\n",
3323 fac->u.CCNR_T_Request.Component.Result.RetentionSupported);
3329 #endif /* defined(AST_MISDN_ENHANCEMENTS) */
3331 /* No facility so print nothing */
3334 chan_misdn_log(1, bc->port, " --> unknown facility\n");
3339 static void print_bearer(struct misdn_bchannel *bc)
3341 chan_misdn_log(2, bc->port, " --> Bearer: %s\n", bearer2str(bc->capability));
3344 case INFO_CODEC_ALAW:
3345 chan_misdn_log(2, bc->port, " --> Codec: Alaw\n");
3347 case INFO_CODEC_ULAW:
3348 chan_misdn_log(2, bc->port, " --> Codec: Ulaw\n");
3355 * \brief Prefix a string to another string in place.
3357 * \param str_prefix String to prefix to the main string.
3358 * \param str_main String to get the prefix added to it.
3359 * \param size Buffer size of the main string (Includes null terminator).
3361 * \note The str_main buffer size must be greater than one.
3365 static void misdn_prefix_string(const char *str_prefix, char *str_main, size_t size)
3372 len_prefix = strlen(str_prefix);
3374 /* There is no prefix to prepend. */
3377 len_main = strlen(str_main);
3378 len_total = len_prefix + len_main;
3379 if (size <= len_total) {
3380 /* We need to truncate since the buffer is too small. */
3381 len_over = len_total + 1 - size;
3382 if (len_over <= len_main) {
3383 len_main -= len_over;
3385 len_over -= len_main;
3387 len_prefix -= len_over;
3391 memmove(str_main + len_prefix, str_main, len_main);
3393 memcpy(str_main, str_prefix, len_prefix);
3394 str_main[len_prefix + len_main] = '\0';
3399 * \brief Add a configured prefix to the given number.
3401 * \param port Logical port number
3402 * \param number_type Type-of-number passed in.
3403 * \param number Given number string to add prefix
3404 * \param size Buffer size number string occupies.
3408 static void misdn_add_number_prefix(int port, enum mISDN_NUMBER_TYPE number_type, char *number, size_t size)
3410 enum misdn_cfg_elements type_prefix;
3411 char num_prefix[MISDN_MAX_NUMBER_LEN];
3413 /* Get prefix string. */
3414 switch (number_type) {
3415 case NUMTYPE_UNKNOWN:
3416 type_prefix = MISDN_CFG_TON_PREFIX_UNKNOWN;
3418 case NUMTYPE_INTERNATIONAL:
3419 type_prefix = MISDN_CFG_TON_PREFIX_INTERNATIONAL;
3421 case NUMTYPE_NATIONAL:
3422 type_prefix = MISDN_CFG_TON_PREFIX_NATIONAL;
3424 case NUMTYPE_NETWORK_SPECIFIC:
3425 type_prefix = MISDN_CFG_TON_PREFIX_NETWORK_SPECIFIC;
3427 case NUMTYPE_SUBSCRIBER:
3428 type_prefix = MISDN_CFG_TON_PREFIX_SUBSCRIBER;
3430 case NUMTYPE_ABBREVIATED:
3431 type_prefix = MISDN_CFG_TON_PREFIX_ABBREVIATED;
3434 /* Type-of-number does not have a prefix that can be added. */
3437 misdn_cfg_get(port, type_prefix, num_prefix, sizeof(num_prefix));
3439 misdn_prefix_string(num_prefix, number, size);
3442 static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc)
3446 if (!bc->AOCD_need_export || !ast) {
3450 if (originator == ORG_AST) {
3451 ast = ast_bridged_channel(ast);
3457 switch (bc->AOCDtype) {
3458 case Fac_AOCDCurrency:
3459 pbx_builtin_setvar_helper(ast, "AOCD_Type", "currency");
3460 if (bc->AOCD.currency.chargeNotAvailable) {
3461 pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
3463 pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
3464 if (bc->AOCD.currency.freeOfCharge) {
3465 pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
3467 pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
3468 if (snprintf(buf, sizeof(buf), "%d %s", bc->AOCD.currency.currencyAmount * bc->AOCD.currency.multiplier, bc->AOCD.currency.currency) < sizeof(buf)) {
3469 pbx_builtin_setvar_helper(ast, "AOCD_Amount", buf);
3470 if (bc->AOCD.currency.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.currency.billingId) < sizeof(buf)) {
3471 pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
3477 case Fac_AOCDChargingUnit:
3478 pbx_builtin_setvar_helper(ast, "AOCD_Type", "charging_unit");
3479 if (bc->AOCD.chargingUnit.chargeNotAvailable) {
3480 pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
3482 pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
3483 if (bc->AOCD.chargingUnit.freeOfCharge) {
3484 pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
3486 pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
3487 if (snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.recordedUnits) < sizeof(buf)) {
3488 pbx_builtin_setvar_helper(ast, "AOCD_RecordedUnits", buf);
3489 if (bc->AOCD.chargingUnit.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.billingId) < sizeof(buf)) {
3490 pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
3500 bc->AOCD_need_export = 0;
3503 /*************** Helpers END *************/
3505 static void sighandler(int sig)
3509 static void *misdn_tasks_thread_func(void *data)
3512 struct sigaction sa;
3514 sa.sa_handler = sighandler;
3515 sa.sa_flags = SA_NODEFER;
3516 sigemptyset(&sa.sa_mask);
3517 sigaddset(&sa.sa_mask, SIGUSR1);
3518 sigaction(SIGUSR1, &sa, NULL);
3520 sem_post((sem_t *)data);
3523 wait = ast_sched_wait(misdn_tasks);
3527 if (poll(NULL, 0, wait) < 0) {
3528 chan_misdn_log(4, 0, "Waking up misdn_tasks thread\n");
3530 ast_sched_runq(misdn_tasks);
3535 static void misdn_tasks_init(void)
3540 if (sem_init(&blocker, 0, 0)) {
3541 perror("chan_misdn: Failed to initialize semaphore!");
3545 chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
3547 misdn_tasks = ast_sched_context_create();
3548 pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, &blocker);
3550 while (sem_wait(&blocker) && --i) {
3552 sem_destroy(&blocker);
3555 static void misdn_tasks_destroy(void)
3558 chan_misdn_log(4, 0, "Killing misdn_tasks thread\n");
3559 if (pthread_cancel(misdn_tasks_thread) == 0) {
3560 cb_log(4, 0, "Joining misdn_tasks thread\n");
3561 pthread_join(misdn_tasks_thread, NULL);
3563 ast_sched_context_destroy(misdn_tasks);
3567 static inline void misdn_tasks_wakeup(void)
3569 pthread_kill(misdn_tasks_thread, SIGUSR1);
3572 static inline int _misdn_tasks_add_variable(int timeout, ast_sched_cb callback, const void *data, int variable)
3579 task_id = ast_sched_add_variable(misdn_tasks, timeout, callback, data, variable);
3580 misdn_tasks_wakeup();
3585 static int misdn_tasks_add(int timeout, ast_sched_cb callback, const void *data)
3587 return _misdn_tasks_add_variable(timeout, callback, data, 0);
3590 static int misdn_tasks_add_variable(int timeout, ast_sched_cb callback, const void *data)
3592 return _misdn_tasks_add_variable(timeout, callback, data, 1);
3595 static void misdn_tasks_remove(int task_id)
3597 AST_SCHED_DEL(misdn_tasks, task_id);
3600 static int misdn_l1_task(const void *vdata)
3602 const int *data = vdata;
3604 misdn_lib_isdn_l1watcher(*data);
3605 chan_misdn_log(5, *data, "L1watcher timeout\n");
3609 static int misdn_overlap_dial_task(const void *data)
3611 struct timeval tv_end, tv_now;
3613 struct chan_list *ch = (struct chan_list *) data;
3616 chan_misdn_log(4, ch->bc->port, "overlap dial task, chan_state: %d\n", ch->state);
3618 if (ch->state != MISDN_WAITING4DIGS) {
3619 ch->overlap_dial_task = -1;
3623 ast_mutex_lock(&ch->overlap_tv_lock);
3624 tv_end = ch->overlap_tv;
3625 ast_mutex_unlock(&ch->overlap_tv_lock);
3627 tv_end.tv_sec += ch->overlap_dial;
3628 tv_now = ast_tvnow();
3630 diff = ast_tvdiff_ms(tv_end, tv_now);
3635 /* if we are 100ms near the timeout, we are satisfied.. */
3638 if (ast_strlen_zero(ch->bc->dialed.number)) {
3640 ast_channel_exten_set(ch->ast, dad);
3642 dad = ch->bc->dialed.number;
3645 if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->caller.number)) {
3646 ch->state = MISDN_DIALING;
3647 if (pbx_start_chan(ch) < 0) {
3648 chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
3649 goto misdn_overlap_dial_task_disconnect;
3652 misdn_overlap_dial_task_disconnect:
3653 hanguptone_indicate(ch);
3654 ch->bc->out_cause = AST_CAUSE_UNALLOCATED;
3655 ch->state = MISDN_CLEANING;
3656 misdn_lib_send_event(ch->bc, EVENT_DISCONNECT);
3658 ch->overlap_dial_task = -1;
3662 static void send_digit_to_chan(struct chan_list *cl, char digit)
3664 static const char * const dtmf_tones[] = {
3666 "!941+1336/100,!0/100", /* 0 */
3667 "!697+1209/100,!0/100", /* 1 */
3668 "!697+1336/100,!0/100", /* 2 */
3669 "!697+1477/100,!0/100", /* 3 */
3670 "!770+1209/100,!0/100", /* 4 */
3671 "!770+1336/100,!0/100", /* 5 */
3672 "!770+1477/100,!0/100", /* 6 */
3673 "!852+1209/100,!0/100", /* 7 */
3674 "!852+1336/100,!0/100", /* 8 */
3675 "!852+1477/100,!0/100", /* 9 */
3676 "!697+1633/100,!0/100", /* A */
3677 "!770+1633/100,!0/100", /* B */
3678 "!852+1633/100,!0/100", /* C */
3679 "!941+1633/100,!0/100", /* D */
3680 "!941+1209/100,!0/100", /* * */
3681 "!941+1477/100,!0/100", /* # */
3684 struct ast_channel *chan = cl->ast;
3686 if (digit >= '0' && digit <='9') {
3687 ast_playtones_start(chan, 0, dtmf_tones[digit - '0'], 0);
3688 } else if (digit >= 'A' && digit <= 'D') {
3689 ast_playtones_start(chan, 0, dtmf_tones[digit - 'A' + 10], 0);
3690 } else if (digit == '*') {
3691 ast_playtones_start(chan, 0, dtmf_tones[14], 0);
3692 } else if (digit == '#') {
3693 ast_playtones_start(chan, 0, dtmf_tones[15], 0);
3696 ast_debug(1, "Unable to handle DTMF tone '%c' for '%s'\n", digit, ast_channel_name(chan));
3700 /*** CLI HANDLING ***/
3701 static char *handle_cli_misdn_set_debug(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
3707 e->command = "misdn set debug [on|off]";
3709 "Usage: misdn set debug {on|off|<level>} [only] | [port <port> [only]]\n"
3710 " Set the debug level of the mISDN channel.\n";
3713 return complete_debug_port(a);
3716 if (a->argc < 4 || a->argc > 7) {
3717 return CLI_SHOWUSAGE;
3720 if (!strcasecmp(a->argv[3], "on")) {
3722 } else if (!strcasecmp(a->argv[3], "off")) {
3724 } else if (isdigit(a->argv[3][0])) {
3725 level = atoi(a->argv[3]);
3727 return CLI_SHOWUSAGE;
3737 if (strncasecmp(a->argv[4], "only", strlen(a->argv[4]))) {
3738 return CLI_SHOWUSAGE;
3744 for (i = 0; i <= max_ports; i++) {
3745 misdn_debug[i] = level;
3746 misdn_debug_only[i] = only;
3748 ast_cli(a->fd, "changing debug level for all ports to %d%s\n", misdn_debug[0], only ? " (only)" : "");
3755 if (strncasecmp(a->argv[4], "port", strlen(a->argv[4])))
3756 return CLI_SHOWUSAGE;
3757 port = atoi(a->argv[5]);
3758 if (port <= 0 || port > max_ports) {
3759 switch (max_ports) {
3761 ast_cli(a->fd, "port number not valid! no ports available so you won't get lucky with any number here...\n");
3764 ast_cli(a->fd, "port number not valid! only port 1 is available.\n");
3767 ast_cli(a->fd, "port number not valid! only ports 1 to %d are available.\n", max_ports);
3772 if (strncasecmp(a->argv[6], "only", strlen(a->argv[6]))) {
3773 return CLI_SHOWUSAGE;