Index: extensions/dbg_interactive/dbg_interactive.i
===================================================================
--- extensions/dbg_interactive/dbg_interactive.i	(revision 637)
+++ extensions/dbg_interactive/dbg_interactive.i	(revision 638)
@@ -129,4 +129,9 @@
 
 
+/* Forward declaration for the peers module */
+%{
+static void fd_add_cb(struct peer_info *peer, void *data);
+%}
+
 /*********************************************************
  Now, create wrappers for (almost) all objects from fD API 
Index: extensions/dbg_interactive/dictionary.i
===================================================================
--- extensions/dbg_interactive/dictionary.i	(revision 637)
+++ extensions/dbg_interactive/dictionary.i	(revision 638)
@@ -242,3 +242,170 @@
 		fd_log_debug("] '%.*s%s'\n", n, $self->data, n == LEN_MAX ? "..." : "");
 	}
-}
+	%cstring_output_allocate_size(char ** outbuffer, size_t * outlen, free(*$1));
+	void as_str ( char ** outbuffer, size_t * outlen ) {
+		char * b;
+		if (!$self->len) {
+			*outlen = 0;
+			*outbuffer = NULL;
+			return;
+		}
+		b = malloc($self->len);
+		if (!b) {
+			DI_ERROR_MALLOC;
+			return;
+		}
+		memcpy(b, $self->data, $self->len);
+		*outlen = $self->len;
+		*outbuffer = b;
+	}
+}
+
+
+/* Allow constructors with parameters for the dict_*_data */
+%extend dict_vendor_data {
+	dict_vendor_data(uint32_t id = 0, char * name = NULL) {
+		struct dict_vendor_data * d = (struct dict_vendor_data *)calloc(1, sizeof(struct dict_vendor_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		d->vendor_id = id;
+		if (name) {
+			d->vendor_name = strdup(name);
+			if (!d->vendor_name) {
+				DI_ERROR_MALLOC;
+				free(d);
+				return NULL;
+			}
+		}
+		return d;
+	}
+}
+
+%extend dict_application_data {
+	dict_application_data(uint32_t id = 0, char * name = NULL) {
+		struct dict_application_data * d = (struct dict_application_data *)calloc(1, sizeof(struct dict_application_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		d->application_id = id;
+		if (name) {
+			d->application_name = strdup(name);
+			if (!d->application_name) {
+				DI_ERROR_MALLOC;
+				free(d);
+				return NULL;
+			}
+		}
+		return d;
+	}
+}
+
+%extend dict_type_data {
+	dict_type_data(enum dict_avp_basetype base = 0, char * name = NULL) {
+		struct dict_type_data * d = (struct dict_type_data *)calloc(1, sizeof(struct dict_type_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		d->type_base = base;
+		if (name) {
+			d->type_name = strdup(name);
+			if (!d->type_name) {
+				DI_ERROR_MALLOC;
+				free(d);
+				return NULL;
+			}
+		}
+		return d;
+	}
+}
+
+%extend dict_enumval_data {
+	dict_enumval_data(char * name = NULL, uint32_t v = 0) {
+		struct dict_enumval_data * d = (struct dict_enumval_data *)calloc(1, sizeof(struct dict_enumval_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		if (name) {
+			d->enum_name = strdup(name);
+			if (!d->enum_name) {
+				DI_ERROR_MALLOC;
+				free(d);
+				return NULL;
+			}
+		}
+		d->enum_value.u32 = v;
+		return d;
+	}
+}
+
+%extend dict_avp_data {
+	dict_avp_data(uint32_t code = 0, char * name = NULL, enum dict_avp_basetype basetype = 0, uint32_t vendor = 0, int mandatory=0) {
+		struct dict_avp_data * d = (struct dict_avp_data *)calloc(1, sizeof(struct dict_avp_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		if (name) {
+			d->avp_name = strdup(name);
+			if (!d->avp_name) {
+				DI_ERROR_MALLOC;
+				free(d);
+				return NULL;
+			}
+		}
+		d->avp_code = code;
+		d->avp_basetype = basetype;
+		d->avp_vendor = vendor;
+		if (vendor) {
+			d->avp_flag_val |= AVP_FLAG_VENDOR;
+			d->avp_flag_mask |= AVP_FLAG_VENDOR;
+		}
+		d->avp_flag_mask |= AVP_FLAG_MANDATORY;
+		if (mandatory)
+			d->avp_flag_val |= AVP_FLAG_MANDATORY;
+		return d;
+	}
+}
+
+%extend dict_cmd_data {
+	dict_cmd_data(uint32_t code = 0, char * name = NULL, int request = 1) {
+		struct dict_cmd_data * d = (struct dict_cmd_data *)calloc(1, sizeof(struct dict_cmd_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		if (name) {
+			d->cmd_name = strdup(name);
+			if (!d->cmd_name) {
+				DI_ERROR_MALLOC;
+				free(d);
+				return NULL;
+			}
+		}
+		d->cmd_code = code;
+		d->cmd_flag_mask = CMD_FLAG_REQUEST | CMD_FLAG_PROXIABLE;
+		d->cmd_flag_val = CMD_FLAG_PROXIABLE | ( request ? CMD_FLAG_REQUEST : 0 );
+		return d;
+	}
+}
+
+%extend dict_rule_data {
+	dict_rule_data(struct dict_object *avp = NULL, enum rule_position pos = 0, int min = -1, int max = -1 ) {
+		struct dict_rule_data * d = (struct dict_rule_data *)calloc(1, sizeof(struct dict_rule_data));
+		if (!d) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		d->rule_avp = avp;
+		d->rule_position = pos;
+		d->rule_order = 1;
+		d->rule_min = min;
+		d->rule_max = max;
+		return d;
+	}
+}
+
Index: extensions/dbg_interactive/dispatch.i
===================================================================
--- extensions/dbg_interactive/dispatch.i	(revision 637)
+++ extensions/dbg_interactive/dispatch.i	(revision 638)
@@ -36,2 +36,119 @@
 /* Do not include this directly, use dbg_interactive.i instead */
 
+/****** DISPATCH *********/
+
+
+%{
+/* store the python callback function here */
+static PyObject * py_dispatch_cb = NULL;
+static int        py_dispatch_cb_n = 0;
+/* call it (will be called from a different thread than the interpreter, when message arrives) */
+static int call_the_python_dispatch_callback(struct msg **msg, struct avp *avp, struct session *session, enum disp_action *action) {
+	PyObject *PyMsg, *PyAvp, *PySess;
+	PyObject *result = NULL;
+	int ret = 0;
+	
+	if (!py_dispatch_cb)
+		return ENOTSUP;
+	
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+	/* Convert the arguments */
+	PyMsg  = SWIG_NewPointerObj((void *)*msg,     SWIGTYPE_p_msg,     0 );
+	PyAvp  = SWIG_NewPointerObj((void *) avp,     SWIGTYPE_p_avp,     0 );
+	PySess = SWIG_NewPointerObj((void *) session, SWIGTYPE_p_session, 0 );
+	
+	/* Call the function */
+	result = PyEval_CallFunction(py_dispatch_cb, "(OOO)", PyMsg, PyAvp, PySess);
+	
+	/* The result is supposedly composed of: [ ret, *msg, *action ] */
+	if ((result == NULL) || (!PyList_Check(result)) || (PyList_Size(result) != 3)) {
+		fd_log_debug("Error: The Python callback did not return [ ret, msg, action ].\n");
+		ret = EINVAL;
+		goto out;
+	}
+	
+	/* Convert the return values */
+	if (!SWIG_IsOK(SWIG_AsVal_int(PyList_GetItem(result, 0), &ret))) {
+		fd_log_debug("Error: Cannot convert the first return value to integer.\n");
+		ret = EINVAL;
+		goto out;
+	}
+	if (ret) {
+		TRACE_DEBUG(INFO, "The Python callback returned the error code %d (%s)\n", ret, strerror(ret));
+		goto out;
+	}
+	
+	if (!SWIG_IsOK(SWIG_ConvertPtr(PyList_GetItem(result, 1), (void *)msg, SWIGTYPE_p_msg, SWIG_POINTER_DISOWN))) {
+		fd_log_debug("Error: Cannot convert the second return value to message.\n");
+		ret = EINVAL;
+		goto out;
+	}
+	
+	if (!SWIG_IsOK(SWIG_AsVal_int(PyList_GetItem(result, 2), (int *)action))) {
+		fd_log_debug("Error: Cannot convert the third return value to integer.\n");
+		ret = EINVAL;
+		goto out;
+	}
+	
+	TRACE_DEBUG(FULL, "Python callback return: *action = %d\n", *action);
+out:	
+	Py_XDECREF(result);
+	
+	SWIG_PYTHON_THREAD_END_BLOCK;
+	return ret;
+}
+%}
+
+struct disp_hdl {
+};
+
+%nodefaultctor disp_hdl;
+%extend disp_hdl {
+	disp_hdl(PyObject * PyCb, enum disp_how how, struct disp_when * when) {
+		struct disp_hdl * hdl = NULL;
+		int ret;
+		if (py_dispatch_cb && (py_dispatch_cb != PyCb)) {
+			DI_ERROR(EINVAL, PyExc_SyntaxError, "Only one dispatch callback is supported at the moment in this extension\n.");
+			return NULL;
+		}
+		py_dispatch_cb = PyCb;
+		py_dispatch_cb_n += 1;
+		Py_XINCREF(py_dispatch_cb);
+		
+		ret = fd_disp_register ( call_the_python_dispatch_callback, how, when, &hdl );
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return hdl;
+	}
+	~disp_hdl() {
+		struct disp_hdl * hdl = self;
+		int ret = fd_disp_unregister(&hdl);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		/* Now free the callback */
+		Py_XDECREF(py_dispatch_cb);
+		py_dispatch_cb_n -= 1;
+		if (!py_dispatch_cb_n)
+			py_dispatch_cb = NULL;
+		return;
+	}
+}
+
+
+%extend disp_when {
+	disp_when(struct dict_object * app = NULL, struct dict_object * command = NULL, struct dict_object * avp = NULL, struct dict_object * value = NULL) {
+      		struct disp_when * w = (struct disp_when *)calloc(1, sizeof(struct disp_when));
+		if (!w) {
+			DI_ERROR_MALLOC;
+			return NULL;
+		}
+		w->app = app;
+		w->command = command;
+		w->avp = avp;
+		w->value = value;
+		return w;
+	}
+}
Index: extensions/dbg_interactive/messages.i
===================================================================
--- extensions/dbg_interactive/messages.i	(revision 637)
+++ extensions/dbg_interactive/messages.i	(revision 638)
@@ -38,4 +38,47 @@
 /****** MESSAGES *********/
 
+%{
+struct anscb_py_layer {
+	PyObject * cb;
+	PyObject * data;
+};
+
+/* If a python callback was provided, it is received in cbdata */
+static void anscb_python(void *cbdata, struct msg ** msg) {
+	/* The python callback is received in cbdata */
+	PyObject * result, *PyMsg;
+	struct anscb_py_layer * l = cbdata;
+	
+	if (!l) {
+		fd_log_debug("Internal error! Python callback disappeared...\n");
+		return;
+	}
+	
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+	
+	if (!msg || !*msg) {
+		PyMsg = Py_None;
+	} else {
+		PyMsg = SWIG_NewPointerObj((void *)*msg,     SWIGTYPE_p_msg,     0 );
+	}
+	
+	result = PyEval_CallFunction(l->cb, "(OO)", PyMsg, l->data);
+	Py_XDECREF(l->cb);
+	Py_XDECREF(l->data);
+	free(l);
+	
+	/* The callback is supposed to return a message or NULL */
+	if (!SWIG_IsOK(SWIG_ConvertPtr(result, (void *)msg, SWIGTYPE_p_msg, SWIG_POINTER_DISOWN))) {
+		fd_log_debug("Error: Cannot convert the return value to message.\n");
+		*msg = NULL;
+	}
+	
+	Py_XDECREF(result);
+	
+	SWIG_PYTHON_THREAD_END_BLOCK;
+	
+}
+%}
+
 struct msg {
 };
@@ -75,4 +118,32 @@
 		}
 	}
+	
+	/* SEND THE MESSAGE */
+	%delobject send; /* when this has been called, the msg must not be freed anymore */
+	void send(PyObject * PyCb = NULL, PyObject * data = NULL) {
+		int ret;
+		struct msg * m = $self;
+		struct anscb_py_layer * l = NULL;
+		
+		if (PyCb) {
+			l = malloc(sizeof(struct anscb_py_layer));
+			if (!l) {
+				DI_ERROR_MALLOC;
+				return;
+			}
+
+			Py_XINCREF(PyCb);
+			Py_XINCREF(data);
+			l->cb = PyCb;
+			l->data = data;
+		}
+		
+		ret = fd_msg_send(&m, PyCb ? anscb_python : NULL, l);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Create an answer */
 	%delobject create_answer; /* when this has been called, the original msg should not be freed anymore */
 	struct msg * create_answer(struct dictionary * dict = NULL, int flags = 0) {
@@ -313,4 +384,21 @@
 		}
 	}
+	
+	/* Set the result code */
+	void rescode_set(char * rescode = "DIAMETER_SUCCESS", char * errormsg = NULL, struct avp * optavp = NULL, int type_id = 0) {
+		int ret = fd_msg_rescode_set( $self, rescode, errormsg, optavp, type_id );
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Add the origin */
+	void add_origin(int osi = 0) {
+		int ret = fd_msg_add_origin( $self, osi );
+		if (ret) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
 }
 
Index: extensions/dbg_interactive/peers.i
===================================================================
--- extensions/dbg_interactive/peers.i	(revision 637)
+++ extensions/dbg_interactive/peers.i	(revision 638)
@@ -36,2 +36,54 @@
 /* Do not include this directly, use dbg_interactive.i instead */
 
+/****** PEERS *********/
+
+%{
+static void fd_add_cb(struct peer_info *peer, void *data) {
+	/* Callback called when the peer connection completes (or fails) */
+	PyObject *PyPeer, *PyFunc;
+	PyObject *result = NULL;
+	
+	if (!data) {
+		TRACE_DEBUG(INFO, "Internal error: missing callback\n");
+		return;
+	}
+	PyFunc = data;
+	
+	SWIG_PYTHON_THREAD_BEGIN_BLOCK;
+	
+	/* Convert the argument */
+	PyPeer  = SWIG_NewPointerObj((void *)peer,     SWIGTYPE_p_peer_info,     0 );
+	
+	/* Call the function */
+	result = PyEval_CallFunction(PyFunc, "(O)", PyPeer);
+	
+	Py_XDECREF(result);
+	Py_XDECREF(PyFunc);
+	
+	SWIG_PYTHON_THREAD_END_BLOCK;
+	return;
+}
+%}
+
+%extend peer_info {
+	/* Wrapper around fd_peer_add to allow calling the python callback */
+	void add(PyObject * PyCb=NULL) {
+		int ret;
+		
+		if (PyCb) {
+			Py_XINCREF(PyCb);
+			ret = fd_peer_add ( $self, "dbg_interactive", fd_add_cb, PyCb );
+		} else {
+			ret = fd_peer_add ( $self, "dbg_interactive", NULL, NULL );
+		}
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+
+	/* Add an endpoint */
+	void add_endpoint(char * endpoint) {
+		fd_log_debug("What is the best way in python to pass an endpoint? (ip + port)");
+	}
+
+}
Index: extensions/dbg_interactive/queues.i
===================================================================
--- extensions/dbg_interactive/queues.i	(revision 637)
+++ extensions/dbg_interactive/queues.i	(revision 638)
@@ -36,2 +36,110 @@
 /* Do not include this directly, use dbg_interactive.i instead */
 
+/****** FIFO QUEUES *********/
+
+struct fifo {
+};
+
+%extend fifo {
+	fifo() {
+		struct fifo * q = NULL;
+		int ret = fd_fifo_new(&q);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+			return NULL;
+		}
+		return q;
+	}
+	~fifo() {
+		struct fifo *q = self;
+		fd_fifo_del(&q);
+	}
+	
+	/* Move all elements to another queue */
+	void move(struct fifo * to) {
+		int ret = fd_fifo_move($self, to, NULL);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Get the length of the queue (nb elements) */
+	int length() {
+		int l;
+		int ret = fd_fifo_length ( $self, &l );
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		return l;
+	}
+
+	/* Is the threashold function useful here? TODO... */
+	
+	/* Post an item */
+	void post(PyObject * item) {
+		int ret;
+		PyObject * i = item;
+		
+		Py_XINCREF(i);
+		ret = fd_fifo_post($self, &i);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+	}
+	
+	/* Get (blocking) */
+	PyObject * get() {
+		int ret;
+		PyObject * i = NULL;
+		
+		ret = fd_fifo_get($self, &i);
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		
+		return i;
+	}
+	
+	/* TryGet (non-blocking, returns None on empty queue) */
+	PyObject * tryget() {
+		int ret;
+		PyObject * i = NULL;
+		
+		ret = fd_fifo_tryget($self, &i);
+		if (ret == EWOULDBLOCK) {
+			Py_XINCREF(Py_None);
+			return Py_None;
+		}
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		
+		return i;
+	}
+	
+	/* TimedGet (blocking for a while) */
+	PyObject * timedget(long seconds) {
+		int ret;
+		PyObject * i = NULL;
+		struct timespec ts;
+		
+		clock_gettime(CLOCK_REALTIME, &ts);
+		ts.tv_sec += seconds;
+		
+		ret = fd_fifo_timedget($self, &i, &ts);
+		if (ret == ETIMEDOUT) {
+			Py_XINCREF(Py_None);
+			return Py_None;
+		}
+		if (ret != 0) {
+			DI_ERROR(ret, NULL, NULL);
+		}
+		
+		return i;
+	}
+	
+}		
+	
+	
+	
+	
Index: extensions/dbg_interactive/sessions.i
===================================================================
--- extensions/dbg_interactive/sessions.i	(revision 637)
+++ extensions/dbg_interactive/sessions.i	(revision 638)
@@ -59,9 +59,6 @@
 };
 
+%nodefaultctor session_handler;
 %extend session_handler {
-	session_handler() {
-		DI_ERROR(EINVAL, PyExc_SyntaxError, "a cleanup callback parameter is required.");
-		return NULL;
-	}
 	session_handler(PyObject * PyCb) {
 		struct session_handler * hdl = NULL;
@@ -96,4 +93,5 @@
 	}
 }
+
 
 struct session {
