Index: pbx.c
===================================================================
RCS file: /usr/cvsroot/asterisk/pbx.c,v
retrieving revision 1.207
diff -u -u -r1.207 pbx.c
--- pbx.c	25 Feb 2005 00:25:27 -0000	1.207
+++ pbx.c	25 Feb 2005 17:32:22 -0000
@@ -139,7 +139,10 @@
     ast_state_cb_type callback;
     struct ast_state_cb *next;
 };
-	    
+
+static struct ast_pluggable_pbx *pluggable_pbx_root = NULL;
+static struct ast_pluggable_pbx *global_ppbx = NULL;
+
 /* ast_state_cb: An extension state notify */
 struct ast_devstate_cb {
     void *data;
@@ -2151,6 +2154,64 @@
 	return 0;
 }
 
+struct ast_pluggable_pbx* ast_pbx_find(char *name) 
+{
+	struct ast_pluggable_pbx *pbxptr;
+
+	for (pbxptr = pluggable_pbx_root ; pbxptr ; pbxptr = pbxptr->next) {
+		if (!strcmp(name, pbxptr->name)) {
+			break;
+		}
+	}	
+	
+	return pbxptr;
+}
+
+int ast_pbx_unregister(struct ast_pluggable_pbx *pbx) 
+{
+	struct ast_pluggable_pbx *pbxptr, *lastpbx = NULL;
+
+	if (pbx) {
+		if (pbx == global_ppbx) {
+			global_ppbx = NULL;
+		}
+		for (pbxptr = pluggable_pbx_root ; pbxptr ; pbxptr = pbxptr->next) {
+			if (pbxptr == pbx) {
+				if (lastpbx) {
+					lastpbx->next = pbx->next;
+				} else {
+					pluggable_pbx_root = pbx->next;
+				}
+				ast_verbose(VERBOSE_PREFIX_1 "Unregistered custom PBX %s\n", pbx->name);
+				return 0;
+			}
+			lastpbx = pbxptr;
+		}
+	}
+	return -1;
+}
+
+int ast_pbx_register(struct ast_pluggable_pbx *pbx) 
+{
+	struct ast_pluggable_pbx *pbxptr;
+
+	if (pbx) {
+		if (pbx->global) {
+			global_ppbx = pbx;
+		}
+		if((pbxptr = ast_pbx_find(pbx->name))) {
+			ast_log(LOG_ERROR, "PBX %s already in use.\n", pbx->name);
+			return -1;
+		}
+		pbx->next = pluggable_pbx_root;
+		pluggable_pbx_root = pbx;
+		ast_verbose(VERBOSE_PREFIX_1 "Registered custom %sPBX %s\n", pbx->global ? "global " : "", pbx->name);
+		return 0;
+	}
+
+	return -1;
+}
+
 static void *pbx_thread(void *data)
 {
 	/* Oh joyeous kernel, we're a new thread, with nothing to do but
@@ -2158,8 +2219,17 @@
 	   confusing, but necessary to get smooth transitions between
 	   the execution of different applications (without the use of
 	   additional threads) */
+	struct ast_pluggable_pbx *pbx = NULL;
 	struct ast_channel *c = data;
-	ast_pbx_run(c);
+	int res = 0;
+
+	if ((pbx = c->ppbx) || (pbx = global_ppbx)) {
+		res = pbx->run(c);
+	}
+
+	if (res || ! pbx)
+		ast_pbx_run(c);
+	
 	pthread_exit(NULL);
 	return NULL;
 }
Index: include/asterisk/pbx.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/pbx.h,v
retrieving revision 1.41
diff -u -u -r1.41 pbx.h
--- include/asterisk/pbx.h	2 Feb 2005 02:54:15 -0000	1.41
+++ include/asterisk/pbx.h	25 Feb 2005 17:32:23 -0000
@@ -71,6 +71,15 @@
 	int (*matchmore)(struct ast_channel *chan, const char *context, const char *exten, int priority, const char *callerid, const char *data);
 };
 
