PJ_DEF(pj_status_t) pjsip_endpt_create_response( pjsip_endpoint *endpt,
						 const pjsip_rx_data *rdata,
						 int st_code,
						 const pj_str_t *st_text,
						 pjsip_tx_data **p_tdata)
{
    pjsip_tx_data *tdata;
    pjsip_msg *msg, *req_msg;
    pjsip_hdr *hdr;
    pjsip_to_hdr *to_hdr;
    pjsip_via_hdr *top_via = NULL, *via;
    pjsip_rr_hdr *rr;
    pj_status_t status;

    /* Check arguments. */
    PJ_ASSERT_RETURN(endpt && rdata && p_tdata, PJ_EINVAL);

    /* Check status code. */
    PJ_ASSERT_RETURN(st_code >= 100 && st_code <= 699, PJ_EINVAL);

    /* rdata must be a request message. */
    req_msg = rdata->msg_info.msg;
    pj_assert(req_msg->type == PJSIP_REQUEST_MSG);

    /* Request MUST NOT be ACK request! */
    PJ_ASSERT_RETURN(req_msg->line.req.method.id != PJSIP_ACK_METHOD,
		     PJ_EINVALIDOP);

    /* Create a new transmit buffer. */
    status = pjsip_endpt_create_tdata( endpt, &tdata);
    if (status != PJ_SUCCESS)
	return status;

    /* Set initial reference count to 1. */
    pjsip_tx_data_add_ref(tdata);

    /* Create new response message. */
    tdata->msg = msg = pjsip_msg_create(tdata->pool, PJSIP_RESPONSE_MSG);

    /* Set status code and reason text. */
    msg->line.status.code = st_code;
    if (st_text)
	pj_strdup(tdata->pool, &msg->line.status.reason, st_text);
    else
	msg->line.status.reason = *pjsip_get_status_text(st_code);

    /* Set TX data attributes. */
    tdata->rx_timestamp = rdata->pkt_info.timestamp;

    /* Copy all the via headers, in order. */
    via = rdata->msg_info.via;
    while (via) {
	pjsip_via_hdr *new_via;

	new_via = (pjsip_via_hdr*)pjsip_hdr_clone(tdata->pool, via);
	if (top_via == NULL)
	    top_via = new_via;

	pjsip_msg_add_hdr( msg, (pjsip_hdr*)new_via);
	via = via->next;
	if (via != (void*)&req_msg->hdr)
	    via = (pjsip_via_hdr*) 
	    	  pjsip_msg_find_hdr(req_msg, PJSIP_H_VIA, via);
	else
	    break;
    }

    /* Copy all Record-Route headers, in order. */
    rr = (pjsip_rr_hdr*) 
    	 pjsip_msg_find_hdr(req_msg, PJSIP_H_RECORD_ROUTE, NULL);
    while (rr) {
	pjsip_msg_add_hdr(msg, (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, rr));
	rr = rr->next;
	if (rr != (void*)&req_msg->hdr)
	    rr = (pjsip_rr_hdr*) pjsip_msg_find_hdr(req_msg, 
	    					    PJSIP_H_RECORD_ROUTE, rr);
	else
	    break;
    }

    /* Copy Call-ID header. */
    hdr = (pjsip_hdr*) pjsip_msg_find_hdr( req_msg, PJSIP_H_CALL_ID, NULL);
    pjsip_msg_add_hdr(msg, (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, hdr));

    /* Copy From header. */
    hdr = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, rdata->msg_info.from);
    pjsip_msg_add_hdr( msg, hdr);

    /* Copy To header. */
    to_hdr = (pjsip_to_hdr*) pjsip_hdr_clone(tdata->pool, rdata->msg_info.to);
    pjsip_msg_add_hdr( msg, (pjsip_hdr*)to_hdr);

    /* Must add To tag in the response (Section 8.2.6.2), except if this is
     * 100 (Trying) response. Same tag must be created for the same request
     * (e.g. same tag in provisional and final response). The easiest way
     * to do this is to derive the tag from Via branch parameter (or to
     * use it directly).
     */
    if (to_hdr->tag.slen==0 && st_code > 100 && top_via) {
	to_hdr->tag = top_via->branch_param;
    }

    /* Copy CSeq header. */
    hdr = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, rdata->msg_info.cseq);
    pjsip_msg_add_hdr( msg, hdr);

    /* All done. */
    *p_tdata = tdata;

    PJ_LOG(5,(THIS_FILE, "%s created", pjsip_tx_data_get_info(tdata)));
    return PJ_SUCCESS;
}