Index: loader.c
===================================================================
RCS file: /usr/cvsroot/asterisk/loader.c,v
retrieving revision 1.40
diff -u -r1.40 loader.c
--- loader.c	22 Apr 2005 13:11:34 -0000	1.40
+++ loader.c	25 May 2005 21:09:03 -0000
@@ -44,6 +44,9 @@
 { 0x8e, 0x93, 0x22, 0x83, 0xf5, 0xc3, 0xc0, 0x75,
   0xff, 0x8b, 0xa9, 0xbe, 0x7c, 0x43, 0x74, 0x63 };
 
+/*
+ * A module is described by this data structure.
+ */
 struct module {
 	int (*load_module)(void);
 	int (*unload_module)(void);
@@ -54,8 +57,43 @@
 	void *lib;
 	char resource[256];
 	struct module *next;
+
+	enum {	/* possible states of a module */
+		MS_NEW,			/* nothing known */
+		MS_RESOLVED,		/* all required resolved */
+		MS_CANLOAD,		/* as above, plus cyclic depend.*/
+		MS_ACTIVE,		/* all done */
+		MS_FAILED,		/* cannot load */
+	} status;
+	struct symbol_entry *required;
+	struct symbol_entry *es;
+	int export_refcount;	/* how many users of exported symbols */
 };
 
+/*
+ * helper routine to print the symbolic name associated to a state
+ */
+static const char *st_name(int status)
+{
+	/* try to resolve required symbols */
+	const char *st;
+	switch (status) {
+#define ST(x)	case x: st = # x; break;
+	ST(MS_NEW);
+	ST(MS_FAILED);
+	ST(MS_RESOLVED);
+	ST(MS_ACTIVE);
+	ST(MS_CANLOAD);
+	default: st = "unknown";
+	}
+	return st;
+#undef ST(x)
+}
+
+/*
+ * Routines to check that the key() returned by a module is
+ * what we expect.
+ */
 static int printdigest(unsigned char *d)
 {
 	int x;
@@ -73,12 +111,11 @@
 
 static int key_matches(char *key1, char *key2)
 {
-	int match = 1;
 	int x;
-	for (x=0;x<16;x++) {
-		match &= (key1[x] == key2[x]);
-	}
-	return match;
+	for (x=0;x<16;x++)
+		if (key1[x] != key2[x])
+			return 0;
+	return 1;
 }
 
 static int verify_key(char *key)
@@ -94,54 +131,145 @@
 	return -1;
 }
 
-static struct loadupdate {
-	int (*updater)(void);
-	struct loadupdate *next;
-} *updaters = NULL;
 
 AST_MUTEX_DEFINE_STATIC(modlock);
 AST_MUTEX_DEFINE_STATIC(reloadlock);
 
-static struct module *module_list=NULL;
+/*
+ * The list of modules.
+ */
+static struct module *ml_head=NULL;
+static struct module *ml_tail=NULL;
 static int modlistver = 0;
 
