· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
Asterisk Ver0-1-0/Main2 Dial

AsteriskVer0-1-0/Main2Dial


main


* int main(int argc, char *argv[])
  • if (geteuid()) {
    • Must be run as root, exit(1);
  • }
  • while((c=getopt(argc, argv, "dvq")) != EOF) {
    • case d, v, q
    • exit(1);
  • }
  • signal ó¸®
  • if (init_logger()) event_log È­ÀÏÀ» append mode ·Î open ÇÑ´Ù.
    • exit(1);
  • if (load_pbx()) builtin function À» ast_app ¿¡ µî·ÏÇÑ´Ù.
    • exit(1);
  • if (load_modules()) module µéÀÇ load_module À» ¼öÇàÇÏ°í, module_list ¿¡ µî·ÏÇÑ´Ù.
    • exit(1);
    • module ÀÌ application À̸é, application list ¿¡ link ½ÃÅ°°í, channel deiverÀ̸é ÇØ´çµÇ´Â config ÆÄÀÏÀ» Àоî channel(interface) list ¸¦ ¸¸µé°í chanlist ¿¡ link ½ÃŲ´Ù.
    • channel driver ´Â °¢°¢ÀÇ channel(interface) ¿¡ ÀÔ·ÂÀÌ µé¾î¿À±â¸¦ ±â´Ù¸°´Ù.
  • select(0,NULL,NULL,NULL,NULL);
    • interrupt °¡ µé¾î ¿Ã ¶§±îÁö ´ë±â»óÅ·ΠÀִ´Ù.
  • return 0;
If the readfs , writefs , and errorfds arguments are all null pointers and the timeout  argument is a null pointer, select()  blocks until interrupted by a signal.
model.txt
Description of call model:

Incoming Call:

        Channel backend waits for a RING or equivalent on some sort of
interface. Typically this is done in its own thread.  When a RING is
detected, the backend should create a channel structure and then call
ast_pbx_start() on that channel, which will create a thread to monitor
that interface.  At this point, the PBX and/or applications it launches
will manage the interface, and it need not be monitored by the
aforementioned thread.  When the applications are finished, the requisite
hangup function will be called, at which the channel can be considered to
be no longer valid, and the thread that controls it will immenantly be
terminated.

* include/logger.h
  • #define EVENTLOG "event_log"

* logger.c
  • #define AST_EVENT_LOG AST_LOG_DIR "/" EVENTLOG
  • AST_EVENT_LOG: /var/log/asterisk/event_log
* int init_logger(void)
  • mkdir(AST_LOG_DIR, 0755);
  • eventlog = fopen(AST_EVENT_LOG, "a");
  • if (eventlog) {
    • return 0;
  • } else
  • return -1;

* pbx.c
struct ast_app {
        /* Name of the application */
        char name[AST_MAX_APP];
        int (*execute)(struct ast_channel *chan, void *data);
        struct ast_app *next;
};

static struct ast_app *apps = NULL;

static struct pbx_builtin {
        char name[AST_MAX_APP];
        int (*execute)(struct ast_channel *chan, void *data);
} builtins[] =
{
        /* These applications are built into the PBX core and do not
           need separate modules */
        { "Answer", pbx_builtin_answer },
        { "Goto", pbx_builtin_goto },
        { "Hangup", pbx_builtin_hangup },
        { "DigitTimeout", pbx_builtin_dtimeout },
        { "ResponseTimeout", pbx_builtin_rtimeout },
        { "BackGround", pbx_builtin_background },
        { "Wait", pbx_builtin_wait },
};
* int load_pbx(void)
  • for (x=0;x
    • if (ast_register_application(builtinsx.name, builtinsx.execute)) {
      • return -1;
    • }
  • }
  • return 0;

* int ast_register_application(char *app, int (*execute)(struct ast_channel *, void *))
  • application list ¿¡ lock À» °É¼ö ¾øÀ¸¸é return -1;
  • tmp = apps;
  • while(tmp) {
    • ÀÌ¹Ì µî·ÏµÇ¾î ÀÖÀ¸¸é return -1;
  • }
  • tmp = malloc(sizeof(struct ast_app));
  • if (tmp) {
    • strncpy(tmp->name, app, sizeof(tmp->name));
    • tmp->execute = execute;
  • } else {
    • return -1;
  • }
  • return 0;

