/**************************************************************************
*** COPYRIGHT (c) 2002 by TransNexus, Inc.                              ***
***                                                                     ***
*** This software is property of TransNexus, Inc.                       ***
*** This software is freely available under license from TransNexus.    ***
*** The license terms and conditions for free use of this software by   ***
*** third parties are defined in the OSP Toolkit Software License       ***
*** Agreement (LICENSE.txt).  Any use of this software by third         ***
*** parties, which does not comply with the terms and conditions of the ***
*** OSP Toolkit Software License Agreement is prohibited without        ***
*** the prior, express, written consent of TransNexus, Inc.             ***
***                                                                     ***
*** Thank you for using the OSP ToolKit(TM).  Please report any bugs,   ***
*** suggestions or feedback to support@transnexus.com                   ***
***                                                                     ***
**************************************************************************/

/* ospmime.cpp - mime stuff */

#include "osp/ospmime.h"

void OSPPMimeBodyFree(
    OSPTMIMEBODY *ospvMimeBody)
{
    int count = 0;

    OSPM_DBGENTER(("ENTER: OSPPMimeBodyFree()\n"));
    if (ospvMimeBody != (OSPTMIMEBODY *)NULL) {
        if (ospvMimeBody->Boundary != (OSPTMIMEPART *)NULL) {
            OSPPMimePartFree(ospvMimeBody->Boundary);
        }

        while (count < OSPC_MAX_BODYPARTS) {
            if (ospvMimeBody->BodyParts[count] != (OSPTMIMEPART *)NULL) {
                OSPPMimePartFree(ospvMimeBody->BodyParts[count]);
            }
            count++;
        }
    }
    OSPM_DBGEXIT(("EXIT : OSPPMimeBodyFree()\n"));
}

int OSPPMimeBodyPartsParse(
    OSPTMIMEPART *ospvBodyData,
    OSPTMIMEBODY *ospvMimeBody,
    OSPTMIMEPART *ospvBoundary)
{
    int errorcode = OSPC_ERR_NO_ERROR;
    unsigned char *buf = ospvBodyData->Content;
    unsigned currpos = 0;
    unsigned bufend = ospvBodyData->Length;
    unsigned start = 0;
    int found = 0, bfound = 0;
    int bresult = -1;
    OSPTMIMEPART header;
    int partsfound = 0;

    OSPM_DBGENTER(("ENTER: OSPPMimeBodyPartsParse() bufend == [%d] buf = [%*s]\n", bufend, bufend, (char *)buf));
    OSPM_MEMSET(&header, 0, sizeof(OSPTMIMEPART));

    /* strip off body parts, send to parser */
    while ((partsfound < OSPC_MAX_BODYPARTS) && (currpos < bufend)) {
        /* if there is no boundary set, we have text/plain */
        if ((ospvBoundary != OSPC_OSNULL) && (ospvBoundary->Content != OSPC_OSNULL)) {
            while ((currpos < bufend) && (!found)) {

                if (buf[currpos] == ospvBoundary->Content[0]) {

                    /* make sure we really are at the boundary */
                    bresult = OSPM_MEMCMP(&buf[currpos], ospvBoundary->Content, ospvBoundary->Length);

                    if (bresult == 0) {
                        found = 1;
                        break;
                    }
                }
                currpos++;
            }   /* end while(currpos < bufend... */

            if (found) {

                /* get past the boundary, CRLF */
                currpos += ospvBoundary->Length;

                while (currpos < bufend) {
                    if ((buf[currpos] != '\n') && (buf[currpos] != ' ') && (buf[currpos] != '\t') && (buf[currpos] != '\r')) {
                        bfound = 1;
                        break;
                    }
                    currpos++;
                }

                if (bfound) {
                    int cresult = -1;

                    start = currpos;
                    /* get to the next boundary (CRLF--boundary) */
                    while (currpos < bufend) {
                        if ((buf[currpos] == '\r') &&
                            (currpos + 3 < bufend) && (buf[currpos + 1] == '\n') && (buf[currpos + 2] == '-') && (buf[currpos + 3] == '-')) {

                            /* make sure we really are at the boundary */
                            cresult = OSPM_MEMCMP(&buf[currpos + 4], ospvBoundary->Content, ospvBoundary->Length);
                            if (cresult == 0) {
                                /* move past the CRLF */
                                currpos += 2;
                                break;
                            }
                        }
                        currpos++;
                    }
                }
            }
        } else {
            /* get to the next CRLFCRLF (CRLFCRLF) */
            while (currpos < bufend) {
                if ((buf[currpos] == '\r') &&
                    (currpos + 3 < bufend) && (buf[currpos + 1] == '\n') && (buf[currpos + 2] == '\r') && (buf[currpos + 3] == '\n')) {
                    /*now we are in the right spot */
                    break;
                }
                currpos++;
            }

            start = currpos;

            /* set currpos to bufend, so we can parse the whole buffer. this is text/plain */
            currpos = bufend;
        }

        if (currpos <= bufend) {

            OSPM_MALLOC(ospvMimeBody->BodyParts[partsfound], OSPTMIMEPART, sizeof(OSPTMIMEPART));

            if (ospvMimeBody->BodyParts[partsfound] != (OSPTMIMEPART *)NULL) {


                OSPM_MEMSET(ospvMimeBody->BodyParts[partsfound], 0, sizeof(ospvMimeBody->BodyParts[partsfound]));

                errorcode = OSPPMimeBufferParse(&buf[start], currpos - start, &header, ospvMimeBody->BodyParts[partsfound]);

                if (header.Content) {
                    OSPM_FREE(header.Content);
                    header.Content = OSPC_OSNULL;
                }

                if (errorcode == OSPC_ERR_NO_ERROR) {

                    partsfound++;
                    found = 0;
                    bfound = 0;
                } else {
                    break;
                }
            } else {
                errorcode = OSPC_ERR_MIME_MALLOC_FAILED;
                OSPM_DBGERRORLOG(errorcode, "malloc failed for body part");
                break;
            }
        }
    }

    if (errorcode == OSPC_ERR_NO_ERROR) {
        ospvMimeBody->NumBodyParts = partsfound;
    }
    OSPM_DBGEXIT(("EXIT : OSPPMimeBodyPartsParse()\n"));

    return errorcode;
}

