Browse Source

modules/ims_registrar_pcscf: New features to support P-CSCF subscription and publishing reg event
Migrated pua_reginfo functionality to ims_registrar_pcscf so ims_usrloc_pcscf is used
New features include subscribing to reg event on Registration, processing notifications and publishing when reg event changes

Richard Good 11 năm trước cách đây
mục cha
commit
ddc93ce8a9

+ 421 - 0
modules/ims_registrar_pcscf/notify.c

@@ -0,0 +1,421 @@
+/*
+ * pua_reginfo module - Presence-User-Agent Handling of reg events
+ *
+ * Copyright (C) 2011-2012 Carsten Bock, [email protected]
+ * http://www.ng-voice.com
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ * * History:
+ * ========
+ * 
+ * Nov 2013 Richard Good migrated pua_reginfo funtionality to ims_registrar_pcscf
+ * 
+ */
+
+#include "notify.h"
+#include "reg_mod.h"
+#include "../../parser/parse_from.h"
+#include "../../parser/parse_content.h"
+#include "../../parser/parse_uri.h"
+#include "../../modules/ims_usrloc_pcscf/usrloc.h"
+#include "ul_callback.h"
+#include <libxml/parser.h>
+
+#include "subscribe.h"
+
+#include "../pua/pua_bind.h"
+
+/*<?xml version="1.0"?>
+<reginfo xmlns="urn:ietf:params:xml:ns:reginfo" version="0" state="full">
+.<registration aor="sip:[email protected]" id="0xb33fa860" state="active">
+..<contact id="0xb33fa994" state="active" event="registered" expires="3600">
+...<uri>sip:[email protected]:43582;transport=udp</uri>
+...<unknown-param name="+g.3gpp.cs-voice"></unknown-param>
+...<unknown-param name="+g.3gpp.icsi-ref">urn0X0.0041FB74E7B54P-1022urn-70X0P+03gpp-application.ims.iari.gsma-vs</unknown-param>
+...<unknown-param name="audio"></unknown-param>
+...<unknown-param name="+g.oma.sip-im.large-message"></unknown-param>
+...<unknown-param name="+g.3gpp.smsip"></unknown-param>
+...<unknown-param name="language">en,fr</unknown-param>
+...<unknown-param name="+g.oma.sip-im"></unknown-param>
+...<unknown-param name="expires">600000</unknown-param>
+..</contact>
+.</registration>
+</reginfo> */
+
+#define STATE_ACTIVE 1
+#define STATE_TERMINATED 0
+#define STATE_UNKNOWN -1
+
+#define EVENT_UNKNOWN -1
+#define EVENT_REGISTERED 0
+#define EVENT_UNREGISTERED 1
+#define EVENT_TERMINATED 2
+#define EVENT_CREATED 3
+#define EVENT_REFRESHED 4
+#define EVENT_EXPIRED 5
+
+#define RESULT_ERROR -1
+#define RESULT_CONTACTS_FOUND 1
+
+extern usrloc_api_t ul;
+extern time_t time_now;
+
+int process_contact(udomain_t * _d, int expires, str contact_uri, int contact_state) {
+	
+	pcontact_t* pcontact;
+	
+	struct pcontact_info ci;
+	
+	int local_time_now;
+	int ret = RESULT_CONTACTS_FOUND;
+
+	pcscf_act_time();
+	local_time_now = time_now;
+	
+	//get contact
+	//if does not exist then add it
+	//if it does exist check if state it terminated - if so delete it, if not update it
+	
+	memset(&ci, 0, sizeof(struct pcontact_info));
+	ci.num_public_ids=0;
+	ci.num_service_routes=0;
+	
+	expires = local_time_now + expires;  //turn expires into correct time since epoch format
+	LM_DBG("Changed expires to format time since the epoch: %d", expires);
+	ci.expires=expires;
+	ci.reg_state = PCONTACT_REGISTERED;
+	
+	
+	ul.lock_udomain(_d, &contact_uri);
+	
+	if (ul.get_pcontact(_d, &contact_uri, &pcontact) != 0) { //contact does not exist
+	    if (contact_state == STATE_TERMINATED) {
+		LM_DBG("This contact: <%.*s> is in state terminated and is not in usrloc, ignore\n", contact_uri.len, contact_uri.s);
+		return 1;
+	    }
+		LM_DBG("This contact: <%.*s> is in state active and is not in usrloc so adding it to usrloc, expires: %d which is in %d seconds\n", contact_uri.len, contact_uri.s, expires, expires-local_time_now);
+		if (ul.insert_pcontact(_d, &contact_uri, &ci, &pcontact) != 0) {
+			LM_ERR("Failed inserting new pcontact\n");
+			ret = RESULT_ERROR;
+			goto done;
+		} else {
+			//register for callbacks on this contact so we can send PUBLISH to SCSCF should status change
+			LM_DBG("registering for UL callback\n");
+			ul.register_ulcb(pcontact, PCSCF_CONTACT_DELETE | PCSCF_CONTACT_EXPIRE, callback_pcscf_contact_cb, NULL);
+		}
+	} else {//contact exists
+		if (contact_state == STATE_TERMINATED) {
+			//delete contact
+			LM_DBG("This contact <%.*s> is in state terminated and is in usrloc so removing it from usrloc\n", contact_uri.len, contact_uri.s);
+			if (ul.delete_pcontact(_d, &contact_uri, pcontact) != 0) {
+				LM_DBG("failed to delete pcscf contact <%.*s> - not a problem this may have been removed by de registration", contact_uri.len, contact_uri.s);
+			}
+		}else {//state is active
+			//update this contact
+			LM_DBG("This contact: <%.*s> is in state active and is in usrloc so just updating - old expires: %li, new expires: %i which is in %i seconds\n", contact_uri.len, contact_uri.s,
+									pcontact->expires,
+									expires,
+									expires-local_time_now);
+			if (ul.update_pcontact(_d, &ci, pcontact) != 0) {
+				LM_ERR("failed to update pcscf contact\n");
+				ret = RESULT_ERROR;
+				goto done;
+			}
+			pcontact->expires = expires;
+		}
+	}
+	
+done:	 
+	ul.unlock_udomain(_d, &contact_uri);
+	return ret;
+}
+
+
+int reginfo_parse_state(char * s) {
+	if (s == NULL) {
+		return STATE_UNKNOWN;
+	}
+	switch (strlen(s)) {
+		case 6:
+			if (strncmp(s, "active", 6) ==  0) return STATE_ACTIVE;
+			break;
+		case 10:
+			if (strncmp(s, "terminated", 10) ==  0) return STATE_TERMINATED;
+			break;
+		default:
+			LM_ERR("Unknown State %s\n", s);
+			return STATE_UNKNOWN;
+	}
+	LM_ERR("Unknown State %s\n", s);
+	return STATE_UNKNOWN;
+}
+
+int reginfo_parse_event(char * s) {
+	if (s == NULL) {
+		return EVENT_UNKNOWN;
+	}
+	switch (strlen(s)) {
+		case 7:
+			if (strncmp(s, "created", 7) ==  0) return EVENT_CREATED;
+			if (strncmp(s, "expired", 7) ==  0) return EVENT_EXPIRED;
+			break;
+		case 9:
+			if (strncmp(s, "refreshed", 9) ==  0) return EVENT_CREATED;
+			break;
+		case 10:
+			if (strncmp(s, "registered", 10) ==  0) return EVENT_REGISTERED;
+			if (strncmp(s, "terminated", 10) ==  0) return EVENT_TERMINATED;
+			break;
+		case 12:
+			if (strncmp(s, "unregistered", 12) ==  0) return EVENT_UNREGISTERED;
+			break;
+		default:
+			LM_ERR("Unknown Event %s\n", s);
+			return EVENT_UNKNOWN;
+	}
+	LM_ERR("Unknown Event %s\n", s);
+	return EVENT_UNKNOWN;
+}
+
+xmlNodePtr xmlGetNodeByName(xmlNodePtr parent, const char *name) {
+	xmlNodePtr cur = parent;
+	xmlNodePtr match = NULL;
+	while (cur) {
+		if (xmlStrcasecmp(cur->name, (unsigned char*)name) == 0)
+			return cur;
+		match = xmlGetNodeByName(cur->children, name);
+		if (match)
+			return match;
+		cur = cur->next;
+	}
+	return NULL;
+}
+
+char * xmlGetAttrContentByName(xmlNodePtr node, const char *name) {
+	xmlAttrPtr attr = node->properties;
+	while (attr) {
+		if (xmlStrcasecmp(attr->name, (unsigned char*)name) == 0)
+			return (char*)xmlNodeGetContent(attr->children);
+		attr = attr->next;
+	}
+	return NULL;
+}
+
+int process_body(struct sip_msg* msg, str notify_body, udomain_t * domain) {
+	xmlDocPtr doc= NULL;
+	xmlNodePtr doc_root = NULL, registrations = NULL, contacts = NULL, uris = NULL;
+	str aor = {0, 0};
+	str callid = {0, 0};
+	str contact_uri = {0, 0};
+	str received = {0,0};
+	str path = {0,0};
+	str user_agent = {0, 0};
+	int reg_state, contact_state, event, expires, result, final_result = RESULT_ERROR;
+	char * expires_char,  * cseq_char;
+	int cseq = 0;
+	pv_elem_t *presentity_uri_pv;
+	
+	doc = xmlParseMemory(notify_body.s, notify_body.len);
+	if(doc== NULL)  {
+		LM_ERR("Error while parsing the xml body message, Body is:\n%.*s\n",
+			notify_body.len, notify_body.s);
+		return -1;
+	}
+	doc_root = xmlGetNodeByName(doc->children, "reginfo");
+	if(doc_root == NULL) {
+		LM_ERR("while extracting the reginfo node\n");
+		goto error;
+	}
+	registrations = doc_root->children;
+	while (registrations) {
+		/* Only process registration sub-items */
+		if (xmlStrcasecmp(registrations->name, BAD_CAST "registration") != 0)
+			goto next_registration;
+		reg_state = reginfo_parse_state(xmlGetAttrContentByName(registrations, "state"));
+		if (reg_state == STATE_UNKNOWN) {
+			LM_ERR("No state for this registration!\n");		
+			goto next_registration;
+		}
+		aor.s = xmlGetAttrContentByName(registrations, "aor");
+		if (aor.s == NULL) {
+			LM_ERR("No AOR for this registration!\n");		
+			goto next_registration;
+		}
+		aor.len = strlen(aor.s);
+		LM_DBG("AOR %.*s has reg_state \"%d\"\n", aor.len, aor.s, reg_state);
+		
+		if (reg_state == STATE_TERMINATED) {
+		    //TODO we if there is a IMPU record state here we should delete all contacts associated to it
+		    //Right now we do it go through all the contacts
+		    LM_DBG("AOR %.*s is in state terminated so unsubscribing from reginfo\n", aor.len, aor.s);
+		    if(pv_parse_format(&aor, &presentity_uri_pv)<0) {
+			    LM_ERR("wrong format[%.*s] - failed unsubscribing to reginfo\n",aor.len, aor.s);
+		    }
+		    reginfo_subscribe_real(msg, presentity_uri_pv, 0, 0);
+		}
+		
+		/* Now lets process the Contact's from this Registration: */
+		contacts = registrations->children;
+		while (contacts) {
+			if (xmlStrcasecmp(contacts->name, BAD_CAST "contact") != 0)
+				goto next_contact;
+			callid.s = xmlGetAttrContentByName(contacts, "callid");
+			if (callid.s == NULL) {
+				LM_DBG("No Call-ID for this contact!\n");		
+				callid.len = 0;
+			} else {
+				callid.len = strlen(callid.s);
+				LM_DBG("contact has callid <%.*s>\n", callid.len, callid.s);		
+			}	
+			
+			received.s = xmlGetAttrContentByName(contacts, "received");
+			if (received.s == NULL) {
+				LM_DBG("No received for this contact!\n");
+				received.len = 0;
+			} else {
+				received.len = strlen(received.s);
+				LM_DBG("contact has received <%.*s>\n", received.len, received.s);
+			}
+
+			path.s = xmlGetAttrContentByName(contacts, "path");	
+			if (path.s == NULL) {
+				LM_DBG("No path for this contact!\n");
+				path.len = 0;
+			} else {
+				path.len = strlen(path.s);
+				LM_DBG("contact has path <%.*s>\n", path.len, path.s);
+			}
+
+			user_agent.s = xmlGetAttrContentByName(contacts, "user_agent");
+			if (user_agent.s == NULL) {
+				LM_DBG("No user_agent for this contact!\n");
+				user_agent.len = 0;
+			} else {
+				user_agent.len = strlen(user_agent.s);
+				LM_DBG("contact has user_agent <%.*s>\n", user_agent.len, user_agent.s);
+			}
+			event = reginfo_parse_event(xmlGetAttrContentByName(contacts, "event"));
+			if (event == EVENT_UNKNOWN) {
+				LM_ERR("No event for this contact - going to next contact!\n");		
+				goto next_contact;
+			}
+			expires_char = xmlGetAttrContentByName(contacts, "expires");
+			if (expires_char == NULL) {
+				LM_ERR("No expires for this contact - going to next contact!\n");		
+				goto next_contact;
+			}
+			expires = atoi(expires_char);
+			if (expires < 0) {
+				LM_ERR("No valid expires for this contact - going to next contact!\n");		
+				goto next_contact;
+			}
+			
+			contact_state = reginfo_parse_state(xmlGetAttrContentByName(contacts, "state"));
+			if (contact_state == STATE_UNKNOWN) {
+			    LM_ERR("No state for this contact - going to next contact!\n");		
+			    goto next_contact;
+			} 
+			
+			LM_DBG("Contact state %d: Event \"%d\", expires %d\n", contact_state, event, expires);
+
+			
+			
+			cseq_char = xmlGetAttrContentByName(contacts, "cseq");
+			if (cseq_char == NULL) {
+				LM_DBG("No cseq for this contact!\n");		
+			} else {
+				cseq = atoi(cseq_char);
+				if (cseq < 0) {
+					LM_DBG("No valid cseq for this contact!\n");		
+				}
+			}
+
+			/* Now lets process the URI's from this Contact: */
+			uris = contacts->children;
+			while (uris) {
+				if (xmlStrcasecmp(uris->name, BAD_CAST "uri") != 0)
+					goto next_uri;
+				contact_uri.s = (char*)xmlNodeGetContent(uris);	
+				if (contact_uri.s == NULL) {
+					LM_ERR("No URI for this contact - going to next registration!\n");		
+					goto next_registration;
+				}
+				contact_uri.len = strlen(contact_uri.s);
+				LM_DBG("Contact: %.*s\n",
+					contact_uri.len, contact_uri.s);
+
+				/* Add to Usrloc: */
+				result = process_contact(domain, expires, contact_uri, contact_state);
+
+				/* Process the result */
+				if (final_result != RESULT_CONTACTS_FOUND) final_result = result;
+next_uri:
+				uris = uris->next;
+			}
+next_contact:
+			contacts = contacts->next;
+		}
+		
+next_registration:
+		// if (ul_record) ul.release_urecord(ul_record);		
+		/* Unlock the domain for this AOR: */
+		//if (aor_key.len > 0)
+		//	ul.unlock_udomain(domain, &aor_key);
+
+		registrations = registrations->next;
+	}
+error:
+	/* Free the XML-Document */
+    	if(doc) xmlFreeDoc(doc);
+	return final_result;
+}
+
+
+
+int reginfo_handle_notify(struct sip_msg* msg, char* domain, char* s2) {
+	
+	LM_DBG("Handling notify\n");
+	str body;
+	int result = 1;
+
+  	/* If not done yet, parse the whole message now: */
+  	if (parse_headers(msg, HDR_EOH_F, 0) == -1) {
+  		LM_ERR("Error parsing headers\n");
+  		return -1;
+  	}
+	if (get_content_length(msg) == 0) {
+   		LM_DBG("Content length = 0\n");
+		/* No Body? Then there is no published information available, which is ok. */
+   		return 1;
+   	} else {
+   		body.s=get_body(msg);
+   		if (body.s== NULL) {
+   			LM_ERR("cannot extract body from msg\n");
+   			return -1;
+   		}
+   		body.len = get_content_length(msg);
+   	}
+
+	LM_DBG("Body is %.*s\n", body.len, body.s);
+	
+	result = process_body(msg, body, (udomain_t*)domain);
+
+	
+	return result;
+}
+