* int load_modules()
  • module.h:#define AST_MODULE_CONFIG "modules.conf"
  • cfg = ast_load(AST_MODULE_CONFIG);
  • if (cfg) {
    • modules.conf ÆÄÀÏÀÌ ÀÖÀ¸¸é
    • v = ast_variable_browse(cfg, "modules");
    • while(v) {
      • modules category °¡ ÀÖÀ¸¸é
      • if (!strcasecmp(v->name, "load")) {
        • load °¡ ÀÖÀ¸¸é
        • if (ast_load_resource(v->value)) {
          • return -1;
  • if (!cfg || ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
    • modules.conf ÆÄÀÏÀÌ ¾ø°Å³ª, modules category ¿¡ autoload °¡ ÀÖÀ¸¸é
    • mods = opendir(AST_MODULE_DIR);
    • if (mods) {
      • while((d = readdir(mods))) {
        • .so file ÀÌ°í module list ¿¡ ¾øÀ¸¸é {
          • cfg ¿¡ noload ¸é skip
          • if (ast_load_resource(d->d_name)) {
            • return -1;
          • }
        • }
      • }
    • } else {
    • }
  • }
  • ast_destroy(cfg);
  • return 0;
    • }
    • }
    • v=v->next;
    • }
  • }

struct module {
        int (*load_module)(void);
        int (*unload_module)(void);
        int (*usecount)(void);
        char *(*description)(void);
        void *lib;
        char resource[256];
        struct module *next;
};

static struct module *module_list=NULL;
* int ast_load_resource(char *resource_name)
  • struct module *m = malloc(sizeof(struct module));
  • strncpy(m->resource, resource_name, sizeof(m->resource));
  • m->lib = dlopen(fn, RTLD_NOW | RTLD_GLOBAL);
  • m->load_module = dlsym(m->lib, "load_module");
  • m->unload_module = dlsym(m->lib, "unload_module");
  • m->usecount = dlsym(m->lib, "usecount");
  • m->description = dlsym(m->lib, "description");
  • if ((res = m->load_module())) {
    • return -1;
    • channel driver ÀÎ °æ¿ì load µÇ°í, wait »óÅ¿¡ ÀÖ°Ô µÈ´Ù.
  • }
  • m->next = module_list;
  • module_list = m;
  • ast_update_use_count();
  • return 0;

* dlsym - obtain the address of a symbol from a dlopen object

ast_load

* config.c

struct ast_variable {
        char *name;
        char *value;
        struct ast_variable *next;
};

struct ast_category {
        char name[80];
        struct ast_variable *root;
        struct ast_category *next;
};

struct ast_config {
        /* Maybe this structure isn't necessary but we'll keep it
           for now */
        struct ast_category *root;
};

* struct ast_config *ast_load(char *configfile)
  • asterisk.h:#define AST_CONFIG_DIR "/etc/asterisk"
  • fn = AST_CONFIG_DIR + '/' + configfile
  • f = fopen(fn, "r")
    • tmp = malloc(sizeof(struct ast_config));
    • tmp->root = NULL;
    • while(!feof(f))
      • fgets(buf, sizeof(buf), f);
        • category
          • tmpc = malloc(sizeof(struct ast_category));
          • strncpy(tmpc->name, cur+1, sizeof(tmpc->name));
        • variable = value
          • v = malloc(sizeof(struct ast_variable));
          • v->name = strdup(strip(cur));
          • v->value = strdup(strip(c));
          • category struct ¿Í ¿¬°á
    • fclose(f);
  • return tmp;

* char *ast_category_browse(struct ast_config *config, char *prev)
  • prev °¡ NULL À̸é, ù¹ø° category ¸íÀ» return
  • prev category °¡ Á¸ÀçÇϸé, ´ÙÀ½ category ¸íÀ» return

* struct ast_variable *ast_variable_browse(struct ast_config *config, char *category)
  • category °¡ Á¸ÀçÇϸé, ù¹ø° variable ÀÇ pointer return

* char *ast_variable_retrieve(struct ast_config *config, char *category, char *value)
  • category Á¸ÀçÇÏ°í, variable Á¸ÀçÇϸé, ÇØ´ç °ªÀ» return

chan_ixj.c

Connected to the PhoneJack PCI card is a Nortel Venture phone. My
phone.conf file has "mode=dialtone", "format=slinear", "echocancel=off",
"txgain=100%", "rxgain=1.0", and "device => /dev/phone0"