/* Pulls apart header from body */
int OSPPMimeBufferParse(
    unsigned char *ospvInputbuffer, /* In - buffer to be parsed */
    unsigned ospvSizeOfInputbuffer, /* In - size of buffer to be parsed */
    OSPTMIMEPART *ospvHeader,       /* Out - Mime header data */
    OSPTMIMEPART *ospvBody)         /* Out - Mime body data */
{
    unsigned char *buffin = ospvInputbuffer;
    unsigned buffinend = ospvSizeOfInputbuffer;
    unsigned currpos = 0;
    unsigned hdrstart = 0;
    unsigned hdrlen = 0;
    unsigned bdystart = 0;
    unsigned bdylen = 0;
    int errorcode = OSPC_ERR_NO_ERROR;

    OSPM_DBGENTER(("ENTER: OSPPMimeBufferParse()\n"));
    /* If first character is a LF (ANSI C or UNIX)
     * or if first two characters are CR LF (MIME or DOS),
     * there are no headers.
     */
    if ((currpos < buffinend) && (buffin[currpos] != '\n')
        && !((buffin[currpos] == '\r') && (currpos + 1 < buffinend)
             && (buffin[currpos + 1] == '\n'))) {

        while (currpos < buffinend) {
            /* Is it LF LF ? */
            if ((buffin[currpos] == '\n')
                && (currpos + 1 < buffinend)
                && (buffin[currpos + 1] == '\n')) {

                ++hdrlen;
                ++currpos;
                break;
            }
            /* Is it CR LF CR LF? */
            else if ((buffin[currpos] == '\r')
                     && (currpos + 3 < buffinend)
                     && (buffin[currpos + 1] == '\n')
                     && (buffin[currpos + 2] == '\r')
                     && (buffin[currpos + 3] == '\n')) {

                hdrlen += 2;
                currpos += 2;
                break;
            }
            ++currpos;
            ++hdrlen;
        }
    }

    errorcode = OSPPUtilMallocAndCopySubString(ospvInputbuffer, &(ospvHeader->Content), hdrstart, hdrlen);
    ospvHeader->Length = hdrlen;

    if (errorcode == OSPC_ERR_NO_ERROR) {

        /* Skip blank line
         * LF (ANSI C or UNIX)
         */
        if (currpos < buffinend && buffin[currpos] == '\n') {
            ++currpos;
        }
        /* CR LF (MIME or DOS) */
        else if (currpos < buffinend && buffin[currpos] == '\r' && currpos + 1 < buffinend && buffin[currpos + 1] == '\n') {

            currpos += 2;
        }

        bdystart = currpos;
        bdylen = ospvSizeOfInputbuffer;

        /* get rid of whitspace, CRLFs at end of body string */
        while (bdylen > bdystart) {
            if ((!isspace(buffin[bdylen - 1])) && (buffin[bdylen - 1] != '\n') && (buffin[bdylen - 1] != '\r')) {
                break;
            }
            --bdylen;
        }

        bdylen = bdylen - bdystart;

        errorcode = OSPPUtilMallocAndCopySubString(ospvInputbuffer, &(ospvBody->Content), bdystart, bdylen);
        ospvBody->Length = bdylen;
    }
    OSPM_DBGEXIT(("EXIT : OSPPMimeBufferParse()\n"));

    return errorcode;
}

void OSPPMimeDataFree(
    OSPTMIMEMSG *ospvMessage)
{
    OSPM_DBGENTER(("ENTER: OSPPMimeDataFree()\n"));
    OSPPMimePartFree(ospvMessage->MsgPart);
    OSPPMimePartFree(ospvMessage->SigPart);
    OSPM_DBGEXIT(("EXIT : OSPPMimeDataFree()\n"));
}

void OSPPMimeFieldFree(
    OSPTMIMEFIELD *ospvField)
{
    int count = 0;

    OSPM_DBGENTER(("ENTER: OSPPMimeFieldFree()\n"));
    if (ospvField != (OSPTMIMEFIELD *)NULL) {
        if (ospvField->Params != (OSPTMIMEPARAM **)NULL) {
            for (count = 0; count < OSPC_MAX_PARAMS; count++) {
                if (ospvField->Params[count] != (OSPTMIMEPARAM *)NULL) {
                    OSPPMimeParamFree(ospvField->Params[count]);

                    OSPM_FREE(ospvField->Params[count]);
                    ospvField->Params[count] = NULL;
                }
            }
        }
    }
    OSPM_DBGEXIT(("EXIT : OSPPMimeFieldFree()\n"));
}