+ 37 - 0
modules/ims_registrar_pcscf/notify.h

@@ -0,0 +1,37 @@
+/*
+ * pua_reginfo module - Presence-User-Agent Handling of reg events
+ *
+ * Copyright (C) 2011 Carsten Bock, [email protected]
+ * http://www.ng-voice.com
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ * * History:
+ * ========
+ * 
+ * Nov 2013 Richard Good migrated pua_reginfo funtionality to ims_registrar_pcscf
+ * 
+ */
+
+#ifndef NOTIFY_H
+#define NOTIFY_H
+
+#include "../../parser/msg_parser.h"
+
+int reginfo_handle_notify(struct sip_msg*, char*, char*);
+
+#endif

+ 45 - 26
modules/ims_registrar_pcscf/reg_mod.c

@@ -60,7 +60,8 @@
 #include "../../mod_fix.h"
 
 /* Bindings to PUA */
-//#include "../../modules_k/pua/pua_bind.h"
+#include "../pua/pua_bind.h"
+#include "notify.h"
 
 #include "reg_mod.h"
 #include "save.h"
@@ -71,8 +72,11 @@ MODULE_VERSION
 usrloc_api_t ul;						/**!< Structure containing pointers to usrloc functions*/
 sl_api_t slb;							/**!< SL API structure */
 struct tm_binds tmb;					/**!< TM API structure */
