Thu Apr 28 2011 16:57:00

Asterisk developer's documentation


chan_misdn.c File Reference

the chan_misdn channel driver for Asterisk More...

#include "asterisk.h"
#include <pthread.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <sys/file.h>
#include <semaphore.h>
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/module.h"
#include "asterisk/pbx.h"
#include "asterisk/io.h"
#include "asterisk/frame.h"
#include "asterisk/translate.h"
#include "asterisk/cli.h"
#include "asterisk/musiconhold.h"
#include "asterisk/dsp.h"
#include "asterisk/file.h"
#include "asterisk/callerid.h"
#include "asterisk/indications.h"
#include "asterisk/app.h"
#include "asterisk/features.h"
#include "asterisk/term.h"
#include "asterisk/sched.h"
#include "asterisk/stringfields.h"
#include "asterisk/abstract_jb.h"
#include "asterisk/causes.h"
#include "chan_misdn_config.h"
#include "isdn_lib.h"
#include "asterisk/strings.h"
Include dependency graph for chan_misdn.c:

Go to the source code of this file.

Data Structures

struct  allowed_bearers
struct  chan_list
 Channel call record structure. More...
struct  hold_info
struct  misdn_jb
struct  robin_list
struct  state_struct

Defines

#define MISDN_ASTERISK_PVT(ast)   1
#define MISDN_ASTERISK_TECH_PVT(ast)   ast->tech_pvt
#define ORG_AST   1
#define ORG_MISDN   2
#define TRANSFER_ON_HELD_CALL_HANGUP   1

Enumerations