int OSPPMimeMessageBuild(
    OSPTMIMEMSG *ospvMessage,
    unsigned char **ospvMimeOut,
    unsigned *ospvSizeOfMimeOut)
{
    int errorcode = OSPC_ERR_NO_ERROR;
    unsigned char *next = NULL;
    char msgtmp[20];
    char sigtmp[20];
    int boundln = 0, mshdrln = 0, msszln = 0, sighdrln = 0, sigszln = 0, count = 0, numdelims = 0, numcrlfs = 0;

    if (ospvMessage->SigPart->Length > 0) {
        msszln = sprintf(msgtmp, "%d", ospvMessage->MsgPart->Length);
        mshdrln = OSPM_STRLEN(OSPC_MIME_MSG_HEADER);
        boundln = OSPM_STRLEN(OSPC_MIME_BOUNDARY);
        sigszln = sprintf(sigtmp, "%d", ospvMessage->SigPart->Length), sighdrln = OSPM_STRLEN(OSPC_MIME_SIG_HEADER);
        numdelims = 4;
        numcrlfs = 12;
    }

    OSPM_DBGENTER(("ENTER: OSPPMimeMessageBuild()\n"));
    count = (boundln * 3) + mshdrln + msszln + ospvMessage->MsgPart->Length + sighdrln + sigszln + ospvMessage->SigPart->Length + 2 * numdelims + 2 * numcrlfs;     /* CRLFs, boundary delimiters */

    ospvMessage->Length = count;

    *ospvSizeOfMimeOut = ospvMessage->Length;

    OSPM_MALLOC(*ospvMimeOut, unsigned char, *ospvSizeOfMimeOut);

    if (*ospvMimeOut != (unsigned char *)NULL) {

        OSPM_MEMSET(*ospvMimeOut, 0, *ospvSizeOfMimeOut);

        next = *ospvMimeOut;

        if (ospvMessage->SigPart->Length > 0) {
            /* CRLF for beginning of boundary */
            OSPM_MEMCPY(next, OSPC_MIME_CRLF, 2);

            next += 2;

            /* -- for start of boundary */
            OSPM_MEMCPY(next, OSPC_MIME_BOUNDARY_DELIM, 2);

            next += 2;

            /* boundary */
            OSPM_MEMCPY(next, OSPC_MIME_BOUNDARY, boundln);

            next += boundln;

            /* CRLF */
            OSPM_MEMCPY(next, OSPC_MIME_CRLF, 2);

            next += 2;

            /* Message header */
            OSPM_MEMCPY(next, OSPC_MIME_MSG_HEADER, mshdrln);

            next += mshdrln;

            /* Message length */
            OSPM_MEMCPY(next, msgtmp, msszln);
            next += msszln;

            /* CRLF for end of message header */
            OSPM_MEMCPY(next, OSPC_MIME_CRLF, 2);

            next += 2;

            /* CRLF for beginning of message */
            OSPM_MEMCPY(next, OSPC_MIME_CRLF, 2);

            next += 2;
        }

        /* Message content */

        OSPM_MEMCPY(next, ospvMessage->MsgPart->Content, ospvMessage->MsgPart->Length);

        next += ospvMessage->MsgPart->Length;

        if (ospvMessage->SigPart->Length > 0) {

            /* CRLF for end of message body */
            OSPM_MEMCPY(next, OSPC_MIME_CRLF, 2);

            next += 2;

            /* CRLF for beginning of boundary */
            OSPM_MEMCPY(next, OSPC_MIME_CRLF, 2);

            next += 2;

            /* -- for start of boundary */
            OSPM_MEMCPY(next, OSPC_MIME_BOUNDARY_DELIM, 2);

            next += 2;

            /* boundary */
            OSPM_MEMCPY(next, OSPC_MIME_BOUNDARY, boundln);

            next += boundln;

            /* CRLF for end of boundary */
            OSPM_MEMCPY(next, OSPC_MIME_CRLF, 2);

            next += 2;

            /* Signature Header */
            OSPM_MEMCPY(next, OSPC_MIME_SIG_HEADER, sighdrln);

            next += sighdrln;

            /* Signature length */
            OSPM_MEMCPY(next, sigtmp, sigszln);
            next += sigszln;

            /* CRLF for end of signature header */
            OSPM_MEMCPY(next, OSPC_MIME_CRLF, 2);

            next += 2;

            /* CRLF for beginning of content */
            OSPM_MEMCPY(next, OSPC_MIME_CRLF, 2);

            next += 2;

            /* Signature content */
            OSPM_MEMCPY(next, ospvMessage->SigPart->Content, ospvMessage->SigPart->Length);

            next += ospvMessage->SigPart->Length;

            /* CRLF for end of signature body */
            OSPM_MEMCPY(next, OSPC_MIME_CRLF, 2);

            next += 2;

            /* CRLF for start of boundary */
            OSPM_MEMCPY(next, OSPC_MIME_CRLF, 2);

            next += 2;

            /* -- for start of boundary */
            OSPM_MEMCPY(next, OSPC_MIME_BOUNDARY_DELIM, 2);

            next += 2;

            /* boundary */
            OSPM_MEMCPY(next, OSPC_MIME_BOUNDARY, boundln);

            next += boundln;

            /* -- for end of final boundary */
            OSPM_MEMCPY(next, OSPC_MIME_BOUNDARY_DELIM, 2);

            next += 2;

            /* CRLF for end of boundary */
            OSPM_MEMCPY(next, OSPC_MIME_CRLF, 2);

            next += 2;
        }
    }
    OSPM_DBGEXIT(("EXIT : OSPPMimeMessageBuild()\n"));

    return errorcode;
}