-//pua_api_t pua; 							/**!< PUA API structure */
+pua_api_t pua; 							/**!< PUA API structure */
 
+int publish_reginfo = 0;
+int subscribe_to_reginfo = 0;
+int subscription_expires = 3600;
 
 time_t time_now;
 char * pcscf_uri = "sip:pcscf.ims.smilecoms.com:4060";
@@ -97,6 +101,7 @@ static int w_save_pending(struct sip_msg* _m, char* _d, char* _cflags);
 static int w_follows_service_routes(struct sip_msg* _m, char* _d, char* _foo);
 static int w_force_service_routes(struct sip_msg* _m, char* _d, char* _foo);
 static int w_is_registered(struct sip_msg* _m, char* _d, char* _foo);
+static int w_reginfo_handle_notify(struct sip_msg* _m, char* _d, char* _foo);
 
 static int w_assert_identity(struct sip_msg* _m, char* _d, char* _preferred_uri);
 
@@ -130,6 +135,8 @@ static cmd_export_t cmds[] = {
 
 	{"pcscf_assert_identity", (cmd_function)w_assert_identity,      2,  	assert_identity_fixup, 	0,		REQUEST_ROUTE },
 
+	{"reginfo_handle_notify", (cmd_function)w_reginfo_handle_notify, 1, domain_fixup, 0, REQUEST_ROUTE},
+	
 	{0, 0, 0, 0, 0, 0}
 };
 
