Sat Nov 1 06:28:26 2008

Asterisk developer's documentation


chan_misdn.c

Go to the documentation of this file.
00001 /*
00002  * Asterisk -- An open source telephony toolkit.
00003  * 
00004  * Copyright (C) 2004 - 2006, Christian Richter
00005  *
00006  * Christian Richter <crich@beronet.com>
00007  *
00008  * See http://www.asterisk.org for more information about
00009  * the Asterisk project. Please do not directly contact
00010  * any of the maintainers of this project for assistance;
00011  * the project provides a web site, mailing lists and IRC
00012  * channels for your use.
00013  *
00014  * This program is free software, distributed under the terms of
00015  * the GNU General Public License Version 2. See the LICENSE file
00016  * at the top of the source tree.
00017  *
00018  */
00019 
00020 /*!
00021  * \file
00022  *
00023  * \brief the chan_misdn channel driver for Asterisk
00024  *
00025  * \author Christian Richter <crich@beronet.com>
00026  *
00027  * \extref MISDN http://www.misdn.org/
00028  *
00029  * \ingroup channel_drivers
00030  */
00031 
00032 /*** MODULEINFO
00033    <depend>isdnnet</depend>
00034    <depend>misdn</depend>
00035    <depend>suppserv</depend>
00036  ***/
00037 #include "asterisk.h"
00038 
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 150124 $")
00040 
00041 #include <stdio.h>
00042 #include <pthread.h>
00043 #include <string.h>
00044 #include <sys/socket.h>
00045 #include <sys/time.h>
00046 #include <errno.h>
00047 #include <unistd.h>
00048 #include <stdlib.h>
00049 #include <arpa/inet.h>
00050 #include <fcntl.h>
00051 #include <sys/ioctl.h>
00052 #include <signal.h>
00053 #include <sys/file.h>
00054 #include <semaphore.h>
00055 
00056 #include "asterisk/channel.h"
00057 #include "asterisk/config.h"
00058 #include "asterisk/logger.h"
00059 #include "asterisk/module.h"
00060 #include "asterisk/pbx.h"
00061 #include "asterisk/options.h"
00062 #include "asterisk/io.h"
00063 #include "asterisk/frame.h"
00064 #include "asterisk/translate.h"
00065 #include "asterisk/cli.h"
00066 #include "asterisk/musiconhold.h"
00067 #include "asterisk/dsp.h"
00068 #include "asterisk/translate.h"
00069 #include "asterisk/config.h"
00070 #include "asterisk/file.h"
00071 #include "asterisk/callerid.h"
00072 #include "asterisk/indications.h"
00073 #include "asterisk/app.h"
00074 #include "asterisk/features.h"
00075 #include "asterisk/term.h"
00076 #include "asterisk/sched.h"
00077 #include "asterisk/stringfields.h"
00078 #include "asterisk/causes.h"
00079 
00080 #include "chan_misdn_config.h"
00081 #include "isdn_lib.h"
00082 
00083 char global_tracefile[BUFFERSIZE + 1];
00084 
00085 static int g_config_initialized = 0;
00086 
00087 struct misdn_jb{
00088    int size;
00089    int upper_threshold;
00090    char *samples, *ok;
00091    int wp,rp;
00092    int state_empty;
00093    int state_full;
00094    int state_buffer;
00095    int bytes_wrote;
00096    ast_mutex_t mutexjb;
00097 };
00098 
00099 
00100 
00101 /*! \brief allocates the jb-structure and initialize the elements */
00102 struct misdn_jb *misdn_jb_init(int size, int upper_threshold);
00103 
00104 /*! \brief frees the data and destroys the given jitterbuffer struct */
00105 void misdn_jb_destroy(struct misdn_jb *jb);
00106 
00107 /*! \brief fills the jitterbuffer with len data returns < 0 if there was an
00108 error (buffer overrun). */
00109 int misdn_jb_fill(struct misdn_jb *jb, const char *data, int len);
00110 
00111 /*! \brief gets len bytes out of the jitterbuffer if available, else only the
00112 available data is returned and the return value indicates the number
00113 of data. */
00114 int misdn_jb_empty(struct misdn_jb *jb, char *data, int len);
00115 
00116 
00117 /* BEGIN: chan_misdn.h */
00118 
00119 ast_mutex_t release_lock;
00120 
00121 enum misdn_chan_state {
00122    MISDN_NOTHING=0,  /*!< at beginning */
00123    MISDN_WAITING4DIGS, /*!<  when waiting for infos */
00124    MISDN_EXTCANTMATCH, /*!<  when asterisk couldn't match our ext */
00125    MISDN_INCOMING_SETUP, /*!<  for incoming setups*/
00126    MISDN_DIALING, /*!<  when pbx_start */
00127    MISDN_PROGRESS, /*!<  we got a progress */
00128    MISDN_PROCEEDING, /*!<  we got a progress */
00129    MISDN_CALLING, /*!<  when misdn_call is called */
00130    MISDN_CALLING_ACKNOWLEDGE, /*!<  when we get SETUP_ACK */
00131    MISDN_ALERTING, /*!<  when Alerting */
00132    MISDN_BUSY, /*!<  when BUSY */
00133    MISDN_CONNECTED, /*!<  when connected */
00134    MISDN_PRECONNECTED, /*!<  when connected */
00135    MISDN_DISCONNECTED, /*!<  when connected */
00136    MISDN_RELEASED, /*!<  when connected */
00137    MISDN_BRIDGED, /*!<  when bridged */
00138    MISDN_CLEANING, /*!< when hangup from * but we were connected before */
00139    MISDN_HUNGUP_FROM_MISDN, /*!< when DISCONNECT/RELEASE/REL_COMP  came from misdn */
00140    MISDN_HUNGUP_FROM_AST, /*!< when DISCONNECT/RELEASE/REL_COMP came out of misdn_hangup */
00141    MISDN_HOLDED, /*!< if this chan is holded */
00142    MISDN_HOLD_DISCONNECT, /*!< if this chan is holded */
00143   
00144 };
00145 
00146 #define ORG_AST 1
00147 #define ORG_MISDN 2
00148 
00149 struct hold_info {
00150    int port;
00151    int channel;
00152 };
00153 
00154 struct chan_list {
00155   
00156    char allowed_bearers[BUFFERSIZE + 1];
00157    
00158    enum misdn_chan_state state;
00159    int need_queue_hangup;
00160    int need_hangup;
00161    int need_busy;
00162    
00163    int originator;
00164    int noautorespond_on_setup;
00165    
00166    int norxtone;
00167    int notxtone; 
00168 
00169    int toggle_ec;
00170    
00171    int incoming_early_audio;
00172 
00173    int ignore_dtmf;
00174 
00175    int pipe[2];
00176    char ast_rd_buf[4096];
00177    struct ast_frame frame;
00178 
00179    int faxdetect; /*!<  0:no 1:yes 2:yes+nojump */
00180    int faxdetect_timeout;
00181    struct timeval faxdetect_tv;
00182    int faxhandled;
00183 
00184    int ast_dsp;
00185 
00186    int jb_len;
00187    int jb_upper_threshold;
00188    struct misdn_jb *jb;
00189    
00190    struct ast_dsp *dsp;
00191    struct ast_trans_pvt *trans;
00192   
00193    struct ast_channel * ast;
00194 
00195    int dummy;
00196   
00197    struct misdn_bchannel *bc;
00198 
00199    struct hold_info hold_info;
00200 
00201    unsigned int l3id;
00202    int addr;
00203 
00204    char context[BUFFERSIZE];
00205 
00206    int zero_read_cnt;
00207    int dropped_frame_cnt;
00208 
00209    int far_alerting;
00210 
00211    int nttimeout;
00212 
00213    int other_pid;
00214    struct chan_list *other_ch;
00215 
00216    const struct ind_tone_zone_sound *ts;
00217    
00218    int overlap_dial;
00219    int overlap_dial_task;
00220    ast_mutex_t overlap_tv_lock;
00221    struct timeval overlap_tv;
00222   
00223    struct chan_list *peer;
00224    struct chan_list *next;
00225    struct chan_list *prev;
00226    struct chan_list *first;
00227 };
00228 
00229 
00230 
00231 void export_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
00232 void import_ch(struct ast_channel *chan, struct misdn_bchannel *bc, struct chan_list *ch);
00233 
00234 struct robin_list {
00235    char *group;
00236    int port;
00237    int channel;
00238    struct robin_list *next;
00239    struct robin_list *prev;
00240 };
00241 static struct robin_list *robin = NULL;
00242 
00243 
00244 
00245 static struct ast_frame *process_ast_dsp(struct chan_list *tmp, struct ast_frame *frame);
00246 
00247 
00248 
00249 static inline void free_robin_list_r (struct robin_list *r)
00250 {
00251    if (r) {
00252       if (r->next)
00253          free_robin_list_r(r->next);
00254       if (r->group)
00255          free(r->group);
00256       free(r);
00257    }
00258 }
00259 
00260 static void free_robin_list ( void )
00261 {
00262    free_robin_list_r(robin);
00263    robin = NULL;
00264 }
00265 
00266 static struct robin_list* get_robin_position (char *group) 
00267 {
00268    struct robin_list *new;
00269    struct robin_list *iter = robin;
00270    for (; iter; iter = iter->next) {
00271       if (!strcasecmp(iter->group, group))
00272          return iter;
00273    }
00274    new = (struct robin_list *) calloc(1, sizeof(struct robin_list));
00275    new->group = strndup(group, strlen(group));
00276    new->port = 0;
00277    new->channel = 0;
00278    if (robin) {
00279       new->next = robin;
00280       robin->prev = new;
00281    }
00282    robin = new;
00283    return robin;
00284 }
00285 
00286 
00287 /*! \brief the main schedule context for stuff like l1 watcher, overlap dial, ... */
00288 static struct sched_context *misdn_tasks = NULL;
00289 static pthread_t misdn_tasks_thread;
00290 
00291 static int *misdn_ports;
00292 
00293 static void chan_misdn_log(int level, int port, char *tmpl, ...)
00294    __attribute__ ((format (printf, 3, 4)));
00295 
00296 static struct ast_channel *misdn_new(struct chan_list *cl, int state,  char *exten, char *callerid, int format, int port, int c);
00297 static void send_digit_to_chan(struct chan_list *cl, char digit );
00298 
00299 static void hangup_chan(struct chan_list *ch);
00300 static int pbx_start_chan(struct chan_list *ch);
00301 
00302 #define MISDN_ASTERISK_TECH_PVT(ast) ast->tech_pvt
00303 #define MISDN_ASTERISK_PVT(ast) 1
00304 
00305 #include "asterisk/strings.h"
00306 
00307 /* #define MISDN_DEBUG 1 */
00308 
00309 static const char misdn_type[] = "mISDN";
00310 
00311 static int tracing = 0 ;
00312 
00313 /*! \brief Only alaw and mulaw is allowed for now */
00314 static int prefformat =  AST_FORMAT_ALAW ; /*  AST_FORMAT_SLINEAR ;  AST_FORMAT_ULAW | */
00315 
00316 static int *misdn_debug;
00317 static int *misdn_debug_only;
00318 static int max_ports;
00319 
00320 static int *misdn_in_calls;
00321 static int *misdn_out_calls;
00322 
00323 
00324 struct chan_list dummy_cl;
00325 
00326 struct chan_list *cl_te=NULL;
00327 ast_mutex_t cl_te_lock;
00328 
00329 static enum event_response_e
00330 cb_events(enum event_e event, struct misdn_bchannel *bc, void *user_data);
00331 
00332 static void send_cause2ast(struct ast_channel *ast, struct misdn_bchannel*bc, struct chan_list *ch);
00333 
00334 static void cl_queue_chan(struct chan_list **list, struct chan_list *chan);
00335 static void cl_dequeue_chan(struct chan_list **list, struct chan_list *chan);
00336 static struct chan_list *find_chan_by_bc(struct chan_list *list, struct misdn_bchannel *bc);
00337 static struct chan_list *find_chan_by_pid(struct chan_list *list, int pid);
00338 
00339 
00340 
00341 static int dialtone_indicate(struct chan_list *cl);
00342 static int hanguptone_indicate(struct chan_list *cl);
00343 static int stop_indicate(struct chan_list *cl);
00344 
00345 static int start_bc_tones(struct chan_list *cl);
00346 static int stop_bc_tones(struct chan_list *cl);
00347 static void release_chan(struct misdn_bchannel *bc);
00348 
00349 static int misdn_check_l2l1(struct ast_channel *chan, void *data);
00350 static int misdn_set_opt_exec(struct ast_channel *chan, void *data);
00351 static int misdn_facility_exec(struct ast_channel *chan, void *data);
00352 
00353 int chan_misdn_jb_empty(struct misdn_bchannel *bc, char *buf, int len);
00354 
00355 
00356 void debug_numplan(int port, int numplan, char *type);
00357 
00358 
00359 int add_out_calls(int port);
00360 int add_in_calls(int port);
00361 
00362 
00363 #ifdef MISDN_1_2
00364 static int update_pipeline_config(struct misdn_bchannel *bc);
00365 #else
00366 static int update_ec_config(struct misdn_bchannel *bc);
00367 #endif
00368 
00369 
00370 
00371 /*************** Helpers *****************/
00372 
00373 static struct chan_list * get_chan_by_ast(struct ast_channel *ast)
00374 {
00375    struct chan_list *tmp;
00376   
00377    for (tmp=cl_te; tmp; tmp = tmp->next) {
00378       if ( tmp->ast == ast ) return tmp;
00379    }
00380   
00381    return NULL;
00382 }
00383 
00384 static struct chan_list * get_chan_by_ast_name(char *name)
00385 {
00386    struct chan_list *tmp;
00387   
00388    for (tmp=cl_te; tmp; tmp = tmp->next) {
00389       if ( tmp->ast  && strcmp(tmp->ast->name,name) == 0) return tmp;
00390    }
00391   
00392    return NULL;
00393 }
00394 
00395 
00396 
00397 struct allowed_bearers {
00398    char *name;       /*!< Bearer capability name string used in /etc/misdn.conf allowed_bearers */
00399    char *display;    /*!< Bearer capability displayable name */
00400    int cap;       /*!< SETUP message bearer capability field code value */
00401    int deprecated;      /*!< TRUE if this entry is deprecated. (Misspelled or bad name to use) */
00402 };
00403 
00404 /* *INDENT-OFF* */
00405 static const struct allowed_bearers allowed_bearers_array[]= {
00406    /* Name,                      Displayable Name       Bearer Capability,                    Deprecated */
00407    { "speech",                  "Speech",               INFO_CAPABILITY_SPEECH,               0 },
00408    { "3_1khz",                  "3.1KHz Audio",         INFO_CAPABILITY_AUDIO_3_1K,           0 },
00409    { "digital_unrestricted",    "Unrestricted Digital", INFO_CAPABILITY_DIGITAL_UNRESTRICTED, 0 },
00410    { "digital_restricted",      "Restricted Digital",   INFO_CAPABILITY_DIGITAL_RESTRICTED,   0 },
00411    { "digital_restriced",       "Restricted Digital",   INFO_CAPABILITY_DIGITAL_RESTRICTED,   1 }, /* Allow misspelling for backwards compatibility */
00412    { "video",                   "Video",                INFO_CAPABILITY_VIDEO,                0 }
00413 };
00414 /* *INDENT-ON* */
00415 
00416 static const char *bearer2str(int cap)
00417 {
00418    unsigned index;
00419 
00420    for (index = 0; index < ARRAY_LEN(allowed_bearers_array); ++index) {
00421       if (allowed_bearers_array[index].cap == cap) {
00422          return allowed_bearers_array[index].display;
00423       }
00424    }  /* end for */
00425 
00426    return "Unknown Bearer";
00427 }
00428 
00429 
00430 static void print_facility(struct FacParm *fac, struct misdn_bchannel *bc)
00431 {
00432    switch (fac->Function) {
00433    case Fac_CD:
00434       chan_misdn_log(1,bc->port," --> calldeflect to: %s, screened: %s\n", fac->u.CDeflection.DeflectedToNumber,
00435          fac->u.CDeflection.PresentationAllowed ? "yes" : "no");
00436       break;
00437    case Fac_AOCDCurrency:
00438       if (fac->u.AOCDcur.chargeNotAvailable)
00439          chan_misdn_log(1,bc->port," --> AOCD currency: charge not available\n");
00440       else if (fac->u.AOCDcur.freeOfCharge)
00441          chan_misdn_log(1,bc->port," --> AOCD currency: free of charge\n");
00442       else if (fac->u.AOCDchu.billingId >= 0)
00443          chan_misdn_log(1,bc->port," --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s billingId:%d\n",
00444             fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
00445             (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDcur.billingId);
00446       else
00447          chan_misdn_log(1,bc->port," --> AOCD currency: currency:%s amount:%d multiplier:%d typeOfChargingInfo:%s\n",
00448             fac->u.AOCDcur.currency, fac->u.AOCDcur.currencyAmount, fac->u.AOCDcur.multiplier,
00449             (fac->u.AOCDcur.typeOfChargingInfo == 0) ? "subTotal" : "total");
00450       break;
00451    case Fac_AOCDChargingUnit:
00452       if (fac->u.AOCDchu.chargeNotAvailable)
00453          chan_misdn_log(1,bc->port," --> AOCD charging unit: charge not available\n");
00454       else if (fac->u.AOCDchu.freeOfCharge)
00455          chan_misdn_log(1,bc->port," --> AOCD charging unit: free of charge\n");
00456       else if (fac->u.AOCDchu.billingId >= 0)
00457          chan_misdn_log(1,bc->port," --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s billingId:%d\n",
00458             fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total", fac->u.AOCDchu.billingId);
00459       else
00460          chan_misdn_log(1,bc->port," --> AOCD charging unit: recordedUnits:%d typeOfChargingInfo:%s\n",
00461             fac->u.AOCDchu.recordedUnits, (fac->u.AOCDchu.typeOfChargingInfo == 0) ? "subTotal" : "total");
00462       break;
00463    default:
00464       chan_misdn_log(1,bc->port," --> unknown facility\n");
00465       break;
00466    }
00467 }
00468 
00469 static void print_bearer(struct misdn_bchannel *bc) 
00470 {
00471    
00472    chan_misdn_log(2, bc->port, " --> Bearer: %s\n",bearer2str(bc->capability));
00473    
00474    switch(bc->law) {
00475    case INFO_CODEC_ALAW:
00476       chan_misdn_log(2, bc->port, " --> Codec: Alaw\n");
00477       break;
00478    case INFO_CODEC_ULAW:
00479       chan_misdn_log(2, bc->port, " --> Codec: Ulaw\n");
00480       break;
00481    }
00482 }
00483 
00484 static void export_aoc_vars(int originator, struct ast_channel *ast, struct misdn_bchannel *bc)
00485 {
00486    char buf[128];
00487 
00488    if (!ast)
00489       return;
00490 
00491    if (originator == ORG_AST) {
00492       ast = ast_bridged_channel(ast);
00493       if (!ast)
00494          return;
00495    }
00496 
00497    switch (bc->AOCDtype) {
00498    case Fac_AOCDCurrency:
00499       pbx_builtin_setvar_helper(ast, "AOCD_Type", "currency");
00500       if (bc->AOCD.currency.chargeNotAvailable)
00501          pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
00502       else {
00503          pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
00504          if (bc->AOCD.currency.freeOfCharge)
00505             pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
00506          else {
00507             pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
00508             if (snprintf(buf, sizeof(buf), "%d %s", bc->AOCD.currency.currencyAmount * bc->AOCD.currency.multiplier, bc->AOCD.currency.currency) < sizeof(buf)) {
00509                pbx_builtin_setvar_helper(ast, "AOCD_Amount", buf);
00510                if (bc->AOCD.currency.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.currency.billingId) < sizeof(buf))
00511                   pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
00512             }
00513          }
00514       }
00515       break;
00516    case Fac_AOCDChargingUnit:
00517       pbx_builtin_setvar_helper(ast, "AOCD_Type", "charging_unit");
00518       if (bc->AOCD.chargingUnit.chargeNotAvailable)
00519          pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "no");
00520       else {
00521          pbx_builtin_setvar_helper(ast, "AOCD_ChargeAvailable", "yes");
00522          if (bc->AOCD.chargingUnit.freeOfCharge)
00523             pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "yes");
00524          else {
00525             pbx_builtin_setvar_helper(ast, "AOCD_FreeOfCharge", "no");
00526             if (snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.recordedUnits) < sizeof(buf)) {
00527                pbx_builtin_setvar_helper(ast, "AOCD_RecordedUnits", buf);
00528                if (bc->AOCD.chargingUnit.billingId >= 0 && snprintf(buf, sizeof(buf), "%d", bc->AOCD.chargingUnit.billingId) < sizeof(buf))
00529                   pbx_builtin_setvar_helper(ast, "AOCD_BillingId", buf);
00530             }
00531          }
00532       }
00533       break;
00534    default:
00535       break;
00536    }
00537 }
00538 
00539 /*************** Helpers END *************/
00540 
00541 static void sighandler(int sig)
00542 {}
00543 
00544 static void* misdn_tasks_thread_func (void *data)
00545 {
00546    int wait;
00547    struct sigaction sa;
00548 
00549    sa.sa_handler = sighandler;
00550    sa.sa_flags = SA_NODEFER;
00551    sigemptyset(&sa.sa_mask);
00552    sigaddset(&sa.sa_mask, SIGUSR1);
00553    sigaction(SIGUSR1, &sa, NULL);
00554    
00555    sem_post((sem_t *)data);
00556 
00557    while (1) {
00558       wait = ast_sched_wait(misdn_tasks);
00559       if (wait < 0)
00560          wait = 8000;
00561       if (poll(NULL, 0, wait) < 0)
00562          chan_misdn_log(4, 0, "Waking up misdn_tasks thread\n");
00563       ast_sched_runq(misdn_tasks);
00564    }
00565    return NULL;
00566 }
00567 
00568 static void misdn_tasks_init (void)
00569 {
00570    sem_t blocker;
00571    int i = 5;
00572 
00573    if (sem_init(&blocker, 0, 0)) {
00574       perror("chan_misdn: Failed to initialize semaphore!");
00575       exit(1);
00576    }
00577 
00578    chan_misdn_log(4, 0, "Starting misdn_tasks thread\n");
00579    
00580    misdn_tasks = sched_context_create();
00581    pthread_create(&misdn_tasks_thread, NULL, misdn_tasks_thread_func, &blocker);
00582 
00583    while (sem_wait(&blocker) && --i);
00584    sem_destroy(&blocker);
00585 }
00586 
00587 static void misdn_tasks_destroy (void)
00588 {
00589    if (misdn_tasks) {
00590       chan_misdn_log(4, 0, "Killing misdn_tasks thread\n");
00591       if ( pthread_cancel(misdn_tasks_thread) == 0 ) {
00592          cb_log(4, 0, "Joining misdn_tasks thread\n");
00593          pthread_join(misdn_tasks_thread, NULL);
00594       }
00595       sched_context_destroy(misdn_tasks);
00596    }
00597 }
00598 
00599 static inline void misdn_tasks_wakeup (void)
00600 {
00601    pthread_kill(misdn_tasks_thread, SIGUSR1);
00602 }
00603 
00604 static inline int _misdn_tasks_add_variable (int timeout, ast_sched_cb callback, const void *data, int variable)
00605 {
00606    int task_id;
00607 
00608    if (!misdn_tasks) {
00609       misdn_tasks_init();
00610    }
00611    task_id = ast_sched_add_variable(misdn_tasks, timeout, callback, data, variable);
00612    misdn_tasks_wakeup();
00613 
00614    return task_id;
00615 }
00616 
00617 static int misdn_tasks_add (int timeout, ast_sched_cb callback, const void *data)
00618 {
00619    return _misdn_tasks_add_variable(timeout, callback, data, 0);
00620 }
00621 
00622 static int misdn_tasks_add_variable (int timeout, ast_sched_cb callback, const void *data)
00623 {
00624    return _misdn_tasks_add_variable(timeout, callback, data, 1);
00625 }
00626 
00627 static void misdn_tasks_remove (int task_id)
00628 {
00629    AST_SCHED_DEL(misdn_tasks, task_id);
00630 }
00631 
00632 static int misdn_l1_task (const void *data)
00633 {
00634    misdn_lib_isdn_l1watcher(*(int *)data);
00635    chan_misdn_log(5, *(int *)data, "L1watcher timeout\n");
00636    return 1;
00637 }
00638 
00639 static int misdn_overlap_dial_task (const void *data)
00640 {
00641    struct timeval tv_end, tv_now;
00642    int diff;
00643    struct chan_list *ch = (struct chan_list *)data;
00644 
00645    chan_misdn_log(4, ch->bc->port, "overlap dial task, chan_state: %d\n", ch->state);
00646 
00647    if (ch->state != MISDN_WAITING4DIGS) {
00648       ch->overlap_dial_task = -1;
00649       return 0;
00650    }
00651    
00652    ast_mutex_lock(&ch->overlap_tv_lock);
00653    tv_end = ch->overlap_tv;
00654    ast_mutex_unlock(&ch->overlap_tv_lock);
00655    
00656    tv_end.tv_sec += ch->overlap_dial;
00657    tv_now = ast_tvnow();
00658 
00659    diff = ast_tvdiff_ms(tv_end, tv_now);
00660 
00661    if (diff <= 100) {
00662       char *dad=ch->bc->dad, sexten[]="s";
00663       /* if we are 100ms near the timeout, we are satisfied.. */
00664       stop_indicate(ch);
00665       
00666       if (ast_strlen_zero(ch->bc->dad)) {
00667          dad=sexten;
00668          strcpy(ch->ast->exten, sexten);
00669       }
00670 
00671       if (ast_exists_extension(ch->ast, ch->context, dad, 1, ch->bc->oad)) {
00672          ch->state=MISDN_DIALING;
00673          if (pbx_start_chan(ch) < 0) {
00674             chan_misdn_log(-1, ch->bc->port, "ast_pbx_start returned < 0 in misdn_overlap_dial_task\n");
00675             goto misdn_overlap_dial_task_disconnect;
00676          }
00677       } else {
00678 misdn_overlap_dial_task_disconnect:
00679          hanguptone_indicate(ch);
00680          ch->bc->out_cause = AST_CAUSE_UNALLOCATED;
00681          ch->state=MISDN_CLEANING;
00682          misdn_lib_send_event(ch->bc, EVENT_DISCONNECT);
00683       }
00684       ch->overlap_dial_task = -1;
00685       return 0;
00686    } else
00687       return diff;
00688 }
00689 
00690 static void send_digit_to_chan(struct chan_list *cl, char digit )
00691 {
00692    static const char* dtmf_tones[] = {
00693       "!941+1336/100,!0/100", /* 0 */
00694       "!697+1209/100,!0/100", /* 1 */
00695       "!697+1336/100,!0/100", /* 2 */
00696       "!697+1477/100,!0/100", /* 3 */
00697       "!770+1209/100,!0/100", /* 4 */
00698       "!770+1336/100,!0/100", /* 5 */
00699       "!770+1477/100,!0/100", /* 6 */
00700       "!852+1209/100,!0/100", /* 7 */
00701       "!852+1336/100,!0/100", /* 8 */
00702       "!852+1477/100,!0/100", /* 9 */
00703       "!697+1633/100,!0/100", /* A */
00704       "!770+1633/100,!0/100", /* B */
00705       "!852+1633/100,!0/100", /* C */
00706       "!941+1633/100,!0/100", /* D */
00707       "!941+1209/100,!0/100", /* * */
00708       "!941+1477/100,!0/100" };  /* # */
00709    struct ast_channel *chan=cl->ast; 
00710   
00711    if (digit >= '0' && digit <='9')
00712       ast_playtones_start(chan,0,dtmf_tones[digit-'0'], 0);
00713    else if (digit >= 'A' && digit <= 'D')
00714       ast_playtones_start(chan,0,dtmf_tones[digit-'A'+10], 0);
00715    else if (digit == '*')
00716       ast_playtones_start(chan,0,dtmf_tones[14], 0);
00717    else if (digit == '#')
00718       ast_playtones_start(chan,0,dtmf_tones[15], 0);
00719    else {
00720       /* not handled */
00721       ast_log(LOG_DEBUG, "Unable to handle DTMF tone '%c' for '%s'\n", digit, chan->name);
00722    }
00723 }
00724 
00725 /*** CLI HANDLING ***/
00726 static int misdn_set_debug(int fd, int argc, char *argv[])
00727 {
00728    int level;
00729 
00730    if (argc != 4 && argc != 5 && argc != 6 && argc != 7)
00731       return RESULT_SHOWUSAGE; 
00732 
00733    level = atoi(argv[3]);
00734 
00735    switch (argc) {
00736    case 4:
00737    case 5:
00738       {
00739          int i;
00740          int only = 0;
00741          if (argc == 5) {
00742             if (strncasecmp(argv[4], "only", strlen(argv[4])))
00743                return RESULT_SHOWUSAGE;
00744             else
00745                only = 1;
00746          }
00747    
00748          for (i = 0; i <= max_ports; i++) {
00749             misdn_debug[i] = level;
00750             misdn_debug_only[i] = only;
00751          }
00752          ast_cli(fd, "changing debug level for all ports to %d%s\n",misdn_debug[0], only?" (only)":"");
00753       }
00754       break;
00755    case 6:
00756    case 7:
00757       {
00758          int port;
00759          if (strncasecmp(argv[4], "port", strlen(argv[4])))
00760             return RESULT_SHOWUSAGE;
00761          port = atoi(argv[5]);
00762          if (port <= 0 || port > max_ports) {
00763             switch (max_ports) {
00764             case 0:
00765                ast_cli(fd, "port number not valid! no ports available so you won't get lucky with any number here...\n");
00766                break;
00767             case 1:
00768                ast_cli(fd, "port number not valid! only port 1 is available.\n");
00769                break;
00770             default:
00771                ast_cli(fd, "port number not valid! only ports 1 to %d are available.\n", max_ports);
00772             }
00773             return 0;
00774          }
00775          if (argc == 7) {
00776             if (strncasecmp(argv[6], "only", strlen(argv[6])))
00777                return RESULT_SHOWUSAGE;
00778             else
00779                misdn_debug_only[port] = 1;
00780          } else
00781             misdn_debug_only[port] = 0;
00782          misdn_debug[port] = level;
00783          ast_cli(fd, "changing debug level to %d%s for port %d\n", misdn_debug[port], misdn_debug_only[port]?" (only)":"", port);
00784       }
00785    }
00786    return 0;
00787 }
00788 
00789 static int misdn_set_crypt_debug(int fd, int argc, char *argv[])
00790 {
00791    if (argc != 5) return RESULT_SHOWUSAGE; 
00792 
00793    return 0;
00794 }
00795 
00796 static int misdn_port_block(int fd, int argc, char *argv[])
00797 {
00798    int port;
00799 
00800    if (argc != 4)
00801       return RESULT_SHOWUSAGE;
00802   
00803    port = atoi(argv[3]);
00804 
00805    misdn_lib_port_block(port);
00806 
00807    return 0;
00808 }
00809 
00810 static int misdn_port_unblock(int fd, int argc, char *argv[])
00811 {
00812    int port;
00813   
00814    if (argc != 4)
00815       return RESULT_SHOWUSAGE;
00816   
00817    port = atoi(argv[3]);
00818 
00819    misdn_lib_port_unblock(port);
00820 
00821    return 0;
00822 }
00823 
00824 
00825 static int misdn_restart_port (int fd, int argc, char *argv[])
00826 {
00827    int port;
00828   
00829    if (argc != 4)
00830       return RESULT_SHOWUSAGE;
00831   
00832    port = atoi(argv[3]);
00833 
00834    misdn_lib_port_restart(port);
00835 
00836    return 0;
00837 }
00838 
00839 static int misdn_restart_pid (int fd, int argc, char *argv[])
00840 {
00841    int pid;
00842   
00843    if (argc != 4)
00844       return RESULT_SHOWUSAGE;
00845   
00846    pid = atoi(argv[3]);
00847 
00848    misdn_lib_pid_restart(pid);
00849 
00850    return 0;
00851 }
00852 
00853 static int misdn_port_up (int fd, int argc, char *argv[])
00854 {
00855    int port;
00856    
00857    if (argc != 4)
00858       return RESULT_SHOWUSAGE;
00859    
00860    port = atoi(argv[3]);
00861    
00862    misdn_lib_get_port_up(port);
00863   
00864    return 0;
00865 }
00866 
00867 static int misdn_port_down (int fd, int argc, char *argv[])
00868 {
00869    int port;
00870 
00871    if (argc != 4)
00872       return RESULT_SHOWUSAGE;
00873    
00874    port = atoi(argv[3]);
00875    
00876    misdn_lib_get_port_down(port);
00877   
00878    return 0;
00879 }
00880 
00881 static inline void show_config_description (int fd, enum misdn_cfg_elements elem)
00882 {
00883    char section[BUFFERSIZE];
00884    char name[BUFFERSIZE];
00885    char desc[BUFFERSIZE];
00886    char def[BUFFERSIZE];
00887    char tmp[BUFFERSIZE];
00888 
00889    misdn_cfg_get_name(elem, tmp, sizeof(tmp));
00890    term_color(name, tmp, COLOR_BRWHITE, 0, sizeof(tmp));
00891    misdn_cfg_get_desc(elem, desc, sizeof(desc), def, sizeof(def));
00892 
00893    if (elem < MISDN_CFG_LAST)
00894       term_color(section, "PORTS SECTION", COLOR_YELLOW, 0, sizeof(section));
00895    else
00896       term_color(section, "GENERAL SECTION", COLOR_YELLOW, 0, sizeof(section));
00897 
00898    if (*def)
00899       ast_cli(fd, "[%s] %s   (Default: %s)\n\t%s\n", section, name, def, desc);
00900    else
00901       ast_cli(fd, "[%s] %s\n\t%s\n", section, name, desc);
00902 }
00903 
00904 static int misdn_show_config (int fd, int argc, char *argv[])
00905 {
00906    char buffer[