int OSPPMimeMessageCreate(
    unsigned char *ospvMessage,
    unsigned ospvSizeOfMessage,
    unsigned char *ospvSignature,
    unsigned ospvSizeOfSignature,
    unsigned char **ospvMimeMessage,
    unsigned *ospvSizeOfMimeMessage)
{
    int errorcode = OSPC_ERR_NO_ERROR;
    OSPTMIMEMSG msg;

    OSPM_DBGENTER(("ENTER: OSPPMimeMessageCreate()\n"));
    /* Initialize the structure to hold the Mime message data */
    errorcode = OSPPMimeMessageInit(&msg);

    /* Set up the message and signature parts. We will use this function for the
     * signature part as well when we get a real signature in */
    if (errorcode == OSPC_ERR_NO_ERROR) {
        errorcode = OSPPMimeMessageSetContentAndLength(msg.MsgPart, ospvMessage, ospvSizeOfMessage);
    }

    if ((errorcode == OSPC_ERR_NO_ERROR) && (ospvSignature != OSPC_OSNULL)) {
        errorcode = OSPPMimeMessageSetContentAndLength(msg.SigPart, ospvSignature, ospvSizeOfSignature);
    }

    /* Build the MIME message */
    if (errorcode == OSPC_ERR_NO_ERROR) {
        errorcode = OSPPMimeMessageBuild(&msg, ospvMimeMessage, ospvSizeOfMimeMessage);
    }

    /* Free the structure holding the message data */
    OSPPMimeDataFree(&msg);

    OSPM_DBGEXIT(("EXIT : OSPPMimeMessageCreate()\n"));

    return errorcode;
}

int OSPPMimeMessageInit(
    OSPTMIMEMSG *ospvMessage)
{
    int errorcode = OSPC_ERR_NO_ERROR;

    OSPM_DBGENTER(("ENTER: OSPPMimeMessageInit()\n"));
    if (ospvMessage != (OSPTMIMEMSG *)NULL) {
        OSPM_MEMSET(ospvMessage, 0, sizeof(OSPTMIMEMSG));
    } else {
        errorcode = OSPC_ERR_MIME_VAR_NOT_FOUND;
        OSPM_DBGERRORLOG(errorcode, "no pointer found for mime message");
    }

    if (errorcode == OSPC_ERR_NO_ERROR) {
        OSPM_MALLOC(ospvMessage->MsgPart, OSPTMIMEPART, sizeof(OSPTMIMEPART));

        if (ospvMessage->MsgPart == (OSPTMIMEPART *)NULL) {
            errorcode = OSPC_ERR_MIME_MALLOC_FAILED;
            OSPM_DBGERRORLOG(errorcode, "can't malloc message part");
        } else {
            OSPM_MEMSET(ospvMessage->MsgPart, 0, sizeof(OSPTMIMEPART));
        }

        if (errorcode == OSPC_ERR_NO_ERROR) {
            OSPM_MALLOC(ospvMessage->SigPart, OSPTMIMEPART, sizeof(OSPTMIMEPART));

            if (ospvMessage->SigPart == (OSPTMIMEPART *)NULL) {
                errorcode = OSPC_ERR_MIME_MALLOC_FAILED;
                OSPM_DBGERRORLOG(errorcode, "can't malloc signature part");
            } else {
                OSPM_MEMSET(ospvMessage->SigPart, 0, sizeof(OSPTMIMEPART));
            }
        }

        if (errorcode == OSPC_ERR_NO_ERROR) {
            ospvMessage->Length = OSPM_STRLEN(OSPC_MIME_MSG_HEADER) + OSPM_STRLEN(OSPC_MIME_SIG_HEADER);
            ospvMessage->NumParts = 2;
        }
    }
    OSPM_DBGEXIT(("EXIT : OSPPMimeMessageInit()\n"));

    return errorcode;
}