@@ -144,11 +151,12 @@ static param_export_t params[] = {
 	{"received_avp",       STR_PARAM, &rcv_avp_param       					},
 
 	{"is_registered_fallback2ip",	INT_PARAM, &is_registered_fallback2ip	},
+	
+	{"publish_reginfo", INT_PARAM, &publish_reginfo},
+        {"subscribe_to_reginfo", INT_PARAM, &subscribe_to_reginfo},
+        {"subscription_expires",INT_PARAM, &subscription_expires        },
 
 
-//	{"ims_mode",           INT_PARAM, &registrar_ims_mode                  	}, /* 0-PCSCF ; 1-SCSCF */
-//	{"subscription_max_expires",INT_PARAM, &subscription_max_expires       	},
-//	{"subscription_min_expires",INT_PARAM, &subscription_min_expires       	},
 //	{"store_profile_dereg",	INT_PARAM, &store_data_on_dereg},
 	{0, 0, 0}
 };
@@ -217,7 +225,7 @@ int fix_parameters() {
  */
 static int mod_init(void) {
 	bind_usrloc_t bind_usrloc;
-//	bind_pua_t bind_pua;
+	bind_pua_t bind_pua;
 
 	if (!fix_parameters()) goto error;
 
@@ -246,26 +254,32 @@ static int mod_init(void) {
 	}
 	LM_DBG("Successfully bound to PCSCF Usrloc module\n");
 
-	/* Bind to PUA: */
-//	bind_pua = (bind_pua_t) find_export("bind_pua", 1, 0);
-//	if (!bind_pua) {
-//		LM_ERR("Can't bind pua\n");
-//		return -1;
-//	}
-//	if (bind_pua(&pua) < 0) {
-//		LM_ERR("Can't bind pua\n");
-//		return -1;
-//	}
-//	/* Check for Publish/Subscribe methods */
-//	if (pua.send_publish == NULL) {
-//		LM_ERR("Could not import send_publish\n");
-//		return -1;
-//	}
-//	if (pua.send_subscribe == NULL) {
-//		LM_ERR("Could not import send_subscribe\n");
-//		return -1;
-//	}
-//	LM_DBG("Successfully bound to PUA module\n");
+       if(subscribe_to_reginfo == 1){
+               /* Bind to PUA: */
+               bind_pua = (bind_pua_t) find_export("bind_pua", 1, 0);
+               if (!bind_pua) {
+                       LM_ERR("Can't bind pua\n");
+                       return -1;
+               }
+               if (bind_pua(&pua) < 0) {
+                       LM_ERR("Can't bind pua\n");
+                       return -1;
+               }
+               /* Check for Publish/Subscribe methods */
+               if (pua.send_publish == NULL) {
+                       LM_ERR("Could not import send_publish\n");
+                       return -1;
+               }
+               if (pua.send_subscribe == NULL) {
+                       LM_ERR("Could not import send_subscribe\n");
+                       return -1;
+               }
+	       if (pua.get_subs_list == NULL) {
+                       LM_ERR("Could not import get_subs_list\n");
+                       return -1;
+               }
+	       LM_DBG("Successfully bound to PUA module\n");
+       }
 
 	return 0;
 
@@ -379,6 +393,11 @@ static int w_is_registered(struct sip_msg* _m, char* _d, char* _foo)
 	return is_registered(_m, (udomain_t*)_d);
 }
 
+static int w_reginfo_handle_notify(struct sip_msg* _m, char* _d, char* _foo)
+{
+       return reginfo_handle_notify(_m, _d, _foo);
+}
+
 static int w_assert_identity(struct sip_msg* _m, char* _d, char* _preferred_uri) {
 	pv_elem_t *model;
 	str identity;

+ 53 - 3
modules/ims_registrar_pcscf/save.c

@@ -47,11 +47,17 @@
 #include "save.h"
 #include "reg_mod.h"
 #include "ul_callback.h"
+#include "subscribe.h"
+
+#include "../pua/pua_bind.h"
 
 extern struct tm_binds tmb;
 extern usrloc_api_t ul;
 extern time_t time_now;
 extern unsigned int pending_reg_expires;
+extern int subscribe_to_reginfo;
+extern int subscription_expires;
+extern pua_api_t pua;
 
 struct sip_msg* get_request_from_reply(struct sip_msg* reply)
 {
@@ -148,6 +154,11 @@ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udoma
 
 				ul.lock_udomain(_d, &c->uri);
 				if (ul.get_pcontact(_d, &c->uri, &pcontact) != 0) { //need to insert new contact
+					if ((expires-local_time_now)<=0) { //remove contact - de-register
+						LM_DBG("This is a de-registration for contact <%.*s> but contact is not in usrloc - ignore\n", c->uri.len, c->uri.s);
+						goto next_contact;
+					} 
+				    
 					LM_DBG("Adding pcontact: <%.*s>, expires: %d which is in %d seconds\n", c->uri.len, c->uri.s, expires, expires-local_time_now);
 
 					// Received Info: First try AVP, otherwise simply take the source of the request:
@@ -199,6 +210,7 @@ static inline int update_contacts(struct sip_msg *req,struct sip_msg *rpl, udoma
 						pcontact->expires = expires;
 					}
 				}
+next_contact:
 				ul.unlock_udomain(_d, &c->uri);
 			}
 	}
@@ -324,7 +336,8 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags) {
 	int num_public_ids = 0;
 	str *service_routes=0;
 	int num_service_routes = 0;
-
+	pv_elem_t *presentity_uri_pv;
+	
 	//get request from reply
 	req = get_request_from_reply(_m);
 	if (!req) {
@@ -346,8 +359,45 @@ int save(struct sip_msg* _m, udomain_t* _d, int _cflags) {
 		goto error;
 	}
 
-	//TODO: we need to subscribe to SCSCF for reg events on the impu!
-
+	if(subscribe_to_reginfo == 1){
+	    
+	    //use the first p_associated_uri - i.e. the default IMPU
+	    LM_DBG("Subscribe to reg event for primary p_associated_uri");
+	    if(num_public_ids > 0){
+		//find the first routable (not a tel: URI and use that that presentity)
+		//if you can not find one then exit
+		int i = 0;
+		int found_presentity_uri=0;
+		while (i < num_public_ids && found_presentity_uri == 0)
+		{
+		    //check if public_id[i] is NOT a tel URI - if it isn't then concert to pv format and set found presentity_uri to 1
+		    if (strncasecmp(public_ids[i].s,"tel:",4)==0) {
+			LM_DBG("This is a tel URI - it is not routable so we don't use it to subscribe");
+			i++;
+		    }
+		    else {
+			//convert primary p_associated_uri to pv_elem_t
+			if(pv_parse_format(&public_ids[i], &presentity_uri_pv)<0) {
+				LM_ERR("wrong format[%.*s]\n",public_ids[i].len, public_ids[i].s);
+				goto error;
+			}
+			found_presentity_uri=1;
+		    }
+		}
+		if(found_presentity_uri!=1){
+		    LM_ERR("Could not find routable URI in p_assoiated_uri list - failed to subscribe");
+		    goto error;
+		}
+	    }else{
+		//Now some how check if there is a pua record and what the presentity uri is from there - if nothing there
+		LM_DBG("No p_associated_uri in 200 OK this must be a de-register - we ignore this - will unsubscribe when the notify is received");
+		goto done;
+		
+	    }
+	    reginfo_subscribe_real(_m, presentity_uri_pv, service_routes, subscription_expires);
+	}
+    
+done:
 	if (public_ids && public_ids->s) pkg_free(public_ids);
 	if (service_routes && service_routes->s) pkg_free(service_routes);
 	return 1;

+ 106 - 0
modules/ims_registrar_pcscf/subscribe.c

@@ -0,0 +1,106 @@
+/*
+ * pua_reginfo module - Presence-User-Agent Handling of reg events
+ *
+ * Copyright (C) 2011 Carsten Bock, [email protected]
+ * http://www.ng-voice.com
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ * * History:
+ * ========
+ * 
+ * Nov 2013 Richard Good migrated pua_reginfo funtionality to ims_registrar_pcscf
+ */
+
+#include "subscribe.h"
+
+#include "../pua/send_subscribe.h"
+#include "../pua/pua.h"
+
+#include "../pua/pua_bind.h"
+
+
+extern pua_api_t pua;
+extern char* pcscf_uri;
+
+#define P_ASSERTED_IDENTITY_HDR_PREFIX	"P-Asserted-Identity: <"
+
+int reginfo_subscribe_real(struct sip_msg* msg, pv_elem_t* uri, str* service_routes, int expires) {
+	str uri_str = {0, 0};
+	char uri_buf[512];
+	int uri_buf_len = 512;
+	subs_info_t subs;
+	str server_address = {pcscf_uri, strlen(pcscf_uri)};
+	str p_asserted_identity_header;
+	
+	int len = strlen(P_ASSERTED_IDENTITY_HDR_PREFIX) + server_address.len + 1 + CRLF_LEN;
+	p_asserted_identity_header.s = (char *)pkg_malloc( len );
+	if ( p_asserted_identity_header.s == NULL ) {
+	    LM_ERR( "insert_asserted_identity: pkg_malloc %d bytes failed", len );
+	    return -1;
+	}
+
+	memcpy(p_asserted_identity_header.s, P_ASSERTED_IDENTITY_HDR_PREFIX, strlen(P_ASSERTED_IDENTITY_HDR_PREFIX));
+	p_asserted_identity_header.len = strlen(P_ASSERTED_IDENTITY_HDR_PREFIX);
+	memcpy(p_asserted_identity_header.s + p_asserted_identity_header.len, server_address.s, server_address.len);
+	p_asserted_identity_header.len += server_address.len;
+	*(p_asserted_identity_header.s + p_asserted_identity_header.len) = '>';
+	p_asserted_identity_header.len ++;
+	memcpy( p_asserted_identity_header.s + p_asserted_identity_header.len, CRLF, CRLF_LEN );
+	p_asserted_identity_header.len += CRLF_LEN;
+	
+	if (pv_printf(msg, uri, uri_buf, &uri_buf_len) < 0) {
+		LM_ERR("cannot print uri into the format\n");
+		if (p_asserted_identity_header.s) {
+                    pkg_free(p_asserted_identity_header.s);
+                }
+		return -1;
+	}
+	uri_str.s = uri_buf;
+	uri_str.len = uri_buf_len;
+	
+	LM_DBG("p_asserted_identity_header: [%.*s]", p_asserted_identity_header.len, p_asserted_identity_header.s);
+
+	LM_DBG("Subscribing to %.*s\n", uri_str.len, uri_str.s);
+
+	memset(&subs, 0, sizeof(subs_info_t));
+
+	subs.remote_target = &uri_str;
+	subs.pres_uri= &uri_str;
+	subs.watcher_uri= &server_address;
+	subs.expires = expires;
+
+	subs.source_flag= REGINFO_SUBSCRIBE;
+	subs.event= REGINFO_EVENT;
+	subs.contact= &server_address;
+	subs.extra_headers = &p_asserted_identity_header;
+	
+	subs.flag|= UPDATE_TYPE;
+	
+	if(pua.send_subscribe(&subs)< 0) {
+		LM_ERR("while sending subscribe\n");
+	}	
+	
+	if (p_asserted_identity_header.s) {
+		pkg_free(p_asserted_identity_header.s);
+	}
+
+	return 1;
+}
+
+
+

+ 41 - 0
modules/ims_registrar_pcscf/subscribe.h

@@ -0,0 +1,41 @@
+/*
+ * pua_reginfo module - Presence-User-Agent Handling of reg events
+ *
+ * Copyright (C) 2011 Carsten Bock, [email protected]
+ * http://www.ng-voice.com
+ *
+ * This file is part of Kamailio, a free SIP server.
+ *
+ * Kamailio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version
+ *
+ * Kamailio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License 
+ * along with this program; if not, write to the Free Software 
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * 
+ * * History:
+ * ========
+ * 
+ * Nov 2013 Richard Good migrated pua_reginfo funtionality to ims_registrar_pcscf
+ * 
+ */
+
+#ifndef SUBSCRIBE_H
+#define SUBSCRIBE_H
+
+#include "../../pvar.h"
+#include "../../parser/msg_parser.h"
+
+
+
+
+int reginfo_subscribe_real(struct sip_msg* msg, pv_elem_t* uri, str* service_routes, int expires);
+
+#endif

+ 220 - 157
modules/ims_registrar_pcscf/ul_callback.c

@@ -44,163 +44,221 @@
  */
 
 #include "ul_callback.h"
-//#include "../../modules_k/pua/pua.h"
-//#include "../../modules_k/pua/send_publish.h"
+#include "../pua/pua.h"
+#include "../pua/send_publish.h"
+
+#include "../pua/pua_bind.h"
+
 #include <libxml/parser.h>
 
+/*
+Contact: <sip:[email protected]:44733;transport=udp>;expires=600000;+g.oma.sip-im;language="en,fr";+g.3gpp.smsip;+g.oma.sip-im.large-message;audio;+g.3gpp.icsi-ref="urn%3Aurn-7%3A3gpp-application.ims.iari.gsma-vs";+g.3gpp.cs-voice.
+Call-ID: 9ad9f89f-164d-bb86-1072-52e7e9eb5025.
+*/
+
+/*<?xml version="1.0"?>
+<reginfo xmlns="urn:ietf:params:xml:ns:reginfo" version="0" state="full">
+.<registration aor="sip:[email protected]" id="0xb33fa860" state="active">
+..<contact id="0xb33fa994" state="active" event="registered" expires="3600">
+...<uri>sip:[email protected]:43582;transport=udp</uri>
+...<unknown-param name="+g.3gpp.cs-voice"></unknown-param>
+...<unknown-param name="+g.3gpp.icsi-ref">urn0X0.0041FB74E7B54P-1022urn-70X0P+03gpp-application.ims.iari.gsma-vs</unknown-param>
+...<unknown-param name="audio"></unknown-param>
+...<unknown-param name="+g.oma.sip-im.large-message"></unknown-param>
+...<unknown-param name="+g.3gpp.smsip"></unknown-param>
+...<unknown-param name="language">en,fr</unknown-param>
+...<unknown-param name="+g.oma.sip-im"></unknown-param>
+...<unknown-param name="expires">600000</unknown-param>
+..</contact>
+.</registration>
+</reginfo> */
+
+extern pua_api_t pua;
+extern char* pcscf_uri;
+extern int publish_reginfo;
+
 /* methods for building reg publish */
-//str* build_reginfo_partial(ppublic_t *impu, struct pcontact* c, int type) {
-//	xmlDocPtr doc = NULL;
-//	xmlNodePtr root_node = NULL;
-//	xmlNodePtr registration_node = NULL;
-//	xmlNodePtr contact_node = NULL;
-//	xmlNodePtr uri_node = NULL;
-//	str * body = NULL;
-//	struct pcontact * ptr;
-//	char buf[512];
-//	int buf_len;
-//	int reg_active = 0;
-//	time_t cur_time = time(0);
-//
-//	/* create the XML-Body */
-//	doc = xmlNewDoc(BAD_CAST "1.0");
-//	if (doc == 0) {
-//		LM_ERR("Unable to create XML-Doc\n");
-//		return NULL;
-//	}
-//
-//	root_node = xmlNewNode(NULL, BAD_CAST "reginfo");
-//	if (root_node == 0) {
-//		LM_ERR("Unable to create reginfo-XML-Element\n");
-//		return NULL;
-//	}
-//	/* This is our Root-Element: */
-//	xmlDocSetRootElement(doc, root_node);
-//
-//	xmlNewProp(root_node, BAD_CAST "xmlns", BAD_CAST "urn:ietf:params:xml:ns:reginfo");
-//
-//	/* we set the version to 0 but it should be set to the correct value in the pua module */
-//	xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "0");
-//	xmlNewProp(root_node, BAD_CAST "state", BAD_CAST "partial" );
-//
-//	/* Registration Node */
-//	registration_node = xmlNewChild(root_node, NULL, BAD_CAST "registration", NULL);
-//	if (registration_node == NULL) {
-//		LM_ERR("while adding child\n");
-//		goto error;
-//	}
-//
-//	/* Add the properties to this Node for AOR and ID: */
-//	xmlNewProp(registration_node, BAD_CAST "aor", BAD_CAST impu->public_identity.s);
-//	buf_len = snprintf(buf, sizeof(buf), "%p", impu);
-//	xmlNewProp(registration_node, BAD_CAST "id", BAD_CAST buf);
-//
-//
-//	//now the updated contact
-//	contact_node =xmlNewChild(registration_node, NULL, BAD_CAST "contact", NULL);
-//	if (contact_node == NULL) {
-//		LM_ERR("while adding child\n");
-//		goto error;
-//	}
-//	memset(buf, 0, sizeof(buf));
-//	buf_len = snprintf(buf, sizeof(buf), "%p", c);
-//	xmlNewProp(contact_node, BAD_CAST "id", BAD_CAST buf);
-//
-//	//TODO: this needs to be dependent on state
-//	xmlNewProp(contact_node, BAD_CAST "state", BAD_CAST "terminated");
-//	xmlNewProp(contact_node, BAD_CAST "event", BAD_CAST "unregistered");
-//	memset(buf, 0, sizeof(buf));
-//    //buf_len = snprintf(buf, sizeof(buf), "%i", (int)(ptr->expires-cur_time));
-//    //xmlNewProp(contact_node, BAD_CAST "expires", BAD_CAST buf);
-//
-//	/* URI-Node */
-//	memset(buf, 0, sizeof(buf));
-//	buf_len = snprintf(buf, sizeof(buf), "%.*s", c->aor.len, c->aor.s);
-//	uri_node = xmlNewChild(contact_node, NULL, BAD_CAST "uri", BAD_CAST buf);
-//	if (uri_node == NULL) {
-//		LM_ERR("while adding child\n");
-//		goto error;
-//	}
-//
-//	/* create the body */
-//	body = (str*) pkg_malloc(sizeof(str));
-//	if (body == NULL) {
-//		LM_ERR("while allocating memory\n");
-//		return NULL;
-//	}
-//	memset(body, 0, sizeof(str));
-//
-//	/* Write the XML into the body */
-//	xmlDocDumpFormatMemory(doc, (unsigned char**) (void*) &body->s, &body->len,
-//			1);
-//
-//	/*free the document */
-//	xmlFreeDoc(doc);
-//	xmlCleanupParser();
-//
-//	return body;
-//
-//error:
-//	if (body) {
-//		if (body->s)
-//			xmlFree(body->s);
-//		pkg_free(body);
-//	}
-//	if (doc)
-//		xmlFreeDoc(doc);
-//	return NULL;
-//
-//}
-//
-//int send_partial_publish(ppublic_t *impu, struct pcontact *c, int type)
-//{
-//	publ_info_t publ;
-//    str content_type;
-//    int id_buf_len;
-//    char id_buf[512];
-//
-//    content_type.s = "application/reginfo+xml";
-//    content_type.len = 23;
-//
-//	LM_DBG("Sending publish\n");
-//	str *body = build_reginfo_partial(impu, c, type);
-//
-//	if (body == NULL || body->s == NULL) {
-//		LM_ERR("Error on creating XML-Body for publish\n");
-//		goto error;
-//	}
-//	LM_DBG("XML-Body:\n%.*s\n", body->len, body->s);
-//
-//	memset(&publ, 0, sizeof(publ_info_t));
-//	publ.pres_uri = &impu->public_identity;
-//	publ.body = body;
-//	id_buf_len = snprintf(id_buf, sizeof(id_buf), "IMSPCSCF_PUBLISH.%.*s", c->aor.len, c->aor.s);
-//	publ.id.s = id_buf;
-//	publ.id.len = id_buf_len;
-//	publ.content_type = content_type;
-//	publ.expires = 3600;
-//
-//	/* make UPDATE_TYPE, as if this "publish dialog" is not found
-//	 by pua it will fallback to INSERT_TYPE anyway */
-//	publ.flag |= UPDATE_TYPE;
-//	publ.source_flag |= REGINFO_PUBLISH;
-//	publ.event |= REGINFO_EVENT;
-//	publ.extra_headers = NULL;
-//
-//	if (pua.send_publish(&publ) < 0) {
-//		LM_ERR("Error while sending publish\n");
-//	}
-//
-//	return 1;
-//
-//error:
-//	if (body) {
-//		if (body->s)
-//			xmlFree(body->s);
-//		pkg_free(body);
-//	}
-//	return -1;
-//}
+str* build_reginfo_partial(ppublic_t *impu, struct pcontact* c, int type) {
+	xmlDocPtr doc = NULL;
+	xmlNodePtr root_node = NULL;
+	xmlNodePtr registration_node = NULL;
+	xmlNodePtr contact_node = NULL;
+	xmlNodePtr uri_node = NULL;
+	str * body = NULL;
+	char buf[512];
+
+	/* create the XML-Body */
+	doc = xmlNewDoc(BAD_CAST "1.0");
+	if (doc == 0) {
+		LM_ERR("Unable to create XML-Doc\n");
+		return NULL;
+	}
+
+	root_node = xmlNewNode(NULL, BAD_CAST "reginfo");
+	if (root_node == 0) {
+		LM_ERR("Unable to create reginfo-XML-Element\n");
+		return NULL;
+	}
+	/* This is our Root-Element: */
+	xmlDocSetRootElement(doc, root_node);
+
+	xmlNewProp(root_node, BAD_CAST "xmlns", BAD_CAST "urn:ietf:params:xml:ns:reginfo");
+
+	/* we set the version to 0 but it should be set to the correct value in the pua module */
+	xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "0");
+	xmlNewProp(root_node, BAD_CAST "state", BAD_CAST "partial" );
+
+	/* Registration Node */
+	registration_node = xmlNewChild(root_node, NULL, BAD_CAST "registration", NULL);
+	if (registration_node == NULL) {
+		LM_ERR("while adding child\n");
+		goto error;
+	}
+
+	/* Add the properties to this Node for AOR and ID: */
+	//registration aor nodes
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf), "%.*s", impu->public_identity.len, impu->public_identity.s);
+	xmlNewProp(registration_node, BAD_CAST "aor", BAD_CAST buf);
+	
+	//registration id
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf), "%p", impu);
+	xmlNewProp(registration_node, BAD_CAST "id", BAD_CAST buf);
+
+	//now the updated contact
+	contact_node =xmlNewChild(registration_node, NULL, BAD_CAST "contact", NULL);
+	if (contact_node == NULL) {
+		LM_ERR("while adding child\n");
+		goto error;
+	}
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf), "%p", c);
+	xmlNewProp(contact_node, BAD_CAST "id", BAD_CAST buf);
+
+	//TODO: currently we only support publish of termination for event unregistered and expires 0
+	xmlNewProp(contact_node, BAD_CAST "state", BAD_CAST "terminated");
+	xmlNewProp(contact_node, BAD_CAST "event", BAD_CAST "unregistered");
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf), "%i", 0);
+	xmlNewProp(contact_node, BAD_CAST "expires", BAD_CAST buf);
+
+	/* URI-Node */
+	memset(buf, 0, sizeof(buf));
+	snprintf(buf, sizeof(buf), "%.*s", c->aor.len, c->aor.s);
+	uri_node = xmlNewChild(contact_node, NULL, BAD_CAST "uri", BAD_CAST buf);
+	if (uri_node == NULL) {
+		LM_ERR("while adding child\n");
+		goto error;
+	}
+
+	/* create the body */
+	body = (str*) pkg_malloc(sizeof(str));
+	if (body == NULL) {
+		LM_ERR("while allocating memory\n");
+		return NULL;
+	}
+	memset(body, 0, sizeof(str));
+
+	/* Write the XML into the body */
+	xmlDocDumpFormatMemory(doc, (unsigned char**) (void*) &body->s, &body->len,
+			1);
+
+	/*free the document */
+	xmlFreeDoc(doc);
+	xmlCleanupParser();
+
+	return body;
+
+error:
+	if (body) {
+		if (body->s)
+			xmlFree(body->s);
+		pkg_free(body);
+	}
+	if (doc)
+		xmlFreeDoc(doc);
+	return NULL;
+
+}
+
+#define P_ASSERTED_IDENTITY_HDR_PREFIX	"P-Asserted-Identity: <"
+int send_partial_publish(ppublic_t *impu, struct pcontact *c, int type)
+{
+	publ_info_t publ;
+	str content_type;
+	int id_buf_len;
+	char id_buf[512];
+	str server_address = {pcscf_uri, strlen(pcscf_uri)};
+	str p_asserted_identity_header;
+
+	content_type.s = "application/reginfo+xml";
+	content_type.len = 23;
+	
+	int len = strlen(P_ASSERTED_IDENTITY_HDR_PREFIX) + server_address.len + 1 + CRLF_LEN;
+	p_asserted_identity_header.s = (char *)pkg_malloc( len );
+	if ( p_asserted_identity_header.s == NULL ) {
+	    LM_ERR( "insert_asserted_identity: pkg_malloc %d bytes failed", len );
+	    goto error;
+	}
+	
+	memcpy(p_asserted_identity_header.s, P_ASSERTED_IDENTITY_HDR_PREFIX, strlen(P_ASSERTED_IDENTITY_HDR_PREFIX));
+	p_asserted_identity_header.len = strlen(P_ASSERTED_IDENTITY_HDR_PREFIX);
+	memcpy(p_asserted_identity_header.s + p_asserted_identity_header.len, server_address.s, server_address.len);
+	p_asserted_identity_header.len += server_address.len;
+	*(p_asserted_identity_header.s + p_asserted_identity_header.len) = '>';
+	p_asserted_identity_header.len ++;
+	memcpy( p_asserted_identity_header.s + p_asserted_identity_header.len, CRLF, CRLF_LEN );
+	p_asserted_identity_header.len += CRLF_LEN;
+	
+	LM_DBG("p_asserted_identity_header: [%.*s]", p_asserted_identity_header.len, p_asserted_identity_header.s);
+	
+	LM_DBG("Sending publish\n");
+	str *body = build_reginfo_partial(impu, c, type);
+
+	if (body == NULL || body->s == NULL) {
+		LM_ERR("Error on creating XML-Body for publish\n");
+		goto error;
+	}
+	LM_DBG("XML-Body:\n%.*s\n", body->len, body->s);
+
+	memset(&publ, 0, sizeof(publ_info_t));
+	publ.pres_uri = &impu->public_identity;
+	publ.body = body;
+	id_buf_len = snprintf(id_buf, sizeof(id_buf), "IMSPCSCF_PUBLISH.%.*s", c->aor.len, c->aor.s);
+	publ.id.s = id_buf;
+	publ.id.len = id_buf_len;
+	publ.content_type = content_type;
+	publ.expires = 3600;
+
+	/* make UPDATE_TYPE, as if this "publish dialog" is not found
+	 by pua it will fallback to INSERT_TYPE anyway */
+	publ.flag |= UPDATE_TYPE;
+	publ.source_flag |= REGINFO_PUBLISH;
+	publ.event |= REGINFO_EVENT;
+	publ.extra_headers = &p_asserted_identity_header;
+
+	if (pua.send_publish(&publ) < 0) {
+		LM_ERR("Error while sending publish\n");
+	}
+	if (p_asserted_identity_header.s) {
+		pkg_free(p_asserted_identity_header.s);
+	}
+	
+	return 1;
+
+error:
+	
+	if (p_asserted_identity_header.s) {
+		pkg_free(p_asserted_identity_header.s);
+	}
+	if (body) {
+		if (body->s)
+			xmlFree(body->s);
+		pkg_free(body);
+	}
+	return -1;
+}
 
 void callback_pcscf_contact_cb(struct pcontact *c, int type, void *param) {
 	ppublic_t *ptr;
@@ -209,16 +267,21 @@ void callback_pcscf_contact_cb(struct pcontact *c, int type, void *param) {
 	LM_DBG("PCSCF Contact Callback in regsitrar!\n");
 	LM_DBG("Contact AOR: [%.*s]\n", c->aor.len, c->aor.s);
 	LM_DBG("Callback type [%d]\n", type);
+	LM_DBG("Reg state [%d]\n", c->reg_state);
 
-	if (type == (PCSCF_CONTACT_DELETE | PCSCF_CONTACT_UPDATE)) {
+	if ((type&PCSCF_CONTACT_UPDATE)) {
 		//send publish for each associated IMPU
 		ptr = c->head;
 			while (ptr) {
-				if (c->reg_state == PCONTACT_DEREG_PENDING_PUBLISH) {
+				if (c->reg_state == PCONTACT_DEREG_PENDING_PUBLISH && publish_reginfo) {
 					LM_DBG("delete/update on contact <%.*s> associated with IMPU <%.*s> (sending publish)\n",
 											c->aor.len, c->aor.s,
 											ptr->public_identity.len, ptr->public_identity.s);
-					//send_partial_publish(ptr, c, type);
+					if (ptr->public_identity.len > 4 && strncasecmp(ptr->public_identity.s,"tel:",4)==0) {
+					    LM_DBG("This is a tel URI - it is not routable so we don't publish for it");
+					}else{
+					    send_partial_publish(ptr, c, type);
+					}
 				}
 
 				ptr = ptr->next;