Index: pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c
===================================================================
--- pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c	(revision 4548)
+++ pjproject/trunk/pjsip/src/pjsip-ua/sip_reg.c	(revision 4586)
@@ -76,4 +76,5 @@
     void			*token;
     pjsip_regc_cb		*cb;
+    pjsip_regc_tsx_cb           *tsx_cb;
 
     pj_str_t			 str_srv_url;
@@ -728,4 +729,24 @@
 }
 
+static void cbparam_init( struct pjsip_regc_cbparam *cbparam,
+                          pjsip_regc *regc, 
+                          pj_status_t status, int st_code, 
+			  const pj_str_t *reason,
+			  pjsip_rx_data *rdata, pj_int32_t expiration,
+			  int contact_cnt, pjsip_contact_hdr *contact[])
+{
+    cbparam->regc = regc;
+    cbparam->token = regc->token;
+    cbparam->status = status;
+    cbparam->code = st_code;
+    cbparam->reason = *reason;
+    cbparam->rdata = rdata;
+    cbparam->contact_cnt = contact_cnt;
+    cbparam->expiration = expiration;
+    if (contact_cnt) {
+	pj_memcpy( cbparam->contact, contact, 
+		   contact_cnt*sizeof(pjsip_contact_hdr*));
+    }
+}
 
 static void call_callback(pjsip_regc *regc, pj_status_t status, int st_code, 
@@ -736,21 +757,9 @@
     struct pjsip_regc_cbparam cbparam;
 
-
     if (!regc->cb)
 	return;
 
-    cbparam.regc = regc;
-    cbparam.token = regc->token;
-    cbparam.status = status;
-    cbparam.code = st_code;
-    cbparam.reason = *reason;
-    cbparam.rdata = rdata;
-    cbparam.contact_cnt = contact_cnt;
-    cbparam.expiration = expiration;
-    if (contact_cnt) {
-	pj_memcpy( cbparam.contact, contact, 
-		   contact_cnt*sizeof(pjsip_contact_hdr*));
-    }
-
+    cbparam_init(&cbparam, regc, status, st_code, reason, rdata, expiration,
+                 contact_cnt, contact);
     (*regc->cb)(&cbparam);
 }
@@ -813,4 +822,13 @@
     }
 }
+
+PJ_DEF(pj_status_t) pjsip_regc_set_reg_tsx_cb( pjsip_regc *regc,
+				               pjsip_regc_tsx_cb *tsx_cb)
+{
+    PJ_ASSERT_RETURN(regc, PJ_EINVAL);
+    regc->tsx_cb = tsx_cb;
+    return PJ_SUCCESS;
+}
+
 
 PJ_DEF(pj_status_t) pjsip_regc_set_via_sent_by( pjsip_regc *regc,
@@ -1036,4 +1054,5 @@
     pjsip_transaction *tsx = event->body.tsx_state.tsx;
     pj_bool_t handled = PJ_TRUE;
+    pj_bool_t update_contact = PJ_FALSE;
 
     pj_atomic_inc(regc->busy_ctr);
@@ -1055,4 +1074,47 @@
 	    pjsip_transport_add_ref(regc->last_transport);
 	}
+    }
+
+    if (regc->_delete_flag == 0 && regc->tsx_cb &&
+        regc->current_op == REGC_REGISTERING)
+    {
+        struct pjsip_regc_tsx_cb_param param;
+
+        param.contact_cnt = -1;
+        cbparam_init(&param.cbparam, regc, PJ_SUCCESS, tsx->status_code,
+		     &tsx->status_text,
+                     (event->body.tsx_state.type==PJSIP_EVENT_RX_MSG) ? 
+	              event->body.tsx_state.src.rdata : NULL,
+                     -1, 0, NULL);
+
+        /* Call regc tsx callback before handling any response */
+        pj_lock_release(regc->lock);
+        (*regc->tsx_cb)(&param);
+        pj_lock_acquire(regc->lock);
+
+        if (param.contact_cnt >= 0) {
+            /* Since we receive non-2xx response, it means that (some) contact
+             * bindings haven't been established so we can safely remove these
+             * contact headers. This is to avoid removing non-existent contact
+             * bindings later.
+             */
+            if (tsx->status_code/100 != 2) {
+                pjsip_contact_hdr *h;
+
+	        h = regc->contact_hdr_list.next;
+	        while (h != &regc->contact_hdr_list) {
+                    pjsip_contact_hdr *next = h->next;
+
+                    if (h->expires == -1) {
+                        pj_list_erase(h);
+                    }
+                    h = next;
+                }
+	    }
+
+            /* Update contact address */
+            pjsip_regc_update_contact(regc, param.contact_cnt, param.contact);
+            update_contact = PJ_TRUE;
+        }
     }
 
@@ -1067,5 +1129,47 @@
 	regc->current_op = REGC_IDLE;
 
-	status = pjsip_auth_clt_reinit_req( &regc->auth_sess,
+        if (update_contact) {
+            pjsip_msg *msg;
+            pjsip_hdr *hdr, *ins_hdr;
+            pjsip_contact_hdr *chdr;
+
+            /* Delete Contact headers, but we shouldn't delete headers
+             * which are supposed to remove contact bindings since
+             * we cannot reconstruct those headers.
+             */
+            msg = tsx->last_tx->msg;
+            hdr = msg->hdr.next;
+            ins_hdr = &msg->hdr;
+            while (hdr != &msg->hdr) {
+                pjsip_hdr *next = hdr->next;
+
+                if (hdr->type == PJSIP_H_CONTACT) {
+                    chdr = (pjsip_contact_hdr *)hdr;
+                    if (chdr->expires != 0) {
+                        pj_list_erase(hdr);
+                        ins_hdr = next;
+                    }
+                }
+                hdr = next;
+            }
+
+            /* Add Contact headers. */
+            chdr = regc->contact_hdr_list.next;
+            while (chdr != &regc->contact_hdr_list) {
+	        pj_list_insert_before(ins_hdr, (pjsip_hdr*)
+                    pjsip_hdr_shallow_clone(tsx->last_tx->pool, chdr));
+	        chdr = chdr->next;
+            }
+
+            /* Also add bindings which are to be removed */
+            while (!pj_list_empty(&regc->removed_contact_hdr_list)) {
+	        chdr = regc->removed_contact_hdr_list.next;
+	        pj_list_insert_before(ins_hdr, (pjsip_hdr*)
+                    pjsip_hdr_clone(tsx->last_tx->pool, chdr));
+	        pj_list_erase(chdr);
+            }
+        }
+
+        status = pjsip_auth_clt_reinit_req( &regc->auth_sess,
 					    rdata, 
 					    tsx->last_tx,  