enum  misdn_chan_state {
  MISDN_NOTHING = 0, MISDN_WAITING4DIGS, MISDN_EXTCANTMATCH, MISDN_INCOMING_SETUP,
  MISDN_DIALING, MISDN_PROGRESS, MISDN_PROCEEDING, MISDN_CALLING,
  MISDN_CALLING_ACKNOWLEDGE, MISDN_ALERTING, MISDN_BUSY, MISDN_CONNECTED,
  MISDN_DISCONNECTED, MISDN_CLEANING
}
enum  misdn_hold_state { MISDN_HOLD_IDLE, MISDN_HOLD_ACTIVE, MISDN_HOLD_TRANSFER, MISDN_HOLD_DISCONNECT }

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int _misdn_tasks_add_variable (int timeout, ast_sched_cb callback, const void *data, int variable)
int add_in_calls (int port)
int add_out_calls (int port)
static const char * bearer2str (int cap)
static enum event_response_e cb_events (enum event_e event, struct misdn_bchannel *bc, void *user_data)
int chan_misdn_jb_empty (struct misdn_bchannel *bc, char *buf, int len)
static void chan_misdn_log (int level, int port, char *tmpl,...)
static void cl_dequeue_chan (struct chan_list **list, struct chan_list *chan)
static void cl_queue_chan (struct chan_list **list, struct chan_list *chan)
static char * complete_ch (struct ast_cli_args *a)
static char * complete_debug_port (struct ast_cli_args *a)
static char * complete_show_config (struct ast_cli_args *a)
static void config_jitterbuffer (struct chan_list *ch)
void debug_numplan (int port, int numplan, char *type)
static int dialtone_indicate (struct chan_list *cl)
static void do_immediate_setup (struct misdn_bchannel *bc, struct chan_list *ch, struct ast_channel *ast)
static void export_aoc_vars (int originator, struct ast_channel *ast, struct misdn_bchannel *bc)
void export_ch (struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
 Export parameters to the dialplan environment variables.
static struct chan_listfind_chan_by_bc (struct chan_list *list, struct misdn_bchannel *bc)
static struct chan_listfind_chan_by_pid (struct chan_list *list, int pid)
static struct chan_listfind_hold_active_call (struct chan_list *list, struct misdn_bchannel *bc)
static struct chan_listfind_hold_call (struct chan_list *list, struct misdn_bchannel *bc)
static struct chan_listfind_hold_call_l3 (struct chan_list *list, unsigned long l3_id)
static void free_robin_list (void)
static struct chan_listget_chan_by_ast (struct ast_channel *ast)
static struct chan_listget_chan_by_ast_name (char *name)
static struct robin_listget_robin_position (char *group)
static char * handle_cli_misdn_port_block (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_port_down (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_port_unblock (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_port_up (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_reload (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_restart_pid (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_restart_port (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_send_digit (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_send_display (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_send_facility (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_send_restart (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_set_crypt_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_set_debug (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_set_tics (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_show_channel (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_show_channels (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_show_config (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_show_port (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_show_ports_stats (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_show_stacks (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static char * handle_cli_misdn_toggle_echocancel (struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void hangup_chan (struct chan_list *ch, struct misdn_bchannel *bc)
static void hanguptone_indicate (struct chan_list *cl)
void import_ch (struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch)
 Import parameters from the dialplan environment variables.
static struct chan_listinit_chan_list (int orig)
static int load_module (void)
static int misdn_answer (struct ast_channel *ast)
static int misdn_attempt_transfer (struct chan_list *active_ch, struct chan_list *held_ch)
static enum ast_bridge_result misdn_bridge (struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc, int timeoutms)
static int misdn_call (struct ast_channel *ast, char *dest, int timeout)
static int misdn_check_l2l1 (struct ast_channel *chan, void *data)
static int misdn_digit_begin (struct ast_channel *chan, char digit)
static int misdn_digit_end (struct ast_channel *ast, char digit, unsigned int duration)
static int misdn_facility_exec (struct ast_channel *chan, void *data)
static int misdn_fixup (struct ast_channel *oldast, struct ast_channel *ast)
static const char * misdn_get_ch_state (struct chan_list *p)
static int misdn_hangup (struct ast_channel *ast)
static int misdn_indication (struct ast_channel *ast, int cond, const void *data, size_t datalen)
void misdn_jb_destroy (struct misdn_jb *jb)
 frees the data and destroys the given jitterbuffer struct
int misdn_jb_empty (struct misdn_jb *jb, char *data, int len)
 gets len bytes out of the jitterbuffer if available, else only the available data is returned and the return value indicates the number of data.
int misdn_jb_fill (struct misdn_jb *jb, const char *data, int len)
 fills the jitterbuffer with len data returns < 0 if there was an error (buffer overrun).
struct misdn_jbmisdn_jb_init (int size, int upper_threshold)
 allocates the jb-structure and initialize the elements
static int misdn_l1_task (const void *vdata)
static struct ast_channelmisdn_new (struct chan_list *cl, int state, char *exten, char *callerid, int format, int port, int c)
static int misdn_overlap_dial_task (const void *data)
static struct ast_framemisdn_read (struct ast_channel *ast)
static struct ast_channelmisdn_request (const char *type, int format, void *data, int *cause)
static int misdn_send_text (struct ast_channel *chan, const char *text)
static int misdn_set_opt_exec (struct ast_channel *chan, void *data)
static int misdn_tasks_add (int timeout, ast_sched_cb callback, const void *data)
static int misdn_tasks_add_variable (int timeout, ast_sched_cb callback, const void *data)
static void misdn_tasks_destroy (void)
static void misdn_tasks_init (void)
static void misdn_tasks_remove (int task_id)
static void * misdn_tasks_thread_func (void *data)
static void misdn_tasks_wakeup (void)
static int misdn_write (struct ast_channel *ast, struct ast_frame *frame)
static int pbx_start_chan (struct chan_list *ch)
static void print_bc_info (int fd, struct chan_list *help, struct misdn_bchannel *bc)
static void print_bearer (struct misdn_bchannel *bc)
static void print_facility (struct FacParm *fac, struct misdn_bchannel *bc)
static struct ast_frameprocess_ast_dsp (struct chan_list *tmp, struct ast_frame *frame)
static int read_config (struct chan_list *ch, int orig)
static void release_chan (struct chan_list *ch, struct misdn_bchannel *bc)
static void release_chan_early (struct chan_list *ch)
static int reload (void)
static void reload_config (void)
static void send_cause2ast (struct ast_channel *ast, struct misdn_bchannel *bc, struct chan_list *ch)
static void send_digit_to_chan (struct chan_list *cl, char digit)
static void show_config_description (int fd, enum misdn_cfg_elements elem)
static void sighandler (int sig)
static int start_bc_tones (struct chan_list *cl)
static void start_pbx (struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan)
static int stop_bc_tones (struct chan_list *cl)
static int stop_indicate (struct chan_list *cl)
static int unload_module (void)
static int update_config (struct chan_list *ch, int orig)
 Updates caller ID information from config.
static int update_ec_config (struct misdn_bchannel *bc)
static void update_name (struct ast_channel *tmp, int port, int c)
static void wait_for_digits (struct chan_list *ch, struct misdn_bchannel *bc, struct ast_channel *chan)

Variables

static struct ast_module_info
__MODULE_INFO_SECTION 
__mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Channel driver for mISDN Support (BRI/PRI)" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, }
static struct allowed_bearers allowed_bearers_array []
static struct ast_module_infoast_module_info = &__mod_info
static struct ast_cli_entry chan_misdn_clis []
struct chan_listcl_te = NULL
 Global channel call record list head.
ast_mutex_t cl_te_lock
struct chan_list dummy_cl
static int g_config_initialized = 0
static int glob_channel = 0
char global_tracefile [BUFFERSIZE+1]
static int max_ports
int MAXTICS = 8
static int * misdn_debug
static int * misdn_debug_only
static int * misdn_in_calls
static int * misdn_out_calls
static int * misdn_ports
static struct sched_contextmisdn_tasks = NULL
 the main schedule context for stuff like l1 watcher, overlap dial, ...
static pthread_t misdn_tasks_thread
static struct ast_channel_tech misdn_tech
static struct ast_channel_tech misdn_tech_wo_bridge
static const char misdn_type [] = "mISDN"
static int prefformat = AST_FORMAT_ALAW
 Only alaw and mulaw is allowed for now.
ast_mutex_t release_lock
static struct robin_listrobin
static struct state_struct state_array []
static int tracing = 0

Detailed Description

the chan_misdn channel driver for Asterisk

Author:
Christian Richter <crich@beronet.com>
ExtRef:
MISDN http://www.misdn.org/

Definition in file chan_misdn.c.


Define Documentation

#define MISDN_ASTERISK_PVT (   ast)    1

Definition at line 486 of file chan_misdn.c.

Referenced by cb_events(), and do_immediate_setup().

#define ORG_MISDN   2

Definition at line 134 of file chan_misdn.c.

Referenced by cb_events(), and misdn_indication().

#define TRANSFER_ON_HELD_CALL_HANGUP   1

Definition at line 3834 of file chan_misdn.c.


Enumeration Type Documentation

Enumerator:
MISDN_NOTHING 

at beginning

MISDN_WAITING4DIGS 

when waiting for info

MISDN_EXTCANTMATCH 

when asterisk couldn't match our ext

MISDN_INCOMING_SETUP 

for incoming setup

MISDN_DIALING 

when pbx_start

MISDN_PROGRESS 

we have progress

MISDN_PROCEEDING 

we have progress

MISDN_CALLING 

when misdn_call is called

MISDN_CALLING_ACKNOWLEDGE 

when we get SETUP_ACK

MISDN_ALERTING 

when Alerting

MISDN_BUSY 

when BUSY

MISDN_CONNECTED 

when connected

MISDN_DISCONNECTED 

when connected

MISDN_CLEANING 

when hangup from * but we were connected before

Definition at line 116 of file chan_misdn.c.

                      {
   MISDN_NOTHING = 0,         /*!< at beginning */
   MISDN_WAITING4DIGS,        /*!< when waiting for info */
   MISDN_EXTCANTMATCH,        /*!< when asterisk couldn't match our ext */
   MISDN_INCOMING_SETUP,      /*!< for incoming setup */
   MISDN_DIALING,             /*!< when pbx_start */
   MISDN_PROGRESS,            /*!< we have progress */
   MISDN_PROCEEDING,          /*!< we have progress */
   MISDN_CALLING,             /*!< when misdn_call is called */
   MISDN_CALLING_ACKNOWLEDGE, /*!< when we get SETUP_ACK */
   MISDN_ALERTING,            /*!< when Alerting */
   MISDN_BUSY,                /*!< when BUSY */
   MISDN_CONNECTED,           /*!< when connected */
   MISDN_DISCONNECTED,        /*!< when connected */
   MISDN_CLEANING,            /*!< when hangup from * but we were connected before */
};
Enumerator:
MISDN_HOLD_IDLE 

HOLD not active

MISDN_HOLD_ACTIVE 

Call is held

MISDN_HOLD_TRANSFER 

Held call is being transferred

MISDN_HOLD_DISCONNECT 

Held call is being disconnected

Definition at line 136 of file chan_misdn.c.

                      {
   MISDN_HOLD_IDLE,     /*!< HOLD not active */
   MISDN_HOLD_ACTIVE,      /*!< Call is held */
   MISDN_HOLD_TRANSFER, /*!< Held call is being transferred */
   MISDN_HOLD_DISCONNECT,  /*!< Held call is being disconnected */
};

Function Documentation

static void __reg_module ( void  ) [static]

Definition at line 6196 of file chan_misdn.c.

static void __unreg_module ( void  ) [static]

Definition at line 6196 of file chan_misdn.c.

static int _misdn_tasks_add_variable ( int  timeout,
ast_sched_cb  callback,
const void *  data,
int  variable 
) [inline, static]

Definition at line 810 of file chan_misdn.c.

References ast_sched_add_variable(), misdn_tasks_init(), and misdn_tasks_wakeup().

Referenced by misdn_tasks_add(), and misdn_tasks_add_variable().

{
   int task_id;

   if (!misdn_tasks) {
      misdn_tasks_init();
   }
   task_id = ast_sched_add_variable(misdn_tasks, timeout, callback, data, variable);
   misdn_tasks_wakeup();

   return task_id;
}
int add_in_calls ( int  port)

Definition at line 4319 of file chan_misdn.c.

References ast_log(), LOG_NOTICE, misdn_cfg_get(), and MISDN_CFG_MAX_IN.

Referenced by cb_events().

{
   int max_in_calls;
   
   misdn_cfg_get(port, MISDN_CFG_MAX_IN, &max_in_calls, sizeof(max_in_calls));
   misdn_in_calls[port]++;

   if (max_in_calls >= 0 && max_in_calls < misdn_in_calls[port]) {
      ast_log(LOG_NOTICE, "Marking Incoming Call on port[%d]\n", port);
      return misdn_in_calls[port] - max_in_calls;
   }
   
   return 0;
}
int add_out_calls ( int  port)

Definition at line 4334 of file chan_misdn.c.

References ast_log(), LOG_NOTICE, misdn_cfg_get(), and MISDN_CFG_MAX_OUT.

Referenced by misdn_call().

{
   int max_out_calls;
   
   misdn_cfg_get(port, MISDN_CFG_MAX_OUT, &max_out_calls, sizeof(max_out_calls));

   if (max_out_calls >= 0 && max_out_calls <= misdn_out_calls[port]) {
      ast_log(LOG_NOTICE, "Rejecting Outgoing Call on port[%d]\n", port);
      return (misdn_out_calls[port] + 1) - max_out_calls;
   }

   misdn_out_calls[port]++;
   
   return 0;
}
static const char* bearer2str ( int  cap) [static]

Definition at line 602 of file chan_misdn.c.

References ARRAY_LEN, and allowed_bearers::display.

Referenced by cb_events(), print_bc_info(), and print_bearer().

{
   unsigned index;

   for (index = 0; index < ARRAY_LEN(allowed_bearers_array); ++index) {
      if (allowed_bearers_array[index].cap == cap) {
         return allowed_bearers_array[index].display;
      }
   }

   return "Unknown Bearer";
}
static enum event_response_e cb_events ( enum event_e  event,
struct misdn_bchannel bc,
void *  user_data 
) [static]

queue new chan

Sending SETUP_ACK

Supplementary Services

Definition at line 4376 of file chan_misdn.c.

References add_in_calls(), misdn_bchannel::addr, chan_list::addr, chan_list::allowed_bearers, misdn_bchannel::AOCD, misdn_bchannel::AOCD_need_export, misdn_bchannel::AOCDtype, ARRAY_LEN, chan_list::ast, ast_bridged_channel(), ast_canmatch_extension(), AST_CAUSE_DESTINATION_OUT_OF_ORDER, AST_CAUSE_INCOMPATIBLE_DESTINATION, AST_CAUSE_NORMAL_CLEARING, AST_CAUSE_UNALLOCATED, AST_CAUSE_USER_BUSY, ast_cdr_update(), AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_HOLD, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RINGING, AST_CONTROL_UNHOLD, ast_copy_string(), ast_deactivate_generator(), ast_exists_extension(), AST_FORMAT_ALAW, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_free, ast_log(), ast_mutex_lock(), ast_mutex_unlock(), ast_pickup_call(), ast_pickup_ext(), ast_poll, AST_PRES_ALLOWED, AST_PRES_NETWORK_NUMBER, AST_PRES_RESTRICTED, AST_PRES_UNAVAILABLE, AST_PRES_USER_NUMBER_FAILED_SCREEN, AST_PRES_USER_NUMBER_PASSED_SCREEN, AST_PRES_USER_NUMBER_UNSCREENED, ast_queue_control(), ast_queue_frame(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, AST_STATE_RINGING, ast_strlen_zero(), ast_transfercapability2str(), ast_tv(), ast_tvnow(), chan_list::bc, misdn_bchannel::bc_state, bc_state2str(), bearer2str(), misdn_bchannel::bframe, misdn_bchannel::bframe_len, misdn_bchannel::cad, misdn_bchannel::capability, misdn_bchannel::cause, cause, cb_log, chan, chan_misdn_log(), hold_info::channel, misdn_bchannel::channel, misdn_bchannel::chargingUnit, ast_channel::cid, ast_callerid::cid_pres, cl_queue_chan(), chan_list::context, misdn_bchannel::cpnnumplan, misdn_bchannel::currency, misdn_bchannel::cw, misdn_bchannel::dad, ast_frame::data, ast_frame::datalen, ast_frame::delivery, do_immediate_setup(), misdn_bchannel::dtmf, misdn_bchannel::dummy, errno, EVENT_ALERTING, EVENT_BCHAN_ACTIVATED, EVENT_BCHAN_DATA, EVENT_BCHAN_ERROR, EVENT_CLEANUP, EVENT_CONNECT, EVENT_CONNECT_ACKNOWLEDGE, EVENT_DISCONNECT, EVENT_DTMF_TONE, EVENT_FACILITY, EVENT_HOLD, EVENT_HOLD_ACKNOWLEDGE, EVENT_HOLD_REJECT, EVENT_INFORMATION, EVENT_NEW_BC, EVENT_NEW_CHANNEL, EVENT_NEW_L3ID, EVENT_PORT_ALARM, EVENT_PROCEEDING, EVENT_PROGRESS, EVENT_RELEASE, EVENT_RELEASE_COMPLETE, EVENT_RESTART, EVENT_RETRIEVE, EVENT_RETRIEVE_ACKNOWLEDGE, EVENT_RETRIEVE_REJECT, EVENT_SETUP, EVENT_SETUP_ACKNOWLEDGE, EVENT_STATUS, EVENT_TIMEOUT, EVENT_TONE_GENERATE, export_aoc_vars(), export_ch(), ast_channel::exten, misdn_bchannel::fac_in, chan_list::far_alerting, find_chan_by_bc(), find_hold_active_call(), find_hold_call(), find_hold_call_l3(), ast_frame::frametype, ast_generator::generate, ast_channel::generator, ast_channel::generatordata, hangup_chan(), ast_channel::hangupcause, hanguptone_indicate(), chan_list::hold, chan_list::ignore_dtmf, INFO_CAPABILITY_DIGITAL_UNRESTRICTED, misdn_bchannel::info_dad, INFO_PI_INBAND_AVAILABLE, misdn_bchannel::infos_pending, init_chan_list(), misdn_bchannel::keypad, misdn_bchannel::l3_id, chan_list::l3id, LOG_ERROR, LOG_NOTICE, LOG_WARNING, ast_frame::mallocd, manager_isdn_get_info(), MISDN_ALERTING, MISDN_ASTERISK_PVT, MISDN_ASTERISK_TECH_PVT, misdn_attempt_transfer(), MISDN_CALLING, MISDN_CALLING_ACKNOWLEDGE, misdn_cap_is_speech(), MISDN_CFG_ALARM_BLOCK, MISDN_CFG_ALWAYS_IMMEDIATE, misdn_cfg_get(), MISDN_CFG_HOLD_ALLOWED, MISDN_CFG_IMMEDIATE, misdn_cfg_is_msn_valid(), MISDN_CFG_REJECT_CAUSE, MISDN_CLEANING, MISDN_CONNECTED, MISDN_DIALING, MISDN_DISCONNECTED, MISDN_EXTCANTMATCH, MISDN_GEN_APPEND_DIGITS2EXTEN, misdn_get_ch_state(), MISDN_HOLD_ACTIVE, MISDN_HOLD_DISCONNECT, MISDN_HOLD_IDLE, misdn_inband_avail(), MISDN_INCOMING_SETUP, misdn_lib_is_ptp(), misdn_lib_log_ies(), misdn_lib_port_block(), misdn_lib_send_event(), misdn_new(), MISDN_NOTHING, misdn_overlap_dial_task(), MISDN_PROCEEDING, MISDN_PROGRESS, misdn_tasks_add_variable(), MISDN_WAITING4DIGS, allowed_bearers::name, chan_list::need_busy, misdn_bchannel::need_disconnect, misdn_bchannel::need_more_infos, misdn_bchannel::need_release, misdn_bchannel::need_release_complete, chan_list::noautorespond_on_setup, misdn_bchannel::nt, chan_list::nttimeout, misdn_bchannel::oad, ast_frame::offset, ORG_AST, ORG_MISDN, chan_list::originator, misdn_bchannel::out_cause, chan_list::overlap_dial, chan_list::overlap_dial_task, chan_list::overlap_tv, chan_list::overlap_tv_lock, pbx_builtin_setvar_helper(), pbx_start_chan(), misdn_bchannel::pid, chan_list::pipe, hold_info::port, misdn_bchannel::port, misdn_bchannel::pres, print_bearer(), print_facility(), misdn_bchannel::progress_indicator, ast_frame::ptr, read_config(), release_chan(), RESPONSE_IGNORE_SETUP, RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE, RESPONSE_OK, RESPONSE_RELEASE_SETUP, ast_channel::rings, ast_frame::samples, misdn_bchannel::screen, misdn_bchannel::sending_complete, ast_frame::src, start_bc_tones(), start_pbx(), hold_info::state, chan_list::state, stop_bc_tones(), stop_indicate(), ast_frame::subclass, ast_channel::tech, misdn_bchannel::tone_cnt, ast_channel::transfercapability, ast_channel_tech::type, update_name(), and wait_for_digits().

Referenced by load_module().

{
   int msn_valid;
   struct chan_list *held_ch;
   struct chan_list *ch = find_chan_by_bc(cl_te, bc);
   
   if (event != EVENT_BCHAN_DATA && event != EVENT_TONE_GENERATE) { /*  Debug Only Non-Bchan */
      int debuglevel = 1;
      if ( event == EVENT_CLEANUP && !user_data) {
         debuglevel = 5;
      }

      chan_misdn_log(debuglevel, bc->port, "I IND :%s oad:%s dad:%s pid:%d state:%s\n", manager_isdn_get_info(event), bc->oad, bc->dad, bc->pid, ch ? misdn_get_ch_state(ch) : "none");
      if (debuglevel == 1) {
         misdn_lib_log_ies(bc);
         chan_misdn_log(4, bc->port, " --> bc_state:%s\n", bc_state2str(bc->bc_state));
      }
   }
   
   if (!ch) {
      switch(event) {
      case EVENT_SETUP:
      case EVENT_DISCONNECT:
      case EVENT_RELEASE:
      case EVENT_RELEASE_COMPLETE:
      case EVENT_PORT_ALARM:
      case EVENT_RETRIEVE:
      case EVENT_NEW_BC:
      case EVENT_FACILITY:
         break;
      case EVENT_CLEANUP:
      case EVENT_TONE_GENERATE:
      case EVENT_BCHAN_DATA:
         return -1;
      default:
         chan_misdn_log(1, bc->port, "Chan not existing at the moment bc->l3id:%x bc:%p event:%s port:%d channel:%d\n", bc->l3_id, bc, manager_isdn_get_info(event), bc->port, bc->channel);
         return -1;
      }
   }
   
   if (ch) {
      switch (event) {
      case EVENT_TONE_GENERATE:
         break;
      case EVENT_DISCONNECT:
      case EVENT_RELEASE:
      case EVENT_RELEASE_COMPLETE:
      case EVENT_CLEANUP:
      case EVENT_TIMEOUT:
         if (!ch->ast) {
            chan_misdn_log(3, bc->port, "ast_hangup already called, so we have no ast ptr anymore in event(%s)\n", manager_isdn_get_info(event));
         }
         break;
      default:
         if (!ch->ast  || !MISDN_ASTERISK_PVT(ch->ast) || !MISDN_ASTERISK_TECH_PVT(ch->ast)) {
            if (event != EVENT_BCHAN_DATA) {
               ast_log(LOG_NOTICE, "No Ast or No private Pointer in Event (%d:%s)\n", event, manager_isdn_get_info(event));
            }
            return -1;
         }
      }
   }
   
   
   switch (event) {
   case EVENT_PORT_ALARM:
      {
         int boa = 0;
         misdn_cfg_get(bc->port, MISDN_CFG_ALARM_BLOCK, &boa, sizeof(boa));
         if (boa) {
            cb_log(1, bc->port, " --> blocking\n");
            misdn_lib_port_block(bc->port); 
         }
      }
      break;
   case EVENT_BCHAN_ACTIVATED:
      break;
      
   case EVENT_NEW_CHANNEL:
      update_name(ch->ast,bc->port,bc->channel);
      break;
      
   case EVENT_NEW_L3ID:
      ch->l3id=bc->l3_id;
      ch->addr=bc->addr;
      break;

   case EVENT_NEW_BC:
      if (!ch) {
         ch = find_hold_call(cl_te,bc);
      }
      
      if (!ch) {
         ast_log(LOG_WARNING, "NEW_BC without chan_list?\n");
         break;
      }

      if (bc) {
         ch->bc = (struct misdn_bchannel *)user_data;
      }
      break;
      
   case EVENT_DTMF_TONE:
   {
      /*  sending INFOS as DTMF-Frames :) */
      struct ast_frame fr;

      memset(&fr, 0, sizeof(fr));
      fr.frametype = AST_FRAME_DTMF;
      fr.subclass = bc->dtmf ;
      fr.src = NULL;
      fr.data.ptr = NULL;
      fr.datalen = 0;
      fr.samples = 0;
      fr.mallocd = 0;
      fr.offset = 0;
      fr.delivery = ast_tv(0,0);
      
      if (!ch->ignore_dtmf) {
         chan_misdn_log(2, bc->port, " --> DTMF:%c\n", bc->dtmf);
         ast_queue_frame(ch->ast, &fr);
      } else {
         chan_misdn_log(2, bc->port, " --> Ignoring DTMF:%c due to bridge flags\n", bc->dtmf);
      }
   }
      break;
   case EVENT_STATUS:
      break;
    
   case EVENT_INFORMATION:
      if (ch->state != MISDN_CONNECTED) {
         stop_indicate(ch);
      }
   
      if (!ch->ast) {
         break;
      }

      if (ch->state == MISDN_WAITING4DIGS ) {
         /*  Ok, incomplete Setup, waiting till extension exists */
         if (ast_strlen_zero(bc->info_dad) && ! ast_strlen_zero(bc->keypad)) {
            chan_misdn_log(1, bc->port, " --> using keypad as info\n");
            ast_copy_string(bc->info_dad, bc->keypad, sizeof(bc->info_dad));
         }

         strncat(bc->dad, bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1);
         ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));

         /* Check for Pickup Request first */
         if (!strcmp(ch->ast->exten, ast_pickup_ext())) {
            if (ast_pickup_call(ch->ast)) {
               hangup_chan(ch, bc);
            } else {
               struct ast_channel *chan = ch->ast;
               ch->state = MISDN_CALLING_ACKNOWLEDGE;
               ast_setstate(chan, AST_STATE_DOWN);
               hangup_chan(ch, bc);
               ch->ast = NULL;
               break;
            }
         }
         
         if (!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
            if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) {
               ast_log(LOG_WARNING,
                  "Extension '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
                  bc->dad, ch->context, bc->port);
               strcpy(ch->ast->exten, "i");

               ch->state = MISDN_DIALING;
               start_pbx(ch, bc, ch->ast);
               break;
            }

            ast_log(LOG_WARNING,
               "Extension '%s@%s' can never match. Disconnecting. port:%d\n"
               "\tMaybe you want to add an 'i' extension to catch this case.\n",
               bc->dad, ch->context, bc->port);

            if (bc->nt) {
               hanguptone_indicate(ch);
            }
            ch->state = MISDN_EXTCANTMATCH;
            bc->out_cause = AST_CAUSE_UNALLOCATED;

            misdn_lib_send_event(bc, EVENT_DISCONNECT);
            break;
         }

         if (ch->overlap_dial) {
            ast_mutex_lock(&ch->overlap_tv_lock);
            ch->overlap_tv = ast_tvnow();
            ast_mutex_unlock(&ch->overlap_tv_lock);
            if (ch->overlap_dial_task == -1) {
               ch->overlap_dial_task = 
                  misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch);
            }
            break;
         }

         if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad))  {
            ch->state = MISDN_DIALING;
            start_pbx(ch, bc, ch->ast);
         }
      } else {
         /*  sending INFOS as DTMF-Frames :) */
         struct ast_frame fr;
         int digits;

         memset(&fr, 0, sizeof(fr));
         fr.frametype = AST_FRAME_DTMF;
         fr.subclass = bc->info_dad[0] ;
         fr.src = NULL;
         fr.data.ptr = NULL;
         fr.datalen = 0;
         fr.samples = 0;
         fr.mallocd = 0;
         fr.offset = 0;
         fr.delivery = ast_tv(0,0);

         misdn_cfg_get(0, MISDN_GEN_APPEND_DIGITS2EXTEN, &digits, sizeof(digits));
         if (ch->state != MISDN_CONNECTED ) {
            if (digits) {
               strncat(bc->dad, bc->info_dad, sizeof(bc->dad) - strlen(bc->dad) - 1);
               ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
               ast_cdr_update(ch->ast);
            }
            
            ast_queue_frame(ch->ast, &fr);
         }
      }
      break;
   case EVENT_SETUP:
   {
      struct chan_list *ch = find_chan_by_bc(cl_te, bc);
      struct ast_channel *chan;
      int exceed;
      int pres, screen;
      int ai;
      int im;

      if (ch) {
         switch (ch->state) {
         case MISDN_NOTHING:
            ch = NULL;
            break;
         default:
            chan_misdn_log(1, bc->port, " --> Ignoring Call we have already one\n");
            return RESPONSE_IGNORE_SETUP_WITHOUT_CLOSE; /*  Ignore MSNs which are not in our List */
         }
      }

      msn_valid = misdn_cfg_is_msn_valid(bc->port, bc->dad);
      if (!bc->nt && ! msn_valid) {
         chan_misdn_log(1, bc->port, " --> Ignoring Call, its not in our MSN List\n");
         return RESPONSE_IGNORE_SETUP; /*  Ignore MSNs which are not in our List */
      }

      if (bc->cw) {
         int cause;
         chan_misdn_log(0, bc->port, " --> Call Waiting on PMP sending RELEASE_COMPLETE\n");
         misdn_cfg_get(bc->port, MISDN_CFG_REJECT_CAUSE, &cause, sizeof(cause));
         bc->out_cause = cause ? cause : AST_CAUSE_NORMAL_CLEARING;
         return RESPONSE_RELEASE_SETUP;
      }

      print_bearer(bc);

      ch = init_chan_list(ORG_MISDN);

      if (!ch) {
         chan_misdn_log(-1, bc->port, "cb_events: malloc for chan_list failed!\n");
         return 0;
      }

      ch->bc = bc;
      ch->l3id = bc->l3_id;
      ch->addr = bc->addr;
      ch->originator = ORG_MISDN;

      chan = misdn_new(ch, AST_STATE_RESERVED, bc->dad, bc->oad, AST_FORMAT_ALAW, bc->port, bc->channel);
      if (!chan) {
         ast_free(ch);
         misdn_lib_send_event(bc,EVENT_RELEASE_COMPLETE);
         ast_log(LOG_ERROR, "cb_events: misdn_new failed !\n"); 
         return 0;
      }

      ch->ast = chan;

      if ((exceed = add_in_calls(bc->port))) {
         char tmp[16];
         snprintf(tmp, sizeof(tmp), "%d", exceed);
         pbx_builtin_setvar_helper(chan, "MAX_OVERFLOW", tmp);
      }

      read_config(ch, ORG_MISDN);

      export_ch(chan, bc, ch);

      ch->ast->rings = 1;
      ast_setstate(ch->ast, AST_STATE_RINGING);

      switch (bc->pres) {
      case 1:
         pres = AST_PRES_RESTRICTED;
         chan_misdn_log(2, bc->port, " --> PRES: Restricted (1)\n");
         break;
      case 2:
         pres = AST_PRES_UNAVAILABLE;
         chan_misdn_log(2, bc->port, " --> PRES: Unavailable (2)\n");
         break;
      default:
         pres = AST_PRES_ALLOWED;
         chan_misdn_log(2, bc->port, " --> PRES: Allowed (%d)\n", bc->pres);
         break;
      }

      switch (bc->screen) {
      default:
      case 0:
         screen = AST_PRES_USER_NUMBER_UNSCREENED;
         chan_misdn_log(2, bc->port, " --> SCREEN: Unscreened (%d)\n", bc->screen);
         break;
      case 1:
         screen = AST_PRES_USER_NUMBER_PASSED_SCREEN;
         chan_misdn_log(2, bc->port, " --> SCREEN: Passed screen (1)\n");
         break;
      case 2:
         screen = AST_PRES_USER_NUMBER_FAILED_SCREEN;
         chan_misdn_log(2, bc->port, " --> SCREEN: failed screen (2)\n");
         break;
      case 3:
         screen = AST_PRES_NETWORK_NUMBER;
         chan_misdn_log(2, bc->port, " --> SCREEN: Network Number (3)\n");
         break;
      }

      chan->cid.cid_pres = pres | screen;

      pbx_builtin_setvar_helper(chan, "TRANSFERCAPABILITY", ast_transfercapability2str(bc->capability));
      chan->transfercapability = bc->capability;

      switch (bc->capability) {
      case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
         pbx_builtin_setvar_helper(chan, "CALLTYPE", "DIGITAL");
         break;
      default:
         pbx_builtin_setvar_helper(chan, "CALLTYPE", "SPEECH");
      }

      /** queue new chan **/
      cl_queue_chan(&cl_te, ch);

      if (!strstr(ch->allowed_bearers, "all")) {
         int i;

         for (i = 0; i < ARRAY_LEN(allowed_bearers_array); ++i) {
            if (allowed_bearers_array[i].cap == bc->capability) {
               if (strstr(ch->allowed_bearers, allowed_bearers_array[i].name)) {
                  /* The bearer capability is allowed */
                  if (allowed_bearers_array[i].deprecated) {
                     chan_misdn_log(0, bc->port, "%s in allowed_bearers list is deprecated\n",
                        allowed_bearers_array[i].name);
                  }
                  break;
               }
            }
         }  /* end for */
         if (i == ARRAY_LEN(allowed_bearers_array)) {
            /* We did not find the bearer capability */
            chan_misdn_log(0, bc->port, "Bearer capability not allowed: %s(%d)\n",
               bearer2str(bc->capability), bc->capability);
            bc->out_cause = AST_CAUSE_INCOMPATIBLE_DESTINATION;

            ch->state = MISDN_EXTCANTMATCH;
            misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
            return RESPONSE_OK;
         }
      }

      /* Check for Pickup Request first */
      if (!strcmp(chan->exten, ast_pickup_ext())) {
         if (!ch->noautorespond_on_setup) {
            int ret;/** Sending SETUP_ACK**/
            ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
         } else {
            ch->state = MISDN_INCOMING_SETUP;
         }
         if (ast_pickup_call(chan)) {
            hangup_chan(ch, bc);
         } else {
            ch->state = MISDN_CALLING_ACKNOWLEDGE;
            ast_setstate(chan, AST_STATE_DOWN);
            hangup_chan(ch, bc);
            ch->ast = NULL;
            break;
         }
      }

      /*
       * added support for s extension hope it will help those poor cretains
       * which haven't overlap dial.
       */
      misdn_cfg_get(bc->port, MISDN_CFG_ALWAYS_IMMEDIATE, &ai, sizeof(ai));
      if (ai) {
         do_immediate_setup(bc, ch, chan);
         break;
      }

      /* check if we should jump into s when we have no dad */
      misdn_cfg_get(bc->port, MISDN_CFG_IMMEDIATE, &im, sizeof(im));
      if (im && ast_strlen_zero(bc->dad)) {
         do_immediate_setup(bc, ch, chan);
         break;
      }

      chan_misdn_log(5, bc->port, "CONTEXT:%s\n", ch->context);
      if (!ast_canmatch_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
         if (ast_exists_extension(ch->ast, ch->context, "i", 1, bc->oad)) {
            ast_log(LOG_WARNING,
               "Extension '%s@%s' can never match. Jumping to 'i' extension. port:%d\n",
               bc->dad, ch->context, bc->port);
            strcpy(ch->ast->exten, "i");
            misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE);
            ch->state = MISDN_DIALING;
            start_pbx(ch, bc, chan);
            break;
         }

         ast_log(LOG_WARNING,
            "Extension '%s@%s' can never match. Disconnecting. port:%d\n"
            "\tMaybe you want to add an 'i' extension to catch this case.\n",
            bc->dad, ch->context, bc->port);
         if (bc->nt) {
            hanguptone_indicate(ch);
         }

         ch->state = MISDN_EXTCANTMATCH;
         bc->out_cause = AST_CAUSE_UNALLOCATED;

         misdn_lib_send_event(bc, bc->nt ? EVENT_RELEASE_COMPLETE : EVENT_RELEASE);

         break;
      }

      /* Whatever happens, when sending_complete is set or we are PTMP TE, we will definitely 
       * jump into the dialplan, when the dialed extension does not exist, the 's' extension 
       * will be used by Asterisk automatically. */
      if (bc->sending_complete || (!bc->nt && !misdn_lib_is_ptp(bc->port))) {
         if (!ch->noautorespond_on_setup) {
            ch->state=MISDN_DIALING;
            misdn_lib_send_event(bc, EVENT_PROCEEDING );
         } else {
            ch->state = MISDN_INCOMING_SETUP;
         }
         start_pbx(ch, bc, chan);
         break;
      }


      /*
       * When we are NT and overlapdial is set and if 
       * the number is empty, we wait for the ISDN timeout
       * instead of our own timer.
       */
      if (ch->overlap_dial && bc->nt && !bc->dad[0] ) {
         wait_for_digits(ch, bc, chan);
         break;
      }

      /* 
       * If overlapdial we will definitely send a SETUP_ACKNOWLEDGE and wait for more 
       * Infos with a Interdigit Timeout.
       * */
      if (ch->overlap_dial) {
         ast_mutex_lock(&ch->overlap_tv_lock);
         ch->overlap_tv = ast_tvnow();
         ast_mutex_unlock(&ch->overlap_tv_lock);

         wait_for_digits(ch, bc, chan);
         if (ch->overlap_dial_task == -1) {
            ch->overlap_dial_task = 
               misdn_tasks_add_variable(ch->overlap_dial, misdn_overlap_dial_task, ch);
         }
         break;
      }

      /* If the extension does not exist and we're not TE_PTMP we wait for more digits 
       * without interdigit timeout.
       * */
      if (!ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad))  {
         wait_for_digits(ch, bc, chan);
         break;
      }

      /*
       * If the extension exists let's just jump into it.
       * */
      if (ast_exists_extension(ch->ast, ch->context, bc->dad, 1, bc->oad)) {
         misdn_lib_send_event(bc, bc->need_more_infos ? EVENT_SETUP_ACKNOWLEDGE : EVENT_PROCEEDING);
         ch->state = MISDN_DIALING;
         start_pbx(ch, bc, chan);
         break;
      }
   }
      break;

   case EVENT_SETUP_ACKNOWLEDGE:
      ch->state = MISDN_CALLING_ACKNOWLEDGE;

      if (bc->channel) 
         update_name(ch->ast,bc->port,bc->channel);
      
      if (!ast_strlen_zero(bc->infos_pending)) {
         /* TX Pending Infos */
         strncat(bc->dad, bc->infos_pending, sizeof(bc->dad) - strlen(bc->dad) - 1);

         if (!ch->ast) {
            break;
         }
         ast_copy_string(ch->ast->exten, bc->dad, sizeof(ch->ast->exten));
         ast_copy_string(bc->info_dad, bc->infos_pending, sizeof(bc->info_dad));
         ast_copy_string(bc->infos_pending, "", sizeof(bc->infos_pending));

         misdn_lib_send_event(bc, EVENT_INFORMATION);
      }
      break;
   case EVENT_PROCEEDING:
      if (misdn_cap_is_speech(bc->capability) &&
           misdn_inband_avail(bc) ) {
         start_bc_tones(ch);
      }

      ch->state = MISDN_PROCEEDING;
      
      if (!ch->ast) {
         break;
      }

      ast_queue_control(ch->ast, AST_CONTROL_PROCEEDING);
      break;
   case EVENT_PROGRESS:
      if (bc->channel) {
         update_name(ch->ast, bc->port, bc->channel);
      }

      if (!bc->nt ) {
         if (misdn_cap_is_speech(bc->capability) &&
            misdn_inband_avail(bc)) {
            start_bc_tones(ch);
         }
         
         ch->state = MISDN_PROGRESS;

         if (!ch->ast) {
            break;
         }
         ast_queue_control(ch->ast, AST_CONTROL_PROGRESS);
      }
      break;
   case EVENT_ALERTING:
      ch->state = MISDN_ALERTING;
      
      if (!ch->ast) {
         break;
      }

      ast_queue_control(ch->ast, AST_CONTROL_RINGING);
      ast_setstate(ch->ast, AST_STATE_RINGING);
      
      cb_log(7, bc->port, " --> Set State Ringing\n");
      
      if (misdn_cap_is_speech(bc->capability) && misdn_inband_avail(bc)) {
         cb_log(1, bc->port, "Starting Tones, we have inband Data\n");
         start_bc_tones(ch);
      } else {
         cb_log(3, bc->port, " --> We have no inband Data, the other end must create ringing\n");
         if (ch->far_alerting) {
            cb_log(1, bc->port, " --> The other end can not do ringing eh ?.. we must do all ourself..");
            start_bc_tones(ch);
            /*tone_indicate(ch, TONE_FAR_ALERTING);*/
         }
      }
      break;
   case EVENT_CONNECT:
      {
         struct ast_channel *bridged;

         /*we answer when we've got our very new L3 ID from the NT stack */
         misdn_lib_send_event(bc, EVENT_CONNECT_ACKNOWLEDGE);

         if (!ch->ast) {
            break;
         }

         bridged = ast_bridged_channel(ch->ast);
         stop_indicate(ch);

         if (bridged && !strcasecmp(bridged->tech->type, "mISDN")) {
            struct chan_list *bridged_ch = MISDN_ASTERISK_TECH_PVT(bridged);

            chan_misdn_log(1, bc->port, " --> copying cpndialplan:%d and cad:%s to the A-Channel\n", bc->cpnnumplan, bc->cad);
            if (bridged_ch) {
               bridged_ch->bc->cpnnumplan = bc->cpnnumplan;
               ast_copy_string(bridged_ch->bc->cad, bc->cad, sizeof(bridged_ch->bc->cad));
            }
         }
      }
      ch->l3id = bc->l3_id;
      ch->addr = bc->addr;

      start_bc_tones(ch);
   
      ch->state = MISDN_CONNECTED;
   
      ast_queue_control(ch->ast, AST_CONTROL_ANSWER);
      break;
   case EVENT_CONNECT_ACKNOWLEDGE:
      ch->l3id = bc->l3_id;
      ch->addr = bc->addr;

      start_bc_tones(ch);

      ch->state = MISDN_CONNECTED;
      break;
   case EVENT_DISCONNECT:
      /* we might not have an ch->ast ptr here anymore */
      if (ch) {
         chan_misdn_log(3, bc->port, " --> org:%d nt:%d, inbandavail:%d state:%d\n", ch->originator, bc->nt, misdn_inband_avail(bc), ch->state);
         if (ch->originator == ORG_AST && !bc->nt && misdn_inband_avail(bc) && ch->state != MISDN_CONNECTED) {
            /* If there's inband information available (e.g. a
               recorded message saying what was wrong with the
               dialled number, or perhaps even giving an
               alternative number, then play it instead of
               immediately releasing the call */
            chan_misdn_log(1, bc->port, " --> Inband Info Avail, not sending RELEASE\n");
      
            ch->state = MISDN_DISCONNECTED;
            start_bc_tones(ch);

            if (ch->ast) {
               ch->ast->hangupcause = bc->cause;
               if (bc->cause == AST_CAUSE_USER_BUSY) {
                  ast_queue_control(ch->ast, AST_CONTROL_BUSY);
               }
            }
            ch->need_busy = 0;
            break;
         }

         bc->need_disconnect = 0;
         stop_bc_tones(ch);

         /* Check for held channel, to implement transfer */
         held_ch = find_hold_call(cl_te, bc);
         if (!held_ch || !ch->ast || misdn_attempt_transfer(ch, held_ch)) {
            hangup_chan(ch, bc);
         }
      } else {
         held_ch = find_hold_call_l3(cl_te, bc->l3_id);
         if (held_ch && held_ch->hold.state == MISDN_HOLD_ACTIVE) {
            bc->need_disconnect = 0;

#if defined(TRANSFER_ON_HELD_CALL_HANGUP)
            /*
             * Some phones disconnect the held call and the active call at the
             * same time to do the transfer.  Unfortunately, either call could
             * be disconnected first.
             */
            ch = find_hold_active_call(cl_te, bc);
            if (!ch || misdn_attempt_transfer(ch, held_ch)) {
               held_ch->hold.state = MISDN_HOLD_DISCONNECT;
               hangup_chan(held_ch, bc);
            }
#else
            hangup_chan(held_ch, bc);
#endif   /* defined(TRANSFER_ON_HELD_CALL_HANGUP) */
         }
      }
      bc->out_cause = -1;
      if (bc->need_release) {
         misdn_lib_send_event(bc, EVENT_RELEASE);
      }
      break;
   case EVENT_RELEASE:
      if (!ch) {
         ch = find_hold_call_l3(cl_te, bc->l3_id);
         if (!ch) {
            chan_misdn_log(1, bc->port,
               " --> no Ch, so we've already released. (%s)\n",
               manager_isdn_get_info(event));
            return -1;
         }
      }

      bc->need_disconnect = 0;
      bc->need_release = 0;

      hangup_chan(ch, bc);
      release_chan(ch, bc);
      break;
   case EVENT_RELEASE_COMPLETE:
      if (!ch) {
         ch = find_hold_call_l3(cl_te, bc->l3_id);
         if (!ch) {
            chan_misdn_log(1, bc->port,
               " --> no Ch, so we've already released. (%s)\n",
               manager_isdn_get_info(event));
            break;
         }
      }

      bc->need_disconnect = 0;
      bc->need_release = 0;
      bc->need_release_complete = 0;

      stop_bc_tones(ch);
      hangup_chan(ch, bc);
      release_chan(ch, bc);
      break;
   case EVENT_BCHAN_ERROR:
   case EVENT_CLEANUP:
      stop_bc_tones(ch);
      
      switch (ch->state) {
      case MISDN_CALLING:
         bc->cause = AST_CAUSE_DESTINATION_OUT_OF_ORDER;
         break;
      default:
         break;
      }
      
      hangup_chan(ch, bc);
      release_chan(ch, bc);
      break;
   case EVENT_TONE_GENERATE:
   {
      int tone_len = bc->tone_cnt;
      struct ast_channel *ast = ch->ast;
      void *tmp;
      int res;
      int (*generate)(struct ast_channel *chan, void *tmp, int datalen, int samples);

      chan_misdn_log(9, bc->port, "TONE_GEN: len:%d\n", tone_len);

      if (!ast) {
         break;
      }

      if (!ast->generator) {
         break;
      }

      tmp = ast->generatordata;
      ast->generatordata = NULL;
      generate = ast->generator->generate;

      if (tone_len < 0 || tone_len > 512 ) {
         ast_log(LOG_NOTICE, "TONE_GEN: len was %d, set to 128\n", tone_len);
         tone_len = 128;
      }

      res = generate(ast, tmp, tone_len, tone_len);
      ast->generatordata = tmp;
      
      if (res) {
         ast_log(LOG_WARNING, "Auto-deactivating generator\n");
         ast_deactivate_generator(ast);
      } else {
         bc->tone_cnt = 0;
      }
   }
      break;

   case EVENT_BCHAN_DATA:
      if (ch->bc->AOCD_need_export) {
         export_aoc_vars(ch->originator, ch->ast, ch->bc);
      }
      if (!misdn_cap_is_speech(ch->bc->capability)) {
         struct ast_frame frame;
         /*In Data Modes we queue frames*/
         memset(&frame, 0, sizeof(frame));
         frame.frametype = AST_FRAME_VOICE; /* we have no data frames yet */
         frame.subclass = AST_FORMAT_ALAW;
         frame.datalen = bc->bframe_len;
         frame.samples = bc->bframe_len;
         frame.mallocd = 0;
         frame.offset = 0;
         frame.delivery = ast_tv(0, 0);
         frame.src = NULL;
         frame.data.ptr = bc->bframe;

         if (ch->ast) 
            ast_queue_frame(ch->ast, &frame);
      } else {
         struct pollfd pfd = { .fd = ch->pipe[1], .events = POLLOUT };
         int t;

         t = ast_poll(&pfd, 1, 0);

         if (t < 0) {
            chan_misdn_log(-1, bc->port, "poll() error (err=%s)\n", strerror(errno));
            break;
         }

         if (!t) {
            chan_misdn_log(9, bc->port, "poll() timed out\n");
            break;
         }

         if (pfd.revents & POLLOUT) {
            chan_misdn_log(9, bc->port, "writing %d bytes to asterisk\n", bc->bframe_len);
            if (write(ch->pipe[1], bc->bframe, bc->bframe_len) <= 0) {
               chan_misdn_log(0, bc->port, "Write returned <=0 (err=%s) --> hanging up channel\n", strerror(errno));

               stop_bc_tones(ch);
               hangup_chan(ch, bc);
               release_chan(ch, bc);
            }
         } else {
            chan_misdn_log(1, bc->port, "Write Pipe full!\n");
         }
      }
      break;
   case EVENT_TIMEOUT:
      if (ch && bc) {
         chan_misdn_log(1, bc->port, "--> state: %s\n", misdn_get_ch_state(ch));
      }

      switch (ch->state) {
      case MISDN_DIALING:
      case MISDN_PROGRESS:
         if (bc->nt && !ch->nttimeout) {
            break;
         }
         /* fall-through */
      case MISDN_CALLING:
      case MISDN_ALERTING:
      case MISDN_PROCEEDING:
      case MISDN_CALLING_ACKNOWLEDGE:
         if (bc->nt) {
            bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
            hanguptone_indicate(ch);
         }

         bc->out_cause = AST_CAUSE_UNALLOCATED;
         misdn_lib_send_event(bc, EVENT_DISCONNECT);
         break;
      case MISDN_WAITING4DIGS:
         if (bc->nt) {
            bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
            bc->out_cause = AST_CAUSE_UNALLOCATED;
            hanguptone_indicate(ch);
            misdn_lib_send_event(bc, EVENT_DISCONNECT);
         } else {
            bc->out_cause = AST_CAUSE_NORMAL_CLEARING;
            misdn_lib_send_event(bc, EVENT_RELEASE);
         }
         break;
      case MISDN_CLEANING: 
         chan_misdn_log(1, bc->port, " --> in state cleaning .. so ignoring, the stack should clean it for us\n");
         break;
      default:
         misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
      }
      break;

   /****************************/
   /** Supplementary Services **/
   /****************************/
   case EVENT_RETRIEVE:
      if (!ch) {
         chan_misdn_log(4, bc->port, " --> no CH, searching for held call\n");
         ch = find_hold_call_l3(cl_te, bc->l3_id);
         if (!ch || ch->hold.state != MISDN_HOLD_ACTIVE) {
            ast_log(LOG_WARNING, "No held call found, cannot Retrieve\n");
            misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
            break;
         }
      }

      /* remember the channel again */
      ch->bc = bc;

      ch->hold.state = MISDN_HOLD_IDLE;
      ch->hold.port = 0;
      ch->hold.channel = 0;

      ast_queue_control(ch->ast, AST_CONTROL_UNHOLD);
   
      if (misdn_lib_send_event(bc, EVENT_RETRIEVE_ACKNOWLEDGE) < 0) {
         chan_misdn_log(4, bc->port, " --> RETRIEVE_ACK failed\n");
         misdn_lib_send_event(bc, EVENT_RETRIEVE_REJECT);
      }
      break;
   case EVENT_HOLD:
   {
      int hold_allowed;
      struct ast_channel *bridged;

      misdn_cfg_get(bc->port, MISDN_CFG_HOLD_ALLOWED, &hold_allowed, sizeof(hold_allowed));
      if (!hold_allowed) {
         chan_misdn_log(-1, bc->port, "Hold not allowed this port.\n");
         misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
         break;
      }

      bridged = ast_bridged_channel(ch->ast);
      if (bridged) {
         chan_misdn_log(2, bc->port, "Bridge Partner is of type: %s\n", bridged->tech->type);
         ch->l3id = bc->l3_id;

         /* forget the channel now */
         ch->bc = NULL;
         ch->hold.state = MISDN_HOLD_ACTIVE;
         ch->hold.port = bc->port;
         ch->hold.channel = bc->channel;

         ast_queue_control(ch->ast, AST_CONTROL_HOLD);
         
         misdn_lib_send_event(bc, EVENT_HOLD_ACKNOWLEDGE);
      } else {
         misdn_lib_send_event(bc, EVENT_HOLD_REJECT);
         chan_misdn_log(0, bc->port, "We aren't bridged to anybody\n");
      }
   } 
      break;
   case EVENT_FACILITY:
      print_facility(&(bc->fac_in), bc);
      
      switch (bc->fac_in.Function) {
#ifdef HAVE_MISDN_FAC_RESULT
      case Fac_RESULT:
         break;
#endif
      case Fac_CD:
         if (ch) {
            struct ast_channel *bridged = ast_bridged_channel(ch->ast);
            struct chan_list *ch_br;
            if (bridged && MISDN_ASTERISK_TECH_PVT(bridged)) {
               ch_br = MISDN_ASTERISK_TECH_PVT(bridged);
               /*ch->state = MISDN_FACILITY_DEFLECTED;*/
               if (ch_br->bc) {
                  if (ast_exists_extension(bridged, ch->context, (char *)bc->fac_in.u.CDeflection.DeflectedToNumber, 1, bc->oad)) {
                     ch_br->state = MISDN_DIALING;
                     if (pbx_start_chan(ch_br) < 0) {
                        chan_misdn_log(-1, ch_br->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
                     }
                  }
               }
            }
            misdn_lib_send_event(bc, EVENT_DISCONNECT);
         } 
         break;
      case Fac_AOCDCurrency:
         if (ch) {
            bc->AOCDtype = Fac_AOCDCurrency;
            memcpy(&(bc->AOCD.currency), &(bc->fac_in.u.AOCDcur), sizeof(bc->AOCD.currency));
            bc->AOCD_need_export = 1;
            export_aoc_vars(ch->originator, ch->ast, bc);
         }
         break;
      case Fac_AOCDChargingUnit:
         if (ch) {
            bc->AOCDtype = Fac_AOCDChargingUnit;
            memcpy(&(bc->AOCD.chargingUnit), &(bc->fac_in.u.AOCDchu), sizeof(bc->AOCD.chargingUnit));
            bc->AOCD_need_export = 1;
            export_aoc_vars(ch->originator, ch->ast, bc);
         }
         break;
      case Fac_None:
#ifdef HAVE_MISDN_FAC_ERROR
      case Fac_ERROR:
#endif
         break;
      default:
         chan_misdn_log(0, bc->port," --> not yet handled: facility type:%d\n", bc->fac_in.Function);
      }
      
      break;
   case EVENT_RESTART:
      if (!bc->dummy) {
         stop_bc_tones(ch);
         release_chan(ch, bc);
      }
      break;
   default:
      chan_misdn_log(1, 0, "Got Unknown Event\n");
      break;
   }
   
   return RESPONSE_OK;
}
int chan_misdn_jb_empty ( struct misdn_bchannel bc,
char *  buf,
int  len 
)

Definition at line 5942 of file chan_misdn.c.

References find_chan_by_bc(), chan_list::jb, and misdn_jb_empty().

Referenced by load_module().

{
   struct chan_list *ch = find_chan_by_bc(cl_te, bc);
   
   if (ch && ch->jb) {
      return misdn_jb_empty(ch->jb, buf, len);
   }
   
   return -1;
}
static void chan_misdn_log ( int  level,
int  port,
char *  tmpl,
  ... 
) [static]

Definition at line 6132 of file chan_misdn.c.

References ast_console_puts(), ast_log(), ast_strlen_zero(), buf, errno, and LOG_WARNING.

Referenced by cb_events(), cl_queue_chan(), config_jitterbuffer(), debug_numplan(), dialtone_indicate(), do_immediate_setup(), export_ch(), find_chan_by_bc(), find_chan_by_pid(), find_hold_call(), import_ch(), init_chan_list(), load_module(), misdn_answer(), misdn_attempt_transfer(), misdn_bridge(), misdn_call(), misdn_check_l2l1(), misdn_digit_end(), misdn_facility_exec(), misdn_fixup(), misdn_hangup(), misdn_indication(), misdn_jb_empty(), misdn_jb_fill(), misdn_jb_init(), misdn_l1_task(), misdn_new(), misdn_overlap_dial_task(), misdn_read(), misdn_request(), misdn_set_opt_exec(), misdn_tasks_destroy(), misdn_tasks_init(), misdn_tasks_thread_func(), misdn_write(), print_bearer(), print_facility(), process_ast_dsp(), read_config(), release_chan(), send_cause2ast(), start_pbx(), stop_indicate(), update_config(), and update_name().

{
   va_list ap;
   char buf[1024];
   char port_buf[8];

   if (! ((0 <= port) && (port <= max_ports))) {
      ast_log(LOG_WARNING, "cb_log called with out-of-range port number! (%d)\n", port);
      port = 0;
      level = -1;
   }

   snprintf(port_buf, sizeof(port_buf), "P[%2d] ", port);

   va_start(ap, tmpl);
   vsnprintf(buf, sizeof(buf), tmpl, ap);
   va_end(ap);

   if (level == -1) {
      ast_log(LOG_WARNING, "%s", buf);

   } else if (misdn_debug_only[port] ? 
         (level == 1 && misdn_debug[port]) || (level == misdn_debug[port]) 
       : level <= misdn_debug[port]) {
      
      ast_console_puts(port_buf);
      ast_console_puts(buf);
   }
   
   if ((level <= misdn_debug[0]) && !ast_strlen_zero(global_tracefile) ) {
      char ctimebuf[30];
      time_t tm = time(NULL);
      char *tmp = ctime_r(&tm, ctimebuf), *p;

      FILE *fp = fopen(global_tracefile, "a+");

      if ((p = strchr(tmp, '\n'))) {
         *p = ':';
      }
      
      if (!fp) {
         ast_console_puts("Error opening Tracefile: [ ");
         ast_console_puts(global_tracefile);
         ast_console_puts(" ] ");
         
         ast_console_puts(strerror(errno));
         ast_console_puts("\n");
         return ;
      }
      
      fputs(tmp, fp);
      fputs(" ", fp);
      fputs(port_buf, fp);
      fputs(" ", fp);
      fputs(buf, fp);

      fclose(fp);
   }
}
static void cl_dequeue_chan ( struct chan_list **  list,
struct chan_list chan 
) [static]

Definition at line 3886 of file chan_misdn.c.

References ast_dsp_free(), ast_mutex_lock(), ast_mutex_unlock(), chan_list::dsp, and chan_list::next.

Referenced by release_chan(), and release_chan_early().

{
   struct chan_list *help;

   if (chan->dsp) {
      ast_dsp_free(chan->dsp);
   }

   ast_mutex_lock(&cl_te_lock);
   if (!*list) {
      ast_mutex_unlock(&cl_te_lock);
      return;
   }
  
   if (*list == chan) {
      *list = (*list)->next;
      ast_mutex_unlock(&cl_te_lock);
      return;
   }
  
   for (help = *list; help->next; help = help->next) {
      if (help->next == chan) {
         help->next = help->next->next;
         ast_mutex_unlock(&cl_te_lock);
         return;
      }
   }
   
   ast_mutex_unlock(&cl_te_lock);
}
static void cl_queue_chan ( struct chan_list **  list,
struct chan_list chan 
) [static]

Definition at line 3870 of file chan_misdn.c.

References ast_mutex_lock(), ast_mutex_unlock(), chan_list::bc, chan, chan_misdn_log(), chan_list::next, and misdn_bchannel::port.

Referenced by cb_events(), and misdn_request().

{
   chan_misdn_log(4, chan->bc ? chan->bc->port : 0, "* Queuing chan %p\n", chan);
  
   ast_mutex_lock(&cl_te_lock);
   if (!*list) {
      *list = chan;
   } else {
      struct chan_list *help = *list;
      for (; help->next; help = help->next); 
      help->next = chan;
   }
   chan->next = NULL;
   ast_mutex_unlock(&cl_te_lock);
}
static char * complete_debug_port ( struct ast_cli_args a) [static]

Definition at line 1902 of file chan_misdn.c.

References ast_strdup, ast_cli_args::n, ast_cli_args::pos, and ast_cli_args::word.

Referenced by handle_cli_misdn_set_debug().

{
   if (a->n) {
      return NULL;
   }

   switch (a->pos) {
   case 4:
      if (a->word[0] == 'p') {
         return ast_strdup("port");
      } else if (a->word[0] == 'o') {
         return ast_strdup("only");
      }
      break;
   case 6:
      if (a->word[0] == 'o') {
         return ast_strdup("only");
      }
      break;
   }
   return NULL;
}
static char * complete_show_config ( struct ast_cli_args a) [static]

Definition at line 1925 of file chan_misdn.c.

References ast_strdup, BUFFERSIZE, ast_cli_args::line, MISDN_CFG_FIRST, misdn_cfg_get_name(), misdn_cfg_get_next_port(), MISDN_CFG_LAST, MISDN_GEN_FIRST, MISDN_GEN_LAST, ast_cli_args::n, ast_cli_args::pos, and ast_cli_args::word.

Referenced by handle_cli_misdn_show_config().

{
   char buffer[BUFFERSIZE];
   enum misdn_cfg_elements elem;
   int wordlen = strlen(a->word);
   int which = 0;
   int port = 0;

   switch (a->pos) {
   case 3:
      if ((!strncmp(a->word, "description", wordlen)) && (++which > a->n)) {
         return ast_strdup("description");
      }
      if ((!strncmp(a->word, "descriptions", wordlen)) && (++which > a->n)) {
         return ast_strdup("descriptions");
      }
      if ((!strncmp(a->word, "0", wordlen)) && (++which > a->n)) {
         return ast_strdup("0");
      }
      while ((port = misdn_cfg_get_next_port(port)) != -1) {
         snprintf(buffer, sizeof(buffer), "%d", port);
         if ((!strncmp(a->word, buffer, wordlen)) && (++which > a->n)) {
            return ast_strdup(buffer);
         }
      }
      break;
   case 4:
      if (strstr(a->line, "description ")) {
         for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) {
            if ((elem == MISDN_CFG_LAST) || (elem == MISDN_GEN_FIRST)) {
               continue;
            }
            misdn_cfg_get_name(elem, buffer, sizeof(buffer));
            if (!wordlen || !strncmp(a->word, buffer, wordlen)) {
               if (++which > a->n) {
                  return ast_strdup(buffer);
               }
            }
         }
      } else if (strstr(a->line, "descriptions ")) {
         if ((!wordlen || !strncmp(a->word, "general", wordlen)) && (++which > a->n)) {
            return ast_strdup("general");
         }
         if ((!wordlen || !strncmp(a->word, "ports", wordlen)) && (++which > a->n)) {
            return ast_strdup("ports");
         }
      }
      break;
   }
   return NULL;
}
static void config_jitterbuffer ( struct chan_list ch) [static]

Definition at line 2087 of file chan_misdn.c.

References chan_list::bc, cb_log, chan_misdn_log(), chan_list::jb, chan_list::jb_len, chan_list::jb_upper_threshold, len(), misdn_jb_destroy(), misdn_jb_init(), misdn_bchannel::nojitter, and misdn_bchannel::port.

Referenced by misdn_set_opt_exec(), and read_config().

{
   struct misdn_bchannel *bc = ch->bc;
   int len = ch->jb_len, threshold = ch->jb_upper_threshold;
   
   chan_misdn_log(5, bc->port, "config_jb: Called\n");
   
   if (! len) {
      chan_misdn_log(1, bc->port, "config_jb: Deactivating Jitterbuffer\n");
      bc->nojitter=1;
   } else {
      if (len <= 100 || len > 8000) {
         chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer out of Bounds, setting to 1000\n");
         len = 1000;
      }

      if (threshold > len) {
         chan_misdn_log(0, bc->port, "config_jb: Jitterbuffer Threshold > Jitterbuffer setting to Jitterbuffer -1\n");
      }

      if ( ch->jb) {
         cb_log(0, bc->port, "config_jb: We've got a Jitterbuffer Already on this port.\n");
         misdn_jb_destroy(ch->jb);
         ch->jb = NULL;
      }

      ch->jb = misdn_jb_init(len, threshold);

      if (!ch->jb) {
         bc->nojitter = 1;
      }
   }
}
void debug_numplan ( int  port,
int  numplan,
char *  type 
)

Definition at line 2122 of file chan_misdn.c.

References chan_misdn_log(), NUMPLAN_INTERNATIONAL, NUMPLAN_NATIONAL, NUMPLAN_SUBSCRIBER, and NUMPLAN_UNKNOWN.

Referenced by read_config().

{
   switch (numplan) {
   case NUMPLAN_INTERNATIONAL:
      chan_misdn_log(2, port, " --> %s: International\n", type);
      break;
   case NUMPLAN_NATIONAL:
      chan_misdn_log(2, port, " --> %s: National\n", type);
      break;
   case NUMPLAN_SUBSCRIBER:
      chan_misdn_log(2, port, " --> %s: Subscriber\n", type);
      break;
   case NUMPLAN_UNKNOWN:
      chan_misdn_log(2, port, " --> %s: Unknown\n", type);
      break;
      /* Maybe we should cut off the prefix if present ? */
   default:
      chan_misdn_log(0, port, " --> !!!! Wrong dialplan setting, please see the misdn.conf sample file\n ");
      break;
   }
}
static int dialtone_indicate ( struct chan_list cl) [static]

AST INDICATIONS END

Definition at line 3327 of file chan_misdn.c.

References chan_list::ast, ast_get_indication_tone(), ast_playtones_start(), chan_list::bc, chan_misdn_log(), ast_tone_zone_sound::data, misdn_cfg_get(), MISDN_CFG_NODIALTONE, chan_list::norxtone, chan_list::notxtone, misdn_bchannel::port, chan_list::ts, and ast_channel::zone.

Referenced by wait_for_digits().

{
   struct ast_channel *ast = cl->ast;
   int nd = 0;

   if (!ast) {
      chan_misdn_log(0, cl->bc->port, "No Ast in dialtone_indicate\n");
      return -1;
   }

   misdn_cfg_get(cl->bc->port, MISDN_CFG_NODIALTONE, &nd, sizeof(nd));

   if (nd) {
      chan_misdn_log(1, cl->bc->port, "Not sending Dialtone, because config wants it\n");
      return 0;
   }
   
   chan_misdn_log(3, cl->bc->port, " --> Dial\n");

   cl->ts = ast_get_indication_tone(ast->zone, "dial");
   
   if (cl->ts) {
      cl->notxtone = 0;
      cl->norxtone = 0;
      /* This prods us in misdn_write */
      ast_playtones_start(ast, 0, cl->ts->data, 0);
   }

   return 0;
}
static void do_immediate_setup ( struct misdn_bchannel bc,
struct chan_list ch,
struct ast_channel ast 
) [static]

Definition at line 4140 of file chan_misdn.c.

References chan_list::ast, ast_canmatch_extension(), AST_CAUSE_UNALLOCATED, AST_FRAME_DTMF, ast_queue_frame(), ast_strdupa, ast_strlen_zero(), ast_tv(), chan_misdn_log(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, ast_frame::data, ast_frame::datalen, ast_frame::delivery, EVENT_DISCONNECT, EVENT_PROCEEDING, EVENT_RELEASE_COMPLETE, EVENT_SETUP_ACKNOWLEDGE, ast_channel::exten, ast_frame::frametype, hangup_chan(), hanguptone_indicate(), ast_frame::mallocd, MISDN_ASTERISK_PVT, MISDN_ASTERISK_TECH_PVT, MISDN_DIALING, MISDN_INCOMING_SETUP, misdn_lib_is_ptp(), misdn_lib_send_event(), chan_list::noautorespond_on_setup, misdn_bchannel::nt, misdn_bchannel::oad, ast_frame::offset, misdn_bchannel::out_cause, pbx_start_chan(), misdn_bchannel::port, ast_frame::ptr, ast_frame::samples, ast_frame::src, chan_list::state, and ast_frame::subclass.

Referenced by cb_events().

{
   char *predial;
   struct ast_frame fr;

   predial = ast_strdupa(ast->exten);

   ch->state = MISDN_DIALING;

   if (!ch->noautorespond_on_setup) {
      if (bc->nt) {
         int ret; 
         ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
      } else {
         int ret;
         if ( misdn_lib_is_ptp(bc->port)) {
            ret = misdn_lib_send_event(bc, EVENT_SETUP_ACKNOWLEDGE );
         } else {
            ret = misdn_lib_send_event(bc, EVENT_PROCEEDING );
         }
      }
   } else {
      ch->state = MISDN_INCOMING_SETUP;
   }

   chan_misdn_log(1, bc->port, "* Starting Ast ctx:%s dad:%s oad:%s with 's' extension\n", ast->context, ast->exten, ast->cid.cid_num);
  
   strcpy(ast->exten, "s");
  
   if (!ast_canmatch_extension(ast, ast->context, ast->exten, 1, bc->oad) || pbx_start_chan(ch) < 0) {
      ast = NULL;
      bc->out_cause = AST_CAUSE_UNALLOCATED;
      hangup_chan(ch, bc);
      hanguptone_indicate(ch);

      misdn_lib_send_event(bc, bc->nt ? EVENT_RELEASE_COMPLETE : EVENT_DISCONNECT);
   }
  
  
   while (!ast_strlen_zero(predial) ) {
      fr.frametype = AST_FRAME_DTMF;
      fr.subclass = *predial;
      fr.src = NULL;
      fr.data.ptr = NULL;
      fr.datalen = 0;
      fr.samples = 0;
      fr.mallocd = 0;
      fr.offset = 0;
      fr.delivery = ast_tv(0,0);

      if (ch->ast && MISDN_ASTERISK_PVT(ch->ast) && MISDN_ASTERISK_TECH_PVT(ch->ast)) {
         ast_queue_frame(ch->ast, &fr);
      }
      predial++;
   }
}
static void export_aoc_vars ( int  originator,
struct ast_channel ast,
struct misdn_bchannel bc 
) [static]

Definition at line 683 of file chan_misdn.c.

References misdn_bchannel::AOCD, misdn_bchannel::AOCD_need_export, misdn_bchannel::AOCDtype, ast_bridged_channel(), buf, misdn_bchannel::chargingUnit, misdn_bchannel::currency, ORG_AST, and pbx_builtin_setvar_helper().

Referenced by cb_events().

{
   char buf[128];

   if (!bc->AOCD_need_export || !ast) {
      return;
   }

   if (originator == ORG_AST) {
      if (!(ast = ast_bridged_channel(ast))) {
         return;
      }
   }

   switch (bc->AOCDtype) {
   case Fac_AOCDCurrency:
      pbx_builtin_setvar_helper(ast, "AOCD_Type", "currency");
      if (bc->AOCD.currency.chargeNotAvailable) {
         pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
      } else {
         pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
         if (bc->AOCD.currency.freeOfCharge) {
            pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
         } else {
            pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
            if (snprintf(buf, sizeof(buf), "%d %s", bc->AOCD.currency.currencyAmount * bc->AOCD.currency.multiplier, bc->AOCD.currency.currency) < sizeof(buf)) {
               pbx_builtin_setvar_helper(ast, "AOCD_Amount", buf);
               if (bc->AOCD.currency.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.currency.billingId) < sizeof(buf)) {
                  pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
               }
            }
         }
      }
      break;
   case Fac_AOCDChargingUnit:
      pbx_builtin_setvar_helper(ast, "AOCD_Type", "charging_unit");
      if (bc->AOCD.chargingUnit.chargeNotAvailable) {
         pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
      } else {
         pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
         if (bc->AOCD.chargingUnit.freeOfCharge) {
            pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
         } else {
            pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
            if (snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.recordedUnits) < sizeof(buf)) {
               pbx_builtin_setvar_helper(ast, "AOCD_RecordedUnits", buf);
               if (bc->AOCD.chargingUnit.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.billingId) < sizeof(buf)) {
                  pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
               }
            }
         }
      }
      break;
   default:
      break;
   }
   
   bc->AOCD_need_export = 0;
}
void export_ch ( struct ast_channel chan,
struct misdn_bchannel bc,
struct chan_list ch 
)

Export parameters to the dialplan environment variables.

Definition at line 4293 of file chan_misdn.c.

References ast_strlen_zero(), chan_misdn_log(), misdn_bchannel::keypad, pbx_builtin_setvar_helper(), misdn_bchannel::pid, misdn_bchannel::port, misdn_bchannel::sending_complete, misdn_bchannel::urate, misdn_bchannel::uu, and misdn_bchannel::uulen.

Referenced by cb_events().

{
   char tmp[32];
   chan_misdn_log(3, bc->port, " --> EXPORT_PID: pid:%d\n", bc->pid);
   snprintf(tmp, sizeof(tmp), "%d", bc->pid);
   pbx_builtin_setvar_helper(chan, "_MISDN_PID", tmp);

   if (bc->sending_complete) {
      snprintf(tmp, sizeof(tmp), "%d", bc->sending_complete);
      pbx_builtin_setvar_helper(chan, "MISDN_ADDRESS_COMPLETE", tmp);
   }

   if (bc->urate) {
      snprintf(tmp, sizeof(tmp), "%d", bc->urate);
      pbx_builtin_setvar_helper(chan, "MISDN_URATE", tmp);
   }

   if (bc->uulen) {
      pbx_builtin_setvar_helper(chan, "MISDN_USERUSER", bc->uu);
   }

   if (!ast_strlen_zero(bc->keypad)) {
      pbx_builtin_setvar_helper(chan, "MISDN_KEYPAD", bc->keypad);
   }
}
static struct chan_list * find_chan_by_bc ( struct chan_list list,
struct misdn_bchannel bc 
) [static, read]

Definition at line 3772 of file chan_misdn.c.

References chan_list::bc, chan_misdn_log(), misdn_bchannel::dad, chan_list::next, misdn_bchannel::oad, and misdn_bchannel::port.

Referenced by cb_events(), and chan_misdn_jb_empty().

{
   struct chan_list *help = list;
   for (; help; help = help->next) {
      if (help->bc == bc) {
         return help;
      }
   }

   chan_misdn_log(6, bc->port, "$$$ find_chan: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad);

   return NULL;
}
static struct chan_list * find_chan_by_pid ( struct chan_list list,
int  pid 
) [static, read]

Definition at line 3786 of file chan_misdn.c.

References chan_list::bc, chan_misdn_log(), chan_list::next, and misdn_bchannel::pid.

Referenced by import_ch().

{
   struct chan_list *help = list;
   for (; help; help = help->next) {
      if (help->bc && (help->bc->pid == pid)) {
         return help;
      }
   }

   chan_misdn_log(6, 0, "$$$ find_chan: No channel found for pid:%d\n", pid);

   return NULL;
}
static struct chan_list* find_hold_active_call ( struct chan_list list,
struct misdn_bchannel bc 
) [static, read]

Definition at line 3850 of file chan_misdn.c.

References chan_list::ast, chan_list::bc, chan_list::hold, MISDN_ALERTING, MISDN_CONNECTED, MISDN_HOLD_IDLE, MISDN_PROCEEDING, MISDN_PROGRESS, chan_list::next, misdn_bchannel::port, chan_list::state, and hold_info::state.

Referenced by cb_events().

{
   for (; list; list = list->next) {
      if (list->hold.state == MISDN_HOLD_IDLE && list->bc && list->bc->port == bc->port
         && list->ast) {
         switch (list->state) {
         case MISDN_PROCEEDING:
         case MISDN_PROGRESS:
         case MISDN_ALERTING:
         case MISDN_CONNECTED:
            return list;
         default:
            break;
         }
      }
   }
   return NULL;
}
static struct chan_list* find_hold_call ( struct chan_list list,
struct misdn_bchannel bc 
) [static, read]

Definition at line 3800 of file chan_misdn.c.

References chan_misdn_log(), hold_info::channel, misdn_bchannel::channel, misdn_bchannel::dad, chan_list::hold, MISDN_HOLD_ACTIVE, chan_list::next, misdn_bchannel::oad, hold_info::port, misdn_bchannel::port, misdn_bchannel::pri, and hold_info::state.

Referenced by cb_events().

{
   struct chan_list *help = list;

   if (bc->pri) {
      return NULL;
   }

   chan_misdn_log(6, bc->port, "$$$ find_hold_call: channel:%d oad:%s dad:%s\n", bc->channel, bc->oad, bc->dad);
   for (;help; help = help->next) {
      chan_misdn_log(4, bc->port, "$$$ find_hold_call: --> hold:%d channel:%d\n", help->hold.state, help->hold.channel);
      if (help->hold.state == MISDN_HOLD_ACTIVE && help->hold.port == bc->port) {
         return help;
      }
   }
   chan_misdn_log(6, bc->port, "$$$ find_hold_call: No channel found for oad:%s dad:%s\n", bc->oad, bc->dad);

   return NULL;
}
static struct chan_list* find_hold_call_l3 ( struct chan_list list,
unsigned long  l3_id 
) [static, read]

Definition at line 3821 of file chan_misdn.c.

References chan_list::hold, chan_list::l3id, MISDN_HOLD_IDLE, chan_list::next, and hold_info::state.

Referenced by cb_events().

{
   struct chan_list *help = list;

   for (; help; help = help->next) {
      if (help->hold.state != MISDN_HOLD_IDLE && help->l3id == l3_id) {
         return help;
      }
   }

   return NULL;
}
static void free_robin_list ( void  ) [static]

Definition at line 431 of file chan_misdn.c.

References ast_free, robin_list::group, robin_list::next, and robin.

Referenced by reload_config(), and unload_module().

{
   struct robin_list *r;
   struct robin_list *next;

   for (r = robin, robin = NULL; r; r = next) {
      next = r->next;
      ast_free(r->group);
      ast_free(r);
   }
}
static struct chan_list* get_chan_by_ast ( struct ast_channel ast) [static, read]

Definition at line 555 of file chan_misdn.c.

References chan_list::ast, and chan_list::next.

Referenced by misdn_bridge().

{
   struct chan_list *tmp;
  
   for (tmp = cl_te; tmp; tmp = tmp->next) {
      if (tmp->ast == ast) {
         return tmp;
      }
   }
  
   return NULL;
}
static struct chan_list* get_chan_by_ast_name ( char *  name) [static, read]

Definition at line 568 of file chan_misdn.c.

References chan_list::ast, ast_channel::name, and chan_list::next.

Referenced by handle_cli_misdn_send_digit(), handle_cli_misdn_send_display(), handle_cli_misdn_send_facility(), and handle_cli_misdn_toggle_echocancel().

{
   struct chan_list *tmp;
  
   for (tmp = cl_te; tmp; tmp = tmp->next) {
      if (tmp->ast && strcmp(tmp->ast->name, name) == 0) {
         return tmp;
      }
   }
  
   return NULL;
}
static struct robin_list* get_robin_position ( char *  group) [static, read]

Definition at line 443 of file chan_misdn.c.

References ast_calloc, ast_free, ast_strdup, robin_list::group, robin_list::next, robin_list::prev, and robin.

Referenced by misdn_request().

{
   struct robin_list *new;
   struct robin_list *iter = robin;
   for (; iter; iter = iter->next) {
      if (!strcasecmp(iter->group, group)) {
         return iter;
      }
   }
   new = ast_calloc(1, sizeof(*new));
   if (!new) {
      return NULL;
   }
   new->group = ast_strdup(group);
   if (!new->group) {
      ast_free(new);
      return NULL;
   }
   new->channel = 1;
   if (robin) {
      new->next = robin;
      robin->prev = new;
   }
   robin = new;
   return robin;
}
static char* handle_cli_misdn_port_block ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1043 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, misdn_lib_port_block(), and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn port block";
      e->usage =
         "Usage: misdn port block <port>\n"
         "       Block the specified port by <port>.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 4) {
      return CLI_SHOWUSAGE;
   }

   misdn_lib_port_block(atoi(a->argv[3]));

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_port_down ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1153 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, misdn_lib_get_port_down(), and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn port down";
      e->usage =
         "Usage: misdn port down <port>\n"
         "       Try to deactivate the L1 on the given port.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 4) {
      return CLI_SHOWUSAGE;
   }

   misdn_lib_get_port_down(atoi(a->argv[3]));

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_port_unblock ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1065 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, misdn_lib_port_unblock(), and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn port unblock";
      e->usage =
         "Usage: misdn port unblock <port>\n"
         "       Unblock the port specified by <port>.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 4) {
      return CLI_SHOWUSAGE;
   }

   misdn_lib_port_unblock(atoi(a->argv[3]));

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_port_up ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1131 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, misdn_lib_get_port_up(), and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn port up";
      e->usage =
         "Usage: misdn port up <port>\n"
         "       Try to establish L1 on the given port.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 4) {
      return CLI_SHOWUSAGE;
   }

   misdn_lib_get_port_up(atoi(a->argv[3]));

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_reload ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1352 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, reload_config(), and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn reload";
      e->usage =
         "Usage: misdn reload\n"
         "       Reload internal mISDN config, read from the config\n"
         "       file.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 2) {
      return CLI_SHOWUSAGE;
   }

   ast_cli(a->fd, "Reloading mISDN configuration\n");
   reload_config();
   return CLI_SUCCESS;
}
static char* handle_cli_misdn_restart_pid ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1109 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, misdn_lib_pid_restart(), and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn restart pid";
      e->usage =
         "Usage: misdn restart pid <pid>\n"
         "       Restart the given pid\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 4) {
      return CLI_SHOWUSAGE;
   }

   misdn_lib_pid_restart(atoi(a->argv[3]));

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_restart_port ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1087 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, misdn_lib_port_restart(), and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn restart port";
      e->usage =
         "Usage: misdn restart port <port>\n"
         "       Restart the given port.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 4) {
      return CLI_SHOWUSAGE;
   }

   misdn_lib_port_restart(atoi(a->argv[3]));

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_send_digit ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1763 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, chan_list::ast, ast_cli(), ast_dtmf_stream(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_ch(), ast_cli_args::fd, get_chan_by_ast_name(), msg, msglen, send_digit_to_chan(), and ast_cli_entry::usage.

{
   char *channame; 
   char *msg; 
   struct chan_list *tmp;
   int i, msglen;

   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn send digit";
      e->usage =
         "Usage: misdn send digit <channel> \"<msg>\" \n"
         "       Send <digit> to <channel> as DTMF Tone\n"
         "       when channel is a mISDN channel\n";
      return NULL;
   case CLI_GENERATE:
      return complete_ch(a);
   }

   if (a->argc != 5) {
      return CLI_SHOWUSAGE;
   }

   channame = a->argv[3];
   msg = a->argv[4];
   msglen = strlen(msg);

   ast_cli(a->fd, "Sending %s to %s\n", msg, channame);

   tmp = get_chan_by_ast_name(channame);
   if (!tmp) {
      ast_cli(a->fd, "Sending %s to %s failed Channel does not exist\n", msg, channame);
      return CLI_SUCCESS; 
   }
#if 1
   for (i = 0; i < msglen; i++) {
      ast_cli(a->fd, "Sending: %c\n", msg[i]);
      send_digit_to_chan(tmp, msg[i]);
      /* res = ast_safe_sleep(tmp->ast, 250); */
      usleep(250000);
      /* res = ast_waitfor(tmp->ast,100); */
   }
#else
   ast_dtmf_stream(tmp->ast, NULL, msg, 250);
#endif

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_send_display ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1858 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), ast_copy_string(), chan_list::bc, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_ch(), misdn_bchannel::display, EVENT_INFORMATION, ast_cli_args::fd, get_chan_by_ast_name(), misdn_lib_send_event(), msg, and ast_cli_entry::usage.

{
   char *channame;
   char *msg;
   struct chan_list *tmp;

   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn send display";
      e->usage =
         "Usage: misdn send display <channel> \"<msg>\" \n"
         "       Send <msg> to <channel> as Display Message\n"
         "       when channel is a mISDN channel\n";
      return NULL;
   case CLI_GENERATE:
      return complete_ch(a);
   }

   if (a->argc != 5) {
      return CLI_SHOWUSAGE;
   }

   channame = a->argv[3];
   msg = a->argv[4];

   ast_cli(a->fd, "Sending %s to %s\n", msg, channame);
   tmp = get_chan_by_ast_name(channame);
    
   if (tmp && tmp->bc) {
      ast_copy_string(tmp->bc->display, msg, sizeof(tmp->bc->display));
      misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
   } else {
      ast_cli(a->fd, "No such channel %s\n", channame);
      return CLI_SUCCESS;
   }

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_send_facility ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1640 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_copy_string(), ast_verbose(), chan_list::bc, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_ch(), dummy(), EVENT_FACILITY, misdn_bchannel::fac_out, get_chan_by_ast_name(), misdn_lib_port_is_nt(), misdn_lib_send_event(), misdn_make_dummy(), and ast_cli_entry::usage.

{
   char *channame; 
   char *nr;
   struct chan_list *tmp;
   int port; 
   char *served_nr;
   struct misdn_bchannel dummy, *bc=&dummy;
 
   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn send facility";
      e->usage = "Usage: misdn send facility <type> <channel|port> \"<args>\" \n"
      "\t type is one of:\n"
      "\t - calldeflect\n"
      "\t - CFActivate\n"
      "\t - CFDeactivate\n";

      return NULL;
   case CLI_GENERATE:
      return complete_ch(a);
   }

   if (a->argc < 5) {
      return CLI_SHOWUSAGE;
   }
 
   if (strstr(a->argv[3], "calldeflect")) {
      if (a->argc < 6) {
         ast_verbose("calldeflect requires 1 arg: ToNumber\n\n");
         return 0;
      }
      channame = a->argv[4];
      nr = a->argv[5];

      ast_verbose("Sending Calldeflection (%s) to %s\n", nr, channame);
      tmp = get_chan_by_ast_name(channame);
      if (!tmp) {
         ast_verbose("Sending CD with nr %s to %s failed: Channel does not exist.\n", nr, channame);
         return 0; 
      }

      if (strlen(nr) >= 15) {
         ast_verbose("Sending CD with nr %s to %s failed: Number too long (up to 15 digits are allowed).\n", nr, channame);
         return 0; 
      }
      tmp->bc->fac_out.Function = Fac_CD;
      ast_copy_string((char *)tmp->bc->fac_out.u.CDeflection.DeflectedToNumber, nr, sizeof(tmp->bc->fac_out.u.CDeflection.DeflectedToNumber));
      misdn_lib_send_event(tmp->bc, EVENT_FACILITY);
   } else if (strstr(a->argv[3], "CFActivate")) {
      if (a->argc < 7) {
         ast_verbose("CFActivate requires 2 args: 1.FromNumber, 2.ToNumber\n\n");
         return 0;
      }
      port = atoi(a->argv[4]);
      served_nr = a->argv[5];
      nr = a->argv[6];

      misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);

      ast_verbose("Sending CFActivate  Port:(%d) FromNr. (%s) to Nr. (%s)\n", port, served_nr, nr);

      bc->fac_out.Function = Fac_CFActivate;
      bc->fac_out.u.CFActivate.BasicService = 0; /* All Services */
      bc->fac_out.u.CFActivate.Procedure = 0; /* Unconditional */
      ast_copy_string((char *)bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
      ast_copy_string((char *)bc->fac_out.u.CFActivate.ForwardedToNumber, nr, sizeof(bc->fac_out.u.CFActivate.ForwardedToNumber));

      misdn_lib_send_event(bc, EVENT_FACILITY);
   } else if (strstr(a->argv[3], "CFDeactivate")) {
      if (a->argc < 6) {
         ast_verbose("CFDeactivate requires 1 arg: FromNumber\n\n");
         return 0;
      }
      port = atoi(a->argv[4]);
      served_nr = a->argv[5];
      
      misdn_make_dummy(bc, port, 0, misdn_lib_port_is_nt(port), 0);
      ast_verbose("Sending CFDeactivate  Port:(%d) FromNr. (%s)\n", port, served_nr);

      bc->fac_out.Function = Fac_CFDeactivate;
      bc->fac_out.u.CFDeactivate.BasicService = 0; //All Services
      bc->fac_out.u.CFDeactivate.Procedure = 0; //Unconditional
      
      ast_copy_string((char *)bc->fac_out.u.CFActivate.ServedUserNumber, served_nr, sizeof(bc->fac_out.u.CFActivate.ServedUserNumber));
      misdn_lib_send_event(bc, EVENT_FACILITY);
   }

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_send_restart ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1731 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, misdn_bchannel::channel, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, misdn_lib_send_restart(), misdn_bchannel::port, and ast_cli_entry::usage.

{
   int port;
   int channel;

   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn send restart";
      e->usage =
         "Usage: misdn send restart [port [channel]]\n"
         "       Send a restart for every bchannel on the given port.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc < 4 || a->argc > 5) {
      return CLI_SHOWUSAGE;
   }

   port = atoi(a->argv[3]);

   if (a->argc == 5) {
      channel = atoi(a->argv[4]);
      misdn_lib_send_restart(port, channel);
   } else {
      misdn_lib_send_restart(port, -1);
   }

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_set_crypt_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1020 of file chan_misdn.c.

References ast_cli_args::argc, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn set crypt debug";
      e->usage =
         "Usage: misdn set crypt debug <level>\n"
         "       Set the crypt debug level of the mISDN channel. Level\n"
         "       must be 1 or 2.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 5) {
      return CLI_SHOWUSAGE;
   }

   /* XXX Is this supposed to not do anything? XXX */

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_set_debug ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 935 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_debug_port(), ast_cli_args::fd, max_ports, and ast_cli_entry::usage.

{
   int level;

   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn set debug [on|off]";
      e->usage =
         "Usage: misdn set debug {on|off|<level>} [only] | [port <port> [only]]\n"
         "       Set the debug level of the mISDN channel.\n";
      return NULL;
   case CLI_GENERATE:
      return complete_debug_port(a);
   }

   if (a->argc < 4 || a->argc > 7) {
      return CLI_SHOWUSAGE;
   }

   if (!strcasecmp(a->argv[3], "on")) {
      level = 1;
   } else if (!strcasecmp(a->argv[3], "off")) {
      level = 0;
   } else {
      level = atoi(a->argv[3]);
   }

   switch (a->argc) {
   case 4:
   case 5:
      {
         int i;
         int only = 0;
         if (a->argc == 5) {
            if (strncasecmp(a->argv[4], "only", strlen(a->argv[4]))) {
               return CLI_SHOWUSAGE;
            } else {
               only = 1;
            }
         }
   
         for (i = 0; i <= max_ports; i++) {
            misdn_debug[i] = level;
            misdn_debug_only[i] = only;
         }
         ast_cli(a->fd, "changing debug level for all ports to %d%s\n", misdn_debug[0], only ? " (only)" : "");
      }
      break;
   case 6:
   case 7:
      {
         int port;
         if (strncasecmp(a->argv[4], "port", strlen(a->argv[4])))
            return CLI_SHOWUSAGE;
         port = atoi(a->argv[5]);
         if (port <= 0 || port > max_ports) {
            switch (max_ports) {
            case 0:
               ast_cli(a->fd, "port number not valid! no ports available so you won't get lucky with any number here...\n");
               break;
            case 1:
               ast_cli(a->fd, "port number not valid! only port 1 is available.\n");
               break;
            default:
               ast_cli(a->fd, "port number not valid! only ports 1 to %d are available.\n", max_ports);
            }
            return 0;
         }
         if (a->argc == 7) {
            if (strncasecmp(a->argv[6], "only", strlen(a->argv[6]))) {
               return CLI_SHOWUSAGE;
            } else {
               misdn_debug_only[port] = 1;
            }
         } else {
            misdn_debug_only[port] = 0;
         }
         misdn_debug[port] = level;
         ast_cli(a->fd, "changing debug level to %d%s for port %d\n", misdn_debug[port], misdn_debug_only[port] ? " (only)" : "", port);
      }
   }

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_set_tics ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1530 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, and ast_cli_entry::usage.

{
   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn set tics";
      e->usage =
         "Usage: misdn set tics <value>\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 4) {
      return CLI_SHOWUSAGE;
   }

   /* XXX Wow, this does... a whole lot of nothing... XXX */
   MAXTICS = atoi(a->argv[3]);

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_show_channel ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1494 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, chan_list::ast, chan_list::bc, cl_te, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_ch(), ast_cli_args::fd, ast_channel::name, chan_list::next, print_bc_info(), and ast_cli_entry::usage.

{
   struct chan_list *help;

   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn show channel";
      e->usage =
         "Usage: misdn show channel <channel>\n"
         "       Show an internal mISDN channel\n.";
      return NULL;
   case CLI_GENERATE:
      return complete_ch(a);
   }

   if (a->argc != 4) {
      return CLI_SHOWUSAGE;
   }

   help = cl_te;

   for (; help; help = help->next) {
      struct misdn_bchannel *bc = help->bc;   
      struct ast_channel *ast = help->ast;
    
      if (bc && ast) {
         if (!strcasecmp(ast->name, a->argv[3])) {
            print_bc_info(a->fd, help, bc);
            break; 
         }
      }
   }

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_show_channels ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1430 of file chan_misdn.c.

References ast_cli_args::argc, chan_list::ast, ast_cli(), chan_list::bc, hold_info::channel, ast_channel::cid, ast_callerid::cid_num, cl_te, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_channel::exten, ast_cli_args::fd, chan_list::hold, chan_list::l3id, misdn_dump_chanlist(), MISDN_HOLD_IDLE, chan_list::next, misdn_bchannel::pid, hold_info::port, print_bc_info(), hold_info::state, and ast_cli_entry::usage.

{
   struct chan_list *help;

   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn show channels";
      e->usage =
         "Usage: misdn show channels\n"
         "       Show the internal mISDN channel list\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 3) {
      return CLI_SHOWUSAGE;
   }

   help = cl_te;
  
   ast_cli(a->fd, "Channel List: %p\n", cl_te);

   for (; help; help = help->next) {
      struct misdn_bchannel *bc = help->bc;   
      struct ast_channel *ast = help->ast;
      if (!ast) {
         if (!bc) {
            ast_cli(a->fd, "chan_list obj. with l3id:%x has no bc and no ast Leg\n", help->l3id);
            continue;
         }
         ast_cli(a->fd, "bc with pid:%d has no Ast Leg\n", bc->pid);
         continue;
      }

      if (misdn_debug[0] > 2) {
         ast_cli(a->fd, "Bc:%p Ast:%p\n", bc, ast);
      }
      if (bc) {
         print_bc_info(a->fd, help, bc);
      } else {
         if (help->hold.state != MISDN_HOLD_IDLE) {
            ast_cli(a->fd, "ITS A HELD CALL BC:\n");
            ast_cli(a->fd, " --> l3_id: %x\n"
                  " --> dad:%s oad:%s\n"
                  " --> hold_port: %d\n"
                  " --> hold_channel: %d\n",
                  help->l3id,
                  ast->exten,
                  ast->cid.cid_num,
                  help->hold.port,
                  help->hold.channel
                  );
         } else {
            ast_cli(a->fd, "* Channel in unknown STATE !!! Exten:%s, Callerid:%s\n", ast->exten, ast->cid.cid_num);
         }
      }
   }

   misdn_dump_chanlist();

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_show_config ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1200 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), BUFFERSIZE, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_show_config(), ast_cli_args::fd, MISDN_CFG_FIRST, misdn_cfg_get_config_string(), misdn_cfg_get_elem(), misdn_cfg_get_next_port(), misdn_cfg_is_port_valid(), MISDN_CFG_LAST, MISDN_GEN_FIRST, MISDN_GEN_LAST, show_config_description(), and ast_cli_entry::usage.

{
   char buffer[BUFFERSIZE];
   enum misdn_cfg_elements elem;
   int linebreak;
   int onlyport = -1;
   int ok = 0;

   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn show config";
      e->usage =
         "Usage: misdn show config [<port> | description <config element> | descriptions [general|ports]]\n"
         "       Use 0 for <port> to only print the general config.\n";
      return NULL;
   case CLI_GENERATE:
      return complete_show_config(a);
   }

   if (a->argc >= 4) {
      if (!strcmp(a->argv[3], "description")) {
         if (a->argc == 5) {
            enum misdn_cfg_elements elem = misdn_cfg_get_elem(a->argv[4]);
            if (elem == MISDN_CFG_FIRST) {
               ast_cli(a->fd, "Unknown element: %s\n", a->argv[4]);
            } else {
               show_config_description(a->fd, elem);
            }
            return CLI_SUCCESS;
         }
         return CLI_SHOWUSAGE;
      } else if (!strcmp(a->argv[3], "descriptions")) {
         if ((a->argc == 4) || ((a->argc == 5) && !strcmp(a->argv[4], "general"))) {
            for (elem = MISDN_GEN_FIRST + 1; elem < MISDN_GEN_LAST; ++elem) {
               show_config_description(a->fd, elem);
               ast_cli(a->fd, "\n");
            }
            ok = 1;
         }
         if ((a->argc == 4) || ((a->argc == 5) && !strcmp(a->argv[4], "ports"))) {
            for (elem = MISDN_CFG_FIRST + 1; elem < MISDN_CFG_LAST - 1 /* the ptp hack, remove the -1 when ptp is gone */; ++elem) {
               show_config_description(a->fd, elem);
               ast_cli(a->fd, "\n");
            }
            ok = 1;
         }
         return ok ? CLI_SUCCESS : CLI_SHOWUSAGE;
      } else if (!sscanf(a->argv[3], "%5d", &onlyport) || onlyport < 0) {
         ast_cli(a->fd, "Unknown option: %s\n", a->argv[3]);
         return CLI_SHOWUSAGE;
      }
   } else if (a->argc == 3 || onlyport == 0) {
      ast_cli(a->fd, "mISDN General-Config:\n");
      for (elem = MISDN_GEN_FIRST + 1, linebreak = 1; elem < MISDN_GEN_LAST; elem++, linebreak++) {
         misdn_cfg_get_config_string(0, elem, buffer, sizeof(buffer));
         ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
      }
      ast_cli(a->fd, "\n");
   }

   if (onlyport < 0) {
      int port = misdn_cfg_get_next_port(0);
      for (; port > 0; port = misdn_cfg_get_next_port(port)) {
         ast_cli(a->fd, "\n[PORT %d]\n", port);
         for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
            misdn_cfg_get_config_string(port, elem, buffer, sizeof(buffer));
            ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
         }  
         ast_cli(a->fd, "\n");
      }
   }
   
   if (onlyport > 0) {
      if (misdn_cfg_is_port_valid(onlyport)) {
         ast_cli(a->fd, "[PORT %d]\n", onlyport);
         for (elem = MISDN_CFG_FIRST + 1, linebreak = 1; elem < MISDN_CFG_LAST; elem++, linebreak++) {
            misdn_cfg_get_config_string(onlyport, elem, buffer, sizeof(buffer));
            ast_cli(a->fd, "%-36s%s", buffer, !(linebreak % 2) ? "\n" : "");
         }  
         ast_cli(a->fd, "\n");
      } else {
         ast_cli(a->fd, "Port %d is not active!\n", onlyport);
      }
   }

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_show_port ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1611 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), buf, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, get_show_stack_details(), and ast_cli_entry::usage.

{
   int port;
   char buf[128];

   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn show port";
      e->usage =
         "Usage: misdn show port <port>\n"
         "       Show detailed information for given port.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 4) {
      return CLI_SHOWUSAGE;
   }

   port = atoi(a->argv[3]);

   ast_cli(a->fd, "BEGIN STACK_LIST:\n");
   get_show_stack_details(port, buf);
   ast_cli(a->fd, "  %s  Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_show_ports_stats ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1582 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli(), CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, misdn_cfg_get_next_port(), and ast_cli_entry::usage.

{
   int port;

   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn show ports stats";
      e->usage =
         "Usage: misdn show ports stats\n"
         "       Show mISDNs channel's call statistics per port.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 4) {
      return CLI_SHOWUSAGE;
   }

   ast_cli(a->fd, "Port\tin_calls\tout_calls\n");
   for (port = misdn_cfg_get_next_port(0); port > 0;
        port = misdn_cfg_get_next_port(port)) {
      ast_cli(a->fd, "%d\t%d\t\t%d\n", port, misdn_in_calls[port], misdn_out_calls[port]);
   }
   ast_cli(a->fd, "\n");

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_show_stacks ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1552 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli(), buf, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, ast_cli_args::fd, get_show_stack_details(), misdn_cfg_get_next_port(), and ast_cli_entry::usage.

{
   int port;

   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn show stacks";
      e->usage =
         "Usage: misdn show stacks\n"
         "       Show internal mISDN stack_list.\n";
      return NULL;
   case CLI_GENERATE:
      return NULL;
   }

   if (a->argc != 3) {
      return CLI_SHOWUSAGE;
   }

   ast_cli(a->fd, "BEGIN STACK_LIST:\n");
   for (port = misdn_cfg_get_next_port(0); port > 0;
        port = misdn_cfg_get_next_port(port)) {
      char buf[128];
      get_show_stack_details(port, buf);
      ast_cli(a->fd, "  %s  Debug:%d%s\n", buf, misdn_debug[port], misdn_debug_only[port] ? "(only)" : "");
   }

   return CLI_SUCCESS;
}
static char* handle_cli_misdn_toggle_echocancel ( struct ast_cli_entry e,
int  cmd,
struct ast_cli_args a 
) [static]

Definition at line 1812 of file chan_misdn.c.

References ast_cli_args::argc, ast_cli_args::argv, ast_cli(), chan_list::bc, CLI_GENERATE, CLI_INIT, CLI_SHOWUSAGE, CLI_SUCCESS, ast_cli_entry::command, complete_ch(), ast_cli_args::fd, get_chan_by_ast_name(), manager_ec_disable(), manager_ec_enable(), chan_list::toggle_ec, update_ec_config(), and ast_cli_entry::usage.

{
   char *channame;
   struct chan_list *tmp;

   switch (cmd) {
   case CLI_INIT:
      e->command = "misdn toggle echocancel";
      e->usage =
         "Usage: misdn toggle echocancel <channel>\n"
         "       Toggle EchoCancel on mISDN Channel.\n";
      return NULL;
   case CLI_GENERATE:
      return complete_ch(a);
   }

   if (a->argc != 4) {
      return CLI_SHOWUSAGE;
   }

   channame = a->argv[3];
  
   ast_cli(a->fd, "Toggling EchoCancel on %s\n", channame);
  
   tmp = get_chan_by_ast_name(channame);
   if (!tmp) {
      ast_cli(a->fd, "Toggling EchoCancel %s failed Channel does not exist\n", channame);
      return CLI_SUCCESS;
   }

   tmp->toggle_ec = tmp->toggle_ec ? 0 : 1;

   if (tmp->toggle_ec) {
#ifdef MISDN_1_2
      update_pipeline_config(tmp->bc);
#else
      update_ec_config(tmp->bc);
#endif
      manager_ec_enable(tmp->bc);
   } else {
      manager_ec_disable(tmp->bc);
   }

   return CLI_SUCCESS;
}
static void hangup_chan ( struct chan_list ch,
struct misdn_bchannel bc 
) [static]

Definition at line 3929 of file chan_misdn.c.

References chan_list::ast, ast_hangup(), ast_queue_hangup_with_cause(), misdn_bchannel::cause, cb_log, chan_list::need_hangup, chan_list::need_queue_hangup, misdn_bchannel::port, and send_cause2ast().

Referenced by cb_events(), do_immediate_setup(), and start_pbx().

{
   int port;

   if (!ch) {
      cb_log(1, 0, "Cannot hangup chan, no ch\n");
      return;
   }

   port = bc->port;
   cb_log(5, port, "hangup_chan called\n");

   if (ch->need_hangup) {
      cb_log(2, port, " --> hangup\n");
      ch->need_hangup = 0;
      ch->need_queue_hangup = 0;
      if (ch->ast) {
         send_cause2ast(ch->ast, bc, ch);
         ast_hangup(ch->ast);
      }
      return;
   }

   if (!ch->need_queue_hangup) {
      cb_log(2, port, " --> No need to queue hangup\n");
   }

   ch->need_queue_hangup = 0;
   if (ch->ast) {
      send_cause2ast(ch->ast, bc, ch);
      ast_queue_hangup_with_cause(ch->ast, bc->cause);
      cb_log(2, port, " --> queue_hangup\n");
   } else {
      cb_log(1, port, "Cannot hangup chan, no ast\n");
   }
}
static void hanguptone_indicate ( struct chan_list cl) [static]
void import_ch ( struct ast_channel chan,
struct misdn_bchannel bc,
struct chan_list ch 
)

Import parameters from the dialplan environment variables.

Definition at line 4256 of file chan_misdn.c.

References ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_log(), chan_misdn_log(), find_chan_by_pid(), misdn_bchannel::keypad, LOG_NOTICE, chan_list::other_ch, chan_list::other_pid, pbx_builtin_getvar_helper(), misdn_bchannel::port, misdn_bchannel::sending_complete, misdn_bchannel::uu, and misdn_bchannel::uulen.

Referenced by misdn_call().

{
   const char *tmp;

   ast_channel_lock(chan);
   tmp = pbx_builtin_getvar_helper(chan, "MISDN_PID");
   if (tmp) {
      ch->other_pid = atoi(tmp);
      chan_misdn_log(3, bc->port, " --> IMPORT_PID: importing pid:%s\n", tmp);
      if (ch->other_pid > 0) {
         ch->other_ch = find_chan_by_pid(cl_te, ch->other_pid);
         if (ch->other_ch) {
            ch->other_ch->other_ch = ch;
         }
      }
   }

   tmp = pbx_builtin_getvar_helper(chan, "MISDN_ADDRESS_COMPLETE");
   if (tmp && (atoi(tmp) == 1)) {
      bc->sending_complete = 1;
   }

   tmp = pbx_builtin_getvar_helper(chan, "MISDN_USERUSER");
   if (tmp) {
      ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", tmp);
      ast_copy_string(bc->uu, tmp, sizeof(bc->uu));
      bc->uulen = strlen(bc->uu);
   }

   tmp = pbx_builtin_getvar_helper(chan, "MISDN_KEYPAD");
   if (tmp) {
      ast_copy_string(bc->keypad, tmp, sizeof(bc->keypad));
   }
   ast_channel_unlock(chan);
}
static struct chan_list* init_chan_list ( int  orig) [static, read]

Definition at line 3405 of file chan_misdn.c.

References ast_calloc, chan_misdn_log(), chan_list::need_busy, chan_list::need_hangup, chan_list::need_queue_hangup, chan_list::originator, and chan_list::overlap_dial_task.

Referenced by cb_events(), and misdn_request().

{
   struct chan_list *cl;

   if (!(cl = ast_calloc(1, sizeof(*cl)))) {
      chan_misdn_log(-1, 0, "misdn_request: malloc failed!");
      return NULL;
   }
   
   cl->originator = orig;
   cl->need_queue_hangup = 1;
   cl->need_hangup = 1;
   cl->need_busy = 1;
   cl->overlap_dial_task = -1;

   return cl;
}
static int load_module ( void  ) [static]

Definition at line 5415 of file chan_misdn.c.

References ast_calloc, ast_channel_register(), ast_cli_register_multiple(), ast_free, ast_log(), ast_malloc, AST_MODULE_LOAD_DECLINE, ast_mutex_init(), ast_register_application, ast_strlen_zero(), BUFFERSIZE, misdn_lib_iface::cb_event, cb_events(), chan_misdn_jb_empty(), chan_misdn_log(), LOG_ERROR, max_ports, misdn_cfg_get(), misdn_cfg_get_next_port(), misdn_cfg_get_ports_string(), misdn_cfg_init(), MISDN_CFG_L1_TIMEOUT, misdn_cfg_update_ptp(), misdn_check_l2l1(), misdn_facility_exec(), MISDN_GEN_DEBUG, MISDN_GEN_NTDEBUGFILE, MISDN_GEN_NTDEBUGFLAGS, MISDN_GEN_NTKEEPCALLS, MISDN_GEN_TRACEFILE, misdn_l1_task(), misdn_lib_init(), misdn_lib_maxports_get(), misdn_lib_nt_debug_init(), misdn_lib_nt_keepcalls(), misdn_set_opt_exec(), misdn_tasks_add(), and unload_module().

{
   int i, port;
   int ntflags = 0, ntkc = 0;
   char ports[256] = "";
   char tempbuf[BUFFERSIZE + 1];
   char ntfile[BUFFERSIZE + 1];
   struct misdn_lib_iface iface = {
      .cb_event = cb_events,
      .cb_log = chan_misdn_log,
      .cb_jb_empty = chan_misdn_jb_empty,
   };

   max_ports = misdn_lib_maxports_get();
   
   if (max_ports <= 0) {
      ast_log(LOG_ERROR, "Unable to initialize mISDN\n");
      return AST_MODULE_LOAD_DECLINE;
   }
   
   if (misdn_cfg_init(max_ports, 0)) {
      ast_log(LOG_ERROR, "Unable to initialize misdn_config.\n");
      return AST_MODULE_LOAD_DECLINE;
   }
   g_config_initialized = 1;
   
   misdn_debug = ast_malloc(sizeof(int) * (max_ports + 1));
   if (!misdn_debug) {
      ast_log(LOG_ERROR, "Out of memory for misdn_debug\n");
      return AST_MODULE_LOAD_DECLINE;
   }
   misdn_ports = ast_malloc(sizeof(int) * (max_ports + 1));
   if (!misdn_ports) {
      ast_free(misdn_debug);
      ast_log(LOG_ERROR, "Out of memory for misdn_ports\n");
      return AST_MODULE_LOAD_DECLINE;
   }
   misdn_cfg_get(0, MISDN_GEN_DEBUG, &misdn_debug[0], sizeof(misdn_debug[0]));
   for (i = 1; i <= max_ports; i++) {
      misdn_debug[i] = misdn_debug[0];
      misdn_ports[i] = i;
   }
   *misdn_ports = 0;
   misdn_debug_only = ast_calloc(max_ports + 1, sizeof(int));
   if (!misdn_debug_only) {
      ast_free(misdn_ports);
      ast_free(misdn_debug);
      ast_log(LOG_ERROR, "Out of memory for misdn_debug_only\n");
      return AST_MODULE_LOAD_DECLINE;
   }

   misdn_cfg_get(0, MISDN_GEN_TRACEFILE, tempbuf, sizeof(tempbuf));
   if (!ast_strlen_zero(tempbuf)) {
      tracing = 1;
   }

   misdn_in_calls = ast_malloc(sizeof(int) * (max_ports + 1));
   if (!misdn_in_calls) {
      ast_free(misdn_debug_only);
      ast_free(misdn_ports);
      ast_free(misdn_debug);
      ast_log(LOG_ERROR, "Out of memory for misdn_in_calls\n");
      return AST_MODULE_LOAD_DECLINE;
   }
   misdn_out_calls = ast_malloc(sizeof(int) * (max_ports + 1));
   if (!misdn_out_calls) {
      ast_free(misdn_in_calls);
      ast_free(misdn_debug_only);
      ast_free(misdn_ports);
      ast_free(misdn_debug);
      ast_log(LOG_ERROR, "Out of memory for misdn_out_calls\n");
      return AST_MODULE_LOAD_DECLINE;
   }

   for (i = 1; i <= max_ports; i++) {
      misdn_in_calls[i] = 0;
      misdn_out_calls[i] = 0;
   }

   ast_mutex_init(&cl_te_lock);
   ast_mutex_init(&release_lock);

   misdn_cfg_update_ptp();
   misdn_cfg_get_ports_string(ports);

   if (!ast_strlen_zero(ports)) {
      chan_misdn_log(0, 0, "Got: %s from get_ports\n", ports);
   }
   if (misdn_lib_init(ports, &iface, NULL)) {
      chan_misdn_log(0, 0, "No te ports initialized\n");
   }

   misdn_cfg_get(0, MISDN_GEN_NTDEBUGFLAGS, &ntflags, sizeof(ntflags));
   misdn_cfg_get(0, MISDN_GEN_NTDEBUGFILE, &ntfile, sizeof(ntfile));
   misdn_cfg_get( 0, MISDN_GEN_NTKEEPCALLS, &ntkc, sizeof(ntkc));

   misdn_lib_nt_keepcalls(ntkc);
   misdn_lib_nt_debug_init(ntflags, ntfile);

   if (ast_channel_register(&misdn_tech)) {
      ast_log(LOG_ERROR, "Unable to register channel class %s\n", misdn_type);
      unload_module();
      return AST_MODULE_LOAD_DECLINE;
   }
  
   ast_cli_register_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry));

   ast_register_application("misdn_set_opt", misdn_set_opt_exec, "misdn_set_opt",
      "misdn_set_opt(:<opt><optarg>:<opt><optarg>...):\n"
      "Sets mISDN opts. and optargs\n"
      "\n"
      "The available options are:\n"
      "    a - Have Asterisk detect DTMF tones on called channel\n"
      "    c - Make crypted outgoing call, optarg is keyindex\n"
      "    d - Send display text to called phone, text is the optarg\n"
      "    e - Perform echo cancelation on this channel,\n"
      "        takes taps as optarg (32,64,128,256)\n"
      "   e! - Disable echo cancelation on this channel\n"
      "    f - Enable fax detection\n"
      "    h - Make digital outgoing call\n"
      "   h1 - Make HDLC mode digital outgoing call\n"
      "    i - Ignore detected DTMF tones, don't signal them to Asterisk,\n"
      "        they will be transported inband.\n"
      "   jb - Set jitter buffer length, optarg is length\n"
      "   jt - Set jitter buffer upper threshold, optarg is threshold\n"
      "   jn - Disable jitter buffer\n"
      "    n - Disable mISDN DSP on channel.\n"
      "        Disables: echo cancel, DTMF detection, and volume control.\n"
      "    p - Caller ID presentation,\n"
      "        optarg is either 'allowed' or 'restricted'\n"
      "    s - Send Non-inband DTMF as inband\n"
      "   vr - Rx gain control, optarg is gain\n"
      "   vt - Tx gain control, optarg is gain\n"
      );

   
   ast_register_application("misdn_facility", misdn_facility_exec, "misdn_facility",
             "misdn_facility(<FACILITY_TYPE>|<ARG1>|..)\n"
             "Sends the Facility Message FACILITY_TYPE with \n"
             "the given Arguments to the current ISDN Channel\n"
             "Supported Facilities are:\n"
             "\n"
             "type=calldeflect args=Nr where to deflect\n"
      );


   ast_register_application("misdn_check_l2l1", misdn_check_l2l1, "misdn_check_l2l1",
             "misdn_check_l2l1(<port>||g:<groupname>,timeout)"
             "Checks if the L2 and L1 are up on either the given <port> or\n"
             "on the ports in the group with <groupname>\n"
             "If the L1/L2 are down, check_l2l1 gets up the L1/L2 and waits\n"
             "for <timeout> seconds that this happens. Otherwise, nothing happens\n"
             "\n"
             "This application, ensures the L1/L2 state of the Ports in a group\n"
             "it is intended to make the pmp_l1_check option redundant and to\n"
             "fix a buggy switch config from your provider\n"
             "\n"
             "a sample dialplan would look like:\n\n"
             "exten => _X.,1,misdn_check_l2l1(g:out|2)\n"
             "exten => _X.,n,dial(mISDN/g:out/${EXTEN})\n"
             "\n"
      );


   misdn_cfg_get(0, MISDN_GEN_TRACEFILE, global_tracefile, sizeof(global_tracefile));

   /* start the l1 watchers */
   
   for (port = misdn_cfg_get_next_port(0); port >= 0; port = misdn_cfg_get_next_port(port)) {
      int l1timeout;
      misdn_cfg_get(port, MISDN_CFG_L1_TIMEOUT, &l1timeout, sizeof(l1timeout));
      if (l1timeout) {
         chan_misdn_log(4, 0, "Adding L1watcher task: port:%d timeout:%ds\n", port, l1timeout);
         misdn_tasks_add(l1timeout * 1000, misdn_l1_task, &misdn_ports[port]);  
      }
   }

   chan_misdn_log(0, 0, "-- mISDN Channel Driver Registered --\n");

   return 0;
}
static int misdn_answer ( struct ast_channel ast) [static]

