diff -urN xcon_bfcp/apps/app_meetme.c xcon_bfcp_patched/apps/app_meetme.c
--- xcon_bfcp/apps/app_meetme.c	2007-03-07 11:43:50.000000000 +0100
+++ xcon_bfcp_patched/apps/app_meetme.c	2007-04-23 15:50:28.000000000 +0200
@@ -31,6 +31,8 @@
 
 /*** MODULEINFO
 	<depend>zaptel</depend>
+	<depend>bfcp</depend>
+	<depend>msrp</depend>
  ***/
 
 #include "asterisk.h"
@@ -78,6 +80,9 @@
 /*! Static, embedded, definitions of some common conference blueprints
 	\todo: make it dynamic */
 #include "xcon_bfcp/xcon_blueprints.h"
+/*! The MSRP (Message Session Relay Protocol) conference room manager */
+#include <msrp.h>
+
 
 #include "enter.h"
 #include "leave.h"
@@ -87,7 +92,7 @@
 #define DEFAULT_BFCP_TRANSPORT		BFCP_OVER_TLS	/*!< Default transport for BFCP (it can be BFCP_OVER_TCP as well) */
 #define DEFAULT_BFCP_PORT		2345		/*!< Default BFCP Server listening port */
 #define DEFAULT_GW_BFCP_PORT		2354		/*!< Default Gatewayed BFCP Server listening port (if used) */
-#define DEFAULT_GW_BFCP_DISPATCHER	3000		/*!< Default DCON Dispatcher listening port (if used) */
+#define DEFAULT_GW_DISPATCHER_PORT	3000		/*!< Default DCON Dispatcher listening port (if used) */
 #define DEFAULT_BFCP_MAXCONF	  	10		/*!< Default BFCP Server max number of allowed concurrent conferences */
 #define MAX_QUEUED_VIDEO_FRAMES		100		/*!< Max number of video fraes to enqueue for each user (then drop them) */
 
@@ -384,6 +389,8 @@
 	unsigned short int audiofloorID;	/*!< BFCP Floor ID for Audio, if enabled */
 	unsigned short int videofloorID;	/*!< BFCP Floor ID for Video, if enabled */
 
+	MsrpSwitch *msrp_room;			/*!< The MSRP conference room, if enabled */
+
 	AST_LIST_HEAD_NOLOCK(, ast_conf_user) userlist;
 	AST_LIST_HEAD_NOLOCK(, xcon_cascaded_conference) cascadedlist;
 	AST_LIST_HEAD_NOLOCK(, dcon_user) dconuserlist;		/* List of remote users */
@@ -421,6 +428,8 @@
 
 	unsigned short int dcon_stub_userID;	/*!< Temporary ID needed in DCON initial transactions */
 
+	unsigned short int msrp_user;		/*!< The MSRP conference user ID, if enabled */
+
 	unsigned short int queued_video_frames;
 	AST_LIST_HEAD_NOLOCK(, xcon_videoframe) videoframes;
 	ast_mutex_t videoframe_lock;		/*!< Lock to update/retrieve frames */
@@ -438,7 +447,14 @@
 	AST_LIST_ENTRY(dcon_user) list;
 };
 