int OSPPMimeMessageParse(
    unsigned char *ospvMessageBuffer,
    unsigned ospvSizeOfMessageBuffer,
    unsigned char *ospvContent,
    unsigned ospvSizeOfContent,
    unsigned char **ospvMessageData,
    unsigned *ospvSizeOfMessageData,
    unsigned char **ospvSignatureData,
    unsigned *ospvSizeOfSignatureData)
{
    int errorcode = OSPC_ERR_NO_ERROR, result = -1;
    OSPTMIMEFIELD content;
    OSPTMIMEBODY mimebody;
    OSPTMIMEPART boundary, body;
    unsigned currpos = 0;

    OSPM_DBGENTER(("ENTER: OSPPMimeMessageParse()\n"));
    OSPM_MEMSET(&mimebody, 0, sizeof(OSPTMIMEBODY));
    OSPM_MEMSET(&body, 0, sizeof(OSPTMIMEPART));
    OSPM_MEMSET(&boundary, 0, sizeof(OSPTMIMEPART));
    OSPM_MEMSET(&content, 0, sizeof(OSPTMIMEFIELD));

    /* Make sure we have only the field body without the field name. */
    while ((isspace(ospvContent[currpos])) && (currpos < ospvSizeOfContent)) {
        currpos++;
    }
    /* if we find a 'c' we have the field name. Get past it */
    if (tolower(ospvContent[currpos]) == 'c') {
        while (currpos < ospvSizeOfContent) {
            if (ospvContent[currpos] == ':') {
                break;
            }
            currpos++;
        }
        /* get past the ':' */
        currpos++;
    }

    /* Is there anything left? If so, get to the chars */
    if (currpos < ospvSizeOfContent) {
        while ((isspace(ospvContent[currpos])) && (currpos < ospvSizeOfContent)) {
            currpos++;
        }
    }

    content.FieldBody.Content = &ospvContent[currpos];
    content.FieldBody.Length = ospvSizeOfContent - currpos;
    body.Content = ospvMessageBuffer;
    body.Length = ospvSizeOfMessageBuffer;

    /* Make sure all the parameters meet our criteria, and copy
     * the ones we intend to keep into their places
     */
    if (errorcode == OSPC_ERR_NO_ERROR) {

        errorcode = OSPPMimeVerifyParameters(&content, &boundary, OSPC_MAIN);
    }

    /* Pull out the body parts, i.e. the message and the signature */
    if (errorcode == OSPC_ERR_NO_ERROR) {
        errorcode = OSPPUtilMemCaseCmp(content.FieldBody.Content, content.FieldBody.Length, "text/plain", OSPM_STRLEN("text/plain"), &result);

        if ((errorcode == OSPC_ERR_NO_ERROR) && (result == 0)) {
            /* Possible Optimization -
             * When it is not a multibody message, there is no need to allocate memory
             * for mimebody.BodyParts[0], we can just set - mimebody.NumBodyParts = 1
             * and that will do. Allocating memory for the 0th element is not required.
             */
            OSPM_MALLOC(mimebody.BodyParts[0], OSPTMIMEPART, sizeof(OSPTMIMEPART));

            if (mimebody.BodyParts[0] != (OSPTMIMEPART *)NULL) {


                OSPM_MEMSET(mimebody.BodyParts[0], 0, sizeof(mimebody.BodyParts[0]));

                mimebody.BodyParts[0]->Content = ospvMessageBuffer;
                mimebody.BodyParts[0]->Length = ospvSizeOfMessageBuffer;
                mimebody.NumBodyParts = 1;
            }
        } else {
            errorcode = OSPPMimeBodyPartsParse(&body, &mimebody, &boundary);
        }
    }

    /* Copy the body parts into the buffers to be sent back. Set the length of each */
    if (errorcode == OSPC_ERR_NO_ERROR) {

        if (mimebody.NumBodyParts > 0) {

            errorcode = OSPPUtilMallocAndCopySubString(mimebody.BodyParts[0]->Content, ospvMessageData, 0, mimebody.BodyParts[0]->Length);
            if (errorcode == OSPC_ERR_NO_ERROR) {

                *ospvSizeOfMessageData = mimebody.BodyParts[0]->Length;

                if (mimebody.NumBodyParts > 1) {
                    errorcode = OSPPUtilMallocAndCopySubString(mimebody.BodyParts[1]->Content, ospvSignatureData, 0, mimebody.BodyParts[1]->Length);

                    if (errorcode == OSPC_ERR_NO_ERROR) {

                        *ospvSizeOfSignatureData = mimebody.BodyParts[1]->Length;
                    }
                }
            }
        } else {
            errorcode = OSPC_ERR_MIME_MSG_PARTS_NOT_FOUND;
            OSPM_DBGERRORLOG(errorcode, "not enough message parts for full message");
        }
    }

    OSPPMimeFieldFree(&content);

    if (OSPM_STRSTR((const char *)content.FieldBody.Content, "multipart")) {
        OSPPMimeBodyFree(&mimebody);
    } else {
        OSPM_FREE(mimebody.BodyParts[0]);
    }

    if (boundary.Content) {
        OSPM_FREE(boundary.Content);
        boundary.Content = OSPC_OSNULL;
    }
    OSPM_DBGEXIT(("EXIT : OSPPMimeMessageParse()\n"));

    return errorcode;
}

long __mptr = 0;