Definition at line 2539 of file chan_misdn.c.

References AST_CAUSE_NETWORK_OUT_OF_ORDER, AST_CAUSE_PROTOCOL_ERROR, ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_log(), ast_queue_hangup_with_cause(), ast_strlen_zero(), ast_true(), chan_list::bc, misdn_bchannel::cad, chan_misdn_log(), misdn_bchannel::crypt_key, misdn_bchannel::dad, EVENT_CONNECT, misdn_bchannel::hdlc, LOG_WARNING, MISDN_ASTERISK_TECH_PVT, MISDN_CONNECTED, misdn_lib_send_event(), misdn_bchannel::nodsp, misdn_bchannel::nojitter, pbx_builtin_getvar_helper(), misdn_bchannel::port, start_bc_tones(), chan_list::state, and stop_indicate().

{
   struct chan_list *p;
   const char *tmp;

   if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
      return -1;
   }
   
   chan_misdn_log(1, p ? (p->bc ? p->bc->port : 0) : 0, "* ANSWER:\n");
   
   if (!p) {
      ast_log(LOG_WARNING, " --> Channel not connected ??\n");
      ast_queue_hangup_with_cause(ast, AST_CAUSE_NETWORK_OUT_OF_ORDER);
   }

   if (!p->bc) {
      chan_misdn_log(1, 0, " --> Got Answer, but there is no bc obj ??\n");

      ast_queue_hangup_with_cause(ast, AST_CAUSE_PROTOCOL_ERROR);
   }

   ast_channel_lock(ast);
   tmp = pbx_builtin_getvar_helper(ast, "CRYPT_KEY");
   if (!ast_strlen_zero(tmp)) {
      chan_misdn_log(1, p->bc->port, " --> Connection will be BF crypted\n");
      ast_copy_string(p->bc->crypt_key, tmp, sizeof(p->bc->crypt_key));
   } else {
      chan_misdn_log(3, p->bc->port, " --> Connection is without BF encryption\n");
   }

   tmp = pbx_builtin_getvar_helper(ast, "MISDN_DIGITAL_TRANS");
   if (!ast_strlen_zero(tmp) && ast_true(tmp)) {
      chan_misdn_log(1, p->bc->port, " --> Connection is transparent digital\n");
      p->bc->nodsp = 1;
      p->bc->hdlc = 0;
      p->bc->nojitter = 1;
   }
   ast_channel_unlock(ast);

   p->state = MISDN_CONNECTED;
   stop_indicate(p);

   if ( ast_strlen_zero(p->bc->cad) ) {
      chan_misdn_log(2, p->bc->port, " --> empty cad using dad\n");
      ast_copy_string(p->bc->cad, p->bc->dad, sizeof(p->bc->cad));
   }

   misdn_lib_send_event(p->bc, EVENT_CONNECT);
   start_bc_tones(p);

   return 0;
}
static int misdn_attempt_transfer ( struct chan_list active_ch,
struct chan_list held_ch 
) [static]