-/*! \brief Mixer(s) and RTP related stuff */
+
+/*! \brief Callbacks from MSRP library (and chan_sip for SDP) */
+void callback_msrp(int event, MsrpSwitch *switcher, unsigned short int userID, void *data, int bytes);
+void events_msrp(int event, void *info);
+void sdp_msrp(unsigned long int conferenceID, struct ast_channel *chan, char *path);
+
+
+/*! \brief Mixer(s), Cascaded Conferences and RTP related stuff */
 struct xcon_videoframe {
 	struct ast_frame *frame;		/*!< A received frame, to send to the user */
 	AST_LIST_ENTRY(xcon_videoframe) list;
@@ -555,9 +571,9 @@
 static int xcon_debug_level;		/*! Level of verbose debug about XCON/DCON (0=no debug) */
 static int bfcp_exists;			/*! A static variable to check whether the FCS is up or not */
 static int bfcp_transport;		/*! A static variable that tells which transport will be used for BFCP */
-static unsigned short int bfcp_port;	/*! The port the BFCP server will listen on (TCP only, TLS not supported yet) */
-static unsigned short int gw_bfcp_port;	/*! The port the BFCP server will listen on, if gatewayed (TCP only, TLS not supported yet) */
-static char gw_ip[15];			/*! The IP the BFCP server will listen on, if gatewayed (TCP only, TLS not supported yet) */
+static unsigned short int bfcp_port;	/*! The port the BFCP server will listen on */
+static unsigned short int gw_bfcp_port;	/*! The port the BFCP server will listen on, if gatewayed */
+static char gw_ip[15];			/*! The IP the BFCP server will listen on, if gatewayed */
 static unsigned short int gw_bfcp_dispatcher;
 /*! Callback function called by the BFCP library to notify the application about incoming/outgoing BFCP messages */
 int bfcp_notifications(bfcp_arguments *arguments, int outgoing);
@@ -566,6 +582,9 @@
 /*! Callback function called by the Gateway to notify the application about DCON updates */
 int gw_notifications(int update, ...);
 
+/*! The address (IP or symbolic address) to report in MSRP negotiations */
+static char msrp_server[30];
+
 /*! XCON Registered Conferences management, to avoid always checking the configuration file */
 struct xcon_registered_conference {
 	char *subject;						/*! The conference subject (topic) */
@@ -974,6 +993,26 @@
 					if (option_verbose > 2)
 						ast_verbose(VERBOSE_PREFIX_3 "The new remote conference could not be added to the BFCP Server...\n");
 				}
+				/* NOTE: we create a local MSRP room */
+				cnf->msrp_room = msrp_switch_new();
+				if(!cnf->msrp_room) {
+					if (option_verbose > 2)
+						ast_verbose(VERBOSE_PREFIX_3 "Error creating new MSRP conference room...\n");
+				} else {
+					if (option_verbose > 2)
+						ast_verbose(VERBOSE_PREFIX_3 "New MSRP conference room (ID %lu) created:\n", cnf->msrp_room->ID);
+					/* Setup the MSRP server */
+					if(msrp_switch_set_from(cnf->msrp_room, msrp_server, 0) < 0) {
+						if (option_verbose > 2)
+							ast_verbose(VERBOSE_PREFIX_3 "\tError setting address for MSRP conference room...\n");
+						msrp_switch_destroy(cnf->msrp_room);
+						cnf->msrp_room = NULL;
+					} else {
+						if (option_verbose > 2)
+							ast_verbose(VERBOSE_PREFIX_3 "\tMSRP Path:\t%s\n", msrp_switch_get_fullpath(cnf->msrp_room));
+						cnf->msrp_room->opaque = cnf;
+					}
+				}
 				/* NOTE: we create an RTP channel to send/receive audio to/from the main XCON focus */
 				if(!xcon_setup_new_cascaded_conference(cnf)) {
 					fatal++;
@@ -993,7 +1032,7 @@
 				} else {
 					AST_LIST_TRAVERSE(&regxconfs, conferences, list) {	/* We look for the right conference */
 						if(conferences->conferenceID == cnf->xconconferenceID) {	/* Found, read it*/
-							/* Set up the conference type (remote or local) */
+							/* Set up the conference type (local) */
 							cnf->xcondcontype = XCON_LOCAL_CONFERENCE;
 							/* First of all we get the Administrator's numeric password... */
 							cnf->xconpassword = conferences->password;
@@ -1016,7 +1055,7 @@
 							/* ...and finally we add the required floors to the BFCP conference */
 							if(conferences->audiofloorID) { /* Add a Floor for Audio */
 								cnf->audiofloorID = conferences->audiofloorID;
-								if(bfcp_gw_add_floor_server(conferences->conferenceID, AUDIO_FLOOR, conferences->audiofloorID, 0, conferences->audiousers) <0 ) {
+								if(bfcp_gw_add_floor_server(conferences->conferenceID, AUDIO_FLOOR, conferences->audiofloorID, 0, conferences->audiousers) < 0) {
 									fatal++;
 									if (option_verbose > 2)
 										ast_verbose(VERBOSE_PREFIX_3 "Couldn't add the new Audio Floor to the Conference...\n");
@@ -1029,7 +1068,7 @@
 								cnf->videofloorID = conferences->videofloorID;
 								/* Only add to the list if Audio and Video floors are different (they could be managed together in the same floor) */
 								if(cnf->videofloorID != cnf->audiofloorID) {
-									if(bfcp_gw_add_floor_server(conferences->conferenceID, VIDEO_FLOOR, conferences->videofloorID, 0, conferences->videousers) <0 ) {
+									if(bfcp_gw_add_floor_server(conferences->conferenceID, VIDEO_FLOOR, conferences->videofloorID, 0, conferences->videousers) < 0) {
 										fatal++;
 										if (option_verbose > 2)
 											ast_verbose(VERBOSE_PREFIX_3 "Couldn't add the new Video Floor to the Conference...\n");
@@ -1041,6 +1080,26 @@
 							}
 							cnf->subject = conferences->subject;
 							conferences->is_active = 1;
+							/* Finally, create an MSRP room */
+							cnf->msrp_room = msrp_switch_new();
+							if(!cnf->msrp_room) {
+								if (option_verbose > 2)
+									ast_verbose(VERBOSE_PREFIX_3 "Error creating new MSRP conference room...\n");
+							} else {
+								if (option_verbose > 2)
+									ast_verbose(VERBOSE_PREFIX_3 "New MSRP conference room (ID %lu) created:\n", cnf->msrp_room->ID);
+								/* Setup the MSRP server */
+								if(msrp_switch_set_from(cnf->msrp_room, msrp_server, 0) < 0) {
+									if (option_verbose > 2)
+										ast_verbose(VERBOSE_PREFIX_3 "\tError setting address for MSRP conference room...\n");
+									msrp_switch_destroy(cnf->msrp_room);
+									cnf->msrp_room = NULL;
+								} else {
+									if (option_verbose > 2)
+										ast_verbose(VERBOSE_PREFIX_3 "\tMSRP Path:\t%s\n", msrp_switch_get_fullpath(cnf->msrp_room));
+									cnf->msrp_room->opaque = cnf;
+								}
+							}
 							break;
 						}
 					}
@@ -1102,7 +1161,8 @@
 "          0 - no debug (only joins/leaves)\n"
 "          1 - only DCON/XCON messages\n"
 "          2 - BFCP messages too\n"
-"          3 - full debug\n";
+"          3 - full debug\n"
+"          4 - VERY full debug (also useless MSRP log)\n";
 
 static char xcon_show_registered_usage[] = 
 "Usage: xcon show registered\n"
@@ -1173,9 +1233,11 @@
 	else
 		ast_cli(fd, "BFCP Server not up.\n");
 	if (scheduler_exists)
-		ast_cli(fd, "\tXconScheduler Server listening on port %d.\n", scheduler_port);
+		ast_cli(fd, "\tXconScheduler Server listening on port %d\n", scheduler_port);
 	else
-		ast_cli(fd, "XconScheduler Server not up.\n");
+		ast_cli(fd, "XconScheduler Server not up\n");
+	ast_cli(fd, "\tMSRP enabled, reporting public address %s (TCP/MSRP)\n", msrp_server);
+
 	return RESULT_SUCCESS;
 }
 
@@ -1185,7 +1247,7 @@
 		return RESULT_SHOWUSAGE;
 
 	int level = atoi(argv[2]);
-	if((level < 0) || (level > 3))
+	if((level < 0) || (level > 4))
 		return RESULT_SHOWUSAGE;
 
 	xcon_debug_level = level;
@@ -2202,6 +2264,10 @@
 			}
 		}
 
+		/* Destroy the MSRP conference room, if it exists */
+		if(conf->msrp_room)
+			msrp_switch_destroy(conf->msrp_room);
+
 		conf->xconconferenceID = 0;
 	}
 
@@ -2488,8 +2554,11 @@
 */
 			if(!strcmp(chan->tech->type, "SIP")) {	/* We only add the SDP reinvite if it's a SIP call */
 				if ((option_verbose > 2) && (xcon_debug_level > 2))
-					ast_verbose(VERBOSE_PREFIX_3 "  Sending required BFCP information to chan_sip...\n");
-				bfcp_sdp *sdp_bfcp = bfcp_create_sdp(bfcp_port, bfcp_transport, conf->xconconferenceID, user->xconuserID, conf->audiofloorID, conf->videofloorID);
+					ast_verbose(VERBOSE_PREFIX_3 "  Sending required BFCP+MSRP information to chan_sip...\n");
+				bfcp_sdp *sdp_bfcp = bfcp_create_sdp(bfcp_port, bfcp_transport,
+								conf->xconconferenceID, user->xconuserID,
+								conf->audiofloorID, conf->videofloorID,
+								sdp_msrp, msrp_switch_get_port(conf->msrp_room), msrp_switch_get_fullpath(conf->msrp_room));
 				ast_indicate_data(chan, -2, sdp_bfcp, 0);	/* A trick: we send the BFCP values using the 'indicate' channel operation */
 			} else {
 				if ((option_verbose > 2) && (xcon_debug_level > 2))
@@ -2969,8 +3038,9 @@
 					if(user->videofloorstatus == BFCP_GRANTED) {
 						videofloorstatus = BFCP_FLOOR_GRANTED;
 						ast_indicate(user->chan, AST_CONTROL_VIDUPDATE);
-					} else
+					} else {
 						videofloorstatus = BFCP_FLOOR_NOT_GRANTED;
+					}
 					if(conf->audiofloorID != conf->videofloorID)
 						ast_indicate_data(chan, -4, &videofloorstatus, 0);	/* A trick: we send the update using the 'indicate' channel operation,
 													   but only if video and audio have different floors */
@@ -3252,7 +3322,7 @@
 									break;
 								ast_mutex_lock(&usr->videoframe_lock);
 								if(usr->queued_video_frames < MAX_QUEUED_VIDEO_FRAMES) {
-									struct xcon_videoframe *vframe = calloc(sizeof(struct xcon_videoframe), sizeof(char));
+									struct xcon_videoframe *vframe = ast_calloc(1, sizeof(*vframe));
 									if(vframe) {
 										usr->queued_video_frames++;
 										vframe->frame = ast_frdup(f);
@@ -3287,7 +3357,7 @@
 									break;
 								ast_mutex_lock(&usr->videoframe_lock);
 								if(usr->queued_video_frames < MAX_QUEUED_VIDEO_FRAMES) {
-									struct xcon_videoframe *vframe = calloc(sizeof(struct xcon_videoframe), sizeof(char));
+									struct xcon_videoframe *vframe = ast_calloc(1, sizeof(*vframe));
 									if(vframe) {
 										usr->queued_video_frames++;
 										vframe->frame = ast_frdup(f);
@@ -3489,6 +3559,17 @@
 		}
 	}
 
+	/* Remove user from MSRP conference room, if needed */
+	if(conf->msrp_room && user->msrp_user) {
+		if(msrp_switch_remove_user(conf->msrp_room, user->msrp_user) < 0) {
+			if ((option_verbose > 2) && (xcon_debug_level > 2))
+				ast_verbose(VERBOSE_PREFIX_3 "\tCouldn't remove MSRP user with ID %hu from the MSRP conference room\n", user->msrp_user);
+		} else {
+			if ((option_verbose > 2) && (xcon_debug_level > 2))
+				ast_verbose(VERBOSE_PREFIX_3 "\tRemoved MSRP user with ID %hu from the MSRP conference room\n", user->msrp_user);
+		}
+	}
+
 	free(user);
 	AST_LIST_UNLOCK(&confs);
 
@@ -4398,14 +4479,14 @@
 {
 	if(!cnf || !ID)
 		return -1;
-	struct dcon_user *newuser = calloc(sizeof(struct dcon_user),sizeof(char));
+	struct dcon_user *newuser = ast_calloc(1, sizeof(*newuser));
 	if(!newuser)
 		return -1;
 	newuser->xconuserID = ID;
-	newuser->xconuseruri = calloc(strlen(uri)+1, sizeof(char));
+	newuser->xconuseruri = ast_calloc(strlen(uri)+1, sizeof(char));
 	if(newuser->xconuseruri)
 		strcpy(newuser->xconuseruri, uri);
-	newuser->xconuserdisplay = calloc(strlen(display)+1, sizeof(char));
+	newuser->xconuserdisplay = ast_calloc(strlen(display)+1, sizeof(char));
 	if(newuser->xconuserdisplay)
 		strcpy(newuser->xconuserdisplay, display);
 	newuser->audiofloorstatus = BFCP_FLOOR_NOT_GRANTED;
@@ -4566,8 +4647,8 @@
 			}
 		}
 	}
-	struct xcon_registered_conference *newconf = calloc(sizeof(struct xcon_registered_conference),sizeof(char));
-	newconf->subject = calloc(strlen(subject)+1, sizeof(char));
+	struct xcon_registered_conference *newconf = ast_calloc(1, sizeof(*newconf));
+	newconf->subject = ast_calloc(strlen(subject)+1, sizeof(char));
 	newconf->subject = strcpy(newconf->subject, subject);
 	newconf->conferenceID = conferenceID;
 	newconf->pin = pin;
@@ -4825,7 +4906,7 @@
 	struct ast_conference *cnf = NULL;
 	struct ast_conf_user *user = NULL;
 
-	int conf_type = 0, outgoing_bfcp_msg = 0;
+	int conf_type = 0, outgoing_bfcp_msg = 0, is_send = 0;
 	unsigned long int conferenceID = 0;
 	unsigned short int userID = 0, tempUserID = 0, audioFloor = 0, videoFloor = 0;
 	char *uri = NULL, *display = NULL, *msg = NULL;
@@ -4893,7 +4974,7 @@
 				if(!strcmp(user->chan->tech->type, "SIP")) {	/* We only add the SDP reinvite if it's a SIP call */
 					if ((option_verbose > 2) && (xcon_debug_level > 2))
 						ast_verbose(VERBOSE_PREFIX_3 "  Sending required BFCP information to chan_sip...\n");
-					bfcp_sdp *sdp_bfcp = bfcp_create_sdp(bfcp_port, bfcp_transport, cnf->xconconferenceID, user->xconuserID, cnf->audiofloorID, cnf->videofloorID);
+					bfcp_sdp *sdp_bfcp = bfcp_create_sdp(bfcp_port, bfcp_transport, cnf->xconconferenceID, user->xconuserID, cnf->audiofloorID, cnf->videofloorID, NULL, 0, NULL);	/* FIXME */
 					ast_indicate_data(user->chan, -2, sdp_bfcp, 0);	/* A trick: we send the BFCP values using the 'indicate' channel operation */
 				} else {
 					if ((option_verbose > 2) && (xcon_debug_level > 2))
@@ -5004,7 +5085,7 @@
 			if(audioRtpPort) {
 				if ((option_verbose > 2) && (xcon_debug_level > 2))
 					ast_verbose(VERBOSE_PREFIX_3 "Setting %s:%hu as audio RTP peer...\n", rtpIP, audioRtpPort);
-				mixer_audiohp = calloc(1, sizeof(struct ast_hostent));
+				mixer_audiohp = ast_calloc(1, sizeof(*mixer_audiohp));
 				mixer_ahp = ast_gethostbyname(rtpIP, mixer_audiohp);
 				asin.sin_family = AF_INET;
 				if (mixer_ahp)
@@ -5015,7 +5096,7 @@
 			if(videoRtpPort) {
 				if ((option_verbose > 2) && (xcon_debug_level > 2))
 					ast_verbose(VERBOSE_PREFIX_3 "Setting %s:%hu as video RTP peer...\n", rtpIP, videoRtpPort);
-				mixer_videohp = calloc(1, sizeof(struct ast_hostent));
+				mixer_videohp = ast_calloc(1, sizeof(*mixer_videohp));
 				mixer_vhp = ast_gethostbyname(rtpIP, mixer_videohp);
 				vsin.sin_family = AF_INET;
 				if (mixer_vhp)
@@ -5032,7 +5113,7 @@
 			/* We store the peer's information */
 			casconf->audioPeerPort = audioRtpPort;
 			casconf->videoPeerPort = videoRtpPort;
-			casconf->peerIP = calloc(strlen(rtpIP)+1, sizeof(char));
+			casconf->peerIP = ast_calloc(strlen(rtpIP)+1, sizeof(char));
 			if(casconf->peerIP)
 				strcpy(casconf->peerIP, rtpIP);
 			break;
@@ -5075,7 +5156,7 @@
 			/* We store the peer's information */
 			casconf->audioPeerPort = audioRtpPort;
 			casconf->videoPeerPort = videoRtpPort;
-			casconf->peerIP = calloc(strlen(rtpIP)+1, sizeof(char));
+			casconf->peerIP = ast_calloc(strlen(rtpIP)+1, sizeof(char));
 			if(casconf->peerIP)
 				strcpy(casconf->peerIP, rtpIP);
 			AST_LIST_UNLOCK(&confs);
@@ -5083,7 +5164,7 @@
 			if(audioRtpPort) {	/* Set RTP peer for audio */
 				if ((option_verbose > 2) && (xcon_debug_level > 2))
 					ast_verbose(VERBOSE_PREFIX_3 "Setting %s:%hu as audio RTP peer...\n", rtpIP, audioRtpPort);
-				mixer_audiohp = calloc(1, sizeof(struct ast_hostent));
+				mixer_audiohp = ast_calloc(1, sizeof(*mixer_audiohp));
 				mixer_ahp = ast_gethostbyname(rtpIP, mixer_audiohp);
 				asin.sin_family = AF_INET;
 				if (mixer_ahp)
@@ -5100,7 +5181,7 @@
 			if(videoRtpPort) {	/* Set RTP peer for audio */
 				if ((option_verbose > 2) && (xcon_debug_level > 2))
 					ast_verbose(VERBOSE_PREFIX_3 "Setting %s:%hu as video RTP peer...\n", rtpIP, videoRtpPort);
-				mixer_videohp = calloc(1, sizeof(struct ast_hostent));
+				mixer_videohp = ast_calloc(1, sizeof(*mixer_videohp));
 				mixer_vhp = ast_gethostbyname(rtpIP, mixer_videohp);
 				vsin.sin_family = AF_INET;
 				if (mixer_vhp)
@@ -5183,6 +5264,21 @@
 			sprintf(tmp2, "_%hu.", prefix);
 			ast_context_remove_extension("default", tmp2, 0, NULL);
 			break;
+		case GW_MSRP_MESSAGE:			/* A new MSRP message has arrived, manage it */
+			conferenceID = va_arg(ap, unsigned long int);
+			is_send = va_arg(ap, int);
+			msg = va_arg(ap, char *);
+			cnf = xcon_get_conference(conferenceID);
+			if(!cnf) {
+				if ((option_verbose > 2) && (xcon_debug_level > 2))
+					ast_verbose(VERBOSE_PREFIX_3 "Could not find Conference %lu for MSRP message...\n", conferenceID);
+				break;
+			}
+			if(!is_send)	/* REPORT (announcement) */
+				msrp_switch_announcement(cnf->msrp_room, 0, msg);
+			else 		/* SEND (chat text) */
+				msrp_switch_message(cnf->msrp_room, 0, msg);
+			break;
 		case GW_VERBOSE:		/* Verbose notifications from the Dispatcher */
 			msg = va_arg(ap, char *);
 			if ((option_verbose > 2) && (xcon_debug_level > 0))
@@ -5616,6 +5712,138 @@
 	return 0;
 }
 
+
+/*! \brief The callback to receive switching (conference rooms) related events from the MSRP library */
+void callback_msrp(int event, MsrpSwitch *switcher, unsigned short int userID, void *data, int bytes)
+{
+	if((event < 0) || !switcher)
+		return;
+
+	struct ast_conf_user *user = NULL;
+	struct ast_conference *conf = (struct ast_conference *)switcher->opaque;
+	if(!conf)
+		return;
+
+	char tmp[80];
+	char buffer[500];
+
+	switch(event) {
+		case MSRP_CONFUSER_SEND:	/* An MSRP user sent text in a room */
+			if ((option_verbose > 2) && (xcon_debug_level > 3))
+				ast_verbose(VERBOSE_PREFIX_3 "[%s] SEND: %s\n", term_color(tmp, "MSRP", COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), data ? (char *)data : "??");
+			if(dcon_enabled && !AST_LIST_EMPTY(&conf->cascadedlist)) {
+				AST_LIST_TRAVERSE(&conf->userlist, user, list) {
+					if (user->msrp_user == userID)
+						break;
+				}
+				if(!user)
+					break;
+				char *new_data = calloc(bytes + strlen(user->xconuserdisplay) + 4, sizeof(char));
+				sprintf(new_data, "@%s@ %s", user->xconuserdisplay, (char *)data);
+				bfcp_gw_dispatcher_forward_msrp_msg(conf->xconconferenceID, 1, new_data);
+				free(new_data);
+			}
+			break;
+		case MSRP_CONFUSER_JOIN:	/* A new MSRP user joined the room */
+			memset(buffer, 0, 500);
+			sprintf(buffer, "Topic: '%s'", conf->subject ? conf->subject : "No topic");
+			/* Play welcome message for this user only */
+			msrp_switch_announcement(switcher, userID, buffer);
+			/* Play an overall announcement to notify the join */
+			memset(buffer, 0, 500);
+			sprintf(buffer, "%s joined", data ? (char *)data : "??");
+			msrp_switch_announcement(switcher, 0, buffer);
+			if(dcon_enabled && !AST_LIST_EMPTY(&conf->cascadedlist))
+				bfcp_gw_dispatcher_forward_msrp_msg(conf->xconconferenceID, 0, buffer);
+			if ((option_verbose > 2) && (xcon_debug_level > 3))
+				ast_verbose(VERBOSE_PREFIX_3 "[%s] %s\n", term_color(tmp, "MSRP", COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), buffer);
+			break;
+		case MSRP_CONFUSER_LEAVE:	/* An MSRP user left the room */
+			/* Play an overall announcement to notify the leave */
+			memset(buffer, 0, 500);
+			sprintf(buffer, "%s left", data ? (char *)data : "??");
+			msrp_switch_announcement(switcher, 0, buffer);
+			if(dcon_enabled && !AST_LIST_EMPTY(&conf->cascadedlist))
+				bfcp_gw_dispatcher_forward_msrp_msg(conf->xconconferenceID, 0, buffer);
+			if ((option_verbose > 2) && (xcon_debug_level > 3))
+				ast_verbose(VERBOSE_PREFIX_3 "[%s] %s\n", term_color(tmp, "MSRP", COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), buffer);
+			break;
+		default:
+			break;
+	}
+}
+
+/*! \brief The callback to receive incoming logging events from the MSRP library */
+void events_msrp(int event, void *info)
+{
+	if((xcon_debug_level < 4) || (event == MSRP_NONE))
+		return;
+
+	/* Debug text notifications */
+	char *head = NULL;
+	if(event == MSRP_LOG)
+		head = "MSRP_LOG";
+	else if(event == MSRP_ERROR)
+		head = "MSRP_ERROR";
+	else
+		return;
+
+	char tmp[200];
+	if (option_verbose > 2)
+		ast_verbose(VERBOSE_PREFIX_3 "[%s] %s\n", term_color(tmp, head, COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), info ? (char *)info : "??");
+}
+
+/*! \brief The callback to receive SDP negotiated MSRP paths */
+void sdp_msrp(unsigned long int conferenceID, struct ast_channel *chan, char *path)
+{
+	if(!conferenceID || !chan || !path)
+		return;
+
+	/*
+		The SIP channel driver just told us that a user
+		(*chan in the specified conference) negotiated
+		*path as his MSRP path: now we have to look for
+		the user in the specified conference, and
+		add her/him to the MSRP conference room there
+	*/
+
+	struct ast_conference *conf = xcon_get_conference(conferenceID);
+	if(!conf) {
+		if ((option_verbose > 2) && (xcon_debug_level > 2))
+			ast_verbose(VERBOSE_PREFIX_3 "\tInvalid conference %lu in SDP notification about MSRP path %s...\n", conferenceID, path);
+		return;
+	}
+	if(!conf->msrp_room) {
+		if ((option_verbose > 2) && (xcon_debug_level > 2))
+			ast_verbose(VERBOSE_PREFIX_3 "\tInvalid MSRP room in conference %lu, can't add MSRP path %s...\n", conferenceID, path);
+		return;
+	}
+	/* Look for the user with the specified channel in this conference */
+	struct ast_conf_user *user;
+	AST_LIST_TRAVERSE(&conf->userlist, user, list) {
+		if (user->chan == chan)
+			break;
+	}
+	if(!user) {
+		if ((option_verbose > 2) && (xcon_debug_level > 2))
+			ast_verbose(VERBOSE_PREFIX_3 "\tCouldn't find channel in conference %lu, can't add MSRP path %s...\n", conferenceID, path);
+		return;
+	}
+	char *display = user->xconuserdisplay;
+	int flags = MSRP_ACTIVE | MSRP_OVER_TCP;
+	unsigned short int msrpID = 0;
+	msrpID = msrp_switch_add_user(conf->msrp_room, display, path, MSRP_TEXT_PLAIN, flags, MSRP_SENDRECV);
+	if(!msrpID) {
+		if ((option_verbose > 2) && (xcon_debug_level > 2))
+			ast_verbose(VERBOSE_PREFIX_3 "\tCouldn't add %s (%s) to the MSRP conference room\n", display, path);
+	} else {
+		user->msrp_user = msrpID;
+		if ((option_verbose > 2) && (xcon_debug_level > 2))
+			ast_verbose(VERBOSE_PREFIX_3 "\tAdded %s (%s) to the MSRP conference room with ID %hu\n", display, path, msrpID);
+	}
+}
+
+
 /*! \brief Method to setup a new cascaded conference */
 struct xcon_cascaded_conference *xcon_setup_new_cascaded_conference(struct ast_conference *cnf)
 {
@@ -5851,7 +6079,7 @@
 						break;
 					ast_mutex_lock(&usr->videoframe_lock);
 					if(usr->queued_video_frames < MAX_QUEUED_VIDEO_FRAMES) {
-						struct xcon_videoframe *vframe = calloc(sizeof(struct xcon_videoframe), sizeof(char));
+						struct xcon_videoframe *vframe = ast_calloc(1, sizeof(*vframe));
 						if(vframe) {
 							usr->queued_video_frames++;
 							vframe->frame = ast_frdup(f);
@@ -7537,31 +7765,31 @@
 	if ((val = ast_variable_retrieve(cfg, "general", "fcs_port"))) {
 		if (sscanf(val, "%hd", &(gw_bfcp_port)) == 1) {
 			if (option_verbose > 2)
-				ast_verbose(VERBOSE_PREFIX_3 "Gatewayed BFCP Server will listen on port %d...\n",gw_bfcp_port);
+				ast_verbose(VERBOSE_PREFIX_3 "Gatewayed BFCP Server will listen on port %d...\n", gw_bfcp_port);
 		} else {
 			ast_log(LOG_WARNING, "Invalid port number '%s', using default value\n", val);
 			gw_bfcp_port = DEFAULT_GW_BFCP_PORT;
 			if (option_verbose > 2)
-				ast_verbose(VERBOSE_PREFIX_3 "Not a valid port, Gatewayed BFCP Server will listen on default port %d...\n",gw_bfcp_port);
+				ast_verbose(VERBOSE_PREFIX_3 "Not a valid port, Gatewayed BFCP Server will listen on default port %d...\n", gw_bfcp_port);
 		}
 	}
 	/* ...and the IP to reach the gatewayed FCS (default: 127.0.0.1) */
 	if ((val = ast_variable_retrieve(cfg, "general", "fcs_ip"))) {
 		if (sscanf(val, "%s", gw_ip) == 1)
 			if (option_verbose > 2)
-				ast_verbose(VERBOSE_PREFIX_3 "Gatewayed BFCP Server will listen on IP %s...\n",gw_ip);
+				ast_verbose(VERBOSE_PREFIX_3 "Gatewayed BFCP Server will listen on IP %s...\n", gw_ip);
 	}
 
 	/* If DCON is enabled, we get the port number for the Dispatcher listener as well */
 	if ((val = ast_variable_retrieve(cfg, "general", "dispatcher"))) {
 		if (sscanf(val, "%hd", &(gw_bfcp_dispatcher)) == 1) {
 			if (option_verbose > 2)
-				ast_verbose(VERBOSE_PREFIX_3 "XCON <--> DCON BFCP Dispatcher will listen on port %d...\n",gw_bfcp_dispatcher);
+				ast_verbose(VERBOSE_PREFIX_3 "XCON <--> DCON BFCP Dispatcher will listen on port %d...\n", gw_bfcp_dispatcher);
 		} else {
 			ast_log(LOG_WARNING, "Invalid port number '%s', using default value\n", val);
-			gw_bfcp_dispatcher = DEFAULT_GW_BFCP_DISPATCHER;
+			gw_bfcp_dispatcher = DEFAULT_GW_DISPATCHER_PORT;
 			if (option_verbose > 2)
-				ast_verbose(VERBOSE_PREFIX_3 "Not a valid port, DCON BFCP Dispatcher will listen on default port %d...\n",gw_bfcp_port);
+				ast_verbose(VERBOSE_PREFIX_3 "Not a valid port, DCON BFCP Dispatcher will listen on default port %d...\n", gw_bfcp_port);
 		}
 	}
 
@@ -7616,22 +7844,22 @@
 		} else if (!strcasecmp(v->name, "maxconf")) {
 			if (sscanf(v->value, "%d", &maxconf) == 1) {
 				if (option_verbose > 2)
-					ast_verbose(VERBOSE_PREFIX_3 "BFCP Server will allow max %d conferences at a time...\n",maxconf);
+					ast_verbose(VERBOSE_PREFIX_3 "BFCP Server will allow max %d conferences at a time...\n", maxconf);
 			} else {
 				ast_log(LOG_WARNING, "Invalid maxconf '%s' at line %d of %s, using default value\n", v->value, v->lineno, CONFIG_FILE_NAME);
 				maxconf = DEFAULT_BFCP_MAXCONF;
 				if (option_verbose > 2)
-					ast_verbose(VERBOSE_PREFIX_3 "BFCP Server will allow max %d (default value setting) conferences at a time...\n",maxconf);
+					ast_verbose(VERBOSE_PREFIX_3 "BFCP Server will allow max %d (default value setting) conferences at a time...\n", maxconf);
 			}
 		} else if (!strcasecmp(v->name, "bfcp_port")) {
 			if (sscanf(v->value, "%hd", &(bfcp_port)) == 1) {
 				if (option_verbose > 2)
-					ast_verbose(VERBOSE_PREFIX_3 "BFCP Server will listen on port %d...\n",bfcp_port);
+					ast_verbose(VERBOSE_PREFIX_3 "BFCP Server will listen on port %d...\n", bfcp_port);
 			} else {
 				ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s, using default value\n", v->value, v->lineno, CONFIG_FILE_NAME);
 				bfcp_port = DEFAULT_BFCP_PORT;
 				if (option_verbose > 2)
-					ast_verbose(VERBOSE_PREFIX_3 "Not a valid port, BFCP Server will listen on default port %d...\n",bfcp_port);
+					ast_verbose(VERBOSE_PREFIX_3 "Not a valid port, BFCP Server will listen on default port %d...\n", bfcp_port);
 			}
 		} else if (!strcasecmp(v->name, "bfcp_transport")) {
 			if (!strcasecmp(v->value, "TLS"))
@@ -7643,12 +7871,12 @@
 		} else if (!strcasecmp(v->name, "scheduler_port")) {
 			if (sscanf(v->value, "%hd", &(scheduler_port)) == 1) {
 				if (option_verbose > 2)
-					ast_verbose(VERBOSE_PREFIX_3 "XconScheduler will listen on port %d...\n",scheduler_port);
+					ast_verbose(VERBOSE_PREFIX_3 "XconScheduler will listen on port %d...\n", scheduler_port);
 			} else {
 				ast_log(LOG_WARNING, "Invalid port number '%s' at line %d of %s, using default value\n", v->value, v->lineno, CONFIG_FILE_NAME);
 				scheduler_port = DEFAULT_SCHEDULER_PORT;
 				if (option_verbose > 2)
-					ast_verbose(VERBOSE_PREFIX_3 "Not a valid port, XconScheduler will listen on default port %d...\n",scheduler_port);
+					ast_verbose(VERBOSE_PREFIX_3 "Not a valid port, XconScheduler will listen on default port %d...\n", scheduler_port);
 			}
 		}
 		v = v->next;
@@ -7687,10 +7915,10 @@
 		v = ast_variable_browse(cfg, "tls");
 		while(v) {
 			if (!strcasecmp(v->name, "certificate")) {
-				certificate = calloc(strlen(v->value)+1, sizeof(char));
+				certificate = ast_calloc(strlen(v->value)+1, sizeof(char));
 				strcpy(certificate, v->value);
 			} else if (!strcasecmp(v->name, "privatekey")) {
-				privatekey = calloc(strlen(v->value)+1, sizeof(char));
+				privatekey = ast_calloc(strlen(v->value)+1, sizeof(char));
 				strcpy(privatekey, v->value);
 			}
 			v = v->next;
@@ -7827,6 +8055,24 @@
 		}
 		var_rooms = var_rooms->next;
 	}
+
+	/* Finally we initialize the MSRP library, by passing the callback to receive events */
+	char tmp[80];
+	if ((val = ast_variable_retrieve(cfg, "msrp", "msrp"))) {
+		sscanf(val, "%s", msrp_server);
+		if (option_verbose > 2)
+			ast_verbose(VERBOSE_PREFIX_3 "[%s] Using %s as address to report in MSRP negotiations\n", term_color(tmp, "MSRP", COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)), msrp_server);
+	} else {
+		sprintf(msrp_server, "127.0.0.1");
+		if (option_verbose > 2)
+			ast_verbose(VERBOSE_PREFIX_3 "[%s] No 'msrp' in [msrp], using '127.0.0.1' (BAD!) as address to report in MSRP negotiations...\n", term_color(tmp, "MSRP", COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)));
+	}
+	msrp_init(events_msrp);
+	if (option_verbose > 2)
+		ast_verbose(VERBOSE_PREFIX_3 "[%s] MSRP library initialized...\n", term_color(tmp, "MSRP", COLOR_MAGENTA, COLOR_BLACK, sizeof(tmp)));
+	/* Setup the callback to receive switching (conference rooms) related info */
+	msrp_sw_callback(callback_msrp);
+
 	ast_config_destroy(cfg);
 }
 
@@ -7897,13 +8143,13 @@
 	res |= ast_devstate_prov_add("SLA", sla_state);
 
 
-	/* Make sure both the BFCP and the XCON Scheduler server are up after the configs load */
-	if (!bfcp_exists) {
+	/* Make sure both the BFCP and the XCON Scheduler server are up after the configs load, if XCON is needed */
+	if (xcon_prefix && !bfcp_exists) {
 		if (option_verbose > 2)
 			ast_verbose(VERBOSE_PREFIX_3 "BFCP Server not up, fatal error...\n");
 		res = -1;
 	}
-	if (!scheduler_exists) {
+	if (xcon_prefix && !scheduler_exists) {
 		if (option_verbose > 2)
 			ast_verbose(VERBOSE_PREFIX_3 "XconScheduler Server not up, fatal error...\n");
 		res = -1;
diff -urN xcon_bfcp/apps/Makefile xcon_bfcp_patched/apps/Makefile
--- xcon_bfcp/apps/Makefile	2007-03-07 11:43:49.000000000 +0100
+++ xcon_bfcp_patched/apps/Makefile	2007-04-23 15:50:28.000000000 +0200
@@ -37,4 +37,5 @@
 
 include $(ASTTOPDIR)/Makefile.moddir_rules
 
-app_meetme.so : app_meetme.o xcon_bfcp/xcon_scheduler.o xcon_bfcp/bfcp_server.o xcon_bfcp/bfcp_link_list.o xcon_bfcp/bfcp_user_list.o xcon_bfcp/bfcp_floor_list.o xcon_bfcp/bfcp_messages.o xcon_bfcp/bfcp_messages_build.o xcon_bfcp/bfcp_messages_parse.o xcon_bfcp/bfcp_sdp.o xcon_bfcp/bfcp_gw.o xcon_bfcp/bfcp_base64.o
+XCONBFCP = xcon_bfcp/xcon_scheduler.o xcon_bfcp/bfcp_sdp.o xcon_bfcp/bfcp_gw.o xcon_bfcp/bfcp_base64.o
+app_meetme.so : app_meetme.o $(XCONBFCP)
diff -urN xcon_bfcp/apps/xcon_bfcp/bfcp_base64.c xcon_bfcp_patched/apps/xcon_bfcp/bfcp_base64.c
--- xcon_bfcp/apps/xcon_bfcp/bfcp_base64.c	2007-03-07 11:43:49.000000000 +0100
+++ xcon_bfcp_patched/apps/xcon_bfcp/bfcp_base64.c	2007-04-23 15:50:28.000000000 +0200
@@ -1,618 +1,53 @@
-/*********************************************************************\
-
-MODULE NAME:    b64.c
-
-AUTHOR:         Bob Trower 08/04/01
-
-PROJECT:        Crypt Data Packaging
-
-COPYRIGHT:      Copyright (c) Trantor Standard Systems Inc., 2001
-
-NOTE:           This source code may be used as you wish, subject to
-                the MIT license.  See the LICENCE section below.
-
-DESCRIPTION:
-                This little utility implements the Base64
-                Content-Transfer-Encoding standard described in
-                RFC1113 (http://www.faqs.org/rfcs/rfc1113.html).
-
-                This is the coding scheme used by MIME to allow
-                binary data to be transferred by SMTP mail.
-
-                Groups of 3 bytes from a binary stream are coded as
-                groups of 4 bytes in a text stream.
-
-                The input stream is 'padded' with zeros to create
-                an input that is an even multiple of 3.
-
-                A special character ('=') is used to denote padding so
-                that the stream can be decoded back to its exact size.
-
-                Encoded output is formatted in lines which should
-                be a maximum of 72 characters to conform to the
-                specification.  This program defaults to 72 characters,
-                but will allow more or less through the use of a
-                switch.  The program enforces a minimum line size
-                of 4 characters.
-
-                Example encoding:
-
-                The stream 'ABCD' is 32 bits long.  It is mapped as
-                follows:
-
-                ABCD
-
-                 A (65)     B (66)     C (67)     D (68)   (None) (None)
-                01000001   01000010   01000011   01000100
-
-                16 (Q)  20 (U)  9 (J)   3 (D)    17 (R) 0 (A)  NA (=) NA (=)
-                010000  010100  001001  000011   010001 000000 000000 000000
-
-
-                QUJDRA==
-
-                Decoding is the process in reverse.  A 'decode' lookup
-                table has been created to avoid string scans.
-
-DESIGN GOALS:	Specifically:
-		Code is a stand-alone utility to perform base64 
-		encoding/decoding. It should be genuinely useful 
-		when the need arises and it meets a need that is 
-		likely to occur for some users.  
-		Code acts as sample code to show the author's 
-		design and coding style.  
-
-		Generally: 
-		This program is designed to survive:
-		Everything you need is in a single source file.
-		It compiles cleanly using a vanilla ANSI C compiler.
-		It does its job correctly with a minimum of fuss.  
-		The code is not overly clever, not overly simplistic 
-		and not overly verbose. 
-		Access is 'cut and paste' from a web page.  
-		Terms of use are reasonable.  
-
-VALIDATION:     Non-trivial code is never without errors.  This
-                file likely has some problems, since it has only
-                been tested by the author.  It is expected with most
-                source code that there is a period of 'burn-in' when
-                problems are identified and corrected.  That being
-                said, it is possible to have 'reasonably correct'
-                code by following a regime of unit test that covers
-                the most likely cases and regression testing prior
-                to release.  This has been done with this code and
-                it has a good probability of performing as expected.
-
-                Unit Test Cases:
-
-                case 0:empty file:
-                    CASE0.DAT  ->  ->
-                    (Zero length target file created
-                    on both encode and decode.)
-
-                case 1:One input character:
-                    CASE1.DAT A -> QQ== -> A
-
-                case 2:Two input characters:
-                    CASE2.DAT AB -> QUJD -> AB
-
-                case 3:Three input characters:
-                    CASE3.DAT ABC -> QUJD -> ABC
-
-                case 4:Four input characters:
-                    case4.dat ABCD -> QUJDRA== -> ABCD
-
-                case 5:All chars from 0 to ff, linesize set to 50:
-
-                    AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIj
-                    JCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZH
-                    SElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWpr
-                    bG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6P
-                    kJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz
-                    tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX
-                    2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7
-                    /P3+/w==
-
-                case 6:Mime Block from e-mail:
-                    (Data same as test case 5)
-
-                case 7: Large files:
-                    Tested 28 MB file in/out.
-
-                case 8: Random Binary Integrity:
-                    This binary program (b64.exe) was encoded to base64,
-                    back to binary and then executed.
-
-                case 9 Stress:
-                    All files in a working directory encoded/decoded
-                    and compared with file comparison utility to
-                    ensure that multiple runs do not cause problems
-                    such as exhausting file handles, tmp storage, etc.
-
-                -------------
-
-                Syntax, operation and failure:
-                    All options/switches tested.  Performs as
-                    expected.
-
-                case 10:
-                    No Args -- Shows Usage Screen
-                    Return Code 1 (Invalid Syntax)
-                case 11:
-                    One Arg (invalid) -- Shows Usage Screen
-                    Return Code 1 (Invalid Syntax)
-                case 12:
-                    One Arg Help (-?) -- Shows detailed Usage Screen.
-                    Return Code 0 (Success -- help request is valid).
-                case 13:
-                    One Arg Help (-h) -- Shows detailed Usage Screen.
-                    Return Code 0 (Success -- help request is valid).
-                case 14:
-                    One Arg (valid) -- Uses stdin/stdout (filter)
-                    Return Code 0 (Sucess)
-                case 15:
-                    Two Args (invalid file) -- shows system error.
-                    Return Code 2 (File Error)
-                case 16:
-                    Encode non-existent file -- shows system error.
-                    Return Code 2 (File Error)
-                case 17:
-                    Out of disk space -- shows system error.
-                    Return Code 3 (File I/O Error)
-
-                -------------
-
-                Compile/Regression test:
-                    gcc compiled binary under Cygwin
-                    Microsoft Visual Studio under Windows 2000
-                    Microsoft Version 6.0 C under Windows 2000
-
-DEPENDENCIES:   None
-
-LICENCE:        Copyright (c) 2001 Bob Trower, Trantor Standard Systems Inc.
-
-                Permission is hereby granted, free of charge, to any person
-                obtaining a copy of this software and associated
-                documentation files (the "Software"), to deal in the
-                Software without restriction, including without limitation
-                the rights to use, copy, modify, merge, publish, distribute,
-                sublicense, and/or sell copies of the Software, and to
-                permit persons to whom the Software is furnished to do so,
-                subject to the following conditions:
-
-                The above copyright notice and this permission notice shall
-                be included in all copies or substantial portions of the
-                Software.
-
-                THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
-                KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
-                WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-                PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
-                OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-                OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-                OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-                SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
-VERSION HISTORY:
-                Bob Trower 08/04/01 -- Create Version 0.00.00B
-
-\******************************************************************* */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include "bfcp_base64.h"
-
-
-/*
-** Prototyes not in header
-*/
-void encodeblock( unsigned char in[3], unsigned char out[4], int len );
-void encode( FILE *infile, FILE *outfile, int linesize );
-void decodeblock( unsigned char in[4], unsigned char out[3] );
-void decode( FILE *infile, FILE *outfile );
-char *b64_message( int errcode );
-int b64( int opt, char *infilename, char *outfilename, int linesize );
-void showuse( int morehelp );
-
-
-/*
-** Translation Table as described in RFC1113
-*/
-static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
-/*
-** Translation Table to decode (created by author)
-*/
-static const char cd64[]="|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`abcdefghijklmnopq";
-
-/*
-** encodeblock
-**
-** encode 3 8-bit binary bytes as 4 '6-bit' characters
-*/
-void encodeblock( unsigned char in[3], unsigned char out[4], int len )
-{
-    out[0] = cb64[ in[0] >> 2 ];
-    out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
-    out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
-    out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
-}
-
-/*
-** encode
-**
-** base64 encode a stream adding padding and line breaks as per spec.
-*/
-void encode( FILE *infile, FILE *outfile, int linesize )
-{
-    unsigned char in[3], out[4];
-    int i, len, blocksout = 0;
-
-    while( !feof( infile ) ) {
-        len = 0;
-        for( i = 0; i < 3; i++ ) {
-            in[i] = (unsigned char) getc( infile );
-            if( !feof( infile ) ) {
-                len++;
-            }
-            else {
-                in[i] = 0;
-            }
-        }
-        if( len ) {
-            encodeblock( in, out, len );
-            for( i = 0; i < 4; i++ ) {
-                putc( out[i], outfile );
-            }
-            blocksout++;
-        }
-        if( blocksout >= (linesize/4) || feof( infile ) ) {
-            if( blocksout ) {
-                fprintf( outfile, "\r\n" );
-            }
-            blocksout = 0;
-        }
-    }
-}
-
-/*
-** encode_to_base64
-**
-** encode a BFCP message to Base64
-*/
-char *encode_to_base64( bfcp_message *message )
-{
-	if( !message )
-		return NULL;
-	if( message->length < 1 )
-		return NULL;
-
-	char *base64 = calloc( (message->length/2)*3, sizeof(char) );
-	if( !base64 )
-		return NULL;
-	char *temp64 = base64;
-
-	unsigned char in[3], out[4];
-	int i, len, blocksout = 0;
-
-	message->position = 0;
-
-	while( message->position <= message->length ) {
-		len = 0;
-		for( i = 0; i < 3; i++ ) {
-			in[i] = (unsigned char) *(message->buffer + message->position);
-			message->position++;
-			if( message->position <= message->length )
-				len++;
-			else
-				in[i] = 0;
-		}
-		if( len ) {
-			encodeblock( in, out, len );
-			for( i = 0; i < 4; i++ ) {
-				memcpy( temp64, &out[i], 1 );
-				temp64++;
-			}
-			blocksout++;
-		}
-	}
-	char ch='\0';
-	memcpy( temp64, &ch, 1 );
-	return base64;
-}
-
-/*
-** decodeblock
-**
-** decode 4 '6-bit' characters into 3 8-bit binary bytes
-*/
-void decodeblock( unsigned char in[4], unsigned char out[3] )
-{   
-    out[ 0 ] = (unsigned char ) (in[0] << 2 | in[1] >> 4);
-    out[ 1 ] = (unsigned char ) (in[1] << 4 | in[2] >> 2);
-    out[ 2 ] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]);
-}
-
-/*
-** decode
-**
-** decode a base64 encoded stream discarding padding, line breaks and noise
-*/
-void decode( FILE *infile, FILE *outfile )
-{
-    unsigned char in[4], out[3], v;
-    int i, len;
-
-    while( !feof( infile ) ) {
-        for( len = 0, i = 0; i < 4 && !feof( infile ); i++ ) {
-            v = 0;
-            while( !feof( infile ) && v == 0 ) {
-                v = (unsigned char) getc( infile );
-                v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);
-                if( v ) {
-                    v = (unsigned char) ((v == '$') ? 0 : v - 61);
-                }
-            }
-            if( !feof( infile ) ) {
-                len++;
-                if( v ) {
-                    in[ i ] = (unsigned char) (v - 1);
-                }
-            }
-            else {
-                in[i] = 0;
-            }
-        }
-        if( len ) {
-            decodeblock( in, out );
-            for( i = 0; i < len - 1; i++ ) {
-                putc( out[i], outfile );
-            }
-        }
-    }
-}
-
-/*
-** decode_from_base64
-**
-** decode Base64 to a BFCP message
-*/
-bfcp_message *decode_from_base64( char *base64 )
-{
-	if( !base64 )
-		return NULL;
-	int base64_pos = 0, base64_len = strlen( base64 );
-	if( !base64_len )
-		return NULL;
-
-	unsigned char *bfcp_buffer = calloc( (base64_len/4)*3, sizeof(char) );
-	if( !bfcp_buffer )
-		return NULL;
-	unsigned char *temp_buffer = bfcp_buffer;
-
-	unsigned char in[4], out[3], v;
-	int i, len;
-
-	while( base64_pos <= base64_len ) {
-		for( len = 0, i = 0; i < 4 && ( base64_pos <= base64_len ); i++ ) {
-			v = 0;
-			while( ( base64_pos <= base64_len ) && v == 0 ) {
-				v = (unsigned char) *(base64 + base64_pos);
-				base64_pos++;
-				v = (unsigned char) ((v < 43 || v > 122) ? 0 : cd64[ v - 43 ]);
-				if( v )
-					v = (unsigned char) ((v == '$') ? 0 : v - 61);
-			}
-			if( base64_pos <= base64_len ) {
-				len++;
-				if( v )
-					in[ i ] = (unsigned char) (v - 1);
-			} else
-				in[i] = 0;
-		}
-		if( len ) {
-			decodeblock( in, out );
-			for( i = 0; i < len - 1; i++ ) {
-				memcpy( temp_buffer, &out[i], 1 );
-				temp_buffer++;
-			}
-		}
-	}
-	bfcp_message *message = bfcp_new_message( bfcp_buffer, temp_buffer - bfcp_buffer );
-	return message;
-}
-
-/*
-** returnable errors
-**
-** Error codes returned to the operating system.
-**
-*/
-#define B64_SYNTAX_ERROR        1
-#define B64_FILE_ERROR          2
-#define B64_FILE_IO_ERROR       3
-#define B64_ERROR_OUT_CLOSE     4
-#define B64_LINE_SIZE_TO_MIN    5
-
-/*
-** b64_message
-**
-** Gather text messages in one place.
-**
-*/
-char *b64_message( int errcode )
-{
-    #define B64_MAX_MESSAGES 6
-    char *msgs[ B64_MAX_MESSAGES ] = {
-            "b64:000:Invalid Message Code.",
-            "b64:001:Syntax Error -- check help for usage.",
-            "b64:002:File Error Opening/Creating Files.",
-            "b64:003:File I/O Error -- Note: output file not removed.",
-            "b64:004:Error on output file close.",
-            "b64:004:linesize set to minimum."
-    };
-    char *msg = msgs[ 0 ];
-
-    if( errcode > 0 && errcode < B64_MAX_MESSAGES ) {
-        msg = msgs[ errcode ];
-    }
-
-    return( msg );
-}
-
-/*
-** b64
-**
-** 'engine' that opens streams and calls encode/decode
-*/
-
-int b64( int opt, char *infilename, char *outfilename, int linesize )
-{
-    FILE *infile;
-    int retcode = B64_FILE_ERROR;
-
-    if( !infilename ) {
-        infile = stdin;
-    }
-    else {
-        infile = fopen( infilename, "rb" );
-    }
-    if( !infile ) {
-        perror( infilename );
-    }
-    else {
-        FILE *outfile;
-        if( !outfilename ) {
-            outfile = stdout;
-        }
-        else {
-            outfile = fopen( outfilename, "wb" );
-        }
-        if( !outfile ) {
-            perror( outfilename );
-        }
-        else {
-            if( opt == 'e' ) {
-                encode( infile, outfile, linesize );
-            }
-            else {
-                decode( infile, outfile );
-            }
-            if (ferror( infile ) || ferror( outfile )) {
-                retcode = B64_FILE_IO_ERROR;
-            }
-            else {
-                 retcode = 0;
-            }
-            if( outfile != stdout ) {
-                if( fclose( outfile ) != 0 ) {
-                    perror( b64_message( B64_ERROR_OUT_CLOSE ) );
-                    retcode = B64_FILE_IO_ERROR;
-                }
-            }
-        }
-        if( infile != stdin ) {
-            fclose( infile );
-        }
-    }
-
-    return( retcode );
-}
-
-/*
-** showuse
-**
-** display usage information, help, version info
-*/
-void showuse( int morehelp )
-{
-    {
-        printf( "\n" );
-        printf( "  b64      (Base64 Encode/Decode)      Bob Trower 08/03/01 \n" );
-        printf( "           (C) Copr Bob Trower 1986-01.      Version 0.00B \n" );
-        printf( "  Usage:   b64 -option  [ -l num ] [<FileIn> [<FileOut>]]  \n" );
-        printf( "  Purpose: This program is a simple utility that implements\n" );
-        printf( "           Base64 Content-Transfer-Encoding (RFC1113).     \n" );
-    }
-    if( !morehelp ) {
-        printf( "           Use -h option for additional help.              \n" );
-    }
-    else {
-        printf( "  Options: -e  encode to Base64   -h  This help text.      \n" );
-        printf( "           -d  decode from Base64 -?  This help text.      \n" );
-        printf( "  Note:    -l  use to change line size (from 72 characters)\n" );
-        printf( "  Returns: 0 = success.  Non-zero is an error code.        \n" );
-        printf( "  ErrCode: 1 = Bad Syntax, 2 = File Open, 3 = File I/O     \n" );
-        printf( "  Example: b64 -e binfile b64file     <- Encode to b64     \n" );
-        printf( "           b64 -d b64file binfile     <- Decode from b64   \n" );
-        printf( "           b64 -e -l40 infile outfile <- Line Length of 40 \n" );
-        printf( "  Note:    Will act as a filter, but this should only be   \n" );
-        printf( "           used on text files due to translations made by  \n" );
-        printf( "           operating systems.                              \n" );
-        printf( "  Release: 0.00.00, Tue Aug 7   2:00:00 2001, ANSI-SOURCE C\n" );
-    }
-}
-
-#define B64_DEF_LINE_SIZE   72
-#define B64_MIN_LINE_SIZE    4
-
-#define THIS_OPT(ac, av) (ac > 1 ? av[1][0] == '-' ? av[1][1] : 0 : 0)
-
-/*
-** main
-**
-** parse and validate arguments and call b64 engine or help
-
-int main( int argc, char **argv )
-{
-    int opt = 0;
-    int retcode = 0;
-    int linesize = B64_DEF_LINE_SIZE;
-    char *infilename = NULL, *outfilename = NULL;
-
-    while( THIS_OPT( argc, argv ) ) {
-        switch( THIS_OPT(argc, argv) ) {
-            case 'l':
-                    linesize = atoi( &(argv[1][2]) );
-                    if( linesize < B64_MIN_LINE_SIZE ) {
-                        linesize = B64_MIN_LINE_SIZE;
-                        printf( "%s\n", b64_message( B64_LINE_SIZE_TO_MIN ) );
-                    }
-                    break;
-            case '?':
-            case 'h':
-                    opt = 'h';
-                    break;
-            case 'e':
-            case 'd':
-                    opt = THIS_OPT(argc, argv);
-                    break;
-             default:
-                    opt = 0;
-                    break;
-        }
-        argv++;
-        argc--;
-    }
-    switch( opt ) {
-        case 'e':
-        case 'd':
-            infilename = argc > 1 ? argv[1] : NULL;
-            outfilename = argc > 2 ? argv[2] : NULL;
-            retcode = b64( opt, infilename, outfilename, linesize );
-            break;
-        case 0:
-            retcode = B64_SYNTAX_ERROR;
-        case 'h':
-            showuse( opt );
-            break;
-
-    }
-    if( retcode ) {
-        printf( "%s\n", b64_message( retcode ) );
-    }
-
-    return( retcode );
-}
-*/
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "bfcp_base64.h"
+
+/*! Encode a BFCP message to Base64 */
+char *encode_to_base64(bfcp_message *message)
+{
+	if(!message)
+		return NULL;
+	if(message->length < 1)
+		return NULL;
+
+	int base64_len = message->length*2;	/* Reserve enough space for the output buffer */
+	char *base64 = calloc(base64_len, sizeof(char));
+	if(!base64)
+		return NULL;
+
+	int err = ast_base64encode(base64, (const unsigned char *)message->buffer, message->length, base64_len);
+	if(err < 0) {
+		free(base64);
+		return NULL;
+	}
+
+	return base64;
+}
+
+/*! Decode a Base64 string to a BFCP message */
+bfcp_message *decode_from_base64(const char *base64)
+{
+	if(!base64)
+		return NULL;
+	int base64_len = strlen(base64);
+	if(!base64_len)
+		return NULL;
+	unsigned short int bfcp_len = (base64_len/4)*3;
+	if(bfcp_len%4)		/* Reserve enough space for the output buffer (including padding) */
+		bfcp_len += (4 - (bfcp_len%4));
+
+	unsigned char *bfcp_buffer = calloc(bfcp_len, sizeof(unsigned char));
+	if(!bfcp_buffer)
+		return NULL;
+
+	int err = ast_base64decode(bfcp_buffer, base64, bfcp_len);
+	if(err < 0) {
+		free(bfcp_buffer);
+		return NULL;
+	}
+	err -= err%4;
+
+	bfcp_message *message = bfcp_new_message(bfcp_buffer, err);
+	return message;
+}
diff -urN xcon_bfcp/apps/xcon_bfcp/bfcp_base64.h xcon_bfcp_patched/apps/xcon_bfcp/bfcp_base64.h
--- xcon_bfcp/apps/xcon_bfcp/bfcp_base64.h	2007-03-07 11:43:49.000000000 +0100
+++ xcon_bfcp_patched/apps/xcon_bfcp/bfcp_base64.h	2007-04-23 15:50:28.000000000 +0200
@@ -1,15 +1,15 @@
 #ifndef _BFCP_BASE_64_H
 #define _BFCP_BASE_64_H
 
-#include "bfcp_messages.h"
+#include <bfcp_messages.h>
+#include "asterisk/utils.h"
 
 /*
- 	Slightly modified version of the http://base64.sourceforge.net/
-	Base64 Content-Transfer-Encoding utility to enable library-style
-	encoding/decoding to/from Base64 of binary BFCP Messages
+ 	Wrappers to the Asterisk Base64 encoding/decoding functionality
+	for encoding/decoding to/from Base64 of binary BFCP Messages
 */
 
-char *encode_to_base64( bfcp_message *message );
-bfcp_message *decode_from_base64( char *base64 );
+char *encode_to_base64(bfcp_message *message);
+bfcp_message *decode_from_base64(const char *base64);
 
 #endif
diff -urN xcon_bfcp/apps/xcon_bfcp/bfcp_gw.c xcon_bfcp_patched/apps/xcon_bfcp/bfcp_gw.c
--- xcon_bfcp/apps/xcon_bfcp/bfcp_gw.c	2007-03-07 11:43:49.000000000 +0100
+++ xcon_bfcp_patched/apps/xcon_bfcp/bfcp_gw.c	2007-04-23 15:50:28.000000000 +0200
@@ -1,5 +1,6 @@
 #include "asterisk.h"
 #include "asterisk/linkedlists.h"
+#include "asterisk/utils.h"
 
 #include "bfcp_gw.h"
 #include "bfcp_base64.h"
@@ -162,6 +163,14 @@
 int bfcp_gw_send_bfcp_error(int fd, bfcp_entity *entity, int error_code, char *text);
 
 
+/*! Variable that tells us if we have to be DCON-compliant or not */
+int is_dcon_enabled;
+/*! Counter to assign channel identifiers for new connections */
+unsigned long int bfcp_gw_channel;
+/*! User counter to assign new BFCP User IDs */
+unsigned short int bfcp_user_id;
+
+
 /*! TLS-related stuff: server-side and client side will have different contexts */
 SSL_CTX *server_context;
 SSL_CTX *client_context;
@@ -190,9 +199,9 @@
 void bfcp_gw_initialize(int dcon_enabled, int(*notify_about_dispatcher)(int update, ...))
 {
 	is_dcon_enabled = dcon_enabled;	/* Enable/disable DCON functionality */
+	bfcp_user_id = 1;		/* Start the UserID counter */
 
 	if(is_dcon_enabled) {
-		bfcp_user_id = 1;		/* Start the UserID counter */
 		bfcp_gw_channel = 1;		/* Start the channel counter */
 		bfcp_gw_dispatcher.callback_func = notify_about_dispatcher;
 	}
@@ -222,7 +231,7 @@
 /* Transaction constructor */
 bfcp_gw_transaction *bfcp_gw_new_transaction(bfcp_message *message, int fd)
 {
-	bfcp_gw_transaction *transaction = calloc(1, sizeof(bfcp_gw_transaction));
+	bfcp_gw_transaction *transaction = ast_calloc(1, sizeof(bfcp_gw_transaction));
 	if(!transaction)
 		return NULL;
 
@@ -346,14 +355,19 @@
 {
 	int res = bfcp_add_floor_server(bfcp_server_list, conferenceID, floorID, chairID, granted_floors_limit);
 	if(res < 0) {	/* Before returning an error, check if the floor already exists */
-		if((bfcp_gw_conferences_get_floor(AUDIO_FLOOR, conferenceID) == floorID) ||
-			(bfcp_gw_conferences_get_floor(VIDEO_FLOOR, conferenceID) == floorID))
-			return bfcp_gw_conferences_set_floor(floor_type, conferenceID, floorID);
-		else
-			return res;
+		if(is_dcon_enabled) {
+			if((bfcp_gw_conferences_get_floor(AUDIO_FLOOR, conferenceID) == floorID) ||
+				(bfcp_gw_conferences_get_floor(VIDEO_FLOOR, conferenceID) == floorID))
+				return bfcp_gw_conferences_set_floor(floor_type, conferenceID, floorID);
+			else
+				return res;
+		}
 	}
 
-	return bfcp_gw_conferences_set_floor(floor_type, conferenceID, floorID);
+	if(is_dcon_enabled)
+		return bfcp_gw_conferences_set_floor(floor_type, conferenceID, floorID);
+
+	return res;
 }
 
 int bfcp_gw_delete_floor_server(unsigned long int conferenceID, unsigned short int floorID)
@@ -451,7 +465,7 @@
 		AST_LIST_UNLOCK(&gw_fd_session_pairs);
 		return 0;
 	}
-	pair = calloc(1, sizeof(bfcp_gw_fd_session_pair));
+	pair = ast_calloc(1, sizeof(bfcp_gw_fd_session_pair));
 	if(!pair) {
 		AST_LIST_UNLOCK(&gw_fd_session_pairs);
 		return -1;
@@ -539,7 +553,7 @@
 		AST_LIST_UNLOCK(&gw_conferences);
 		return 0;
 	}
-	cnf = calloc(1, sizeof(bfcp_gw_conferences));
+	cnf = ast_calloc(1, sizeof(bfcp_gw_conferences));
 	if(!cnf) {
 		AST_LIST_UNLOCK(&gw_conferences);
 		return -1;
@@ -690,7 +704,7 @@
 		AST_LIST_UNLOCK(&gw_routing_table);
 		return 0;	/* Error, channel already exists */
 	}
-	route = calloc(1, sizeof(bfcp_gw_routing_table));
+	route = ast_calloc(1, sizeof(bfcp_gw_routing_table));
 	if(!route) {	/* Could not create new channel */
 		AST_LIST_UNLOCK(&gw_routing_table);
 		return 0;	/* 0 is a failure */
@@ -1265,8 +1279,8 @@
 		}
 	} else {
 		/* Initialize the GW FCS stuff */
-		bfcp_gw_fcs.address = calloc(1, sizeof(struct sockaddr_in));
-		bfcp_gw_fcs.addr_gw = calloc(1, sizeof(struct sockaddr_in));
+		bfcp_gw_fcs.address = ast_calloc(1, sizeof(struct sockaddr_in));
+		bfcp_gw_fcs.addr_gw = ast_calloc(1, sizeof(struct sockaddr_in));
 	}
 
 	/* Only create the new GW FCS if we need to */
@@ -1506,7 +1520,7 @@
 	int err, fd, client = 0;
 	fd_set tempfds;
 	struct sockaddr_in client_address;
-	unsigned int addrlen = 0;
+	unsigned int addrlen = sizeof(struct sockaddr);
 	if(listen(bfcp_gw_fcs.fd,5) < 0)
 		pthread_exit(0);
 	FD_ZERO(&bfcp_gw_fcs.readfds);
@@ -1650,7 +1664,7 @@
 		}
 	} else {
 		/* Initialize the Dispatcher stuff */
-		bfcp_gw_dispatcher.address = calloc(1, sizeof(struct sockaddr_in));
+		bfcp_gw_dispatcher.address = ast_calloc(1, sizeof(struct sockaddr_in));
 	}
 
 	/* Only create the new Dispatcher if we need to */
@@ -1685,7 +1699,7 @@
 	int fd = *process_fd;
 	char buffer[4096];
 	memset(buffer, 0, 4096);
-	char *message = calloc(4096, sizeof(char));
+	char *message = ast_calloc(4096, sizeof(char));
 	int err = 0, position = 0, message_to_read = 0;
 	char *end = NULL;
 	while(1) {
@@ -1709,7 +1723,7 @@
 		if(bfcp_gw_dispatcher.authenticated == 0) {
 			char *line = NULL;
 			char value[1024];
-			if(!strcasecmp(command,"Message: Authenticate")) {
+			if(!strcasecmp(command, "Message: Authenticate")) {
 				char admin[15], password[15];
 				while(1) {	/* We parse the contents of the message */
 					message++;		/* Skip the \r\n after the field read before */
@@ -1964,11 +1978,11 @@
 					else if(sscanf(line,"TempUserID: %s", value))
 						tempUserID = atoi(value);
 					else if(sscanf(line,"URI: %s", value)) {
-						uri = calloc(strlen(line) - 4, sizeof(char));
+						uri = ast_calloc(strlen(line) - 4, sizeof(char));
 						if(uri)
 							strncpy(uri, line + 5, strlen(line) - 5);
 					} else if(sscanf(line,"Display: %s", value)) {
-						display = calloc(strlen(line) - 8, sizeof(char));
+						display = ast_calloc(strlen(line) - 8, sizeof(char));
 						if(display)
 							strncpy(display, line + 9, strlen(line) - 9);
 					}
@@ -2161,6 +2175,47 @@
 				} else {	/* A new remote focus is online, keep track of its conferences prefix */
 					bfcp_gw_dispatcher.callback_func(GW_FOCUS_REMOVED, prefix);
 				}
+			} else if(!strcasecmp(command, "Message: MSRP")) {
+				memset(buffer, 0, 4096);
+				unsigned long int conferenceID = 0;
+				int is_send = -1;
+				while(1) {	/* We parse the contents of the message */
+					message++;		/* Skip the \r\n after the field read before */
+					if(message >= end)	/* and stop if we reached the end of the message */
+						break;
+					line = strsep(&message, "\r\n");
+					if(!line)
+						break;
+					if(sscanf(line,"ConferenceID: %s", value))
+						conferenceID = atoi(value);
+					else if(sscanf(line,"SEND: %s", value)) {
+						strcpy(buffer, value);
+						is_send = 1;
+					} else if(sscanf(line,"REPORT: %s", value)) {
+						strcpy(buffer, value);
+						is_send = 0;
+					}
+				}
+				if(!conferenceID) {
+					sprintf(tmp, "Invalid Conference %lu in 'MSRP' message", conferenceID);
+					bfcp_gw_dispatcher_error(tmp);
+				} else if(is_send < 0) {
+					bfcp_gw_dispatcher_error("Invalid body in 'MSRP' message");
+				} else {
+					/* We decode the message and route it */
+					int base64_len = strlen(buffer);
+					unsigned short int msrp_len = (base64_len/4)*3;
+					if(msrp_len%4)		/* Reserve enough space for the output buffer (including padding) */
+						msrp_len += (4 - (msrp_len%4));
+					unsigned char *msrp_buffer = calloc(msrp_len+1, sizeof(char));
+					int err = ast_base64decode(msrp_buffer, buffer, msrp_len);
+					if(err < 0) {
+						free(msrp_buffer);
+						return NULL;
+					}
+					err -= err%4;
+					bfcp_gw_dispatcher.callback_func(GW_MSRP_MESSAGE, conferenceID, is_send, msrp_buffer, err);
+				}
 			} else if(!strcasecmp(command, "Message: Error")) {
 				while(1) {	/* We parse the contents of the message */
 					message++;		/* Skip the \r\n after the field read before */
@@ -2194,7 +2249,7 @@
 	int err, fd, client = 0;
 	fd_set tempfds;
 	struct sockaddr_in client_address;
-	unsigned int addrlen = 0;
+	unsigned int addrlen = sizeof(struct sockaddr);
 	if(listen(bfcp_gw_dispatcher.fd, 1) < 0)
 		pthread_exit(0);
 	FD_ZERO(&bfcp_gw_dispatcher.readfds);
@@ -2322,7 +2377,7 @@
 		return -1;
 
 	int linelen = strlen(attribute) + strlen(value) + 5;	/* ": " + "\r\n\0" */
-	char *line = calloc(linelen, sizeof(char));
+	char *line = ast_calloc(linelen, sizeof(char));
 	if(!line)
 		return -1;
 	sprintf(line, "%s: %s\r\n", attribute, value);
@@ -2659,6 +2714,36 @@
 	return res;
 }
 
+int bfcp_gw_dispatcher_forward_msrp_msg(unsigned long int conferenceID, int is_send, char *text)
+{
+	if(!conferenceID || !text)
+		return -1;
+
+	char buffer[2048], tmp[50];
+	buffer[0] = '\0';
+	int res = 0;
+	res = bfcp_gw_dispatcher_add_msgline(buffer, "Message", "MSRP");
+
+	sprintf(tmp, "%lu", conferenceID);
+	res |= bfcp_gw_dispatcher_add_msgline(buffer, "ConferenceID", tmp);
+
+	int base64_len = strlen(text)*2;	/* Reserve enough space for the output buffer */
+	char *base64_message = calloc(base64_len+1, sizeof(char));
+	if(!base64_message)
+		return -1;
+	int err = ast_base64encode(base64_message, (const unsigned char *)text, strlen(text), base64_len);
+	if(err < 0) {
+		free(base64_message);
+		return -1;
+	}
+
+	res |= bfcp_gw_dispatcher_add_msgline(buffer, is_send ? "SEND" : "REPORT", base64_message);
+
+	res |= bfcp_gw_dispatcher_send_message(buffer, 1);
+
+	return res;
+}
+
 
 int bfcp_gw_dispatcher_error(char *text)
 {
diff -urN xcon_bfcp/apps/xcon_bfcp/bfcp_gw.h xcon_bfcp_patched/apps/xcon_bfcp/bfcp_gw.h
--- xcon_bfcp/apps/xcon_bfcp/bfcp_gw.h	2007-03-07 11:43:49.000000000 +0100
+++ xcon_bfcp_patched/apps/xcon_bfcp/bfcp_gw.h	2007-04-23 15:50:28.000000000 +0200
@@ -3,9 +3,9 @@
 
 
 /*! The library managing the (centralized) Floor Control Server behaviour */
-#include "bfcp_server.h"
+#include <bfcp_server.h>
 /*! Useful user-friendly strings for BFCP definitions */
-#include "bfcp_strings.h"
+#include <bfcp_strings.h>
 /*! Definition of the structure to pass to chan_sip for BFCP+SDP reinvites */
 #include "bfcp_sdp.h"
 /*! The library managing the XCON Scheduler protocol behaviour */
@@ -43,6 +43,7 @@
 #define GW_CASCADED_CONFERENCE_GONE	11
 #define GW_FOCUS_ADDED			12
 #define GW_FOCUS_REMOVED		13
+#define GW_MSRP_MESSAGE			14
 #define GW_VERBOSE			20
 
 
@@ -60,14 +61,6 @@
 int xcon_gw_scheduler_setup_admin(char *admin, char *password);
 
 
-/*! Variable that tells us if we have to be DCON-compliant or not */
-int is_dcon_enabled;
-/*! Counter to assign channel identifiers for new connections */
-unsigned long int bfcp_gw_channel;
-/*! User counter to assign new BFCP User IDs */
-unsigned short int bfcp_user_id;
-
-
 /*! Wrappers around the actual BFCP Server, to which we will be a gateway for app_meetme:
 	1. dcon_enabled while initializing instructs wether the gateway shall just forward the
 	   method calls, or act as a gateway between the FCS, the users and the DCON Dispatcher;
@@ -114,6 +107,7 @@
 int bfcp_gw_dispatcher_remove_all_users(void);
 int bfcp_gw_dispatcher_forward_bfcp_msg(unsigned long int channel, bfcp_message *message);
 int bfcp_gw_dispatcher_forward_scheduler_msg(int fd, char *message);
+int bfcp_gw_dispatcher_forward_msrp_msg(unsigned long int conferenceID, int is_send, char *text);
 int bfcp_gw_dispatcher_error(char *text);
 
 
diff -urN xcon_bfcp/apps/xcon_bfcp/bfcp_sdp.c xcon_bfcp_patched/apps/xcon_bfcp/bfcp_sdp.c
--- xcon_bfcp/apps/xcon_bfcp/bfcp_sdp.c	2007-03-07 11:43:49.000000000 +0100
+++ xcon_bfcp_patched/apps/xcon_bfcp/bfcp_sdp.c	2007-04-23 15:50:29.000000000 +0200
@@ -1,4 +1,4 @@
-/* draft-ietf-mmusic-sdp-bfcp-03 */
+/* RFC 4583 */
 
 #include <string.h>
 #include <stdlib.h>
@@ -6,7 +6,7 @@
 #include "bfcp_sdp.h"
 
 /* Methods */
-bfcp_sdp *bfcp_create_sdp(unsigned short int bfcp_port, int bfcp_transport, unsigned long int conferenceID, unsigned short int userID, unsigned short int audioFloorID, unsigned short int videoFloorID)
+bfcp_sdp *bfcp_create_sdp(unsigned short int bfcp_port, int bfcp_transport, unsigned long int conferenceID, unsigned short int userID, unsigned short int audioFloorID, unsigned short int videoFloorID, void (*msrp_callback)(unsigned long int conferenceID, struct ast_channel *chan, char *path), unsigned short int msrp_port, char *msrp_path)
 {
 	bfcp_sdp *sdp_bfcp = calloc(1, sizeof(bfcp_sdp));
 	if(!sdp_bfcp)
@@ -18,10 +18,20 @@
 	sdp_bfcp->audioFloorID = audioFloorID;
 	sdp_bfcp->videoFloorID = videoFloorID;
 	sdp_bfcp->status = BFCP_WAITING;
+
+	/* MSRP */
+	sdp_bfcp->msrp_callback = msrp_callback;
+	sdp_bfcp->msrp_port = msrp_port;
+	sdp_bfcp->msrp_path = calloc(strlen(msrp_path)+1, sizeof(char));
+	strcpy(sdp_bfcp->msrp_path, msrp_path);
+
 	return sdp_bfcp;
 }
 
 void bfcp_free_sdp(bfcp_sdp *sdp_bfcp) {
-	if(sdp_bfcp)
+	if(sdp_bfcp) {
+		if(sdp_bfcp->msrp_path)
+			free(sdp_bfcp->msrp_path);
 		free(sdp_bfcp);
+	}
 }
diff -urN xcon_bfcp/apps/xcon_bfcp/bfcp_sdp.h xcon_bfcp_patched/apps/xcon_bfcp/bfcp_sdp.h
--- xcon_bfcp/apps/xcon_bfcp/bfcp_sdp.h	2007-03-07 11:43:49.000000000 +0100
+++ xcon_bfcp_patched/apps/xcon_bfcp/bfcp_sdp.h	2007-04-23 15:50:29.000000000 +0200
@@ -1,8 +1,13 @@
-/* draft-ietf-mmusic-sdp-bfcp-03 */
+/* RFC 4583 */
 
 #ifndef _BFCP_SDP_H
 #define _BFCP_SDP_H
 
+#include "asterisk.h"
+
+#include "asterisk/channel.h"
+
+
 #define BFCP_WAITING	0
 #define BFCP_SENDING	1
 #define BFCP_SENT	2
@@ -25,10 +30,14 @@
 	unsigned short int audioFloorID;	/* The Audio Floor Identifier */
 	unsigned short int videoFloorID;	/* The Video Floor Identifier */
 	int status;				/* Status of the SDP+BFCP reinvite transmission */
+	/* We use this structure for MSRP negotiations as well */
+	void (*msrp_callback)(unsigned long int conferenceID, struct ast_channel *chan, char *path);
+	unsigned short int msrp_port;		/* The MSRP conference room port */
+	char *msrp_path;			/* The MSRP conference room path */
 } bfcp_sdp;
 
 /* Methods */
-bfcp_sdp *bfcp_create_sdp(unsigned short int bfcp_port, int bfcp_transport, unsigned long int conferenceID, unsigned short int userID, unsigned short int audioFloorID, unsigned short int videoFloorID);
+bfcp_sdp *bfcp_create_sdp(unsigned short int bfcp_port, int bfcp_transport, unsigned long int conferenceID, unsigned short int userID, unsigned short int audioFloorID, unsigned short int videoFloorID, void (*msrp_callback)(unsigned long int conferenceID, struct ast_channel *chan, char *path), unsigned short int msrp_port, char *msrp_path);
 void bfcp_free_sdp(bfcp_sdp *sdp_bfcp);
 
 #endif
diff -urN xcon_bfcp/apps/xcon_bfcp/xcon_scheduler.c xcon_bfcp_patched/apps/xcon_bfcp/xcon_scheduler.c
--- xcon_bfcp/apps/xcon_bfcp/xcon_scheduler.c	2007-03-07 11:43:49.000000000 +0100
+++ xcon_bfcp_patched/apps/xcon_bfcp/xcon_scheduler.c	2007-04-23 15:50:29.000000000 +0200
@@ -1,5 +1,22 @@
+#include "asterisk.h"
+#include "asterisk/utils.h"
+
 #include "xcon_scheduler.h"
 
+/*! XCON Scheduler server */
+struct xcon_scheduler {
+	int fd;				/*! The file descriptor */
+	unsigned short int port;	/*! The listening port */
+	struct sockaddr_in *address;	/*! The listening address */
+	int fdmax;			/*! The highest file descriptor (needed for select) */
+	fd_set readfds, writefds;	/*! The file descriptor sets for select */
+	pthread_t thread;		/*! The XconScheduler listening thread */
+	char admin[15];			/*! The manager's username... (must be a valid user from manager.conf)  */
+	char password[15];		/*! 	... and password 						*/
+	/*! This callback function handles the notifications regarding Scheduler messages */
+	int(*callback)(int message, ...);
+} xcon_scheduler;
+
 
 /*! Listening/Processing methods */
 int xcon_scheduler_listen(unsigned short int port);
@@ -33,7 +50,7 @@
 	int fd = *process_fd;
 	char buffer[4096];
 	memset(buffer,0,4096);
-	char *message = calloc(2048, sizeof(char));
+	char *message = ast_calloc(2048, sizeof(char));
 	int err = 0, position = 0, message_to_read = 0;
 	char *end = NULL;
 	while(1) {
@@ -55,10 +72,10 @@
 		char *command = strsep(&message, "\r\n");
 		xcon_scheduler.callback(XCON_SCHEDULER_CONSOLE, command);
 		char *line = NULL, *variable = NULL, *value = NULL, *argument = NULL, *subject = NULL;
-		variable = calloc(100, sizeof(char));
-		value = calloc(100, sizeof(char));
-		argument = calloc(100, sizeof(char));
-		if(!strcasecmp(command,"XconScheduler: Register")) {
+		variable = ast_calloc(100, sizeof(char));
+		value = ast_calloc(100, sizeof(char));
+		argument = ast_calloc(100, sizeof(char));
+		if(!strcasecmp(command, "XconScheduler: Register")) {
 		/* We Schedulate in a more complex way than in the XconScheduler dialplan application */
 		/* We use the settings in the message instead of some default ones */
 			int private = 0, audio = 0, video = 0, audiovideo = 0;
@@ -74,14 +91,14 @@
 					subject = strsep(&line, ": ");
 					subject = line + 1;
 				} else if(sscanf(line,"Access: %s", value)) {
-					if(!strcasecmp(value,"Private"))
+					if(!strcasecmp(value, "Private"))
 						private++;
 				} else if(sscanf(line,"MaxFloors: %s", value)) {
 					maxfloors = atoi(value);
 				} else if(sscanf(line,"MaxRequests: %s", value)) {
 					maxrequests = atoi(value);
 				} else if(sscanf(line,"AutoPolicy: %s", value)) {
-					if(!strcasecmp(value,"deny"))
+					if(!strcasecmp(value, "deny"))
 						autodeny++;
 				} else if(sscanf(line,"Audio: %s", value)) {
 					if(sscanf(value, "Enabled,%s", argument)) {
@@ -106,7 +123,7 @@
 			} else {
 				xcon_scheduler.callback(XCON_SCHEDULER_REGISTER, fd, buffer, subject, private, maxfloors, maxrequests, autodeny, audio, audio_users, video, video_users, audiovideo, audiovideo_users);
 			}
-		} else if(!strcasecmp(command,"XconScheduler: QueryConferences")) {
+		} else if(!strcasecmp(command, "XconScheduler: QueryConferences")) {
 		/* Send all the registered and/or active conferences to the requester */
 			int active = 0, registered = 0;
 			while(1) {	/* We parse the contents of the request */
@@ -117,17 +134,17 @@
 				if(!line)
 					break;
 				if(sscanf(line,"Status: %s", value)) {
-					if(!strcasecmp(value,"All")) {
+					if(!strcasecmp(value, "All")) {
 						registered++;
 						active++;
-					} else if(!strcasecmp(value,"Registered"))
+					} else if(!strcasecmp(value, "Registered"))
 						registered++;
-					else if(!strcasecmp(value,"Active"))
+					else if(!strcasecmp(value, "Active"))
 						active++;
 				}
 			}
 			xcon_scheduler.callback(XCON_SCHEDULER_QUERYCONFERENCES, fd, buffer, registered, active);
-		} else if(!strcasecmp(command,"XconScheduler: Unregister")) {
+		} else if(!strcasecmp(command, "XconScheduler: Unregister")) {
 			unsigned long int conferenceID = 0;
 			unsigned short int password = 0;
 			int fatal = 0;
@@ -152,7 +169,7 @@
 			} else {
 				xcon_scheduler.callback(XCON_SCHEDULER_UNREGISTER, fd, buffer, conferenceID, password);
 			}
-		} else if(!strcasecmp(command,"XconScheduler: SetChair")) {
+		} else if(!strcasecmp(command, "XconScheduler: SetChair")) {
 			unsigned long int conferenceID = 0;
 			unsigned short int password = 0, FloorID = 0, ChairID = 0;
 			while(1) {	/* We parse the contents of the request */
@@ -177,9 +194,9 @@
 			} else {
 				xcon_scheduler.callback(XCON_SCHEDULER_SETCHAIR, fd, buffer, conferenceID, password, FloorID, ChairID);
 			}
-		} else if(!strcasecmp(command,"XconScheduler: QueryBlueprints")) {
+		} else if(!strcasecmp(command, "XconScheduler: QueryBlueprints")) {
 			xcon_scheduler.callback(XCON_SCHEDULER_QUERYBLUEPRINTS, fd, buffer);
-		} else if(!strcasecmp(command,"XconScheduler: QueryTemplate")) {
+		} else if(!strcasecmp(command, "XconScheduler: QueryTemplate")) {
 			char *template = NULL;
 			while(1) {	/* We parse the contents of the request */
 				message++;		/* Skip the \r\n after the field read before */
@@ -194,7 +211,7 @@
 			if(!template)
 				template = "(no name)";
 			xcon_scheduler.callback(XCON_SCHEDULER_QUERYTEMPLATE, fd, buffer, template);
-		} else if(!strcasecmp(command,"XconScheduler: QueryUsers")) {
+		} else if(!strcasecmp(command, "XconScheduler: QueryUsers")) {
 			unsigned long int conferenceID = 0;
 			unsigned short int pin = 0;
 			while(1) {	/* We parse the contents of the request */
@@ -215,7 +232,7 @@
 			} else {
 				xcon_scheduler.callback(XCON_SCHEDULER_QUERYUSERS, fd, buffer, conferenceID, pin);
 			}
-		} else if(!strcasecmp(command,"XconScheduler: QueryUpdate")) {
+		} else if(!strcasecmp(command, "XconScheduler: QueryUpdate")) {
 			char admin[15], password[15];
 			while(1) {	/* We parse the contents of the request */
 				message++;		/* Skip the \r\n after the field read before */
@@ -254,22 +271,22 @@
 	int err, fd, client = 0;
 	struct sockaddr_in client_address;
 	fd_set tempfds;
-	unsigned int addrlen=0;
+	unsigned int addrlen = sizeof(struct sockaddr);
 	if(listen(xcon_scheduler.fd, 5) < 0) {
 		xcon_scheduler.callback(XCON_SCHEDULER_CONSOLE, "XconScheduler Socket Listen failed: closing the XconScheduler Thread...");
 		return NULL;
 	}
-	FD_ZERO(xcon_scheduler.readfds);
+	FD_ZERO(&xcon_scheduler.readfds);
 	FD_ZERO(&tempfds);
-	FD_SET(xcon_scheduler.fd, xcon_scheduler.readfds);
+	FD_SET(xcon_scheduler.fd, &xcon_scheduler.readfds);
 	xcon_scheduler.fdmax = xcon_scheduler.fd;
 
 	while(1) {
-		memcpy(&tempfds, xcon_scheduler.readfds, sizeof(fd_set));
+		tempfds = xcon_scheduler.readfds;
 		err=select(xcon_scheduler.fdmax+1, &tempfds, NULL, NULL, (struct timeval *)NULL);
-		if(err==0)
+		if(err == 0)
 			continue;	/* There's nothing to read yet, keep monitoring */
-		else if(err<0) {
+		else if(err < 0) {
 			xcon_scheduler.callback(XCON_SCHEDULER_CONSOLE, "Error in Select: closing the XconScheduler Thread...");
 			break;
 		}
@@ -279,17 +296,17 @@
 				if(FD_ISSET(fd, &tempfds)) {
 					if(fd == xcon_scheduler.fd) {	/* We have a new connection from a client */
 						client = accept(fd, (struct sockaddr *)(&client_address), &addrlen);
-						if(client <0) {
+						if(client < 0) {
 							xcon_scheduler.callback(XCON_SCHEDULER_CONSOLE, "Error accepting XconScheduler Connection from a client...\n");
 							continue;
 						}
-						FD_SET(client, xcon_scheduler.readfds);
+						FD_SET(client, &xcon_scheduler.readfds);
 						if(client > xcon_scheduler.fdmax)
 							xcon_scheduler.fdmax=client;
 					} else {	/* There's data to read from a client */
 						int process_fd = fd;
 						/* We remove since now this socket from the select list */
-						FD_CLR(fd, xcon_scheduler.readfds);
+						FD_CLR(fd, &xcon_scheduler.readfds);
 						/* We call a separate thread to process the request */
 						pthread_attr_t attr;
 						pthread_t processing_thread;
@@ -318,15 +335,13 @@
 		if(xcon_scheduler.port != port) {
 			xcon_scheduler.callback(XCON_SCHEDULER_CONSOLE, "Reloading module, closing existing XCON Scheduler...");
 			need_reload++;
-			shutdown(xcon_scheduler.fd,SHUT_RDWR);
+			shutdown(xcon_scheduler.fd, SHUT_RDWR);
 			close(xcon_scheduler.fd);
 		} else
 			xcon_scheduler.callback(XCON_SCHEDULER_CONSOLE, "Reloading module, mantaining existing XCON Scheduler...");
 	} else {
 		/* Initialize the Scheduler stuff */
-		xcon_scheduler.address = calloc(sizeof(struct sockaddr_in),sizeof(char));
-		xcon_scheduler.readfds = calloc(sizeof(fd_set),sizeof(char));
-		xcon_scheduler.writefds = calloc(sizeof(fd_set),sizeof(char));
+		xcon_scheduler.address = ast_calloc(1, sizeof(struct sockaddr_in));
 	}
 
 	/* Only create the new scheduler if we need to */
@@ -348,7 +363,7 @@
 		xcon_scheduler.callback(XCON_SCHEDULER_CONSOLE, "Starting the XconScheduler listening thread...");
 		sprintf(tmp, "Binding XconScheduler at port %d...", xcon_scheduler.port);
 		xcon_scheduler.callback(XCON_SCHEDULER_CONSOLE, tmp);
-		if(bind(xcon_scheduler.fd,(struct sockaddr *)(xcon_scheduler.address),sizeof(struct sockaddr)) <0) {
+		if(bind(xcon_scheduler.fd, (struct sockaddr *)(xcon_scheduler.address), sizeof(struct sockaddr)) < 0) {
 			sprintf(tmp, "\tBinding XconScheduler at port %d failed...", xcon_scheduler.port);
 			xcon_scheduler.callback(XCON_SCHEDULER_CONSOLE, tmp);
 			return-1;
@@ -407,7 +422,7 @@
 		return -1;
 
 	int linelen = strlen(attribute) + strlen(value) + 5;	/* ": " + "\r\n\0" */
-	char *line = calloc(linelen, sizeof(char));
+	char *line = ast_calloc(linelen, sizeof(char));
 	if(!line)
 		return -1;
 	sprintf(line, "%s: %s\r\n", attribute, value);
diff -urN xcon_bfcp/apps/xcon_bfcp/xcon_scheduler.h xcon_bfcp_patched/apps/xcon_bfcp/xcon_scheduler.h
--- xcon_bfcp/apps/xcon_bfcp/xcon_scheduler.h	2007-03-07 11:43:49.000000000 +0100
+++ xcon_bfcp_patched/apps/xcon_bfcp/xcon_scheduler.h	2007-04-23 15:50:28.000000000 +0200
@@ -51,19 +51,6 @@
 
 
 /*! XCON Scheduler server management */
-struct xcon_scheduler {
-	int fd;				/*! The file descriptor */
-	unsigned short int port;	/*! The listening port */
-	struct sockaddr_in *address;	/*! The listening address */
-	int fdmax;			/*! The highest file descriptor (needed for select) */
-	fd_set *readfds, *writefds;	/*! The file descriptor sets for select */
-	pthread_t thread;		/*! The XconScheduler listening thread */
-	char admin[15];			/*! The manager's username... (must be a valid user from manager.conf)  */
-	char password[15];		/*! 	... and password 						*/
-	/*! This callback function handles the notifications regarding Scheduler messages */
-	int(*callback)(int message, ...);
-} xcon_scheduler;
-
 int xcon_scheduler_initialize(unsigned short int port, int(*notify_about_scheduler)(int message, ...));
 int xcon_scheduler_setup_admin(char *admin, char *password);
 
diff -urN xcon_bfcp/build_tools/menuselect-deps.in xcon_bfcp_patched/build_tools/menuselect-deps.in
--- xcon_bfcp/build_tools/menuselect-deps.in	2007-03-07 11:43:43.000000000 +0100
+++ xcon_bfcp_patched/build_tools/menuselect-deps.in	2007-04-23 15:50:28.000000000 +0200
@@ -1,4 +1,6 @@
 ASOUND=@PBX_ALSA@
+BFCP=@PBX_BFCP@
+MSRP=@PBX_MSRP@
 CURL=@PBX_CURL@
 FREETDS=@PBX_FREETDS@
 GSM=@PBX_GSM@
diff -urN xcon_bfcp/channels/bfcp_sdp/bfcp_sdp.c xcon_bfcp_patched/channels/bfcp_sdp/bfcp_sdp.c
--- xcon_bfcp/channels/bfcp_sdp/bfcp_sdp.c	2007-03-07 11:43:45.000000000 +0100
+++ xcon_bfcp_patched/channels/bfcp_sdp/bfcp_sdp.c	2007-04-23 15:50:29.000000000 +0200
@@ -1,4 +1,4 @@
-/* draft-ietf-mmusic-sdp-bfcp-03 */
+/* RFC 4583 */
 
 #include <string.h>
 #include <stdlib.h>
@@ -6,7 +6,7 @@
 #include "bfcp_sdp.h"
 
 /* Methods */
-bfcp_sdp *bfcp_create_sdp(unsigned short int bfcp_port, int bfcp_transport, unsigned long int conferenceID, unsigned short int userID, unsigned short int audioFloorID, unsigned short int videoFloorID)
+bfcp_sdp *bfcp_create_sdp(unsigned short int bfcp_port, int bfcp_transport, unsigned long int conferenceID, unsigned short int userID, unsigned short int audioFloorID, unsigned short int videoFloorID, void (*msrp_callback)(unsigned long int conferenceID, struct ast_channel *chan, char *path), unsigned short int msrp_port, char *msrp_path)
 {
 	bfcp_sdp *sdp_bfcp = calloc(1, sizeof(bfcp_sdp));
 	if(!sdp_bfcp)
@@ -18,10 +18,20 @@
 	sdp_bfcp->audioFloorID = audioFloorID;
 	sdp_bfcp->videoFloorID = videoFloorID;
 	sdp_bfcp->status = BFCP_WAITING;
+
+	/* MSRP */
+	sdp_bfcp->msrp_callback = msrp_callback;
+	sdp_bfcp->msrp_port = msrp_port;
+	sdp_bfcp->msrp_path = calloc(strlen(msrp_path)+1, sizeof(char));
+	strcpy(sdp_bfcp->msrp_path, msrp_path);
+
 	return sdp_bfcp;
 }
 
 void bfcp_free_sdp(bfcp_sdp *sdp_bfcp) {
-	if(sdp_bfcp)
+	if(sdp_bfcp) {
+		if(sdp_bfcp->msrp_path)
+			free(sdp_bfcp->msrp_path);
 		free(sdp_bfcp);
+	}
 }
diff -urN xcon_bfcp/channels/bfcp_sdp/bfcp_sdp.h xcon_bfcp_patched/channels/bfcp_sdp/bfcp_sdp.h
--- xcon_bfcp/channels/bfcp_sdp/bfcp_sdp.h	2007-03-07 11:43:45.000000000 +0100
+++ xcon_bfcp_patched/channels/bfcp_sdp/bfcp_sdp.h	2007-04-23 15:50:29.000000000 +0200
@@ -1,8 +1,13 @@
-/* draft-ietf-mmusic-sdp-bfcp-03 */
+/* RFC 4583 */
 
 #ifndef _BFCP_SDP_H
 #define _BFCP_SDP_H
 
+#include "asterisk.h"
+
+#include "asterisk/channel.h"
+
+
 #define BFCP_WAITING	0
 #define BFCP_SENDING	1
 #define BFCP_SENT	2
@@ -25,10 +30,14 @@
 	unsigned short int audioFloorID;	/* The Audio Floor Identifier */
 	unsigned short int videoFloorID;	/* The Video Floor Identifier */
 	int status;				/* Status of the SDP+BFCP reinvite transmission */
+	/* We use this structure for MSRP negotiations as well */
+	void (*msrp_callback)(unsigned long int conferenceID, struct ast_channel *chan, char *path);
+	unsigned short int msrp_port;		/* The MSRP conference room port */
+	char *msrp_path;			/* The MSRP conference room path */
 } bfcp_sdp;
 
 /* Methods */
-bfcp_sdp *bfcp_create_sdp(unsigned short int bfcp_port, int bfcp_transport, unsigned long int conferenceID, unsigned short int userID, unsigned short int audioFloorID, unsigned short int videoFloorID);
+bfcp_sdp *bfcp_create_sdp(unsigned short int bfcp_port, int bfcp_transport, unsigned long int conferenceID, unsigned short int userID, unsigned short int audioFloorID, unsigned short int videoFloorID, void (*msrp_callback)(unsigned long int conferenceID, struct ast_channel *chan, char *path), unsigned short int msrp_port, char *msrp_path);
 void bfcp_free_sdp(bfcp_sdp *sdp_bfcp);
 
 #endif
diff -urN xcon_bfcp/channels/chan_sip.c xcon_bfcp_patched/channels/chan_sip.c
--- xcon_bfcp/channels/chan_sip.c	2007-03-07 11:43:48.000000000 +0100
+++ xcon_bfcp_patched/channels/chan_sip.c	2007-04-23 15:50:29.000000000 +0200
@@ -1036,6 +1036,8 @@
 	int xcon_firstack;			/*!< BFCP: to know if the first ACK has already been received */
 	int audio_floor_status;			/*!< BFCP: to keep track of the audio moderation for this peer */
 	int video_floor_status;			/*!< BFCP: to keep track of the video moderation for this peer */
+	unsigned short int msrp_port;		/*!< MSRP: the negotiated MSRP port */
+	char *msrp_path;			/*!< MSRP: the negotiated MSRP path */
 };
 
 static struct sip_pvt *dialoglist = NULL;
@@ -3292,6 +3294,9 @@
 	/* BFCP: destroy BFCP info too, if present */
 	if(p->sdp_bfcp)
 		bfcp_free_sdp(p->sdp_bfcp);
+	/* MSRP: destroy negotiated MSRP path too, if present */
+	if(p->msrp_path)
+		free(p->msrp_path);
 
 	ast_mutex_destroy(&p->pvt_lock);
 
@@ -4076,7 +4081,12 @@
 	case -1:
 		res = -1;
 		break;
-	/* BFCP: IDs are passed by app_meetme to the channel passing -2 as condition */
+	/*
+	   BFCP: IDs are passed by app_meetme to the channel passing -2 as condition
+		The attached data (sdp_bfcp) contains not only BFCP-related information
+		(identifiers, the FCS port), but also the MSRP path to join the
+		MSRP conference chatroom and a callback to use to notify about the reply.
+	*/
 	case -2:
 		sdp_bfcp = (bfcp_sdp*)data;
 		if(!sdp_bfcp) {
@@ -4758,6 +4768,8 @@
 	p->xcon_firstack = 0;				/* BFCP: no ACK has been received yet, of course */
 	p->audio_floor_status = BFCP_FLOOR_INACTIVE;	/* BFCP: bfcp floors are considered inactive by default */
 	p->video_floor_status = BFCP_FLOOR_INACTIVE;	/* BFCP: bfcp floors are considered inactive by default */
+	p->msrp_port = 0;				/* MSRP: no port received from this channel yet */
+	p->msrp_path = 0;				/* MSRP: no path received from this channel yet */
 
 	/* Add to active dialog list */
 	dialoglist_lock();
@@ -5256,6 +5268,9 @@
 	if (p->trtp)
 		ast_rtp_pt_clear(newtextrtp);  /* Must be cleared in case no m=text line exists */
 
+	/* MSRP SDP-negotiable values */
+	char msrp_path[80];
+
 	/* Find media streams in this SDP offer */
 	while ((m = get_sdp_iterate(&iterator, req, "m"))[0] != '\0') {
 		int x;
@@ -5345,6 +5360,11 @@
 		} else if (sscanf(m, "application %d TCP/TLS/BFCP *", &x) == 1) {
 			if (option_verbose > 2)
 				ast_verbose(VERBOSE_PREFIX_3 "\tParsing BFCP information in SIP OK's SDP: TCP/TLS/BFCP (bfcp port = %d, %s)...\n", x, (x == 9) ? "discard" : "bound");
+		/* MSRP: we parse the MSRP m-line too, if it is there */
+		} else if (sscanf(m, "message %d TCP/MSRP *", &x) == 1) {
+			if (option_verbose > 2)
+				ast_verbose(VERBOSE_PREFIX_3 "\tParsing MSRP information in SIP OK's SDP: TCP/MSRP (MSRP port = %d)...\n", x);
+			p->msrp_port = x;
 		} else 
 			ast_log(LOG_WARNING, "Unsupported SDP media type in offer: %s\n", m);
 		if (numberofports > 1)
@@ -5533,6 +5553,15 @@
 				ast_rtp_set_rtpmap_type(newaudiortp, codec, "audio", mimeSubtype,
 						ast_test_flag(&p->flags[0], SIP_G726_NONSTANDARD) ? AST_RTP_OPT_G726_NONSTANDARD : 0);
 			}
+		} else if (sscanf(a, "path:%s", msrp_path) == 1) {
+			ast_log(LOG_WARNING, "MSRP path a-line: %s\n", a);
+			if(p->sdp_bfcp) {
+				if(p->sdp_bfcp->msrp_callback && p->msrp_port && !p->msrp_path) {
+					p->msrp_path = calloc(strlen(msrp_path)+1, sizeof(char));
+					strcpy(p->msrp_path, msrp_path);
+					p->sdp_bfcp->msrp_callback(p->sdp_bfcp->conferenceID, p->owner, p->msrp_path);
+				}
+			}
 		}
 	}
 	
@@ -6727,10 +6756,13 @@
 static enum sip_result add_sdp(struct sip_request *resp, struct sip_pvt *p)
 {
 	/* BFCP: first of all let's check if we need to add BFCP info to SDP */
-	int bfcp = 0;
+	int bfcp = 0, msrp = 0;
 	if(p->sdp_bfcp) {
-		if(p->sdp_bfcp->status != BFCP_SENT)
+		if(p->sdp_bfcp->status != BFCP_SENT) {
 			bfcp++;
+			if(p->sdp_bfcp->msrp_port && p->sdp_bfcp->msrp_path)
+				msrp++;
+		}
 	}
 
 	int len = 0;
@@ -6781,6 +6813,14 @@
 	char *audio_hold = NULL;
 	char *video_hold = NULL;
 
+	/* MSRP: m and a lines for SDP */
+	char m_msrp[256];
+	char a_msrp[1024];
+	char *m_msrp_next = m_msrp;
+	size_t m_msrp_left = sizeof(m_msrp);
+	char *a_msrp_next = a_msrp;
+	size_t a_msrp_left = sizeof(a_msrp);
+
 	int x;
 	int capability;
 	int needvideo = FALSE;
@@ -7037,15 +7077,25 @@
 			ast_build_string(&a_audio_next, &a_audio_left, "a=label:10\r\n");
 		if ((p->sdp_bfcp->videoFloorID) && needvideo)
 			ast_build_string(&a_video_next, &a_video_left, "a=label:11\r\n");
+
+		/* Now MSRP, if needed */
+		if (msrp) {
+			/* m-line: only TCP/MSRP is supported for now */
+			ast_build_string(&m_msrp_next, &m_msrp_left, "m=message %d %s *\r\n", p->sdp_bfcp->msrp_port, "TCP/MSRP");
+			/* a-lines: default values for the MSRP conference */
+			ast_build_string(&a_msrp_next, &a_msrp_left, "a=accept-types:text/plain\r\n");
+			/* a-line for the MSRP conference path */
+			ast_build_string(&a_msrp_next, &a_msrp_left, "a=path:%s\r\n", p->sdp_bfcp->msrp_path);
+		}
 	}
 
  	/* XXX don't think you can have ptime for text */
  	if (min_text_packet_size)
  		ast_build_string(&a_text_next, &a_text_left, "a=ptime:%d\r\n", min_text_packet_size);
 
-	/* BFCP: we consider the BFCP-related m-line and a-lines too for the buffer */
+	/* BFCP: we consider the BFCP- and MSRP-related m-lines and a-lines too for the buffer */
 	if ((m_audio_left < 2) || (m_video_left < 2) || (m_text_left < 2) || (a_audio_left == 0) || 
-		(a_video_left == 0) || (m_bfcp_left < 2) || (a_bfcp_left == 0))
+		(a_video_left == 0) || (m_bfcp_left < 2) || (a_bfcp_left == 0) || (m_msrp_left < 2) || (a_msrp_left == 0))
 		ast_log(LOG_WARNING, "SIP SDP may be truncated due to undersized buffer!!\n");
 
  	ast_build_string(&m_audio_next, &m_audio_left, "\r\n");
@@ -7062,6 +7112,9 @@
 	/* BFCP: strings lenght must be added, if present */
 	if(bfcp)
 		len += strlen(m_bfcp) + strlen(a_bfcp);
+	/* MSRP: strings lenght must be added, if present */
+	if(msrp)
+		len += strlen(m_msrp) + strlen(a_msrp);
 
 	add_header(resp, "Content-Type", "application/sdp");
 	add_header_contentLength(resp, len);
@@ -7103,6 +7156,12 @@
 		add_line(resp, hold);	/* Repeat hold for the text stream */
 	}
 
+	/* MSRP: m and a lines below the existing ones, if needed */
+	if(msrp) {
+		add_line(resp, m_msrp);
+		add_line(resp, a_msrp);
+	}
+
 	/* BFCP: m and a lines below the existing ones, if needed */
 	if(bfcp) {
 		add_line(resp, m_bfcp);
diff -urN xcon_bfcp/configs/xcon.conf.sample xcon_bfcp_patched/configs/xcon.conf.sample
--- xcon_bfcp/configs/xcon.conf.sample	2007-03-07 11:43:56.000000000 +0100
+++ xcon_bfcp_patched/configs/xcon.conf.sample	2007-04-23 15:50:29.000000000 +0200
@@ -9,10 +9,14 @@
 				;	1 - only DCON/XCON messages
 				;	2 - BFCP messages too
 				;	3 - full debug
+				;	4 - VERY full debug (also useless MSRP log)
 
-[tls]				; Certificate and PrivateKey files needed by TLS, if enabled
-certificate => /path/to/server.pem
-privatekey => /path/to/server.key
+;[tls]				; Certificate and PrivateKey files needed by TLS, if enabled
+;certificate => /path/to/server.pem
+;privatekey => /path/to/server.key
+
+;[msrp]				; Settings for MSRP, if used
+;msrp => msrp.example.com	; The address to report in MSRP negotiations
 
 [manager]
 admin => manager		; The admin's username and password will have to be the same as the Asterisk
diff -urN xcon_bfcp/configure.ac xcon_bfcp_patched/configure.ac
--- xcon_bfcp/configure.ac	2007-03-07 11:43:59.000000000 +0100
+++ xcon_bfcp_patched/configure.ac	2007-04-23 15:50:28.000000000 +0200
@@ -179,6 +179,10 @@
 
 AST_EXT_LIB_SETUP([ALSA], [Advanced Linux Sound Architecture], [asound])
 
+# BFCP and MSRP are used in the enhanced XCON-compliant MeetMe (CONFIANCE)
+AST_EXT_LIB_SETUP([BFCP], [BFCP Server Behavior library], [bfcp])
+AST_EXT_LIB_SETUP([MSRP], [MSRP library], [msrp])
+
 # BKTR is used for backtrace support on platforms that do not
 # have it natively.
 AST_EXT_LIB_SETUP([BKTR], [Stack Backtrace support], [execinfo])
@@ -416,6 +420,10 @@
    fi
 fi
 
+AST_EXT_LIB_CHECK([BFCP], [bfcpsrv], [bfcp_initialize_bfcp_server], [bfcp_server.h])
+
+AST_EXT_LIB_CHECK([MSRP], [msrp], [msrp_init], [msrp.h])
+
 AST_EXT_LIB_CHECK([IKSEMEL], [iksemel], [iks_start_sasl], [iksemel.h])
 
 if test "${PBX_IKSEMEL}" = 1; then
diff -urN xcon_bfcp/makeopts.in xcon_bfcp_patched/makeopts.in
--- xcon_bfcp/makeopts.in	2007-03-07 11:43:59.000000000 +0100
+++ xcon_bfcp_patched/makeopts.in	2007-04-23 15:50:28.000000000 +0200
@@ -183,3 +183,9 @@
 TINFO_INCLUDE=@TINFO_INCLUDE@
 TINFO_LIB=@TINFO_LIB@
 TINFO_DIR=@TINFO_DIR@
+
+BFCP_INCLUDE=@BFCP_INCLUDE@
+BFCP_LIB=@BFCP_LIB@
+
+MSRP_INCLUDE=@MSRP_INCLUDE@
+MSRP_LIB=@MSRP_LIB@
