/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include "debug.h"
#include "phone_debug.h"
#include "ccsip_publish.h"
#include "util_string.h"
#include "sip_interface_regmgr.h"

extern boolean dump_reg_msg;

/* SIP flags */
cc_int32_t SipDebugMessage          = 1; /* SIP messaging output */
cc_int32_t SipDebugState            = 0; /* SIP State Machine output */
cc_int32_t SipDebugTask             = 1; /* SIP Task output */
cc_int32_t SipDebugRegState         = 0; /* SIP Registration State Mach. output */

/**
 * SipRelDevEnabled flag is not a debug print flag. It actually turns
 * on and off reliable delivery module in sip layer. We will keep
 * this on as retransmissions are enabled on CUCM by default even for TCP transport
 */
int32_t SipRelDevEnabled           = 1; /* Is reliable delivery on? */

int32_t SipDebugGenContactHeader = 0; /* Generate Contact header */
cc_int32_t SipDebugTrx              = 0; /* SIP Transaction Layer output */

cc_int32_t GSMDebug                 = 0;
cc_int32_t FIMDebug                 = 0;
cc_int32_t LSMDebug                 = 0;
cc_int32_t FSMDebugSM               = 0;
int32_t CSMDebugSM               = 0;
cc_int32_t CCDebug                  = 0;
cc_int32_t CCDebugMsg               = 0;
cc_int32_t AuthDebug                = 0;
cc_int32_t g_DEFDebug               = 1;
cc_int32_t TNPDebug                 = 1;
cc_int32_t VCMDebug                 = 0;
cc_int32_t CCEVENTDebug             = 0;
cc_int32_t PLATDebug                = 0;
cc_int32_t TMRDebug                 = 0;
cc_int32_t g_dcsmDebug              = 0;

/**
 *
 * Dump sip messages
 *
 * @param msg - message buffer
 *        pSIPMessage - parsed message structure
 *        cc_remote_ipaddr - remote ip address
 *        cc_remote_port - remote port number
 *
 * @return  none
 *
 * @pre     (valid pSIPMessage AND
 *           valid cc_remote_ipaddr)
 */

void ccsip_dump_send_msg_info (char *msg, sipMessage_t *pSIPMessage,
                               cpr_ip_addr_t *cc_remote_ipaddr,
                               uint16_t cc_remote_port)
{
    char *disp_buf;
    const char *req_uri;
    const char *cseq;
    const char *callid;
    char ipaddr_str[MAX_IPADDR_STR_LEN];
    static const char fname[] = "ccsip_dump_send_msg_info";

    ipaddr2dotted(ipaddr_str, cc_remote_ipaddr);

    req_uri = sippmh_get_header_val(pSIPMessage, SIP_HEADER_TO, NULL);
    if (req_uri == NULL) {
        /* No REQ URI, fill with blank */
        req_uri = "";
    }
    cseq = sippmh_get_header_val(pSIPMessage, SIP_HEADER_CSEQ, NULL);
    if (cseq == NULL) {
        /* No REQ CSEQ, fill with blank */
        cseq = "";
    }
    callid = sippmh_get_header_val(pSIPMessage, SIP_HEADER_CALLID, NULL);
    if (callid == NULL) {
        /* No REQ CSEQ, fill with blank */
        callid = "";
    }

    /* For messages starting with SIP add 8 byte. default
     * debugs do not show all the SIP message information
     * rather show initial msg.
     */
    if (msg != NULL) {
        if (msg[0] == 'S' &&
            msg[1] == 'I' &&
            msg[2] == 'P') {
            disp_buf = &msg[8];
        } else {
            disp_buf = msg;
        }
        if ((strncmp(disp_buf, SIP_METHOD_REGISTER, sizeof(SIP_METHOD_REGISTER)-1) == 0) &&
            (!dump_reg_msg)) {
            return;
        }
    } else {
        /* No msg. buffer */
        disp_buf = NULL;
    }


    if (disp_buf != NULL) {
        DEF_DEBUG(DEB_F_PREFIX"<%s:%-4d>:%c%c%c%c%c%c%c: %-10s :%-6s::%s\n",
                    DEB_F_PREFIX_ARGS(SIP_MSG_SEND, fname),
                    ipaddr_str, cc_remote_port,
                    disp_buf[0],
                    disp_buf[1],
                    disp_buf[2],
                    disp_buf[3],
                    disp_buf[4],
                    disp_buf[5],
                    disp_buf[6],
                    req_uri,
                    cseq, callid);
    } else {
        /* No msg to send */
        DEF_DEBUG(DEB_F_PREFIX"<%s:%-4d>: empty message\n",
                  DEB_F_PREFIX_ARGS(SIP_MSG_SEND, fname),
                  ipaddr_str, cc_remote_port);
    }
}