Definition at line 4105 of file chan_misdn.c.

References chan_list::ast, ast_bridged_channel(), ast_channel_masquerade(), AST_CONTROL_UNHOLD, ast_queue_control(), chan_misdn_log(), chan_list::hold, MISDN_ALERTING, MISDN_CONNECTED, MISDN_HOLD_TRANSFER, MISDN_PROCEEDING, MISDN_PROGRESS, ast_channel::name, hold_info::port, hold_info::state, and chan_list::state.

Referenced by cb_events().

{
   int retval;
   struct ast_channel *bridged;

   switch (active_ch->state) {
   case MISDN_PROCEEDING:
   case MISDN_PROGRESS:
   case MISDN_ALERTING:
   case MISDN_CONNECTED:
      break;
   default:
      return -1;
   }

   bridged = ast_bridged_channel(held_ch->ast);
   if (bridged) {
      ast_queue_control(held_ch->ast, AST_CONTROL_UNHOLD);
      held_ch->hold.state = MISDN_HOLD_TRANSFER;

      chan_misdn_log(1, held_ch->hold.port, "TRANSFERRING %s to %s\n",
         held_ch->ast->name, active_ch->ast->name);
      retval = ast_channel_masquerade(active_ch->ast, bridged);
   } else {
      /*
       * Could not transfer.  Held channel is not bridged anymore.
       * Held party probably got tired of waiting and hung up.
       */
      retval = -1;
   }

   return retval;
}
static enum ast_bridge_result misdn_bridge ( struct ast_channel c0,
struct ast_channel c1,
int  flags,
struct ast_frame **  fo,
struct ast_channel **  rc,
int  timeoutms 
) [static]