+/*
+ * append a module to the list.
+ * XXX watch out for recursive calls in m->load_module()
+ */
+static void module_append(struct module *m)
+{
+	m->next = NULL;
+	if (ml_head == NULL)
+		ml_head = m;
+	else
+		ml_tail->next = m;
+	ml_tail = m;
+}
+
+static struct module *find_module(const char *resource)
+{
+	struct module *m;
+	for (m = ml_head; m; m = m->next) {
+		if (!strcasecmp(resource, m->resource))
+			break;
+	}
+	return m;
+}
+
+/*
+ * Fetch/release an exported symbol - modify export_refcount by delta
+ * on success, and return symbol value.
+ * If src is non-NULL, non exit *src points to the module.
+ */
+static void *module_symbol_helper(const char *name,
+		int delta, struct module **src)
+{
+	void *ret = NULL;
+	struct module *m;
+	struct symbol_entry *es;
+
+	for (m = ml_head; m; m = m->next) {
+		/* cannot 'get' a symbole from a failed module */
+		if (delta > 0 && m->status == MS_FAILED)
+			continue;
+		for (es = m->es; ret == NULL && es && es->name; es++) {
+			if (!strcmp(es->name, name)) {
+				ret = es->value;
+				m->export_refcount += delta;
+				if (src)
+					*src = m;
+				break;
+			}
+		}
+		if (ret)
+			break;
+	}
+	if (ret == NULL)
+		ast_log(LOG_WARNING, "symbol %s not found\n", name);
+	return ret;
+}
+
+static void *release_module_symbol(const char *name)
+{
+	return module_symbol_helper(name, -1, NULL);
+}
+
+static void *get_module_symbol(const char *name, struct module **src)
+{
+	return module_symbol_helper(name, +1, src);
+}
+
+/*
+ * Helper function to release a module. Release refcounts to symbols
+ * imported, and change state to MS_FAILED.
+ */
+static void release_module(struct module *m)
+{
+	struct symbol_entry *s;
+	for (s = m->required; s && s->name != NULL; s++) {
+		if (s->value != NULL) {
+			release_module_symbol(s->name);
+			s->value = NULL;
+		}
+	}
+	m->status = MS_FAILED;
+}
+
+static struct loadupdate {
+	int (*updater)(void);
+	struct loadupdate *next;
+} *updaters = NULL;
+
+/*
+ * API functio to unload a resource.
+ * XXX check behaviour on recursive calls.
+ */
 int ast_unload_resource(const char *resource_name, int force)
 {
 	struct module *m, *ml = NULL;
 	int res = -1;
-	if (ast_mutex_lock(&modlock))
-		ast_log(LOG_WARNING, "Failed to lock\n");
-	m = module_list;
-	while(m) {
-		if (!strcasecmp(m->resource, resource_name)) {
-			if ((res = m->usecount()) > 0)  {
-				if (force) 
-					ast_log(LOG_WARNING, "Warning:  Forcing removal of module %s with use count %d\n", resource_name, res);
-				else {
-					ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name, res);
-					ast_mutex_unlock(&modlock);
-					return -1;
-				}
-			}
-			res = m->unload_module();
-			if (res) {
-				ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
-				if (force <= AST_FORCE_FIRM) {
-					ast_mutex_unlock(&modlock);
-					return -1;
-				} else
-					ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
+	ast_mutex_lock(&modlock);
+	for (ml = NULL, m = ml_head; m; ml = m, m = m->next) {
+		if (strcasecmp(m->resource, resource_name) != 0)
+			continue;
+		if ((res = m->usecount()) > 0)  {
+			if (force) 
+				ast_log(LOG_WARNING, "Warning:  Forcing removal of module %s with use count %d\n", resource_name, res);
+			else {
+				ast_log(LOG_WARNING, "Soft unload failed, '%s' has use count %d\n", resource_name, res);
+				ast_mutex_unlock(&modlock);
+				return -1;
 			}
-			if (ml)
-				ml->next = m->next;
-			else
-				module_list = m->next;
-			dlclose(m->lib);
-			free(m);
-			break;
 		}
-		ml = m;
-		m = m->next;
+		res = m->unload_module();
+		if (res) {
+			ast_log(LOG_WARNING, "Firm unload failed for %s\n", resource_name);
+			if (force <= AST_FORCE_FIRM) {
+				ast_mutex_unlock(&modlock);
+				return -1;
+			} else
+				ast_log(LOG_WARNING, "** Dangerous **: Unloading resource anyway, at user request\n");
+		}
+		release_module(m);
+		if (ml)
+			ml->next = m->next;
+		else
+			ml_head = m->next;
+		if (ml_tail == m)
+			ml_tail = ml;
+		dlclose(m->lib);
+		free(m);
+		break;
 	}
 	modlistver = rand();
 	ast_mutex_unlock(&modlock);
@@ -149,7 +277,12 @@
 	return res;
 }
 
-char *ast_module_helper(char *line, char *word, int pos, int state, int rpos, int needsreload)
+/*
+ * Helper function used by the cli to do something on modules
+ * XXX what ?
+ */
+char *ast_module_helper(char *line, char *word, int pos, int state,
+	int rpos, int needsreload)
 {
 	struct module *m;
 	int which=0;
@@ -157,13 +290,11 @@
 	if (pos != rpos)
 		return NULL;
 	ast_mutex_lock(&modlock);
-	m = module_list;
-	while(m) {
+	for (m = ml_head; m; m = m->next) {
 		if (!strncasecmp(word, m->resource, strlen(word)) && (m->reload || !needsreload)) {
 			if (++which > state)
 				break;
 		}
-		m = m->next;
 	}
 	if (m) {
 		ret = strdup(m->resource);
@@ -193,7 +324,6 @@
 	struct module *m;
 	int reloaded = 0;
 	int oldversion;
-	int (*reload)(void);
 	/* We'll do the logger and manager the favor of calling its reload here first */
 
 	if (ast_mutex_trylock(&reloadlock)) {
@@ -224,339 +354,403 @@
 
 	ast_mutex_lock(&modlock);
 	oldversion = modlistver;
-	m = module_list;
-	while(m) {
+	for (m = ml_head; m; m = m->next) {
 		if (!name || !strcasecmp(name, m->resource)) {
 			if (reloaded < 1)
 				reloaded = 1;
-			reload = m->reload;
 			ast_mutex_unlock(&modlock);
-			if (reload) {
+			if (m->reload) {
 				reloaded = 2;
 				if (option_verbose > 2) 
 					ast_verbose(VERBOSE_PREFIX_3 "Reloading module '%s' (%s)\n", m->resource, m->description());
-				reload();
+				m->reload();
 			}
 			ast_mutex_lock(&modlock);
 			if (oldversion != modlistver)
 				break;
 		}
-		m = m->next;
 	}
 	ast_mutex_unlock(&modlock);
 	ast_mutex_unlock(&reloadlock);
 	return reloaded;
 }
 
-static int __load_resource(const char *resource_name, const struct ast_config *cfg)
+/*
+ * lookup a symbol with or without leading '_'
+ * accept either form
+ */
+static void *find_symbol(struct module *m, char *name, int verbose)
+{
+	int l = strlen(name);
+	char *n1 = alloca(l+2); /* room for leading '_' and final '\0' */
+	void *s;
+
+	n1[0] = '_';
+	strcpy((name[0] == '_') ? n1 : n1+1, name);
+ 	s = dlsym(m->lib, n1+1);	/* try without '_' */
+	if (s == NULL)
+		s = dlsym(m->lib, n1);
+	if (verbose && s == NULL)
+		ast_log(LOG_WARNING, "No symbol '%s' in module '%s\n",
+			n1, m->resource);
+	return s;
+}
+
+/*
+ * Find or initialize the record for the resource
+ */
+static struct module * __load_resource(const char *name, int verbose)
 {
 	static char fn[256];
 	int errors=0;
-	int res;
-	struct module *m;
-	int flags=RTLD_NOW;
-#ifdef RTLD_GLOBAL
-	char *val;
-#endif
-	char *key;
+	struct module *m = NULL;
+	char *key = NULL;
 	char tmp[80];
 
-	if (strncasecmp(resource_name, "res_", 4)) {
-#ifdef RTLD_GLOBAL
-		if (cfg) {
-			if ((val = ast_variable_retrieve(cfg, "global", resource_name))
-					&& ast_true(val))
-				flags |= RTLD_GLOBAL;
+	if (verbose) {
+		if (option_debug && !option_verbose)
+			ast_log(LOG_DEBUG, "Loading module %s\n", name);
+		if (option_verbose) {
+			ast_verbose(VERBOSE_PREFIX_1 "[%s]",
+				term_color(tmp, name, COLOR_BRWHITE, 0, sizeof(tmp)));
+			fflush(stdout);
 		}
-#endif
-	} else {
-		/* Resource modules are always loaded global and lazy */
-#ifdef RTLD_GLOBAL
-		flags = (RTLD_GLOBAL | RTLD_LAZY);
-#else
-		flags = RTLD_LAZY;
-#endif
-	}
-	
-	if (ast_mutex_lock(&modlock))
-		ast_log(LOG_WARNING, "Failed to lock\n");
-	m = module_list;
-	while(m) {
-		if (!strcasecmp(m->resource, resource_name)) {
-			ast_log(LOG_WARNING, "Module '%s' already exists\n", resource_name);
-			ast_mutex_unlock(&modlock);
-			return -1;
-		}
-		m = m->next;
+	}
+
+	m = find_module(name);
+	if (m) { /* not fatal, already in the list */
+		ast_mutex_unlock(&modlock);
+		return m;
 	}
 	m = malloc(sizeof(struct module));	
 	if (!m) {
 		ast_log(LOG_WARNING, "Out of memory\n");
-		ast_mutex_unlock(&modlock);
-		return -1;
+		goto done;
 	}
-	strncpy(m->resource, resource_name, sizeof(m->resource)-1);
-	if (resource_name[0] == '/') {
-		strncpy(fn, resource_name, sizeof(fn)-1);
+	m->status = MS_NEW;
+	strncpy(m->resource, name, sizeof(m->resource)-1);
+	if (name[0] == '/') {
+		strncpy(fn, name, sizeof(fn)-1);
 	} else {
-		snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_MODULE_DIR, resource_name);
+		snprintf(fn, sizeof(fn), "%s/%s", (char *)ast_config_AST_MODULE_DIR, name);
 	}
-	m->lib = dlopen(fn, flags);
+	m->lib = dlopen(fn, RTLD_NOW | RTLD_LOCAL);
 	if (!m->lib) {
 		ast_log(LOG_WARNING, "%s\n", dlerror());
-		free(m);
-		ast_mutex_unlock(&modlock);
-		return -1;
+		goto done;
 	}
-	m->load_module = dlsym(m->lib, "load_module");
+
+	/*
+	 * Find all symbols required by the API
+	 * XXX in the future, just one struct
+	 */
+	m->load_module = find_symbol(m, "load_module", 1);
 	if (m->load_module == NULL)
-		m->load_module = dlsym(m->lib, "_load_module");
-	if (!m->load_module) {
-		ast_log(LOG_WARNING, "No load_module in module %s\n", fn);
 		errors++;
-	}
-	m->unload_module = dlsym(m->lib, "unload_module");
+	m->unload_module = find_symbol(m, "unload_module", 1);
 	if (m->unload_module == NULL)
-		m->unload_module = dlsym(m->lib, "_unload_module");
-	if (!m->unload_module) {
-		ast_log(LOG_WARNING, "No unload_module in module %s\n", fn);
 		errors++;
-	}
-	m->usecount = dlsym(m->lib, "usecount");
-	if (m->usecount == NULL)
-		m->usecount = dlsym(m->lib, "_usecount");
-	if (!m->usecount) {
-		ast_log(LOG_WARNING, "No usecount in module %s\n", fn);
+	m->usecount = find_symbol(m, "usecount", 1);
+	if (!m->usecount)
 		errors++;
-	}
-	m->description = dlsym(m->lib, "description");
+	m->description = find_symbol(m, "description", 1);
 	if (m->description == NULL)
-		m->description = dlsym(m->lib, "_description");
-	if (!m->description) {
-		ast_log(LOG_WARNING, "No description in module %s\n", fn);
 		errors++;
-	}
-	m->key = dlsym(m->lib, "key");
+	m->key = find_symbol(m, "key", 1);
 	if (m->key == NULL)
-		m->key = dlsym(m->lib, "_key");
-	if (!m->key) {
-		ast_log(LOG_WARNING, "No key routine in module %s\n", fn);
 		errors++;
-	}
-	m->reload = dlsym(m->lib, "reload");
-	if (m->reload == NULL)
-		m->reload = dlsym(m->lib, "_reload");
+	m->reload = find_symbol(m, "reload", 0); /* this is optional */
 	if (!m->key || !(key = m->key())) {
 		ast_log(LOG_WARNING, "Key routine returned NULL in module %s\n", fn);
-		key = NULL;
 		errors++;
 	}
 	if (key && verify_key(key)) {
 		ast_log(LOG_WARNING, "Unexpected key returned by module %s\n", fn);
 		errors++;
 	}
+	m->es = find_symbol(m, "exported_symbols", 0);
+	if (m->es) {	/* check that no NULL symbols are exported */
+		struct symbol_entry *es;
+		ast_log(LOG_WARNING, "module %s exports the following symbols\n",
+				name);
+		for (es = m->es; es->name; es++) {
+			void **p = es->value;
+			int i;
+
+			ast_log(LOG_WARNING, "\taddr %p size %8d %s\n",
+				es->value, es->size, es->name);
+			for (i = 0; i <  es->size / sizeof(void *); i++, p++) {
+				if (*p == NULL) {
+					ast_log(LOG_WARNING, "\t *** null field at offset %d\n", i);
+					errors++;
+				}
+			}
+		}
+	}
+	m->required = find_symbol(m, "required_symbols", 0);
 	if (errors) {
-		ast_log(LOG_WARNING, "%d error(s) loading module %s, aborted\n", errors, fn);
+		ast_log(LOG_WARNING, "%d error(s) loading module %s, aborted\n",
+			errors, fn);
 		dlclose(m->lib);
-		free(m);
-		ast_mutex_unlock(&modlock);
-		return -1;
+		goto done;
 	}
 	if (!fully_booted) {
 		if (option_verbose) 
-			ast_verbose( " => (%s)\n", term_color(tmp, m->description(), COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
+			ast_verbose(" => (%s)\n",
+				term_color(tmp, m->description(),
+					COLOR_BROWN, COLOR_BLACK, sizeof(tmp)));
 		if (option_console && !option_verbose)
-			ast_verbose( ".");
+			ast_verbose(".");
 	} else {
 		if (option_verbose)
-			ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", fn, m->description());
+			ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n",
+				fn, m->description());
 	}
-
-	/* add module 'm' to end of module_list chain
-  	   so reload commands will be issued in same order modules were loaded */
-	m->next = NULL;
-	if (module_list == NULL) {
-		/* empty list so far, add at front */
-		module_list = m;
-	}
-	else {
-		struct module *i;
-		/* find end of chain, and add there */
-		for (i = module_list; i->next; i = i->next)
-			;
-		i->next = m;
-	}
-	
+	module_append(m);
 	modlistver = rand();
-	ast_mutex_unlock(&modlock);
-	if ((res = m->load_module())) {
-		ast_log(LOG_WARNING, "%s: load_module failed, returning %d\n", m->resource, res);
-		ast_unload_resource(resource_name, 0);
-		return -1;
-	}
-	ast_update_use_count();
 	return 0;
+
+done:
+	if (m)
+		free(m);
+	if (verbose)
+		ast_log(LOG_WARNING, "Loading module %s failed!\n", name);
+	return NULL;
 }
 
-int ast_load_resource(const char *resource_name)
-{
-	int o;
-	struct ast_config *cfg = NULL;
-	int res;
-
-	/* Keep the module file parsing silent */
-	o = option_verbose;
-	option_verbose = 0;
-	cfg = ast_config_load(AST_MODULE_CONFIG);
-	option_verbose = o;
-	res = __load_resource(resource_name, cfg);
-	if (cfg)
-		ast_config_destroy(cfg);
-	return res;
-}	
 
-static int ast_resource_exists(char *resource)
+/*
+ * Resolve symbols and determine if the suppliers are in MS_ACTIVE
+ * Return true if can try loading (i.e. all suppliers are MS_ACTIVE,
+ * or the module is in MS_CANLOAD meaning a cyclic dependency).
+ * Release the module if a symbol cannot be resolved or the supplier
+ * is in MS_FAILED
+ */
+static int resolve(struct module *m)
 {
-	struct module *m;
-	if (ast_mutex_lock(&modlock))
-		ast_log(LOG_WARNING, "Failed to lock\n");
-	m = module_list;
-	while(m) {
-		if (!strcasecmp(resource, m->resource))
+	int canload = 1;
+	struct symbol_entry *s;
+
+	if (m->status == MS_FAILED || m->status == MS_ACTIVE)
+		return 0;
+	if (m->status == MS_CANLOAD)
+		return 1;
+	/* resolve missing symbols, or verify existing ones */
+	for (s = m->required; s && s->name != NULL; s++) {
+		void **p = (void **)(s->value);
+
+		if (*p == NULL)
+			*p = get_module_symbol(s->name, &s->src);
+		if (*p == NULL || s->src->status == MS_FAILED) {	/* fail */
+			ast_log(LOG_WARNING,
+						"Failed symbol %s for module %s\n",
+						s->name, m->resource);
+			release_module(m);
 			break;
-		m = m->next;
+		}
+		if (s->src->status != MS_ACTIVE)
+			canload = 0;
 	}
-	ast_mutex_unlock(&modlock);
-	if (m)
-		return -1;
-	else
-		return 0;
+	return canload;
 }
 
-static const char *loadorder[] =
+/*
+ * Fixup references and load modules according to their dependency order.
+ * Called when new modules are added to the list.
+ * The algorithm is as follows:
+ * - all modules MS_FAILED are changed to MS_NEW, in case something
+ *	 happened that could help them.
+ * - first try to resolve symbols. If successful, change the
+ *   module's state to MS_RESOLVED otherwise to MS_FAILED
+ * - repeat on all modules until there is progress:
+ *    . if it is MS_ACTIVE or MS_FAILED, continue (no progress)
+ *    . if one has all required modules in MS_ACTIVE, try to load it.
+ *      If successful it becomes MS_ACTIVE itself, otherwise
+ *		MS_FAILED and releases all symbols.
+ *		In any case, we have progress.
+ *    . if one of the dependencies is MS_FAILED, release and set to
+ *      MS_FAILED here too. We have progress.
+ * - if we have no progress there is a cyclic dependency.
+ *	 Take first and change to MS_CANLOAD, i.e. as if all required are
+ *	 MS_ACTIVE. we have progress, so repeat.
+ * NOTE:
+ *   must be called with lock held
+ *   recursive calls simply return success.
+ */
+static int fixup(const char *caller)
 {
-	"res_",
-	"chan_",
-	"pbx_",
-	NULL,
-};
+	struct module *m;
+	int total, new, cycle;
+	static int in_fixup = 0;	/* disable recursive calls */
+
+	if (in_fixup)
+		return 0;
+	in_fixup++;
+	total = 0;
+	new = 0;
+	for (m = ml_head; m; m = m->next) {
+		total++;
+		if (m->status == MS_FAILED)
+			m->status = MS_NEW;
+		if (m->status == MS_NEW)
+			new++;
+		if (m->status == MS_NEW && (m->es || m->required))	/* diagnostic */
+			ast_log(LOG_WARNING,
+				"module %-30s exports %p requires %p status %d\n",
+				m->resource, m->es, m->required, m->status);
+	}
+	ast_log(LOG_WARNING, "---- fixup (%s): %d modules, %d new ---\n",
+		caller, total, new);
+	for (cycle = 0;;cycle++) {
+		int progress = 0;
+
+		ast_log(LOG_WARNING, "---- fixup: cycle %d ---\n", cycle);
+		for (m = ml_head; m; m = m->next) {
+			int canload = resolve(m);
+			if (canload || m->status == MS_NEW)
+				progress = 1;
+			if (canload) {
+				if (m->load_module()) {	/* error */
+					ast_log(LOG_WARNING, "load_module %s fail\n",
+						m->resource);
+					release_module(m);
+				} else {
+					ast_log(LOG_WARNING, "load_module %s success\n",
+						m->resource);
+					m->status = MS_ACTIVE;
+				}
+			}
+		}
+		if (!progress) {
+			/* resolve cyclic dependencies. Set one to MS_CANLOAD and repeat */
+			for (m = ml_head; m; m = m->next) {
+				if (m->status == MS_RESOLVED) {
+					m->status = MS_CANLOAD;
+					progress = 1;
+					break;
+				}
+			}
+			if (!progress)
+				break;
+		}
+	}
+	ast_log(LOG_WARNING, "---- fixup complete ---\n");
+	in_fixup--;
+	return 0;
+}
 
+/*
+ * load all modules from a configuration
+ */
 int load_modules()
 {
 	struct ast_config *cfg;
 	struct ast_variable *v;
-	char tmp[80];
+	DIR *mods = NULL;
+	struct dirent *d;
+
 	if (option_verbose) 
 		ast_verbose( "Asterisk Dynamic Loader Starting:\n");
 	cfg = ast_config_load(AST_MODULE_CONFIG);
+	ast_mutex_lock(&modlock);
 	if (cfg) {
 		/* Load explicitly defined modules */
-		v = ast_variable_browse(cfg, "modules");
-		while(v) {
-			if (!strcasecmp(v->name, "load")) {
-				if (option_debug && !option_verbose)
-					ast_log(LOG_DEBUG, "Loading module %s\n", v->value);
-				if (option_verbose) {
-					ast_verbose( VERBOSE_PREFIX_1 "[%s]", term_color(tmp, v->value, COLOR_BRWHITE, 0, sizeof(tmp)));
-					fflush(stdout);
-				}
-				if (__load_resource(v->value, cfg)) {
-					ast_log(LOG_WARNING, "Loading module %s failed!\n", v->value);
-					if (cfg)
-						ast_config_destroy(cfg);
-					return -1;
-				}
-			}
-			v=v->next;
+		if (option_verbose) 
+			ast_verbose( "Load Explicit Modules:\n");
+		for (v = ast_variable_browse(cfg, "modules"); v; v = v->next) {
+			if (strcasecmp(v->name, "load") != 0)
+				continue;
+			__load_resource(v->value, 1 /* verbose */);
 		}
 	}
 	if (!cfg || ast_true(ast_variable_retrieve(cfg, "modules", "autoload"))) {
-		/* Load all modules */
-		DIR *mods;
-		struct dirent *d;
-		int x;
-		/* Loop through each order */
-		for (x=0;x<sizeof(loadorder) / sizeof(loadorder[0]);x++) {
-			mods = opendir((char *)ast_config_AST_MODULE_DIR);
-			if (mods) {
-				while((d = readdir(mods))) {
-					/* Must end in .so to load it.  */
-					if ((strlen(d->d_name) > 3) && 
-					    (!loadorder[x] || !strncasecmp(d->d_name, loadorder[x], strlen(loadorder[x]))) && 
-					    !strcasecmp(d->d_name + strlen(d->d_name) - 3, ".so") &&
-						!ast_resource_exists(d->d_name)) {
-						/* It's a shared library -- Just be sure we're allowed to load it -- kinda
-						   an inefficient way to do it, but oh well. */
-						if (cfg) {
-							v = ast_variable_browse(cfg, "modules");
-							while(v) {
-								if (!strcasecmp(v->name, "noload") &&
-								    !strcasecmp(v->value, d->d_name)) 
-									break;
-								v = v->next;
-							}
-							if (v) {
-								if (option_verbose) {
-									ast_verbose( VERBOSE_PREFIX_1 "[skipping %s]\n", d->d_name);
-									fflush(stdout);
-								}
-								continue;
-							}
-							
-						}
-					    if (option_debug && !option_verbose)
-							ast_log(LOG_DEBUG, "Loading module %s\n", d->d_name);
-						if (option_verbose) {
-							ast_verbose( VERBOSE_PREFIX_1 "[%s]", term_color(tmp, d->d_name, COLOR_BRWHITE, 0, sizeof(tmp)));
-							fflush(stdout);
-						}
-						if (__load_resource(d->d_name, cfg)) {
-							ast_log(LOG_WARNING, "Loading module %s failed!\n", d->d_name);
-							if (cfg)
-								ast_config_destroy(cfg);
-							return -1;
-						}
+		mods = opendir((char *)ast_config_AST_MODULE_DIR);
+		if (mods == NULL) {
+			if (!option_quiet)
+				ast_log(LOG_WARNING, "Unable to open modules directory %s.\n",
+					ast_config_AST_MODULE_DIR);
+			
+		}
+	}
+	if (mods) {
+		while((d = readdir(mods))) {
+			/* Must end in .so to load it.  */
+			int want;
+
+			want = strlen(d->d_name) > 3 && 
+					!strcasecmp(d->d_name + strlen(d->d_name) - 3, ".so") &&
+					!find_module(d->d_name);
+				
+			if (!want)
+				continue;
+
+			/* It's a shared library --
+			 * Just be sure we're allowed to load it -- kinda
+			 * an inefficient way to do it, but oh well. */
+			if (cfg) {
+				for (v = ast_variable_browse(cfg, "modules");v; v = v->next) {
+					if (!strcasecmp(v->name, "noload") &&
+							!strcasecmp(v->value, d->d_name)) 
+						break;
+				}
+				if (v) {
+					if (option_verbose) {
+						ast_verbose( VERBOSE_PREFIX_1 "[skipping %s]\n",
+							d->d_name);
+						fflush(stdout);
 					}
+					continue;
 				}
-				closedir(mods);
-			} else {
-				if (!option_quiet)
-					ast_log(LOG_WARNING, "Unable to open modules directory %s.\n", (char *)ast_config_AST_MODULE_DIR);
 			}
+			__load_resource(d->d_name, 1 /* verbose */);
 		}
+		closedir(mods);
 	} 
-	ast_config_destroy(cfg);
+	fixup("load_modules");
+	ast_mutex_unlock(&modlock);
+	if (cfg)
+		ast_config_destroy(cfg);
 	return 0;
 }
 
+/*
+ * load a single module (API call).
+ * (recursive calls from load_module() succeed.
+ */
+int ast_load_resource(const char *resource_name)
+{
+	struct module *m;
+	int ret;
+
+	ast_mutex_unlock(&modlock);
+	m = __load_resource(resource_name, 0);
+	fixup(resource_name);
+	ret = (m->status == MS_FAILED) ? -1 : 0;
+	ast_mutex_unlock(&modlock);
+	return ret;
+}	
+
 void ast_update_use_count(void)
 {
 	/* Notify any module monitors that the use count for a 
 	   resource has changed */
 	struct loadupdate *m;
-	if (ast_mutex_lock(&modlock))
-		ast_log(LOG_WARNING, "Failed to lock\n");
-	m = updaters;
-	while(m) {
+	ast_mutex_lock(&modlock);
+	for (m = updaters; m ; m = m->next)
 		m->updater();
-		m = m->next;
-	}
 	ast_mutex_unlock(&modlock);
-	
 }
 
-int ast_update_module_list(int (*modentry)(char *module, char *description, int usecnt, char *like), char *like)
+int ast_update_module_list(int (*modentry)(char *module,
+		char *description, int usecnt, char *like), char *like)
 {
 	struct module *m;
-	int unlock = -1;
-	int total_mod_loaded = 0;
-	if (ast_mutex_trylock(&modlock))
-		unlock = 0;
-	m = module_list;
-	while(m) {
-		total_mod_loaded += modentry(m->resource, m->description(), m->usecount(), like);
-		m = m->next;
-	}
+	int unlock, total_mod_loaded = 0;
+
+	unlock = ast_mutex_trylock(&modlock) ? 0 : 1;
+	for (m = ml_head; m; m = m->next)
+		total_mod_loaded += modentry(m->resource,
+				m->description(), m->usecount(), like);
 	if (unlock)
 		ast_mutex_unlock(&modlock);
 	return total_mod_loaded;
@@ -566,38 +760,32 @@
 {
 	struct loadupdate *tmp;
 	/* XXX Should be more flexible here, taking > 1 verboser XXX */
-	if ((tmp = malloc(sizeof (struct loadupdate)))) {
-		tmp->updater = v;
-		if (ast_mutex_lock(&modlock))
-			ast_log(LOG_WARNING, "Failed to lock\n");
-		tmp->next = updaters;
-		updaters = tmp;
-		ast_mutex_unlock(&modlock);
-		return 0;
-	}
-	return -1;
+	tmp = malloc(sizeof (struct loadupdate));
+	if (tmp == NULL)
+		return -1;
+	tmp->updater = v;
+	ast_mutex_lock(&modlock);
+	tmp->next = updaters;
+	updaters = tmp;
+	ast_mutex_unlock(&modlock);
+	return 0;
 }
 
 int ast_loader_unregister(int (*v)(void))
 {
-	int res = -1;
-	struct loadupdate *tmp, *tmpl=NULL;
-	if (ast_mutex_lock(&modlock))
-		ast_log(LOG_WARNING, "Failed to lock\n");
-	tmp = updaters;
-	while(tmp) {
-		if (tmp->updater == v)	{
-			if (tmpl)
-				tmpl->next = tmp->next;
+	struct loadupdate *u, *pu;
+
+	ast_mutex_lock(&modlock);
+	for (pu = NULL, u = updaters; pu; pu = u, u = u->next) {
+		if (u->updater == v)	{
+			if (pu)
+				pu->next = u->next;
 			else
-				updaters = tmp->next;
+				updaters = u->next;
 			break;
 		}
-		tmpl = tmp;
-		tmp = tmp->next;
 	}
-	if (tmp)
-		res = 0;
 	ast_mutex_unlock(&modlock);
-	return res;
+	return (u ? 0 : -1);
 }
+/* end of file */
Index: apps/app_adsiprog.c
===================================================================
RCS file: /usr/cvsroot/asterisk/apps/app_adsiprog.c,v
retrieving revision 1.10
diff -u -r1.10 app_adsiprog.c
--- apps/app_adsiprog.c	21 Apr 2005 06:02:43 -0000	1.10
+++ apps/app_adsiprog.c	25 May 2005 21:09:05 -0000
@@ -39,6 +39,13 @@
 
 static char *synopsis = "Load Asterisk ADSI Scripts into phone";
 
+static struct adsi_services *adsi;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(adsi),
+        { NULL, NULL }
+};
+
+
 /* #define DUMP_MESSAGES */
 
 static char *descrip =
@@ -1432,11 +1439,11 @@
 		return -1;
 
 	/* Start an empty ADSI Session */
-	if (adsi_load_session(chan, NULL, 0, 1) < 1) 
+	if (adsi->load_session(chan, NULL, 0, 1) < 1) 
 		return -1;
 
 	/* Now begin the download attempt */
-	if (adsi_begin_download(chan, scr->desc, scr->fdn, scr->sec, scr->ver)) {
+	if (adsi->begin_download(chan, scr->desc, scr->fdn, scr->sec, scr->ver)) {
 		/* User rejected us for some reason */
 		if (option_verbose > 2)
 			ast_verbose(VERBOSE_PREFIX_3 "User rejected download attempt\n");
@@ -1450,7 +1457,7 @@
 	for (x=0;x<scr->numkeys;x++) {
 		if (bytes + scr->keys[x].retstrlen > 253) {
 			/* Send what we've collected so far */
-			if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+			if (adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
 				ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
 				return -1;
 			}
@@ -1463,7 +1470,7 @@
 #endif
 	}
 	if (bytes) {
-		if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+		if (adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
 			ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
 			return -1;
 		}
@@ -1474,7 +1481,7 @@
 	for (x=0;x<scr->numdisplays;x++) {
 		if (bytes + scr->displays[x].datalen > 253) {
 			/* Send what we've collected so far */
-			if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+			if (adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
 				ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
 				return -1;
 			}
@@ -1487,7 +1494,7 @@
 #endif
 	}
 	if (bytes) {
-		if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+		if (adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
 			ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
 			return -1;
 		}
@@ -1498,7 +1505,7 @@
 	for (x=0;x<scr->numsubs;x++) {
 		if (bytes + scr->subs[x].datalen > 253) {
 			/* Send what we've collected so far */
-			if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+			if (adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
 				ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
 				return -1;
 			}
@@ -1511,7 +1518,7 @@
 #endif
 	}
 	if (bytes) {
-		if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
+		if (adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD)) {
 			ast_log(LOG_WARNING, "Unable to send chunk ending at %d\n", x);
 			return -1;
 		}
@@ -1519,11 +1526,11 @@
 
 
 	bytes = 0;
-	bytes += adsi_display(buf, ADSI_INFO_PAGE, 1, ADSI_JUST_LEFT, 0, "Download complete.", "");
-	bytes += adsi_set_line(buf, ADSI_INFO_PAGE, 1);
-	if (adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY) < 0)
+	bytes += adsi->display(buf, ADSI_INFO_PAGE, 1, ADSI_JUST_LEFT, 0, "Download complete.", "");
+	bytes += adsi->set_line(buf, ADSI_INFO_PAGE, 1);
+	if (adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY) < 0)
 		return -1;
-	if (adsi_end_download(chan)) {
+	if (adsi->end_download(chan)) {
 		/* Download failed for some reason */
 		if (option_verbose > 2)
 			ast_verbose(VERBOSE_PREFIX_3 "Download attempt failed\n");
@@ -1532,7 +1539,7 @@
 		return -1;
 	}
 	free(scr);
-	adsi_unload_session(chan);
+	adsi->unload_session(chan);
 	return 0;
 }
 
@@ -1543,7 +1550,7 @@
 	if (!data || ast_strlen_zero(data))
 		data = "asterisk.adsi";
 	LOCAL_USER_ADD(u);
-	if (!adsi_available(chan)) {
+	if (!adsi->available(chan)) {
 		if (option_verbose > 2)
 			ast_verbose(VERBOSE_PREFIX_3 "ADSI Unavailable on CPE.  Not bothering to try.\n");
 	} else {
Index: apps/app_dial.c
===================================================================
RCS file: /usr/cvsroot/asterisk/apps/app_dial.c,v
retrieving revision 1.153
diff -u -r1.153 app_dial.c
--- apps/app_dial.c	16 May 2005 00:09:09 -0000	1.153
+++ apps/app_dial.c	25 May 2005 21:09:06 -0000
@@ -38,6 +38,12 @@
 #include <sys/signal.h>
 #include <netinet/in.h>
 
+static struct ast_features *ast_features;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(ast_features),
+        { NULL, NULL }
+};
+
 static char *tdesc = "Dialing Application";
 
 static char *app = "Dial";
@@ -1320,7 +1326,7 @@
 				ast_hangup(peer);
 				return -1;
 			}
-			res = ast_bridge_call(chan,peer,&config);
+			res = ast_features->ast_bridge_call(chan,peer,&config);
 			time(&end_time);
 			snprintf(toast, sizeof(toast), "%ld", (long)(end_time - start_time));
 			pbx_builtin_setvar_helper(chan, "DIALEDTIME", toast);
Index: apps/app_getcpeid.c
===================================================================
RCS file: /usr/cvsroot/asterisk/apps/app_getcpeid.c,v
retrieving revision 1.5
diff -u -r1.5 app_getcpeid.c
--- apps/app_getcpeid.c	21 Apr 2005 06:02:43 -0000	1.5
+++ apps/app_getcpeid.c	25 May 2005 21:09:07 -0000
@@ -30,6 +30,13 @@
 
 static char *synopsis = "Get ADSI CPE ID";
 
+static struct adsi_services *adsi;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(adsi),
+        { NULL, NULL }
+};
+
+
 static char *descrip =
 "  GetCPEID: Obtains and displays ADSI CPE ID and other information in order\n"
 "to properly setup zapata.conf for on-hook operations.\n"
@@ -47,7 +54,7 @@
 	for (x=0;x<4;x++)
 		tmp[x] = stuff[x];
 	tmp[4] = NULL;
-	return adsi_print(chan, tmp, justify, voice);
+	return adsi->print(chan, tmp, justify, voice);
 }
 
 static int cpeid_exec(struct ast_channel *chan, void *idata)
@@ -70,10 +77,10 @@
 	strncpy(stuff[0], "** CPE Info **", sizeof(data[0]) - 1);
 	strncpy(stuff[1], "Identifying CPE...", sizeof(data[1]) - 1);
 	strncpy(stuff[2], "Please wait...", sizeof(data[2]) - 1);
-	res = adsi_load_session(chan, NULL, 0, 1);
+	res = adsi->load_session(chan, NULL, 0, 1);
 	if (res > 0) {
 		cpeid_setstatus(chan, stuff, 0);
-		res = adsi_get_cpeid(chan, cpeid, 0);
+		res = adsi->get_cpeid(chan, cpeid, 0);
 		if (res > 0) {
 			gotcpeid = 1;
 			if (option_verbose > 2)
@@ -83,7 +90,7 @@
 			strncpy(stuff[1], "Measuring CPE...", sizeof(data[1]) - 1);
 			strncpy(stuff[2], "Please wait...", sizeof(data[2]) - 1);
 			cpeid_setstatus(chan, stuff, 0);
-			res = adsi_get_cpeinfo(chan, &width, &height, &buttons, 0);
+			res = adsi->get_cpeinfo(chan, &width, &height, &buttons, 0);
 			if (res > -1) {
 				if (option_verbose > 2)
 					ast_verbose(VERBOSE_PREFIX_3 "CPE has %d lines, %d columns, and %d buttons on '%s'\n", height, width, buttons, chan->name);
@@ -110,7 +117,7 @@
 					break;
 				}
 			}
-			adsi_unload_session(chan);
+			adsi->unload_session(chan);
 		}
 	}
 	LOCAL_USER_REMOVE(u);
Index: apps/app_parkandannounce.c
===================================================================
RCS file: /usr/cvsroot/asterisk/apps/app_parkandannounce.c,v
retrieving revision 1.14
diff -u -r1.14 app_parkandannounce.c
--- apps/app_parkandannounce.c	21 Apr 2005 06:02:43 -0000	1.14
+++ apps/app_parkandannounce.c	25 May 2005 21:09:07 -0000
@@ -31,6 +31,12 @@
 #include <string.h>
 #include <stdlib.h>
 
+static struct ast_features *ast_features;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(ast_features),
+        { NULL, NULL }
+};
+
 static char *tdesc = "Call Parking and Announce Application";
 
 static char *app = "ParkAndAnnounce";
@@ -152,7 +158,7 @@
 	/* we are using masq_park here to protect * from touching the channel once we park it.  If the channel comes out of timeout
 	before we are done announcing and the channel is messed with, Kablooeee.  So we use Masq to prevent this.  */
 
-	ast_masq_park_call(chan, NULL, timeout, &lot);
+	ast_features->ast_masq_park_call(chan, NULL, timeout, &lot);
 
 	res=-1; 
 
Index: apps/app_queue.c
===================================================================
RCS file: /usr/cvsroot/asterisk/apps/app_queue.c,v
retrieving revision 1.137
diff -u -r1.137 app_queue.c
--- apps/app_queue.c	15 May 2005 05:42:51 -0000	1.137
+++ apps/app_queue.c	25 May 2005 21:09:10 -0000
@@ -76,6 +76,15 @@
 #define QUEUE_STRATEGY_RANDOM		4
 #define QUEUE_STRATEGY_RRMEMORY		5
 
+static struct ast_features *ast_features;
+static struct ast_monitor *ast_monitor;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(ast_monitor),
+        MOD_WANT(ast_features),
+        { NULL, NULL }
+};
+
+
 static struct strategy {
 	int strategy;
 	char *name;
@@ -1694,11 +1703,11 @@
 			else
 				which = peer;
 			if (monitorfilename)
-				ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 );
+				ast_monitor->start(which, qe->parent->monfmt, monitorfilename, 1 );
 			else
-				ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
+				ast_monitor->start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 );
 			if (qe->parent->monjoin)
-				ast_monitor_setjoinfiles(which, 1);
+				ast_monitor->setjoinfiles(which, 1);
 		}
 		/* Drop out of the queue at this point, to prepare for next caller */
 		leave_queue(qe);			
@@ -1721,7 +1730,7 @@
 		ast_copy_string(oldexten, qe->chan->exten, sizeof(oldexten));
 		time(&callstart);
 
-		bridge = ast_bridge_call(qe->chan,peer, &bridge_config);
+		bridge = ast_features->ast_bridge_call(qe->chan,peer, &bridge_config);
 
 		if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) {
 			ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context);
Index: apps/app_voicemail.c
===================================================================
RCS file: /usr/cvsroot/asterisk/apps/app_voicemail.c,v
retrieving revision 1.215
diff -u -r1.215 app_voicemail.c
--- apps/app_voicemail.c	17 May 2005 17:19:53 -0000	1.215
+++ apps/app_voicemail.c	25 May 2005 21:09:15 -0000
@@ -88,6 +88,12 @@
 
 static int load_config(void);
 
+static struct adsi_services *adsi;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(adsi),
+        { NULL, NULL }
+};
+
 /* Syntaxes supported, not really language codes.
 	en - English
 	de - German
@@ -2319,8 +2325,8 @@
 static int adsi_logo(unsigned char *buf)
 {
 	int bytes = 0;
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
 	return bytes;
 }
 
@@ -2332,26 +2338,26 @@
 	char num[5];
 
 	*useadsi = 0;
-	bytes += adsi_data_mode(buf + bytes);
- 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	bytes += adsi->data_mode(buf + bytes);
+ 	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 
 	bytes = 0;
 	bytes += adsi_logo(buf);
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
 #ifdef DISPLAY
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .", "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .", "");
 #endif
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
-	bytes += adsi_data_mode(buf + bytes);
- 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+	bytes += adsi->data_mode(buf + bytes);
+ 	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 
-	if (adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
+	if (adsi->begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
 		bytes = 0;
-		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
-		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
-		bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
-		bytes += adsi_voice_mode(buf + bytes, 0);
-		adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+		bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
+		bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
+		bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+		bytes += adsi->voice_mode(buf + bytes, 0);
+		adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 		return 0;
 	}
 
@@ -2359,106 +2365,106 @@
 	/* Add a dot */
 	bytes = 0;
 	bytes += adsi_logo(buf);
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ..", "");
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
- 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ..", "");
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+ 	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 #endif
 	bytes = 0;
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
- 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
+ 	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
 
 #ifdef DISPLAY
 	/* Add another dot */
 	bytes = 0;
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ...", "");
-	bytes += adsi_voice_mode(buf + bytes, 0);
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ...", "");
+	bytes += adsi->voice_mode(buf + bytes, 0);
 
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
- 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+ 	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 #endif
 
 	bytes = 0;
 	/* These buttons we load but don't use yet */
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
- 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
+ 	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
 
 #ifdef DISPLAY
 	/* Add another dot */
 	bytes = 0;
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ....", "");
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
- 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   ....", "");
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+ 	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 #endif
 
 	bytes = 0;
 	for (x=0;x<5;x++) {
 		snprintf(num, sizeof(num), "%d", x);
-		bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
+		bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
 	}
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
- 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
+ 	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
 
 #ifdef DISPLAY
 	/* Add another dot */
 	bytes = 0;
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .....", "");
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
- 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, "   .....", "");
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+ 	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 #endif
 
-	if (adsi_end_download(chan)) {
+	if (adsi->end_download(chan)) {
 		bytes = 0;
-		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
-		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
-		bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
-		bytes += adsi_voice_mode(buf + bytes, 0);
-		adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+		bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
+		bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
+		bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+		bytes += adsi->voice_mode(buf + bytes, 0);
+		adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 		return 0;
 	}
 	bytes = 0;
-	bytes += adsi_download_disconnect(buf + bytes);
-	bytes += adsi_voice_mode(buf + bytes, 0);
- 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
+	bytes += adsi->download_disconnect(buf + bytes);
+	bytes += adsi->voice_mode(buf + bytes, 0);
+ 	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
 
 	ast_log(LOG_DEBUG, "Done downloading scripts...\n");
 
 #ifdef DISPLAY
 	/* Add last dot */
 	bytes = 0;
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "   ......", "");
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "   ......", "");
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
 #endif
 	ast_log(LOG_DEBUG, "Restarting session...\n");
 
 	bytes = 0;
 	/* Load the session now */
-	if (adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
+	if (adsi->load_session(chan, adsifdn, adsiver, 1) == 1) {
 		*useadsi = 1;
-		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
+		bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
 	} else
-		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
+		bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
 
- 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+ 	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 	return 0;
 }
 
 static void adsi_begin(struct ast_channel *chan, int *useadsi)
 {
 	int x;
-	if (!adsi_available(chan))
+	if (!adsi->available(chan))
 		return;
-	x = adsi_load_session(chan, adsifdn, adsiver, 1);
+	x = adsi->load_session(chan, adsifdn, adsiver, 1);
 	if (x < 0)
 		return;
 	if (!x) {
@@ -2476,7 +2482,7 @@
 	int bytes=0;
 	unsigned char keys[8];
 	int x;
-	if (!adsi_available(chan))
+	if (!adsi->available(chan))
 		return;
 
 	for (x=0;x<8;x++)
@@ -2485,15 +2491,15 @@
 	keys[3] = ADSI_KEY_APPS + 3;
 
 	bytes += adsi_logo(buf + bytes);
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
-	bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
-	bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
-	bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
-	bytes += adsi_set_keys(buf + bytes, keys);
-	bytes += adsi_voice_mode(buf + bytes, 0);
- 	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+	bytes += adsi->input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
+	bytes += adsi->input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
+	bytes += adsi->load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
+	bytes += adsi->set_keys(buf + bytes, keys);
+	bytes += adsi->voice_mode(buf + bytes, 0);
+ 	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
 static void adsi_password(struct ast_channel *chan)
@@ -2502,7 +2508,7 @@
 	int bytes=0;
 	unsigned char keys[8];
 	int x;
-	if (!adsi_available(chan))
+	if (!adsi->available(chan))
 		return;
 
 	for (x=0;x<8;x++)
@@ -2510,12 +2516,12 @@
 	/* Set one key for next */
 	keys[3] = ADSI_KEY_APPS + 3;
 
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
-	bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
-	bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
-	bytes += adsi_set_keys(buf + bytes, keys);
-	bytes += adsi_voice_mode(buf + bytes, 0);
-	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+	bytes += adsi->input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
+	bytes += adsi->input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
+	bytes += adsi->set_keys(buf + bytes, keys);
+	bytes += adsi->voice_mode(buf + bytes, 0);
+	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
 static void adsi_folders(struct ast_channel *chan, int start, char *label)
@@ -2525,7 +2531,7 @@
 	unsigned char keys[8];
 	int x,y;
 
-	if (!adsi_available(chan))
+	if (!adsi->available(chan))
 		return;
 
 	for (x=0;x<5;x++) {
@@ -2538,13 +2544,13 @@
 	keys[6] = 0;
 	keys[7] = 0;
 
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
-	bytes += adsi_set_keys(buf + bytes, keys);
-	bytes += adsi_voice_mode(buf + bytes, 0);
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+	bytes += adsi->set_keys(buf + bytes, keys);
+	bytes += adsi->voice_mode(buf + bytes, 0);
 
-	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
@@ -2563,7 +2569,7 @@
 
 	int x;
 
-	if (!adsi_available(chan))
+	if (!adsi->available(chan))
 		return;
 
 	/* Retrieve important info */
@@ -2602,7 +2608,7 @@
 		if (vms->curmsg) {
 			/* but not only message, provide "Folder" instead */
 			keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
-			bytes += adsi_voice_mode(buf + bytes, 0);
+			bytes += adsi->voice_mode(buf + bytes, 0);
 
 		} else {
 			/* Otherwise if only message, leave blank */
@@ -2628,15 +2634,15 @@
 		strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
  	snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
 
- 	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
-	bytes += adsi_set_keys(buf + bytes, keys);
-	bytes += adsi_voice_mode(buf + bytes, 0);
+ 	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+	bytes += adsi->set_keys(buf + bytes, keys);
+	bytes += adsi->voice_mode(buf + bytes, 0);
 
-	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
@@ -2647,7 +2653,7 @@
 
 	int x;
 
-	if (!adsi_available(chan))
+	if (!adsi->available(chan))
 		return;
 
 	/* New meaning for keys */
@@ -2678,10 +2684,10 @@
 
 	/* Except "Exit" */
 	keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
-	bytes += adsi_set_keys(buf + bytes, keys);
-	bytes += adsi_voice_mode(buf + bytes, 0);
+	bytes += adsi->set_keys(buf + bytes, keys);
+	bytes += adsi->voice_mode(buf + bytes, 0);
 
-	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
@@ -2693,7 +2699,7 @@
 
 	char *newm = (vms->newmessages == 1) ? "message" : "messages";
 	char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
-	if (!adsi_available(chan))
+	if (!adsi->available(chan))
 		return;
 	if (vms->newmessages) {
 		snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
@@ -2711,9 +2717,9 @@
 		buf2[0] = ' ';
 		buf2[1] = '\0';
 	}
- 	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+ 	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
 
 	for (x=0;x<6;x++)
 		keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
@@ -2723,11 +2729,11 @@
 	/* Don't let them listen if there are none */
 	if (vms->lastmsg < 0)
 		keys[0] = 1;
-	bytes += adsi_set_keys(buf + bytes, keys);
+	bytes += adsi->set_keys(buf + bytes, keys);
 
-	bytes += adsi_voice_mode(buf + bytes, 0);
+	bytes += adsi->voice_mode(buf + bytes, 0);
 
-	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
@@ -2739,7 +2745,7 @@
 
 	char *mess = (vms->lastmsg == 0) ? "message" : "messages";
 
-	if (!adsi_available(chan))
+	if (!adsi->available(chan))
 		return;
 
 	/* Original command keys */
@@ -2759,15 +2765,15 @@
 		snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
 	else
 		strncpy(buf2, "no messages.", sizeof(buf2) - 1);
- 	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
-	bytes += adsi_set_keys(buf + bytes, keys);
+ 	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+	bytes += adsi->set_keys(buf + bytes, keys);
 
-	bytes += adsi_voice_mode(buf + bytes, 0);
+	bytes += adsi->voice_mode(buf + bytes, 0);
 
-	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 	
 }
 
@@ -2776,12 +2782,12 @@
 {
 	char buf[256];
 	int bytes=0;
-	if (!adsi_available(chan))
+	if (!adsi->available(chan))
 		return;
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
-	bytes += adsi_voice_mode(buf + bytes, 0);
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+	bytes += adsi->voice_mode(buf + bytes, 0);
 
-	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 */
 
@@ -2790,15 +2796,15 @@
 	char buf[256];
 	int bytes=0;
 
-	if (!adsi_available(chan))
+	if (!adsi->available(chan))
 		return;
 	bytes += adsi_logo(buf + bytes);
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
-	bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
-	bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
-	bytes += adsi_voice_mode(buf + bytes, 0);
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
+	bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
+	bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+	bytes += adsi->voice_mode(buf + bytes, 0);
 
-	adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+	adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 }
 
 /*--- get_folder: Folder menu ---*/
@@ -4140,13 +4146,13 @@
 	char buf[256];
 	int bytes=0;
 
-	if (adsi_available(chan)) {
+	if (adsi->available(chan)) {
 		bytes += adsi_logo(buf + bytes);
-		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
-		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
-		bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
-		bytes += adsi_voice_mode(buf + bytes, 0);
-		adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+		bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "New User Setup", "");
+		bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
+		bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+		bytes += adsi->voice_mode(buf + bytes, 0);
+		adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 	}
 
 	/* First, have the user change their password 
@@ -4214,14 +4220,14 @@
 	char buf[256];
 	int bytes=0;
 
-	if (adsi_available(chan))
+	if (adsi->available(chan))
 	{
 		bytes += adsi_logo(buf + bytes);
-		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
-		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
-		bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
-		bytes += adsi_voice_mode(buf + bytes, 0);
-		adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+		bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Options Menu", "");
+		bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
+		bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+		bytes += adsi->voice_mode(buf + bytes, 0);
+		adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 	}
 	while ((cmd >= 0) && (cmd != 't')) {
 		if (cmd)
@@ -4309,14 +4315,14 @@
 	char buf[256];
 	int bytes=0;
 
-	if (adsi_available(chan))
+	if (adsi->available(chan))
 	{
 		bytes += adsi_logo(buf + bytes);
-		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
-		bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
-		bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
-		bytes += adsi_voice_mode(buf + bytes, 0);
-		adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
+		bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Temp Greeting Menu", "");
+		bytes += adsi->display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Not Done", "");
+		bytes += adsi->set_line(buf + bytes, ADSI_COMM_PAGE, 1);
+		bytes += adsi->voice_mode(buf + bytes, 0);
+		adsi->transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
 	}
 	snprintf(prefile,sizeof(prefile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, vms->username);
 	while((cmd >= 0) && (cmd != 't')) {
@@ -4962,7 +4968,7 @@
 				res = 0;
 		}
 		if (useadsi)
-			adsi_unload_session(chan);
+			adsi->unload_session(chan);
 	}
 	if (vmu)
 		close_mailbox(&vms, vmu);
Index: channels/chan_agent.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_agent.c,v
retrieving revision 1.134
diff -u -r1.134 chan_agent.c
--- channels/chan_agent.c	15 May 2005 02:48:16 -0000	1.134
+++ channels/chan_agent.c	25 May 2005 21:09:18 -0000
@@ -96,6 +96,12 @@
 "Description: Will list info about all possible agents.\n"
 "Variables: NONE\n";
 
+static struct ast_monitor *ast_monitor;	/* methods */
+struct symbol_entry required_symbols[] = {
+	MOD_WANT(ast_monitor),
+	{ NULL, NULL }
+};
+
 static char moh[80] = "default";
 
 #define AST_MAX_AGENT	80		/* Agent ID or Password max length */
@@ -365,8 +371,8 @@
 		if ((pointer = strchr(filename, '.')))
 			*pointer = '-';
 		snprintf(tmp, sizeof(tmp), "%s%s",savecallsin ? savecallsin : "", filename);
-		ast_monitor_start(ast, recordformat, tmp, needlock);
-		ast_monitor_setjoinfiles(ast, 1);
+		ast_monitor->start(ast, recordformat, tmp, needlock);
+		ast_monitor->setjoinfiles(ast, 1);
 		snprintf(tmp2, sizeof(tmp2), "%s%s.%s", urlprefix ? urlprefix : "", filename, recordformatext);
 #if 0
 		ast_verbose("name is %s, link is %s\n",tmp, tmp2);
Index: channels/chan_iax2.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_iax2.c,v
retrieving revision 1.294
diff -u -r1.294 chan_iax2.c
--- channels/chan_iax2.c	19 May 2005 04:31:02 -0000	1.294
+++ channels/chan_iax2.c	25 May 2005 21:09:27 -0000
@@ -71,6 +71,14 @@
 #include "iax2-provision.h"
 #include "astconf.h"
 
+static struct ast_crypto *ast_crypto;
+static struct ast_features *ast_features;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(ast_crypto),
+        MOD_WANT(ast_features),
+        { NULL, NULL }
+};
+
 /* Define NEWJB to use the new channel independent jitterbuffer,
  * otherwise, use the old jitterbuffer */
 #define NEWJB
@@ -4926,8 +4934,8 @@
 		stringp=tmpkey;
 		keyn = strsep(&stringp, ":");
 		while(keyn) {
-			key = ast_key_get(keyn, AST_KEY_PUBLIC);
-			if (key && !ast_check_signature(key, p->challenge, rsasecret)) {
+			key = ast_crypto->ast_key_get(keyn, AST_KEY_PUBLIC);
+			if (key && !ast_crypto->ast_check_signature(key, p->challenge, rsasecret)) {
 				res = 0;
 				break;
 			} else if (!key)
@@ -5030,8 +5038,8 @@
 			stringp=tmpkeys;
 			keyn = strsep(&stringp, ":");
 			while(keyn) {
-				key = ast_key_get(keyn, AST_KEY_PUBLIC);
-				if (key && !ast_check_signature(key, iaxs[callno]->challenge, rsasecret)) {
+				key = ast_crypto->ast_key_get(keyn, AST_KEY_PUBLIC);
+				if (key && !ast_crypto->ast_check_signature(key, iaxs[callno]->challenge, rsasecret)) {
 					iaxs[callno]->state |= IAX_STATE_AUTHENTICATED;
 					break;
 				} else if (!key) 
@@ -5122,11 +5130,11 @@
 		} else {
 			char sig[256];
 			struct ast_key *key;
-			key = ast_key_get(keyn, AST_KEY_PRIVATE);
+			key = ast_crypto->ast_key_get(keyn, AST_KEY_PRIVATE);
 			if (!key) {
 				ast_log(LOG_NOTICE, "Unable to find private key '%s'\n", keyn);
 			} else {
-				if (ast_sign(key, challenge, sig)) {
+				if (ast_crypto->ast_sign(key, challenge, sig)) {
 					ast_log(LOG_NOTICE, "Unable to sign challenge withy key\n");
 					res = -1;
 				} else {
@@ -5989,7 +5997,7 @@
 	memset(&ied1, 0, sizeof(ied1));
 	mm = ast_matchmore_extension(NULL, context, callednum, 1, callerid);
 	/* Must be started */
-	if (!strcmp(callednum, ast_parking_ext()) || ast_exists_extension(NULL, context, callednum, 1, callerid)) {
+	if (!strcmp(callednum, ast_features->ast_parking_ext()) || ast_exists_extension(NULL, context, callednum, 1, callerid)) {
 		dpstatus = IAX_DPSTATUS_EXISTS;
 	} else if (ast_canmatch_extension(NULL, context, callednum, 1, callerid)) {
 		dpstatus = IAX_DPSTATUS_CANEXIST;
@@ -6061,7 +6069,7 @@
 	f = ast_read(chan1);
 	if (f)
 		ast_frfree(f);
-	res = ast_park_call(chan1, chan2, 0, &ext);
+	res = ast_features->ast_park_call(chan1, chan2, 0, &ext);
 	ast_hangup(chan2);
 	ast_log(LOG_DEBUG, "Parked on extension '%d'\n", ext);
 	return NULL;
@@ -6889,7 +6897,7 @@
 				break;
 			case IAX_COMMAND_TRANSFER:
 				if (iaxs[fr.callno]->owner && ast_bridged_channel(iaxs[fr.callno]->owner) && ies.called_number) {
-					if (!strcmp(ies.called_number, ast_parking_ext())) {
+					if (!strcmp(ies.called_number, ast_features->ast_parking_ext())) {
 						if (iax_park(ast_bridged_channel(iaxs[fr.callno]->owner), iaxs[fr.callno]->owner)) {
 							ast_log(LOG_WARNING, "Failed to park call on '%s'\n", ast_bridged_channel(iaxs[fr.callno]->owner)->name);
 						} else
Index: channels/chan_mgcp.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_mgcp.c,v
retrieving revision 1.121
diff -u -r1.121 chan_mgcp.c
--- channels/chan_mgcp.c	15 May 2005 03:21:51 -0000	1.121
+++ channels/chan_mgcp.c	25 May 2005 21:09:31 -0000
@@ -137,6 +137,12 @@
 #define MGCP_CX_MUTE		4
 #define MGCP_CX_INACTIVE	4
 
+static struct   ast_features *ast_features;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(ast_features),
+        {NULL, NULL}
+};
+
 static char *mgcp_cxmodes[] = {
 	"sendonly",
 	"recvonly",
@@ -2664,12 +2670,12 @@
 			len = 0;
 			memset(exten, 0, sizeof(exten));
 			timeout = firstdigittimeout;
-		} else if (!strcmp(exten,ast_pickup_ext())) {
+		} else if (!strcmp(exten, ast_features->ast_pickup_ext())) {
 			/* Scan all channels and see if any there
 			 * ringing channqels with that have call groups
 			 * that equal this channels pickup group  
 			 */
-			if (ast_pickup_call(chan)) {
+			if ( ast_features->ast_pickup_call(chan)) {
 				ast_log(LOG_WARNING, "No call pickup possible...\n");
 				/*res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);*/
 				transmit_notify_request(sub, "G/cg");
@@ -2740,11 +2746,11 @@
 			getforward = 0;
 			memset(exten, 0, sizeof(exten));
 			len = 0;
-		} else if (!strcmp(exten, ast_parking_ext()) && 
+		} else if (!strcmp(exten,  ast_features->ast_parking_ext()) && 
 			sub->next->owner && ast_bridged_channel(sub->next->owner)) {
 			/* This is a three way call, the main call being a real channel, 
 			   and we're parking the first call. */
-			ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
+			ast_features->ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
 			if (option_verbose > 2) {
 				ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
 			}
Index: channels/chan_modem.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_modem.c,v
retrieving revision 1.39
diff -u -r1.39 chan_modem.c
--- channels/chan_modem.c	21 Apr 2005 06:02:43 -0000	1.39
+++ channels/chan_modem.c	25 May 2005 21:09:31 -0000
@@ -173,14 +173,14 @@
 	return mc;
 }
 
-int ast_register_modem_driver(struct ast_modem_driver *mc)
+int ast_modem_register_driver(struct ast_modem_driver *mc)
 {
 	mc->next = drivers;
 	drivers = mc;
 	return 0;
 }
 
-int ast_unregister_modem_driver(struct ast_modem_driver *mc)
+int ast_modem_unregister_driver(struct ast_modem_driver *mc)
 {
 	struct ast_modem_driver *last = NULL, *cur;
 	cur = drivers;
@@ -1097,3 +1097,18 @@
 	return ASTERISK_GPL_KEY;
 }
 
+#define	METHOD(x)	METHOD_BASE(ast_modem_, x)
+static struct ast_modem ast_modem = {
+	METHOD(register_driver),
+	METHOD(unregister_driver),
+	METHOD(send),
+	METHOD(expect),
+	METHOD(read_response),
+	METHOD(new),
+	METHOD(trim),
+};
+
+struct symbol_entry exported_symbols[] = {
+	MOD_DATA(ast_modem),
+	{ NULL, NULL }
+};
Index: channels/chan_modem_aopen.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_modem_aopen.c,v
retrieving revision 1.14
diff -u -r1.14 chan_modem_aopen.c
--- channels/chan_modem_aopen.c	21 Apr 2005 06:02:43 -0000	1.14
+++ channels/chan_modem_aopen.c	25 May 2005 21:09:32 -0000
@@ -29,6 +29,13 @@
 #define VRA "40"			/* Number of 100ms of non-ring after a ring cadence after which we consider the lien to be answered */
 #define VRN "100"			/* Number of 100ms of non-ring with no cadence after which we assume an answer */
 
+static struct ast_modem *ast_modem;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(ast_modem),
+        { NULL, NULL }
+};
+
+
 static char *breakcmd = "\0x10\0x03";
 
 static char *desc = "A/Open (Rockwell Chipset) ITU-2 VoiceModem Driver";
@@ -45,17 +52,17 @@
 static int aopen_setdev(struct ast_modem_pvt *p, int dev)
 {
 	char cmd[80];
-	if (ast_modem_send(p, "AT#VLS?", 0)) {
+	if (ast_modem->send(p, "AT#VLS?", 0)) {
 		ast_log(LOG_WARNING, "Unable to select current mode %d\n", dev);
 		return -1;
 	}
-	if (ast_modem_read_response(p, 5)) {
+	if (ast_modem->read_response(p, 5)) {
 		ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
 		return -1;
 	}
-	ast_modem_trim(p->response);
+	ast_modem->trim(p->response);
 	strncpy(cmd, p->response, sizeof(cmd)-1);
-	if (ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Modem did not respond properly\n");
 		return -1;
 	}
@@ -65,15 +72,15 @@
 		return 0;
 	}
 	snprintf(cmd, sizeof(cmd), "AT#VLS=%d", dev);
-	if (ast_modem_send(p, cmd, 0))  {
+	if (ast_modem->send(p, cmd, 0))  {
 		ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
 		return -1;
 	}
-	if (ast_modem_read_response(p, 5)) {
+	if (ast_modem->read_response(p, 5)) {
 		ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
 		return -1;
 	}
-	ast_modem_trim(p->response);
+	ast_modem->trim(p->response);
 	if (strcasecmp(p->response, "VCON") && strcasecmp(p->response, "OK")) {
 		ast_log(LOG_WARNING, "Unexpected reply: %s\n", p->response);
 		return -1;
@@ -83,8 +90,8 @@
 
 static int aopen_startrec(struct ast_modem_pvt *p)
 {
-	if (ast_modem_send(p, "AT#VRX", 0) ||
-	     ast_modem_expect(p, "CONNECT", 5)) {
+	if (ast_modem->send(p, "AT#VRX", 0) ||
+	     ast_modem->expect(p, "CONNECT", 5)) {
 		ast_log(LOG_WARNING, "Unable to start recording\n");
 		return -1;
 	}
@@ -94,33 +101,33 @@
 
 static int aopen_break(struct ast_modem_pvt *p)
 {
-	if (ast_modem_send(p, "\r\n", 2)) {
+	if (ast_modem->send(p, "\r\n", 2)) {
 		ast_log(LOG_WARNING, "Failed to send enter?\n");
 		return -1;
 	}
-	if (ast_modem_send(p, breakcmd, 2)) {
+	if (ast_modem->send(p, breakcmd, 2)) {
 		ast_log(LOG_WARNING, "Failed to break\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "\r\n", 2)) {
+	if (ast_modem->send(p, "\r\n", 2)) {
 		ast_log(LOG_WARNING, "Failed to send enter?\n");
 		return -1;
 	}
 	/* Read any outstanding junk */
-	while(!ast_modem_read_response(p, 1));
-	if (ast_modem_send(p, "AT", 0)) {
+	while(!ast_modem->read_response(p, 1));
+	if (ast_modem->send(p, "AT", 0)) {
 		/* Modem might be stuck in some weird mode, try to get it out */
-		ast_modem_send(p, "+++", 3);
-		if (ast_modem_expect(p, "OK", 10)) {
+		ast_modem->send(p, "+++", 3);
+		if (ast_modem->expect(p, "OK", 10)) {
 			ast_log(LOG_WARNING, "Modem is not responding\n");
 			return -1;
 		}
-		if (ast_modem_send(p, "AT", 0)) {
+		if (ast_modem->send(p, "AT", 0)) {
 			ast_log(LOG_WARNING, "Modem is not responding\n");
 			return -1;
 		}
 	}
-	if (ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Modem did not respond properly\n");
 		return -1;
 	}
@@ -135,43 +142,43 @@
 		return -1;
 	/* Force into command mode */
 	p->ministate = STATE_COMMAND;
-	if (ast_modem_send(p, "AT#BDR=0", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT#BDR=0", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to auto-baud\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT#CLS=8", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT#CLS=8", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to voice mode\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT#VBS=8", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT#VBS=8", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to 8-bit mode\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT#VSR=8000", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT#VSR=8000", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to 8000 Hz sampling\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT#VLS=0", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT#VLS=0", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to telco interface\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT#VRA=" VRA, 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT#VRA=" VRA, 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to 'ringback goes away' timer\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT#VRN=" VRN, 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT#VRN=" VRN, 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to 'ringback never came timer'\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT#VTD=3F,3F,3F", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT#VTD=3F,3F,3F", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to tone detection\n");
 		return -1;
 	}
@@ -214,7 +221,7 @@
 		return &p->fr;
 	case 'o': /* Overrun */
 		ast_log(LOG_WARNING, "Overflow on modem, flushing buffers\n");
-		if (ast_modem_send(p, "\0x10E", 2)) 
+		if (ast_modem->send(p, "\0x10E", 2)) 
 			ast_log(LOG_WARNING, "Unable to flush buffers\n");
 		return &p->fr;	
 	case 'u': /* Underrun */
@@ -256,7 +263,7 @@
 				return aopen_handle_escape(p, 0);
 			/* Read the rest of the line */
 			fgets(result + 2, sizeof(result) - 2, p->f);
-			ast_modem_trim(result);
+			ast_modem->trim(result);
 			if (!strcasecmp(result, "VCON")) {
 				/* If we're in immediate mode, reply now */
 				if (p->mode == MODEM_MODE_IMMEDIATE)
@@ -346,21 +353,21 @@
 	char mfr[80];
 	char mdl[80];
 	char rev[80];
-	ast_modem_send(p, "AT#MDL?", 0);
-	ast_modem_read_response(p, 5);
+	ast_modem->send(p, "AT#MDL?", 0);
+	ast_modem->read_response(p, 5);
 	strncpy(mdl, p->response, sizeof(mdl)-1);
-	ast_modem_trim(mdl);
-	ast_modem_expect(p, "OK", 5);
-	ast_modem_send(p, "AT#MFR?", 0);
-	ast_modem_read_response(p, 5);
+	ast_modem->trim(mdl);
+	ast_modem->expect(p, "OK", 5);
+	ast_modem->send(p, "AT#MFR?", 0);
+	ast_modem->read_response(p, 5);
 	strncpy(mfr, p->response, sizeof(mfr)-1);
-	ast_modem_trim(mfr);
-	ast_modem_expect(p, "OK", 5);
-	ast_modem_send(p, "AT#REV?", 0);
-	ast_modem_read_response(p, 5);
+	ast_modem->trim(mfr);
+	ast_modem->expect(p, "OK", 5);
+	ast_modem->send(p, "AT#REV?", 0);
+	ast_modem->read_response(p, 5);
 	strncpy(rev, p->response, sizeof(rev)-1);
-	ast_modem_trim(rev);
-	ast_modem_expect(p, "OK", 5);
+	ast_modem->trim(rev);
+	ast_modem->expect(p, "OK", 5);
 	snprintf(identity, sizeof(identity), "%s Model %s Revision %s", mfr, mdl, rev);
 	return strdup(identity);
 }
@@ -383,8 +390,8 @@
 
 static int aopen_answer(struct ast_modem_pvt *p)
 {
-	if (ast_modem_send(p, "ATA", 0) ||
-	     ast_modem_expect(p, "VCON", 10)) {
+	if (ast_modem->send(p, "ATA", 0) ||
+	     ast_modem->expect(p, "VCON", 10)) {
 		ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
 		return -1;
 	}
@@ -395,8 +402,8 @@
 {
 	char cmd[80];
 	snprintf(cmd, sizeof(cmd), "AT#VTS=%c", digit);
-	if (ast_modem_send(p, cmd, 0) ||
-	     ast_modem_expect(p, "VCON", 10)) {
+	if (ast_modem->send(p, cmd, 0) ||
+	     ast_modem->expect(p, "VCON", 10)) {
 		ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
 		return -1;
 	}
@@ -407,7 +414,7 @@
 {
 	char cmd[80];
 	snprintf(cmd, sizeof(cmd), "ATD%c %s", p->dialtype,stuff);
-	if (ast_modem_send(p, cmd, 0)) {
+	if (ast_modem->send(p, cmd, 0)) {
 		ast_log(LOG_WARNING, "Unable to dial\n");
 		return -1;
 	}
@@ -419,13 +426,13 @@
 	if (aopen_break(p))
 		return -1;
 	/* Hangup by switching to data, then back to voice */
-	if (ast_modem_send(p, "ATH", 0) ||
-	     ast_modem_expect(p, "OK", 8)) {
+	if (ast_modem->send(p, "ATH", 0) ||
+	     ast_modem->expect(p, "OK", 8)) {
 		ast_log(LOG_WARNING, "Unable to set to data mode\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT#CLS=8", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT#CLS=8", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to voice mode\n");
 		return -1;
 	}
@@ -467,14 +474,15 @@
 	return res;
 }
 
+
 int load_module(void)
 {
-	return ast_register_modem_driver(&aopen_driver);
+	return ast_modem->register_driver(&aopen_driver);
 }
 
 int unload_module(void)
 {
-	return ast_unregister_modem_driver(&aopen_driver);
+	return ast_modem->unregister_driver(&aopen_driver);
 }
 
 char *description()
Index: channels/chan_modem_bestdata.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_modem_bestdata.c,v
retrieving revision 1.15
diff -u -r1.15 chan_modem_bestdata.c
--- channels/chan_modem_bestdata.c	21 Apr 2005 06:02:43 -0000	1.15
+++ channels/chan_modem_bestdata.c	25 May 2005 21:09:32 -0000
@@ -47,13 +47,19 @@
 	NULL
 };
 
+static struct ast_modem *ast_modem;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(ast_modem),
+        { NULL, NULL }
+};
+
 static int bestdata_break(struct ast_modem_pvt *p);
 
 static int bestdata_startrec(struct ast_modem_pvt *p)
 {
 	if (p->ministate != STATE_COMMAND) bestdata_break(p);
-	if (ast_modem_send(p, "AT+VRX", 0) ||
-	     ast_modem_expect(p, "CONNECT", 5)) {
+	if (ast_modem->send(p, "AT+VRX", 0) ||
+	     ast_modem->expect(p, "CONNECT", 5)) {
 		ast_log(LOG_WARNING, "Unable to start recording\n");
 		return -1;
 	}
@@ -64,8 +70,8 @@
 static int bestdata_startplay(struct ast_modem_pvt *p)
 {
 	if (p->ministate != STATE_COMMAND) bestdata_break(p);
-	if (ast_modem_send(p, "AT+VTX", 0) ||
-	     ast_modem_expect(p, "CONNECT", 5)) {
+	if (ast_modem->send(p, "AT+VTX", 0) ||
+	     ast_modem->expect(p, "CONNECT", 5)) {
 		ast_log(LOG_WARNING, "Unable to start recording\n");
 		return -1;
 	}
@@ -75,27 +81,27 @@
 
 static int bestdata_break(struct ast_modem_pvt *p)
 {
-	if (ast_modem_send(p, breakcmd, 2)) {
+	if (ast_modem->send(p, breakcmd, 2)) {
 		ast_log(LOG_WARNING, "Failed to break\n");
 		return -1;
 	}
 	p->ministate = STATE_COMMAND;
 	usleep(10000);
 	/* Read any outstanding junk */
-	while(!ast_modem_read_response(p, 1));
-	if (ast_modem_send(p, "AT", 0)) {
+	while(!ast_modem->read_response(p, 1));
+	if (ast_modem->send(p, "AT", 0)) {
 		/* Modem might be stuck in some weird mode, try to get it out */
-		ast_modem_send(p, "+++", 3);
-		if (ast_modem_expect(p, "OK", 10)) {
+		ast_modem->send(p, "+++", 3);
+		if (ast_modem->expect(p, "OK", 10)) {
 			ast_log(LOG_WARNING, "Modem is not responding\n");
 			return -1;
 		}
-		if (ast_modem_send(p, "AT", 0)) {
+		if (ast_modem->send(p, "AT", 0)) {
 			ast_log(LOG_WARNING, "Modem is not responding\n");
 			return -1;
 		}
 	}
-	if (ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Modem did not respond properly\n");
 		return -1;
 	}
@@ -110,38 +116,38 @@
 		return -1;
 	/* Force into command mode */
 	p->ministate = STATE_COMMAND;
-	if (ast_modem_send(p, "AT+FCLASS=8", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT+FCLASS=8", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to voice mode\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT+VSM=1,8000,0,0", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT+VSM=1,8000,0,0", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to 8000 Hz sampling\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT+VLS=0", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT+VLS=0", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to telco interface\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT+VRA=" VRA, 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT+VRA=" VRA, 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to 'ringback goes away' timer\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT+VRN=" VRN, 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT+VRN=" VRN, 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to 'ringback never came timer'\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT+VTD=63", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT+VTD=63", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to tone detection\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT+VCID=1", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT+VCID=1", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to enable Caller*ID\n");
 		return -1;
 	}
@@ -189,9 +195,9 @@
 		   {
 			char res[1000]="";
 
-			if (ast_modem_read_response(p, 5)) break;
+			if (ast_modem->read_response(p, 5)) break;
 			strncpy(res, p->response, sizeof(res)-1);
-			ast_modem_trim(res);
+			ast_modem->trim(res);
 			if (!strncmp(res,"\020.",2)) break;
 			if (!strncmp(res,"NAME",4)) strncpy(name,res + 7, sizeof(name) - 1);
 			if (!strncmp(res,"NMBR",4)) strncpy(nmbr,res + 7, sizeof(nmbr) - 1);
@@ -221,7 +227,7 @@
 		return &p->fr;
 	case 'o': /* Overrun */
 		ast_log(LOG_WARNING, "Overflow on modem, flushing buffers\n");
-		if (ast_modem_send(p, "\0x10E", 2)) 
+		if (ast_modem->send(p, "\0x10E", 2)) 
 			ast_log(LOG_WARNING, "Unable to flush buffers\n");
 		return &p->fr;	
 	case '0':  /* All the DTMF characters */
@@ -300,7 +306,7 @@
 				return bestdata_handle_escape(p, 0);
 			/* Read the rest of the line */
 			fgets(result + 2, sizeof(result) - 2, p->f);
-			ast_modem_trim(result);
+			ast_modem->trim(result);
 			if (!strcasecmp(result, "OK")) {
 				/* If we're in immediate mode, reply now */
 				if (p->mode == MODEM_MODE_IMMEDIATE)
@@ -421,21 +427,21 @@
 	char mfr[80];
 	char mdl[80];
 	char rev[80];
-	ast_modem_send(p, "AT+FMM", 0);
-	ast_modem_read_response(p, 5);
+	ast_modem->send(p, "AT+FMM", 0);
+	ast_modem->read_response(p, 5);
 	strncpy(mdl, p->response, sizeof(mdl)-1);
-	ast_modem_trim(mdl);
-	ast_modem_expect(p, "OK", 5);
-	ast_modem_send(p, "AT+FMI", 0);
-	ast_modem_read_response(p, 5);
+	ast_modem->trim(mdl);
+	ast_modem->expect(p, "OK", 5);
+	ast_modem->send(p, "AT+FMI", 0);
+	ast_modem->read_response(p, 5);
 	strncpy(mfr, p->response, sizeof(mfr)-1);
-	ast_modem_trim(mfr);
-	ast_modem_expect(p, "OK", 5);
-	ast_modem_send(p, "AT+FMR", 0);
-	ast_modem_read_response(p, 5);
+	ast_modem->trim(mfr);
+	ast_modem->expect(p, "OK", 5);
+	ast_modem->send(p, "AT+FMR", 0);
+	ast_modem->read_response(p, 5);
 	strncpy(rev, p->response, sizeof(rev)-1);
-	ast_modem_trim(rev);
-	ast_modem_expect(p, "OK", 5);
+	ast_modem->trim(rev);
+	ast_modem->expect(p, "OK", 5);
 	snprintf(identity, sizeof(identity), "%s Model %s Revision %s", mfr, mdl, rev);
 	return strdup(identity);
 }
@@ -460,8 +466,8 @@
 {
 	p->ringt = 0;
 	p->lastring = 0;
-	if (ast_modem_send(p, "AT+VLS=1", 0) ||
-	     ast_modem_expect(p, "OK", 10)) {
+	if (ast_modem->send(p, "AT+VLS=1", 0) ||
+	     ast_modem->expect(p, "OK", 10)) {
 		ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
 		return -1;
 	}
@@ -474,8 +480,8 @@
 
 	if (p->ministate != STATE_COMMAND) bestdata_break(p);
 	snprintf(cmd, sizeof(cmd), "AT+VTS=%c", digit);
-	if (ast_modem_send(p, cmd, 0) ||
-	     ast_modem_expect(p, "OK", 10)) {
+	if (ast_modem->send(p, cmd, 0) ||
+	     ast_modem->expect(p, "OK", 10)) {
 		ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
 		return -1;
 	}
@@ -515,7 +521,7 @@
 	   {
 		snprintf(cmd, sizeof(cmd), "ATD%c %s", p->dialtype,stuff);
 	   }
-	if (ast_modem_send(p, cmd, 0)) {
+	if (ast_modem->send(p, cmd, 0)) {
 		ast_log(LOG_WARNING, "Unable to dial\n");
 		return -1;
 	}
@@ -527,13 +533,13 @@
 	if (bestdata_break(p))
 		return -1;
 	/* Hangup by switching to data, then back to voice */
-	if (ast_modem_send(p, "ATH", 0) ||
-	     ast_modem_expect(p, "OK", 8)) {
+	if (ast_modem->send(p, "ATH", 0) ||
+	     ast_modem->expect(p, "OK", 8)) {
 		ast_log(LOG_WARNING, "Unable to set to data mode\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT+FCLASS=8", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT+FCLASS=8", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to voice mode\n");
 		return -1;
 	}
@@ -581,12 +587,12 @@
 
 int load_module(void)
 {
-	return ast_register_modem_driver(&bestdata_driver);
+	return ast_modem->register_driver(&bestdata_driver);
 }
 
 int unload_module(void)
 {
-	return ast_unregister_modem_driver(&bestdata_driver);
+	return ast_modem->unregister_driver(&bestdata_driver);
 }
 
 char *description()
Index: channels/chan_modem_i4l.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_modem_i4l.c,v
retrieving revision 1.25
diff -u -r1.25 chan_modem_i4l.c
--- channels/chan_modem_i4l.c	21 Apr 2005 06:02:43 -0000	1.25
+++ channels/chan_modem_i4l.c	25 May 2005 21:09:33 -0000
@@ -36,6 +36,13 @@
 
 static char *desc = "ISDN4Linux Emulated Modem Driver";
 
+struct ast_modem *ast_modem;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(ast_modem),
+        { NULL, NULL }
+};
+
+
 static int usecnt;
 AST_MUTEX_DEFINE_STATIC(usecnt_lock);
 
@@ -53,17 +60,17 @@
 		return -1;
 	} else	/* Convert DEV to our understanding of it */
 		dev = 2;
-	if (ast_modem_send(p, "AT+VLS?", 0)) {
+	if (ast_modem->send(p, "AT+VLS?", 0)) {
 		ast_log(LOG_WARNING, "Unable to select current mode %d\n", dev);
 		return -1;
 	}
-	if (ast_modem_read_response(p, 5)) {
+	if (ast_modem->read_response(p, 5)) {
 		ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
 		return -1;
 	}
-	ast_modem_trim(p->response);
+	ast_modem->trim(p->response);
 	strncpy(cmd, p->response, sizeof(cmd)-1);
-	if (ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Modem did not respond properly\n");
 		return -1;
 	}
@@ -73,15 +80,15 @@
 		return 0;
 	}
 	snprintf(cmd, sizeof(cmd), "AT+VLS=%d", dev);
-	if (ast_modem_send(p, cmd, 0))  {
+	if (ast_modem->send(p, cmd, 0))  {
 		ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
 		return -1;
 	}
-	if (ast_modem_read_response(p, 5)) {
+	if (ast_modem->read_response(p, 5)) {
 		ast_log(LOG_WARNING, "Unable to select device %d\n", dev);
 		return -1;
 	}
-	ast_modem_trim(p->response);
+	ast_modem->trim(p->response);
 	if (strcasecmp(p->response, "VCON") && strcasecmp(p->response, "OK")) {
 		ast_log(LOG_WARNING, "Unexpected reply: %s\n", p->response);
 		return -1;
@@ -91,8 +98,8 @@
 
 static int i4l_startrec(struct ast_modem_pvt *p)
 {
-	if (ast_modem_send(p, "AT+VRX+VTX", 0) ||
-	     ast_modem_expect(p, "CONNECT", 5)) {
+	if (ast_modem->send(p, "AT+VRX+VTX", 0) ||
+	     ast_modem->expect(p, "CONNECT", 5)) {
 		ast_log(LOG_WARNING, "Unable to start recording\n");
 		return -1;
 	}
@@ -117,31 +124,31 @@
 
 static int i4l_break(struct ast_modem_pvt *p)
 {
-	if (ast_modem_send(p, breakcmd, 2)) {
+	if (ast_modem->send(p, breakcmd, 2)) {
 		ast_log(LOG_WARNING, "Failed to break\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "\r\n", 2)) {
+	if (ast_modem->send(p, "\r\n", 2)) {
 		ast_log(LOG_WARNING, "Failed to send enter?\n");
 		return -1;
 	}
 #if 0
 	/* Read any outstanding junk */
-	while(!ast_modem_read_response(p, 1));
+	while(!ast_modem->read_response(p, 1));
 #endif
-	if (ast_modem_send(p, "AT", 0)) {
+	if (ast_modem->send(p, "AT", 0)) {
 		/* Modem might be stuck in some weird mode, try to get it out */
-		ast_modem_send(p, "+++", 3);
-		if (ast_modem_expect(p, "OK", 10)) {
+		ast_modem->send(p, "+++", 3);
+		if (ast_modem->expect(p, "OK", 10)) {
 			ast_log(LOG_WARNING, "Modem is not responding\n");
 			return -1;
 		}
-		if (ast_modem_send(p, "AT", 0)) {
+		if (ast_modem->send(p, "AT", 0)) {
 			ast_log(LOG_WARNING, "Modem is not responding\n");
 			return -1;
 		}
 	}
-	if (ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Modem did not respond properly\n");
 		return -1;
 	}
@@ -157,15 +164,15 @@
 		return -1;
 	/* Force into command mode */
 	p->ministate = STATE_COMMAND;
-	if (ast_modem_send(p, "AT+FCLASS=8", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT+FCLASS=8", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to voice mode\n");
 		return -1;
 	}
 	if (strlen(p->msn)) {
 		snprintf(cmd, sizeof(cmd), "AT&E%s", p->msn);
-		if (ast_modem_send(p, cmd, 0) ||
-		    ast_modem_expect(p, "OK", 5)) {
+		if (ast_modem->send(p, cmd, 0) ||
+		    ast_modem->expect(p, "OK", 5)) {
 			ast_log(LOG_WARNING, "Unable to set MSN to %s\n", p->msn);
 			return -1;
 		}
@@ -180,45 +187,45 @@
 			if (*q == ',') *q = ';';
 			++q;
 		}
-		if (ast_modem_send(p, cmd, 0) ||
-		    ast_modem_expect(p, "OK", 5)) {
+		if (ast_modem->send(p, cmd, 0) ||
+		    ast_modem->expect(p, "OK", 5)) {
 			ast_log(LOG_WARNING, "Unable to set Listen to %s\n", p->msn);
 			return -1;
 		}
 	}
-	if (ast_modem_send(p, "AT&D2", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT&D2", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to DTR disconnect mode\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "ATS18=1", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "ATS18=1", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to audio only mode\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "ATS13.6=1", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "ATS13.6=1", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to RUNG indication\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "ATS14=4", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "ATS14=4", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to transparent mode\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "ATS23=9", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "ATS23=9", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to transparent/ringing mode\n");
 		return -1;
 	}
 
-	if (ast_modem_send(p, "AT+VSM=6", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT+VSM=6", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to muLAW mode\n");
 		return -1;
 	}
-	if (ast_modem_send(p, "AT+VLS=2", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT+VLS=2", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to phone line interface\n");
 		return -1;
 	}
@@ -265,7 +272,7 @@
 		return &p->fr;
 	case 'o': /* Overrun */
 		ast_log(LOG_WARNING, "Overflow on modem, flushing buffers\n");
-		if (ast_modem_send(p, "\0x10E", 2)) 
+		if (ast_modem->send(p, "\0x10E", 2)) 
 			ast_log(LOG_WARNING, "Unable to flush buffers\n");
 		return &p->fr;	
 	case CHAR_ETX: /* End Transmission */
@@ -335,7 +342,7 @@
 				return i4l_handle_escape(p, 0);
 			/* Read the rest of the line */
 			fgets(result + 2, sizeof(result) - 2, p->f);
-			ast_modem_trim(result);
+			ast_modem->trim(result);
 			if (!strcasecmp(result, "VCON")) {
 				/* If we're in immediate mode, reply now */
 /*				if (p->mode == MODEM_MODE_IMMEDIATE) */
@@ -550,20 +557,20 @@
 
 static int i4l_answer(struct ast_modem_pvt *p)
 {
-	if (ast_modem_send(p, "ATA\r", 4) ||
-	     ast_modem_expect(p, "VCON", 10)) {
+	if (ast_modem->send(p, "ATA\r", 4) ||
+	     ast_modem->expect(p, "VCON", 10)) {
 		ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
 		return -1;
 	}
 #if 1
-	if (ast_modem_send(p, "AT+VDD=0,8", 0) ||
-	     ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->send(p, "AT+VDD=0,8", 0) ||
+	     ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Unable to set to phone line interface\n");
 		return -1;
 	}
 #endif
-	if (ast_modem_send(p, "AT+VTX+VRX", 0) ||
-	     ast_modem_expect(p, "CONNECT", 10)) {
+	if (ast_modem->send(p, "AT+VTX+VRX", 0) ||
+	     ast_modem->expect(p, "CONNECT", 10)) {
 		ast_log(LOG_WARNING, "Unable to answer: %s", p->response);
 		return -1;
 	}
@@ -617,7 +624,7 @@
 	    if(strlen(p->outgoingmsn) && strstr(p->outgoingmsn,tmpmsn) != NULL) {
 	      /* Tell ISDN4Linux to use this as A number */
 	      snprintf(cmd, sizeof(cmd), "AT&E%s\n", c->cid.cid_num);
-	      if (ast_modem_send(p, cmd, strlen(cmd))) {
+	      if (ast_modem->send(p, cmd, strlen(cmd))) {
 		ast_log(LOG_WARNING, "Unable to set A number to %s\n", c->cid.cid_num);
 	      }
 
@@ -627,7 +634,7 @@
 	}
 
 	snprintf(cmd, sizeof(cmd), "ATD%c %s\n", p->dialtype,stuff);
-	if (ast_modem_send(p, cmd, strlen(cmd))) {
+	if (ast_modem->send(p, cmd, strlen(cmd))) {
 		ast_log(LOG_WARNING, "Unable to dial\n");
 		return -1;
 	}
@@ -659,11 +666,11 @@
 	/* basically we're done, just to be sure */
 	write(p->fd, "\n\n", 2);
 	read(p->fd, dummy, sizeof(dummy));
-	if (ast_modem_send(p, "ATH", 0)) {
+	if (ast_modem->send(p, "ATH", 0)) {
 		ast_log(LOG_WARNING, "Unable to hang up\n");
 		return -1;
 	}
-	if (ast_modem_expect(p, "OK", 5)) {
+	if (ast_modem->expect(p, "OK", 5)) {
 		ast_log(LOG_WARNING, "Final 'OK' not received\n");
 		return -1;
 	}
@@ -708,12 +715,12 @@
 
 int load_module(void)
 {
-	return ast_register_modem_driver(&i4l_driver);
+	return ast_modem->register_driver(&i4l_driver);
 }
 
 int unload_module(void)
 {
-	return ast_unregister_modem_driver(&i4l_driver);
+	return ast_modem->unregister_driver(&i4l_driver);
 }
 
 char *description()
Index: channels/chan_sip.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_sip.c,v
retrieving revision 1.739
diff -u -r1.739 chan_sip.c
--- channels/chan_sip.c	20 May 2005 03:14:41 -0000	1.739
+++ channels/chan_sip.c	25 May 2005 21:09:45 -0000
@@ -110,6 +110,12 @@
 #define DEBUG_READ	0			/* Recieved data	*/
 #define DEBUG_SEND	1			/* Transmit data	*/
 
+static struct	ast_features *ast_features;
+struct symbol_entry required_symbols[] = {
+	MOD_WANT(ast_features),
+	{NULL, NULL}
+};
+
 static const char desc[] = "Session Initiation Protocol (SIP)";
 static const char channeltype[] = "SIP";
 static const char config[] = "sip.conf";
@@ -5617,14 +5623,14 @@
 	if (sip_debug_test_pvt(p))
 		ast_verbose("Looking for %s in %s\n", c, p->context);
 	if (ast_exists_extension(NULL, p->context, c, 1, fr) ||
-		!strcmp(c, ast_pickup_ext())) {
+		!strcmp(c, ast_features->ast_pickup_ext())) {
 		if (!oreq)
 			ast_copy_string(p->exten, c, sizeof(p->exten));
 		return 0;
 	}
 
 	if (ast_canmatch_extension(NULL, p->context, c, 1, fr) ||
-	    !strncmp(c, ast_pickup_ext(),strlen(c))) {
+	    !strncmp(c, ast_features->ast_pickup_ext(),strlen(c))) {
 		return 1;
 	}
 	
@@ -5797,7 +5803,7 @@
 	    		  INVITE with a replaces header -anthm XXX */
 			/* The only way to find out is to use the dialplan - oej */
 		}
-	} else if (ast_exists_extension(NULL, sip_pvt->context, refer_to, 1, NULL) || !strcmp(refer_to, ast_parking_ext())) {
+	} else if (ast_exists_extension(NULL, sip_pvt->context, refer_to, 1, NULL) || !strcmp(refer_to, ast_features->ast_parking_ext())) {
 		/* This is an unsupervised transfer (blind transfer) */
 		
 		ast_log(LOG_DEBUG,"Unsupervised transfer to (Refer-To): %s\n", refer_to);
@@ -8471,7 +8477,7 @@
 	ast_mutex_lock(&chan1->lock);
 	ast_do_masquerade(chan1);
 	ast_mutex_unlock(&chan1->lock);
-	res = ast_park_call(chan1, chan2, 0, &ext);
+	res = ast_features->ast_park_call(chan1, chan2, 0, &ext);
 	/* Then hangup */
 	ast_hangup(chan2);
 	ast_log(LOG_DEBUG, "Parked on extension '%d'\n", ext);
@@ -8780,7 +8786,7 @@
 		case AST_STATE_DOWN:
 			transmit_response(p, "100 Trying", req);
 			ast_setstate(c, AST_STATE_RING);
-			if (strcmp(p->exten, ast_pickup_ext())) {
+			if (strcmp(p->exten, ast_features->ast_pickup_ext())) {
 				if (ast_pbx_start(c)) {
 					ast_log(LOG_WARNING, "Failed to start PBX :(\n");
 					/* Unlock locks so ast_hangup can do its magic */
@@ -8796,7 +8802,7 @@
 				}
 			} else {
 				ast_mutex_unlock(&c->lock);
-				if (ast_pickup_call(c)) {
+				if (ast_features->ast_pickup_call(c)) {
 					ast_log(LOG_NOTICE, "Nothing to pick up\n");
 					if (ignore)
 						transmit_response(p, "503 Unavailable", req);
@@ -8886,7 +8892,7 @@
 					if (transfer_to) {
 						ast_log(LOG_DEBUG, "Got SIP blind transfer, applying to '%s'\n", transfer_to->name);
 						ast_moh_stop(transfer_to);
-						if (!strcmp(p->refer_to, ast_parking_ext())) {
+						if (!strcmp(p->refer_to, ast_features->ast_parking_ext())) {
 							/* Must release c's lock now, because it will not longer
 							    be accessible after the transfer! */
 							*nounlock = 1;
Index: channels/chan_skinny.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_skinny.c,v
retrieving revision 1.73
diff -u -r1.73 chan_skinny.c
--- channels/chan_skinny.c	15 May 2005 03:21:51 -0000	1.73
+++ channels/chan_skinny.c	25 May 2005 21:09:48 -0000
@@ -52,6 +52,12 @@
 #include "asterisk/dsp.h"
 #include <ctype.h>
 
+static struct ast_features *ast_features;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(ast_features),
+        { NULL, NULL }
+};
+
 /************************************************************************************/
 /*                         Skinny/Asterisk Protocol Settings                        */
 /************************************************************************************/
@@ -1515,12 +1521,12 @@
             memset(exten, 0, sizeof(exten));
             timeout = firstdigittimeout;
                 
-        } else if (!strcmp(exten,ast_pickup_ext())) {
+        } else if (!strcmp(exten,ast_features->ast_pickup_ext())) {
             /* Scan all channels and see if any there
              * ringing channqels with that have call groups
              * that equal this channels pickup group  
              */
-            if (ast_pickup_call(chan)) {
+            if (ast_features->ast_pickup_call(chan)) {
                 ast_log(LOG_WARNING, "No call pickup possible...\n");
 				transmit_tone(s, SKINNY_REORDER);
             }
@@ -1588,12 +1594,12 @@
             getforward = 0;
             memset(exten, 0, sizeof(exten));
             len = 0;
-        } else if (!strcmp(exten, ast_parking_ext()) && 
+        } else if (!strcmp(exten, ast_features->ast_parking_ext()) && 
                     sub->next->owner &&
                     ast_bridged_channel(sub->next->owner)) {
             /* This is a three way call, the main call being a real channel, 
                 and we're parking the first call. */
-            ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
+            ast_features->ast_masq_park_call(ast_bridged_channel(sub->next->owner), chan, 0, NULL);
             if (option_verbose > 2) {
                 ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
             }
Index: channels/chan_zap.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_zap.c,v
retrieving revision 1.448
diff -u -r1.448 chan_zap.c
--- channels/chan_zap.c	20 May 2005 19:09:21 -0000	1.448
+++ channels/chan_zap.c	25 May 2005 21:10:05 -0000
@@ -121,6 +121,12 @@
 #endif
 ;
 
+static struct ast_features *ast_features;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(ast_features),
+        { NULL, NULL }
+};
+
 static const char type[] = "Zap";
 static const char config[] = "zapata.conf";
 
@@ -267,6 +273,8 @@
 #ifdef PRI_GETSET_TIMERS
 static int pritimers[PRI_MAX_TIMERS];
 #endif
+static int pridebugfd = -1;
+static char pridebugfilename[1024]="";
 #endif
 
 /* Wait up to 16 seconds for first digit (FXO logic) */
@@ -288,8 +296,6 @@
 static int ifcount = 0;
 
 AST_MUTEX_DEFINE_STATIC(pridebugfdlock);
-static int pridebugfd = -1;
-static char pridebugfilename[1024]="";
 
 /* Whether we answer on a Polarity Switch event */
 static int answeronpolarityswitch = 0;
@@ -5195,7 +5201,7 @@
 				tone_zone_play_tone(p->subs[index].zfd, -1);
 			else
 				tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_DIALTONE);
-			if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num) && strcmp(exten, ast_parking_ext())) {
+			if (ast_exists_extension(chan, chan->context, exten, 1, p->cid_num) && strcmp(exten, ast_features->ast_parking_ext())) {
 				if (!res || !ast_matchmore_extension(chan, chan->context, exten, 1, p->cid_num)) {
 					if (getforward) {
 						/* Record this as the forwarding extension */
@@ -5260,7 +5266,7 @@
 				memset(exten, 0, sizeof(exten));
 				timeout = firstdigittimeout;
 					
-			} else if (!strcmp(exten,ast_pickup_ext())) {
+			} else if (!strcmp(exten,ast_features->ast_pickup_ext())) {
 				/* Scan all channels and see if any there
 				 * ringing channqels with that have call groups
 				 * that equal this channels pickup group  
@@ -5275,7 +5281,7 @@
 						unalloc_sub(p, SUB_THREEWAY);
 					}
 					zt_enable_ec(p);
-					if (ast_pickup_call(chan)) {
+					if (ast_features->ast_pickup_call(chan)) {
 						ast_log(LOG_DEBUG, "No call pickup possible...\n");
 						res = tone_zone_play_tone(p->subs[index].zfd, ZT_TONE_CONGESTION);
 						zt_wait_event(p->subs[index].zfd);
@@ -5354,12 +5360,12 @@
 				getforward = 0;
 				memset(exten, 0, sizeof(exten));
 				len = 0;
-			} else if ((p->transfer || p->canpark) && !strcmp(exten, ast_parking_ext()) && 
+			} else if ((p->transfer || p->canpark) && !strcmp(exten, ast_features->ast_parking_ext()) && 
 						p->subs[SUB_THREEWAY].owner &&
 						ast_bridged_channel(p->subs[SUB_THREEWAY].owner)) {
 				/* This is a three way call, the main call being a real channel, 
 					and we're parking the first call. */
-				ast_masq_park_call(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), chan, 0, NULL);
+				ast_features->ast_masq_park_call(ast_bridged_channel(p->subs[SUB_THREEWAY].owner), chan, 0, NULL);
 				if (option_verbose > 2)
 					ast_verbose(VERBOSE_PREFIX_3 "Parking call to '%s'\n", chan->name);
 				break;
Index: include/asterisk/adsi.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/adsi.h,v
retrieving revision 1.8
diff -u -r1.8 adsi.h
--- include/asterisk/adsi.h	21 Apr 2005 06:02:44 -0000	1.8
+++ include/asterisk/adsi.h	25 May 2005 21:10:15 -0000
@@ -110,6 +110,8 @@
 #define ADSI_DIR_FROM_LEFT (0)
 #define ADSI_DIR_FROM_RIGHT (1)
 
+struct adsi_services {
+#if 0
 /*! Perform Asterisk ADSI initialization (for channel drivers that want */
 /*    to support ADSI when the handset is first lifted) */ 
 /*! 
@@ -118,11 +120,12 @@
  * Returns 0 on success (or adsi unavailable) and -1 on hangup
  * 
  */
-extern int adsi_channel_init(struct ast_channel *chan);
+int (*channel_init)(struct ast_channel *chan);
+#endif
 
-extern int adsi_begin_download(struct ast_channel *chan, char *service, char *fdn, char *sec, int version);
+int (*begin_download)(struct ast_channel *chan, char *service, char *fdn, char *sec, int version);
 
-extern int adsi_end_download(struct ast_channel *chan);
+int (*end_download)(struct ast_channel *chan);
 
 /*! Restore ADSI initialization (for applications that play with ADSI */
 /*   and want to restore it to normal.  If you touch "INFO" then you */
@@ -133,7 +136,7 @@
  * Returns 0 on success (or adsi unavailable) and -1 on hangup
  *
  */
-extern int adsi_channel_restore(struct ast_channel *chan);
+int (*channel_restore)(struct ast_channel *chan);
 
 /*! Display some stuff on the screen */
 /*!
@@ -145,7 +148,7 @@
  * Return 0 on success (or adsi unavailable) and -1 on hangup
  *
  */
-extern int adsi_print(struct ast_channel *chan, char **lines, int *align, int voice);
+int (*print)(struct ast_channel *chan, char **lines, int *align, int voice);
 
 /*! Check if scripts for a given app are already loaded.  Version may be -1 */
 /*   if any version is okay, or 0-255 for a specific version. */
@@ -158,18 +161,21 @@
  * Returns 0 if scripts is not loaded or not an ADSI CPE.  Returns -1
  * on hangup.  Returns 1 if script already loaded.
  */
-extern int adsi_load_session(struct ast_channel *chan, unsigned char *app, int ver, int data);
-extern int adsi_unload_session(struct ast_channel *chan);
+int (*load_session)(struct ast_channel *chan, unsigned char *app, int ver, int data);
+int (*unload_session)(struct ast_channel *chan);
 
+#if 0
 /* ADSI Layer 2 transmission functions */
-extern int adsi_transmit_messages(struct ast_channel *chan, unsigned char **msg, int *msglen, int *msgtype);
-extern int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype);
-extern int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait);
+int (*transmit_messages)(struct ast_channel *chan, unsigned char **msg, int *msglen, int *msgtype);
+#endif
+
+int (*transmit_message)(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype);
+int (*transmit_message_full)(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait);
 /*! Read some encoded DTMF data.   */
 /*!
  * Returns number of bytes received
  */
-extern int adsi_read_encoded_dtmf(struct ast_channel *chan, unsigned char *buf, int maxlen);
+int (*read_encoded_dtmf)(struct ast_channel *chan, unsigned char *buf, int maxlen);
 
 /* ADSI Layer 3 creation functions */
 
@@ -183,14 +189,14 @@
  *
  */
 
-extern int adsi_connect_session(unsigned char *buf, unsigned char *fdn, int ver);
+int (*connect_session)(unsigned char *buf, unsigned char *fdn, int ver);
 
 /*! Build Query CPE ID of equipment */ 
 /*!
  *  Returns number of bytes added to message
  */
-extern int adsi_query_cpeid(unsigned char *buf);
-extern int adsi_query_cpeinfo(unsigned char *buf);
+int (*query_cpeid)(unsigned char *buf);
+int (*query_cpeinfo)(unsigned char *buf);
 
 /*! Get CPE ID from an attached ADSI compatible CPE. */
 /*!
@@ -198,9 +204,9 @@
  * or -1 on hangup, or 0 if there was no hangup but it failed to find the
  * device ID.  Returns to voice mode if "voice" is non-zero.
  */
-extern int adsi_get_cpeid(struct ast_channel *chan, unsigned char *cpeid, int voice);
+int (*get_cpeid)(struct ast_channel *chan, unsigned char *cpeid, int voice);
 
-extern int adsi_get_cpeinfo(struct ast_channel *chan, int *width, int *height, int *buttons, int voice);
+int (*get_cpeinfo)(struct ast_channel *chan, int *width, int *height, int *buttons, int voice);
 
 /*! Begin an ADSI script download */ 
 /*!
@@ -214,7 +220,7 @@
  *
  */
 
-extern int adsi_download_connect(unsigned char *buf, unsigned char *service, unsigned char *fdn, unsigned char *sec, int ver);
+int (*download_connect)(unsigned char *buf, unsigned char *service, unsigned char *fdn, unsigned char *sec, int ver);
 
 /*! Disconnects a running session */
 /*!
@@ -223,7 +229,7 @@
  * Returns number of bytes added to buffer or -1 on error.
  *
  */
-extern int adsi_disconnect_session(unsigned char *buf);
+int (*disconnect_session)(unsigned char *buf);
 
 /*! Disconnects (and hopefully saves) a downloaded script */
 /*!
@@ -232,7 +238,7 @@
  * Returns number of bytes added to buffer or -1 on error.
  *
  */
-extern int adsi_download_disconnect(unsigned char *buf);
+int (*download_disconnect)(unsigned char *buf);
 
 /*! Puts CPE in data mode... */
 /*!
@@ -241,9 +247,9 @@
  * Returns number of bytes added to buffer or -1 on error.
  *
  */
-extern int adsi_data_mode(unsigned char *buf);
-extern int adsi_clear_soft_keys(unsigned char *buf);
-extern int adsi_clear_screen(unsigned char *buf);
+int (*data_mode)(unsigned char *buf);
+int (*clear_soft_keys)(unsigned char *buf);
+int (*clear_screen)(unsigned char *buf);
 
 /*! Puts CPE in voice mode... */
 /*!
@@ -253,14 +259,14 @@
  * Returns number of bytes added to buffer or -1 on error.
  *
  */
-extern int adsi_voice_mode(unsigned char *buf, int when);
+int (*voice_mode)(unsigned char *buf, int when);
 
 /*! Returns non-zero if Channel does or might support ADSI */
 /*!
  * \param chan Channel to check
  *
  */
-extern int adsi_available(struct ast_channel *chan);
+int (*available)(struct ast_channel *chan);
 
 /*! Loads a line of info into the display */ 
 /*!
@@ -276,7 +282,7 @@
  *
  */
 
-extern int adsi_display(unsigned char *buf, int page, int line, int just, int wrap, unsigned char *col1, unsigned char *col2);
+int (*display)(unsigned char *buf, int page, int line, int just, int wrap, unsigned char *col1, unsigned char *col2);
 
 /*! Sets the current line and page */ 
 /*!
@@ -288,7 +294,7 @@
  *
  */
 
-extern int adsi_set_line(unsigned char *buf, int page, int line);
+int (*set_line)(unsigned char *buf, int page, int line);
 
 /*! Creates "load soft key" parameters */
 /*! 
@@ -302,7 +308,7 @@
  * Returns number of bytes added to buffer or -1 on error.
  *
  */
-extern int adsi_load_soft_key(unsigned char *buf, int key, unsigned char *llabel, unsigned char *slabel, unsigned char *ret, int data);
+int (*load_soft_key)(unsigned char *buf, int key, unsigned char *llabel, unsigned char *slabel, unsigned char *ret, int data);
 
 /*! Set which soft keys should be displayed */
 /*!
@@ -313,7 +319,7 @@
  * Returns number of bytes added to buffer or -1 on error.
  *
  */
-extern int adsi_set_keys(unsigned char *buf, unsigned char *keys);
+int (*set_keys)(unsigned char *buf, unsigned char *keys);
 
 /*! Set input information */
 /*!
@@ -327,7 +333,7 @@
  * Returns number of bytes added to buffer or -1 on error.
  *
  */
-extern int adsi_input_control(unsigned char *buf, int page, int line, int display, int format, int just);
+int (*input_control)(unsigned char *buf, int page, int line, int display, int format, int just);
 
 /*! Set input format */
 /*!
@@ -341,5 +347,6 @@
  * Returns number of bytes added to buffer or -1 on error.
  *
  */
-extern int adsi_input_format(unsigned char *buf, int num, int dir, int wrap, unsigned char *format1, unsigned char *format2);
+int (*input_format)(unsigned char *buf, int num, int dir, int wrap, unsigned char *format1, unsigned char *format2);
+};
 #endif
Index: include/asterisk/crypto.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/crypto.h,v
retrieving revision 1.6
diff -u -r1.6 crypto.h
--- include/asterisk/crypto.h	21 Apr 2005 06:02:44 -0000	1.6
+++ include/asterisk/crypto.h	25 May 2005 21:10:15 -0000
@@ -26,6 +26,7 @@
 
 struct ast_key;
 
+struct ast_crypto {
 /*! Retrieve a key */
 /*! 
  * \param name of the key we are retrieving
@@ -33,14 +34,16 @@
  *
  * Returns the key on success or NULL on failure
  */
-extern struct ast_key *ast_key_get(char *key, int type);
+struct ast_key *(*ast_key_get)(char *key, int type);
 
+#if 0
 /*! Initialize keys (that is, retrieve pass codes for all private keys) */
 /*!
  * \param fd a file descriptor for I/O for passwords
  *
  */
-extern int ast_key_init(int fd);
+int (*ast_key_init)(int fd);
+#endif
 
 /*! Check the authenticity of a message signature using a given public key */
 /*!
@@ -51,7 +54,7 @@
  * Returns 0 if the signature is valid, or -1 otherwise
  *
  */
-extern int ast_check_signature(struct ast_key *key, char *msg, char *sig);
+int (*ast_check_signature)(struct ast_key *key, char *msg, char *sig);
 
 /*! Check the authenticity of a message signature using a given public key */
 /*!
@@ -62,7 +65,7 @@
  * Returns 0 if the signature is valid, or -1 otherwise
  *
  */
-extern int ast_check_signature_bin(struct ast_key *key, char *msg, int msglen, unsigned char *sig);
+int (*ast_check_signature_bin)(struct ast_key *key, char *msg, int msglen, unsigned char *sig);
 
 /*!
  * \param key a private key to use to create the signature
@@ -73,7 +76,7 @@
  * Returns 0 on success or -1 on failure.
  *
  */
-extern int ast_sign(struct ast_key *key, char *msg, char *sig);
+int (*ast_sign)(struct ast_key *key, char *msg, char *sig);
 /*!
  * \param key a private key to use to create the signature
  * \param msg the message to sign
@@ -83,7 +86,7 @@
  * Returns 0 on success or -1 on failure.
  *
  */
-extern int ast_sign_bin(struct ast_key *key, char *msg, int msglen, unsigned char *sig);
+int (*ast_sign_bin)(struct ast_key *key, char *msg, int msglen, unsigned char *sig);
 
 /*!
  * \param key a private key to use to encrypt
@@ -95,7 +98,7 @@
  * Returns length of encrypted data on success or -1 on failure.
  *
  */
-extern int ast_encrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key);
+int (*ast_encrypt_bin)(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key);
 
 /*!
  * \param key a private key to use to decrypt
@@ -107,7 +110,9 @@
  * Returns length of decrypted data on success or -1 on failure.
  *
  */
-extern int ast_decrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key);
+int (*ast_decrypt_bin)(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key);
+};
+
 #if defined(__cplusplus) || defined(c_plusplus)
 }
 #endif
Index: include/asterisk/features.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/features.h,v
retrieving revision 1.4
diff -u -r1.4 features.h
--- include/asterisk/features.h	15 Jan 2005 23:48:12 -0000	1.4
+++ include/asterisk/features.h	25 May 2005 21:10:15 -0000
@@ -17,6 +17,7 @@
 #ifndef _AST_FEATURES_H
 #define _AST_FEATURES_H
 
+struct ast_features {
 /*! Park a call and read back parked location */
 /*! \param chan the channel to actually be parked
     \param host the channel which will have the parked location read to
@@ -27,7 +28,7 @@
 	\param timeout is a timeout in milliseconds
 	\param extout is a parameter to an int that will hold the parked location, or NULL if you want
 */
-extern int ast_park_call(struct ast_channel *chan, struct ast_channel *host, int timeout, int *extout);
+int (*ast_park_call)(struct ast_channel *chan, struct ast_channel *host, int timeout, int *extout);
 /*! Park a call via a masqueraded channel */
 /*! \param rchan the real channel to be parked
     \param host the channel to have the parking read to
@@ -36,19 +37,19 @@
 	\param timeout is a timeout in milliseconds
 	\param extout is a parameter to an int that will hold the parked location, or NULL if you want
 */
-extern int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *host, int timeout, int *extout);
+int (*ast_masq_park_call)(struct ast_channel *rchan, struct ast_channel *host, int timeout, int *extout);
 
 /*! Determine system parking extension */
 /*! Returns the call parking extension for drivers that provide special
     call parking help */
-extern char *ast_parking_ext(void);
-extern char *ast_pickup_ext(void);
+char * (*ast_parking_ext)(void);
+char * (*ast_pickup_ext)(void);
 
 /*! Bridge a call, optionally allowing redirection */
 
-extern int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer,struct ast_bridge_config *config);
-
-extern int ast_pickup_call(struct ast_channel *chan);
+int (*ast_bridge_call)(struct ast_channel *chan, struct ast_channel *peer,struct ast_bridge_config *config);
 
+int (*ast_pickup_call)(struct ast_channel *chan);
+};
 
 #endif /* _AST_FEATURES_H */
Index: include/asterisk/module.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/module.h,v
retrieving revision 1.16
diff -u -r1.16 module.h
--- include/asterisk/module.h	16 Jan 2005 22:59:30 -0000	1.16
+++ include/asterisk/module.h	25 May 2005 21:10:16 -0000
@@ -213,8 +213,53 @@
 	res = localusecnt; \
 	ast_mutex_unlock(&localuser_lock); \
 }
-	
-	
+
+/*
+ * modules that export symbols should provide an array
+ *	struct symbol_entry exported_symbols[]
+ * of symbols, with a NULL name on the last entry
+ * Functions should be added with MOD_FUNC(name),
+ * data structures with MOD_DATA(_name).
+ *
+ * Modules that require symbols supplied by other modules should
+ * provide an array
+ *	struct symbol_entry required_symbols[]
+ * of symbols, with a NULL name on the last entry
+ * Functions should be added with MOD_FUNC(name),
+ * data structures with MOD_DATA(_name).
+ *
+ * Typically, the whole interface exported by a module should be
+ * in a single structure named after the module, as follows.
+ * Say the module high level name is 'foo', then we should have
+ * - in include/asterisk/foo.h
+ *	struct foo_interface {
+ *		int (*f1)(int, char *);	-- first function exported
+ *		...			--- other functions
+ *	}
+ * - in the module exporting the interface, e.g. res/res_foo.c
+ *	struct foo_interface foo = {
+ *		MOD_FIELD(f1),			-- field and function name are the same
+ *		METHOD_BASE(foo_, f1),	-- field and function name differ by a prefix
+ *		.f1 = function_name,	-- generic case
+ *	}
+ *
+ * Note that the loader requires that no fields of exported_symbols
+ * are NULL.
+ */
+
+struct module;	/* forward declaration for pointer below */
+struct symbol_entry {
+	const char *name;
+	void *value;
+	int size;
+	struct module *src;	/* source module */
+};
+
+#define	MOD_FUNC(_name) { #_name, _name, sizeof(_name) }
+#define	MOD_DATA(_name) { #_name, &_name, sizeof(_name) }
+#define	MOD_WANT(_name) { #_name, &_name, 0 }	/* for required symbols */
+#define	MOD_FIELD(f)	. ## f = f
+#define	METHOD_BASE(_base, _name)	. ## _name = _base ## _name
 
 #if defined(__cplusplus) || defined(c_plusplus)
 }
Index: include/asterisk/monitor.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/monitor.h,v
retrieving revision 1.4
diff -u -r1.4 monitor.h
--- include/asterisk/monitor.h	21 Apr 2005 06:02:44 -0000	1.4
+++ include/asterisk/monitor.h	25 May 2005 21:10:16 -0000
@@ -21,17 +21,19 @@
 	int (*stop)( struct ast_channel *chan, int need_lock);
 };
 
+struct ast_monitor {
 /* Start monitoring a channel */
-int ast_monitor_start(	struct ast_channel *chan, const char *format_spec,
+int (*start)(	struct ast_channel *chan, const char *format_spec,
 						const char *fname_base, int need_lock );
 
 /* Stop monitoring a channel */
-int ast_monitor_stop( struct ast_channel *chan, int need_lock);
+int (*stop)( struct ast_channel *chan, int need_lock);
 
 /* Change monitoring filename of a channel */
-int ast_monitor_change_fname(	struct ast_channel *chan,
+int (*change_fname)(	struct ast_channel *chan,
 								const char *fname_base, int need_lock );
 
-void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon);
+void (*setjoinfiles)(struct ast_channel *chan, int turnon);
+};
 
 #endif /* _MONITOR_H */
Index: include/asterisk/utils.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/utils.h,v
retrieving revision 1.31
diff -u -r1.31 utils.h
--- include/asterisk/utils.h	20 May 2005 16:30:13 -0000	1.31
+++ include/asterisk/utils.h	25 May 2005 21:10:16 -0000
@@ -197,10 +197,12 @@
 		(ra)->ptr; \
 	})
 
+#if 0
 #ifdef inet_ntoa
 #undef inet_ntoa
 #endif
 #define inet_ntoa __dont__use__inet_ntoa__use__ast_inet_ntoa__instead__
+#endif
 
 #define AST_STACKSIZE 256 * 1024
 #define ast_pthread_create(a,b,c,d) ast_pthread_create_stack(a,b,c,d,0)
Index: include/asterisk/vmodem.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/vmodem.h,v
retrieving revision 1.19
diff -u -r1.19 vmodem.h
--- include/asterisk/vmodem.h	21 Apr 2005 06:02:44 -0000	1.19
+++ include/asterisk/vmodem.h	25 May 2005 21:10:16 -0000
@@ -142,33 +142,35 @@
 	struct ast_modem_pvt *next;			
 };
 
-
+struct ast_modem {
 /*! Register a modem driver */
 /*! Register a driver */
-extern int ast_register_modem_driver(struct ast_modem_driver *mc);
+int (*register_driver)(struct ast_modem_driver *mc);
 
 /*! Unregisters a modem driver */
 /*! Unregister a driver */
-extern int ast_unregister_modem_driver(struct ast_modem_driver *mc);
+int (*unregister_driver)(struct ast_modem_driver *mc);
 
 /*! Sends command */
 /*! Send the command cmd (length len, or 0 if pure ascii) on modem */
-extern int ast_modem_send(struct ast_modem_pvt *p, char *cmd, int len);
+int (*send)(struct ast_modem_pvt *p, char *cmd, int len);
 
 /*! Waits for result */
 /*! Wait for result to occur.  Return non-zero if times out or error, last
    response is stored in p->response  */
-extern int ast_modem_expect(struct ast_modem_pvt *p,  char *result, int timeout);
+int (*expect)(struct ast_modem_pvt *p,  char *result, int timeout);
 
 /*! Waits for result */
 /*! Wait for result to occur.    response is stored in p->response  */
-extern int ast_modem_read_response(struct ast_modem_pvt *p,  int timeout);
+int (*read_response)(struct ast_modem_pvt *p,  int timeout);
 
 /*! Used to start up the PBX on a RING */
 /*! Used by modem drivers to start up the PBX on a RING */
-extern struct ast_channel *ast_modem_new(struct ast_modem_pvt *i, int state);
+struct ast_channel * (*new)(struct ast_modem_pvt *i, int state);
 
 /*! Trim string of trailing stuff */
 /*! Trim off trailing mess */
-extern void ast_modem_trim(char *s);
+void (*trim)(char *s);
+};
+
 #endif
Index: pbx/pbx_dundi.c
===================================================================
RCS file: /usr/cvsroot/asterisk/pbx/pbx_dundi.c,v
retrieving revision 1.34
diff -u -r1.34 pbx_dundi.c
--- pbx/pbx_dundi.c	8 May 2005 16:44:25 -0000	1.34
+++ pbx/pbx_dundi.c	25 May 2005 21:10:22 -0000
@@ -56,6 +56,13 @@
 
 #define MAX_PACKET_SIZE 8192
 
+static struct ast_crypto *ast_crypto;
+struct symbol_entry required_symbols[] = {
+        MOD_WANT(ast_crypto),
+        { NULL, NULL }
+};
+
+
 extern char ast_config_AST_KEY_DIR[];
 
 static char *tdesc = "Distributed Universal Number Discovery (DUNDi)";
@@ -1289,23 +1296,23 @@
 		build_iv(key);
 		aes_encrypt_key128(key, &peer->us_ecx);
 		aes_decrypt_key128(key, &peer->us_dcx);
-		ekey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
+		ekey = ast_crypto->ast_key_get(peer->inkey, AST_KEY_PUBLIC);
 		if (!ekey) {
 			ast_log(LOG_NOTICE, "No such key '%s' for creating RSA encrypted shared key for '%s'!\n",
 				peer->inkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
 			return -1;
 		}
-		skey = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
+		skey = ast_crypto->ast_key_get(peer->outkey, AST_KEY_PRIVATE);
 		if (!skey) {
 			ast_log(LOG_NOTICE, "No such key '%s' for signing RSA encrypted shared key for '%s'!\n",
 				peer->outkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
 			return -1;
 		}
-		if ((res = ast_encrypt_bin(peer->txenckey, key, sizeof(key), ekey)) != 128) {
+		if ((res = ast_crypto->ast_encrypt_bin(peer->txenckey, key, sizeof(key), ekey)) != 128) {
 			ast_log(LOG_NOTICE, "Whoa, got a weird encrypt size (%d != %d)!\n", res, 128);
 			return -1;
 		}
-		if ((res = ast_sign_bin(skey, peer->txenckey, 128, peer->txenckey + 128))) {
+		if ((res = ast_crypto->ast_sign_bin(skey, peer->txenckey, 128, peer->txenckey + 128))) {
 			ast_log(LOG_NOTICE, "Failed to sign key (%d)!\n", res);
 			return -1;
 		}
@@ -1461,14 +1468,14 @@
 		return 1;
 	}
 	/* Decrypt key */
-	key = ast_key_get(peer->outkey, AST_KEY_PRIVATE);
+	key = ast_crypto->ast_key_get(peer->outkey, AST_KEY_PRIVATE);
 	if (!key) {
 		ast_log(LOG_NOTICE, "Unable to find key '%s' to decode shared key from '%s'\n",
 			peer->outkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
 		return -1;
 	}
 
-	skey = ast_key_get(peer->inkey, AST_KEY_PUBLIC);
+	skey = ast_crypto->ast_key_get(peer->inkey, AST_KEY_PUBLIC);
 	if (!skey) {
 		ast_log(LOG_NOTICE, "Unable to find key '%s' to verify shared key from '%s'\n",
 			peer->inkey, dundi_eid_to_str(eid_str, sizeof(eid_str), &peer->eid));
@@ -1476,11 +1483,11 @@
 	}
 
 	/* First check signature */
-	res = ast_check_signature_bin(skey, newkey, 128, newsig);
+	res = ast_crypto->ast_check_signature_bin(skey, newkey, 128, newsig);
 	if (res) 
 		return 0;
 
-	res = ast_decrypt_bin(dst, newkey, sizeof(dst), key);
+	res = ast_crypto->ast_decrypt_bin(dst, newkey, sizeof(dst), key);
 	if (res != 16) {
 		if (res >= 0)
 			ast_log(LOG_NOTICE, "Weird, key decoded to the wrong size (%d)\n", res);
Index: res/res_adsi.c
===================================================================
RCS file: /usr/cvsroot/asterisk/res/res_adsi.c,v
retrieving revision 1.13
diff -u -r1.13 res_adsi.c
--- res/res_adsi.c	21 Apr 2005 06:02:44 -0000	1.13
+++ res/res_adsi.c	25 May 2005 21:10:23 -0000
@@ -51,6 +51,15 @@
 
 static int alignment = 0;
 
+/* XXX some forward declarations */
+static int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait);
+
+static int adsi_download_connect(unsigned char *buf, unsigned char *service,  unsigned char *fdn, unsigned char *sec, int ver);
+static int adsi_download_disconnect(unsigned char *buf);
+static int adsi_data_mode(unsigned char *buf);
+static int adsi_voice_mode(unsigned char *buf, int when);
+static int adsi_print(struct ast_channel *chan, char **lines, int *aligns, int voice);
+
 static int adsi_generate(unsigned char *buf, int msgtype, char *msg, int msglen, int msgnum, int last, int codec)
 {
 	int sum;
@@ -301,7 +310,7 @@
 	
 }
 
-int adsi_begin_download(struct ast_channel *chan, char *service, char *fdn, char *sec, int version)
+static int adsi_begin_download(struct ast_channel *chan, char *service, char *fdn, char *sec, int version)
 {
 	int bytes;
 	unsigned char buf[256];
@@ -320,7 +329,7 @@
 	return -1;
 }
 
-int adsi_end_download(struct ast_channel *chan)
+static int adsi_end_download(struct ast_channel *chan)
 {
 	int bytes;
 	unsigned char buf[256];
@@ -333,7 +342,7 @@
 	return 0;
 }
 
-int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait)
+static int adsi_transmit_message_full(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype, int dowait)
 {
 	unsigned char *msgs[5] = { NULL, NULL, NULL, NULL, NULL };
 	int msglens[5];
@@ -407,7 +416,7 @@
 	return res;
 }
 
-int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype)
+static int adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype)
 {
 	return adsi_transmit_message_full(chan, msg, msglen, msgtype, 1);
 }
@@ -423,7 +432,7 @@
 	return x;
 }
 
-int adsi_load_soft_key(unsigned char *buf, int key, unsigned char *llabel, unsigned char *slabel, unsigned char *ret, int data)
+static int adsi_load_soft_key(unsigned char *buf, int key, unsigned char *llabel, unsigned char *slabel, unsigned char *ret, int data)
 {
 	int bytes=0;
 
@@ -462,7 +471,7 @@
 	
 }
 
-int adsi_connect_session(unsigned char *buf, unsigned char *fdn, int ver)
+static int adsi_connect_session(unsigned char *buf, unsigned char *fdn, int ver)
 {
 	int bytes=0;
 	int x;
@@ -485,7 +494,7 @@
 
 }
 
-int adsi_download_connect(unsigned char *buf, unsigned char *service,  unsigned char *fdn, unsigned char *sec, int ver)
+static int adsi_download_connect(unsigned char *buf, unsigned char *service,  unsigned char *fdn, unsigned char *sec, int ver)
 {
 	int bytes=0;
 	int x;
@@ -515,7 +524,7 @@
 
 }
 
-int adsi_disconnect_session(unsigned char *buf)
+static int adsi_disconnect_session(unsigned char *buf)
 {
 	int bytes=0;
 
@@ -530,7 +539,7 @@
 
 }
 
-int adsi_query_cpeid(unsigned char *buf)
+static int adsi_query_cpeid(unsigned char *buf)
 {
 	int bytes = 0;
 	buf[bytes++] = ADSI_QUERY_CPEID;
@@ -540,7 +549,7 @@
 	return bytes;
 }
 
-int adsi_query_cpeinfo(unsigned char *buf)
+static int adsi_query_cpeinfo(unsigned char *buf)
 {
 	int bytes = 0;
 	buf[bytes++] = ADSI_QUERY_CONFIG;
@@ -550,7 +559,7 @@
 	return bytes;
 }
 
-int adsi_read_encoded_dtmf(struct ast_channel *chan, unsigned char *buf, int maxlen)
+static int adsi_read_encoded_dtmf(struct ast_channel *chan, unsigned char *buf, int maxlen)
 {
 	int bytes = 0;
 	int res;
@@ -585,7 +594,7 @@
 	return bytes;
 }
 
-int adsi_get_cpeid(struct ast_channel *chan, unsigned char *cpeid, int voice)
+static int adsi_get_cpeid(struct ast_channel *chan, unsigned char *cpeid, int voice)
 {
 	char buf[256];
 	int bytes = 0;
@@ -617,7 +626,7 @@
 	return res;
 }
 
-int adsi_get_cpeinfo(struct ast_channel *chan, int *width, int *height, int *buttons, int voice)
+static int adsi_get_cpeinfo(struct ast_channel *chan, int *width, int *height, int *buttons, int voice)
 {
 	char buf[256];
 	int bytes = 0;
@@ -682,7 +691,7 @@
 	return res;
 }
 
-int adsi_data_mode(unsigned char *buf)
+static int adsi_data_mode(unsigned char *buf)
 {
 	int bytes=0;
 
@@ -697,7 +706,7 @@
 
 }
 
-int adsi_clear_soft_keys(unsigned char *buf)
+static int adsi_clear_soft_keys(unsigned char *buf)
 {
 	int bytes=0;
 
@@ -712,7 +721,7 @@
 
 }
 
-int adsi_clear_screen(unsigned char *buf)
+static int adsi_clear_screen(unsigned char *buf)
 {
 	int bytes=0;
 
@@ -727,7 +736,7 @@
 
 }
 
-int adsi_voice_mode(unsigned char *buf, int when)
+static int adsi_voice_mode(unsigned char *buf, int when)
 {
 	int bytes=0;
 
@@ -744,7 +753,7 @@
 
 }
 
-int adsi_available(struct ast_channel *chan)
+static int adsi_available(struct ast_channel *chan)
 {
 	int cpe = chan->adsicpe & 0xff;
 	if ((cpe == AST_ADSI_AVAILABLE) ||
@@ -753,7 +762,7 @@
 	return 0;
 }
 
-int adsi_download_disconnect(unsigned char *buf)
+static int adsi_download_disconnect(unsigned char *buf)
 {
 	int bytes=0;
 
@@ -768,7 +777,7 @@
 
 }
 
-int adsi_display(unsigned char *buf, int page, int line, int just, int wrap, 
+static int adsi_display(unsigned char *buf, int page, int line, int just, int wrap, 
 		 unsigned char *col1, unsigned char *col2)
 {
 	int bytes=0;
@@ -814,7 +823,7 @@
 
 }
 
-int adsi_input_control(unsigned char *buf, int page, int line, int display, int format, int just)
+static int adsi_input_control(unsigned char *buf, int page, int line, int display, int format, int just)
 {
 	int bytes=0;
 
@@ -837,7 +846,7 @@
 
 }
 
-int adsi_input_format(unsigned char *buf, int num, int dir, int wrap, unsigned char *format1, unsigned char *format2)
+static int adsi_input_format(unsigned char *buf, int num, int dir, int wrap, unsigned char *format1, unsigned char *format2)
 {
 	int bytes = 0;
 
@@ -856,7 +865,7 @@
 	return bytes;
 }
 
-int adsi_set_keys(unsigned char *buf, unsigned char *keys)
+static int adsi_set_keys(unsigned char *buf, unsigned char *keys)
 {
 	int bytes=0;
 	int x;
@@ -871,7 +880,7 @@
 	return bytes;
 }
 
-int adsi_set_line(unsigned char *buf, int page, int line)
+static int adsi_set_line(unsigned char *buf, int page, int line)
 {
 	int bytes=0;
 
@@ -902,7 +911,7 @@
 static int total = 0;
 static int speeds = 0;
 
-int adsi_channel_restore(struct ast_channel *chan)
+static int adsi_channel_restore(struct ast_channel *chan)
 {
 	char dsp[256];
 	int bytes;
@@ -929,7 +938,7 @@
 
 }
 
-int adsi_print(struct ast_channel *chan, char **lines, int *aligns, int voice)
+static int adsi_print(struct ast_channel *chan, char **lines, int *aligns, int voice)
 {
 	char buf[4096];
 	int bytes=0;
@@ -949,7 +958,7 @@
 	return res;
 }
 
-int adsi_load_session(struct ast_channel *chan, unsigned char *app, int ver, int data)
+static int adsi_load_session(struct ast_channel *chan, unsigned char *app, int ver, int data)
 {
 	char dsp[256];
 	int bytes;
@@ -990,7 +999,7 @@
 
 }
 
-int adsi_unload_session(struct ast_channel *chan)
+static int adsi_unload_session(struct ast_channel *chan)
 {
 	char dsp[256];
 	int bytes;
@@ -1124,3 +1133,42 @@
 {
 	return ASTERISK_GPL_KEY;
 }
+
+#define	METHOD(x)	METHOD_BASE(adsi_, x)
+struct adsi_services adsi = {
+	/* METHOD(channel_init), */
+	METHOD(begin_download),
+	METHOD(end_download),
+	METHOD(channel_restore),
+	METHOD(print),
+	METHOD(load_session),
+	METHOD(unload_session),
+	/* METHOD(transmit_messages), */
+	METHOD(transmit_message),
+	METHOD(transmit_message_full),
+	METHOD(read_encoded_dtmf),
+	METHOD(connect_session),
+	METHOD(query_cpeid),
+	METHOD(query_cpeinfo),
+	METHOD(get_cpeid),
+	METHOD(get_cpeinfo),
+	METHOD(download_connect),
+	METHOD(disconnect_session),
+	METHOD(download_disconnect),
+	METHOD(data_mode),
+	METHOD(clear_soft_keys),
+	METHOD(clear_screen),
+	METHOD(voice_mode),
+	METHOD(available),
+	METHOD(display),
+	METHOD(set_line),
+	METHOD(load_soft_key),
+	METHOD(set_keys),
+	METHOD(input_control),
+	METHOD(input_format),
+};
+
+struct symbol_entry exported_symbols[] = {
+	MOD_DATA(adsi),
+	{ NULL, NULL }
+};
Index: res/res_crypto.c
===================================================================
RCS file: /usr/cvsroot/asterisk/res/res_crypto.c,v
retrieving revision 1.20
diff -u -r1.20 res_crypto.c
--- res/res_crypto.c	21 Apr 2005 06:02:44 -0000	1.20
+++ res/res_crypto.c	25 May 2005 21:10:24 -0000
@@ -115,7 +115,7 @@
 	return -1;
 }
 
-struct ast_key *ast_key_get(char *kname, int ktype)
+static struct ast_key *ast_key_get(char *kname, int ktype)
 {
 	struct ast_key *key;
 	ast_mutex_lock(&keylock);
@@ -300,7 +300,7 @@
 
 #endif
 
-int ast_sign_bin(struct ast_key *key, char *msg, int msglen, unsigned char *dsig)
+static int ast_sign_bin(struct ast_key *key, char *msg, int msglen, unsigned char *dsig)
 {
 	unsigned char digest[20];
 	int siglen = 128;
@@ -331,7 +331,7 @@
 	
 }
 
-extern int ast_decrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
+static int ast_decrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
 {
 	int res;
 	int pos = 0;
@@ -357,7 +357,7 @@
 	return pos;
 }
 
-extern int ast_encrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
+static int ast_encrypt_bin(unsigned char *dst, const unsigned char *src, int srclen, struct ast_key *key)
 {
 	int res;
 	int bytes;
@@ -385,7 +385,7 @@
 	return pos;
 }
 
-int ast_sign(struct ast_key *key, char *msg, char *sig)
+static int ast_sign(struct ast_key *key, char *msg, char *sig)
 {
 	unsigned char dsig[128];
 	int siglen = sizeof(dsig);
@@ -398,7 +398,7 @@
 	
 }
 
-int ast_check_signature_bin(struct ast_key *key, char *msg, int msglen, unsigned char *dsig)
+static int ast_check_signature_bin(struct ast_key *key, char *msg, int msglen, unsigned char *dsig)
 {
 	unsigned char digest[20];
 	int res;
@@ -424,7 +424,7 @@
 	return 0;
 }
 
-int ast_check_signature(struct ast_key *key, char *msg, char *sig)
+static int ast_check_signature(struct ast_key *key, char *msg, char *sig)
 {
 	unsigned char dsig[128];
 	int res;
@@ -594,3 +594,19 @@
 {
 	return ASTERISK_GPL_KEY;
 }
+
+static struct ast_crypto ast_crypto = {
+	MOD_FIELD(ast_key_get),
+	/* MOD_FIELD(ast_key_init), */
+	MOD_FIELD(ast_check_signature),
+	MOD_FIELD(ast_check_signature_bin),
+	MOD_FIELD(ast_sign),
+	MOD_FIELD(ast_sign_bin),
+	MOD_FIELD(ast_encrypt_bin),
+	MOD_FIELD(ast_decrypt_bin),
+};
+
+struct symbol_entry exported_symbols[] = {
+	MOD_DATA(ast_crypto),
+	{ NULL, NULL }
+};
Index: res/res_features.c
===================================================================
RCS file: /usr/cvsroot/asterisk/res/res_features.c,v
retrieving revision 1.54
diff -u -r1.54 res_features.c
--- res/res_features.c	16 May 2005 00:43:16 -0000	1.54
+++ res/res_features.c	25 May 2005 21:10:26 -0000
@@ -130,6 +130,17 @@
 	struct parkeduser *next;
 };
 
+static struct adsi_services *adsi;
+static struct ast_monitor *ast_monitor;
+struct symbol_entry required_symbols[] = {
+	MOD_WANT(adsi),
+	MOD_WANT(ast_monitor),
+	{ NULL, NULL }
+};
+
+/* XXX forward declarations */
+static int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config);
+
 static struct parkeduser *parkinglot;
 
 AST_MUTEX_DEFINE_STATIC(parking_lock);
@@ -140,12 +151,12 @@
 
 LOCAL_USER_DECL;
 
-char *ast_parking_ext(void)
+static char *ast_parking_ext(void)
 {
 	return parking_ext;
 }
 
-char *ast_pickup_ext(void)
+static char *ast_pickup_ext(void)
 {
 	return pickup_ext;
 }
@@ -241,14 +252,14 @@
 
 	snprintf(tmp, sizeof(tmp), "Parked on %d", parkingnum);
 	message[0] = tmp;
-	res = adsi_load_session(chan, NULL, 0, 1);
+	res = adsi->load_session(chan, NULL, 0, 1);
 	if (res == -1) {
 		return res;
 	}
-	return adsi_print(chan, message, justify, 1);
+	return adsi->print(chan, message, justify, 1);
 }
 
-int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
+static int ast_park_call(struct ast_channel *chan, struct ast_channel *peer, int timeout, int *extout)
 {
 	/* We put the user in the parking list, then wake up the parking thread to be sure it looks
 	   after these channels too */
@@ -334,11 +345,11 @@
                                 );
 
 			if (peer) {
-				if (adsipark && adsi_available(peer)) {
+				if (adsipark && adsi->available(peer)) {
 					adsi_announce_park(peer, pu->parkingnum);
 				}
-				if (adsipark && adsi_available(peer)) {
-					adsi_unload_session(peer);
+				if (adsipark && adsi->available(peer)) {
+					adsi->unload_session(peer);
 				}
 			}
 			con = ast_context_find(parking_con);
@@ -373,7 +384,7 @@
 	return 0;
 }
 
-int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
+static int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer, int timeout, int *extout)
 {
 	struct ast_channel *chan;
 	struct ast_frame *f;
@@ -460,7 +471,7 @@
 	if (callee_chan->monitor) {
 		if (option_verbose > 3)
 			ast_verbose(VERBOSE_PREFIX_3 "User hit '%s' to stop recording call.\n", code);
-		ast_monitor_stop(callee_chan, 1);
+		ast_monitor->stop(callee_chan, 1);
 		return FEATURE_RETURN_SUCCESS;
 	}
 
@@ -909,7 +920,7 @@
 	}
 }
 
-int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
+static int ast_bridge_call(struct ast_channel *chan,struct ast_channel *peer,struct ast_bridge_config *config)
 {
 	/* Copy voice back and forth between the two channels.  Give the peer
 	   the ability to transfer calls with '#<extension' syntax. */
@@ -1645,6 +1656,7 @@
 int load_module(void)
 {
 	int res;
+
 	if ((res = load_config()))
 		return res;
 	ast_cli_register(&showparked);
@@ -1659,7 +1671,7 @@
 	return res;
 }
 
-int ast_pickup_call(struct ast_channel *chan)
+static int ast_pickup_call(struct ast_channel *chan)
 {
 	struct ast_channel *cur;
 	int res = -1;
@@ -1728,3 +1740,17 @@
 {
 	return ASTERISK_GPL_KEY;
 }
+
+struct ast_features ast_features = {
+	MOD_FIELD(ast_park_call),
+	MOD_FIELD(ast_masq_park_call),
+	MOD_FIELD(ast_parking_ext),
+	MOD_FIELD(ast_pickup_ext),
+	MOD_FIELD(ast_bridge_call),
+	MOD_FIELD(ast_pickup_call),
+};
+
+struct symbol_entry exported_symbols[] = {
+	MOD_DATA(ast_features),
+	{NULL, NULL}
+};
Index: res/res_monitor.c
===================================================================
RCS file: /usr/cvsroot/asterisk/res/res_monitor.c,v
retrieving revision 1.33
diff -u -r1.33 res_monitor.c
--- res/res_monitor.c	6 May 2005 07:15:08 -0000	1.33
+++ res/res_monitor.c	25 May 2005 21:10:28 -0000
@@ -25,6 +25,9 @@
 
 AST_MUTEX_DEFINE_STATIC(monitorlock);
 
+/* XXX forward declaration */
+static int ast_monitor_stop(struct ast_channel *chan, int need_lock);
+static void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon);
 static unsigned long seq = 0;
 
 static char *monitor_synopsis = "Monitor a channel";
@@ -65,7 +68,7 @@
 	"The argument is the new filename base to use for monitoring this channel.\n";
 
 /* Start monitoring a channel */
-int ast_monitor_start(	struct ast_channel *chan, const char *format_spec,
+static int ast_monitor_start(	struct ast_channel *chan, const char *format_spec,
 		const char *fname_base, int need_lock)
 {
 	int res = 0;
@@ -186,7 +189,7 @@
 }
 
 /* Stop monitoring a channel */
-int ast_monitor_stop(struct ast_channel *chan, int need_lock)
+static int ast_monitor_stop(struct ast_channel *chan, int need_lock)
 {
 	char *execute, *execute_args;
 	int delfiles = 0;
@@ -270,7 +273,7 @@
 }
 
 /* Change monitoring filename of a channel */
-int ast_monitor_change_fname(struct ast_channel *chan, const char *fname_base, int need_lock)
+static int ast_monitor_change_fname(struct ast_channel *chan, const char *fname_base, int need_lock)
 {
 	char tmp[256];
 	if ((!fname_base) || (ast_strlen_zero(fname_base))) {
@@ -536,7 +539,7 @@
 	return 0;
 }
 
-void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
+static void ast_monitor_setjoinfiles(struct ast_channel *chan, int turnon)
 {
 	if (chan->monitor)
 		chan->monitor->joinfiles = turnon;
@@ -587,3 +590,16 @@
 {
 	return ASTERISK_GPL_KEY;
 }
+
+#define	METHOD(x)	METHOD_BASE(ast_monitor_, x)
+static struct ast_monitor ast_monitor = {
+	METHOD(start),
+	METHOD(stop),
+	METHOD(change_fname),
+	METHOD(setjoinfiles),
+};
+
+struct symbol_entry exported_symbols[] = {
+	MOD_DATA(ast_monitor),
+	{ NULL, NULL}
+};
