Index: channels/chan_mgcp.c
===================================================================
--- channels/chan_mgcp.c	(revision 213491)
+++ channels/chan_mgcp.c	(working copy)
@@ -304,6 +304,33 @@
 #define TYPE_TRUNK 1
 #define TYPE_LINE  2
 
+static struct rfc3149_xml_post_map{
+	char *deck;
+	char *card;
+	int action;
+	struct ast_variable *vars;
+	struct rfc3149_xml_functions *func;
+	struct rfc3149_xml_post_map *next;
+} *xml_mapped;
+
+static struct rfc3149_xml_functions{
+	char *name;
+	char *desc;
+	void (*p_fc)( struct mgcp_subchannel *sub, struct ast_variable *config , struct ast_variable *vars );
+	struct rfc3149_xml_functions *next;
+} *xml_functions;
+
+struct rfc3149_ky_functions{
+	char *name;
+	void (*p_fc)( int fk_num, struct mgcp_subchannel *sub, struct ast_variable *vars );
+	struct ast_variable *vars;
+	char *desc;
+	char *label;
+	char *state;
+	int enabled;
+	struct rfc3149_ky_functions *next;
+} *ky_functions;
+
 struct mgcp_endpoint {
 	ast_mutex_t lock;
 	char name[80];
@@ -316,7 +343,7 @@
 	char cid_name[AST_MAX_EXTENSION];	/*!< Caller*ID name */
 	char lastcallerid[AST_MAX_EXTENSION];	/*!< Last Caller*ID */
 	char dtmf_buf[AST_MAX_EXTENSION];	/*!< place to collect digits be */
-	char call_forward[AST_MAX_EXTENSION];	/*!< Last Caller*ID */
+	char call_forward[AST_MAX_EXTENSION];	/*!< Where call is forwarded */
 	char musicclass[MAX_MUSICCLASS];
 	char curtone[80];			/*!< Current tone */
 	char mailbox[AST_MAX_EXTENSION];
@@ -350,6 +377,7 @@
 	int immediate;
 	int hookstate;
 	int adsi;
+	int disp;
 	char rqnt_ident[80];             /*!< request identifier */
 	struct mgcp_request *rqnt_queue; /*!< pending RQNT commands */
 	ast_mutex_t rqnt_queue_lock;
@@ -363,8 +391,10 @@
 	/* struct ast_rtp *rtp; */
 	/* struct sockaddr_in tmpdest; */
 	/* message go the the endpoint and not the channel so they stay here */
+	struct mgcp_endpoint *endp;
 	struct mgcp_endpoint *next;
 	struct mgcp_gateway *parent;
+	struct rfc3149_ky_functions *fk[100]; /* functions assigned to a particular button defined in RFC3149 */
 };
 
 static struct mgcp_gateway {
@@ -411,6 +441,41 @@
 static int transmit_modify_with_sdp(struct mgcp_subchannel *sub, struct ast_rtp_instance *rtp, int codecs);
 static int transmit_connection_del(struct mgcp_subchannel *sub);
 static int transmit_audit_endpoint(struct mgcp_endpoint *p);
+
+/* RFC3149 config functions */
+void rfc3149_allocate_ky_functions(void);
+void rfc3149_allocate_xml_functions(void);
+struct ast_variable *parse_params(char *var_val, int offset );
+char *rfc3149_ky_wrap( struct mgcp_endpoint *p,  char *rq );
+void rfc3149_indication(struct mgcp_subchannel *sub);
+char *rfc3149_reindicate( struct mgcp_endpoint *p, char *rq );
+void rfc3149_fk_set_state(struct mgcp_endpoint *p, char *name,char *state );
+void rfc3149_conf_pickup( struct ast_variable *var, const char *name, char **value);
+
+/* RFC3149 transmit functions */
+static int transmit_rfc3149_xml(struct mgcp_endpoint *p, char *xml);
+static int transmit_rfc3149_ky_fk(struct mgcp_endpoint *p, const char *fk_num);
+static int transmit_rfc3149_ky_ls(struct mgcp_endpoint *p, const char *fk_num, const char *label );
+static int transmit_rfc3149_ky_ks(struct mgcp_endpoint *p, const char *fk_num, const char *state );
+static int transmit_rfc3149_ignition(struct mgcp_endpoint *p );
+
+/* Endpoint functions - for RFC3149 / KY */
+static void rfc3149_ky_dnd( int fk_num, struct mgcp_subchannel *p, struct ast_variable *vars);
+void rfc3149_ky_forward( int fk_num, struct mgcp_subchannel *p, struct ast_variable *vars );
+static void rfc3149_ky_hold( int fk_num, struct mgcp_subchannel *p, struct ast_variable *vars );
+static void rfc3149_ky_call( int fk_num, struct mgcp_subchannel *sub, struct ast_variable *vars );
+
+/* Endpoint functions - for RFC3149 / XML */
+void handle_rfc3149_xml(struct mgcp_subchannel *sub, char *ev);
+char *rfc3149_create_xml(char *deck, char* card, struct ast_variable *variables);
+int rfc3149_register_xml_function( struct rfc3149_xml_functions *xml_functions, char *xml_deck, char *xml_card, struct ast_variable *vars );
+int rfc3149_register_xml_action( struct rfc3149_xml_functions *xml_functions, char *action, struct ast_variable *vars );
+
+static void rfc3149_xml_dnd( struct mgcp_subchannel *p, struct ast_variable *config, struct ast_variable *vars );
+static void rfc3149_xml_returnka( struct mgcp_subchannel *p, struct ast_variable *config, struct ast_variable *vars );
+static void rfc3149_xml_fwd_active( struct mgcp_subchannel *sub, struct ast_variable *config , struct ast_variable *vars);
+static void rfc3149_xml_fwd_deactive( struct mgcp_subchannel *sub, struct ast_variable *config , struct ast_variable *vars);
+
 static void start_rtp(struct mgcp_subchannel *sub);
 static void handle_response(struct mgcp_endpoint *p, struct mgcp_subchannel *sub,  
                             int result, unsigned int ident, struct mgcp_request *resp);
@@ -1163,14 +1228,384 @@
 	} else {
 		return CLI_SHOWUSAGE;
 	}
+
 	return CLI_SUCCESS;
 }
 