Definition at line 3225 of file chan_misdn.c.

References AST_BRIDGE_COMPLETE, AST_BRIDGE_DTMF_CHANNEL_0, AST_BRIDGE_DTMF_CHANNEL_1, AST_BRIDGE_FAILED, AST_FRAME_CONTROL, AST_FRAME_DTMF, AST_FRAME_VOICE, ast_log(), ast_read(), ast_verb, ast_waitfor_n(), ast_write(), chan_list::bc, chan_misdn_log(), ast_channel::exten, f, ast_frame::frametype, get_chan_by_ast(), chan_list::ignore_dtmf, LOG_NOTICE, MISDN_CFG_BRIDGING, misdn_cfg_get(), MISDN_GEN_BRIDGING, misdn_lib_bridge(), misdn_lib_split_bridge(), ast_channel::name, misdn_bchannel::oad, misdn_bchannel::pid, misdn_bchannel::port, and ast_frame::subclass.

{
   struct chan_list *ch1, *ch2;
   struct ast_channel *carr[2], *who;
   int to = -1;
   struct ast_frame *f;
   int p1_b, p2_b;
   int bridging;
  
   ch1 = get_chan_by_ast(c0);
   ch2 = get_chan_by_ast(c1);

   carr[0] = c0;
   carr[1] = c1;
  
   if (!(ch1 && ch2)) {
      return -1;
   }

   misdn_cfg_get(ch1->bc->port, MISDN_CFG_BRIDGING, &p1_b, sizeof(p1_b));
   misdn_cfg_get(ch2->bc->port, MISDN_CFG_BRIDGING, &p2_b, sizeof(p2_b));

   if (! p1_b || ! p2_b) {
      ast_log(LOG_NOTICE, "Falling back to Asterisk bridging\n");
      return AST_BRIDGE_FAILED;
   }

   misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
   if (bridging) {
      /* trying to make a mISDN_dsp conference */
      chan_misdn_log(1, ch1->bc->port, "I SEND: Making conference with Number:%d\n", ch1->bc->pid + 1);
      misdn_lib_bridge(ch1->bc, ch2->bc);
   }

   ast_verb(3, "Native bridging %s and %s\n", c0->name, c1->name);

   chan_misdn_log(1, ch1->bc->port, "* Making Native Bridge between %s and %s\n", ch1->bc->oad, ch2->bc->oad);
 
   if (! (flags & AST_BRIDGE_DTMF_CHANNEL_0) ) {
      ch1->ignore_dtmf = 1;
   }

   if (! (flags & AST_BRIDGE_DTMF_CHANNEL_1) ) {
      ch2->ignore_dtmf = 1;
   }

   for (;/*ever*/;) {
      to = -1;
      who = ast_waitfor_n(carr, 2, &to);

      if (!who) {
         ast_log(LOG_NOTICE, "misdn_bridge: empty read, breaking out\n");
         break;
      }
      f = ast_read(who);

      if (!f || f->frametype == AST_FRAME_CONTROL) {
         /* got hangup .. */

         if (!f) 
            chan_misdn_log(4, ch1->bc->port, "Read Null Frame\n");
         else
            chan_misdn_log(4, ch1->bc->port, "Read Frame Control class:%d\n", f->subclass);

         *fo = f;
         *rc = who;
         break;
      }
      
      if ( f->frametype == AST_FRAME_DTMF ) {
         chan_misdn_log(1, 0, "Read DTMF %d from %s\n", f->subclass, who->exten);

         *fo = f;
         *rc = who;
         break;
      }
   
#if 0
      if (f->frametype == AST_FRAME_VOICE) {
         chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid +1);
   
         continue;
      }
#endif

      ast_write(who == c0 ? c1 : c0, f);
   }

   chan_misdn_log(1, ch1->bc->port, "I SEND: Splitting conference with Number:%d\n", ch1->bc->pid + 1);

   misdn_lib_split_bridge(ch1->bc, ch2->bc);

   return AST_BRIDGE_COMPLETE;
}
static int misdn_call ( struct ast_channel ast,
char *  dest,
int  timeout 
) [static]

we should have l3id after sending setup

Definition at line 2394 of file chan_misdn.c.

References ast_channel::_state, add_out_calls(), AST_APP_ARG, AST_CAUSE_NORMAL_CIRCUIT_CONGESTION, AST_CAUSE_NORMAL_CLEARING, AST_CAUSE_NORMAL_TEMPORARY_FAILURE, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), AST_NONSTANDARD_APP_ARGS, ast_setstate(), AST_STATE_DIALING, AST_STATE_DOWN, AST_STATE_RESERVED, ast_strdupa, ast_strlen_zero(), ast_transfercapability2str(), chan_list::bc, misdn_bchannel::capability, chan_misdn_log(), ast_channel::cid, ast_callerid::cid_num, ast_callerid::cid_rdnis, ast_channel::context, misdn_bchannel::dad, misdn_bchannel::ec_enable, ENOCHAN, EVENT_SETUP, ext, ast_channel::exten, ast_channel::hangupcause, import_ch(), INFO_CAPABILITY_DIGITAL_UNRESTRICTED, misdn_bchannel::l3_id, chan_list::l3id, LOG_WARNING, MISDN_ASTERISK_TECH_PVT, MISDN_CALLING, misdn_cfg_get(), MISDN_GEN_BRIDGING, misdn_lib_send_event(), misdn_set_opt_exec(), ast_channel::name, misdn_bchannel::nt, misdn_bchannel::oad, ORG_AST, chan_list::other_ch, pbx_builtin_setvar_helper(), misdn_bchannel::pid, misdn_bchannel::port, misdn_bchannel::rad, S_OR, chan_list::state, stop_bc_tones(), ast_channel::transfercapability, type, and update_config().

{
   int port = 0;
   int r;
   int exceed;
   int bridging;
   struct chan_list *ch;
   struct misdn_bchannel *newbc;
   char *dest_cp = ast_strdupa(dest);
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(type);
      AST_APP_ARG(ext);
      AST_APP_ARG(opts);
   );

   /*
    * dest is ---v
    * Dial(mISDN/g:group_name[/extension[/options]])
    * Dial(mISDN/port[:preselected_channel][/extension[/options]])
    *
    * The dial extension could be empty if you are using MISDN_KEYPAD
    * to control ISDN provider features.
    */
   AST_NONSTANDARD_APP_ARGS(args, dest_cp, '/');

   if (ast_strlen_zero(args.ext)) {
      chan_misdn_log(0, 0, "misdn_call: No Extension given!\n");
      return -1;
   }

   if (!ast) {
      ast_log(LOG_WARNING, " --> ! misdn_call called on ast_channel *ast where ast == NULL\n");
      return -1;
   }

   if (((ast->_state != AST_STATE_DOWN) && (ast->_state != AST_STATE_RESERVED)) || !dest) {
      ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
      ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
      ast_setstate(ast, AST_STATE_DOWN);
      return -1;
   }

   ch = MISDN_ASTERISK_TECH_PVT(ast);
   if (!ch) {
      ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
      ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
      ast_setstate(ast, AST_STATE_DOWN);
      return -1;
   }
   
   newbc = ch->bc;
   if (!newbc) {
      ast_log(LOG_WARNING, " --> ! misdn_call called on %s, neither down nor reserved (or dest==NULL)\n", ast->name);
      ast->hangupcause = AST_CAUSE_NORMAL_TEMPORARY_FAILURE;
      ast_setstate(ast, AST_STATE_DOWN);
      return -1;
   }
   
   port = newbc->port;

   if ((exceed = add_out_calls(port))) {
      char tmp[16];
      snprintf(tmp, sizeof(tmp), "%d", exceed);
      pbx_builtin_setvar_helper(ast, "MAX_OVERFLOW", tmp);
      return -1;
   }
   
   chan_misdn_log(1, port, "* CALL: %s\n", dest);
   
   chan_misdn_log(2, port, " --> * dad:%s tech:%s ctx:%s\n", ast->exten, ast->name, ast->context);
   
   chan_misdn_log(3, port, " --> * adding2newbc ext %s\n", ast->exten);
   if (ast->exten) {
      ast_copy_string(ast->exten, args.ext, sizeof(ast->exten));
      ast_copy_string(newbc->dad, args.ext, sizeof(newbc->dad));
   }

   ast_copy_string(newbc->rad, S_OR(ast->cid.cid_rdnis, ""), sizeof(newbc->rad));

   chan_misdn_log(3, port, " --> * adding2newbc callerid %s\n", ast->cid.cid_num);
   if (ast_strlen_zero(newbc->oad) && !ast_strlen_zero(ast->cid.cid_num)) {
      ast_copy_string(newbc->oad, ast->cid.cid_num, sizeof(newbc->oad));
   }

   newbc->capability = ast->transfercapability;
   pbx_builtin_setvar_helper(ast, "TRANSFERCAPABILITY", ast_transfercapability2str(newbc->capability));
   if ( ast->transfercapability == INFO_CAPABILITY_DIGITAL_UNRESTRICTED) {
      chan_misdn_log(2, port, " --> * Call with flag Digital\n");
   }

   /* update screening and presentation */ 
   update_config(ch, ORG_AST);
      
   /* fill in some ies from channel vary */
   import_ch(ast, newbc, ch);

   /* Finally The Options Override Everything */
   if (!ast_strlen_zero(args.opts)) {
      misdn_set_opt_exec(ast, args.opts);
   } else {
      chan_misdn_log(2, port, "NO OPTS GIVEN\n");
   }

   /*check for bridging*/
   misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));
   if (bridging && ch->other_ch) {
#ifdef MISDN_1_2
      chan_misdn_log(1, port, "Disabling EC (aka Pipeline) on both Sides\n");
      *ch->bc->pipeline = 0;
      *ch->other_ch->bc->pipeline = 0;
#else
      chan_misdn_log(1, port, "Disabling EC on both Sides\n");
      ch->bc->ec_enable = 0;
      ch->other_ch->bc->ec_enable = 0;
#endif
   }

   r = misdn_lib_send_event(newbc, EVENT_SETUP);

   /** we should have l3id after sending setup **/
   ch->l3id = newbc->l3_id;

   if (r == -ENOCHAN ) {
      chan_misdn_log(0, port, " --> * Theres no Channel at the moment .. !\n");
      chan_misdn_log(1, port, " --> * SEND: State Down pid:%d\n", newbc ? newbc->pid : -1);
      ast->hangupcause = AST_CAUSE_NORMAL_CIRCUIT_CONGESTION;
      ast_setstate(ast, AST_STATE_DOWN);
      return -1;
   }

   chan_misdn_log(2, port, " --> * SEND: State Dialing pid:%d\n", newbc ? newbc->pid : 1);

   ast_setstate(ast, AST_STATE_DIALING);
   ast->hangupcause = AST_CAUSE_NORMAL_CLEARING;

   if (newbc->nt) {
      stop_bc_tones(ch);
   }

   ch->state = MISDN_CALLING;
   
   return 0; 
}
static int misdn_check_l2l1 ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 5656 of file chan_misdn.c.

References AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), ast_safe_sleep(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), BUFFERSIZE, chan_misdn_log(), LOG_WARNING, misdn_cfg_get(), misdn_cfg_get_next_port(), MISDN_CFG_GROUPNAME, misdn_lib_get_port_up(), misdn_lib_port_up(), and parse().

Referenced by load_module().

{
   char *parse;
   char group[BUFFERSIZE + 1];
   char *port_str;
   int port = 0;
   int timeout;
   int dowait = 0;
   int port_up;

   AST_DECLARE_APP_ARGS(args,
         AST_APP_ARG(grouppar);
         AST_APP_ARG(timeout);
   );

   if (ast_strlen_zero((char *)data)) {
      ast_log(LOG_WARNING, "misdn_check_l2l1 Requires arguments\n");
      return -1;
   }

   parse = ast_strdupa(data);
   AST_STANDARD_APP_ARGS(args, parse);

   if (args.argc != 2) {
      ast_log(LOG_WARNING, "Wrong argument count\n");
      return 0;
   }

   /*ast_log(LOG_NOTICE, "Arguments: group/port '%s' timeout '%s'\n", args.grouppar, args.timeout);*/
   timeout = atoi(args.timeout);
   port_str = args.grouppar;

   if (port_str[0] == 'g' && port_str[1] == ':' ) {
      /* We make a group call lets checkout which ports are in my group */
      port_str += 2;
      ast_copy_string(group, port_str, sizeof(group));
      chan_misdn_log(2, 0, "Checking Ports in group: %s\n", group);

      for ( port = misdn_cfg_get_next_port(port); 
         port > 0;
         port = misdn_cfg_get_next_port(port)) {
         char cfg_group[BUFFERSIZE + 1];

         chan_misdn_log(2, 0, "trying port %d\n", port);

         misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));

         if (!strcasecmp(cfg_group, group)) {
            port_up = misdn_lib_port_up(port, 1);

            if (!port_up) {
               chan_misdn_log(2, 0, " --> port '%d'\n", port);
               misdn_lib_get_port_up(port);
               dowait = 1;
            }
         }
      }

   } else {
      port = atoi(port_str);
      chan_misdn_log(2, 0, "Checking Port: %d\n",port);
      port_up = misdn_lib_port_up(port, 1);
      if (!port_up) {
         misdn_lib_get_port_up(port);
         dowait = 1;
      }
   }

   if (dowait) {
      chan_misdn_log(2, 0, "Waiting for '%d' seconds\n", timeout);
      ast_safe_sleep(chan, timeout * 1000);
   }

   return 0;
}
static int misdn_digit_begin ( struct ast_channel chan,
char  digit 
) [static]

Definition at line 2593 of file chan_misdn.c.

{
   /* XXX Modify this callback to support Asterisk controlling the length of DTMF */
   return 0;
}
static int misdn_digit_end ( struct ast_channel ast,
char  digit,
unsigned int  duration 
) [static]

Definition at line 2599 of file chan_misdn.c.

References chan_list::ast, ast_copy_string(), ast_log(), chan_list::bc, buf, chan_misdn_log(), misdn_bchannel::dad, EVENT_INFORMATION, ast_channel::exten, misdn_bchannel::info_dad, misdn_bchannel::infos_pending, LOG_WARNING, MISDN_ASTERISK_TECH_PVT, MISDN_CALLING, MISDN_CALLING_ACKNOWLEDGE, misdn_lib_send_event(), misdn_bchannel::port, send_digit_to_chan(), misdn_bchannel::send_dtmf, and chan_list::state.

{
   struct chan_list *p;
   struct misdn_bchannel *bc;
   char buf[2] = { digit, 0 };

   if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
      return -1;
   }

   bc = p->bc;
   chan_misdn_log(1, bc ? bc->port : 0, "* IND : Digit %c\n", digit);
   
   if (!bc) {
      ast_log(LOG_WARNING, " --> !! Got Digit Event without having bchannel Object\n");
      return -1;
   }
   
   switch (p->state ) {
   case MISDN_CALLING:
      if (strlen(bc->infos_pending) < sizeof(bc->infos_pending) - 1) {
         strncat(bc->infos_pending, buf, sizeof(bc->infos_pending) - strlen(bc->infos_pending) - 1);
      }
      break;
   case MISDN_CALLING_ACKNOWLEDGE:
      ast_copy_string(bc->info_dad, buf, sizeof(bc->info_dad));
      if (strlen(bc->dad) < sizeof(bc->dad) - 1) {
         strncat(bc->dad, buf, sizeof(bc->dad) - strlen(bc->dad) - 1);
      }
      ast_copy_string(p->ast->exten, bc->dad, sizeof(p->ast->exten));
      misdn_lib_send_event(bc, EVENT_INFORMATION);
      break;
   default:
      if (bc->send_dtmf) {
         send_digit_to_chan(p, digit);
      }
      break;
   }

   return 0;
}
static int misdn_facility_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 5608 of file chan_misdn.c.

References AST_APP_ARG, ast_copy_string(), AST_DECLARE_APP_ARGS, ast_log(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), chan_list::bc, chan_misdn_log(), EVENT_FACILITY, misdn_bchannel::fac_out, LOG_WARNING, MISDN_ASTERISK_TECH_PVT, misdn_lib_send_event(), parse(), misdn_bchannel::port, ast_channel::tech, and ast_channel_tech::type.

Referenced by load_module().

{
   struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
   char *parse;
   AST_DECLARE_APP_ARGS(args,
      AST_APP_ARG(facility_type);
      AST_APP_ARG(arg)[99];
   );

   chan_misdn_log(0, 0, "TYPE: %s\n", chan->tech->type);
   
   if (strcasecmp(chan->tech->type, "mISDN")) {
      ast_log(LOG_WARNING, "misdn_facility makes only sense with chan_misdn channels!\n");
      return -1;
   }
   
   if (ast_strlen_zero((char *)data)) {
      ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,<args>]\n");
      return -1;
   }

   parse = ast_strdupa(data);
   AST_STANDARD_APP_ARGS(args, parse);

   if (ast_strlen_zero(args.facility_type)) {
      ast_log(LOG_WARNING, "misdn_facility requires arguments: facility_type[,<args>]\n");
      return -1;
   }

   if (!strcasecmp(args.facility_type, "calldeflect")) {
      if (ast_strlen_zero(args.arg[0])) {
         ast_log(LOG_WARNING, "Facility: Call Deflection requires an argument: Number\n");
      }

      if (strlen(args.arg[0]) >= sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber)) {
         ast_log(LOG_WARNING, "Facility: Number argument too long (up to %d digits are allowed). Ignoring.\n", (int)sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber));
         return 0;
      }
      ch->bc->fac_out.Function = Fac_CD;
      ast_copy_string((char *)ch->bc->fac_out.u.CDeflection.DeflectedToNumber, args.arg[0], sizeof(ch->bc->fac_out.u.CDeflection.DeflectedToNumber));
      misdn_lib_send_event(ch->bc, EVENT_FACILITY);
   } else {
      chan_misdn_log(1, ch->bc->port, "Unknown Facility: %s\n", args.facility_type);
   }

   return 0;
}
static int misdn_fixup ( struct ast_channel oldast,
struct ast_channel ast 
) [static]

Definition at line 2642 of file chan_misdn.c.

References chan_list::ast, chan_list::bc, chan_misdn_log(), chan_list::l3id, MISDN_ASTERISK_TECH_PVT, misdn_get_ch_state(), and misdn_bchannel::port.

{
   struct chan_list *p;

   if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
      return -1;
   }

   chan_misdn_log(1, p->bc ? p->bc->port : 0, "* IND: Got Fixup State:%s L3id:%x\n", misdn_get_ch_state(p), p->l3id);

   p->ast = ast;

   return 0;
}
static const char* misdn_get_ch_state ( struct chan_list p) [static]

Definition at line 1310 of file chan_misdn.c.

References ARRAY_LEN, state_struct::state, chan_list::state, and state_struct::txt.

Referenced by cb_events(), misdn_fixup(), misdn_hangup(), misdn_write(), and print_bc_info().

{
   int i;
   static char state[8];
   
   if (!p) {
      return NULL;
   }
  
   for (i = 0; i < ARRAY_LEN(state_array); i++) {
      if (state_array[i].state == p->state) {
         return state_array[i].txt;
      }
   }

   snprintf(state, sizeof(state), "%d", p->state) ;

   return state;
}
static int misdn_hangup ( struct ast_channel ast) [static]

Definition at line 2789 of file chan_misdn.c.

