[asterisk-commits] nadi: branch nadi/trunk-cm r44863 - in
/team/nadi/trunk-cm/channels: ./ misdn/
asterisk-commits at lists.digium.com
asterisk-commits at lists.digium.com
Wed Oct 11 03:29:40 MST 2006
Author: nadi
Date: Wed Oct 11 05:29:39 2006
New Revision: 44863
URL: http://svn.digium.com/view/asterisk?rev=44863&view=rev
Log:
Huge chan_misdn commit: Bump approx. 1000 lines of code, use configman, csel and all the new stuff. experimental.
Removed:
team/nadi/trunk-cm/channels/misdn/chan_misdn_config.h
team/nadi/trunk-cm/channels/misdn_config.c
Modified:
team/nadi/trunk-cm/channels/Makefile
team/nadi/trunk-cm/channels/chan_misdn.c
team/nadi/trunk-cm/channels/misdn/isdn_lib.c
team/nadi/trunk-cm/channels/misdn/isdn_lib.h
team/nadi/trunk-cm/channels/misdn/isdn_msg_parser.c
Modified: team/nadi/trunk-cm/channels/Makefile
URL: http://svn.digium.com/view/asterisk/team/nadi/trunk-cm/channels/Makefile?rev=44863&r1=44862&r2=44863&view=diff
==============================================================================
--- team/nadi/trunk-cm/channels/Makefile (original)
+++ team/nadi/trunk-cm/channels/Makefile Wed Oct 11 05:29:39 2006
@@ -111,4 +111,4 @@
misdn_config.o: ASTCFLAGS+=-Imisdn
-$(if $(filter chan_misdn,$(EMBEDDED_MODS)),modules.link,chan_misdn.so): chan_misdn.o misdn_config.o misdn/isdn_lib.o misdn/isdn_msg_parser.o
+$(if $(filter chan_misdn,$(EMBEDDED_MODS)),modules.link,chan_misdn.so): chan_misdn.o misdn/isdn_lib.o misdn/isdn_msg_parser.o
Modified: team/nadi/trunk-cm/channels/chan_misdn.c
URL: http://svn.digium.com/view/asterisk/team/nadi/trunk-cm/channels/chan_misdn.c?rev=44863&r1=44862&r2=44863&view=diff
==============================================================================
--- team/nadi/trunk-cm/channels/chan_misdn.c (original)
+++ team/nadi/trunk-cm/channels/chan_misdn.c Wed Oct 11 05:29:39 2006
@@ -27,10 +27,11 @@
*/
/*** MODULEINFO
- <depend>isdnnet</depend>
- <depend>misdn</depend>
- <depend>suppserv</depend>
+ <depend>isdnnet</depend>
+ <depend>misdn</depend>
+ <depend>suppserv</depend>
***/
+
#include "asterisk.h"
ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
@@ -50,6 +51,9 @@
#include <sys/file.h>
#include <semaphore.h>
+#include "asterisk/configman.h"
+#include "asterisk/csel.h"
+#include "asterisk/hash.h"
#include "asterisk/channel.h"
#include "asterisk/config.h"
#include "asterisk/logger.h"
@@ -63,7 +67,6 @@
#include "asterisk/musiconhold.h"
#include "asterisk/dsp.h"
#include "asterisk/translate.h"
-#include "asterisk/config.h"
#include "asterisk/file.h"
#include "asterisk/callerid.h"
#include "asterisk/indications.h"
@@ -72,422 +75,1195 @@
#include "asterisk/term.h"
#include "asterisk/sched.h"
#include "asterisk/stringfields.h"
-
-#include "chan_misdn_config.h"
+#include <asterisk/strings.h>
+
#include "isdn_lib.h"
-char global_tracefile[BUFFERSIZE+1];
-
-
-struct misdn_jb{
+#define ORG_AST 1
+#define ORG_MISDN 2
+#define BUFFERSIZE 512
+
+#define AST_CID_P(ast) ((ast)->cid.cid_num)
+#define AST_BRIDGED_P(ast) ast_bridged_channel((ast))
+
+#define MISDN_ASTERISK_TECH_PVT(ast) ((ast)->tech_pvt)
+#define MISDN_ASTERISK_PVT(ast) 1
+
+enum misdn_chan_state {
+ MISDN_NOTHING = 0, /*!< at beginning */
+ MISDN_WAITING4DIGS, /*!< when waiting for infos */
+ MISDN_EXTCANTMATCH, /*!< when asterisk couldnt match our ext */
+ MISDN_DIALING, /*!< when pbx_start */
+ MISDN_PROGRESS, /*!< we got a progress */
+ MISDN_PROCEEDING, /*!< we got a 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_PRECONNECTED, /*!< when connected */
+ MISDN_DISCONNECTED, /*!< when connected */
+ MISDN_RELEASED, /*!< when connected */
+ MISDN_BRIDGED, /*!< when bridged */
+ MISDN_CLEANING, /*!< when hangup from * but we were connected before */
+ MISDN_HUNGUP_FROM_MISDN, /*!< when DISCONNECT/RELEASE/REL_COMP cam from misdn */
+ MISDN_HUNGUP_FROM_AST, /*!< when DISCONNECT/RELEASE/REL_COMP came out of */
+ MISDN_HOLDED, /*!< if this chan is holded */
+ MISDN_HOLD_DISCONNECT, /*!< if this chan is holded */
+ MISDN_FIXUP /*!< if this chan is holded */
+};
+
+struct chan_list {
+ char allowed_bearers[BUFFERSIZE];
+ enum misdn_chan_state state;
+
+ int need_queue_hangup;
+ int need_hangup;
+ int need_busy;
+ int orginator;
+ int norxtone;
+ int notxtone;
+ int toggle_ec;
+ int incoming_early_audio;
+ int ignore_dtmf;
+ int faxdetect; /* 0:no 1:yes 2:yes+nojump */
+ int faxdetect_timeout;
+ struct timeval faxdetect_tv;
+ int faxhandled;
+ int jb_len;
+ int jb_upper_threshold;
+ struct misdn_jb *jb;
+ int overlap_dial;
+ int overlap_dial_task;
+ ast_mutex_t overlap_tv_lock;
+ struct timeval overlap_tv;
+
+ int pipe[2];
+ char ast_rd_buf[4096];
+ struct ast_frame frame;
+ int ast_dsp;
+ struct ast_dsp *dsp;
+ struct ast_trans_pvt *trans;
+ struct ast_channel *ast;
+ struct misdn_bchannel *bc;
+ struct {
+ int port;
+ int channel;
+ } hold_info;
+
+ unsigned int l3id;
+ int addr;
+ char context[BUFFERSIZE];
+ int dropped_frame_cnt;
+ int far_alerting;
+ int other_pid;
+ struct chan_list *other_ch;
+ const struct tone_zone_sound *ts;
+
+ struct chan_list *next;
+};
+
+struct allowed_bearer {
+ int cap;
+ char *name;
+ char *nicename;
+};
+
+struct misdn_csel_item {
+ int port;
+ int chan;
+};
+
+struct misdn_jb {
+ ast_mutex_t lock;
int size;
int upper_threshold;
- char *samples, *ok;
- int wp,rp;
+ int wp;
+ int rp;
int state_empty;
int state_full;
int state_buffer;
int bytes_wrote;
- ast_mutex_t mutexjb;
+ char *samples;
+ char *ok;
};
-
-
-/* allocates the jb-structure and initialise the elements*/
-struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
-
-/* frees the data and destroys the given jitterbuffer struct */
-void misdn_jb_destroy(struct misdn_jb *jb);
-
-/* fills the jitterbuffer with len data returns < 0 if there was an
-error (bufferoverun). */
-int misdn_jb_fill(struct misdn_jb *jb, const 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_empty(struct misdn_jb *jb, char *data, int len);
-
-
-enum misdn_chan_state {
- MISDN_NOTHING=0, /*!< at beginning */
- MISDN_WAITING4DIGS, /*!< when waiting for infos */
- MISDN_EXTCANTMATCH, /*!< when asterisk couldnt match our ext */
- MISDN_DIALING, /*!< when pbx_start */
- MISDN_PROGRESS, /*!< we got a progress */
- MISDN_PROCEEDING, /*!< we got a 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_PRECONNECTED, /*!< when connected */
- MISDN_DISCONNECTED, /*!< when connected */
- MISDN_RELEASED, /*!< when connected */
- MISDN_BRIDGED, /*!< when bridged */
- MISDN_CLEANING, /*!< when hangup from * but we were connected before */
- MISDN_HUNGUP_FROM_MISDN, /*!< when DISCONNECT/RELEASE/REL_COMP cam from misdn */
- MISDN_HUNGUP_FROM_AST, /*!< when DISCONNECT/RELEASE/REL_COMP came out of */
- /* misdn_hangup */
- MISDN_HOLDED, /*!< if this chan is holded */
- MISDN_HOLD_DISCONNECT, /*!< if this chan is holded */
- MISDN_FIXUP/*!< if this chan is holded */
-
+/* Global Static Variables */
+static const char misdn_type[] = "mISDN";
+static cm_t * misdn_cm = NULL;
+static int max_ports;
+static const int prefformat = AST_FORMAT_ALAW;
+static char tracefile[BUFFERSIZE];
+
+static struct chan_list * cl_te = NULL;
+static ast_mutex_t cl_te_lock;
+
+static char ** misdn_key_vector = NULL;
+static int misdn_key_vector_size = 0;
+
+static int * misdn_in_calls;
+static int * misdn_out_calls;
+
+static struct sched_context * misdn_tasks = NULL;
+static pthread_t misdn_tasks_thread;
+
+static int * misdn_debug = NULL,
+ * misdn_debug_only = NULL,
+ * misdn_ports = NULL;
+
+static AST_HASH_STR(, struct csel *) group_csel_hash;
+
+/* mISDN Configuration */
+static const cm_dir_t gen_dirs[] = {
+ { },
+ { "debug", "0",
+ "Sets the debugging flag:\n"
+ "\t0 - No Debug\n"
+ "\t1 - mISDN Messages and * - Messages, and * - State changes\n"
+ "\t2 - Messages + Message specific Informations (e.g. bearer capability)\n"
+ "\t3 - very Verbose, the above + lots of Driver specific infos\n"
+ "\t4 - even more Verbose than 3" },
+ { "misdn_init", "/etc/misdn-init.conf",
+ "Set the path to the misdn-init.conf (for nt_ptp mode checking)." },
+ { "tracefile", "/var/log/asterisk/misdn.log",
+ "Set the path to the massively growing trace file, if you want that." },
+ { "bridging", "yes",
+ "Set this to yes if you want mISDN_dsp to bridge the calls in HW." },
+ { "stop_tone_after_first_digit", "yes",
+ "Stops dialtone after getting first digit on NT Port." },
+ { "append_digits2exten", "yes",
+ "Wether to append overlapdialed Digits to Extension or not." },
+ { "dynamic_crypt", "no",
+ "Wether to look out for dynamic crypting attempts." },
+ { "crypt_prefix", 0,
+ "What is used for crypting Protocol." },
+ { "crypt_keys", 0,
+ "Keys for cryption, you reference them in the dialplan\n"
+ "\tLater also in dynamic encr." },
+ { "ntdebugflags", "0",
+ "No description yet."},
+ { "ntdebugfile", "/var/log/misdn-nt.log",
+ "No description yet." }
};
-#define ORG_AST 1
-#define ORG_MISDN 2
-
-struct hold_info {
- int port;
- int channel;
+enum {
+ MCFG_SECNAME = 0,
+ MCFG_DEBUG,
+ MCFG_MISDN_INIT,
+ MCFG_TRACEFILE,
+ MCFG_BRIDGING,
+ MCFG_STOP_TONE_AFTER_FIRST_DIGIT,
+ MCFG_APPEND_DIGITS2EXTEN,
+ MCFG_DYNAMIC_CRYPT,
+ MCFG_CRYPT_PREFIX,
+ MCFG_CRYPT_KEYS,
+ MCFG_NTDEBUGFLAGS,
+ MCFG_NTDEBUGFILE,
+ MCFG_GENERAL_END
};
-struct chan_list {
-
- char allowed_bearers[BUFFERSIZE+1];
+static const cm_dir_t port_dirs[] = {
+ { "groupname", 0,
+ "Name of the portgroup." },
+ { "ports", 0,
+ "Define your ports, e.g. 1, 2 (depends on mISDN-driver loading order)." },
+ { "allowed_bearers", "all",
+ "Here you can define which bearers should be allowed." },
+ { "rxgain", "0",
+ "Set this between -8 and 8 to change the RX Gain." },
+ { "txgain", "0",
+ "Set this between -8 and 8 to change the TX Gain." },
+ { "te_choose_channel", "no",
+ "Some telcos espacially in NL seem to need this set to yes,\n"
+ "\talso in switzerland this seems to be important." },
+ { "far_alerting", "no",
+ "If we should generate ringing for chan_sip and others." },
+ { "pmp_l1_check", "yes",
+ "This option defines, if chan_misdn should check the L1 on a PMP\n"
+ "\tbefore makeing a group call on it. The L1 may go down for PMP Ports\n"
+ "\tso we might need this.\n"
+ "\tBut be aware! a broken or plugged off cable might be used for a group call\n"
+ "\tas well, since chan_misdn has no chance to distinguish if the L1 is down\n"
+ "\tbecause of a lost Link or because the Provider shut it down..." },
+ { "block_on_alarm", "yes",
+ "Block this port if we have an alarm on it.\n"
+ "default: yes" },
+ { "hdlc", "no",
+ "Set this to yes, if you want to bridge a mISDN data channel to\n"
+ "\tanother channel type or to an application." },
+ { "context", "default",
+ "Context to use for incoming calls." },
+ { "language", "en",
+ "Language." },
+ { "musicclass", "default",
+ "Sets the musiconhold class." },
+ { "callerid", "",
+ "Sets the caller ID." },
+ CM_CSEL_METHOD,
+ CM_CSEL_METHOD_PARMS,
+ { "dialplan", "0",
+ "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n"
+ "\n"
+ "\tThere are different types of the dialplan:\n"
+ "\n"
+ "\tdialplan -> outgoing Number\n"
+ "\tlocaldialplan -> callerid\n"
+ "\tcpndialplan -> connected party number\n"
+ "\n"
+ "\tdialplan options:\n"
+ "\n"
+ "\t0 - unknown\n"
+ "\t1 - International\n"
+ "\t2 - National\n"
+ "\t4 - Subscriber\n"
+ "\n"
+ "\tThis setting is used for outgoing calls." },
+ { "localdialplan", "0",
+ "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n"
+ "\n"
+ "\tThere are different types of the dialplan:\n"
+ "\n"
+ "\tdialplan -> outgoing Number\n"
+ "\tlocaldialplan -> callerid\n"
+ "\tcpndialplan -> connected party number\n"
+ "\n"
+ "\tdialplan options:\n"
+ "\n"
+ "\t0 - unknown\n"
+ "\t1 - International\n"
+ "\t2 - National\n"
+ "\t4 - Subscriber\n"
+ "\n"
+ "\tThis setting is used for outgoing calls" },
+ { "cpndialplan", "0",
+ "Dialplan means Type Of Number in ISDN Terms (for outgoing calls)\n"
+ "\n"
+ "\tThere are different types of the dialplan:\n"
+ "\n"
+ "\tdialplan -> outgoing Number\n"
+ "\tlocaldialplan -> callerid\n"
+ "\tcpndialplan -> connected party number\n"
+ "\n"
+ "\tdialplan options:\n"
+ "\n"
+ "\t0 - unknown\n"
+ "\t1 - International\n"
+ "\t2 - National\n"
+ "\t4 - Subscriber\n"
+ "\n"
+ "\tThis setting is used for outgoing calls." },
+ { "nationalprefix", "0",
+ "Prefix for national, this is put before the\n"
+ "\toad if an according dialplan is set by the other end." },
+ { "internationalprefix", "00",
+ "Prefix for international, this is put before the\n"
+ "\toad if an according dialplan is set by the other end." },
+ { "presentation", "-1",
+ "These (presentation and screen) are the exact isdn screening and presentation\n"
+ "\tindicators.\n"
+ "\tIf -1 is given for both values, the presentation indicators are used from\n"
+ "\tAsterisks SetCallerPres application.\n"
+ "\n"
+ "\tscreen=0, presentation=0 -> callerid presented not screened\n"
+ "\tscreen=1, presentation=1 -> callerid presented but screened (the remote end doesn't see it!)" },
+ { "screen", "-1",
+ "These (presentation and screen) are the exact isdn screening and presentation\n"
+ "\tindicators.\n"
+ "\tIf -1 is given for both values, the presentation indicators are used from\n"
+ "\tAsterisks SetCallerPres application.\n"
+ "\n"
+ "\tscreen=0, presentation=0 -> callerid presented not screened\n"
+ "\tscreen=1, presentation=1 -> callerid presented but screened (the remote end doesn't see it!)" },
+ { "always_immediate", "no",
+ "Enable this to get into the s dialplan-extension.\n"
+ "\tThere you can use DigitTimeout if you can't or don't want to use\n"
+ "\tisdn overlap dial.\n"
+ "\tNOTE: This will jump into the s extension for every exten!" },
+ { "nodialtone", "no",
+ "Enable this to prevent chan_misdn to generate the dialtone\n"
+ "\tThis makes only sense together with the always_immediate=yes option\n"
+ "\tto generate your own dialtone with Playtones or so."},
+ { "immediate", "no",
+ "Enable this if you want callers which called exactly the base\n"
+ "\tnumber (so no extension is set) to jump into the s extension.\n"
+ "\tIf the user dials something more, it jumps to the correct extension\n"
+ "\tinstead." },
+ { "senddtmf", "no",
+ "Enable this if we should produce DTMF Tones ourselves." },
+ { "hold_allowed", "no",
+ "Enable this to have support for hold and retrieve." },
+ { "early_bconnect", "yes",
+ "Disable this if you don't mind correct handling of Progress Indicators." },
+ { "incoming_early_audio", "no",
+ "Turn this on if you like to send Tone Indications to a Incoming\n"
+ "\tisdn channel on a TE Port. Rarely used, only if the Telco allows\n"
+ "\tyou to send indications by yourself, normally the Telco sends the\n"
+ "\tindications to the remote party." },
+ { "echocancel", "0",
+ "This enables echocancellation, with the given number of taps.\n"
+ "\tBe aware, move this setting only to outgoing portgroups!\n"
+ "\tA value of zero turns echocancellation off.\n"
+ "\n"
+ "\tPossible values are: 0, 32, 64, 128, 256, yes(=128), no(=0)" },
+ { "echocancelwhenbridged", "no",
+ "This disables echocancellation when the call is bridged between\n"
+ "\tmISDN channels." },
+ { "need_more_infos", "0",
+ "Send Setup_Acknowledge on incoming calls anyway (instead of PROCEEDING),\n"
+ "\tthis requests additional Infos, so we can waitfordigits without much\n"
+ "\tissues. This works only for PTP Ports" },
+ { "jitterbuffer", "4000",
+ "The jitterbuffer." },
+ { "jitterbuffer_upper_threshold", "0",
+ "Change this threshold to enable dejitter functionality." },
+ { "callgroup", 0,
+ "Callgroup." },
+ { "pickupgroup", 0,
+ "Pickupgroup." },
+ { "max_incoming", "-1",
+ "Defines the maximum amount of incoming calls per port for this group.\n"
+ "\tCalls which exceed the maximum will be marked with the channel varible\n"
+ "\tMAX_OVERFLOW. It will contain the amount of overflowed calls" },
+ { "max_outgoing", "-1",
+ "Defines the maximum amount of outgoing calls per port for this group\n"
+ "\texceeding calls will be rejected" },
+ { "reject_cause", "21",
+ "Defines the cause with which a third call is rejected on PTMP BRI." },
+ { "faxdetect", "no",
+ "Setup fax detection:\n"
+ "\t no - no fax detection\n"
+ "\t incoming - fax detection for incoming calls\n"
+ "\t outgoing - fax detection for outgoing calls\n"
+ "\t both - fax detection for incoming and outgoing calls\n"
+ "\tAdd +nojump to your value (i.e. faxdetect=both+nojump) if you don't want to jump into the\n"
+ "\tfax-extension but still want to detect the fax and prepare the channel for fax transfer." },
+ { "faxdetect_timeout", "5",
+ "Number of seconds the fax detection should do its job. After the given period of time,\n"
+ "\twe assume that it's not a fax call and save some CPU time by turning off fax detection.\n"
+ "\tSet this to 0 if you don't want a timeout (never stop detecting)." },
+ { "faxdetect_context", 0,
+ "Context to jump into if we detect a fax. Don't set this if you want to stay in the current context." },
+ { "l1watcher_timeout", "0",
+ "Watches the layer 1. If the layer 1 is down, it tries to\n"
+ "\tget it up. The timeout is given in seconds. with 0 as value it\n"
+ "\tdoes not watch the l1 at all\n"
+ "\n"
+ "\tThis option is only read at loading time of chan_misdn, which\n"
+ "\tmeans you need to unload and load chan_misdn to change the value,\n"
+ "\tan Asterisk restart should do the trick." },
+ { "overlapdial", "0",
+ "Enables overlap dial for the given amount of seconds.\n"
+ "\tPossible values are positive integers or:\n"
+ "\t yes (= 4 seconds)\n"
+ "\t no (= 0 seconds = disabled)" },
+ { "msns", 0,
+ "MSN's for TE ports, listen on those numbers on the above ports, and\n"
+ "\tindicate the incoming calls to Asterisk.\n"
+ "\tHere you can give a comma seperated list, or simply an '*' for any msn." },
+};
+
+enum {
+ MCFG_GROUPNAME = 0,
+ MCFG_PORTS,
+ MCFG_ALLOWED_BEARERS,
+ MCFG_RXGAIN,
+ MCFG_TXGAIN,
+ MCFG_TE_CHOOSE_CHANNEL,
+ MCFG_FAR_ALERTING,
+ MCFG_PMP_L1_CHECK,
+ MCFG_BLOCK_ON_ALARM,
+ MCFG_HDLC,
+ MCFG_CONTEXT,
+ MCFG_LANGUAGE,
+ MCFG_MUSICCLASS,
+ MCFG_CALLERID,
+ MCFG_METHOD,
+ MCFG_METHOD_PARMS,
+ MCFG_DIALPLAN,
+ MCFG_LOCALDIALPLAN,
+ MCFG_CPNDIALPLAN,
+ MCFG_NATIONALPREFIX,
+ MCFG_INTERNATIONALPREFIX,
+ MCFG_PRESENTATION,
+ MCFG_SCREEN,
+ MCFG_ALWAYS_IMMEDIATE,
+ MCFG_NODIALTONE,
+ MCFG_IMMEDIATE,
+ MCFG_SENDDTMF,
+ MCFG_HOLDALLOWED,
+ MCFG_EARLY_BCONNECT,
+ MCFG_INCOMING_EARLY_AUDIO,
+ MCFG_ECHOCANCEL,
+ MCFG_ECHOCANCELWHENBRIDGED,
+ MCFG_NEED_MORE_INFOS,
+ MCFG_JITTERBUFFER,
+ MCFG_JITTERBUFFER_UPPER_THRES,
+ MCFG_CALLGROUP,
+ MCFG_PICKUPGROUP,
+ MCFG_MAX_INCOMING,
+ MCFG_MAX_OUTGOING,
+ MCFG_REJECT_CAUSE,
+ MCFG_FAXDETECT,
+ MCFG_FAXDETECT_TIMEOUT,
+ MCFG_FAXDETECT_CONTEXT,
+ MCFG_L1WATCHER_TIMEOUT,
+ MCFG_OVERLAPDIAL,
+ MCFG_MSNS,
+ MCFG_PORT_END
+};
+
+static const cm_section_t config_sections[] = {
+ { "general", NULL, NULL, KTYPE_NONE, sizeof(gen_dirs) / sizeof(cm_dir_t), gen_dirs },
+ { "port", "default", "ports", KTYPE_INTEGER, sizeof(port_dirs) / sizeof(cm_dir_t), port_dirs },
+};
+
+enum {
+ GENERAL = 0,
+ PORT
+};
+
+static int config_load (void)
+{
+ int cfg_debug = 0,
+ i;
+
+ misdn_cm = cm_create("misdn", config_sections, sizeof(config_sections) / sizeof(cm_section_t));
+ if (!misdn_cm) {
+ ast_log(LOG_ERROR, "Unable to create misdn configman object!\n");
+ return -1;
+ }
+ if (cm_load(misdn_cm, "misdn.conf")) {
+ ast_log(LOG_ERROR, "Unable to load misdn.conf\n");
+ cm_destroy(misdn_cm);
+ misdn_cm = NULL;
+ return -1;
+ }
+
+ cm_get(misdn_cm, tracefile, BUFFERSIZE, GENERAL, MCFG_TRACEFILE);
+ cm_get_int(misdn_cm, cfg_debug, GENERAL, MCFG_DEBUG);
+ if (cfg_debug < 0)
+ cfg_debug = 0;
+
+ misdn_debug = (int *)malloc(sizeof(int) * (max_ports + 1));
+ misdn_debug_only = (int *)calloc(max_ports + 1, sizeof(int));
+ misdn_ports = (int *)malloc(sizeof(int) * (max_ports + 1));
+
+ for (i = 0; i <= max_ports; ++i) {
+ misdn_debug[i] = cfg_debug;
+ misdn_ports[i] = i;
+ }
+
+ return 0;
+}
+
+static void config_destroy (void)
+{
+ if (misdn_cm) {
+ cm_destroy(misdn_cm);
+ misdn_cm = NULL;
+ }
+ if (misdn_debug) {
+ free(misdn_debug);
+ misdn_debug = NULL;
+ }
+ if (misdn_debug_only) {
+ free(misdn_debug_only);
+ misdn_debug_only = NULL;
+ }
+ if (misdn_ports) {
+ free(misdn_ports);
+ misdn_debug_only = NULL;
+ }
+}
+
+static int config_reload (void)
+{
+ config_destroy();
+ return config_load();
+}
+
+/* Logger Function */
+static void chan_misdn_log (int level, int port, char *tmpl, ...)
+{
+ va_list ap;
+ char buf[1024],
+ port_buf[8];
+ time_t tm;
+ char *tmp,
+ *p;
+ FILE *fp;
+
+ 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;
+ }
+
+ sprintf(port_buf, "P[%2d] ", port);
+
+ va_start(ap, tmpl);
+ vsnprintf(buf, sizeof(buf) - 1, tmpl, ap);
+ va_end(ap);
+
+ if (level == -1) {
+ ast_log(LOG_WARNING, 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(tracefile)) {
+ fp = fopen(tracefile, "a+");
+ if (!fp) {
+ ast_console_puts("Error opening Tracefile: [ ");
+ ast_console_puts(tracefile);
+ ast_console_puts(" ] ");
+ ast_console_puts(strerror(errno));
+ ast_console_puts("\n");
+ return ;
+ }
+ tm = time(NULL);
+ tmp = ctime(&tm);
+ p = strchr(tmp, '\n');
+ if (p)
+ *p = ':';
+ fputs(tmp, fp);
+ fputs(" ", fp);
+ fputs(port_buf, fp);
+ fputs(" ", fp);
+ fputs(buf, fp);
+ fclose(fp);
+ }
+}
+
+/* Channel Selection */
+static void * misdn_occupy (void *priv)
+{
+ struct misdn_csel_item *item = priv;
+ struct misdn_bchannel *bc;
+ int l1check,
+ port_up;
+
+ if (cm_get_int(misdn_cm, l1check, PORT, MCFG_PMP_L1_CHECK, item->port))
+ l1check = 0;
+
+ port_up = misdn_lib_port_up(item->port, l1check);
+
+ if (l1check && !port_up)
+ chan_misdn_log(0, item->port, "misdn_occupy: L1 is down!\n");
+
+ if (l1check && port_up < 0)
+ ast_log(LOG_WARNING, "misdn_occupy: port %d is blocked!\n", item->port);
+
+ if (port_up > 0) {
+ bc = misdn_lib_get_free_bc(item->port, item->chan, 0);
+ if (bc) {
+ chan_misdn_log(0, item->port, "misdn_occupy: success! occupied port:%d channel:%d\n", item->port, item->chan);
+ return bc;
+ }
+ }
+
+ return NULL;
+}
+
+static void misdn_csel_init (void)
+{
+ int port,
+ num_chans,
+ i,
+ *prev = NULL;
+ char buf[BUFFERSIZE],
+ method[BUFFERSIZE],
+ params[BUFFERSIZE];
+ struct csel *cs = NULL;
+ struct misdn_csel_item *item;
+
+ AST_HASH_INIT_STR(&group_csel_hash, 512);
+
+ for (; cm_get_next_id(misdn_cm, PORT, prev, &port); prev = &port) {
+ if (!cm_get(misdn_cm, buf, sizeof(buf), PORT, MCFG_GROUPNAME, port)) {
+ num_chans = misdn_lib_get_maxchans(port);
+ if (!num_chans)
+ continue;
+ if (AST_HASH_LOOKUP(&group_csel_hash, buf, cs)) {
+ cm_get(misdn_cm, method, sizeof(method), PORT, MCFG_METHOD, port);
+ cm_get(misdn_cm, params, sizeof(params), PORT, MCFG_METHOD_PARMS, port);
+ cs = csel_create(method, params, misdn_occupy, free);
+ if (!cs)
+ continue;
+ AST_HASH_INSERT(&group_csel_hash, strdup(buf), cs);
+ }
+ for (i = 1; i <= num_chans; ++i) {
+ item = malloc(sizeof(struct misdn_csel_item));
+ item->port = port;
+ item->chan = i;
+ csel_add(cs, item);
+ }
+ }
+ }
+}
+
+static void misdn_csel_destroy (void)
+{
+ char * key;
+ struct csel * val;
+ int i;
+
+ AST_HASH_LOCK(&group_csel_hash);
+ AST_HASH_TRAVERSE_NOLOCK(&group_csel_hash, key, val, i)
+ csel_destroy(val);
+ AST_HASH_UNLOCK(&group_csel_hash);
+ AST_HASH_DESTROY(&group_csel_hash);
+}
+
+/* Chanlist Helpers */
+static struct chan_list * init_chan_list (int orig)
+{
+ struct chan_list *cl = calloc(1, sizeof(struct chan_list));
+
+ if (!cl) {
+ chan_misdn_log(-1, 0, "misdn_request: malloc failed!");
+ return NULL;
+ }
+
+ cl->orginator = orig;
+ cl->need_queue_hangup = 1;
+ cl->need_hangup = 1;
+ cl->need_busy = 1;
+ cl->overlap_dial_task = -1;
+
+ return cl;
+}
+
+static void cl_queue_chan(struct chan_list **list, struct chan_list *chan)
+{
+ struct chan_list *help = *list;
+
+ 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 {
+ for (; help->next; help = help->next);
+ help->next = chan;
+ }
+ chan->next = NULL;
+ ast_mutex_unlock(&cl_te_lock);
+}
+
+static void cl_dequeue_chan (struct chan_list **list, struct chan_list *chan)
+{
+ struct chan_list *help = *list;
+
+ if (chan->dsp)
+ ast_dsp_free(chan->dsp);
+
+ if (chan->trans)
+ ast_translator_free_path(chan->trans);
+
+ ast_mutex_lock(&cl_te_lock);
+ if (!help) {
+ ast_mutex_unlock(&cl_te_lock);
+ return;
+ }
+
+ if (help == chan)
+ *list = help->next;
+ else
+ for (; help->next; help = help->next) {
+ if (help->next == chan) {
+ help->next = chan->next;
+ break;
+ }
+ }
- enum misdn_chan_state state;
- int need_queue_hangup;
- int need_hangup;
- int need_busy;
+ ast_mutex_unlock(&cl_te_lock);
+}
+
+static struct chan_list * find_chan_by_bc (struct chan_list *list, struct misdn_bchannel *bc)
+{
+ for (; list; list = list->next)
+ if (list->bc == bc)
+ return list;
+
+ 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)
+{
+ for (; list; list = list->next)
+ if (list->bc && list->bc->pid == pid)
+ return list;
+
+ chan_misdn_log(6, 0, "$$$ find_chan: No channel found for pid:%d\n", pid);
+ return NULL;
+}
+
+static struct chan_list * find_holded (struct chan_list *list, struct misdn_bchannel *bc)
+{
+ for (; list; list = list->next) {
+ chan_misdn_log(4, bc->port, "$$$ find_holded: --> holded:%d channel:%d\n",
+ list->state == MISDN_HOLDED, list->hold_info.channel);
+ if (list->state == MISDN_HOLDED && list->hold_info.port == bc->port)
+ return list;
+ }
- int orginator;
-
- int norxtone;
- int notxtone;
-
- int toggle_ec;
-
- int incoming_early_audio;
-
- int ignore_dtmf;
-
- int pipe[2];
- char ast_rd_buf[4096];
- struct ast_frame frame;
-
- int faxdetect; /* 0:no 1:yes 2:yes+nojump */
- int faxdetect_timeout;
- struct timeval faxdetect_tv;
- int faxhandled;
-
- int ast_dsp;
-
- int jb_len;
- int jb_upper_threshold;
+ 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_holded_l3 (struct chan_list *list, unsigned long l3_id, int w)
+{
+ for (; list; list = list->next)
+ if (list->state == MISDN_HOLDED && list->l3id == l3_id)
+ return list;
+
+ return NULL;
+}
+
+/* Jitterbuffer */
+static struct misdn_jb * misdn_jb_init (int size, int upper_threshold)
+{
struct misdn_jb *jb;
-
- struct ast_dsp *dsp;
- struct ast_trans_pvt *trans;
-
- struct ast_channel * ast;
-
- int dummy;
-
- struct misdn_bchannel *bc;
-
- struct hold_info hold_info;
-
- unsigned int l3id;
- int addr;
-
- char context[BUFFERSIZE];
-
- int zero_read_cnt;
- int dropped_frame_cnt;
-
- int far_alerting;
- int other_pid;
- struct chan_list *other_ch;
-
- const struct tone_zone_sound *ts;
-
- int overlap_dial;
- int overlap_dial_task;
- ast_mutex_t overlap_tv_lock;
- struct timeval overlap_tv;
-
- struct chan_list *peer;
- struct chan_list *next;
- struct chan_list *prev;
- struct chan_list *first;
+
+ jb = calloc(1, sizeof(struct misdn_jb));
+ jb->size = size;
+ jb->upper_threshold = upper_threshold;
+ jb->samples = malloc(size * sizeof(char));
+ jb->ok = calloc(size, sizeof(char));
+ ast_mutex_init(&jb->lock);
+
+ return jb;
+}
+
+static void misdn_jb_destroy (struct misdn_jb *jb)
+{
+ ast_mutex_destroy(&jb->lock);
+ free(jb->ok);
+ free(jb->samples);
+ free(jb);
+}
+
+static int misdn_jb_fill (struct misdn_jb *jb, const char *data, int len)
+{
+ int i,
+ j,
+ rp,
+ wp;
+
+ if (!jb || !data)
+ return 0;
+
+ ast_mutex_lock(&jb->lock);
+
+ 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;
+
+ 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->lock);
+ 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->lock);
+ return 0;
+}
+
+static int misdn_jb_empty (struct misdn_jb *jb, char *data, int len)
+{
+ int i,
+ wp,
+ rp,
+ read = 0;
+
+ ast_mutex_lock(&jb->lock);
+
+ 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->lock);
+ 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;
+ jb->rp = rp;
+ }
+
+ ast_mutex_unlock(&jb->lock);
+ return read;
+}
+
+static int bc_jb_empty (struct misdn_bchannel *bc, char *buf, int len)
+{
+ 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;
+}
+
+/* mISDN Tech Function Headers */
+static struct ast_channel * misdn_request (const char *type, int format, void *data, int *cause);
+static int misdn_digit_begin (struct ast_channel *chan, char digit);
+static int misdn_digit_end (struct ast_channel *ast, char digit);
+static int misdn_call (struct ast_channel *ast, char *dest, int timeout);
+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_hangup (struct ast_channel *ast);
+static int misdn_answer (struct ast_channel *ast);
+static struct ast_frame * misdn_read (struct ast_channel *ast);
+static int misdn_write (struct ast_channel *ast, struct ast_frame *frame);
+static int misdn_indication (struct ast_channel *ast, int cond, const void *data, size_t datalen);
+static int misdn_fixup (struct ast_channel *oldast, struct ast_channel *ast);
+static int misdn_send_text (struct ast_channel *chan, const char *text);
+
+/* Other Function Headers */
+static int misdn_set_opt_exec (struct ast_channel *chan, void *data);
+static int config_bc_echocancel (struct misdn_bchannel *bc);
+
+/* Tech Structs */
+static struct ast_channel_tech misdn_tech = {
+ .type = "mISDN",
+ .description = "Channel driver for mISDN Support (Bri/Pri)",
+ .capabilities = AST_FORMAT_ALAW,
+ .requester = misdn_request,
+ .send_digit_begin = misdn_digit_begin,
+ .send_digit_end = misdn_digit_end,
+ .call = misdn_call,
+ .bridge = misdn_bridge,
+ .hangup = misdn_hangup,
+ .answer = misdn_answer,
+ .read = misdn_read,
+ .write = misdn_write,
+ .indicate = misdn_indication,
+ .fixup = misdn_fixup,
+ .send_text = misdn_send_text,
+ .properties = 0
};
-
-
-void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
-void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
-
-struct robin_list {
- char *group;
- int port;
- int channel;
- struct robin_list *next;
- struct robin_list *prev;
+static struct ast_channel_tech misdn_tech_wo_bridge = {
+ .type = "mISDN",
+ .description = "Channel driver for mISDN Support (Bri/Pri)",
+ .capabilities = AST_FORMAT_ALAW,
+ .requester = misdn_request,
+ .send_digit_begin = misdn_digit_begin,
+ .send_digit_end = misdn_digit_end,
+ .call = misdn_call,
+ .hangup = misdn_hangup,
+ .answer = misdn_answer,
+ .read = misdn_read,
+ .write = misdn_write,
+ .indicate = misdn_indication,
+ .fixup = misdn_fixup,
+ .send_text = misdn_send_text,
+ .properties = 0
};
-static struct robin_list *robin = NULL;
-
-
-
-static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame);
-
-
-
-static inline void free_robin_list_r (struct robin_list *r)
-{
- if (r) {
- if (r->next) free_robin_list_r(r->next);
- if (r->group) free(r->group);
- free(r);
- }
-}
-
-static void free_robin_list ( void )
-{
- free_robin_list_r(robin);
- robin = NULL;
-}
-
-static struct robin_list* get_robin_position (char *group)
-{
- struct robin_list *iter = robin;
- for (; iter; iter = iter->next) {
- if (!strcasecmp(iter->group, group))
- return iter;
- }
- struct robin_list *new = (struct robin_list *)calloc(1, sizeof(struct robin_list));
- new->group = strndup(group, strlen(group));
- new->channel = 1;
- if (robin) {
- new->next = robin;
- robin->prev = new;
- }
- robin = new;
- return robin;
-}
-
-
-/* the main schedule context for stuff like l1 watcher, overlap dial, ... */
-static struct sched_context *misdn_tasks = NULL;
-static pthread_t misdn_tasks_thread;
-
-static int *misdn_ports;
-
-static void chan_misdn_log(int level, int port, char *tmpl, ...);
-
-static struct ast_channel *misdn_new(struct chan_list *cl, int state, char *exten, char *callerid, int format, int port, int c);
-static void send_digit_to_chan(struct chan_list *cl, char digit );
-
-static void hangup_chan(struct chan_list *ch);
-static int pbx_start_chan(struct chan_list *ch);
-
-
-#define AST_CID_P(ast) ast->cid.cid_num
-#define AST_BRIDGED_P(ast) ast_bridged_channel(ast)
-#define AST_LOAD_CFG ast_config_load
-#define AST_DESTROY_CFG ast_config_destroy
-
-#define MISDN_ASTERISK_TECH_PVT(ast) ast->tech_pvt
-#define MISDN_ASTERISK_PVT(ast) 1
-
-#include <asterisk/strings.h>
-
-/* #define MISDN_DEBUG 1 */
-
-static const char misdn_type[] = "mISDN";
-
-static int tracing = 0 ;
-
-static char **misdn_key_vector=NULL;
-static int misdn_key_vector_size=0;
-
-/* Only alaw and mulaw is allowed for now */
-static int prefformat = AST_FORMAT_ALAW ; /* AST_FORMAT_SLINEAR ; AST_FORMAT_ULAW | */
-
-static int *misdn_debug;
-static int *misdn_debug_only;
-static int max_ports;
-
-static int *misdn_in_calls;
-static int *misdn_out_calls;
-
-
-struct chan_list dummy_cl;
-
-struct chan_list *cl_te=NULL;
-ast_mutex_t cl_te_lock;
-
-static enum event_response_e
-cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);
-
-static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc, struct chan_list *ch);
-
-static void cl_queue_chan(struct chan_list **list, struct chan_list *chan);
-static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan);
-static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc);
-static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid);
-
-
-
-static int dialtone_indicate(struct chan_list *cl);
-static int hanguptone_indicate(struct chan_list *cl);
-static int stop_indicate(struct chan_list *cl);
-
-static int start_bc_tones(struct chan_list *cl);
-static int stop_bc_tones(struct chan_list *cl);
-static void release_chan(struct misdn_bchannel *bc);
-
-static int misdn_set_opt_exec(struct ast_channel *chan, void *data);
-static int misdn_facility_exec(struct ast_channel *chan, void *data);
-
-int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
-
-
-void debug_numplan(int port, int numplan, char *type);
-
-
-int add_out_calls(int port);
-int add_in_calls(int port);
-
-
-static int update_ec_config(struct misdn_bchannel *bc);
-
-
-
-
-/*protos*/
-
-int chan_misdn_jb_empty ( struct misdn_bchannel *bc, char *buf, int len);
-
-/*************** Helpers *****************/
-
-static struct chan_list * get_chan_by_ast(struct ast_channel *ast)
+
+static struct allowed_bearer allowed_bearers[] = {
+ { INFO_CAPABILITY_SPEECH, "speech", "Speech" },
+ { INFO_CAPABILITY_AUDIO_3_1K, "3_1khz", "Audio 3.1k" },
+ { INFO_CAPABILITY_DIGITAL_UNRESTRICTED, "digital_unrestricted", "Unres Digital" },
+ { INFO_CAPABILITY_DIGITAL_RESTRICTED, "digital_restriced", "Res Digital" },
+ { INFO_CAPABILITY_VIDEO, "video", "Video" }
+};
+
+/* Simple Helpers */
+static struct chan_list * get_chan_by_ast (struct ast_channel *ast)
{
struct chan_list *tmp;
-
- for (tmp=cl_te; tmp; tmp = tmp->next) {
- if ( tmp->ast == ast ) return 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 struct chan_list * get_chan_by_ast_name (char *name)
{
struct chan_list *tmp;
-
- for (tmp=cl_te; tmp; tmp = tmp->next) {
- if ( tmp->ast && strcmp(tmp->ast->name,name) == 0) return tmp;
- }
-
+
+ for (tmp = cl_te; tmp; tmp = tmp->next)
+ if (tmp->ast && !strcmp(tmp->ast->name, name))
+ return tmp;
+
return NULL;
}
-
-
-struct allowed_bearers {
- int cap;
- int val;
- char *name;
-};
-
-struct allowed_bearers allowed_bearers_array[]={
- {INFO_CAPABILITY_SPEECH,1,"speech"},
- {INFO_CAPABILITY_AUDIO_3_1K,2,"3_1khz"},
- {INFO_CAPABILITY_DIGITAL_UNRESTRICTED,4,"digital_unrestricted"},
- {INFO_CAPABILITY_DIGITAL_RESTRICTED,8,"digital_restriced"},
- {INFO_CAPABILITY_VIDEO,16,"video"}
-};
-
-static char *bearer2str(int cap) {
- static char *bearers[]={
- "Speech",
- "Audio 3.1k",
- "Unres Digital",
- "Res Digital",
- "Video",
- "Unknown Bearer"
+static char * get_ch_state (struct chan_list *p)
+{
+ struct ch_state {
+ enum misdn_chan_state state;
+ char txt[255] ;
};
-
+ static struct ch_state ch_states[] = {
+ { MISDN_NOTHING, "NOTHING" }, /* at beginning */
+ { MISDN_WAITING4DIGS, "WAITING4DIGS" }, /* when waiting for infos */
[... 7631 lines stripped ...]
More information about the asterisk-commits
mailing list