/**
 *
 * Dump sip messages
 *
 * @param msg - message buffer
 *        pSIPMessage - parsed message structure
 *        cc_remote_ipaddr - remote ip address
 *        cc_remote_port - remote port number
 *
 * @return  none
 *
 * @pre     (valid pSIPMessage AND
 *           valid cc_remote_ipaddr)
 */

void ccsip_dump_recv_msg_info (sipMessage_t *pSIPMessage,
                               cpr_ip_addr_t *cc_remote_ipaddr,
                               uint16_t cc_remote_port)
{
    char *disp_buf;
    const char *req_uri;
    const char *cseq;
    const char *callid;
    char ipaddr_str[MAX_IPADDR_STR_LEN];
    cpr_ip_addr_t cc_ipaddr;
    static const char fname[] = "ccsip_dump_recv_msg_info";

    util_ntohl(&cc_ipaddr, cc_remote_ipaddr);
    ipaddr2dotted(ipaddr_str, &cc_ipaddr);

    req_uri = sippmh_get_cached_header_val(pSIPMessage, FROM);
    if (req_uri == NULL) {
        /* No REQ URI, fill with blank */
        req_uri = "";
    }
    cseq = sippmh_get_cached_header_val(pSIPMessage, CSEQ);
    if (cseq == NULL) {
        /* No REQ CSEQ, fill with blank */
        cseq = "";
    }
    callid = sippmh_get_cached_header_val(pSIPMessage, CALLID);
    if (callid == NULL) {
        /* No REQ CSEQ, fill with blank */
        callid = "";
    }

    if (!dump_reg_msg) {
       if (strstr(cseq, SIP_METHOD_REGISTER) != NULL) {
          return;
       }
    }

    /* For messages starting with SIP add 8 byte. default
     * debugs do not show all the SIP message information
     * rather show initial msg.
     */
    if (pSIPMessage->mesg_line != NULL) {
        if (pSIPMessage->mesg_line[0] == 'S' &&
            pSIPMessage->mesg_line[1] == 'I' &&
            pSIPMessage->mesg_line[2] == 'P') {
            disp_buf = &(pSIPMessage->mesg_line[8]);
        } else {
            disp_buf = pSIPMessage->mesg_line;
        }
    } else {
        /*
         * It is possible that this function is called with
         * invalid message or partially received.
         */
        disp_buf = NULL;
    }

    if (disp_buf != NULL) {
        DEF_DEBUG(DEB_F_PREFIX"<%s:%-4d>:%c%c%c%c%c%c%c: %-10s :%-6s::%s\n",
                    DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname),
                    ipaddr_str, cc_remote_port,
                    disp_buf[0],
                    disp_buf[1],
                    disp_buf[2],
                    disp_buf[3],
                    disp_buf[4],
                    disp_buf[5],
                    disp_buf[6],
                    req_uri,
                    cseq, callid);
    } else {
        /* No line received */
        DEF_DEBUG(DEB_F_PREFIX"<%s:%-4d>: empty message\n",
                  DEB_F_PREFIX_ARGS(SIP_MSG_RECV, fname),
                  ipaddr_str, cc_remote_port);
    }
}

/**
 *
 * platform_print_sip_msg
 *
 * The function perform printing SIP msg.
 *
 * Parameters:   msg - pointer to character strings of the SIP messages.
 *
 * Return Value: None
 *
 */