References ast_channel::_state, chan_list::ast, AST_CAUSE_NORMAL_CLEARING, ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_debug, ast_log(), AST_STATE_RESERVED, chan_list::bc, misdn_bchannel::cause, chan_misdn_log(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, EVENT_DISCONNECT, EVENT_RELEASE, EVENT_RELEASE_COMPLETE, ast_channel::exten, ast_channel::hangupcause, hanguptone_indicate(), chan_list::hold, INFO_PI_INBAND_AVAILABLE, chan_list::l3id, LOG_NOTICE, LOG_WARNING, MISDN_ALERTING, MISDN_ASTERISK_TECH_PVT, MISDN_BUSY, MISDN_CALLING, MISDN_CALLING_ACKNOWLEDGE, MISDN_CLEANING, MISDN_CONNECTED, MISDN_DIALING, MISDN_DISCONNECTED, misdn_get_ch_state(), MISDN_HOLD_DISCONNECT, MISDN_HOLD_IDLE, MISDN_INCOMING_SETUP, misdn_lib_find_held_bc(), misdn_lib_release(), misdn_lib_send_event(), MISDN_NOTHING, MISDN_PROCEEDING, MISDN_PROGRESS, ast_channel::name, chan_list::need_busy, misdn_bchannel::need_disconnect, chan_list::need_hangup, chan_list::need_queue_hangup, misdn_bchannel::need_release, misdn_bchannel::nt, ORG_AST, chan_list::originator, misdn_bchannel::out_cause, pbx_builtin_getvar_helper(), misdn_bchannel::pid, misdn_bchannel::port, hold_info::port, misdn_bchannel::progress_indicator, release_chan(), release_chan_early(), start_bc_tones(), chan_list::state, hold_info::state, stop_bc_tones(), misdn_bchannel::uu, misdn_bchannel::uulen, and var.

{
   struct chan_list *p;
   struct misdn_bchannel *bc;
   const char *var;

   if (!ast || !(p = MISDN_ASTERISK_TECH_PVT(ast))) {
      return -1;
   }
   MISDN_ASTERISK_TECH_PVT(ast) = NULL;

   ast_debug(1, "misdn_hangup(%s)\n", ast->name);

   if (p->hold.state == MISDN_HOLD_IDLE) {
      bc = p->bc;
   } else {
      p->hold.state = MISDN_HOLD_DISCONNECT;
      bc = misdn_lib_find_held_bc(p->hold.port, p->l3id);
      if (!bc) {
         chan_misdn_log(4, p->hold.port,
            "misdn_hangup: Could not find held bc for (%s)\n", ast->name);
         release_chan_early(p);
         return 0;
      }
   }

   if (ast->_state == AST_STATE_RESERVED || p->state == MISDN_NOTHING) {
      /* between request and call */
      ast_debug(1, "State Reserved (or nothing) => chanIsAvail\n");
      release_chan_early(p);
      if (bc) {
         misdn_lib_release(bc);
      }
      return 0;
   }
   if (!bc) {
      ast_log(LOG_WARNING, "Hangup with private but no bc ? state:%s l3id:%x\n",
         misdn_get_ch_state(p), p->l3id);
      release_chan_early(p);
      return 0;
   }

   p->ast = NULL;
   p->need_hangup = 0;
   p->need_queue_hangup = 0;
   p->need_busy = 0;

   if (!bc->nt) {
      stop_bc_tones(p);
   }

   bc->out_cause = ast->hangupcause ? ast->hangupcause : AST_CAUSE_NORMAL_CLEARING;

   ast_channel_lock(ast);
   var = pbx_builtin_getvar_helper(ast, "HANGUPCAUSE");
   if (!var) {
      var = pbx_builtin_getvar_helper(ast, "PRI_CAUSE");
   }
   if (var) {
      int tmpcause;

      tmpcause = atoi(var);
      bc->out_cause = tmpcause ? tmpcause : AST_CAUSE_NORMAL_CLEARING;
   }

   var = pbx_builtin_getvar_helper(ast, "MISDN_USERUSER");
   if (var) {
      ast_log(LOG_NOTICE, "MISDN_USERUSER: %s\n", var);
      ast_copy_string(bc->uu, var, sizeof(bc->uu));
      bc->uulen = strlen(bc->uu);
   }
   ast_channel_unlock(ast);

   chan_misdn_log(1, bc->port,
      "* IND : HANGUP\tpid:%d ctx:%s dad:%s oad:%s State:%s\n",
      bc->pid,
      ast->context,
      ast->exten,
      ast->cid.cid_num,
      misdn_get_ch_state(p));
   chan_misdn_log(3, bc->port, " --> l3id:%x\n", p->l3id);
   chan_misdn_log(3, bc->port, " --> cause:%d\n", bc->cause);
   chan_misdn_log(2, bc->port, " --> out_cause:%d\n", bc->out_cause);

   switch (p->state) {
   case MISDN_INCOMING_SETUP:
      /*
       * This is the only place in misdn_hangup, where we
       * can call release_chan, else it might create a lot of trouble.
       */
      ast_log(LOG_NOTICE, "release channel, in INCOMING_SETUP state.. no other events happened\n");
      release_chan(p, bc);
      misdn_lib_send_event(bc, EVENT_RELEASE_COMPLETE);
      return 0;
   case MISDN_DIALING:
      if (p->hold.state == MISDN_HOLD_IDLE) {
         start_bc_tones(p);
         hanguptone_indicate(p);
      }

      p->state = MISDN_CLEANING;
      if (bc->need_disconnect) {
         misdn_lib_send_event(bc, EVENT_DISCONNECT);
      }
      break;
   case MISDN_CALLING_ACKNOWLEDGE:
      if (p->hold.state == MISDN_HOLD_IDLE) {
         start_bc_tones(p);
         hanguptone_indicate(p);
      }

      if (bc->need_disconnect) {
         misdn_lib_send_event(bc, EVENT_DISCONNECT);
      }
      break;

   case MISDN_CALLING:
   case MISDN_ALERTING:
   case MISDN_PROGRESS:
   case MISDN_PROCEEDING:
      if (p->originator != ORG_AST && p->hold.state == MISDN_HOLD_IDLE) {
         hanguptone_indicate(p);
      }

      if (bc->need_disconnect) {
         misdn_lib_send_event(bc, EVENT_DISCONNECT);
      }
      break;
   case MISDN_CONNECTED:
      /*  Alerting or Disconnect */
      if (bc->nt && p->hold.state == MISDN_HOLD_IDLE) {
         start_bc_tones(p);
         hanguptone_indicate(p);
         bc->progress_indicator = INFO_PI_INBAND_AVAILABLE;
      }
      if (bc->need_disconnect) {
         misdn_lib_send_event(bc, EVENT_DISCONNECT);
      }
      break;
   case MISDN_DISCONNECTED:
      if (bc->need_release) {
         misdn_lib_send_event(bc, EVENT_RELEASE);
      }
      break;

   case MISDN_CLEANING:
      return 0;

   case MISDN_BUSY:
      break;
   default:
      if (bc->nt) {
         bc->out_cause = -1;
         if (bc->need_release) {
            misdn_lib_send_event(bc, EVENT_RELEASE);
         }
      } else {
         if (bc->need_disconnect) {
            misdn_lib_send_event(bc, EVENT_DISCONNECT);
         }
      }
      break;
   }

   p->state = MISDN_CLEANING;
   chan_misdn_log(3, bc->port, " --> Channel: %s hungup new state:%s\n", ast->name,
      misdn_get_ch_state(p));

   return 0;
}
static int misdn_indication ( struct ast_channel ast,
int  cond,
const void *  data,
size_t  datalen 
) [static]

Definition at line 2659 of file chan_misdn.c.

References AST_CAUSE_SWITCH_CONGESTION, AST_CAUSE_USER_BUSY, AST_CONTROL_ANSWER, AST_CONTROL_BUSY, AST_CONTROL_CONGESTION, AST_CONTROL_FLASH, AST_CONTROL_HOLD, AST_CONTROL_OFFHOOK, AST_CONTROL_PROCEEDING, AST_CONTROL_PROGRESS, AST_CONTROL_RING, AST_CONTROL_RINGING, AST_CONTROL_TAKEOFFHOOK, AST_CONTROL_UNHOLD, ast_log(), ast_moh_start(), ast_moh_stop(), ast_setstate(), AST_STATE_BUSY, AST_STATE_RING, chan_list::bc, chan_misdn_log(), EVENT_ALERTING, EVENT_DISCONNECT, EVENT_PROCEEDING, EVENT_PROGRESS, hanguptone_indicate(), chan_list::hold, chan_list::incoming_early_audio, LOG_WARNING, MISDN_ALERTING, MISDN_ASTERISK_TECH_PVT, MISDN_CONNECTED, MISDN_HOLD_IDLE, misdn_inband_avail(), misdn_lib_send_event(), chan_list::mohinterpret, ast_channel::name, misdn_bchannel::nt, ORG_MISDN, chan_list::originator, chan_list::other_ch, misdn_bchannel::out_cause, misdn_bchannel::pid, misdn_bchannel::port, start_bc_tones(), chan_list::state, hold_info::state, and stop_indicate().

{
   struct chan_list *p;

   if (!ast || ! (p=MISDN_ASTERISK_TECH_PVT(ast))) {
      ast_log(LOG_WARNING, "Returned -1 in misdn_indication\n");
      return -1;
   }
   
   if (!p->bc) {
      if (p->hold.state == MISDN_HOLD_IDLE) {
         chan_misdn_log(1, 0, "* IND : Indication [%d] ignored on %s\n", cond,
            ast->name);
         ast_log(LOG_WARNING, "Private Pointer but no bc ?\n");
      } else {
         chan_misdn_log(1, 0, "* IND : Indication [%d] ignored on hold %s\n",
            cond, ast->name);
      }
      return -1;
   }
   
   chan_misdn_log(5, p->bc->port, "* IND : Indication [%d] on %s\n\n", cond, ast->name);
   
   switch (cond) {
   case AST_CONTROL_BUSY:
      chan_misdn_log(1, p->bc->port, "* IND :\tbusy pid:%d\n", p->bc ? p->bc->pid : -1);
      ast_setstate(ast, AST_STATE_BUSY);

      p->bc->out_cause = AST_CAUSE_USER_BUSY;
      if (p->state != MISDN_CONNECTED) {
         start_bc_tones(p);
         misdn_lib_send_event( p->bc, EVENT_DISCONNECT);
      }
      return -1;
   case AST_CONTROL_RING:
      chan_misdn_log(1, p->bc->port, "* IND :\tring pid:%d\n", p->bc ? p->bc->pid : -1);
      return -1;
   case AST_CONTROL_RINGING:
      chan_misdn_log(1, p->bc->port, "* IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1);
      switch (p->state) {
      case MISDN_ALERTING:
         chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but I was Ringing before, so ignoring it\n", p->bc ? p->bc->pid : -1);
         break;
      case MISDN_CONNECTED:
         chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d but Connected, so just send TONE_ALERTING without state changes \n", p->bc ? p->bc->pid : -1);
         return -1;
      default:
         p->state = MISDN_ALERTING;
         chan_misdn_log(2, p->bc->port, " --> * IND :\tringing pid:%d\n", p->bc ? p->bc->pid : -1);
         misdn_lib_send_event( p->bc, EVENT_ALERTING);

         if (p->other_ch && p->other_ch->bc) {
            if (misdn_inband_avail(p->other_ch->bc)) {
               chan_misdn_log(2, p->bc->port, " --> other End is mISDN and has inband info available\n");
               break;
            }

            if (!p->other_ch->bc->nt) {
               chan_misdn_log(2, p->bc->port, " --> other End is mISDN TE so it has inband info for sure (?)\n");
               break;
            }
         }

         chan_misdn_log(3, p->bc->port, " --> * SEND: State Ring pid:%d\n", p->bc ? p->bc->pid : -1);
         ast_setstate(ast, AST_STATE_RING);

         if (!p->bc->nt && (p->originator == ORG_MISDN) && !p->incoming_early_audio) {
            chan_misdn_log(2, p->bc->port, " --> incoming_early_audio off\n");
         } else {
            return -1;
         }
      }
      break;
   case AST_CONTROL_ANSWER:
      chan_misdn_log(1, p->bc->port, " --> * IND :\tanswer pid:%d\n", p->bc ? p->bc->pid : -1);
      start_bc_tones(p);
      break;
   case AST_CONTROL_TAKEOFFHOOK:
      chan_misdn_log(1, p->bc->port, " --> *\ttakeoffhook pid:%d\n", p->bc ? p->bc->pid : -1);
      return -1;
   case AST_CONTROL_OFFHOOK:
      chan_misdn_log(1, p->bc->port, " --> *\toffhook pid:%d\n", p->bc ? p->bc->pid : -1);
      return -1;
   case AST_CONTROL_FLASH:
      chan_misdn_log(1, p->bc->port, " --> *\tflash pid:%d\n", p->bc ? p->bc->pid : -1);
      break;
   case AST_CONTROL_PROGRESS:
      chan_misdn_log(1, p->bc->port, " --> * IND :\tprogress pid:%d\n", p->bc ? p->bc->pid : -1);
      misdn_lib_send_event( p->bc, EVENT_PROGRESS);
      break;
   case AST_CONTROL_PROCEEDING:
      chan_misdn_log(1, p->bc->port, " --> * IND :\tproceeding pid:%d\n", p->bc ? p->bc->pid : -1);
      misdn_lib_send_event( p->bc, EVENT_PROCEEDING);
      break;
   case AST_CONTROL_CONGESTION:
      chan_misdn_log(1, p->bc->port, " --> * IND :\tcongestion pid:%d\n", p->bc ? p->bc->pid : -1);

      p->bc->out_cause = AST_CAUSE_SWITCH_CONGESTION;
      start_bc_tones(p);
      misdn_lib_send_event( p->bc, EVENT_DISCONNECT);

      if (p->bc->nt) {
         hanguptone_indicate(p);
      }
      break;
   case -1 :
      chan_misdn_log(1, p->bc->port, " --> * IND :\t-1! (stop indication) pid:%d\n", p->bc ? p->bc->pid : -1);

      stop_indicate(p);

      if (p->state == MISDN_CONNECTED) {
         start_bc_tones(p);
      }
      break;
   case AST_CONTROL_HOLD:
      ast_moh_start(ast, data, p->mohinterpret); 
      chan_misdn_log(1, p->bc->port, " --> *\tHOLD pid:%d\n", p->bc ? p->bc->pid : -1);
      break;
   case AST_CONTROL_UNHOLD:
      ast_moh_stop(ast);
      chan_misdn_log(1, p->bc->port, " --> *\tUNHOLD pid:%d\n", p->bc ? p->bc->pid : -1);
      break;
   default:
      chan_misdn_log(1, p->bc->port, " --> * Unknown Indication:%d pid:%d\n", cond, p->bc ? p->bc->pid : -1);
      return -1;
   }
  
   return 0;
}
void misdn_jb_destroy ( struct misdn_jb jb)

frees the data and destroys the given jitterbuffer struct

Definition at line 6003 of file chan_misdn.c.

References ast_free, ast_mutex_destroy(), misdn_jb::mutexjb, misdn_jb::ok, and misdn_jb::samples.

Referenced by config_jitterbuffer(), release_chan(), and release_chan_early().

int misdn_jb_empty ( struct misdn_jb jb,
char *  data,
int  len 
)

gets len bytes out of the jitterbuffer if available, else only the available data is returned and the return value indicates the number of data.

Definition at line 6077 of file chan_misdn.c.

References ast_mutex_lock(), ast_mutex_unlock(), chan_misdn_log(), len(), misdn_jb::mutexjb, misdn_jb::ok, misdn_jb::rp, misdn_jb::samples, misdn_jb::size, misdn_jb::state_buffer, misdn_jb::state_empty, and misdn_jb::wp.

Referenced by chan_misdn_jb_empty().

{
   int i, wp, rp, read = 0;

   ast_mutex_lock(&jb->mutexjb);

   rp = jb->rp;
   wp = jb->wp;

   if (jb->state_empty) {  
      for (i = 0; i < len; i++) {
         if (wp == rp) {
            jb->rp = rp;
            jb->state_empty = 0;

            ast_mutex_unlock(&jb->mutexjb);

            return read;
         } else {
            if (jb->ok[rp] == 1) {
               data[i] = jb->samples[rp];
               jb->ok[rp] = 0;
               rp = (rp != jb->size - 1) ? rp + 1 : 0;
               read += 1;
            }
         }
      }

      if (wp >= rp) {
         jb->state_buffer = wp - rp;
      } else {
         jb->state_buffer = jb->size - rp + wp;
      }
      chan_misdn_log(9, 0, "misdn_jb_empty: read:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb);

      jb->rp = rp;
   } else {
      chan_misdn_log(9, 0, "misdn_jb_empty: Wait...requested:%d p:%p\n", len, jb);
   }

   ast_mutex_unlock(&jb->mutexjb);

   return read;
}
int misdn_jb_fill ( struct misdn_jb jb,
const char *  data,
int  len 
)

fills the jitterbuffer with len data returns < 0 if there was an error (buffer overrun).

Definition at line 6014 of file chan_misdn.c.

References ast_mutex_lock(), ast_mutex_unlock(), misdn_jb::bytes_wrote, chan_misdn_log(), len(), misdn_jb::mutexjb, misdn_jb::ok, misdn_jb::rp, misdn_jb::samples, misdn_jb::size, misdn_jb::state_buffer, misdn_jb::state_empty, misdn_jb::state_full, misdn_jb::upper_threshold, and misdn_jb::wp.

Referenced by misdn_write().

{
   int i, j, rp, wp;

   if (!jb || ! data) {
      return 0;
   }

   ast_mutex_lock(&jb->mutexjb);
   
   wp = jb->wp;
   rp = jb->rp;
   
   for (i = 0; i < len; i++) {
      jb->samples[wp] = data[i];
      jb->ok[wp] = 1;
      wp = (wp != jb->size - 1) ? wp + 1 : 0;

      if (wp == jb->rp) {
         jb->state_full = 1;
      }
   }

   if (wp >= rp) {
      jb->state_buffer = wp - rp;
   } else {
      jb->state_buffer = jb->size - rp + wp;
   }
   chan_misdn_log(9, 0, "misdn_jb_fill: written:%d | Buffer status:%d p:%p\n", len, jb->state_buffer, jb);

   if (jb->state_full) {
      jb->wp = wp;

      rp = wp;
      for (j = 0; j < jb->upper_threshold; j++) {
         rp = (rp != 0) ? rp - 1 : jb->size - 1;
      }
      jb->rp = rp;
      jb->state_full = 0;
      jb->state_empty = 1;

      ast_mutex_unlock(&jb->mutexjb);

      return -1;
   }

   if (!jb->state_empty) {
      jb->bytes_wrote += len;
      if (jb->bytes_wrote >= jb->upper_threshold) {
         jb->state_empty = 1;
         jb->bytes_wrote = 0;
      }
   }
   jb->wp = wp;

   ast_mutex_unlock(&jb->mutexjb);
   
   return 0;
}
struct misdn_jb * misdn_jb_init ( int  size,
int  upper_threshold 
) [read]

allocates the jb-structure and initialize the elements

Definition at line 5961 of file chan_misdn.c.

References ast_free, ast_malloc, ast_mutex_init(), misdn_jb::bytes_wrote, chan_misdn_log(), misdn_jb::mutexjb, misdn_jb::ok, misdn_jb::rp, misdn_jb::samples, misdn_jb::size, misdn_jb::state_empty, misdn_jb::state_full, misdn_jb::upper_threshold, and misdn_jb::wp.

Referenced by config_jitterbuffer().

{
   int i;
   struct misdn_jb *jb;

   jb = ast_malloc(sizeof(*jb));
   if (!jb) {
       chan_misdn_log(-1, 0, "No free Mem for jb\n");
       return NULL;
   }
   jb->size = size;
   jb->upper_threshold = upper_threshold;
   jb->wp = 0;
   jb->rp = 0;
   jb->state_full = 0;
   jb->state_empty = 0;
   jb->bytes_wrote = 0;
   jb->samples = ast_malloc(size * sizeof(char));
   if (!jb->samples) {
      ast_free(jb);
      chan_misdn_log(-1, 0, "No free Mem for jb->samples\n");
      return NULL;
   }

   jb->ok = ast_malloc(size * sizeof(char));
   if (!jb->ok) {
      ast_free(jb->samples);
      ast_free(jb);
      chan_misdn_log(-1, 0, "No free Mem for jb->ok\n");
      return NULL;
   }

   for (i = 0; i < size; i++) {
      jb->ok[i] = 0;
   }

   ast_mutex_init(&jb->mutexjb);

   return jb;
}
static int misdn_l1_task ( const void *  vdata) [static]

Definition at line 838 of file chan_misdn.c.

References chan_misdn_log(), and misdn_lib_isdn_l1watcher().

Referenced by load_module().

{
   const int *data = vdata;
   misdn_lib_isdn_l1watcher(*data);
   chan_misdn_log(5, *data, "L1watcher timeout\n");
   return 1;
}
static struct ast_channel * misdn_new ( struct chan_list cl,
int  state,
char *  exten,
char *  callerid,
int  format,
int  port,
int  c 
) [static, read]

Definition at line 3702 of file chan_misdn.c.

References ast_callerid_parse(), ast_channel_alloc(), ast_channel_set_fd(), ast_copy_string(), ast_jb_configure(), ast_log(), AST_STATE_RING, ast_strdup, chan_misdn_log(), ast_channel::cid, ast_callerid::cid_ani, cid_name, cid_num, ast_channel::exten, format, LOG_ERROR, misdn_cfg_get(), misdn_cfg_get_next_port(), MISDN_GEN_BRIDGING, misdn_get_global_jbconf(), misdn_lib_port_is_pri(), misdn_tech_wo_bridge, ast_channel::nativeformats, chan_list::pipe, prefformat, ast_channel::priority, ast_channel::rawreadformat, ast_channel::rawwriteformat, ast_channel::readformat, ast_channel::rings, ast_channel::tech, ast_channel::tech_pvt, and ast_channel::writeformat.

Referenced by cb_events(), and misdn_request().

{
   struct ast_channel *tmp;
   char *cid_name = 0, *cid_num = 0;
   int chan_offset = 0;
   int tmp_port = misdn_cfg_get_next_port(0);
   int bridging;

   for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
      if (tmp_port == port) {
         break;
      }
      chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2;
   }
   if (c < 0) {
      c = 0;
   }

   if (callerid) {
      ast_callerid_parse(callerid, &cid_name, &cid_num);
   }

   tmp = ast_channel_alloc(1, state, cid_num, cid_name, "", exten, "", 0, "%s/%s%d-u%d", misdn_type, c ? "" : "tmp", chan_offset + c, glob_channel++);
   if (tmp) {
      chan_misdn_log(2, 0, " --> * NEW CHANNEL dad:%s oad:%s\n", exten, callerid);

      tmp->nativeformats = prefformat;

      tmp->readformat = format;
      tmp->rawreadformat = format;
      tmp->writeformat = format;
      tmp->rawwriteformat = format;
    
      tmp->tech_pvt = chlist;

      misdn_cfg_get(0, MISDN_GEN_BRIDGING, &bridging, sizeof(bridging));

      tmp->tech = bridging ? &misdn_tech : &misdn_tech_wo_bridge;

      tmp->writeformat = format;
      tmp->readformat = format;
      tmp->priority = 1;

      if (exten) {
         ast_copy_string(tmp->exten, exten, sizeof(tmp->exten));
      } else {
         chan_misdn_log(1, 0, "misdn_new: no exten given.\n");
      }

      if (callerid) {
         /* Don't use ast_set_callerid() here because it will
          * generate a needless NewCallerID event */
         tmp->cid.cid_ani = ast_strdup(cid_num);
      }

      if (pipe(chlist->pipe) < 0) {
         ast_log(LOG_ERROR, "Pipe failed\n");
      }
      ast_channel_set_fd(tmp, 0, chlist->pipe[0]);

      tmp->rings = (state == AST_STATE_RING) ? 1 : 0;

      ast_jb_configure(tmp, misdn_get_global_jbconf());
   } else {
      chan_misdn_log(-1, 0, "Unable to allocate channel structure\n");
   }
   
   return tmp;
}
static int misdn_overlap_dial_task ( const void *  data) [static]

Definition at line 846 of file chan_misdn.c.

References chan_list::ast, AST_CAUSE_UNALLOCATED, ast_copy_string(), ast_exists_extension(), ast_mutex_lock(), ast_mutex_unlock(), ast_strlen_zero(), ast_tvdiff_ms(), ast_tvnow(), chan_list::bc, chan_misdn_log(), chan_list::context, misdn_bchannel::dad, EVENT_DISCONNECT, ast_channel::exten, hanguptone_indicate(), MISDN_CLEANING, MISDN_DIALING, misdn_lib_send_event(), MISDN_WAITING4DIGS, misdn_bchannel::oad, misdn_bchannel::out_cause, chan_list::overlap_dial, chan_list::overlap_dial_task, chan_list::overlap_tv, chan_list::overlap_tv_lock, pbx_start_chan(), misdn_bchannel::port, chan_list::state, and stop_indicate().

Referenced by cb_events().

{
   struct timeval tv_end, tv_now;
   int diff;
   struct chan_list *ch = (struct chan_list *) data;
   char *dad;

   chan_misdn_log(4, ch->bc->port, "overlap dial task, chan_state: %d\n", ch->state);

   if (ch->state != MISDN_WAITING4DIGS) {
      ch->overlap_dial_task = -1;
      return 0;
   }

   ast_mutex_lock(&ch->overlap_tv_lock);
   tv_end = ch->overlap_tv;
   ast_mutex_unlock(&ch->overlap_tv_lock);

   tv_end.tv_sec += ch->overlap_dial;
   tv_now = ast_tvnow();

   if ((diff = ast_tvdiff_ms(tv_end, tv_now)) > 100) {
      return diff;
   }

   /* if we are 100ms near the timeout, we are satisfied.. */
   stop_indicate(ch);

   if (ast_strlen_zero(ch->bc->dad)) {
      dad = "s";
      ast_copy_string(ch->ast->exten, "s", sizeof(ch->ast->exten));
   } else {
      dad = ch->bc->dad;
   }

   if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->oad)) {
      ch->state = MISDN_DIALING;
      if (pbx_start_chan(ch) < 0) {
         chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
         goto misdn_overlap_dial_task_disconnect;
      }
   } else {
misdn_overlap_dial_task_disconnect:
      hanguptone_indicate(ch);
      ch->bc->out_cause = AST_CAUSE_UNALLOCATED;
      ch->state = MISDN_CLEANING;
      misdn_lib_send_event(ch->bc, EVENT_DISCONNECT);
   }
   ch->overlap_dial_task = -1;
   return 0;
}
static struct ast_frame* misdn_read ( struct ast_channel ast) [static, read]

Definition at line 3033 of file chan_misdn.c.

References chan_list::ast_dsp, AST_FORMAT_ALAW, AST_FRAME_VOICE, ast_poll, chan_list::ast_rd_buf, ast_tv(), ast_tvdiff_ms(), ast_tvnow(), ast_tvzero(), chan_list::bc, chan_misdn_log(), ast_frame::data, ast_frame::datalen, ast_frame::delivery, errno, chan_list::faxdetect, chan_list::faxdetect_timeout, chan_list::faxdetect_tv, chan_list::faxhandled, chan_list::frame, ast_frame::frametype, chan_list::hold, len(), ast_frame::mallocd, MISDN_ASTERISK_TECH_PVT, MISDN_HOLD_IDLE, ast_frame::offset, chan_list::pipe, misdn_bchannel::port, process_ast_dsp(), ast_frame::ptr, ast_frame::samples, ast_frame::src, hold_info::state, and ast_frame::subclass.

{
   struct chan_list *tmp;
   int len, t;
   struct pollfd pfd = { .fd = -1, .events = POLLIN };

   if (!ast) {
      chan_misdn_log(1, 0, "misdn_read called without ast\n");
      return NULL;
   }
   if (!(tmp = MISDN_ASTERISK_TECH_PVT(ast))) {
      chan_misdn_log(1, 0, "misdn_read called without ast->pvt\n");
      return NULL;
   }

   if (!tmp->bc && tmp->hold.state == MISDN_HOLD_IDLE) {
      chan_misdn_log(1, 0, "misdn_read called without bc\n");
      return NULL;
   }

   pfd.fd = tmp->pipe[0];
   t = ast_poll(&pfd, 1, 20);

   if (t < 0) {
      chan_misdn_log(-1, tmp->bc->port, "poll() error (err=%s)\n", strerror(errno));
      return NULL;
   }

   if (!t) {
      chan_misdn_log(3, tmp->bc->port, "poll() timed out\n");
      len = 160;
   } else if (pfd.revents & POLLIN) {
      len = read(tmp->pipe[0], tmp->ast_rd_buf, sizeof(tmp->ast_rd_buf));

      if (len <= 0) {
         /* we hangup here, since our pipe is closed */
         chan_misdn_log(2, tmp->bc->port, "misdn_read: Pipe closed, hanging up\n");
         return NULL;
      }

   } else {
      return NULL;
   }

   tmp->frame.frametype = AST_FRAME_VOICE;
   tmp->frame.subclass = AST_FORMAT_ALAW;
   tmp->frame.datalen = len;
   tmp->frame.samples = len;
   tmp->frame.mallocd = 0;
   tmp->frame.offset = 0;
   tmp->frame.delivery = ast_tv(0, 0);
   tmp->frame.src = NULL;
   tmp->frame.data.ptr = tmp->ast_rd_buf;

   if (tmp->faxdetect && !tmp->faxhandled) {
      if (tmp->faxdetect_timeout) {
         if (ast_tvzero(tmp->faxdetect_tv)) {
            tmp->faxdetect_tv = ast_tvnow();
            chan_misdn_log(2, tmp->bc->port, "faxdetect: starting detection with timeout: %ds ...\n", tmp->faxdetect_timeout);
            return process_ast_dsp(tmp, &tmp->frame);
         } else {
            struct timeval tv_now = ast_tvnow();
            int diff = ast_tvdiff_ms(tv_now, tmp->faxdetect_tv);
            if (diff <= (tmp->faxdetect_timeout * 1000)) {
               chan_misdn_log(5, tmp->bc->port, "faxdetect: detecting ...\n");
               return process_ast_dsp(tmp, &tmp->frame);
            } else {
               chan_misdn_log(2, tmp->bc->port, "faxdetect: stopping detection (time ran out) ...\n");
               tmp->faxdetect = 0;
               return &tmp->frame;
            }
         }
      } else {
         chan_misdn_log(5, tmp->bc->port, "faxdetect: detecting ... (no timeout)\n");
         return process_ast_dsp(tmp, &tmp->frame);
      }
   } else {
      if (tmp->ast_dsp) {
         return process_ast_dsp(tmp, &tmp->frame);
      } else {
         return &tmp->frame;
      }
   }
}
static struct ast_channel* misdn_request ( const char *  type,
int  format,
void *  data,
int *  cause 
) [static, read]

Definition at line 3423 of file chan_misdn.c.

References chan_list::ast, ast_copy_string(), ast_free, ast_log(), AST_STATE_RESERVED, ast_strdupa, ast_strlen_zero(), chan_list::bc, BUFFERSIZE, chan_misdn_log(), misdn_bchannel::channel, robin_list::channel, cl_queue_chan(), misdn_bchannel::dec, ext, get_robin_position(), init_chan_list(), LOG_ERROR, LOG_WARNING, METHOD_ROUND_ROBIN, METHOD_STANDARD_DEC, misdn_cfg_get(), misdn_cfg_get_next_port(), misdn_cfg_get_next_port_spin(), MISDN_CFG_GROUPNAME, misdn_cfg_is_group_method(), MISDN_CFG_PMP_L1_CHECK, misdn_lib_get_free_bc(), misdn_lib_get_maxchans(), misdn_lib_port_up(), misdn_new(), chan_list::need_hangup, ORG_AST, misdn_bchannel::port, robin_list::port, read_config(), and strsep().

{
   struct ast_channel *tmp = NULL;
   char group[BUFFERSIZE + 1] = "";
   char dial_str[128];
   char *buf2 = ast_strdupa(data);
   char *ext;
   char *port_str;
   char *p = NULL;
   int channel = 0;
   int port = 0;
   struct misdn_bchannel *newbc = NULL;
   int dec = 0;
   struct chan_list *cl;

   snprintf(dial_str, sizeof(dial_str), "%s/%s", misdn_type, (char *) data);

   /*
    * data is ---v
    * Dial(mISDN/g:group_name[/extension[/options]])
    * Dial(mISDN/port[:preselected_channel][/extension[/options]])
    *
    * The dial extension could be empty if you are using MISDN_KEYPAD
    * to control ISDN provider features.
    */
   port_str = strsep(&buf2, "/");
   if (!ast_strlen_zero(port_str)) {
      if (port_str[0] == 'g' && port_str[1] == ':' ) {
         /* We make a group call lets checkout which ports are in my group */
         port_str += 2;
         ast_copy_string(group, port_str, sizeof(group));
         chan_misdn_log(2, 0, " --> Group Call group: %s\n", group);
      } else if ((p = strchr(port_str, ':'))) {
         /* we have a preselected channel */
         *p = 0;
         channel = atoi(++p);
         port = atoi(port_str);
         chan_misdn_log(2, port, " --> Call on preselected Channel (%d).\n", channel);
      } else {
         port = atoi(port_str);
      }
   } else {
      ast_log(LOG_WARNING, " --> ! IND : Dial(%s) WITHOUT Port or Group, check extensions.conf\n", dial_str);
      return NULL;
   }

   ext = strsep(&buf2, "/");
   if (!ext) {
      ext = "";
   }

   if (misdn_cfg_is_group_method(group, METHOD_STANDARD_DEC)) {
      chan_misdn_log(4, port, " --> STARTING STANDARD DEC...\n");
      dec = 1;
   }

   if (!ast_strlen_zero(group)) {
      char cfg_group[BUFFERSIZE + 1];
      struct robin_list *rr = NULL;

      /* Group dial */

      if (misdn_cfg_is_group_method(group, METHOD_ROUND_ROBIN)) {
         chan_misdn_log(4, port, " --> STARTING ROUND ROBIN...\n");
         rr = get_robin_position(group);
      }

      if (rr) {
         int robin_channel = rr->channel;
         int port_start;
         int next_chan = 1;

         do {
            port_start = 0;
            for (port = misdn_cfg_get_next_port_spin(rr->port); port > 0 && port != port_start;
                port = misdn_cfg_get_next_port_spin(port)) {

               if (!port_start) {
                  port_start = port;
               }

               if (port >= port_start) {
                  next_chan = 1;
               }
               
               if (port <= port_start && next_chan) {
                  int maxbchans=misdn_lib_get_maxchans(port);
                  if (++robin_channel >= maxbchans) {
                     robin_channel = 1;
                  }
                  next_chan = 0;
               }

               misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));

               if (!strcasecmp(cfg_group, group)) {
                  int port_up;
                  int check;
                  misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
                  port_up = misdn_lib_port_up(port, check);

                  if (check && !port_up) {
                     chan_misdn_log(1, port, "L1 is not Up on this Port\n");
                  }
                  
                  if (check && port_up < 0) {
                     ast_log(LOG_WARNING, "This port (%d) is blocked\n", port);
                  }

                  if (port_up > 0)  {
                     newbc = misdn_lib_get_free_bc(port, robin_channel, 0, 0);
                     if (newbc) {
                        chan_misdn_log(4, port, " Success! Found port:%d channel:%d\n", newbc->port, newbc->channel);
                        if (port_up) {
                           chan_misdn_log(4, port, "portup:%d\n",  port_up);
                        }
                        rr->port = newbc->port;
                        rr->channel = newbc->channel;
                        break;
                     }
                  }
               }
            }
         } while (!newbc && robin_channel != rr->channel);
      } else {    
         for (port = misdn_cfg_get_next_port(0); port > 0;
             port = misdn_cfg_get_next_port(port)) {

            misdn_cfg_get(port, MISDN_CFG_GROUPNAME, cfg_group, sizeof(cfg_group));

            chan_misdn_log(3, port, "Group [%s] Port [%d]\n", group, port);
            if (!strcasecmp(cfg_group, group)) {
               int port_up;
               int check;
               misdn_cfg_get(port, MISDN_CFG_PMP_L1_CHECK, &check, sizeof(check));
               port_up = misdn_lib_port_up(port, check);

               chan_misdn_log(4, port, "portup:%d\n", port_up);

               if (port_up > 0) {
                  if ((newbc = misdn_lib_get_free_bc(port, 0, 0, dec))) {
                     break;
                  }
               }
            }
         }
      }
      
      /* Group dial failed ?*/
      if (!newbc) {
         ast_log(LOG_WARNING, 
               "Could not Dial out on group '%s'.\n"
               "\tEither the L2 and L1 on all of these ports where DOWN (see 'show application misdn_check_l2l1')\n"
               "\tOr there was no free channel on none of the ports\n\n"
               , group);
         return NULL;
      }
   } else {
      /* 'Normal' Port dial * Port dial */
      if (channel) {
         chan_misdn_log(1, port, " --> preselected_channel: %d\n", channel);
      }
      newbc = misdn_lib_get_free_bc(port, channel, 0, dec);

      if (!newbc) {
         ast_log(LOG_WARNING, "Could not create channel on port:%d with extensions:%s\n", port, ext);
         return NULL;
      }
   }
   

   /* create ast_channel and link all the objects together */
   cl = init_chan_list(ORG_AST);
   if (!cl) {
      ast_log(LOG_ERROR, "Could not create call record for Dial(%s)\n", dial_str);
      return NULL;
   }
   cl->bc = newbc;
   
   tmp = misdn_new(cl, AST_STATE_RESERVED, ext, NULL, format, port, channel);
   if (!tmp) {
      ast_free(cl);
      ast_log(LOG_ERROR, "Could not create Asterisk object\n");
      return NULL;
   }

   cl->ast = tmp;
   
   /* register chan in local list */
   cl_queue_chan(&cl_te, cl);
   
   /* fill in the config into the objects */
   read_config(cl, ORG_AST);

   /* important */
   cl->need_hangup = 0;
   
   return tmp;
}
static int misdn_send_text ( struct ast_channel chan,
const char *  text 
) [static]

Definition at line 3624 of file chan_misdn.c.

