aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rwxr-xr-xchannel.c239
-rwxr-xr-xinclude/asterisk/channel.h31
-rwxr-xr-xinclude/asterisk/pbx.h108
3 files changed, 341 insertions, 37 deletions
diff --git a/channel.c b/channel.c
index 0f7200162..74ab87809 100755
--- a/channel.c
+++ b/channel.c
@@ -128,6 +128,42 @@ char *ast_state2str(int state)
}
}
+
+int ast_best_codec(int fmts)
+{
+ /* This just our opinion, expressed in code. We are asked to choose
+ the best codec to use, given no information */
+ int x;
+ static int prefs[] =
+ {
+ /* Okay, ulaw is used by all telephony equipment, so start with it */
+ AST_FORMAT_ULAW,
+ /* Unless of course, you're a silly European, so then prefer ALAW */
+ AST_FORMAT_ALAW,
+ /* Okay, well, signed linear is easy to translate into other stuff */
+ AST_FORMAT_SLINEAR,
+ /* ADPCM has great sound quality and is still pretty easy to translate */
+ AST_FORMAT_ADPCM,
+ /* Okay, we're down to vocoders now, so pick GSM because it's small and easier to
+ translate and sounds pretty good */
+ AST_FORMAT_GSM,
+ /* Ick, LPC10 sounds terrible, but at least we have code for it, if you're tacky enough
+ to use it */
+ AST_FORMAT_LPC10,
+ /* Down to G.723.1 which is proprietary but at least designed for voice */
+ AST_FORMAT_G723_1,
+ /* Last and least, MP3 which was of course never designed for real-time voice */
+ AST_FORMAT_MP3,
+ };
+
+
+ for (x=0;x<sizeof(prefs) / sizeof(prefs[0]); x++)
+ if (fmts & prefs[x])
+ return prefs[x];
+ ast_log(LOG_WARNING, "Don't know any of 0x%x formats\n", fmts);
+ return 0;
+}
+
struct ast_channel *ast_channel_alloc(void)
{
struct ast_channel *tmp;
@@ -174,6 +210,22 @@ struct ast_channel *ast_channel_alloc(void)
return tmp;
}
+int ast_channel_defer_dtmf(struct ast_channel *chan)
+{
+ int pre = 0;
+ if (chan) {
+ pre = chan->deferdtmf;
+ chan->deferdtmf = 1;
+ }
+ return pre;
+}
+
+void ast_channel_undefer_dtmf(struct ast_channel *chan)
+{
+ if (chan)
+ chan->deferdtmf = 0;
+}
+
struct ast_channel *ast_channel_walk(struct ast_channel *prev)
{
struct ast_channel *l, *ret=NULL;
@@ -243,19 +295,37 @@ int ast_softhangup(struct ast_channel *chan)
return res;
}
+static void free_translation(struct ast_channel *clone)
+{
+ if (clone->pvt->writetrans)
+ ast_translator_free_path(clone->pvt->writetrans);
+ if (clone->pvt->readtrans)
+ ast_translator_free_path(clone->pvt->readtrans);
+ clone->pvt->writetrans = NULL;
+ clone->pvt->readtrans = NULL;
+ clone->pvt->rawwriteformat = clone->nativeformats;
+ clone->pvt->rawreadformat = clone->nativeformats;
+}
+
int ast_hangup(struct ast_channel *chan)
{
int res = 0;
/* Don't actually hang up a channel that will masquerade as someone else, or
if someone is going to masquerade as us */
- if (chan->masq)
+ ast_pthread_mutex_lock(&chan->lock);
+ if (chan->masq) {
+ ast_log(LOG_WARNING, "We're getting hung up, but someone is trying to masq into us?!?\n");
+ ast_pthread_mutex_unlock(&chan->lock);
return 0;
+ }
/* If this channel is one which will be masqueraded into something,
mark it as a zombie already, so we know to free it later */
if (chan->masqr) {
+ ast_pthread_mutex_unlock(&chan->lock);
chan->zombie=1;
return 0;
}
+ free_translation(chan);
if (chan->stream)
ast_stopstream(chan);
if (chan->sched)
@@ -275,6 +345,7 @@ int ast_hangup(struct ast_channel *chan)
if (option_debug)
ast_log(LOG_DEBUG, "Hanging up zombie '%s'\n", chan->name);
+ ast_pthread_mutex_unlock(&chan->lock);
ast_channel_free(chan);
return res;
}
@@ -307,15 +378,17 @@ void ast_channel_unregister(char *type)
int ast_answer(struct ast_channel *chan)
{
+ int res = 0;
/* Stop if we're a zombie or need a soft hangup */
if (chan->zombie || chan->softhangup)
return -1;
switch(chan->state) {
- case AST_STATE_RING:
case AST_STATE_RINGING:
+ case AST_STATE_RING:
if (chan->pvt->answer)
- return chan->pvt->answer(chan);
+ res = chan->pvt->answer(chan);
chan->state = AST_STATE_UP;
+ return res;
break;
case AST_STATE_UP:
break;
@@ -371,7 +444,8 @@ int ast_waitfor_n_fd(int *fds, int n, int *ms, int *exception)
static int ast_do_masquerade(struct ast_channel *original);
-struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
+struct ast_channel *ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds,
+ int *exception, int *outfd, int *ms)
{
/* Wait for x amount of time on a file descriptor to have input. */
struct timeval tv;
@@ -379,6 +453,10 @@ struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
int res;
int x, y, max=-1;
struct ast_channel *winner = NULL;
+ if (outfd)
+ *outfd = -1;
+ if (exception)
+ *exception = 0;
/* Perform any pending masquerades */
for (x=0;x<n;x++) {
@@ -406,6 +484,12 @@ struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
}
CHECK_BLOCKING(c[x]);
}
+ for (x=0;x<nfds; x++) {
+ FD_SET(fds[x], &rfds);
+ FD_SET(fds[x], &efds);
+ if (fds[x] > max)
+ max = fds[x];
+ }
if (*ms >= 0)
res = select(max + 1, &rfds, NULL, &efds, &tv);
else
@@ -436,16 +520,35 @@ struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
}
}
}
+ for (x=0;x<nfds;x++) {
+ if ((FD_ISSET(fds[x], &rfds) || FD_ISSET(fds[x], &efds)) && !winner) {
+ if (outfd)
+ *outfd = fds[x];
+ if (FD_ISSET(fds[x], &efds) && exception)
+ *exception = 1;
+ winner = NULL;
+ }
+ }
*ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
return winner;
}
+struct ast_channel *ast_waitfor_n(struct ast_channel **c, int n, int *ms)
+{
+ return ast_waitfor_nandfds(c, n, NULL, 0, NULL, NULL, ms);
+}
+
int ast_waitfor(struct ast_channel *c, int ms)
{
struct ast_channel *chan;
+ int oldms = ms;
chan = ast_waitfor_n(&c, 1, &ms);
- if (ms < 0)
- return -1;
+ if (ms < 0) {
+ if (oldms < 0)
+ return 0;
+ else
+ return -1;
+ }
return ms;
}
@@ -499,7 +602,17 @@ struct ast_frame *ast_read(struct ast_channel *chan)
pthread_mutex_unlock(&chan->lock);
return NULL;
}
-
+
+ if (!chan->deferdtmf && strlen(chan->dtmfq)) {
+ /* We have DTMF that has been deferred. Return it now */
+ chan->dtmff.frametype = AST_FRAME_DTMF;
+ chan->dtmff.subclass = chan->dtmfq[0];
+ /* Drop first digit */
+ memmove(chan->dtmfq, chan->dtmfq + 1, sizeof(chan->dtmfq) - 1);
+ pthread_mutex_unlock(&chan->lock);
+ return &chan->dtmff;
+ }
+
chan->blocker = pthread_self();
if (chan->exception) {
if (chan->pvt->exception)
@@ -523,6 +636,13 @@ struct ast_frame *ast_read(struct ast_channel *chan)
/* Make sure we always return NULL in the future */
if (!f)
chan->softhangup = 1;
+ else if (chan->deferdtmf && f->frametype == AST_FRAME_DTMF) {
+ if (strlen(chan->dtmfq) < sizeof(chan->dtmfq) - 2)
+ chan->dtmfq[strlen(chan->dtmfq)] = f->subclass;
+ else
+ ast_log(LOG_WARNING, "Dropping deferred DTMF digits on %s\n", chan->name);
+ f = &null_frame;
+ }
pthread_mutex_unlock(&chan->lock);
return f;
@@ -727,9 +847,13 @@ int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int fti
}
if (d < 0)
return -1;
+ if (d == 0) {
+ s[pos]='\0';
+ return 1;
+ }
if (!strchr(enders, d))
s[pos++] = d;
- if ((d == 0) || strchr(enders, d) || (pos >= len - 1)) {
+ if (strchr(enders, d) || (pos >= len - 1)) {
s[pos]='\0';
return 0;
}
@@ -739,6 +863,27 @@ int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int fti
return 0;
}
+int ast_channel_supports_html(struct ast_channel *chan)
+{
+ if (chan->pvt->send_html)
+ return 1;
+ return 0;
+}
+
+int ast_channel_sendhtml(struct ast_channel *chan, int subclass, char *data, int datalen)
+{
+ if (chan->pvt->send_html)
+ return chan->pvt->send_html(chan, subclass, data, datalen);
+ return -1;
+}
+
+int ast_channel_sendurl(struct ast_channel *chan, char *url)
+{
+ if (chan->pvt->send_html)
+ return chan->pvt->send_html(chan, AST_HTML_URL, url, strlen(url) + 1);
+ return -1;
+}
+
int ast_channel_make_compatible(struct ast_channel *chan, struct ast_channel *peer)
{
int peerf;
@@ -812,13 +957,23 @@ static int ast_do_masquerade(struct ast_channel *original)
char *tmp;
struct ast_channel_pvt *p;
struct ast_channel *clone = original->masq;
+ int rformat = original->readformat;
+ int wformat = original->writeformat;
+
+#if 0
ast_log(LOG_DEBUG, "Actually Masquerading %s(%d) into the structure of %s(%d)\n",
clone->name, clone->state, original->name, original->state);
+#endif
/* XXX This is a seriously wacked out operation. We're essentially putting the guts of
the clone channel into the original channel. Start by killing off the original
channel's backend. I'm not sure we're going to keep this function, because
while the features are nice, the cost is very high in terms of pure nastiness. XXX */
+ /* Having remembered the original read/write formats, we turn off any translation on either
+ one */
+ free_translation(clone);
+ free_translation(original);
+
/* We need the clone's lock, too */
pthread_mutex_lock(&clone->lock);
@@ -836,6 +991,15 @@ static int ast_do_masquerade(struct ast_channel *original)
p = original->pvt;
original->pvt = clone->pvt;
clone->pvt = p;
+
+ clone->softhangup = 1;
+
+
+ if (clone->pvt->fixup){
+ res = clone->pvt->fixup(original, clone);
+ if (res)
+ ast_log(LOG_WARNING, "Fixup failed on channel %s, strange things may happen.\n", clone->name);
+ }
/* Start by disconnecting the original's physical side */
if (clone->pvt->hangup)
@@ -877,6 +1041,9 @@ static int ast_do_masquerade(struct ast_channel *original)
original->callerid = clone->callerid;
clone->callerid = tmp;
+ /* Our native formats are different now */
+ original->nativeformats = clone->nativeformats;
+
/* Context, extension, priority, app data, jump table, remain the same */
/* pvt switches. pbx stays the same, as does next */
@@ -891,10 +1058,12 @@ static int ast_do_masquerade(struct ast_channel *original)
pthread_mutex_unlock(&clone->lock);
}
/* Set the write format */
- ast_set_write_format(original, original->writeformat);
+ ast_set_write_format(original, wformat);
/* Set the read format */
- ast_set_read_format(original, original->readformat);
+ ast_set_read_format(original, rformat);
+
+ ast_log(LOG_DEBUG, "Putting channel %s in %d/%d formats\n", original->name, wformat, rformat);
/* Okay. Last thing is to let the channel driver know about all this mess, so he
can fix up everything as best as possible */
@@ -908,10 +1077,11 @@ static int ast_do_masquerade(struct ast_channel *original)
} else
ast_log(LOG_WARNING, "Driver '%s' does not have a fixup routine (for %s)! Bad things may happen.\n",
original->type, original->name);
-
/* Signal any blocker */
if (original->blocking)
pthread_kill(original->blocker, SIGURG);
+ ast_log(LOG_DEBUG, "Done Masquerading %s(%d) into the structure of %s(%d)\n",
+ clone->name, clone->state, original->name, original->state);
return 0;
}
@@ -922,8 +1092,9 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
struct ast_channel *cs[3];
int to = -1;
struct ast_frame *f;
- struct ast_channel *who;
+ struct ast_channel *who = NULL;
int res;
+ int nativefailed=0;
/* Stop if we're a zombie or need a soft hangup */
if (c0->zombie || c0->softhangup || c1->zombie || c1->softhangup)
return -1;
@@ -941,24 +1112,38 @@ int ast_channel_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags
/* Keep track of bridge */
c0->bridge = c1;
c1->bridge = c0;
-
- if (c0->pvt->bridge &&
- (c0->pvt->bridge == c1->pvt->bridge)) {
- /* Looks like they share a bridge code */
- if (!c0->pvt->bridge(c0, c1, flags, fo, rc)) {
- c0->bridge = NULL;
- c1->bridge = NULL;
- return 0;
- }
- ast_log(LOG_WARNING, "Private bridge between %s and %s failed\n", c0->name, c1->name);
- /* If they return non-zero then continue on normally */
- }
-
-
-
cs[0] = c0;
cs[1] = c1;
for (/* ever */;;) {
+ /* Stop if we're a zombie or need a soft hangup */
+ if (c0->zombie || c0->softhangup || c1->zombie || c1->softhangup) {
+ *fo = NULL;
+ if (who) *rc = who;
+ res = 0;
+ break;
+ }
+ if (c0->pvt->bridge &&
+ (c0->pvt->bridge == c1->pvt->bridge) && !nativefailed) {
+ /* Looks like they share a bridge code */
+ if (!(res = c0->pvt->bridge(c0, c1, flags, fo, rc))) {
+ c0->bridge = NULL;
+ c1->bridge = NULL;
+ return 0;
+ }
+ /* If they return non-zero then continue on normally. Let "-2" mean don't worry about
+ my not wanting to bridge */
+ if ((res != -2) && (res != -3))
+ ast_log(LOG_WARNING, "Private bridge between %s and %s failed\n", c0->name, c1->name);
+ if (res != -3) nativefailed++;
+ }
+
+
+ if ((c0->writeformat != c1->readformat) || (c0->readformat != c1->writeformat)) {
+ if (ast_channel_make_compatible(c0, c1)) {
+ ast_log(LOG_WARNING, "Can't make %s and %s compatible\n", c0->name, c1->name);
+ return -1;
+ }
+ }
who = ast_waitfor_n(cs, 2, &to);
if (!who) {
ast_log(LOG_WARNING, "Nobody there??\n");
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h
index 3d0a30277..ef6cc4fff 100755
--- a/include/asterisk/channel.h
+++ b/include/asterisk/channel.h
@@ -27,7 +27,7 @@ extern "C" {
#ifdef DEBUG_THREADS
-#define TRIES 500
+#define TRIES 50
#include <errno.h>
#include <string.h>
@@ -136,6 +136,9 @@ struct ast_channel {
char exten[AST_MAX_EXTENSION]; /* Current extension number */
int priority; /* Current extension priority */
void *app[AST_CHANNEL_MAX_STACK]; /* Application information -- see assigned numbers */
+ char dtmfq[AST_MAX_EXTENSION]; /* Any/all queued DTMF characters */
+ int deferdtmf; /* Are DTMF digits being deferred */
+ struct ast_frame dtmff; /* DTMF frame */
struct ast_channel_pvt *pvt;
/* Private channel implementation details */
jmp_buf jmp[AST_CHANNEL_MAX_STACK]; /* Jump buffer used for returning from applications */
@@ -202,6 +205,12 @@ int ast_indicate(struct ast_channel *chan, int condition);
Returns < 0 on failure, 0 if nothing ever arrived, and the # of ms remaining otherwise */
int ast_waitfor(struct ast_channel *chan, int ms);
+/* Big momma function here. Wait for activity on any of the n channels, or any of the nfds
+ file descriptors. Returns the channel with activity, or NULL on error or if an FD
+ came first. If the FD came first, it will be returned in outfd, otherwise, outfd
+ will be -1 */
+struct ast_channel *ast_waitfor_nandfds(struct ast_channel **chan, int n, int *fds, int nfds, int *exception, int *outfd, int *ms);
+
/* Wait for input on an array of channels for a given # of milliseconds. Return channel
with activity, or NULL if none has activity. time "ms" is modified in-place, if applicable */
@@ -235,7 +244,8 @@ char ast_waitfordigit(struct ast_channel *c, int ms);
/* Read in a digit string "s", max length "len", maximum timeout between
digits "timeout" (-1 for none), terminated by anything in "enders". Give them rtimeout
- for the first digit */
+ for the first digit. Returns 0 on normal return, or 1 on a timeout. In the case of
+ a timeout, any digits that were read before the timeout will still be available in s. */
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders);
#define AST_BRIDGE_DTMF_CHANNEL_0 (1 << 0) /* Report DTMF on channel 0 */
@@ -275,6 +285,23 @@ int ast_channel_setoption(struct ast_channel *channel, int option, void *data, i
/* Query the value of an option, optionally blocking until a reply is received */
struct ast_frame *ast_channel_queryoption(struct ast_channel *channel, int option, void *data, int *datalen, int block);
+/* Returns 0 if channel does not support HTML or non-zero if it does */
+int ast_channel_supports_html(struct ast_channel *channel);
+
+/* Send HTML or URL on link. Returns 0 on success or -1 on failure */
+int ast_channel_sendhtml(struct ast_channel *channel, int subclass, char *data, int datalen);
+
+/* Send URL on link. Returns 0 on success or -1 on failure */
+int ast_channel_sendurl(struct ast_channel *channel, char *url);
+
+/* Defer DTMF so that you only read things like hangups and audio. Returns
+ non-zero if channel was already DTMF-deferred or 0 if channel is just now
+ being DTMF-deferred */
+int ast_channel_defer_dtmf(struct ast_channel *chan);
+
+/* Undo defer. ast_read will return any dtmf characters that were queued */
+void ast_channel_undefer_dtmf(struct ast_channel *chan);
+
#ifdef DO_CRASH
#define CRASH do { *((int *)0) = 0; } while(0)
#else
diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h
index ee28e2ec6..b456e5ce0 100755
--- a/include/asterisk/pbx.h
+++ b/include/asterisk/pbx.h
@@ -30,6 +30,30 @@ extern "C" {
#define AST_PBX_KEEPALIVE 10 /* Destroy the thread, but don't hang up the channel */
struct ast_context;
+struct ast_exten;
+struct ast_include;
+struct ast_ignorepat;
+struct ast_sw;
+
+struct ast_switch {
+ struct ast_switch *next; /* NULL */
+ char *name; /* Name of the switch */
+ char *description; /* Description of the switch */
+ int (*exists)(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, char *data);
+ int (*canmatch)(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, char *data);
+ int (*exec)(struct ast_channel *chan, char *context, char *exten, int priority, char *callerid, int newstack, char *data);
+};
+
+/* Register an alternative switch */
+extern int ast_register_switch(struct ast_switch *sw);
+
+/* Unregister an alternative switch */
+extern void ast_unregister_switch(struct ast_switch *sw);
+
+/* Look up an application */
+extern struct ast_app *pbx_findapp(char *app);
+
+int pbx_exec(struct ast_channel *c, struct ast_app *app, void *data, int newstack);
/* Register a new context */
struct ast_context *ast_context_create(char *name, char *registrar);
@@ -47,9 +71,15 @@ int ast_pbx_start(struct ast_channel *c);
/* Execute the PBX in the current thread */
int ast_pbx_run(struct ast_channel *c);
-/* Add an extension to an extension context, this time with an ast_context * */
+/* Add and extension to an extension context. Callerid is a pattern to match CallerID, or NULL to match any
+ callerid */
+int ast_add_extension(char *context, int replace, char *extension, int priority, char *callerid,
+ char *application, void *data, void (*datad)(void *), char *registrar);
+
+/* Add an extension to an extension context, this time with an ast_context *. CallerID is a pattern to match
+ on callerid, or NULL to not care about callerid */
int ast_add_extension2(struct ast_context *con,
- int replace, char *extension, int priority,
+ int replace, char *extension, int priority, char *callerid,
char *application, void *data, void (*datad)(void *),
char *registrar);
@@ -64,25 +94,23 @@ int ast_register_application(char *app, int (*execute)(struct ast_channel *, voi
int ast_unregister_application(char *app);
/* If an extension exists, return non-zero */
-int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority);
+int ast_exists_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid);
/* If "exten" *could be* a valid extension in this context with or without
some more digits, return non-zero. Basically, when this returns 0, no matter
what you add to exten, it's not going to be a valid extension anymore */
-int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority);
+int ast_canmatch_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid);
/* Determine if a given extension matches a given pattern (in NXX format) */
int ast_extension_match(char *pattern, char *extension);
/* Launch a new extension (i.e. new stack) */
-int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority);
+int ast_spawn_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid);
/* Execute an extension. If it's not available, do whatever you should do for
default extensions and halt the thread if necessary. This function does not
return, except on error. */
-int ast_exec_extension(struct ast_channel *c, char *context, char *exten, int priority);
-/* Longest extension */
-int ast_pbx_longest_extension(char *context);
+int ast_exec_extension(struct ast_channel *c, char *context, char *exten, int priority, char *callerid);
/* Add an include */
int ast_context_add_include(char *context, char *include, char *registrar);
@@ -92,6 +120,70 @@ int ast_context_add_include2(struct ast_context *con, char *include, char *regis
int ast_context_remove_include(char *context, char *include, char *registrar);
int ast_context_remove_include2(struct ast_context *con, char *include, char *registrar);
+/* Add a switch */
+int ast_context_add_switch(char *context, char *sw, char *data, char *registrar);
+int ast_context_add_switch2(struct ast_context *con, char *sw, char *data, char *registrar);
+
+/* Remove a switch */
+int ast_context_remove_switch(char *context, char *sw, char *data, char *registrar);
+int ast_context_remove_switch2(struct ast_context *con, char *sw, char *data, char *registrar);
+
+/* Simply remove extension from context */
+int ast_context_remove_extension(char *context, char *extension, int priority,
+ char *registrar);
+int ast_context_remove_extension2(struct ast_context *con, char *extension,
+ int priority, char *registrar);
+
+/* Add an ignorepat */
+int ast_context_add_ignorepat(char *context, char *ignorepat, char *registrar);
+int ast_context_add_ignorepat2(struct ast_context *con, char *ignorepat, char *registrar);
+
+/* Remove an ignorepat */
+int ast_context_remove_ignorepat(char *context, char *ignorepat, char *registrar);
+int ast_context_remove_ignorepat2(struct ast_context *con, char *ignorepat, char *registrar);
+
+/* Check if a number should be ignored with respect to dialtone cancellation. Returns 0 if
+ the pattern should not be ignored, or non-zero if the pattern should be ignored */
+int ast_ignore_pattern(char *context, char *pattern);
+
+/* Locking functions for outer modules, especially for completion functions */
+int ast_lock_contexts(void);
+int ast_unlock_contexts(void);
+
+int ast_lock_context(struct ast_context *con);
+int ast_unlock_context(struct ast_context *con);
+
+/* Functions for returning values from structures */
+char *ast_get_context_name(struct ast_context *con);
+char *ast_get_extension_name(struct ast_exten *exten);
+char *ast_get_include_name(struct ast_include *include);
+char *ast_get_ignorepat_name(struct ast_ignorepat *ip);
+char *ast_get_switch_name(struct ast_sw *sw);
+char *ast_get_switch_data(struct ast_sw *sw);
+
+/* Other extension stuff */
+int ast_get_extension_priority(struct ast_exten *exten);
+char *ast_get_extension_app(struct ast_exten *e);
+void *ast_get_extension_app_data(struct ast_exten *e);
+
+/* Registrar info functions ... */
+char *ast_get_context_registrar(struct ast_context *c);
+char *ast_get_extension_registrar(struct ast_exten *e);
+char *ast_get_include_registrar(struct ast_include *i);
+char *ast_get_ignorepat_registrar(struct ast_ignorepat *ip);
+char *ast_get_switch_registrar(struct ast_sw *sw);
+
+/* Walking functions ... */
+struct ast_context *ast_walk_contexts(struct ast_context *con);
+struct ast_exten *ast_walk_context_extensions(struct ast_context *con,
+ struct ast_exten *priority);
+struct ast_exten *ast_walk_extension_priorities(struct ast_exten *exten,
+ struct ast_exten *priority);
+struct ast_include *ast_walk_context_includes(struct ast_context *con,
+ struct ast_include *inc);
+struct ast_ignorepat *ast_walk_context_ignorepats(struct ast_context *con,
+ struct ast_ignorepat *ip);
+struct ast_sw *ast_walk_context_switches(struct ast_context *con, struct ast_sw *sw);
#if defined(__cplusplus) || defined(c_plusplus)
}
#endif