* load_module()
  • static char *config = "ixj.conf";
  • cfg = ast_load(config);
  • v = ast_variable_browse(cfg, "interfaces");
  • while(v)
    • strcasecmp(v->name, "device")
      • tmp = mkif(v->value, mode);
      • tmp->next = iflist;
      • iflist = tmp;
      • °¢°¢ÀÇ device ´Â interface ¿¡ ÇØ´çµÇ°í À̰͵éÀº °¢°¢ÀÇ channel ¿¡ ÇØ´çµÈ´Ù. iflist ¸¦ ÀÌ¿ëÇÏ¿© do_monitor ¿¡¼­ °¢ interface ÀÇ input À» check ÇÑ´Ù.
    • strcasecmp(v->name, "mode")
      • mode = MODE_DIALTONE or MODE_IMMEDIATE
    • strcasecmp(v->name, "context"
      • strncpy(context, v->value, sizeof(context));
      • context °ªÀÌ ¾øÀ¸¸é, default ¸¦ »ç¿ëÇÔ.
  • ast_channel_register(type, tdesc, AST_FORMAT_G723_1, ixj_request)
  • restart_monitor();
    • »õ·Î¿î thread ¸¦ »ý¼º½ÃŲ´Ù. ÀÌ´Â do_monitor ÇÔ¼ö¸¦ ¼öÇàÇÑ´Ù.
    • do_monitor ÇÔ¼ö´Â À§¿¡¼­ »ý¼ºÇÑ iflist ¸¦ ÀÌ¿ëÇÏ¿© °¢ channel ÀÇ input, output, error ¿¡ ÇØ´çÇÏ´Â fd(file descriptor) µéÀÇ ÁýÇÕÀ» FD_SET ¿¡ ³Ö°í, select ¸¦ ÅëÇØ ÀÔ·ÂÀ» ±â´Ù¸°´Ù.

* struct ixj_pvt *mkif(char *iface, int mode)
  • tmp->fd = open(iface, O_RDWR);
    • iface ´Â /dec/phone0
  • device ¸¦ open ÇÏ°í, °ü·Ã ¼³Á¤À» ÇÑ´Ù.
  • tmp->owner = NULL;
  • tmp->dialtone = 0;

ast_channel_register

struct ast_channel {
        char name[AST_CHANNEL_NAME];            /* ASCII Description of channel name */
        pthread_t blocker;                                      /* If anyone is blocking, this is them */
        char *blockproc;                                        /* Procedure causing blocking */
        int blocking;                                           /* Whether or not we're blocking */
        struct sched_context *sched;            /* Schedule context */
        int streamid;                                   /* For streaming playback, the schedule ID */
        struct ast_filestream *stream;  /* Stream itself. */
        struct ast_channel *trans;              /* Translator if present */
        struct ast_channel *master;             /* Master channel, if this is a translator */
        int fd;                                 /* File descriptor for channel -- all must have
                                                   a file descriptor! */
        char *type;                             /* Type of channel */
        int state;                              /* State of line */
        int rings;                              /* Number of rings so far */
        int stack;                              /* Current level of application */
        int format;                             /* Kinds of data this channel can
                                                           natively handle */
        char *dnid;                             /* Malloc'd Dialed Number Identifier */
        char *callerid;                 /* Malloc'd Caller ID */
        char context[AST_MAX_EXTENSION];        /* Current extension context */
        char exten[AST_MAX_EXTENSION];          /* Current extension number */
        int priority;                                           /* Current extension priority */
        void *app[AST_CHANNEL_MAX_STACK];       /* Application information -- see assigned numbers */
        struct ast_channel_pvt *pvt;
                                                /* Private channel implementation details */
        jmp_buf jmp[AST_CHANNEL_MAX_STACK];             /* Jump buffer used for returning from applications */
        struct ast_pbx *pbx;
        struct ast_channel *next;               /* For easy linking */
};
struct chanlist {
        char type[80];
        char description[80];
        int capabilities;
        struct ast_channel * (*requester)(char *type, int format, void *data);
        struct chanlist *next;
} *backends = NULL;

* int ast_channel_register(char *type, char *description, int capabilities, struct ast_channel *(*requester)(char *type, int format, void *data))
  • chanlist ´Â channel list °¡ ¾Æ´Ï¶ó channel driver ÀÇ list ÀÓ.
  • ½ÇÁ¦ channel Áï ast_channel Àº requester ¿¡ ÀÇÇØ ¾ò´Â´Ù.
  • channel list ¿¡ lock À» °É¼ö ¾øÀ¸¸é return -1;
  • chan = backends;
  • while(chan) {
    • ÀÌ¹Ì µî·ÏµÇ¾î ÀÖÀ¸¸é return -1;
  • }
  • chan = malloc(sizeof(struct chanlist));
  • channel structure ¿¡ type, description, capabilities, requester À» ¼³Á¤
  • chan->next = NULL;
  • channel list ³¡¿¡ link
  • return 0;

* chanlist struct ÀÇ requester ¿¡ °¢ ¸ðµâÀÇ request ÇÔ¼ö¸¦ assign ÇÑ´Ù. ÀÌ´Â ast_request ÇÔ¼ö¿¡ ÀÇÇØ ¼öÇàµÈ´Ù.

* static int dial_exec(struct ast_channel *chan, void *data)
  • app_dial.c
  • tmp->chan = ast_request(tech, chan->format, number);

* struct ast_channel *ast_request(char *type, int format, void *data)
  • channel.c
  • c = chan->requester(type, format, data);

* static struct ast_channel *ixj_request(char *type, int format, void *data)
  • tmp = ixj_new(p, AST_STATE_DOWN);

restart_monitor

  • monitor_thread == pthread_self()
  • thread °¡ ÀÖÀ¸¸é, thread ¸¦ ¾ø¾Ø´Ù.
    • pthread_cancel(monitor_thread); or pthread_join(monitor_thread, NULL);
  • pthread_create(&monitor_thread, NULL, do_monitor, NULL)

* do_monitor
  • for
    • FD_ZERO(&rfds);
    • FD_ZERO(&efds);
    • i = iflist;
    • dotone = 0;
    • while(i)
      • if (!i->owner)
        • FD_SET(i->fd, &rfds);
        • FD_SET(i->fd, &efds);
        • if (i->dialtone)
          • if (write(i->fd, DialTone + tonepos, 240) != 240)
          • dotone++;
      • i = i->next;
    • if (dotone)
      • res = select(n + 1, &rfds, NULL, &efds, &tv);
      • ÀÔ·ÂÀ» tv ½Ã°£µ¿¾È ±â´Ù¸°ÈÄ return. ´Ù½Ã loop ·Î µ¹¾Æ°¡ DialTone À» write ÇÑ´Ù.
    • else
      • res = select(n + 1, &rfds, NULL, &efds, NULL);
      • ÀÔ·ÂÀ» ¹«ÇÑÁ¤ ±â´Ù¸°´Ù.
    • i = iflist;
    • while(i)
      • FD_ISSET(i->fd, &rfds)
        • ixj_mini_packet(i);
      • FD_ISSET(i->fd, &efds)
        • ixj_check_exception(i);
      • i=i->next;
read, write, exception, time
¼º°ø½Ã, select´Â ÆÄÀÏÁöÁ¤ÀÚÁýÇÕ¿¡ Ç¥ÇÔµÈ ¼ýÀÚ¸¦ ¹ÝȯÇϸç, ¸®ÅÏÇϱâÀü¿¡ ŸÀӾƿôÀÌ ¹ß»ýÇϸé 0À» ¹ÝȯÇÑ´Ù. ÀÌ·¯½Ã -1ÀÌ ¹ÝȯµÇ¸ç, errno´Â Àû´çÇÑ °ªÀ¸·Î ¼³Á¤µÈ´Ù.

* static void ixj_mini_packet(struct ixj_pvt *i)
  • res = read(i->fd, buf, sizeof(buf));

ixj_check_exception

typedef struct
{
  unsigned int dtmf_ready:1;
  unsigned int hookstate:1;
  unsigned int pstn_ring:1;
  unsigned int caller_id:1;
  unsigned int pstn_wink:1;
  unsigned int f0:1;
  unsigned int f1:1;
  unsigned int f2:1;
  unsigned int f3:1;
  unsigned int reserved:23;
}IXJ_EXCEPT;

typedef union
{
  IXJ_EXCEPT bits;
  unsigned int bytes;
}IXJ_EXCEPTION;

The dtmf_ready bit indicates if there is data waiting in the DTMF buffer.  The hookstate bit is set if there is a change in hookstate status, it does not indicate the current state of the hookswitch.  
The pstn_ring bit indicates that the DAA on a LineJACK card has detected ring voltage on the PSTN port.  
The caller_id bit indicates that caller_id data has been received and is available.  
The pstn_wink bit indicates that the DAA on the LineJACK has received a wink from the telco switch

* static void ixj_check_exception(struct ixj_pvt *i)
  • ixje.bytes = ioctl(i->fd, IXJCTL_EXCEPTION);
  • if (ixje.bits.dtmf_ready) ¼ýÀÚ°¡ ´­·ÁÁö¸é
    • digit0 = ioctl(i->fd, IXJCTL_GET_DTMF_ASCII); ÀÔ·ÂµÈ ¼ýÀÚ¸¦ °¡Á®¿Â´Ù.
    • if (i->mode == MODE_DIALTONE)
      • ioctl IXJCTL_PLAY_STOP, IXJCTL_REC_STOP, IXJCTL_CPT_STOP
      • i->dialtone = 0;
      • if (strlen(i->ext) < AST_MAX_EXTENSION - 1)
        • strcat(i->ext, digit);
        • ÀÔ·ÂµÈ ¼ýÀÚ¸¦ i->ext ¿¡ Ãß°¡ÇÑ´Ù.
        • AST_MAX_EXTENSION ÀÇ °¹¼ö¸¦ ³ÑÀ¸¸é, Ãß°¡ÇÏÁö ¾Ê´Â´Ù.
      • if (ast_exists_extension(NULL, i->context, i->ext, 1)) {
        • i->context ¿¡¼­ ÇØ´çÇÏ´Â extensionÀÌ ÀÖÀ¸¸é
        • ixj_new(i, AST_STATE_UP);
        • /* No need to restart monitor, we are the monitor */
        • if (i->owner)
          • ixj_setup(i->owner);
      • } else if (ast_exists_extension(NULL, "default", i->ext, 1)) {
        • default context ¿¡¼­ extensionÀÌ ÀÖÀ¸¸é
        • À§¿Í ¶È°°Àº ÀÏÀ» ¼öÇàÇÑ´Ù.
      • } else if ((strlen(i->ext) >= ast_pbx_longest_extension(i->context)) & (strlen(i->ext) >= ast_pbx_longest_extension("default"))) {
        • It's not a valid extension, give a busy signal
        • ioctl(i->fd, IXJCTL_BUSY);
      • }
    • }
  • if (ixje.bits.hookstate) hook state °¡ º¯Çϸé
    • offhook = ioctl(i->fd, IXJCTL_HOOKSTATE);
    • if (offhook) ¼öÈ­±â¸¦ µé¸é
      • ioctl(i->fd, IXJCTL_DIALTONE);
      • offhook À» Çϸé dialtone À» ³» º¸³»°í, ´ÙÀ½ exception À» ±â´Ù¸°´Ù.
    • else ¼öÈ­±â¸¦ ³»·Á³õÀ¸¸é
      • memset(i->ext, 0, sizeof(i->ext));
      • ioctl(i->fd, IXJCTL_CPT_STOP);
      • ioctl(i->fd, IXJCTL_PLAY_STOP);
      • ioctl(i->fd, IXJCTL_REC_STOP);
      • i->dialtone = 0;

  • if (ixje.bits.pstn_ring)
    • ast_verbose("Unit is ringing\n");
  • if (ixje.bits.caller_id)
    • ast_verbose("We have caller ID\n");

  • hook off + ¼ýÀÚµé
  • hook off ¸é dial tone À» ³»º¸³»°í ´ÙÀ½ ÀÔ·ÂÀ» ±â´Ù¸°´Ù.
  • ¼ýÀÚ°¡ µé¾î¿À¸é i->ext ¿¡ Ãß°¡ÇÏ°í context ¿¡ ÇØ´çÇÏ´Â extension ÀÌ Àִ°¡ Á¡°ËÇÑ´Ù.
  • ÇØ´çÇÏ´Â extension ÀÌ ÀÖÀ¸¸é ixj_new ¸¦ ½ÇÇàÇÑ´Ù.