References ast_copy_string(), ast_log(), chan_list::bc, misdn_bchannel::display, EVENT_INFORMATION, LOG_WARNING, misdn_lib_send_event(), and ast_channel::tech_pvt.

{
   struct chan_list *tmp = chan->tech_pvt;
   
   if (tmp && tmp->bc) {
      ast_copy_string(tmp->bc->display, text, sizeof(tmp->bc->display));
      misdn_lib_send_event(tmp->bc, EVENT_INFORMATION);
   } else {
      ast_log(LOG_WARNING, "No chan_list but send_text request?\n");
      return -1;
   }
   
   return 0;
}
static int misdn_set_opt_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 5732 of file chan_misdn.c.

References ast_copy_string(), chan_list::ast_dsp, ast_dsp_new(), ast_dsp_set_features(), ast_log(), ast_strdupa, ast_strlen_zero(), chan_list::bc, misdn_bchannel::capability, chan_misdn_log(), config_jitterbuffer(), misdn_bchannel::crypt_key, misdn_bchannel::display, chan_list::dsp, DSP_FEATURE_DIGIT_DETECT, DSP_FEATURE_FAX_DETECT, misdn_bchannel::ec_deftaps, misdn_bchannel::ec_enable, chan_list::faxdetect, chan_list::faxdetect_timeout, misdn_bchannel::hdlc, chan_list::ignore_dtmf, INFO_CAPABILITY_DIGITAL_UNRESTRICTED, chan_list::jb_len, chan_list::jb_upper_threshold, keys, LOG_WARNING, MISDN_ASTERISK_TECH_PVT, MISDN_CFG_FAXDETECT_TIMEOUT, misdn_cfg_get(), MISDN_GEN_CRYPT_KEYS, misdn_bchannel::nodsp, misdn_bchannel::nojitter, misdn_bchannel::orig, chan_list::originator, parse(), misdn_bchannel::port, misdn_bchannel::pres, misdn_bchannel::rxgain, misdn_bchannel::send_dtmf, strsep(), ast_channel::tech, misdn_bchannel::txgain, and ast_channel_tech::type.

Referenced by load_module(), and misdn_call().

{
   struct chan_list *ch = MISDN_ASTERISK_TECH_PVT(chan);
   char *tok, *tokb, *parse;
   int  keyidx = 0;
   int rxgain = 0;
   int txgain = 0;
   int change_jitter = 0;

   if (strcasecmp(chan->tech->type, "mISDN")) {
      ast_log(LOG_WARNING, "misdn_set_opt makes only sense with chan_misdn channels!\n");
      return -1;
   }
   
   if (ast_strlen_zero((char *)data)) {
      ast_log(LOG_WARNING, "misdn_set_opt Requires arguments\n");
      return -1;
   }

   parse = ast_strdupa(data);
   for (tok = strtok_r(parse, ":", &tokb);
        tok;
        tok = strtok_r(NULL, ":", &tokb) ) {
      int neglect = 0;

      if (tok[0] == '!' ) {
         neglect = 1;
         tok++;
      }
      
      switch(tok[0]) {
         
      case 'd' :
         ast_copy_string(ch->bc->display, ++tok, sizeof(ch->bc->display));
         chan_misdn_log(1, ch->bc->port, "SETOPT: Display:%s\n", ch->bc->display);
         break;
         
      case 'n':
         chan_misdn_log(1, ch->bc->port, "SETOPT: No DSP\n");
         ch->bc->nodsp = 1;
         break;

      case 'j':
         chan_misdn_log(1, ch->bc->port, "SETOPT: jitter\n");
         tok++;
         change_jitter = 1;

         switch ( tok[0] ) {
         case 'b':
            ch->jb_len = atoi(++tok);
            chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d\n", ch->jb_len);
            break;
         case 't' :
            ch->jb_upper_threshold = atoi(++tok);
            chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d\n", ch->jb_upper_threshold);
            break;
         case 'n':
            ch->bc->nojitter = 1;
            chan_misdn_log(1, ch->bc->port, " --> nojitter\n");
            break;
         default:
            ch->jb_len = 4000;
            ch->jb_upper_threshold = 0;
            chan_misdn_log(1, ch->bc->port, " --> buffer_len:%d (default)\n", ch->jb_len);
            chan_misdn_log(1, ch->bc->port, " --> upper_threshold:%d (default)\n", ch->jb_upper_threshold);
         }
         break;
      case 'v':
         tok++;

         switch (tok[0]) {
         case 'r' :
            rxgain = atoi(++tok);
            if (rxgain < -8) {
               rxgain = -8;
            }
            if (rxgain > 8) {
               rxgain = 8;
            }
            ch->bc->rxgain = rxgain;
            chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", rxgain);
            break;
         case 't':
            txgain = atoi(++tok);
            if (txgain < -8) {
               txgain = -8;
            }
            if (txgain > 8) {
               txgain = 8;
            }
            ch->bc->txgain = txgain;
            chan_misdn_log(1, ch->bc->port, "SETOPT: Volume:%d\n", txgain);
            break;
         }
         break;
      
      case 'c':
         keyidx = atoi(++tok);
         {
            char keys[4096];
            char *key = NULL, *tmp = keys;
            int i;
            misdn_cfg_get(0, MISDN_GEN_CRYPT_KEYS, keys, sizeof(keys));

            for (i = 0; i < keyidx; i++) {
               key = strsep(&tmp, ",");
            }

            if (key) {
               ast_copy_string(ch->bc->crypt_key, key, sizeof(ch->bc->crypt_key));
            }

            chan_misdn_log(0, ch->bc->port, "SETOPT: crypt with key:%s\n", ch->bc->crypt_key);
            break;
         }
      case 'e':
         chan_misdn_log(1, ch->bc->port, "SETOPT: EchoCancel\n");
         
         if (neglect) {
            chan_misdn_log(1, ch->bc->port, " --> disabled\n");
#ifdef MISDN_1_2
            *ch->bc->pipeline = 0;
#else
            ch->bc->ec_enable = 0;
#endif
         } else {
#ifdef MISDN_1_2
            update_pipeline_config(ch->bc);
#else
            ch->bc->ec_enable = 1;
            ch->bc->orig = ch->originator;
            tok++;
            if (*tok) {
               ch->bc->ec_deftaps = atoi(tok);
            }
#endif
         }
         
         break;
      case 'h':
         chan_misdn_log(1, ch->bc->port, "SETOPT: Digital\n");
         
         if (strlen(tok) > 1 && tok[1] == '1') {
            chan_misdn_log(1, ch->bc->port, "SETOPT: HDLC \n");
            if (!ch->bc->hdlc) {
               ch->bc->hdlc = 1;
            }
         }
         ch->bc->capability = INFO_CAPABILITY_DIGITAL_UNRESTRICTED;
         break;
            
      case 's':
         chan_misdn_log(1, ch->bc->port, "SETOPT: Send DTMF\n");
         ch->bc->send_dtmf = 1;
         break;
         
      case 'f':
         chan_misdn_log(1, ch->bc->port, "SETOPT: Faxdetect\n");
         ch->faxdetect = 1;
         misdn_cfg_get(ch->bc->port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
         break;

      case 'a':
         chan_misdn_log(1, ch->bc->port, "SETOPT: AST_DSP (for DTMF)\n");
         ch->ast_dsp = 1;
         break;

      case 'p':
         chan_misdn_log(1, ch->bc->port, "SETOPT: callerpres: %s\n", &tok[1]);
         /* CRICH: callingpres!!! */
         if (strstr(tok, "allowed")) {
            ch->bc->pres = 0;
         } else if (strstr(tok, "restricted")) {
            ch->bc->pres = 1;
         } else if (strstr(tok, "not_screened")) {
            chan_misdn_log(0, ch->bc->port, "SETOPT: callerpres: not_screened is deprecated\n");
            ch->bc->pres = 1;
         }
         break;
      case 'i' :
         chan_misdn_log(1, ch->bc->port, "Ignoring dtmf tones, just use them inband\n");
         ch->ignore_dtmf=1;
         break;
      default:
         break;
      }
   }

   if (change_jitter) {
      config_jitterbuffer(ch);
   }

   if (ch->faxdetect || ch->ast_dsp) {
      if (!ch->dsp) {
         ch->dsp = ast_dsp_new();
      }
      if (ch->dsp) {
         ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT | DSP_FEATURE_FAX_DETECT);
      }
   }

   if (ch->ast_dsp) {
      chan_misdn_log(1, ch->bc->port, "SETOPT: with AST_DSP we deactivate mISDN_dsp\n");
      ch->bc->nodsp = 1;
   }
   
   return 0;
}
static int misdn_tasks_add ( int  timeout,
ast_sched_cb  callback,
const void *  data 
) [static]

Definition at line 823 of file chan_misdn.c.

References _misdn_tasks_add_variable().

Referenced by load_module().

{
   return _misdn_tasks_add_variable(timeout, callback, data, 0);
}
static int misdn_tasks_add_variable ( int  timeout,
ast_sched_cb  callback,
const void *  data 
) [static]

Definition at line 828 of file chan_misdn.c.

References _misdn_tasks_add_variable().

Referenced by cb_events().

{
   return _misdn_tasks_add_variable(timeout, callback, data, 1);
}
static void misdn_tasks_destroy ( void  ) [static]

Definition at line 793 of file chan_misdn.c.

References cb_log, chan_misdn_log(), and sched_context_destroy().

Referenced by unload_module().

{
   if (misdn_tasks) {
      chan_misdn_log(4, 0, "Killing misdn_tasks thread\n");
      if ( pthread_cancel(misdn_tasks_thread) == 0 ) {
         cb_log(4, 0, "Joining misdn_tasks thread\n");
         pthread_join(misdn_tasks_thread, NULL);
      }
      sched_context_destroy(misdn_tasks);
   }
}
static void misdn_tasks_init ( void  ) [static]

Definition at line 774 of file chan_misdn.c.

References chan_misdn_log(), misdn_tasks_thread_func(), pthread_create, and sched_context_create().

Referenced by _misdn_tasks_add_variable().

{
   sem_t blocker;
   int i = 5;

   if (sem_init(&blocker, 0, 0)) {
      perror("chan_misdn: Failed to initialize semaphore!");
      exit(1);
   }

   chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
   
   misdn_tasks = sched_context_create();
   pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, &blocker);

   while (sem_wait(&blocker) && --i);
   sem_destroy(&blocker);
}
static void misdn_tasks_remove ( int  task_id) [static]

Definition at line 833 of file chan_misdn.c.

References AST_SCHED_DEL.

Referenced by release_chan(), and release_chan_early().

{
   AST_SCHED_DEL(misdn_tasks, task_id);
}
static void* misdn_tasks_thread_func ( void *  data) [static]

Definition at line 748 of file chan_misdn.c.

References ast_sched_runq(), ast_sched_wait(), chan_misdn_log(), and sighandler().

Referenced by misdn_tasks_init().

{
   int wait;
   struct sigaction sa;

   sa.sa_handler = sighandler;
   sa.sa_flags = SA_NODEFER;
   sigemptyset(&sa.sa_mask);
   sigaddset(&sa.sa_mask, SIGUSR1);
   sigaction(SIGUSR1, &sa, NULL);
   
   sem_post((sem_t *)data);

   while (1) {
      wait = ast_sched_wait(misdn_tasks);
      if (wait < 0) {
         wait = 8000;
      }
      if (poll(NULL, 0, wait) < 0) {
         chan_misdn_log(4, 0, "Waking up misdn_tasks thread\n");
      }
      ast_sched_runq(misdn_tasks);
   }
   return NULL;
}
static void misdn_tasks_wakeup ( void  ) [inline, static]

Definition at line 805 of file chan_misdn.c.

Referenced by _misdn_tasks_add_variable().

{
   pthread_kill(misdn_tasks_thread, SIGUSR1);
}
static int misdn_write ( struct ast_channel ast,
struct ast_frame frame 
) [static]

Definition at line 3119 of file chan_misdn.c.

References misdn_bchannel::active, misdn_bchannel::addr, ast_debug, ast_log(), chan_list::bc, misdn_bchannel::bc_state, BCHAN_ACTIVATED, BCHAN_BRIDGED, misdn_bchannel::capability, cb_log, chan_misdn_log(), ast_channel::cid, ast_callerid::cid_num, ast_frame::data, chan_list::dropped_frame_cnt, ast_channel::exten, chan_list::hold, chan_list::jb, misdn_bchannel::l3_id, LOG_WARNING, MISDN_ASTERISK_TECH_PVT, misdn_cap_is_speech(), misdn_get_ch_state(), MISDN_HOLD_IDLE, misdn_jb_fill(), misdn_lib_tone_generator_start(), misdn_lib_tx2misdn_frm(), misdn_bchannel::nojitter, chan_list::notxtone, misdn_bchannel::port, ast_frame::ptr, ast_frame::samples, ast_frame::src, hold_info::state, ast_frame::subclass, and chan_list::ts.

{
   struct chan_list *ch;
   int i  = 0;
   
   if (!ast || !(ch = MISDN_ASTERISK_TECH_PVT(ast))) {
      return -1;
   }

   if (ch->hold.state != MISDN_HOLD_IDLE) {
      chan_misdn_log(7, 0, "misdn_write: Returning because hold active\n");
      return 0;
   }
   
   if (!ch->bc ) {
      ast_log(LOG_WARNING, "private but no bc\n");
      return -1;
   }
   
   if (ch->notxtone) {
      chan_misdn_log(7, ch->bc->port, "misdn_write: Returning because notxtone\n");
      return 0;
   }


   if (!frame->subclass) {
      chan_misdn_log(4, ch->bc->port, "misdn_write: * prods us\n");
      return 0;
   }
   
   if (!(frame->subclass & prefformat)) {
      chan_misdn_log(-1, ch->bc->port, "Got Unsupported Frame with Format:%d\n", frame->subclass);
      return 0;
   }
   

   if (!frame->samples ) {
      chan_misdn_log(4, ch->bc->port, "misdn_write: zero write\n");
      
      if (!strcmp(frame->src,"ast_prod")) {
         chan_misdn_log(1, ch->bc->port, "misdn_write: state (%s) prodded.\n", misdn_get_ch_state(ch));

         if (ch->ts) {
            chan_misdn_log(4, ch->bc->port, "Starting Playtones\n");
            misdn_lib_tone_generator_start(ch->bc);
         }
         return 0;
      }

      return -1;
   }

   if (!ch->bc->addr) {
      chan_misdn_log(8, ch->bc->port, "misdn_write: no addr for bc dropping:%d\n", frame->samples);
      return 0;
   }
   
#ifdef MISDN_DEBUG
   {
      int i, max = 5 > frame->samples ? frame->samples : 5;

      ast_debug(1, "write2mISDN %p %d bytes: ", p, frame->samples);

      for (i = 0; i < max; i++) {
         ast_debug(1, "%2.2x ", ((char *) frame->data.ptr)[i]);
      }
   }
#endif

   switch (ch->bc->bc_state) {
   case BCHAN_ACTIVATED:
   case BCHAN_BRIDGED:
      break;
   default:
      if (!ch->dropped_frame_cnt) {
         chan_misdn_log(5, ch->bc->port, "BC not active (nor bridged) dropping: %d frames addr:%x exten:%s cid:%s ch->state:%s bc_state:%d l3id:%x\n", frame->samples, ch->bc->addr, ast->exten, ast->cid.cid_num, misdn_get_ch_state( ch), ch->bc->bc_state, ch->bc->l3_id);
      }
      
      if (++ch->dropped_frame_cnt > 100) {
         ch->dropped_frame_cnt = 0;
         chan_misdn_log(5, ch->bc->port, "BC not active (nor bridged) dropping: %d frames addr:%x  dropped > 100 frames!\n", frame->samples, ch->bc->addr);
      }

      return 0;
   }

   chan_misdn_log(9, ch->bc->port, "Sending :%d bytes to MISDN\n", frame->samples);
   if (!ch->bc->nojitter && misdn_cap_is_speech(ch->bc->capability)) {
      /* Buffered Transmit (triggered by read from isdn side)*/
      if (misdn_jb_fill(ch->jb, frame->data.ptr, frame->samples) < 0) {
         if (ch->bc->active) {
            cb_log(0, ch->bc->port, "Misdn Jitterbuffer Overflow.\n");
         }
      }
      
   } else {
      /*transmit without jitterbuffer*/
      i = misdn_lib_tx2misdn_frm(ch->bc, frame->data.ptr, frame->samples);
   }

   return 0;
}
static int pbx_start_chan ( struct chan_list ch) [static]

Channel Queue End

Definition at line 3920 of file chan_misdn.c.

References chan_list::ast, ast_pbx_start(), and chan_list::need_hangup.

Referenced by cb_events(), do_immediate_setup(), misdn_overlap_dial_task(), and start_pbx().

{
   int ret = ast_pbx_start(ch->ast);   

   ch->need_hangup = (ret >= 0) ? 0 : 1;

   return ret;
}
static void print_bc_info ( int  fd,
struct chan_list help,
struct misdn_bchannel bc 
) [static]

Definition at line 1375 of file chan_misdn.c.

References misdn_bchannel::active, misdn_bchannel::addr, chan_list::addr, chan_list::ast, ast_cli(), misdn_bchannel::bc_state, bc_state2str(), bearer2str(), misdn_bchannel::capability, misdn_bchannel::channel, ast_channel::cid, ast_callerid::cid_num, ast_channel::context, misdn_bchannel::display, misdn_bchannel::ec_enable, ast_channel::exten, misdn_bchannel::holded, misdn_bchannel::l3_id, chan_list::l3id, misdn_get_ch_state(), ast_channel::name, chan_list::norxtone, chan_list::notxtone, misdn_bchannel::nt, ORG_AST, chan_list::originator, misdn_bchannel::pid, misdn_bchannel::port, and misdn_bchannel::rad.

Referenced by handle_cli_misdn_show_channel(), and handle_cli_misdn_show_channels().

{
   struct ast_channel *ast = help->ast;
   ast_cli(fd,
      "* Pid:%d Prt:%d Ch:%d Mode:%s Org:%s dad:%s oad:%s rad:%s ctx:%s state:%s\n",

      bc->pid, bc->port, bc->channel,
      bc->nt ? "NT" : "TE",
      help->originator == ORG_AST ? "*" : "I",
      ast ? ast->exten : NULL,
      ast ? ast->cid.cid_num : NULL,
      bc->rad,
      ast ? ast->context : NULL,
      misdn_get_ch_state(help)
      );
   if (misdn_debug[bc->port] > 0) {
      ast_cli(fd,
         "  --> astname: %s\n"
         "  --> ch_l3id: %x\n"
         "  --> ch_addr: %x\n"
         "  --> bc_addr: %x\n"
         "  --> bc_l3id: %x\n"
         "  --> display: %s\n"
         "  --> activated: %d\n"
         "  --> state: %s\n"
         "  --> capability: %s\n"
#ifdef MISDN_1_2
         "  --> pipeline: %s\n"
#else
         "  --> echo_cancel: %d\n"
#endif
         "  --> notone : rx %d tx:%d\n"
         "  --> bc_hold: %d\n",
         help->ast->name,
         help->l3id,
         help->addr,
         bc->addr,
         bc ? bc->l3_id : -1,
         bc->display,
         
         bc->active,
         bc_state2str(bc->bc_state),
         bearer2str(bc->capability),
#ifdef MISDN_1_2
         bc->pipeline,
#else
         bc->ec_enable,
#endif

         help->norxtone, help->notxtone,
         bc->holded
         );
   }
}
static void print_bearer ( struct misdn_bchannel bc) [static]

Definition at line 669 of file chan_misdn.c.

References bearer2str(), misdn_bchannel::capability, chan_misdn_log(), INFO_CODEC_ALAW, INFO_CODEC_ULAW, misdn_bchannel::law, and misdn_bchannel::port.

Referenced by cb_events().

{
   chan_misdn_log(2, bc->port, " --> Bearer: %s\n", bearer2str(bc->capability));
   
   switch(bc->law) {
   case INFO_CODEC_ALAW:
      chan_misdn_log(2, bc->port, " --> Codec: Alaw\n");
      break;
   case INFO_CODEC_ULAW:
      chan_misdn_log(2, bc->port, " --> Codec: Ulaw\n");
      break;
   }
}
static void print_facility ( struct FacParm *  fac,
struct misdn_bchannel bc 
) [static]

Definition at line 616 of file chan_misdn.c.

References chan_misdn_log(), and misdn_bchannel::port.

Referenced by cb_events().

{
   switch (fac->Function) {
#ifdef HAVE_MISDN_FAC_RESULT
   case Fac_RESULT:
      chan_misdn_log(0, bc->port, " --> Received RESULT Operation\n");
      break;
#endif
#ifdef HAVE_MISDN_FAC_ERROR
   case Fac_ERROR:
      chan_misdn_log(0, bc->port, " --> Received Error Operation\n");
      chan_misdn_log(0, bc->port, " --> Value:%d Error:%s\n", fac->u.ERROR.errorValue, fac->u.ERROR.error);
      break;
#endif
   case Fac_CD:
      chan_misdn_log(1, bc->port, " --> calldeflect to: %s, presentable: %s\n", fac->u.CDeflection.DeflectedToNumber,
         fac->u.CDeflection.PresentationAllowed ? "yes" : "no");
      break;
   case Fac_AOCDCurrency:
      if (fac->u.AOCDcur.chargeNotAvailable) {
         chan_misdn_log(1, bc->port, " --> AOCD currency: charge not available\n");
      } else if (fac->u.AOCDcur.freeOfCharge) {
         chan_misdn_log(1, bc->port, " --> AOCD currency: free of charge\n");
      } else if (fac->u.AOCDchu.billingId >= 0) {
         chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s billingId:%d\n",
            fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
            (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDcur.billingId);
      } else {
         chan_misdn_log(1, bc->port, " --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s\n",
            fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
            (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total");
      }
      break;
   case Fac_AOCDChargingUnit:
      if (fac->u.AOCDchu.chargeNotAvailable) {
         chan_misdn_log(1, bc->port, " --> AOCD charging unit: charge not available\n");
      } else if (fac->u.AOCDchu.freeOfCharge) {
         chan_misdn_log(1, bc->port, " --> AOCD charging unit: free of charge\n");
      } else if (fac->u.AOCDchu.billingId >= 0) {
         chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d\n",
            fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDchu.billingId);
      } else {
         chan_misdn_log(1, bc->port, " --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n",
            fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total");
      }
      break;
   case Fac_None:
   default:
      chan_misdn_log(1, bc->port, " --> unknown facility\n");
      break;
   }
}
static struct ast_frame * process_ast_dsp ( struct chan_list tmp,
struct ast_frame frame 
) [static, read]

Definition at line 2961 of file chan_misdn.c.

References chan_list::ast, ast_async_goto(), ast_debug, chan_list::ast_dsp, ast_dsp_process(), ast_exists_extension(), AST_FRAME_DTMF, ast_log(), ast_strlen_zero(), ast_verb, chan_list::bc, BUFFERSIZE, chan_misdn_log(), ast_channel::cid, ast_callerid::cid_num, ast_channel::context, context, chan_list::dsp, misdn_bchannel::ec_enable, ast_channel::exten, f, chan_list::faxdetect, chan_list::faxhandled, ast_frame::frametype, isdn_lib_stop_dtmf(), isdn_lib_update_ec(), isdn_lib_update_rxgain(), isdn_lib_update_txgain(), LOG_NOTICE, LOG_WARNING, ast_channel::macrocontext, MISDN_CFG_FAXDETECT_CONTEXT, misdn_cfg_get(), ast_channel::name, pbx_builtin_setvar_helper(), misdn_bchannel::port, misdn_bchannel::rxgain, ast_frame::subclass, and misdn_bchannel::txgain.

Referenced by misdn_read().

{
   struct ast_frame *f;
 
   if (tmp->dsp) {
      f = ast_dsp_process(tmp->ast, tmp->dsp, frame);
   } else {
      chan_misdn_log(0, tmp->bc->port, "No DSP-Path found\n");
      return NULL;
   }

   if (!f || (f->frametype != AST_FRAME_DTMF)) {
      return f;
   }
 
   ast_debug(1, "Detected inband DTMF digit: %c\n", f->subclass);
 
   if (tmp->faxdetect && (f->subclass == 'f')) {
      /* Fax tone -- Handle and return NULL */
      if (!tmp->faxhandled) {
         struct ast_channel *ast = tmp->ast;
         tmp->faxhandled++;
         chan_misdn_log(0, tmp->bc->port, "Fax detected, preparing %s for fax transfer.\n", ast->name);
         tmp->bc->rxgain = 0;
         isdn_lib_update_rxgain(tmp->bc);
         tmp->bc->txgain = 0;
         isdn_lib_update_txgain(tmp->bc);
#ifdef MISDN_1_2
         *tmp->bc->pipeline = 0;
#else
         tmp->bc->ec_enable = 0;
#endif
         isdn_lib_update_ec(tmp->bc);
         isdn_lib_stop_dtmf(tmp->bc);
         switch (tmp->faxdetect) {
         case 1:
            if (strcmp(ast->exten, "fax")) {
               char *context;
               char context_tmp[BUFFERSIZE];
               misdn_cfg_get(tmp->bc->port, MISDN_CFG_FAXDETECT_CONTEXT, &context_tmp, sizeof(context_tmp));
               context = ast_strlen_zero(context_tmp) ? (ast_strlen_zero(ast->macrocontext) ? ast->context : ast->macrocontext) : context_tmp;
               if (ast_exists_extension(ast, context, "fax", 1, ast->cid.cid_num)) {
                  ast_verb(3, "Redirecting %s to fax extension (context:%s)\n", ast->name, context);
                  /* Save the DID/DNIS when we transfer the fax call to a "fax" extension */
                  pbx_builtin_setvar_helper(ast,"FAXEXTEN",ast->exten);
                  if (ast_async_goto(ast, context, "fax", 1)) {
                     ast_log(LOG_WARNING, "Failed to async goto '%s' into fax of '%s'\n", ast->name, context);
                  }
               } else {
                  ast_log(LOG_NOTICE, "Fax detected, but no fax extension ctx:%s exten:%s\n", context, ast->exten);
               }
            } else {
               ast_debug(1, "Already in a fax extension, not redirecting\n");
            }
            break;
         case 2:
            ast_verb(3, "Not redirecting %s to fax extension, nojump is set.\n", ast->name);
            break;
         }
      } else {
         ast_debug(1, "Fax already handled\n");
      }
   }
   
   if (tmp->ast_dsp && (f->subclass != 'f')) {
      chan_misdn_log(2, tmp->bc->port, " --> * SEND: DTMF (AST_DSP) :%c\n", f->subclass);
   }

   return f;
}
static int read_config ( struct chan_list ch,
int  orig 
) [static]

Definition at line 2185 of file chan_misdn.c.

References chan_list::allowed_bearers, misdn_bchannel::AOCDtype, chan_list::ast, ast_copy_string(), chan_list::ast_dsp, ast_dsp_new(), ast_dsp_set_features(), ast_free, ast_log(), ast_mutex_init(), ast_print_group(), ast_set_callerid(), ast_strdup, ast_string_field_set, ast_strlen_zero(), chan_list::bc, buf, BUFFERSIZE, ast_channel::callgroup, misdn_bchannel::capability, chan_misdn_log(), ast_channel::cid, ast_callerid::cid_rdnis, config_jitterbuffer(), ast_channel::context, chan_list::context, misdn_bchannel::cpnnumplan, misdn_bchannel::dad, debug_numplan(), misdn_bchannel::dnumplan, chan_list::dsp, DSP_FEATURE_DIGIT_DETECT, DSP_FEATURE_FAX_DETECT, misdn_bchannel::early_bconnect, ast_channel::exten, chan_list::far_alerting, chan_list::faxdetect, chan_list::faxdetect_timeout, misdn_bchannel::hdlc, chan_list::ignore_dtmf, chan_list::incoming_early_audio, INFO_CAPABILITY_DIGITAL_RESTRICTED, INFO_CAPABILITY_DIGITAL_UNRESTRICTED, chan_list::jb_len, chan_list::jb_upper_threshold, misdn_bchannel::keypad, language, LOG_WARNING, MISDN_CFG_ALLOWED_BEARERS, MISDN_CFG_ASTDTMF, MISDN_CFG_CALLERID, MISDN_CFG_CALLGROUP, MISDN_CFG_CONTEXT, MISDN_CFG_CPNDIALPLAN, MISDN_CFG_DIALPLAN, MISDN_CFG_EARLY_BCONNECT, MISDN_CFG_FAR_ALERTING, MISDN_CFG_FAXDETECT, MISDN_CFG_FAXDETECT_TIMEOUT, misdn_cfg_get(), MISDN_CFG_HDLC, MISDN_CFG_INCOMING_EARLY_AUDIO, MISDN_CFG_INTERNATPREFIX, MISDN_CFG_JITTERBUFFER, MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, MISDN_CFG_LANGUAGE, MISDN_CFG_LOCALDIALPLAN, MISDN_CFG_MUSICCLASS, MISDN_CFG_NATPREFIX, MISDN_CFG_NEED_MORE_INFOS, MISDN_CFG_NOAUTORESPOND_ON_SETUP, MISDN_CFG_NTTIMEOUT, MISDN_CFG_OVERLAP_DIAL, MISDN_CFG_PICKUPGROUP, MISDN_CFG_RXGAIN, MISDN_CFG_SENDDTMF, MISDN_CFG_TE_CHOOSE_CHANNEL, MISDN_CFG_TXGAIN, chan_list::mohinterpret, misdn_bchannel::need_more_infos, chan_list::noautorespond_on_setup, chan_list::nttimeout, NUMPLAN_INTERNATIONAL, NUMPLAN_NATIONAL, misdn_bchannel::oad, misdn_bchannel::onumplan, ORG_AST, misdn_bchannel::orig_dad, chan_list::overlap_dial, chan_list::overlap_dial_task, chan_list::overlap_tv_lock, ast_channel::pickupgroup, misdn_bchannel::port, prefix, misdn_bchannel::rad, misdn_bchannel::rxgain, misdn_bchannel::send_dtmf, misdn_bchannel::te_choose_channel, misdn_bchannel::txgain, and update_ec_config().

Referenced by cb_events(), and misdn_request().

{
   struct ast_channel *ast;
   struct misdn_bchannel *bc;
   int port;
   int hdlc = 0;
   char lang[BUFFERSIZE + 1];
   char faxdetect[BUFFERSIZE + 1];
   char buf[256];
   char buf2[256];
   ast_group_t pg;
   ast_group_t cg;

   if (!ch) {
      ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
      return -1;
   }

   ast = ch->ast;
   bc = ch->bc;
   if (! ast || ! bc) {
      ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
      return -1;
   }
   
   port = bc->port;
   chan_misdn_log(1, port, "read_config: Getting Config\n");

   misdn_cfg_get(port, MISDN_CFG_LANGUAGE, lang, sizeof(lang));
   ast_string_field_set(ast, language, lang);

   misdn_cfg_get(port, MISDN_CFG_MUSICCLASS, ch->mohinterpret, sizeof(ch->mohinterpret));

   misdn_cfg_get(port, MISDN_CFG_TXGAIN, &bc->txgain, sizeof(bc->txgain));
   misdn_cfg_get(port, MISDN_CFG_RXGAIN, &bc->rxgain, sizeof(bc->rxgain));

   misdn_cfg_get(port, MISDN_CFG_INCOMING_EARLY_AUDIO, &ch->incoming_early_audio, sizeof(ch->incoming_early_audio));

   misdn_cfg_get(port, MISDN_CFG_SENDDTMF, &bc->send_dtmf, sizeof(bc->send_dtmf));

   misdn_cfg_get(port, MISDN_CFG_ASTDTMF, &ch->ast_dsp, sizeof(int));

   if (ch->ast_dsp) {
      ch->ignore_dtmf = 1;
   }

   misdn_cfg_get(port, MISDN_CFG_NEED_MORE_INFOS, &bc->need_more_infos, sizeof(bc->need_more_infos));
   misdn_cfg_get(port, MISDN_CFG_NTTIMEOUT, &ch->nttimeout, sizeof(ch->nttimeout));

   misdn_cfg_get(port, MISDN_CFG_NOAUTORESPOND_ON_SETUP, &ch->noautorespond_on_setup, sizeof(ch->noautorespond_on_setup));

   misdn_cfg_get(port, MISDN_CFG_FAR_ALERTING, &ch->far_alerting, sizeof(ch->far_alerting));

   misdn_cfg_get(port, MISDN_CFG_ALLOWED_BEARERS, &ch->allowed_bearers, sizeof(ch->allowed_bearers));

   misdn_cfg_get(port, MISDN_CFG_FAXDETECT, faxdetect, sizeof(faxdetect));

   misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(hdlc));

   if (hdlc) {
      switch (bc->capability) {
      case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
      case INFO_CAPABILITY_DIGITAL_RESTRICTED:
         chan_misdn_log(1, bc->port, " --> CONF HDLC\n");
         bc->hdlc = 1;
         break;
      }
      
   }
   /*Initialize new Jitterbuffer*/
   misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER, &ch->jb_len, sizeof(ch->jb_len));
   misdn_cfg_get(port, MISDN_CFG_JITTERBUFFER_UPPER_THRESHOLD, &ch->jb_upper_threshold, sizeof(ch->jb_upper_threshold));

   config_jitterbuffer(ch);

   misdn_cfg_get(bc->port, MISDN_CFG_CONTEXT, ch->context, sizeof(ch->context));

   ast_copy_string(ast->context, ch->context, sizeof(ast->context));

#ifdef MISDN_1_2
   update_pipeline_config(bc);
#else
   update_ec_config(bc);
#endif

   misdn_cfg_get(bc->port, MISDN_CFG_EARLY_BCONNECT, &bc->early_bconnect, sizeof(bc->early_bconnect));

   misdn_cfg_get(port, MISDN_CFG_PICKUPGROUP, &pg, sizeof(pg));
   misdn_cfg_get(port, MISDN_CFG_CALLGROUP, &cg, sizeof(cg));

   chan_misdn_log(5, port, " --> * CallGrp:%s PickupGrp:%s\n", ast_print_group(buf, sizeof(buf), cg), ast_print_group(buf2, sizeof(buf2), pg));
   ast->pickupgroup = pg;
   ast->callgroup = cg;
   
   if (orig == ORG_AST) {
      char callerid[BUFFERSIZE + 1];

      /* ORIGINATOR Asterisk (outgoing call) */

      misdn_cfg_get(port, MISDN_CFG_TE_CHOOSE_CHANNEL, &(bc->te_choose_channel), sizeof(bc->te_choose_channel));

      if (strstr(faxdetect, "outgoing") || strstr(faxdetect, "both")) {
         ch->faxdetect = strstr(faxdetect, "nojump") ? 2 : 1;
      }

      misdn_cfg_get(port, MISDN_CFG_CALLERID, callerid, sizeof(callerid));
      if (!ast_strlen_zero(callerid)) {
         chan_misdn_log(1, port, " --> * Setting Cid to %s\n", callerid);
         ast_copy_string(bc->oad, callerid, sizeof(bc->oad));
      }

      misdn_cfg_get(port, MISDN_CFG_DIALPLAN, &bc->dnumplan, sizeof(bc->dnumplan));
      misdn_cfg_get(port, MISDN_CFG_LOCALDIALPLAN, &bc->onumplan, sizeof(bc->onumplan));
      misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(bc->cpnnumplan));
      debug_numplan(port, bc->dnumplan, "TON");
      debug_numplan(port, bc->onumplan, "LTON");
      debug_numplan(port, bc->cpnnumplan, "CTON");

      ch->overlap_dial = 0;
   } else {
      /* ORIGINATOR MISDN (incoming call) */
      char prefix[BUFFERSIZE + 1] = "";

      if (strstr(faxdetect, "incoming") || strstr(faxdetect, "both")) {
         ch->faxdetect = (strstr(faxdetect, "nojump")) ? 2 : 1;
      }

      misdn_cfg_get(port, MISDN_CFG_CPNDIALPLAN, &bc->cpnnumplan, sizeof(bc->cpnnumplan));
      debug_numplan(port, bc->cpnnumplan, "CTON");

      switch (bc->onumplan) {
      case NUMPLAN_INTERNATIONAL:
         misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, sizeof(prefix));
         break;

      case NUMPLAN_NATIONAL:
         misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, sizeof(prefix));
         break;
      default:
         break;
      }

      ast_copy_string(buf, bc->oad, sizeof(buf));
      snprintf(bc->oad, sizeof(bc->oad), "%s%s", prefix, buf);

      if (!ast_strlen_zero(bc->dad)) {
         ast_copy_string(bc->orig_dad, bc->dad, sizeof(bc->orig_dad));
      }

      if (ast_strlen_zero(bc->dad) && !ast_strlen_zero(bc->keypad)) {
         ast_copy_string(bc->dad, bc->keypad, sizeof(bc->dad));
      }

      prefix[0] = 0;

      switch (bc->dnumplan) {
      case NUMPLAN_INTERNATIONAL:
         misdn_cfg_get(bc->port, MISDN_CFG_INTERNATPREFIX, prefix, sizeof(prefix));
         break;
      case NUMPLAN_NATIONAL:
         misdn_cfg_get(bc->port, MISDN_CFG_NATPREFIX, prefix, sizeof(prefix));
         break;
      default:
         break;
      }

      ast_copy_string(buf, bc->dad, sizeof(buf));
      snprintf(bc->dad, sizeof(bc->dad), "%s%s", prefix, buf);

      if (strcmp(bc->dad, ast->exten)) {
         ast_copy_string(ast->exten, bc->dad, sizeof(ast->exten));
      }

      ast_set_callerid(ast, bc->oad, NULL, bc->oad);

      if ( !ast_strlen_zero(bc->rad) ) {
         if (ast->cid.cid_rdnis) {
            ast_free(ast->cid.cid_rdnis);
         }
         ast->cid.cid_rdnis = ast_strdup(bc->rad);
      }
   
      misdn_cfg_get(bc->port, MISDN_CFG_OVERLAP_DIAL, &ch->overlap_dial, sizeof(ch->overlap_dial));
      ast_mutex_init(&ch->overlap_tv_lock);
   } /* ORIG MISDN END */

   ch->overlap_dial_task = -1;
   
   if (ch->faxdetect  || ch->ast_dsp) {
      misdn_cfg_get(port, MISDN_CFG_FAXDETECT_TIMEOUT, &ch->faxdetect_timeout, sizeof(ch->faxdetect_timeout));
      if (!ch->dsp) {
         ch->dsp = ast_dsp_new();
      }
      if (ch->dsp) {
         ast_dsp_set_features(ch->dsp, DSP_FEATURE_DIGIT_DETECT | (ch->faxdetect ? DSP_FEATURE_FAX_DETECT : 0));
      }
   }

   /* AOCD initialization */
   bc->AOCDtype = Fac_None;

   return 0;
}
static void release_chan ( struct chan_list ch,
struct misdn_bchannel bc 
) [static]