+static char *handle_mgcp_rfc3149_ky(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct mgcp_gateway  *mg;
+	struct mgcp_endpoint *me;
+	int found = 0;
+	char *ename, *gname, *c;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "mgcp rfc3149 ky {fk|ls|ks}";
+		e->usage =
+			"Usage: mgcp rfc3149 ky {fk|ls|ks} <endpointid> ..\n"
+			"       fk <endpoint> <num>: sets request for event from button fk<num>.\n"
+			"       ls <endpoint> <num> <label>: sets label for button fk<num>. \n"
+			"       ks <endpoint> <num> <state>: sets state for button fk<num>. \n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if ( (a->argc != 6 &&  strcmp(a->argv[3], (char *)"fk") == 0) || a->argc == 3 
+			|| ( a->argc != 7 &&  strcmp(a->argv[3], (char *)"fk") !=0 )) {
+		return CLI_SHOWUSAGE;
+	}
+
+
+	/* Finding endpoint */
+	/* split the name into parts by null */
+	ename = alloca(strlen(a->argv[4]));
+	ast_copy_string(ename, a->argv[4], sizeof(ename));
+	gname = ename;
+	while (*gname) {
+		if (*gname == '@') {
+			*gname = 0;
+			gname++;
+			break;
+		}
+		gname++;
+	}
+	if (gname[0] == '[') {
+		gname++;
+	}
+	if ((c = strrchr(gname, ']'))) {
+		*c = '\0';
+	}
+	ast_mutex_lock(&gatelock);
+	mg = gateways;
+
+	while (mg) {
+		if (!strcasecmp(mg->name, gname)) {
+			me = mg->endpoints;
+			while (me) {
+				if (!strcasecmp(me->name, ename)) {
+					found = 1;
+
+					if( strcmp( a->argv[3], (char *)"fk")==0 ) {
+						transmit_rfc3149_ky_fk(me,a->argv[5]);
+					}
+
+					if( strcmp( a->argv[3], (char *)"ls")==0 ) {
+						transmit_rfc3149_ky_ls(me,a->argv[5],a->argv[6]);
+					}
+
+					if( strcmp( a->argv[3], (char *)"ks")==0 ) {
+						transmit_rfc3149_ky_ks(me,a->argv[5],a->argv[6]);
+					}
+
+					break;
+				}
+				me = me->next;
+			}
+			if (found) {
+				break;
+			}
+		}
+		mg = mg->next;
+	}
+
+	if (!found) {
+		ast_cli(a->fd, "   << Could not find endpoint >>     ");
+	}
+
+	ast_mutex_unlock(&gatelock);
+
+	return CLI_SUCCESS;
+}
+
+static char *handle_mgcp_rfc3149_xml(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct mgcp_gateway  *mg;
+	struct mgcp_endpoint *me;
+	int found = 0, i, xml_length, arglen;
+	char *ename,*gname, *c, *xml="", *xml_tmp="";
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "mgcp rfc3149 xml";
+		e->usage =
+			"Usage: mgcp rfc3149 xml <endpointid> <deck> <card> <$variable=value>...\n"
+			"       This option is for developement and testing only!!!\n"
+			"       Variables might follow afted <deck> and <card>.\n"
+			"       Compound value can be closed by quotation mark.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	/* Only function called */
+	if (a->argc <= 6) {
+		return CLI_SHOWUSAGE;
+	}
+
+	/* Finding endpoint */
+	/* split the name into parts by null */
+	arglen = strlen(a->argv[3]);
+	ename = alloca(arglen);
+	ast_copy_string(ename, a->argv[3], arglen);
+	gname = ename;
+	while (*gname) {
+		if (*gname == '@') {
+			*gname = 0;
+			gname++;
+			break;
+		}
+		gname++;
+	}
+	if (gname[0] == '[') {
+		gname++;
+	}
+	if ((c = strrchr(gname, ']'))) {
+		*c = '\0';
+	}
+
+	ast_mutex_lock(&gatelock);
+	mg = gateways;
+
+	while (mg) {
+		if (!strcasecmp(mg->name, gname)) {
+			me = mg->endpoints;
+			while (me) {
+				if (!strcasecmp(me->name, ename)) {
+					found = 1;
+					xml_length = strlen(a->argv[4]) + strlen(a->argv[5]) +1 +2 ;
+					xml = (char *)calloc( xml_length , sizeof(char));
+					snprintf(xml,xml_length,"%s?%s?", a->argv[4],a->argv[5]);
+					/* Generation of variables part */
+					for (i = 6; i < a->argc; i++) {
+						xml_tmp = xml;
+						xml = (char *)calloc(strlen(xml) + strlen(a->argv[i]) + 1, sizeof(char));
+						strcat( xml, xml_tmp );
+						strcat( xml, a->argv[i]);
+
+						if ( i < a->argc-1 ) {
+							strcat( xml, "?");
+						}
+					}
+					transmit_rfc3149_xml(me, xml);
+					break;
+				}
+				me = me->next;
+			}
+			if (found) {
+				break;
+			}
+		}
+		mg = mg->next;
+	}
+
+	if (!found) {
+		ast_cli(a->fd, "   << Could not find endpoint >>     ");
+	}
+
+	ast_mutex_unlock(&gatelock);
+
+	return CLI_SUCCESS;
+}
+
+static char *handle_mgcp_rfc3149_ignition(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct mgcp_gateway  *mg;
+	struct mgcp_endpoint *me;
+	int found = 0, arglen;
+	char *ename,*gname, *c;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "mgcp rfc3149 ignition";
+		e->usage =
+			"Usage: mgcp rfc3149 ignition <endpointid> ..\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 4) {
+		return CLI_SHOWUSAGE;
+	}
+
+	/* Finding endpoint */
+	/* split the name into parts by null */
+	arglen = strlen(a->argv[3]);
+	ename = alloca(arglen);
+	ast_copy_string(ename, a->argv[3], arglen);
+	gname = ename;
+
+	while (*gname) {
+		if (*gname == '@') {
+			*gname = 0;
+			gname++;
+			break;
+		}
+		gname++;
+	}
+	if (gname[0] == '[') {
+		gname++;
+	}
+	if ((c = strrchr(gname, ']'))) {
+		*c = '\0';
+	}
+
+	ast_mutex_lock(&gatelock);
+	mg = gateways;
+
+	while(mg) {
+		if (!strcasecmp(mg->name, gname)) {
+			me = mg->endpoints;
+			while (me) {
+				if (!strcasecmp(me->name, ename)) {
+					found = 1;
+					transmit_rfc3149_ignition(me);
+					break;
+				}
+				me = me->next;
+			}
+			if (found) {
+				break;
+			}
+		}
+		mg = mg->next;
+	}
+
+	if (!found) {
+		ast_cli(a->fd, "   << Could not find endpoint >>     ");
+	}
+
+	ast_mutex_unlock(&gatelock);
+
+	return CLI_SUCCESS;
+}
+
+static char *handle_mgcp_show_xml_functions(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	static struct rfc3149_xml_functions *maps;
+	int found = 0;
+	maps = xml_functions;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "mgcp show xml functions";
+		e->usage =
+			"Usage: mgcp show xml functions\n"
+			"       Lists all avalaible functions for XML.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 4) {
+		return CLI_SHOWUSAGE;
+	}
+
+	ast_cli(a->fd, "  Name \t\t\t Description\n");
+	while (maps){
+		ast_cli(a->fd, "'%s' \t %s\n", maps->name, maps->desc);
+		maps = maps->next;
+		found++;
+	}
+
+	if (!found) {
+		ast_cli(a->fd, "	<< No functions defined >>	  \n");
+	}
+
+	return CLI_SUCCESS;
+}
+
+static char *handle_mgcp_show_xml_deck(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	static struct rfc3149_xml_post_map *funcs;
+	int found = 0;
+	funcs = xml_mapped;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "mgcp show xml deck";
+		e->usage =
+			"Usage: mgcp show xml deck\n"
+			"       Lists all defined decks and their assigned functions.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 4) {
+		return CLI_SHOWUSAGE;
+	}
+
+	ast_cli(a->fd, "  Deck \t Card \t Function\n");
+	while (funcs) {
+		if (funcs->action) {
+			funcs = funcs->next;
+			continue;
+		}
+		ast_cli(a->fd, "'%s'\t'%s'\t'%s'\n", funcs->deck, funcs->card, funcs->func->name);
+		funcs = funcs->next;
+		found++;
+	}
+
+	if (!found) {
+		ast_cli(a->fd, "	<< No decks defined to a function >>	  \n");
+	}
+
+	return CLI_SUCCESS;
+}
+
+static char *handle_mgcp_show_xml_action(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	static struct rfc3149_xml_post_map *funcs;
+	int found = 0;
+	funcs = xml_mapped;
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "mgcp show xml action";
+		e->usage =
+			"Usage: mgcp show xml action\n"
+			"       Lists all defined actions and their assigned functions.\n";
+		return NULL;
+	case CLI_GENERATE:
+		return NULL;
+	}
+
+	if (a->argc != 4) {
+		return CLI_SHOWUSAGE;
+	}
+
+	ast_cli(a->fd, "  Action \t Function\n");
+	while (funcs) {
+		if (!funcs->action) {
+			funcs = funcs->next;
+			continue;
+		}
+		ast_cli(a->fd, "'%s'\t'%s'\n", funcs->deck, funcs->func->name);
+		funcs = funcs->next;
+		found++;
+	}
+
+	if (!found) {
+		ast_cli(a->fd, "	<< No decks defined to a function >>	  \n");
+	}
+
+	return CLI_SUCCESS;
+}
+
 static struct ast_cli_entry cli_mgcp[] = {
 	AST_CLI_DEFINE(handle_mgcp_audit_endpoint, "Audit specified MGCP endpoint"),
 	AST_CLI_DEFINE(handle_mgcp_show_endpoints, "List defined MGCP endpoints"),
 	AST_CLI_DEFINE(handle_mgcp_set_debug, "Enable/Disable MGCP debugging"),
-	AST_CLI_DEFINE(mgcp_reload, "Reload MGCP configuration"),
+	AST_CLI_DEFINE(handle_mgcp_rfc3149_ky, "Handling Function keys in RFC3149"),
+	AST_CLI_DEFINE(handle_mgcp_rfc3149_xml, "Handling XML features in RFC3149"),
+	AST_CLI_DEFINE(handle_mgcp_rfc3149_ignition, "Proceed all we need for KY functionality"),
+	AST_CLI_DEFINE(*handle_mgcp_show_xml_functions, "List functions avalaible for XML features in RFC3149"),
+	AST_CLI_DEFINE(*handle_mgcp_show_xml_deck, "List functions assignment to a particular deck and card defined in XML package in RFC3149"),
+	AST_CLI_DEFINE(*handle_mgcp_show_xml_action, "List functions assignment to a particular action defined in XML package in RFC3149"),
+ 	AST_CLI_DEFINE(mgcp_reload, "Reload MGCP configuration"),
 };
 
 static int mgcp_answer(struct ast_channel *ast)