int OSPPMimeMessageSetContentAndLength(
    OSPTMIMEPART *ospvMimePart,
    unsigned char *ospvMsgBuffer,
    unsigned ospvSizeOfMsgBuffer)
{
    int errorcode = OSPC_ERR_NO_ERROR;

    OSPM_DBGENTER(("ENTER: OSPPMimeMessageSetContentAndLength()\n"));
    if (ospvSizeOfMsgBuffer > 0) {

        OSPM_MALLOC(ospvMimePart->Content, unsigned char, ospvSizeOfMsgBuffer + 1);

        if (ospvMimePart->Content != (unsigned char *)NULL) {

            OSPM_MEMCPY(ospvMimePart->Content, ospvMsgBuffer, ospvSizeOfMsgBuffer);

            ospvMimePart->Length = ospvSizeOfMsgBuffer;

        } else {
            errorcode = OSPC_ERR_MIME_MALLOC_FAILED;
            OSPM_DBGERRORLOG(errorcode, "can't malloc msg content part");
        }
    } else {
        errorcode = OSPC_ERR_MIME_NO_INPUT;
        OSPM_DBGERRORLOG(errorcode, "no data input for msg part");
    }
    OSPM_DBGEXIT(("EXIT : OSPPMimeMessageSetContentAndLength()\n"));

    return errorcode;
}

void OSPPMimeParamFree(
    OSPTMIMEPARAM *ospvParam)
{
    OSPM_DBGENTER(("ENTER: OSPPMimeParamFree()\n"));
    if (ospvParam != (OSPTMIMEPARAM *)NULL) {
        OSPPMimePartFree(ospvParam->ParamName);
        OSPPMimePartFree(ospvParam->ParamValue);
    }
    OSPM_DBGEXIT(("EXIT : OSPPMimeParamFree()\n"));
}

int OSPPMimeParamsParse(
    OSPTMIMEFIELD *ospvField)
{
    int errorcode = OSPC_ERR_NO_ERROR;
    unsigned start = 0;
    unsigned currpos = 0;
    unsigned bufend = ospvField->FieldBody.Length;
    unsigned char *bufptr = ospvField->FieldBody.Content;
    unsigned count = 0;
    unsigned len = 0;

    OSPM_DBGENTER(("ENTER: OSPPMimeParamsParse()\n"));
    if (bufptr != (unsigned char *)NULL) {

        /* Get past the type/subtype string */
        while ((bufptr[currpos] != ';') && (bufptr[currpos] != '\n') && (currpos < bufend)) {
            currpos++;
        }

        /* pass the ; */
        if (bufptr[currpos] == ';') {
            currpos++;

            /* Now get the name = value pairs and store them */
            while ((ospvField->NumParams < OSPC_MAX_PARAMS) && (currpos < bufend)) {

                /* Skip spaces, tabs, newlines, and stray ';' */
                while (currpos < bufend) {
                    if ((bufptr[currpos] != ' ') && (bufptr[currpos] != '\t') && (bufptr[currpos] != '\n') && (bufptr[currpos] != ';')) {
                        break;
                    }
                    ++currpos;
                }
                start = currpos;

                while (currpos < bufend) {
                    if (bufptr[currpos] == '=') {
                        break;
                    }
                    currpos++;
                }
                len = currpos - start;

                /* remove white space at end */
                while (len > 0) {
                    if (!isspace(bufptr[currpos - 1])) {
                        break;
                    }
                    --len;
                }

                /* Create Param structure */
                OSPM_MALLOC(ospvField->Params[count], OSPTMIMEPARAM, sizeof(OSPTMIMEPARAM));

                if (ospvField->Params[count] != (OSPTMIMEPARAM *)NULL) {

                    OSPM_MEMSET(ospvField->Params[count], 0, sizeof(OSPTMIMEPARAM));

                    /* Create Param Name Structure */
                    OSPM_MALLOC(ospvField->Params[count]->ParamName, OSPTMIMEPART, sizeof(OSPTMIMEPART));

                    if (ospvField->Params[count]->ParamName != (OSPTMIMEPART *)NULL) {

                        OSPM_MEMSET(ospvField->Params[count]->ParamName, 0, sizeof(OSPTMIMEPART));


                        errorcode = OSPPUtilMallocAndCopySubString(ospvField->FieldBody.Content,
                                                                   &(ospvField->Params[count])->ParamName->Content, start, len);
                    } else {
                        errorcode = OSPC_ERR_MIME_MALLOC_FAILED;
                        OSPM_DBGERRORLOG(errorcode, "malloc failed for param name structure");
                    }
                } else {
                    errorcode = OSPC_ERR_MIME_MALLOC_FAILED;
                    OSPM_DBGERRORLOG(errorcode, "malloc failed for param structure");
                }

                /* Now get value */
                if (errorcode == OSPC_ERR_NO_ERROR) {

                    ospvField->Params[count]->ParamName->Length = len;

                    if ((currpos < bufend) && (bufptr[currpos] == '=')) {
                        currpos++;
                    }

                    /* Skip spaces and tabs */
                    while (currpos < bufend) {
                        if ((bufptr[currpos] != ' ') && (bufptr[currpos] != '\t')) {
                            break;
                        }
                        ++currpos;
                    }
                    start = currpos;
                    len = 0;

                    /* Get value */
                    while (currpos < bufend) {

                        /* ; means we are at the end of the param value
                         * get rid of it */
                        if (bufptr[currpos] == ';') {
                            break;
                        }

                        if (bufptr[currpos] == '\n') {

                            /* Are we at the end of the data? */
                            if (currpos == bufend - 1) {
                                currpos++;
                                break;
                            }

                            /* Is this really the end of the param value, and not just the end
                             * of a wrapped line? */
                            else if ((bufptr[currpos + 1] != ' ') && (bufptr[currpos + 1] != '\t')) {
                                currpos++;
                                break;
                            }
                        }
                        currpos++;
                    }

                    /* remove whitespace at end of value */
                    while (currpos > start) {
                        if (!isspace(bufptr[currpos - 1])) {
                            break;
                        }
                        --currpos;
                    }
                    len = currpos - start;

                    /* Create Param Value Structure */
                    OSPM_MALLOC(ospvField->Params[count]->ParamValue, OSPTMIMEPART, sizeof(OSPTMIMEPART));

                    if (ospvField->Params[count]->ParamValue != (OSPTMIMEPART *)NULL) {

                        OSPM_MEMSET(ospvField->Params[count]->ParamValue, 0, sizeof(OSPTMIMEPART));


                        errorcode = OSPPUtilMallocAndCopySubString(ospvField->FieldBody.Content,
                                                                   &(ospvField->Params[count])->ParamValue->Content, start, len);
                    } else {
                        errorcode = OSPC_ERR_MIME_MALLOC_FAILED;
                        OSPM_DBGERRORLOG(errorcode, "malloc failed for param value structure");
                    }

                    if (errorcode == OSPC_ERR_NO_ERROR) {
                        ospvField->Params[count]->ParamValue->Length = len;
                        ospvField->NumParams++;
                    }
                }
                count++;
            }

            if ((count == OSPC_MAX_PARAMS) && (currpos != bufend)) {

                errorcode = OSPC_ERR_MIME_NO_MORE_SPACE;
                OSPM_DBGERRORLOG(errorcode, "no space for this parameter");
            }
        }
    }
    OSPM_DBGEXIT(("EXIT : OSPPMimeParamsParse()\n"));

    return errorcode;
}