Definition at line 3977 of file chan_misdn.c.

References ast_channel::_state, chan_list::ast, ast_free, ast_mutex_destroy(), ast_mutex_lock(), ast_mutex_unlock(), ast_setstate(), AST_STATE_DOWN, AST_STATE_RESERVED, chan_misdn_log(), ast_channel::cid, ast_callerid::cid_num, cl_dequeue_chan(), ast_channel::context, ast_channel::exten, chan_list::jb, misdn_bchannel::l3_id, MISDN_ASTERISK_TECH_PVT, MISDN_CLEANING, misdn_jb_destroy(), misdn_tasks_remove(), misdn_bchannel::nojitter, ORG_AST, chan_list::originator, chan_list::overlap_dial, chan_list::overlap_dial_task, chan_list::overlap_tv_lock, misdn_bchannel::pid, chan_list::pipe, misdn_bchannel::port, and chan_list::state.

Referenced by cb_events(), and misdn_hangup().

{
   struct ast_channel *ast;

   ch->state = MISDN_CLEANING;

   ast_mutex_lock(&release_lock);

   cl_dequeue_chan(&cl_te, ch);

   chan_misdn_log(5, bc->port, "release_chan: bc with pid:%d l3id: %x\n", bc->pid, bc->l3_id);

   /* releasing jitterbuffer */
   if (ch->jb) {
      misdn_jb_destroy(ch->jb);
      ch->jb = NULL;
   } else {
      if (!bc->nojitter) {
         chan_misdn_log(5, bc->port, "Jitterbuffer already destroyed.\n");
      }
   }

   if (ch->overlap_dial) {
      if (ch->overlap_dial_task != -1) {
         misdn_tasks_remove(ch->overlap_dial_task);
         ch->overlap_dial_task = -1;
      }
      ast_mutex_destroy(&ch->overlap_tv_lock);
   }

   if (ch->originator == ORG_AST) {
      --misdn_out_calls[bc->port];
   } else {
      --misdn_in_calls[bc->port];
   }

   close(ch->pipe[0]);
   close(ch->pipe[1]);

   ast = ch->ast;
   if (ast) {
      MISDN_ASTERISK_TECH_PVT(ast) = NULL;
      chan_misdn_log(1, bc->port,
         "* RELEASING CHANNEL pid:%d ctx:%s dad:%s oad:%s\n",
         bc->pid,
         ast->context,
         ast->exten,
         ast->cid.cid_num);

      if (ast->_state != AST_STATE_RESERVED) {
         chan_misdn_log(3, bc->port, " --> Setting AST State to down\n");
         ast_setstate(ast, AST_STATE_DOWN);
      }
   }

   ast_free(ch);

   ast_mutex_unlock(&release_lock);
}
static int reload ( void  ) [static]

Definition at line 5599 of file chan_misdn.c.

References reload_config().

{
   reload_config();

   return 0;
}
static void reload_config ( void  ) [static]

Definition at line 1331 of file chan_misdn.c.

References ast_log(), free_robin_list(), LOG_WARNING, max_ports, misdn_cfg_get(), misdn_cfg_reload(), misdn_cfg_update_ptp(), MISDN_GEN_DEBUG, and MISDN_GEN_TRACEFILE.

Referenced by handle_cli_misdn_reload(), and reload().

{
   int i, cfg_debug;

   if (!g_config_initialized) {
      ast_log(LOG_WARNING, "chan_misdn is not initialized properly, still reloading ?\n");
      return ;
   }
   
   free_robin_list();
   misdn_cfg_reload();
   misdn_cfg_update_ptp();
   misdn_cfg_get(0, MISDN_GEN_TRACEFILE, global_tracefile, sizeof(global_tracefile));
   misdn_cfg_get(0, MISDN_GEN_DEBUG, &cfg_debug, sizeof(cfg_debug));

   for (i = 0;  i <= max_ports; i++) {
      misdn_debug[i] = cfg_debug;
      misdn_debug_only[i] = 0;
   }
}
static void send_cause2ast ( struct ast_channel ast,
struct misdn_bchannel bc,
struct chan_list ch 
) [static]

Definition at line 4199 of file chan_misdn.c.

References AST_CAUSE_CALL_REJECTED, AST_CAUSE_DESTINATION_OUT_OF_ORDER, AST_CAUSE_NO_ROUTE_DESTINATION, AST_CAUSE_NO_ROUTE_TRANSIT_NET, AST_CAUSE_NUMBER_CHANGED, AST_CAUSE_UNALLOCATED, AST_CAUSE_USER_BUSY, AST_CONTROL_BUSY, ast_queue_control(), misdn_bchannel::cause, chan_misdn_log(), ast_channel::hangupcause, MISDN_BUSY, chan_list::need_busy, misdn_bchannel::pid, misdn_bchannel::port, and chan_list::state.

Referenced by hangup_chan().

                                                                                                     {
   if (!ast) {
      chan_misdn_log(1, 0, "send_cause2ast: No Ast\n");
      return;
   }
   if (!bc) {
      chan_misdn_log(1, 0, "send_cause2ast: No BC\n");
      return;
   }
   if (!ch) {
      chan_misdn_log(1, 0, "send_cause2ast: No Ch\n");
      return;
   }

   ast->hangupcause = bc->cause;

   switch (bc->cause) {

   case AST_CAUSE_UNALLOCATED:
   case AST_CAUSE_NO_ROUTE_TRANSIT_NET:
   case AST_CAUSE_NO_ROUTE_DESTINATION:
   case 4:  /* Send special information tone */
   case AST_CAUSE_NUMBER_CHANGED:
   case AST_CAUSE_DESTINATION_OUT_OF_ORDER:
      /* Congestion Cases */
      /*
       * Not Queueing the Congestion anymore, since we want to hear
       * the inband message
       *
      chan_misdn_log(1, bc ? bc->port : 0, " --> * SEND: Queue Congestion pid:%d\n", bc ? bc->pid : -1);
      ch->state = MISDN_BUSY;
      
      ast_queue_control(ast, AST_CONTROL_CONGESTION);
      */
      break;

   case AST_CAUSE_CALL_REJECTED:
   case AST_CAUSE_USER_BUSY:
      ch->state = MISDN_BUSY;

      if (!ch->need_busy) {
         chan_misdn_log(1, bc ? bc->port : 0, "Queued busy already\n");
         break;
      }

      chan_misdn_log(1, bc ? bc->port : 0, " --> * SEND: Queue Busy pid:%d\n", bc ? bc->pid : -1);
      
      ast_queue_control(ast, AST_CONTROL_BUSY);
      
      ch->need_busy = 0;
      
      break;
   }
}
static void send_digit_to_chan ( struct chan_list cl,
char  digit 
) [static]

Definition at line 898 of file chan_misdn.c.

References chan_list::ast, ast_debug, ast_playtones_start(), chan, and ast_channel::name.

Referenced by handle_cli_misdn_send_digit(), and misdn_digit_end().

{
   static const char *dtmf_tones[] = {
      "!941+1336/100,!0/100", /* 0 */
      "!697+1209/100,!0/100", /* 1 */
      "!697+1336/100,!0/100", /* 2 */
      "!697+1477/100,!0/100", /* 3 */
      "!770+1209/100,!0/100", /* 4 */
      "!770+1336/100,!0/100", /* 5 */
      "!770+1477/100,!0/100", /* 6 */
      "!852+1209/100,!0/100", /* 7 */
      "!852+1336/100,!0/100", /* 8 */
      "!852+1477/100,!0/100", /* 9 */
      "!697+1633/100,!0/100", /* A */
      "!770+1633/100,!0/100", /* B */
      "!852+1633/100,!0/100", /* C */
      "!941+1633/100,!0/100", /* D */
      "!941+1209/100,!0/100", /* * */
      "!941+1477/100,!0/100", /* # */
   };
   struct ast_channel *chan = cl->ast; 
  
   if (digit >= '0' && digit <='9') {
      ast_playtones_start(chan, 0, dtmf_tones[digit - '0'], 0);
   } else if (digit >= 'A' && digit <= 'D') {
      ast_playtones_start(chan, 0, dtmf_tones[digit - 'A' + 10], 0);
   } else if (digit == '*') {
      ast_playtones_start(chan, 0, dtmf_tones[14], 0);
   } else if (digit == '#') {
      ast_playtones_start(chan, 0, dtmf_tones[15], 0);
   } else {
      /* not handled */
      ast_debug(1, "Unable to handle DTMF tone '%c' for '%s'\n", digit, chan->name);
   }
}
static void show_config_description ( int  fd,
enum misdn_cfg_elements  elem 
) [inline, static]

Definition at line 1175 of file chan_misdn.c.

References ast_cli(), BUFFERSIZE, COLOR_BRWHITE, COLOR_YELLOW, desc, misdn_cfg_get_desc(), misdn_cfg_get_name(), MISDN_CFG_LAST, name, and term_color().

Referenced by handle_cli_misdn_show_config().

{
   char section[BUFFERSIZE];
   char name[BUFFERSIZE];
   char desc[BUFFERSIZE];
   char def[BUFFERSIZE];
   char tmp[BUFFERSIZE];

   misdn_cfg_get_name(elem, tmp, sizeof(tmp));
   term_color(name, tmp, COLOR_BRWHITE, 0, sizeof(tmp));
   misdn_cfg_get_desc(elem, desc, sizeof(desc), def, sizeof(def));

   if (elem < MISDN_CFG_LAST) {
      term_color(section, "PORTS SECTION", COLOR_YELLOW, 0, sizeof(section));
   } else {
      term_color(section, "GENERAL SECTION", COLOR_YELLOW, 0, sizeof(section));
   }

   if (*def) {
      ast_cli(fd, "[%s] %s   (Default: %s)\n\t%s\n", section, name, def, desc);
   } else {
      ast_cli(fd, "[%s] %s\n\t%s\n", section, name, desc);
   }
}
static void sighandler ( int  sig) [static]

Definition at line 745 of file chan_misdn.c.

Referenced by misdn_tasks_thread_func().

{}
static int start_bc_tones ( struct chan_list cl) [static]
static void start_pbx ( struct chan_list ch,
struct misdn_bchannel bc,
struct ast_channel chan 
) [static]
static int stop_bc_tones ( struct chan_list cl) [static]

Definition at line 3392 of file chan_misdn.c.

References chan_list::norxtone, and chan_list::notxtone.

Referenced by cb_events(), misdn_call(), and misdn_hangup().

{
   if (!cl) {
      return -1;
   }

   cl->notxtone = 1;
   cl->norxtone = 1;
   
   return 0;
}
static int stop_indicate ( struct chan_list cl) [static]

Definition at line 3363 of file chan_misdn.c.

References chan_list::ast, ast_playtones_stop(), ast_tone_zone_sound_unref(), chan_list::bc, chan_misdn_log(), misdn_lib_tone_generator_stop(), misdn_bchannel::port, and chan_list::ts.

Referenced by cb_events(), misdn_answer(), misdn_indication(), and misdn_overlap_dial_task().

{
   struct ast_channel *ast = cl->ast;

   if (!ast) {
      chan_misdn_log(0, cl->bc->port, "No Ast in stop_indicate\n");
      return -1;
   }

   chan_misdn_log(3, cl->bc->port, " --> None\n");
   misdn_lib_tone_generator_stop(cl->bc);
   ast_playtones_stop(ast);

   if (cl->ts) {
      cl->ts = ast_tone_zone_sound_unref(cl->ts);
   }

   return 0;
}
static int unload_module ( void  ) [static]

TE STUFF END

Definition at line 5382 of file chan_misdn.c.

References ast_channel_unregister(), ast_cli_unregister_multiple(), ast_free, ast_log(), ast_unregister_application(), free_robin_list(), LOG_VERBOSE, misdn_cfg_destroy(), misdn_lib_destroy(), and misdn_tasks_destroy().

Referenced by load_module().

{
   /* First, take us out of the channel loop */
   ast_log(LOG_VERBOSE, "-- Unregistering mISDN Channel Driver --\n");

   misdn_tasks_destroy();
   
   if (!g_config_initialized) {
      return 0;
   }
   
   ast_cli_unregister_multiple(chan_misdn_clis, sizeof(chan_misdn_clis) / sizeof(struct ast_cli_entry));

   /* ast_unregister_application("misdn_crypt"); */
   ast_unregister_application("misdn_set_opt");
   ast_unregister_application("misdn_facility");
   ast_unregister_application("misdn_check_l2l1");

   ast_channel_unregister(&misdn_tech);

   free_robin_list();
   misdn_cfg_destroy();
   misdn_lib_destroy();
  
   ast_free(misdn_out_calls);
   ast_free(misdn_in_calls);
   ast_free(misdn_debug_only);
   ast_free(misdn_ports);
   ast_free(misdn_debug);
   
   return 0;
}
static int update_config ( struct chan_list ch,
int  orig 
) [static]

Updates caller ID information from config.

Definition at line 2002 of file chan_misdn.c.

References chan_list::ast, ast_log(), AST_PRES_NETWORK_NUMBER, AST_PRES_RESTRICTED, AST_PRES_UNAVAILABLE, AST_PRES_USER_NUMBER_FAILED_SCREEN, AST_PRES_USER_NUMBER_PASSED_SCREEN, AST_PRES_USER_NUMBER_UNSCREENED, chan_list::bc, misdn_bchannel::capability, chan_misdn_log(), ast_channel::cid, ast_callerid::cid_pres, misdn_bchannel::hdlc, INFO_CAPABILITY_DIGITAL_RESTRICTED, INFO_CAPABILITY_DIGITAL_UNRESTRICTED, LOG_WARNING, misdn_cfg_get(), MISDN_CFG_HDLC, MISDN_CFG_PRES, MISDN_CFG_SCREEN, misdn_bchannel::port, misdn_bchannel::pres, and misdn_bchannel::screen.

Referenced by misdn_call().

{
   struct ast_channel *ast;
   struct misdn_bchannel *bc;
   int port, hdlc = 0;
   int pres, screen;

   if (!ch) {
      ast_log(LOG_WARNING, "Cannot configure without chanlist\n");
      return -1;
   }

   ast = ch->ast;
   bc = ch->bc;
   if (! ast || ! bc) {
      ast_log(LOG_WARNING, "Cannot configure without ast || bc\n");
      return -1;
   }

   port = bc->port;

   chan_misdn_log(7, port, "update_config: Getting Config\n");

   misdn_cfg_get(port, MISDN_CFG_HDLC, &hdlc, sizeof(int));
   
   if (hdlc) {
      switch (bc->capability) {
      case INFO_CAPABILITY_DIGITAL_UNRESTRICTED:
      case INFO_CAPABILITY_DIGITAL_RESTRICTED:
         chan_misdn_log(1, bc->port, " --> CONF HDLC\n");
         bc->hdlc = 1;
         break;
      }
   }

   misdn_cfg_get(port, MISDN_CFG_PRES, &pres, sizeof(pres));
   misdn_cfg_get(port, MISDN_CFG_SCREEN, &screen, sizeof(screen));
   chan_misdn_log(2, port, " --> pres: %d screen: %d\n", pres, screen);
      
   if (pres < 0 || screen < 0) {
      chan_misdn_log(2, port, " --> pres: %x\n", ast->cid.cid_pres);
         
      switch (ast->cid.cid_pres & 0x60) {
      case AST_PRES_RESTRICTED:
         bc->pres = 1;
         chan_misdn_log(2, port, " --> PRES: Restricted (1)\n");
         break;
      case AST_PRES_UNAVAILABLE:
         bc->pres = 2;
         chan_misdn_log(2, port, " --> PRES: Unavailable (2)\n");
         break;
      default:
         bc->pres = 0;
         chan_misdn_log(2, port, " --> PRES: Allowed (0)\n");
         break;
      }

      switch (ast->cid.cid_pres & 0x3) {
      default:
      case AST_PRES_USER_NUMBER_UNSCREENED:
         bc->screen = 0;
         chan_misdn_log(2, port, " --> SCREEN: Unscreened (0)\n");
         break;
      case AST_PRES_USER_NUMBER_PASSED_SCREEN:
         bc->screen = 1;
         chan_misdn_log(2, port, " --> SCREEN: Passed Screen (1)\n");
         break;
      case AST_PRES_USER_NUMBER_FAILED_SCREEN:
         bc->screen = 2;
         chan_misdn_log(2, port, " --> SCREEN: Failed Screen (2)\n");
         break;
      case AST_PRES_NETWORK_NUMBER:
         bc->screen = 3;
         chan_misdn_log(2, port, " --> SCREEN: Network Nr. (3)\n");
         break;
      }
   } else {
      bc->screen = screen;
      bc->pres = pres;
   }

   return 0;
}
static int update_ec_config ( struct misdn_bchannel bc) [static]

Definition at line 2166 of file chan_misdn.c.

References misdn_bchannel::ec_deftaps, misdn_bchannel::ec_enable, MISDN_CFG_ECHOCANCEL, misdn_cfg_get(), and misdn_bchannel::port.

Referenced by handle_cli_misdn_toggle_echocancel(), and read_config().

{
   int ec;
   int port = bc->port;

   misdn_cfg_get(port, MISDN_CFG_ECHOCANCEL, &ec, sizeof(ec));

   if (ec == 1) {
      bc->ec_enable = 1;
   } else if (ec > 1) {
      bc->ec_enable = 1;
      bc->ec_deftaps = ec;
   }

   return 0;
}
static void update_name ( struct ast_channel tmp,
int  port,
int  c 
) [static]

Definition at line 3679 of file chan_misdn.c.

References ast_change_name(), chan_misdn_log(), misdn_cfg_get_next_port(), misdn_lib_port_is_pri(), and ast_channel::name.

Referenced by cb_events().

{
   int chan_offset = 0;
   int tmp_port = misdn_cfg_get_next_port(0);
   char newname[255];
   for (; tmp_port > 0; tmp_port = misdn_cfg_get_next_port(tmp_port)) {
      if (tmp_port == port) {
         break;
      }
      chan_offset += misdn_lib_port_is_pri(tmp_port) ? 30 : 2; 
   }
   if (c < 0) {
      c = 0;
   }

   snprintf(newname, sizeof(newname), "%s/%d-", misdn_type, chan_offset + c);
   if (strncmp(tmp->name, newname, strlen(newname))) {
      snprintf(newname, sizeof(newname), "%s/%d-u%d", misdn_type, chan_offset + c, glob_channel++);
      ast_change_name(tmp, newname);
      chan_misdn_log(3, port, " --> updating channel name to [%s]\n", tmp->name);
   }
}
static void wait_for_digits ( struct chan_list ch,
struct misdn_bchannel bc,
struct ast_channel chan 
) [static]

Variable Documentation

struct ast_module_info __MODULE_INFO_SECTION __mod_info = { __MODULE_INFO_GLOBALS .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "Channel driver for mISDN Support (BRI/PRI)" , .key = ASTERISK_GPL_KEY , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, .reload = reload, } [static]

Definition at line 6196 of file chan_misdn.c.

Definition at line 591 of file chan_misdn.c.

Definition at line 6196 of file chan_misdn.c.

struct ast_cli_entry chan_misdn_clis[] [static]

Definition at line 1977 of file chan_misdn.c.

struct chan_list* cl_te = NULL

Global channel call record list head.

Definition at line 511 of file chan_misdn.c.

Referenced by handle_cli_misdn_show_channel(), and handle_cli_misdn_show_channels().

Definition at line 512 of file chan_misdn.c.

Definition at line 506 of file chan_misdn.c.

int g_config_initialized = 0 [static]

Definition at line 77 of file chan_misdn.c.

int glob_channel = 0 [static]

Definition at line 3677 of file chan_misdn.c.

char global_tracefile[BUFFERSIZE+1]

Definition at line 75 of file chan_misdn.c.

int max_ports [static]

Definition at line 501 of file chan_misdn.c.

Referenced by handle_cli_misdn_set_debug(), load_module(), and reload_config().

int MAXTICS = 8

Definition at line 415 of file chan_misdn.c.

int* misdn_debug [static]

Definition at line 499 of file chan_misdn.c.

int* misdn_debug_only [static]

Definition at line 500 of file chan_misdn.c.

int* misdn_in_calls [static]

Definition at line 503 of file chan_misdn.c.

int* misdn_out_calls [static]

Definition at line 504 of file chan_misdn.c.

int* misdn_ports [static]

Definition at line 475 of file chan_misdn.c.

struct sched_context* misdn_tasks = NULL [static]

the main schedule context for stuff like l1 watcher, overlap dial, ...

Definition at line 472 of file chan_misdn.c.

pthread_t misdn_tasks_thread [static]

Definition at line 473 of file chan_misdn.c.

struct ast_channel_tech misdn_tech [static]

Definition at line 3639 of file chan_misdn.c.

Definition at line 3658 of file chan_misdn.c.

Referenced by misdn_new().

const char misdn_type[] = "mISDN" [static]

Definition at line 492 of file chan_misdn.c.

int prefformat = AST_FORMAT_ALAW [static]

Only alaw and mulaw is allowed for now.

Definition at line 497 of file chan_misdn.c.

Referenced by misdn_new().

Definition at line 114 of file chan_misdn.c.

struct robin_list * robin [static]
struct state_struct state_array[] [static]

Definition at line 1293 of file chan_misdn.c.

int tracing = 0 [static]

Definition at line 494 of file chan_misdn.c.