@@ -1479,6 +1914,7 @@
 		if (!tmp->nativeformats)
 			tmp->nativeformats = capability;
 		fmt = ast_best_codec(tmp->nativeformats);
+		ast_string_field_build(tmp, name, "MGCP/%s@%s-%d", i->name, i->parent->name, sub->id);
 		if (sub->rtp)
 			ast_channel_set_fd(tmp, 0, ast_rtp_instance_fd(sub->rtp, 0));
 		if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) {
@@ -2218,7 +2654,7 @@
 	add_header(&resp, "X", p->rqnt_ident); /* SC */
 	switch (p->hookstate) {
 	case MGCP_ONHOOK:
-		add_header(&resp, "R", "L/hd(N)");
+		add_header(&resp, "R",  rfc3149_ky_wrap(p, (char *)"L/hd(N)"));
 		break;
 	case MGCP_OFFHOOK:
 		add_header_offhook(sub, &resp);
@@ -2260,7 +2696,7 @@
 	add_header(&resp, "X", p->rqnt_ident); /* SC */
 	switch (p->hookstate) {
 	case MGCP_ONHOOK:
-		add_header(&resp, "R", "L/hd(N)");
+		add_header(&resp, "R",  rfc3149_ky_wrap(p, (char *)"L/hd(N)"));
 		break;
 	case MGCP_OFFHOOK:
 		add_header_offhook(sub, &resp);
@@ -2301,7 +2737,7 @@
 	add_header(&resp, "I", sub->cxident);
 	switch (sub->parent->hookstate) {
 	case MGCP_ONHOOK:
-		add_header(&resp, "R", "L/hd(N)");
+		add_header(&resp, "R",  rfc3149_ky_wrap(p, (char *)"L/hd(N)"));
 		break;
 	case MGCP_OFFHOOK:
 		add_header_offhook(sub, &resp);
@@ -2313,7 +2749,43 @@
 	return send_request(p, sub, &resp, oseq); /* SC */
 }
 
+char *rfc3149_ky_wrap(struct mgcp_endpoint *p,  char *rq)
+{
+    char *tmp;
+    int len,i;
+    len = strlen( rq )+1;
+    for(i = 1; i < (sizeof(p->fk)/sizeof(p->fk[0])); i++){
+        if (p->fk[i]->enabled) {
+            tmp = rq;
+            len += snprintf(NULL, 0, ",KY/fk%d", i);
+            rq = (char *)calloc( len+1, sizeof(char));
+            snprintf( rq , len+1, "%s,KY/fk%d", tmp, i);
+        }
+    }
+    return rq;
+}
 
+char *rfc3149_reindicate(struct mgcp_endpoint *p, char *rq)
+{
+    char *tmp;
+    int len,i,cnt=0;
+    len = strlen( rq )+1;
+    for (i = 1; i < (sizeof(p->fk)/sizeof(p->fk[0])); i++) {
+        if (p->fk[i]->enabled) {
+            tmp = rq;
+            len += snprintf(NULL, 0, ",KY/ks(%d,%s)", i, p->fk[i]->state);
+            rq = (char *)calloc( len+1, sizeof(char));
+            if (cnt++ == 0 ||  strlen(tmp) == 0) {
+                snprintf( rq, len+1, "KY/ks(%d,%s)",i, p->fk[i]->state);
+			} else {
+                snprintf( rq, len+1, "%s,KY/ks(%d,%s)",tmp, i, p->fk[i]->state);
+			}
+        }
+    }
+    return rq;
+}
+
+
 static void add_header_offhook(struct mgcp_subchannel *sub, struct mgcp_request *resp)
 {
 	struct mgcp_endpoint *p = sub->parent;
@@ -2321,7 +2793,7 @@
 	if (p && p->sub && p->sub->owner && p->sub->owner->_state >= AST_STATE_RINGING && (p->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)))
 		add_header(resp, "R", "L/hu(N),L/hf(N)");
 	else
-		add_header(resp, "R", "L/hu(N),L/hf(N),D/[0-9#*](N)");
+		add_header(resp, "R",  rfc3149_ky_wrap(p, (char *)"L/hu(N),L/hf(N),D/[0-9#*](N)"));
 }
 
 static int transmit_audit_endpoint(struct mgcp_endpoint *p)
@@ -2337,6 +2809,195 @@
 	return send_request(p, NULL, &resp, oseq);  /* SC */
 }
 
+char *rfc3149_create_xml(char *deck, char* card, struct ast_variable *variables)
+{
+	int len = strlen(deck) + strlen(card) + 2, i = 0;
+	char *output, *vars="", *tmp="";
+
+	while (variables) {
+		len+=strlen(variables->name)+2;
+		len+=strlen(variables->value)+1;
+		tmp = vars;
+		vars = (char *)ast_calloc( len+1, sizeof(char) );
+		if (i++ == 0) {
+			snprintf(vars, len+1 , "$%s=%s", variables->name, variables->value);
+		} else {
+			snprintf(vars, len+1 , "%s?$%s=%s", tmp, variables->name, variables->value);
+		}
+		tmp = (char *)ast_calloc(len + 1, sizeof(char));
+		variables=variables->next;
+	}
+	len++;
+	output = (char *)ast_calloc(len, sizeof(char));
+	snprintf(output, len, "%s?%s?%s", deck, card, vars);
+
+	return output;
+}
+
+static int transmit_rfc3149_xml(struct mgcp_endpoint *p, char *xml_rcvt)
+{
+	struct mgcp_request resp;
+	char *xml;
+	int length;
+
+	length = strlen( "XML/xml()" ) + strlen( xml_rcvt ) + 1;
+	xml = (char *)calloc( length, sizeof(char));
+	snprintf(xml, length, "XML/xml(%s)", xml_rcvt);
+	reqprep(&resp, p, "RQNT");
+	add_header(&resp, "X", p->rqnt_ident);
+	add_header(&resp, "S", xml);
+	resp.cmd = MGCP_CMD_RQNT;
+	resp.trid = oseq;
+	return send_request(p, NULL, &resp, oseq);  /* SC */
+}
+
+static int transmit_rfc3149_ky_fk(struct mgcp_endpoint *p, const char *fk_num)
+{
+	struct mgcp_request resp;
+	int length;
+	char *rqnt;
+
+	length = strlen( "KY/fk" ) + strlen(fk_num) + 1; /* if there was telephone with more than 300x fk, needs to fix. */
+	rqnt = (char *)calloc( length, sizeof(char));
+	snprintf(rqnt, length, "KY/fk%s", fk_num);
+	reqprep(&resp, p, "RQNT");
+	add_header(&resp, "X", p->rqnt_ident);
+	add_header(&resp, "R", rqnt);
+	resp.cmd = MGCP_CMD_RQNT;
+	resp.trid = oseq;
+	return send_request(p, NULL, &resp, oseq);  /* SC */
+}
+
+static int transmit_rfc3149_ky_ks_ls(struct mgcp_endpoint *p, char *type, const char *fk_num, const char *state)
+{
+	struct mgcp_request resp;
+	char *xml;
+	int length;
+
+	length = strlen("KY/ks(,)") + strlen(fk_num) + strlen(state) + 1;
+	xml = (char *)calloc(length, sizeof(char));
+	snprintf(xml, length, "KY/%s(%s,%s)", type, fk_num, state);
+	reqprep(&resp, p, "RQNT");
+	add_header(&resp, "X", p->rqnt_ident);
+	add_header(&resp, "S", xml);
+	add_header(&resp, "R", rfc3149_ky_wrap(p, "L/hd(N)"));
+	resp.cmd = MGCP_CMD_RQNT;
+	resp.trid = oseq;
+	return send_request(p, NULL, &resp, oseq);  /* SC */
+}
+
+static int transmit_rfc3149_ky_ls(struct mgcp_endpoint *p, const char *fk_num, const char *label)
+{
+		return transmit_rfc3149_ky_ks_ls(p, (char *)"ls", fk_num, label);
+}
+
+static int transmit_rfc3149_ky_ks(struct mgcp_endpoint *p, const char *fk_num, const char *state)
+{
+		return transmit_rfc3149_ky_ks_ls(p, (char *)"ks", fk_num, state);
+}
+
+static int transmit_rfc3149_ky_LED_off( struct mgcp_endpoint *p )
+{
+	struct mgcp_request resp;
+	int i, parts = 5, len = 2, cnt_part = 0;
+	char *post, *tmp_line;
+
+	post = (char *)calloc(1, sizeof(char));
+	for(i = 1; i < 100; i++) {
+		tmp_line = post;
+		cnt_part++;
+		len += snprintf(NULL, 0, "KY/ks(%d,db)", i) + 1;
+		if (len <= ((int)MGCP_MAX_PACKET/parts)) {
+			if (cnt_part == 1) {
+				post = (char *)calloc( len + 1, sizeof(char));
+				snprintf(post, len+1 , "KY/ks(%d,db)", i);
+			} else {
+				post = (char *)calloc(len + 1, sizeof(char));
+				snprintf(post, len + 1 , "%s,KY/ks(%d,db)", tmp_line, i);
+			}
+		} else {
+			/* This sends signal to switch off indication of function keys */
+			reqprep(&resp, p, "RQNT");
+			add_header(&resp, "X", p->rqnt_ident);
+			add_header(&resp, "S", post );
+			resp.cmd = MGCP_CMD_RQNT;
+			resp.trid = oseq;
+			send_request(p, NULL, &resp, oseq);
+
+			len = snprintf(NULL, 0, "KY/ks(%d,db)", i)+1;
+			tmp_line = (char *)calloc(1, sizeof(char));
+			i--;
+			cnt_part=0;
+		}
+	}
+
+	reqprep(&resp, p, "RQNT");
+	add_header(&resp, "X", p->rqnt_ident);
+	//ast_verbose("Generuji '%s'\n", post);
+	//add_header(&resp, "S", post );
+	resp.cmd = MGCP_CMD_RQNT;
+	resp.trid = oseq;
+	return 0;
+/*	return send_request(p, NULL, &resp, oseq); */ /* SC */ 
+}
+
+static int transmit_rfc3149_ignition(struct mgcp_endpoint *p)
+{
+	struct mgcp_request resp;
+	int i, len;
+	char header[15];
+	char *fk, *ls_ks, *tmp_line;
+
+	reqprep(&resp, p, "RQNT");
+	ls_ks = (char *)calloc(15, sizeof(char));
+	fk = (char *)calloc(15, sizeof(char));
+	for(i = 1; i < (sizeof(p->fk)/sizeof(p->fk[0])); i++){
+		if (p->fk[i]->enabled) {
+			/* Keys states */
+			tmp_line = ls_ks;
+			snprintf(header, 15, "KY/ks(%d,%s)", i, p->fk[i]->state);
+			ls_ks = (char *)calloc(strlen(header) + strlen(tmp_line) + 3, sizeof(char));
+			if (strlen(tmp_line) != 0) {
+				snprintf(ls_ks, strlen(tmp_line) + 17, "%s,%s", tmp_line, header);
+			} else {
+				snprintf(ls_ks, strlen(tmp_line) + 17, "%s", header);
+			}
+
+			/* Labels */
+			tmp_line = ls_ks;
+			len = strlen(tmp_line);
+			len += snprintf(NULL, 0, "KY/ls(%d,'%s')", i, p->fk[i]->label);
+			ls_ks = (char *)calloc(len + 2 , sizeof(char));
+			snprintf(ls_ks, len + 2, "%s,KY/ls(%d,'%s')", tmp_line, i, p->fk[i]->label);
+
+			/* Functions keys */
+			tmp_line = fk;
+			snprintf(header, 15, "KY/fk%d", i);
+			fk = (char *)calloc(strlen(header) + strlen(tmp_line) + 3, sizeof(char));
+			if (strlen(tmp_line) != 0) {
+				snprintf(fk, strlen(tmp_line) + 17, "%s,%s", tmp_line, header);
+			} else {
+				snprintf(fk, strlen(tmp_line) + 17, "%s", header);
+			}
+		}
+	}
+
+	add_header(&resp, "X", p->rqnt_ident);
+	if (strlen(ls_ks) != 0) {
+		add_header(&resp, "S", ls_ks);
+	}
+	if (strlen(fk) != 0) {
+		add_header(&resp, "R", fk);
+	}
+	resp.cmd = MGCP_CMD_RQNT;
+	resp.trid = oseq;
+       /* If no fk is set, no need to request endpoint */
+	if (strlen(ls_ks) == 0 && strlen(fk) == 0) {
+		return 0;
+	}
+	return send_request(p, NULL, &resp, oseq);  /* SC */
+}
+
 static int transmit_connection_del(struct mgcp_subchannel *sub)
 {
 	struct mgcp_endpoint *p = sub->parent;
@@ -2685,6 +3346,9 @@
 					transmit_notify_request(sub, "L/dl");
 					len = 0;
 					getforward = 0;
+					
+					rfc3149_fk_set_state(p, "FK_Forward", "dc");
+					rfc3149_indication(sub);
 				} else {
 					/*res = tone_zone_play_tone(p->subs[index].zfd, -1);*/
 					ast_indicate(chan, -1);
@@ -2795,6 +3459,8 @@
 			getforward = 0;
 			memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
 			len = 0;
+			rfc3149_fk_set_state(p, "FK_Forward", "en");
+			rfc3149_indication(sub);
 		} else if (!strcmp(p->dtmf_buf, ast_parking_ext()) && 
 			sub->next->owner && ast_bridged_channel(sub->next->owner)) {
 			/* This is a three way call, the main call being a real channel, 
@@ -3011,13 +3677,101 @@
 	}
 }
 
+/* Handling of Function key events */
+void handle_rfc3149_xml(struct mgcp_subchannel *sub, char *ev){
+	char *xml_deck, *xml_card, *xml_variables, *temp="", *temp1;
+	char new_ev[strlen(ev) + 1];
+	int i = 0, cnt = 0, pos[3];
+	static struct rfc3149_xml_post_map *func;
+	struct ast_variable *vars = NULL, *tmp_vars;
+
+	// This changes "post?deck?card?variables" to "post deck card variables" - because of sscanf lower */
+	for(i = 0; *(ev+i) != '\0'; i++) {
+		new_ev[i] = (char )*(ev+i);
+		if (*(ev+i) == '?' && cnt <= 2) {
+			new_ev[i] = ' ';
+			pos[cnt++] = i;
+		}
+	}
+	new_ev[i] = '\0';
+	/*ast_verbose("XML/Zpracovavam udalost: '%s'\n", new_ev);*/
+
+	xml_card = (char *)calloc(pos[1] - pos[0], sizeof(char));
+	xml_deck = (char *)calloc(pos[2] - pos[1], sizeof(char));
+	xml_variables = (char *)calloc(strlen(ev) - pos[2], sizeof(char));
+	i = sscanf(new_ev, "post %s %s %s", xml_deck, xml_card, xml_variables); /* ) needs to fix, but it comes from sscanf in handle_request */
+	
+	if (i == 1) {            
+		/* This is action calling */
+		func=xml_mapped;
+		while (func) {
+			if (func->action) {
+				if (strstr(xml_deck, ")")) {
+						*strstr(xml_deck,")")='\0';
+				}
+				if (!strcasecmp(func->deck, xml_deck) ) {
+					func->func->p_fc(sub, func->vars, NULL);
+					break; /* Function has been found - do not need to continue in searching */
+				}
+			}
+			func=func->next;
+		}
+	} else {
+		/* This is standard function from a deck */
+		func=xml_mapped;
+		while (func) {
+			if (func->action == 0) {				
+				if (!strcasecmp(func->deck, xml_deck) && !strcasecmp(func->card, xml_card)) {
+					*(xml_variables+strlen(xml_variables)-1)='\0'; /* Removes ) from the end string */
+
+					while (temp) {
+						temp = strstr(xml_variables, "?");
+						cnt = temp - xml_variables;
+						if (temp == NULL) {
+							cnt = strlen(xml_variables);
+						}
+						temp1 = (char *)calloc(cnt + 1, sizeof(char));
+						strncpy(temp1, xml_variables, cnt);
+						temp = (char *)calloc(cnt + 1, sizeof(char));
+						for (i = 0; i < strlen(temp1); i++) {
+								*(temp+i) = *(temp1 + i);
+								if (*(temp1 + i) == '=') {
+									*(temp+i) = ' ';
+								}
+						}
+						sscanf(temp, "%s %s", temp1, temp);
+						if (strlen(temp1)!=0) {
+							tmp_vars = (struct ast_variable *)ast_malloc(sizeof(struct ast_variable));
+							tmp_vars->name = temp1;
+							tmp_vars->value = temp;
+							if (vars == NULL) {
+								vars = tmp_vars;
+								tmp_vars->next = NULL;
+							} else {
+								 tmp_vars->next=vars;
+								 vars = tmp_vars;
+							}
+						}
+						temp=strstr(xml_variables, "?");
+						xml_variables = strstr(xml_variables, "?") + 1;
+					}
+
+					func->func->p_fc(sub,func->vars, vars);					
+					break; /* Function has been found - do not need to continue in searching */
+				}
+			}
+			func=func->next;
+		}
+	}
+}
+
 static int handle_request(struct mgcp_subchannel *sub, struct mgcp_request *req, struct sockaddr_in *sin)
 {
-	char *ev, *s;
+	char *ev, *s, *xml = "";
 	struct ast_frame f = { 0, };
 	struct mgcp_endpoint *p = sub->parent;
 	struct mgcp_gateway *g = NULL;
-	int res;
+	int res, fk_num;
 
 	if (mgcpdebug) {
 		ast_verbose("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name);
@@ -3078,6 +3832,7 @@
 		/* Notified of an event */
 		ev = get_header(req, "O");
 		s = strchr(ev, '/');
+		xml = (char *)calloc(strlen(ev) + 1, sizeof(char));
 		if (s) ev = s + 1;
 		ast_debug(1, "Endpoint '%s@%s-%d' observed '%s'\n", p->name, p->parent->name, sub->id, ev);
 		/* Keep looking for events unless this was a hangup */
@@ -3088,6 +3843,14 @@
 			p->hookstate = MGCP_OFFHOOK;
 			sub->cxmode = MGCP_CX_SENDRECV;
 			handle_hd_hf(sub, ev);
+		} else if (sscanf(ev, "fk%d", &fk_num) > 0 || sscanf(ev, "KY/fk%d", &fk_num) > 0) {
+		/* RFC3149: Checks for Function key event */
+			if (sub->parent->fk[fk_num]->enabled) {
+				sub->parent->fk[fk_num]->p_fc(fk_num, sub, sub->parent->fk[fk_num]->vars);
+			}
+		} else if (sscanf(ev, "xml(%s)", xml) > 0 || sscanf(ev, "XML/xml(%s)", xml) > 0) {
+		/* RFC3149: Checks for XML events */
+			handle_rfc3149_xml(sub, xml);
 		} else if (!strcasecmp(ev, "hf")) {
 			/* We can assume we are offhook if we received a hookflash */
 			/* First let's just do call wait and ignore threeway */
@@ -3541,6 +4304,80 @@
 	return tmpc;
 }
 
+void rfc3149_allocate_ky_functions(void)
+{
+	struct rfc3149_ky_functions *actual;
+	actual = (struct rfc3149_ky_functions *) malloc(sizeof(struct rfc3149_ky_functions));
+	actual->name = "FK_DND";
+	actual->desc = "Sets DND for a particular endpoint.";
+	actual->p_fc = rfc3149_ky_dnd;
+	actual->state = "en";
+	actual->label = "DND";
+	ky_functions = actual;
+
+	actual->next = (struct rfc3149_ky_functions *) malloc(sizeof(struct rfc3149_ky_functions));
+	actual = actual->next;
+	actual->name = "FK_Forward";
+	actual->desc = "Forwards all calls to the specified number.";
+	actual->state = "en";
+	actual->label = "FWD";
+	actual->p_fc=rfc3149_ky_forward;
+
+	actual->next = (struct rfc3149_ky_functions *) malloc(sizeof(struct rfc3149_ky_functions));
+	actual = actual->next;
+	actual->name = "FK_Hold";
+	actual->desc = "Holds the call.";
+	actual->state = "en";
+	actual->label = "HOLD";
+	actual->p_fc = rfc3149_ky_hold;
+
+	actual->next = (struct rfc3149_ky_functions *) malloc(sizeof(struct rfc3149_ky_functions));
+	actual = actual->next;
+	actual->name = "FK_Call";
+	actual->desc = "Calls to the specified number in config.";
+	actual->state = "en";
+	actual->label = "Call";
+	actual->p_fc = rfc3149_ky_call;
+
+	/* Last pointer */
+	actual->next =  NULL;
+}
+
+struct ast_variable *parse_params(char *var_val, int offset)
+{
+	char *input = var_val + offset, *tmp;
+	int len, var_len;
+	struct ast_variable *var;
+
+	if (strchr(input, ',')) {
+		len = strchr(input,',') - var_val;
+		tmp = (char *)ast_calloc(len + 1, sizeof(char));
+		input = strncpy(tmp, input, len);
+	} else {
+		len = strlen(input);
+	}
+
+	if (!strchr(input, '=')) {
+		var = (struct ast_variable *)ast_calloc(1, sizeof(struct ast_variable));
+		var->name = (char *)ast_calloc(len + 1 , sizeof(char));
+		var->name = ast_strip(input + offset);
+		var->value = NULL;
+		var->next = NULL;
+		return var;
+	}
+
+	var_len = strchr(input,'=') - input - offset;
+	var = (struct ast_variable *)ast_calloc(1, sizeof(struct ast_variable));
+	var->name = (char *)ast_calloc(var_len + 1, sizeof(char));
+	var->value = (char *)ast_calloc(len - var_len, sizeof(char));
+
+	var->name = ast_strip(strncpy(var->name, input + offset, var_len));
+	var->value = ast_strip(strchr(input, '=') + 1);
+	var->next = NULL;
+     
+	return var;
+}
+
 /* modified for reload support */
 /*! \brief  build_gateway: parse mgcp.conf and create gateway/endpoint structures */
 static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v)
@@ -3548,12 +4385,22 @@
 	struct mgcp_gateway *gw;
 	struct mgcp_endpoint *e;
 	struct mgcp_subchannel *sub;
+	struct rfc3149_ky_functions *e_fk[100], *ky_loop;
+	struct ast_variable *vars, *vars_orig;
+	char *c;
 	/*char txident[80];*/
-	int i=0, y=0;
+	int i = 0, y = 0, fk_num = 0, fk_found = 0, var_num = 0;
 	int gw_reload = 0;
 	int ep_reload = 0;
 	directmedia = DIRECTMEDIA;
 
+	rfc3149_allocate_ky_functions();
+	for(i = 0; i < (sizeof(e_fk) / sizeof(e_fk[0])); i++) {
+		e_fk[i] = (struct rfc3149_ky_functions  *) malloc(sizeof(struct rfc3149_ky_functions));
+		e_fk[i]->enabled = 0;
+		e_fk[i]->state = "db";
+	}
+
 	/* locate existing gateway */
 	gw = gateways;
 	while (gw) {
@@ -3615,6 +4462,52 @@
 				gw->ha = ast_append_ha(v->name, v->value, gw->ha, NULL);
 			} else if (!strcasecmp(v->name, "port")) {
 				gw->addr.sin_port = htons(atoi(v->value));
+			} else if (sscanf(v->name, "fk%d", &fk_num) > 0) {
+				/* Sets particular function to a specified function key - RFC3149 */
+				fk_found = 0; 
+				vars = NULL;
+				vars_orig=NULL;
+				var_num=0;
+				/*ast_verbose("****** Zpracovavam '%s'\n", v->value );*/
+				if (strchr(v->value, ')') && strchr(v->value, '(')) {
+					/* Pick up parameters */
+					c = (char *)ast_calloc(strchr(v->value, ')') - strchr(v->value, '('), sizeof(char));
+					strncpy(c, strchr(v->value, '(') + 1 , strchr(v->value, ')') - strchr(v->value, '(') - 1);
+
+					/*Parse parameters into ast_variable*/
+					vars_orig = (struct ast_variable *)ast_calloc(1, sizeof(struct ast_variable));
+					vars = (struct ast_variable *)ast_calloc(1, sizeof(struct ast_variable));
+					while (strchr(c, ',') || strlen(c) > 0 ) {
+						vars = parse_params(c, 0);
+						vars->next = (struct ast_variable *)ast_calloc(1, sizeof(struct ast_variable));
+						vars->next = vars_orig;
+						vars_orig = vars;
+						if (!strchr(c, ',') && strlen(c) > 0) {
+							break;
+						}
+						c = strchr(c, ',') + 1;
+					}
+
+					/* Pick up function name */
+					c = (char *)ast_calloc(strchr(v->value, '(') - v->value + 1, sizeof(char));
+					v->value = strncpy(c, v->value, strchr(v->value, '(') - v->value);
+				}
+
+				ky_loop = ky_functions;
+				while (ky_loop) {
+					if (!strcasecmp(ky_loop->name, v->value)) {
+						e_fk[fk_num] = ky_loop;
+						e_fk[fk_num]->enabled = 1;
+						e_fk[fk_num]->vars = vars_orig;
+						fk_found = 1;
+					}
+
+					ky_loop = ky_loop->next;
+				}
+
+				if (!fk_found) {
+					ast_log(LOG_WARNING, "Function '%s' has not been implemented yet!\n", v->value );
+				}
 			} else if (!strcasecmp(v->name, "context")) {
 				ast_copy_string(context, v->value, sizeof(context));
 			} else if (!strcasecmp(v->name, "dtmfmode")) {
@@ -3757,6 +4650,9 @@
 					e->onhooktime = time(NULL);
 					/* ASSUME we're onhook */
 					e->hookstate = MGCP_ONHOOK;
+					for (i = 1; i < 100; i++) {
+							e->fk[i] = e_fk[i];
+					}
 					if (!ep_reload) {
 						/*snprintf(txident, sizeof(txident), "%08lx", ast_random());*/
 						for (i = 0; i < MAX_SUBS; i++) {
@@ -3858,6 +4754,10 @@
 					e->slowsequence = slowsequence;
 					e->transfer = transfer;
 					e->threewaycalling = threewaycalling;
+					/* TODO: This is silly way.. needs to fix */
+					for (i = 1; i < 100; i++) {
+						e->fk[i] = e_fk[i];
+					}
 					if (!ep_reload) {
 						e->onhooktime = time(NULL);
 						/* ASSUME we're onhook */
@@ -4067,18 +4967,106 @@
 	ast_mutex_unlock(&gatelock);
 }
 
+int rfc3149_register_xml_function(struct rfc3149_xml_functions *xml_functions, char *xml_deck, char *xml_card, struct ast_variable *vars)
+{
+	struct rfc3149_xml_post_map *dest, *find;
+	ast_verb(3, "Register function '%s' to '%s'->'%s'\n", xml_functions->name, xml_deck, xml_card);
+	dest = (struct rfc3149_xml_post_map *) malloc(sizeof(struct rfc3149_xml_post_map));
+	dest->deck = ast_strip(xml_deck);
+	dest->card = ast_strip(xml_card);
+	dest->func = xml_functions;
+	dest->vars = vars;
+	dest->action = 0;
+	dest->next = NULL;
+
+	if (xml_mapped == NULL) {
+			xml_mapped = dest;
+	} else {
+		find = xml_mapped;
+		while (find) {
+			if (find->next == NULL) {
+				break;
+			}
+			find = find->next;
+		}
+		find->next = dest;
+	}
+	return 1;
+}
+
+int rfc3149_register_xml_action(struct rfc3149_xml_functions *xml_functions, char *action, struct ast_variable *vars)
+{
+	struct rfc3149_xml_post_map *dest,*find;
+	ast_verb(3, "Register action '%s' to '%s'\n", xml_functions->name, action );
+	dest = (struct rfc3149_xml_post_map *) malloc(sizeof(struct rfc3149_xml_post_map));
+	dest->deck = action;
+	dest->func = xml_functions;
+	dest->action=1;
+	dest->vars = vars;
+	dest->next = NULL;
+
+	if (xml_mapped == NULL) {
+		xml_mapped = dest;
+	} else {
+		find = xml_mapped;
+		while (find) {
+			if (find->next == NULL) {
+				break;
+			}
+			find = find->next;
+		}
+		find->next = dest;
+	}
+	return 1;
+}
+
+void rfc3149_allocate_xml_functions(void)
+{
+	struct rfc3149_xml_functions *actual;
+	actual = (struct rfc3149_xml_functions *) malloc(sizeof(struct rfc3149_xml_functions));
+	actual->name = "XML_DND";
+	actual->desc = "Sets DND for a particular endpoint.";
+	actual->p_fc = rfc3149_xml_dnd;
+	xml_functions = actual;
+
+	actual->next = (struct rfc3149_xml_functions *) malloc(sizeof(struct rfc3149_xml_functions));
+	actual = actual->next;
+	actual->name = "XML_milos";
+	actual->desc = "Testing function for a particular endpoint - returns a text.";
+	actual->p_fc = rfc3149_xml_returnka;
+
+	actual->next = (struct rfc3149_xml_functions *) malloc(sizeof(struct rfc3149_xml_functions));
+	actual = actual->next;
+	actual->name = "XML_FWD_ACTIVE";
+	actual->desc = "This function reads inputed data from deck and acording this data it sets up forwardig";
+	actual->p_fc = rfc3149_xml_fwd_active;
+
+	actual->next = (struct rfc3149_xml_functions *) malloc(sizeof(struct rfc3149_xml_functions));
+	actual = actual->next;
+	actual->name = "XML_FWD_DEACTIVE";
+	actual->desc = "Deactivates forwarding when a button on display is pressed.";
+	actual->p_fc = rfc3149_xml_fwd_deactive;
+
+	/* Last pointer */
+	actual->next =  NULL;
+}
+
 static int reload_config(int reload)
 {
 	struct ast_config *cfg;
 	struct ast_variable *v;
 	struct mgcp_gateway *g;
-	struct mgcp_endpoint *e;
-	char *cat;
+	struct mgcp_endpoint *e, *ej;
 	struct ast_hostent ahp;
 	struct hostent *hp;
-	int format;
 	struct ast_flags config_flags = { reload ? CONFIG_FLAG_FILEUNCHANGED : 0 };
-	
+	static struct rfc3149_xml_functions *post;
+	struct ast_variable *vars_orig, *vars;
+	char *cat;
+	char *xml_deck, *xml_card, *xml_func, *disp, *tmpstr;
+	int format, func_found, dec_len;
+
+	rfc3149_allocate_xml_functions();	
 	if (gethostname(ourhost, sizeof(ourhost)-1)) {
 		ast_log(LOG_WARNING, "Unable to get hostname, MGCP disabled\n");
 		return 0;
@@ -4151,6 +5139,109 @@
 		v = v->next;
 	}
 
+	/* Parsing for XML package - RRC3149 */
+	v = ast_variable_browse(cfg, "XML");
+	while (v) {
+
+		if (!strcasecmp(v->name, "action")) {
+			/* This will be handled as XML ACTION */
+			vars_orig = NULL;                             
+			/* Parses action name */
+			dec_len = strstr(v->value, "=>") - v->value;
+			xml_deck = (char *)ast_calloc(dec_len + 1, sizeof(char));
+			ast_copy_string(xml_deck, v->value, dec_len + 1);                
+
+			/* Parses function name with parameters */
+			xml_func = (char *)ast_calloc(strlen(strstr(v->value, "=>") + 2) + 1, sizeof(char));
+			strcpy(xml_func, ast_strip(strstr(v->value, "=>") + 2));                
+
+			if (strchr(xml_func, ')') && strchr(xml_func, '(') ) {
+				xml_card = (char *)ast_calloc(strlen(ast_strip(strstr(xml_func, "(") + 1)), sizeof(char));
+				ast_copy_string(xml_card, ast_strip(strstr(xml_func, "(") + 1), strlen(ast_strip(strstr(xml_func, "(") + 1)));
+				*strstr(xml_func,"(")='\0';
+      
+				vars_orig = (struct ast_variable *)ast_calloc(1, sizeof(struct ast_variable));
+				vars = (struct ast_variable *)ast_calloc(1, sizeof(struct ast_variable));
+				while (strchr(xml_card, ',') || strlen(xml_card) > 0) {
+					vars = parse_params(xml_card, 0);
+					vars->next = (struct ast_variable *)ast_calloc(1, sizeof(struct ast_variable));
+					vars->next = vars_orig;
+					vars_orig = vars;
+					if (!strchr(xml_card, ',') && strlen(xml_card) > 0) {
+						break;
+					}
+					xml_card=strchr(xml_card, ',')+1;
+				}                   
+			}
+			
+			/* Map function with request */
+			func_found = 0;
+			post = xml_functions;
+			while (post) {                         
+				if (!strcasecmp(post->name, xml_func)) {
+					rfc3149_register_xml_action(post, ast_strip(xml_deck), vars_orig);
+					func_found = 1;
+					break;
+				}
+				post = post->next;
+			}
+
+			if (!func_found) {
+				ast_log(LOG_WARNING, "Function '%s' has not been implemented yet!\n", xml_card );
+			} 
+		} else {
+			/* This is normal function assigned to a specific deck&card */
+			vars_orig=NULL;
+			dec_len = strstr(v->value, "=>") - v->value;
+			xml_deck = (char *)ast_calloc(dec_len + 1, sizeof(char));
+			ast_copy_string(xml_deck, v->value, dec_len + 1);
+			v->value = strstr(v->value, "=>") + 2;
+			dec_len = strstr(v->value, "=")-v->value;
+			xml_card = (char *)ast_calloc(dec_len + 1, sizeof(char));
+			ast_copy_string(xml_card, v->value, dec_len+1 );
+
+			v->value=ast_strip(strstr(v->value, "=")+1);
+
+			if (strchr(v->value, ')') && strchr(v->value, '(')) {                  
+				xml_func = (char *)ast_calloc(strstr(v->value, "(") - v->value + 1, sizeof(char));
+				ast_copy_string(xml_func, v->value, strstr(v->value, "(") - v->value + 1);
+				strstr(v->value, "(");
+				tmpstr = (char *)ast_calloc(strlen(strstr(v->value, "(") + 1), sizeof(char));
+				ast_copy_string(tmpstr, strstr(v->value, "(") + 1, strlen(strstr(v->value, "(") + 1));
+
+				vars_orig = (struct ast_variable *)ast_calloc(1, sizeof(struct ast_variable));
+				vars = (struct ast_variable *)ast_calloc(1, sizeof(struct ast_variable));
+				while (strchr(tmpstr, ',') || strlen(tmpstr) > 0) {
+					vars = parse_params(tmpstr, 0);
+					vars->next = (struct ast_variable *)ast_calloc(1, sizeof(struct ast_variable));
+					vars->next = vars_orig;
+					vars_orig = vars;
+					if (!strchr(tmpstr, ',') && strlen(tmpstr) >0) {
+						break;
+					}
+					tmpstr=strchr(tmpstr, ',')+1;
+				}
+			} else {
+				xml_func = (char *)ast_calloc(strlen(v->value) + 1, sizeof(char));
+				strcpy(xml_func, v->value );
+			} 
+
+			func_found=0;post=xml_functions;
+			while (post) {
+				if (!strcasecmp(post->name, ast_strip(xml_func))) {
+					rfc3149_register_xml_function(post, xml_deck, xml_card, vars);
+					func_found = 1;
+					break;
+				}
+				post = post->next;
+			}
+
+			if (!func_found) {
+				ast_log(LOG_WARNING, "Function '%s' has not been implemented yet!\n", xml_func );
+			}
+		}
+			v = v->next;
+	}
 	/* mark existing entries for deletion */
 	ast_mutex_lock(&gatelock);
 	g = gateways;
@@ -4167,15 +5258,27 @@
 	
 	cat = ast_category_browse(cfg, NULL);
 	while(cat) {
-		if (strcasecmp(cat, "general")) {
+		if (strcasecmp(cat, "general") && strcasecmp(cat, "XML")) {
 			ast_mutex_lock(&gatelock);
 			g = build_gateway(cat, ast_variable_browse(cfg, cat));
 			if (g) {
 				ast_verb(3, "Added gateway '%s'\n", g->name);
 				g->next = gateways;
 				gateways = g;
-			}
-			ast_mutex_unlock(&gatelock);
+				e = g->endpoints;
+				while (e) {
+					if (strstr(e->name, "disp/") == NULL) {
+						/*ast_verbose("------Calling ignition for endpoint '%s'\n", e->name);*/
+						e->disp = 0; /* says that this endpoint is not display */
+						transmit_rfc3149_ky_LED_off(e);
+						transmit_rfc3149_ignition(e);
+					} else {
+						e->disp=1; /* says that this endpoint is display */
+					}
+					e = e->next;
+				}
+ 			}
+ 			ast_mutex_unlock(&gatelock);
 
 			/* FS: process queue and IO */
 			if (monitor_thread == pthread_self()) {
@@ -4186,6 +5289,26 @@
 		cat = ast_category_browse(cfg, cat);
 	}
 
+	/* Joins display with telephone */
+	e = g->endpoints;
+	ej = g->endpoints;
+	while (e) {
+		if (e->disp == 0) {
+			disp = (char *)calloc(sizeof(e->name) + 1 + 5, sizeof(char));
+			snprintf(disp, strlen(e->name) + 6, "disp/%s", e->name);
+			ej = g->endpoints;
+			while (ej) {
+				if (!strcasecmp(disp,ej->name)) {
+					/* The display sets address of its telephone and
+					to the telephone it sets address of its display */
+					e->endp = ej;
+					ej->endp = e;
+				}
+				ej = ej->next;
+			}
+		}
+		e = e->next;
+	}
     	/* prune deleted entries etc. */
     	prune_gateways();
 
@@ -4381,6 +5504,247 @@
 	return 0;
 }
 
+/* Endpoint functions implementaion */
+/* Functions for KY package */
+ 
+void rfc3149_indication(struct mgcp_subchannel *sub)
+{
+	struct mgcp_endpoint *p = sub->parent;
+	struct mgcp_request *mr = p->rqnt_queue;
+	struct mgcp_request resp;
+	int i = 0;
+	char *S = "", *subs, *tmp;
+
+	/* Takes S from last request */
+	while (mr) {
+		S = (char *)calloc(MGCP_MAX_PACKET, sizeof(char));
+		subs = (char *)calloc(MGCP_MAX_PACKET, sizeof(char));
+		tmp = (char *)calloc(MGCP_MAX_PACKET, sizeof(char));
+
+		subs = strstr(mr->data, "S:");
+		i=0;
+		while (subs) {
+			tmp=S;
+			sscanf(subs, "S: %s",  S );
+			if (i++ > 0) {
+				snprintf(S, sizeof(S), "%s,%s", tmp, S);
+			}
+			subs = strstr(subs + 2, "S:");
+		}
+		mr = mr->next;
+	}
+
+	reqprep(&resp, p, "RQNT");
+	add_header(&resp, "X", p->rqnt_ident);
+	add_header(&resp, "S", rfc3149_reindicate(p, S));
+
+	switch (sub->parent->hookstate) {
+	case MGCP_ONHOOK:
+		add_header(&resp, "R",  rfc3149_ky_wrap(p, (char *)"L/hd(N)"));
+		break;
+	case MGCP_OFFHOOK:
+		add_header_offhook(sub, &resp);
+		break;
+	}
+	resp.cmd = MGCP_CMD_RQNT;
+	resp.trid = oseq;
+	send_request(p, NULL, &resp, oseq);
+}
+
+
+void rfc3149_fk_set_state(struct mgcp_endpoint *p, char *name,char *state)
+{
+	int i;
+	for (i = 1; i < 100; i++) {
+		if ( p->fk[i]->enabled ) {
+			if (!strcmp(p->fk[i]->name, name )) {
+				p->fk[i]->state=state;
+			}
+		}
+	}
+}
+
+static void rfc3149_ky_dnd(int fk_num, struct mgcp_subchannel *sub, struct ast_variable *vars)
+{
+	struct mgcp_endpoint *p = sub->parent;
+	if (p->dnd) {
+		p->dnd = 0;
+		rfc3149_fk_set_state(p, "FK_DND", "en");
+		ast_verb(3, "Disabled DND on channel %s@%s\n", p->name, p->parent->name);
+	} else {
+		p->dnd = 1;
+		rfc3149_fk_set_state(p, "FK_DND", "dc");
+		ast_verb(3, "Enabled DND on channel %s@%s\n", p->name, p->parent->name);
+	}
+
+	rfc3149_indication(sub);
+}
+
+void rfc3149_conf_pickup(struct ast_variable *var, const char *name, char **value)
+{
+	if (var->name != NULL) {
+		if (!strcasecmp(var->name, name)) {
+			*value = var->value;
+		}
+	}
+}
+
+void rfc3149_ky_forward(int fk_num, struct mgcp_subchannel *sub, struct ast_variable *vars)
+{
+	struct mgcp_endpoint *p = sub->parent;
+	char *deck="forward", *card="input", *bdeck="home", *bcard="home"; /* Default values */
+	
+	ast_verb(4, "Performing call forwarding on channel %s@%s\n", p->name, p->parent->name);
+
+	while (vars) {
+		rfc3149_conf_pickup(vars, "deck", &deck);
+		rfc3149_conf_pickup(vars, "card", &card);
+		rfc3149_conf_pickup(vars, "bcard", &bcard);
+		rfc3149_conf_pickup(vars, "bdeck", &bdeck);
+		vars = vars->next;
+	}
+
+	//ast_verbose("*** routing to>  %s %s\n", deck, card );
+	if (strlen(p->call_forward) == 0) {
+		/* This part sets call forward up */
+		if (p->endp != NULL && p->endp->disp) {
+			/* endpoint has display */
+			transmit_rfc3149_xml( p->endp, rfc3149_create_xml(deck , card , NULL));
+		} else {
+			/* endpoint doesnt have display */
+			ast_copy_string( p->dtmf_buf, "*72", 4 );
+		}
+	} else {
+		/* This part erases call forwarding */
+		transmit_notify_request(sub, "L/sl");
+		/* Erase call_forward & DTMF buffer */
+		memset(p->call_forward, 0, sizeof(p->call_forward));
+		memset(p->dtmf_buf, 0, sizeof(p->dtmf_buf));
+		rfc3149_fk_set_state(p, "FK_Forward", "en");
+		ast_verb(3, "Cancelling call forwarding on channel %s@%s\n", p->name, p->parent->name);
+		rfc3149_indication(sub);
+		if (p->endp != NULL && p->endp->disp) {
+			transmit_rfc3149_xml(p->endp, rfc3149_create_xml(bdeck, bcard, NULL));
+		}
+	}
+}
+
+static void rfc3149_ky_hold(int fk_num, struct mgcp_subchannel *sub, struct ast_variable *vars)
+{
+	struct mgcp_endpoint *p = sub->parent;
+	if (!strcmp(p->fk[fk_num]->state, "ho")) {
+		rfc3149_fk_set_state(p, "FK_Hold", "en");
+	} else {
+		rfc3149_fk_set_state(p, "FK_Hold", "ho");
+	}
+	
+	/*ast_copy_string( p->call_forward, "1000", 5 );*/
+
+}
+
+static void rfc3149_ky_call(int fk_num, struct mgcp_subchannel *sub, struct ast_variable *vars)
+{
+	struct mgcp_endpoint *p = sub->parent;
+	char *num = "";
+
+	while (vars) {
+		rfc3149_conf_pickup(vars , "num", &num);
+		vars = vars->next;
+	}
+
+	ast_verb(3, "Calling on number %s.\n", num);
+	ast_copy_string(p->dtmf_buf, num, strlen(num) + 1);
+}
+
+/* Functions for XML package */
+static void rfc3149_xml_dnd(struct mgcp_subchannel *sub, struct ast_variable *config, struct ast_variable *vars)
+{
+	struct mgcp_endpoint *p = sub->parent->endp, *disp=sub->parent;
+
+	if (p->disp) {
+		p = sub->parent->endp;
+		disp = sub->parent;
+	}
+
+	if (p->dnd) {
+		p->dnd = 0;
+		ast_verb(3, "Disabled DND on channel %s@%s\n", p->name, p->parent->name);
+		rfc3149_fk_set_state(p, "FK_DND", "en");
+	} else {
+		p->dnd = 1;
+		ast_verb(3, "Enabled DND on channel %s@%s\n", p->name, p->parent->name);
+		rfc3149_fk_set_state(p, "FK_DND", "dc");
+	}
+
+	rfc3149_indication(p->sub);
+}
+
+static void rfc3149_xml_returnka(struct mgcp_subchannel *sub, struct ast_variable *config, struct ast_variable *vars)
+{
+	struct mgcp_endpoint *p = sub->parent;
+	struct ast_variable *vars_in = vars;
+
+	ast_verbose("----Predane promene: \n");
+	while (vars_in) {
+		ast_verbose("%s=%s\n", vars_in->name, vars_in->value);
+		vars_in = vars_in->next;
+	}
+
+	ast_verbose("Returnka function is here!!! at '%s' \n", p->name);
+}
+
+static void rfc3149_xml_fwd_active(struct mgcp_subchannel *sub, struct ast_variable *config, struct ast_variable *vars)
+{
+	struct mgcp_endpoint *p = sub->parent;
+	int found = 0;
+	char *deck = "forward", *card = "result";
+
+	while (vars) {
+		if (!strcmp(vars->name, "where")) {
+				found = 1;
+				break;
+		}
+		vars = vars->next;
+	}
+
+	while (config) {            
+		rfc3149_conf_pickup(config , "deck", &deck);
+		rfc3149_conf_pickup(config , "card", &card);
+		config = config->next;
+	}
+
+	if (found) {
+		ast_copy_string( p->endp->call_forward, vars->value, strlen(vars->value)+1 );
+		ast_verb(3, "Setting call forward to '%s' on channel %s@%s\n",  p->endp->call_forward, p->endp->name, p->endp->parent->name);
+		rfc3149_fk_set_state(p, "FK_Forward", "dc");
+		transmit_rfc3149_xml(sub->parent, rfc3149_create_xml(deck, card, vars));
+	}
+
+	/* At last change indication */
+	rfc3149_indication(p->endp->sub);
+}
+
+static void rfc3149_xml_fwd_deactive(struct mgcp_subchannel *sub, struct ast_variable *config, struct ast_variable *vars)
+{
+	struct mgcp_endpoint *p = sub->parent;
+	char *deck = "home", *card = "home";
+
+	while (config) {            
+		rfc3149_conf_pickup(config , "deck", &deck);
+		rfc3149_conf_pickup(config , "card", &card);
+		config = config->next;
+	}
+
+	memset(p->endp->call_forward, 0, sizeof(p->endp->call_forward));
+	memset(p->endp->dtmf_buf, 0, sizeof(p->endp->dtmf_buf));
+	ast_verb(3, "Cancelling call forwarding on channel %s@%s\n", p->endp->name, p->endp->parent->name);
+	transmit_rfc3149_xml(sub->parent, rfc3149_create_xml(deck, card, NULL));
+
+	/* At last change indication */
+	rfc3149_fk_set_state(p, "FK_Forward", "en");
+	rfc3149_indication(p->endp->sub);
+}
+
 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Media Gateway Control Protocol (MGCP)",
 		.load = load_module,
 		.unload = unload_module,
