Przeglądaj źródła

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 lat temu
rodzic
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;