void
platform_print_sip_msg (const char *msg)
{
    char *buf;
    int msg_to_crypto_line_len, msg_to_digits_tag_len, buf_len;
    const char *c_line_begin, *c_line_end;
    static const char crypto_line_tag[] = "a=crypto:";
    static const char crypto_mask[] = "...";
    static const char digits_tag[] = "digits=";

    if (msg == NULL) {
        return;
    }

    buginf_msg("\n");
    /* replace digits for security reasons */
    if (strstr(msg, "kpml-response")) {
        /* This is kpml response. so supress printing digits. */
        c_line_begin = strstr(msg, digits_tag);
        if (c_line_begin == NULL) {
            /* No digits, print everything */
            buginf_msg(msg);
            return;
        }
        /*
         * Calculate the length of the msg. to print from
         * from the beginning to the end of the "digits=" i.e.
         */
        msg_to_digits_tag_len = c_line_begin - msg + sizeof(digits_tag);
        buf_len = msg_to_digits_tag_len + sizeof(crypto_mask);
        buf = (char *) cpr_malloc(buf_len);
        if (buf == NULL) {
            /* No memory */
            return;
        }

        /* Copy the message upto "digits=" */
        memcpy(buf, msg, msg_to_digits_tag_len);

        /* Copy mask and the end NULL terminating char to the buffer */
        memcpy(&buf[msg_to_digits_tag_len], crypto_mask, sizeof(crypto_mask));
        /* Print it out now */
        buginf_msg(buf);
        cpr_free(buf);

        c_line_end = c_line_begin + sizeof(digits_tag) + 3; /* 3 beacuse " + digit + " */
        msg = c_line_end;
        buginf_msg(msg);
    } else if (sip_regmgr_get_sec_level(1) == ENCRYPTED) {
        /* The 1st. line is using encrypted signaling */
        while (TRUE) {
            c_line_begin = strstr(msg, crypto_line_tag);
            if (c_line_begin == NULL) {
                /* No more crypto line, print whatever left and done */
                buginf_msg(msg);
                return;
            } else {
                /*
                 * Found a crypto line:
                 *
                 * Allocate buffer to print the msg. including this
                 * instance of crypto line but no crypto parameter.
                 * For example:
                 *
                 * v=0
                 * o=Cisco-SIPUA 3052 7 IN IP4 10.80.35.217
                 * s=SIP Call
                 * t=0 0
                 * m=audio 28926 RTP/SAVP 0 8 18 101
                 * c=IN IP4 10.80.35.217
                 * a=crypto:1 AES_CM_128_HMAC_SHA1_32 inline:GqT...
                 * a=rtpmap:0 PCMU/8000
                 *
                 *
                 * The output of printing will be
                 *
                 * v=0
                 * o=Cisco-SIPUA 3052 7 IN IP4 10.80.35.217
                 * s=SIP Call
                 * t=0 0
                 * m=audio 28926 RTP/SAVP 0 8 18 101
                 * c=IN IP4 10.80.35.217
                 * a=crypto:1...
                 * a=rtpmap:0 PCMU/8000
                 *
                 */

                /*
                 * Calculate the length of the msg. to print from
                 * current position to the end of the "a=crypto:n" i.e.
                 * from the current of msg passes the ":" by one character
                 * after of the "a=crypto:". This allows the first character
                 * of the crypto tag field character to be included in the
                 * output. Note that there is no explicit adding this
                 * extra character in the code below because of the
                 * sizeof(crypto_line_tag) includes extra 1 byte of string
                 * termination character already. It will be the extra
                 * character to print after the ":".
                 */
                msg_to_crypto_line_len = c_line_begin - msg +
                                         sizeof(crypto_line_tag);
                /*
                 * The buffer allocated to print includes the length from
                 * current msg pointer to this instance of crypto line +
                 * the mask length plus 1 byte for NULL terminating character.
                 * The NULL terminating character is included in the
                 * sizeof(crypto_mask) below.
                 */
                buf_len = msg_to_crypto_line_len + sizeof(crypto_mask);
                buf = (char *) cpr_malloc(buf_len);
                if (buf == NULL) {
                    /* No memory */
                    return;
                }

                /* Copy the message including this instance of crypto line */
                memcpy(buf, msg, msg_to_crypto_line_len);

                /* Copy mask and the end NULL terminating char to the buffer */
                memcpy(&buf[msg_to_crypto_line_len], crypto_mask,
                       sizeof(crypto_mask));
                /* Print it out now */
                buginf_msg(buf);
                cpr_free(buf);

                /* Find the end of the crypto line */
                c_line_end = strpbrk(c_line_begin, "\n");
                if (c_line_end != NULL) {
                    /* Skip pass the "\n" character of the crypto line */
                    msg = c_line_end + 1;
                } else {
                    /* Some thing is wrong, no end line character in SDP */
                    return;
                }
            }
        }
    } else {
        /* print full content */
        buginf_msg(msg);
    }
}

/*
 *  Function: ccsip_debug_init()
 *
 *  Parameters: None
 *
 *  Description: Initialize the Debug keywords used by the SIP protocol stack.
 *
 *  Returns: None
 *
 */
void
ccsip_debug_init (void)
{
    /* Placeholder for doing any initialization related tasks */
}