#define HELPER_EXISTS 0
#define HELPER_SPAWN 1
#define HELPER_EXEC 2
* int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority)
  • return pbx_extension_helper(c, context, exten, priority, HELPER_EXISTS);

* static int pbx_extension_helper(struct ast_channel *c, char *context, char *exten, int priority, int action)
  • context, extension, priority °¡ °°Àº extension À» ã´Â´Ù
  • action ÀÌ HELP_EXISTS ¸é return -1;
  • action ÀÌ HELPER_SPAWN À̸é newstack++;
  • action ÀÌ HELPER_EXEC À̸é
    • app = pbx_findapp(e->app);
    • return pbx_exec(c, app->execute, e->data, newstack);
  • ¾ø°í, action ÀÌ HELP_EXISTS °¡ ¾Æ´Ï¸é return -1;
  • ¾ø°í, action ÀÌ HELP_EXISTS ¸é return 0;

* static struct ast_channel *ixj_new(struct ixj_pvt *i, int state)
  • tmp = ast_channel_alloc();
  • set ast_channel structure
    • tmp ¿¡ type, i->fd, AST_FORMAT_G723_1, state ¸¦ assign
    • if (state == AST_STATE_RING)
      • tmp->rings = 1;
    • tmp->pvt->pvt = i; i->ext ´Â extension number
    • tmp->pvt ¿¡ ixj_digit, ixj_call, ixj_hangup, ixj_answer, ixj_read, ixj_write ¸¦ assign
    • tmp ¿¡ context, extension À» º¹»ç
  • i->owner = tmp;
  • ast_update_use_count();
  • if (state != AST_STATE_DOWN)
    • if (state == AST_STATE_RING)
      • ioctl(tmp->fd, IXJCTL_RINGBACK);
    • if (ast_pbx_start(tmp))
      • ast_hangup(tmp);
  • return tmp;

  • i->ext ¸¦ tmp ¿¡ ¼³Á¤ÇÏ°í, ast_pbx_start ¸¦ ½ÇÇàÇÑ´Ù.