+/*! Data structure associated with an asterisk custom pbx */
+struct ast_pluggable_pbx {
+	char *name;
+	char *desc;
+	int (*run)(struct ast_channel *);
+	int global;
+	struct ast_pluggable_pbx *next;
+};
+
 struct ast_timing {
 	int hastime;				/* If time construct exists */
 	unsigned int monthmask;			/* Mask for month */
@@ -577,7 +586,9 @@
 extern void pbx_substitute_variables_varshead(struct varshead *headp, const char *cp1, char *cp2, int count);
 
 int ast_extension_patmatch(const char *pattern, const char *data);
-
+struct ast_pluggable_pbx* ast_pbx_find(char *name);
+int ast_pbx_unregister(struct ast_pluggable_pbx *pbx);
+int ast_pbx_register(struct ast_pluggable_pbx *pbx);
 /* Set "autofallthrough" flag, if newval is <0, does not acutally set.  If
   set to 1, sets to auto fall through.  If newval set to 0, sets to no auto
   fall through (reads extension instead).  Returns previous value. */
Index: include/asterisk/channel.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/channel.h,v
retrieving revision 1.75
diff -u -u -r1.75 channel.h
--- include/asterisk/channel.h	23 Feb 2005 22:48:47 -0000	1.75
+++ include/asterisk/channel.h	25 Feb 2005 17:32:23 -0000
@@ -122,7 +122,10 @@
 	/*! Current application */
 	char *appl;				
 	/*! Data passed to current application */
-	char *data;				
+	char *data;
+
+	/*! Pluggable PBX*/
+	struct ast_pluggable_pbx *ppbx;
 	
 	/*! Which fd had an event detected on */
 	int fdno;				
Index: channels/chan_iax2.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_iax2.c,v
retrieving revision 1.252
diff -u -u -r1.252 chan_iax2.c
--- channels/chan_iax2.c	19 Feb 2005 20:46:34 -0000	1.252
+++ channels/chan_iax2.c	25 Feb 2005 17:32:30 -0000
@@ -235,6 +235,7 @@
 	struct iax2_context *contexts;
 	struct iax2_user *next;
 	struct ast_variable *vars;
+	struct ast_pluggable_pbx *ppbx;          /* PBX */
 };
 
 struct iax2_peer {
@@ -513,6 +514,7 @@
 	int amaflags;
 	struct iax2_dpcache *dpentries;
 	struct ast_variable *vars;
+	struct ast_pluggable_pbx *pbxptr;
 	/* last received remote rr */
 	struct iax_rr remote_rr;
 	/* Current base time: (just for stats) */
@@ -521,6 +523,7 @@
 	int frames_dropped;
 	/* received frame count: (just for stats) */
 	int frames_received;
+	struct ast_pluggable_pbx *ppbx;
 };
 
 static struct ast_iax2_queue {
@@ -3004,6 +3007,9 @@
 		ast_mutex_unlock(&usecnt_lock);
 		ast_update_use_count();
 		if (state != AST_STATE_DOWN) {
+			if(i->ppbx)
+				tmp->ppbx = i->ppbx;
+			
 			if (ast_pbx_start(tmp)) {
 				ast_log(LOG_WARNING, "Unable to start PBX on %s\n", tmp->name);
 				ast_hangup(tmp);
@@ -4278,6 +4284,7 @@
 				iaxs[callno]->vars = tmpvar;
 			}
 		}
+		iaxs[callno]->ppbx = user->ppbx;
 		iaxs[callno]->prefs = user->prefs;
 		ast_copy_flags(iaxs[callno], user, IAX_CODEC_USER_FIRST);
 		ast_copy_flags(iaxs[callno], user, IAX_CODEC_NOPREFS);
@@ -6097,7 +6104,9 @@
 				/* This might re-enter the IAX code and need the lock */
 				if (strcasecmp(iaxs[fr.callno]->exten, "TBD")) {
 					ast_mutex_unlock(&iaxsl[fr.callno]);
-					exists = ast_exists_extension(NULL, iaxs[fr.callno]->context, iaxs[fr.callno]->exten, 1, iaxs[fr.callno]->cid_num);
+					exists = iaxs[fr.callno]->ppbx ? 1 : 0; /* let them deal with it. */
+					if (! exists)
+						exists = ast_exists_extension(NULL, iaxs[fr.callno]->context, iaxs[fr.callno]->exten, 1, iaxs[fr.callno]->cid_num);
 					ast_mutex_lock(&iaxsl[fr.callno]);
 				} else
 					exists = 0;
@@ -7540,6 +7549,10 @@
 				if (ast_test_flag(user, IAX_TRUNK) && (timingfd < 0)) {
 					ast_log(LOG_WARNING, "Unable to support trunking on user '%s' without zaptel timing\n", user->name);
 					ast_clear_flag(user, IAX_TRUNK);
+				}
+			} else if (!strcasecmp(v->name, "ppbx")) {
+				if (!(user->ppbx = ast_pbx_find(v->value))) {
+					ast_log(LOG_WARNING, "Invalid Pluggable PBX [%s] specified, Ignoring.", v->value);
 				}
 			} else if (!strcasecmp(v->name, "auth")) {
 				user->authmethods = get_auth_methods(v->value);