void OSPPMimePartFree(
    OSPTMIMEPART *ospvPart)
{
    OSPM_DBGENTER(("ENTER: OSPPMimePartFree()\n"));
    if (ospvPart->Content != (unsigned char *)NULL) {
        OSPM_FREE(ospvPart->Content);
        ospvPart->Content = OSPC_OSNULL;
    }

    if (ospvPart != (OSPTMIMEPART *)NULL) {
        OSPM_FREE(ospvPart);
        ospvPart = OSPC_OSNULL;
    }
    OSPM_DBGEXIT(("EXIT : OSPPMimePartFree()\n"));
}

int OSPPMimeVerifyParameters(
    OSPTMIMEFIELD *ospvContent,
    OSPTMIMEPART *ospvBoundary,
    int ospvHeaderType)
{
    int errorcode = OSPC_ERR_NO_ERROR;
    unsigned pcount = 0;
    int result = 0;
    int pfound = 0;

    OSPM_DBGENTER(("ENTER: OSPPMimeVerifyParameters()\n"));
    switch (ospvHeaderType) {
    case OSPC_MAIN:
        /* verify content-type, protocol, micalg, boundary, length */

        /* found content-type, now check type and subtype */
        errorcode = OSPPUtilMemCaseCmp(ospvContent->FieldBody.Content,
            ospvContent->FieldBody.Length, "multipart/signed", OSPM_STRLEN("multipart/signed"), &result);

        if ((errorcode == OSPC_ERR_NO_ERROR) && (result == 0)) {

            /* Parse parameters into structure for easier compares */
            errorcode = OSPPMimeParamsParse(ospvContent);

            if (errorcode == OSPC_ERR_NO_ERROR) {

                pcount = 0;
                pfound = 0;

                /* check protocol */
                while ((pcount < ospvContent->NumParams) && (!pfound)) {
                    errorcode = OSPPUtilMemCaseCmp(ospvContent->Params[pcount]->ParamName->Content,
                        ospvContent->Params[pcount]->ParamName->Length, "protocol", OSPM_STRLEN("protocol"), &result);

                    if ((errorcode == OSPC_ERR_NO_ERROR) && (result == 0)) {
                        pfound = 1;
                        break;
                    }

                    pcount++;
                }

                if (pfound) {
                    /* copy the protocol string somewhere to save it for SECURITY
                     * remember to strip off double quotes
                     */
                } else {
                    errorcode = OSPC_ERR_MIME_PROTOCOL_NOT_FOUND;
                    OSPM_DBGERRORLOG(errorcode, "protocol parameter not found");
                }
            }

            if (errorcode == OSPC_ERR_NO_ERROR) {

                pcount = 0;
                pfound = 0;

                /* check micalg */
                while ((pcount < ospvContent->NumParams) && (!pfound)) {


                    errorcode = OSPPUtilMemCaseCmp(ospvContent->Params[pcount]->ParamName->Content,
                        ospvContent->Params[pcount]->ParamName->Length, "micalg", OSPM_STRLEN("micalg"), &result);

                    if ((errorcode == OSPC_ERR_NO_ERROR) && (result == 0)) {
                        pfound = 1;
                        break;
                    }

                    pcount++;
                }

                if (pfound) {
                    /* copy this out to hand up to SECURITY */

                } else {
                    errorcode = OSPC_ERR_MIME_MICALG_NOT_FOUND;
                    OSPM_DBGERRORLOG(errorcode, "micalg not found");
                }
            }

            if (errorcode == OSPC_ERR_NO_ERROR) {

                pcount = 0;
                pfound = 0;

                /* get boundary */
                while ((pcount < ospvContent->NumParams) && (!pfound)) {

                    errorcode = OSPPUtilMemCaseCmp(ospvContent->Params[pcount]->ParamName->Content,
                        ospvContent->Params[pcount]->ParamName->Length, "boundary", OSPM_STRLEN("boundary"), &result);

                    if ((errorcode == OSPC_ERR_NO_ERROR) && (result == 0)) {
                        pfound = 1;
                        break;
                    }

                    pcount++;
                }

                if (pfound) {
                    OSPM_MALLOC(ospvBoundary->Content, unsigned char, ospvContent->Params[pcount]->ParamValue->Length);

                    if (ospvBoundary->Content != (unsigned char *)NULL) {

                        OSPM_MEMSET(ospvBoundary->Content, 0, ospvContent->Params[pcount]->ParamValue->Length);

                        OSPM_MEMCPY(ospvBoundary->Content,
                            ospvContent->Params[pcount]->ParamValue->Content, ospvContent->Params[pcount]->ParamValue->Length);

                        ospvBoundary->Length = ospvContent->Params[pcount]->ParamValue->Length;
                    } else {
                        errorcode = OSPC_ERR_MIME_MALLOC_FAILED;
                        OSPM_DBGERRORLOG(errorcode, "malloc failed for boundary content");
                    }
                }   /* end if (pfound) */
                else {
                    errorcode = OSPC_ERR_MIME_BOUNDARY_NOT_FOUND;
                    OSPM_DBGERRORLOG(errorcode, "boundary not found");
                }
            } else if (result != 0) {

                errorcode = OSPC_ERR_MIME_INVALID_SUBTYPE;
                OSPM_DBGERRORLOG(errorcode, "subtype does not match");
            }
        } else {
            errorcode = OSPPUtilMemCaseCmp(ospvContent->FieldBody.Content,
                ospvContent->FieldBody.Length, "text/plain", OSPM_STRLEN("text/plain"), &result);

            if (errorcode == OSPC_ERR_NO_ERROR) {
                /* Parse parameters into structure for easier compares */
                errorcode = OSPPMimeParamsParse(ospvContent);
            }
        }
        break;
    case OSPC_BODY:
        /* verify content-type, length */
        break;
    case OSPC_SIGNATURE:
        /* verify content-type, length */
        break;
    default:
        errorcode = OSPC_ERR_MIME_INVALID_TYPE;
        OSPM_DBGERRORLOG(errorcode, "invalid header type");
        break;
    }
    OSPM_DBGEXIT(("EXIT : OSPPMimeVerifyParameters()\n"));

    return errorcode;
}

