PJ_DEF(pj_status_t) pjsip_dlg_fork( const pjsip_dialog *first_dlg,
				    const pjsip_rx_data *rdata,
				    pjsip_dialog **new_dlg )
{
    pjsip_dialog *dlg;
    const pjsip_msg *msg = rdata->msg_info.msg;
    const pjsip_hdr *end_hdr, *hdr;
    const pjsip_contact_hdr *contact;
    pj_status_t status;

    /* Check arguments. */
    PJ_ASSERT_RETURN(first_dlg && rdata && new_dlg, PJ_EINVAL);

    /* rdata must be response message. */
    PJ_ASSERT_RETURN(msg->type == PJSIP_RESPONSE_MSG,
		     PJSIP_ENOTRESPONSEMSG);

    /* Status code MUST be 1xx (but not 100), or 2xx */
    status = msg->line.status.code;
    PJ_ASSERT_RETURN( (status/100==1 && status!=100) ||
		      (status/100==2), PJ_EBUG);

    /* To tag must present in the response. */
    PJ_ASSERT_RETURN(rdata->msg_info.to->tag.slen != 0, PJSIP_EMISSINGTAG);

    /* Find Contact header in the response */
    contact = (const pjsip_contact_hdr*)
	      pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL);
    if (contact == NULL || contact->uri == NULL)
	return PJSIP_EMISSINGHDR;

    /* Create the dialog. */
    status = create_dialog((pjsip_user_agent*)first_dlg->ua, NULL, &dlg);
    if (status != PJ_SUCCESS)
	return status;

    /* Set remote target from the response. */
    dlg->target = (pjsip_uri*) pjsip_uri_clone(dlg->pool, contact->uri);

    /* Clone local info. */
    dlg->local.info = (pjsip_fromto_hdr*)
    		      pjsip_hdr_clone(dlg->pool, first_dlg->local.info);

    /* Clone local tag. */
    pj_strdup(dlg->pool, &dlg->local.info->tag, &first_dlg->local.info->tag);
    dlg->local.tag_hval = first_dlg->local.tag_hval;

    /* Clone local CSeq. */
    dlg->local.first_cseq = first_dlg->local.first_cseq;
    dlg->local.cseq = first_dlg->local.cseq;

    /* Clone local Contact. */
    dlg->local.contact = (pjsip_contact_hdr*)
    			 pjsip_hdr_clone(dlg->pool, first_dlg->local.contact);

    /* Clone remote info. */
    dlg->remote.info = (pjsip_fromto_hdr*)
    		       pjsip_hdr_clone(dlg->pool, first_dlg->remote.info);

    /* Set remote tag from the response. */
    pj_strdup(dlg->pool, &dlg->remote.info->tag, &rdata->msg_info.to->tag);

    /* Initialize remote's CSeq to -1. */
    dlg->remote.cseq = dlg->remote.first_cseq = -1;

    /* Initial role is UAC. */
    dlg->role = PJSIP_ROLE_UAC;

    /* Dialog state depends on the response. */
    status = msg->line.status.code/100;
    if (status == 1 || status == 2)
	dlg->state = PJSIP_DIALOG_STATE_ESTABLISHED;
    else {
	pj_assert(!"Invalid status code");
	dlg->state = PJSIP_DIALOG_STATE_NULL;
    }

    /* Secure? */
    dlg->secure = PJSIP_URI_SCHEME_IS_SIPS(dlg->target);

    /* Clone Call-ID header. */
    dlg->call_id = (pjsip_cid_hdr*)
    		   pjsip_hdr_clone(dlg->pool, first_dlg->call_id);

    /* Get route-set from the response. */
    pj_list_init(&dlg->route_set);
    end_hdr = &msg->hdr;
    for (hdr=msg->hdr.prev; hdr!=end_hdr; hdr=hdr->prev) {
	if (hdr->type == PJSIP_H_RECORD_ROUTE) {
	    pjsip_route_hdr *r;
	    r = (pjsip_route_hdr*) pjsip_hdr_clone(dlg->pool, hdr);
	    pjsip_routing_hdr_set_route(r);
	    pj_list_push_back(&dlg->route_set, r);
	}
    }

    //dlg->route_set_frozen = PJ_TRUE;

    /* Clone client authentication session. */
    status = pjsip_auth_clt_clone(dlg->pool, &dlg->auth_sess,
				  &first_dlg->auth_sess);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Register this dialog to user agent. */
    status = pjsip_ua_register_dlg(dlg->ua, dlg );
    if (status != PJ_SUCCESS)
	goto on_error;


    /* Done! */
    *new_dlg = dlg;

    PJ_LOG(5,(dlg->obj_name, "Forked dialog created"));
    return PJ_SUCCESS;

on_error:
    destroy_dialog(dlg, PJ_FALSE);
    return status;
}