* int ast_pbx_start(struct ast_channel *c)
  • pthread_create(&t, NULL, pbx_thread, c)

* static void *pbx_thread(void *data)
  • extension.conf ¿¡ ÀÖ´Â dialplan À» ¼öÇàÇÑ´Ù.

ast_pbx_start

* int ast_pbx_start(struct ast_channel *c)
  • if (pthread_create(&t, &attr, pbx_thread, c))
    • return -1
  • return 0

* static void *pbx_thread(void *data)
  • struct ast_channel *c = data;
  • if (!ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
    • strncpy(c->context, "default", sizeof(c->context)-1);
    • strncpy(c->exten, "s", sizeof(c->exten)-1);
    • c->priority = 1;
    • context, exten, priority °¡ °°Àº °ÍÀÌ ¾øÀ¸¸é, context ´Â default, exten Àº s, priority ´Â 1 ·Î ¼³Á¤
  • }
  • for(;;) {
    • pos = 0; digit = 0;
    • while(ast_exists_extension(c, c->context, c->exten, c->priority, c->callerid)) {
      • if ((res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->callerid))) {
        • dialplan(extensions.conf) ÀÇ application ÀÌ ¼öÇàµÈ´Ù.
        • goto out;
      • }
      • if (c->stream) {
        • digit = ast_waitstream(c, AST_DIGIT_ANY);
        • ast_stopstream(c);
        • if (digit < 0)
          • goto out;
        • else if (digit) {
          • ast_stopstream(c);
          • extenpos++ = digit;
          • break;
        • }
      • }
      • firstpass = 0;
      • c->priority++;
    • }
    • while(!ast_exists_extension(c, c->context, exten, 1) && (
      strlen(exten) < ast_pbx_longest_extension(c->context))) {
      • digit = ast_waitfordigit(c, waittime * 1000);
      • if (!digit)
        • break;
      • if (digit < 0)
        • goto out;
      • extenpos++ = digit;
      • waittime = c->pbx->dtimeout;
    • }
    • if (ast_exists_extension(c, c->context, exten, 1)) {
      • strncpy(c->exten, exten, sizeof(c->exten));
      • c->priority = 1;
    • } else {
      • if (strlen(exten)) {
        • An invalid extension
        • if (ast_exists_extension(c, c->context, "i", 1)) {
        • } else {
          • Invalid extension, but no rule 'i' in context
          • goto out;
        • }
      • } else {
        • A simple timeout
        • if (ast_exists_extension(c, c->context, "t", 1)) {
          • strncpy(c->exten, "t", sizeof(c->exten))
          • c->priority = 1;
        • } else {
          • Timeout, but no rule 't' in context
          • goto out;
        • }
      • }
    • }
  • }
  • out:
  • pbx_destroy(c->pbx);
  • c->pbx = NULL;
  • ast_hangup(c);
  • pthread_exit(NULL)

ID
Password
Join
Stop searching forever. Happiness is unattainable.


sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2009-07-14 08:44:21
Processing time 0.0172 sec