int OSPPUtilMallocAndCopySubString(
    unsigned char *ospvSrcString,
    unsigned char **ospvDestString,
    unsigned ospvStartOfSubString,
    unsigned ospvSizeOfSubString)
{
    int errorcode = OSPC_ERR_NO_ERROR;

    OSPM_DBGENTER(("ENTER: OSPPUtilMallocAndCopySubString()\n"));
    if (&ospvSrcString[ospvStartOfSubString] != (unsigned char *)NULL) {
        OSPM_MALLOC(*ospvDestString, unsigned char, ospvSizeOfSubString + 1);

        if (*ospvDestString != (unsigned char *)NULL) {
            OSPM_MEMSET(*ospvDestString, 0, ospvSizeOfSubString + 1);

            OSPM_MEMCPY(*ospvDestString, &ospvSrcString[ospvStartOfSubString], ospvSizeOfSubString);
        } else {
            errorcode = OSPC_ERR_UTIL_MALLOC_FAILED;
            OSPM_DBGERRORLOG(errorcode, "malloc failed for mallocandcopystring");
        }
    } else {
        errorcode = OSPC_ERR_UTIL_VALUE_NOT_FOUND;
        OSPM_DBGERRORLOG(errorcode, "no string for mallocandcopystring");
    }
    OSPM_DBGEXIT(("EXIT : OSPPUtilMallocAndCopySubString()\n"));

    return errorcode;
}

int OSPPUtilMemCaseCmp(
    unsigned char *ospvMem1,
    unsigned ospvLen1,
    char *ospvMem2,
    unsigned ospvLen2,
    int *ospvResult)
{
    int errorcode = OSPC_ERR_NO_ERROR;
    unsigned count = 0;
    unsigned len = OSPM_MIN(ospvLen1, ospvLen2);
    int char1 = 0;
    int char2 = 0;

    OSPM_DBGENTER(("ENTER: OSPPUtilMemCaseCmp()\n"));
    *ospvResult = 0;

    if ((ospvMem1 != (unsigned char *)NULL) && (ospvMem2 != (char *)NULL)) {

        for (count = 0; count < len; ++count) {
            char1 = tolower(ospvMem1[count]);
            char2 = tolower(ospvMem2[count]);
            if (char1 < char2) {
                *ospvResult = -1;
                break;
            } else if (char1 > char2) {
                *ospvResult = 1;
                break;
            }
        }   /* end for */
    } else {
        errorcode = OSPC_ERR_MIME_INVALID_ARG;
        OSPM_DBGERRORLOG(errorcode, "no data for compare");
    }
    OSPM_DBGEXIT(("EXIT : OSPPUtilMemCaseCmp()\n"));

    return errorcode;
}

/* End of file */
