dmose%mozilla.org 9fc7780ead updating license boilerplate to xPL v1.1
git-svn-id: svn://10.0.0.236/trunk@52523 18797224-902f-48f8-a5cc-f745e15eee43
1999-11-02 06:20:05 +00:00

2045 lines
40 KiB
C

/*
* The contents of this file are subject to the Netscape Public
* License Version 1.1 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.mozilla.org/NPL/
*
* Software distributed under the License is distributed on an "AS
* IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
* implied. See the License for the specific language governing
* rights and limitations under the License.
*
* The Original Code is the Netscape Messaging Access SDK Version 3.5 code,
* released on or about June 15, 1998. *
* The Initial Developer of the Original Code is Netscape Communications
* Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All
* Rights Reserved.
*
* Contributor(s): ______________________________________.
*/
/*
* Copyright (c) 1997 and 1998 Netscape Communications Corporation
* (http://home.netscape.com/misc/trademarks.html)
*/
/*
* util.c
*
* Prasad, Nov 1997
* clee, Oct 1997
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <malloc.h>
#include <ctype.h>
#include <memory.h>
#include <time.h>
#include "vector.h"
#include "util.h"
#include "mime.h"
#include "mime_internal.h"
#include "mimeparser.h"
static errorLog_t *g_pLog; /* default error log file */
#define CR '\r'
#define LF '\n'
/* base64 translation table */
struct
{
unsigned char digits[66];
unsigned char xlate[256];
unsigned char xlate_table_made;
} base64 =
{
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
"",
0
};
/* ------------------- utility functions ------------------ */
#ifdef HPUX
#define GETTIMEOFDAY(x) gettimeofday(x,(void *)NULL)
#elif defined(AIX)
#define GETTIMEOFDAY(x) gettimeofday(x,(void *)NULL)
#else
#define GETTIMEOFDAY(x) gettimeofday(x)
#endif
/*
* carsonl, jan 8,98
* determine if both strings are the same based on the length of the second string
* case insensitive
*
* parameter :
*
* s1 : first string
* s2 : second string
*
* returns : TRUE if equals
*/
int bStringEquals( char *s1, char *s2 )
{
static char achBuffer[64];
int len;
if ( s1 != NULL && s2 != NULL )
{
len = strlen( s2 );
strncpy( achBuffer, s1, len );
achBuffer[len] = 0;
#ifdef XP_UNIX
if (strcasecmp (achBuffer, s2) == 0)
return TRUE;
#else
if ( stricmp( achBuffer, s2 ) == 0 )
return TRUE;
#endif
}
return FALSE;
}
/* If s1 equals s2, returns TRUE, FALSE otherwise. */
BOOLEAN equalsIgnoreCase (char * s1, char * s2)
{
#ifdef XP_UNIX
if (strcasecmp (s1, s2) == 0)
return TRUE;
else
return FALSE;
#else
if (stricmp (s1, s2 ) == 0)
return TRUE;
else
return FALSE;
#endif
}
/*
* carsonl, jan 8,98
* right trim
*
* parameter :
*
* s : string to be trimmed
*
* returns : string
*/
char *szRTrim( char *s )
{
int i;
if ( s != NULL )
{
for ( i = strlen(s); i > 0; i-- )
{
if ( isspace( s[i-1] ) )
s[i-1] = 0;
else
return s;
}
}
return s;
}
/*
* carsonl, jan 8,98
* left trim
*
* parameter :
*
* s : string to be trimmed
*
* returns : string
*/
char *szLTrim( char *s )
{
char *ss = NULL;
int i;
int len;
if ( s != NULL )
{
ss = s;
len = strlen( s );
for ( i = 0; i < len; i++, ss++ )
{
if ( !isspace( s[i] ) )
return ss;
}
}
return ss;
}
/*
* carsonl, jan 8,98
* trim both sides of the string
*
* parameter :
*
* s : string to be trimmed
*
* returns : string
*/
char *szTrim( char *s ) { return szLTrim( szRTrim( s ) ); }
/*
* carsonl, jan 8,98
* return a new copy of a string passed in
*
* parameter :
*
* s : string to be cloned
*
* returns : cloned string
*/
char *szStringClone( char *s )
{
char *s2 = NULL;
int len;
if ( s != NULL )
{
len = strlen( s );
if ( len > 0 )
{
s2 = (char *) malloc( len + 1 );
if ( s2 != NULL )
strcpy( s2, s );
}
}
return s2;
}
/*
* carsonl, jan 8,98
* determine if content type is a basicpart
*
* parameter :
*
* int nType : content type
*
* returns : TRUE if basicpart
*/
BOOLEAN bIsBasicPart( int nType )
{
if (nType == MIME_CONTENT_TEXT ||
nType == MIME_CONTENT_AUDIO ||
nType == MIME_CONTENT_IMAGE ||
nType == MIME_CONTENT_VIDEO ||
nType == MIME_CONTENT_APPLICATION )
return TRUE;
return FALSE;
}
/* --------------------------------------------- */
/*
* carsonl, jan 8,98
* Decodes a string encoded in RFC2047 format. If the string is not encoded
* returns the original string. Can be used on the header value returned by
* getHeader() and getAllHeaders() methods in MIMEMessage class.
*
* parameter :
*
* szInputString : string to be trimmed
*
* return : The decoded header string.
*/
char *decodeHeader( char *szInputString )
{
int len, retLen = 0;
int i, j, outBytes, outBits;
int nStart = 0;
int nEnd = 0;
char *szEncodedText = NULL;
char *szDecodedText = NULL;
char *plainPart = NULL, *retBuf=NULL;
char *leftOverBuf=NULL, *leftOverDecodedBuf=NULL;
int plainTextLen = 0, leftOverLen=0;
char achCharset[16];
BOOLEAN bEncodeBase64 = FALSE;
BOOLEAN bEncodeQP = FALSE;
BOOLEAN bEncodeString = FALSE;
if ( szInputString == NULL )
return NULL;
len = strlen( szInputString );
/* find start of encoding text */
for ( i = 0; i < len && szInputString[i] != 0 ; i++ )
{
if ( szInputString[i] == '=' && szInputString[i+1] == '?' )
{
bEncodeString = TRUE;
break;
}
}
if (bEncodeString == FALSE)
return (strdup (szInputString));
if (i > 0)
{
plainTextLen = (i);
plainPart = malloc (i+1);
strncpy (plainPart, szInputString, plainTextLen);
plainPart [i] = 0;
}
/* get charset */
for ( i += 2, j = 0; i < len && szInputString[i] != '?' && j < 15; i++, j++ )
{
achCharset[j] = szInputString[i];
}
achCharset[j] = 0;
i++; /* skip ? */
/* get encoding type */
if ( szInputString[i] == 'Q' || szInputString[i] == 'q' )
bEncodeQP = TRUE;
else if ( szInputString[i] == 'B' || szInputString[i] == 'b' )
bEncodeBase64 = TRUE;
if (szInputString[i] == '?' )
i++; /* skip ? */
nStart = ++i;
/* look for end of encoded text */
for ( j = 0; i < len && szInputString[i] != 0; i++, j++ )
{
if ( szInputString[i] == '?' && (i+1) < len && szInputString[i+1] == '=' )
{
nEnd = i;
break;
}
}
if ( nEnd > 0 )
{
/* extract encoded text */
szEncodedText = (char *) malloc( j + 1 );
szDecodedText = (char *) malloc( j + 1 );
if ( szEncodedText != NULL && szDecodedText != NULL )
{
strncpy( szEncodedText, &szInputString[nStart], j );
if ( bEncodeQP )
decodeQP( szEncodedText, szDecodedText, j );
else if ( bEncodeBase64 )
decodeBase64( szEncodedText, szDecodedText, j, j, &outBytes, &outBits );
free( szEncodedText );
}
}
if (nEnd+2 < len-1)
{
leftOverLen = len - (nEnd+2);
leftOverBuf = malloc (leftOverLen + 1);
strncpy (leftOverBuf, &szInputString[nEnd+2], leftOverLen);
leftOverBuf [leftOverLen] = 0;
leftOverDecodedBuf = decodeHeader (leftOverBuf);
}
retLen = plainTextLen + strlen (szDecodedText) + strlen (leftOverDecodedBuf);
retBuf = malloc (retLen +1);
if (plainPart != NULL && szDecodedText != NULL && leftOverDecodedBuf != NULL)
{
sprintf (retBuf, "%s%s%s", plainPart, szDecodedText, leftOverDecodedBuf);
free (plainPart);
free (szDecodedText);
free (leftOverBuf);
free (leftOverDecodedBuf);
}
else if (plainPart != NULL && szDecodedText != NULL)
{
sprintf (retBuf, "%s%s", plainPart, szDecodedText);
free (plainPart);
free (szDecodedText);
}
else if (szDecodedText != NULL && leftOverDecodedBuf != NULL)
{
sprintf (retBuf, "%s%s", szDecodedText, leftOverDecodedBuf);
free (szDecodedText);
free (leftOverBuf);
free (leftOverDecodedBuf);
}
else if (szDecodedText != NULL)
{
free (retBuf);
return szDecodedText;
}
else
{
free (retBuf);
return null;
}
return retBuf;
}
/*
* Prasad
* Generates and returns a boundary string that can be used in multi-parts etc.
*
* @return The boundary string.
*/
char * generateBoundary()
{
int randval1, randval2;
struct timeval tv;
char ca[100];
char * pca;
int ct;
static int prev_randval1=0, prev_randval2=0, counter = 0;
#ifdef WIN32
time_t ltime;
struct tm *ptm;
time( &ltime );
ptm = localtime( &ltime );
ct = ptm->tm_sec;
#else
/*gettimeofday (&tv);*/
GETTIMEOFDAY(&tv);
ct = tv.tv_sec;
#endif
/*srand ((unsigned int)ct);*/
srand ((unsigned int)clock());
randval1 = rand();
randval2 = rand();
/*if (randval1 == prev_randval1 || randval2 == prev_randval2)*/
{
counter++;
randval1 += counter * 200;
randval2 += counter * 200;
}
prev_randval1 = randval1;
prev_randval2 = randval2;
pca = ca;
sprintf (pca, "-------");
pca += 7;
sprintf (pca, "%x%x%x%x", randval1, randval2, randval1, randval2);
return (strdup (ca));
}
/*
* carsonl, jan 8,98
* hex to decimal
*
* parameter :
*
* int nFirstByte : first hex byte
* int nSecondByte : second hex byte
*
* returns : decimal
*/
int nConvertHexToDec( int nFirstByte, int nSecondByte )
{
int nValue = 0;
switch ( nFirstByte )
{
case ' ':
case '0': nValue += 0; break;
case '1': nValue += 16; break;
case '2': nValue += 32; break;
case '3': nValue += 48; break;
case '4': nValue += 64; break;
case '5': nValue += 80; break;
case '6': nValue += 96; break;
case '7': nValue += 112; break;
case '8': nValue += 128; break;
case '9': nValue += 144; break;
case 'A':
case 'a': nValue += 160; break;
case 'B':
case 'b': nValue += 176; break;
case 'C':
case 'c': nValue += 192; break;
case 'D':
case 'd': nValue += 208; break;
case 'E':
case 'e': nValue += 224; break;
case 'F':
case 'f': nValue += 240; break;
}
switch ( nSecondByte )
{
case ' ':
case '0': nValue += 0; break;
case '1': nValue += 1; break;
case '2': nValue += 2; break;
case '3': nValue += 3; break;
case '4': nValue += 4; break;
case '5': nValue += 5; break;
case '6': nValue += 6; break;
case '7': nValue += 7; break;
case '8': nValue += 8; break;
case '9': nValue += 9; break;
case 'A':
case 'a': nValue += 10; break;
case 'B':
case 'b': nValue += 11; break;
case 'C':
case 'c': nValue += 12; break;
case 'D':
case 'd': nValue += 13; break;
case 'E':
case 'e': nValue += 14; break;
case 'F':
case 'f': nValue += 15; break;
}
return nValue;
}
/* ========================= STREAM UTILITIES =============================*/
/*
* Prasad, jan 8,98
* Reader function for a buffer based mime_inputstream
* Note buf space is allocated/freed by the caller.
*
* parameter :
*
* return :
*/
int buf_instream_read (void * rock, char *buf, int size)
{
buf_instream_tracker_t * pStream;
int bytes_to_read = 0, bytes_left;
if (rock == NULL || buf == NULL || size <= 0)
{
return MIME_ERR_INVALIDPARAM;
}
pStream = (buf_instream_tracker_t *) rock;
if (pStream->pDataBuf == NULL)
{
return MIME_ERR_INVALIDPARAM;
}
bytes_left = pStream->total_size - pStream->bytes_read;
if (bytes_left <= 0)
{
return MIME_ERR_EOF;
}
if (bytes_left >= size)
bytes_to_read = size;
else
bytes_to_read = bytes_left;
memcpy( buf, pStream->pNext, bytes_to_read );
buf [bytes_to_read] = NULL; /* NULL terminate it */
if (bytes_to_read == size)
{
/* we still have data to read on the stream */
pStream->bytes_read += bytes_to_read;
if (pStream->bytes_read < pStream->total_size)
pStream->pNext += bytes_to_read;
else
pStream->pNext = pStream->pDataBuf + pStream->total_size -1; /* on last byte */
}
else
{
/* We returned less than what was asked. So we are at EOF */
pStream->bytes_read = pStream->total_size;
pStream->pNext = pStream->pDataBuf + pStream->total_size -1; /* on last byte */
}
return bytes_to_read;
}
/*
* Prasad, jan 8,98
* Rewind function for a buffer based mime_inputstream
*
* parameter : rock
*
* return : nothing
*/
void buf_instream_rewind (void * rock)
{
buf_instream_tracker_t * pStream;
if (rock == NULL)
return;
pStream = (buf_instream_tracker_t *) rock;
pStream->bytes_read = 0;
pStream->pNext = pStream->pDataBuf;
}
/*
* Prasad, jan 8,98
* Close function for a buffer based mime_inputstream
* The client must free the stream after return from close.
*
* parameter : rock
*
* return : nothing
*/
void buf_instream_close (void * rock)
{
buf_instream_tracker_t * pStream;
if (rock == NULL)
{
return;
}
pStream = (buf_instream_tracker_t *) rock;
free (pStream->pDataBuf);
pStream->pDataBuf = NULL;
pStream->pNext = NULL;
pStream->total_size = 0;
pStream->bytes_read = 0;
free (rock);
/* rock = NULL; */
}
/*
* Prasad, jan 8,98
* Makes and returns an input stream out of the databuffer Passed.
* Uses the passed buffer as is. That is, data is not copied.
* data_size must be identical to actual size of data in pDataBuf.
*
* parameter :
*
* return :
*/
int buf_instream_create (char * pDataBuf, long data_size, nsmail_inputstream_t ** ppRetInputStream)
{
nsmail_inputstream_t * pNewStream;
buf_instream_tracker_t * pTracker;
if (pDataBuf == NULL || data_size <= 0)
{
return MIME_ERR_INVALIDPARAM;
}
pNewStream = (nsmail_inputstream_t *) malloc (sizeof (nsmail_inputstream_t));
if (pNewStream == NULL)
{
return MIME_ERR_OUTOFMEMORY;
}
pTracker = (buf_instream_tracker_t *) malloc (sizeof (buf_instream_tracker_t));
if (pTracker == NULL)
{
return MIME_ERR_OUTOFMEMORY;
}
pTracker->pDataBuf = pDataBuf;
pTracker->pNext = pDataBuf;
pTracker->total_size = data_size;
pTracker->bytes_read = 0;
pNewStream->rock = (void *) pTracker;
pNewStream->read = buf_instream_read;
pNewStream->rewind = buf_instream_rewind;
pNewStream->close = buf_instream_close;
*ppRetInputStream = pNewStream;
return MIME_OK;
}
/*
* Prasad, jan 8,98
* Appends src to dest and return the length of src string.
* Assumes there is enough room in dest.
*
* parameter :
*
* return :
*/
int append_str (char * dest, char * src)
{
int len;
len = strlen (src);
if (len > 0)
strncpy (dest, src, len);
return len;
}
/*
* Prasad, jan 8,98
* Reader function for a file based mime_inputstream
* Note: buf space is allocated/freed by the caller.
*
* parameter :
*
* return :
*/
int file_instream_read (void * rock, char *buf, int size)
{
file_instream_tracker_t * pStream;
int read_len = 0;
if (rock == NULL)
{
return -1;
}
pStream = (file_instream_tracker_t *) rock;
if (pStream->fp == NULL)
{
return -1;
}
read_len = fread (buf, sizeof (char), size, pStream->fp);
buf [read_len] = NULL; /* NULL terminate it */
if (read_len > 0)
(pStream->bytes_read += read_len);
else
read_len = -1;
return read_len;
}
/*
* Prasad, jan 8,98
* Rewind function for a file based mime_inputstream
*
* parameter : rock
*
* return : nothing
*/
void file_instream_rewind (void * rock)
{
file_instream_tracker_t * pStream;
if (rock == NULL)
{
return;
}
pStream = (file_instream_tracker_t *) rock;
if (pStream->fp == NULL)
{
return;
}
rewind (pStream->fp);
pStream->bytes_read = 0;
}
/*
* Prasad, jan 8,98
* Close function for a file based mime_inputstream
* The client must free the stream after return from close.
*
* parameter : rock
*
* return : nothing
*/
void file_instream_close (void * rock)
{
file_instream_tracker_t * pStream;
if (rock == NULL)
{
return;
}
pStream = (file_instream_tracker_t *) rock;
if (pStream->fp == NULL)
{
free (rock);
return;
}
fclose (pStream->fp);
free (pStream->file_name);
free (rock);
}
/*
* Prasad, jan 8,98
* Makes and returns an input stream out of the fileName Passed.
* NOTE: fileName must be that of an existing file since this is an inputStream.
*
* parameter :
*
* return :
*/
int file_instream_create (char * fileName, nsmail_inputstream_t ** ppRetInputStream)
{
FILE * fp;
nsmail_inputstream_t * pNewStream;
file_instream_tracker_t * pTracker;
if (fileName == NULL || ppRetInputStream == NULL)
{
return MIME_ERR_INVALIDPARAM;
}
if ((fp = fopen(fileName, "rb")) == (FILE *) NULL)
{
return MIME_ERR_CANTOPENFILE;
}
pNewStream = (nsmail_inputstream_t *) malloc (sizeof (nsmail_inputstream_t));
if (pNewStream == NULL)
{
return MIME_ERR_OUTOFMEMORY;
}
pTracker = (file_instream_tracker_t *) malloc (sizeof (file_instream_tracker_t));
if (pTracker == NULL)
{
return MIME_ERR_OUTOFMEMORY;
}
pTracker->file_name = (char *) strdup (fileName);
pTracker->fp = fp;
pTracker->bytes_read = 0;
pNewStream->rock = (void *) pTracker;
pNewStream->read = file_instream_read;
pNewStream->rewind = file_instream_rewind;
pNewStream->close = file_instream_close;
*ppRetInputStream = pNewStream;
return 0;
}
/*
* Prasad, jan 8,98
* Returns the size of data that is available on the inputstream. -1 on an error.
*
* parameter :
*
* return :
*/
long get_inputstream_size (nsmail_inputstream_t * pTheStream)
{
static char * pLocalBuf; /* allocated only once */
long stream_size = 0;
long read_size = 0;
if (pLocalBuf == NULL)
pLocalBuf = (char *) malloc (MIME_BUFSIZE+1); /* allocated only once */
if (pLocalBuf == NULL)
{
return MIME_ERR_OUTOFMEMORY;
}
while (TRUE)
{
read_size = pTheStream->read (pTheStream->rock, pLocalBuf, MIME_BUFSIZE);
if (read_size > 0)
{
stream_size += read_size;
read_size = 0;
}
else
break;
} /* while */
if (stream_size > 0)
{
pTheStream->rewind (pTheStream->rock);
return (stream_size);
}
else
return (-1);
} /* get_inputstream_size */
char * getFileShortName (char * fileName)
{
char * pCh;
int i, len;
#ifdef XP_UNIX
#define SEPCHAR '/'
#else
#define SEPCHAR '\\'
#endif
if (fileName != NULL)
{
len = strlen (fileName);
if (len <= 2)
return NULL;
pCh = fileName + len;
for (i = len -1; i >= 0; i--)
{
if (fileName [i] == SEPCHAR)
{
return strdup (pCh);
}
pCh--;
}
return strdup (fileName);
}
return NULL;
}
char * getFileExtn (char * fileName)
{
char * pCh;
int i, len;
if (fileName != NULL)
{
len = strlen (fileName);
if (len <= 2)
return NULL;
pCh = fileName + len;
for (i = len -1; i > (len - 6); i--)
{
if (fileName [i] == '.')
{
return strdup (pCh);
}
pCh--;
}
}
return NULL;
}
void file_outstream_write (void * rock, const char *buf, int size)
{
file_outstream_tracker_t * pStream;
int write_len = 0;
if (rock == NULL)
{
return;
}
pStream = (file_outstream_tracker_t *) rock;
if (pStream->fp == NULL)
{
return;
}
#ifdef DEBUG
fprintf (stderr, "%s:%d> size=%d; %s\n", __FILE__, __LINE__, size, buf);
#endif
write_len = fwrite (buf, sizeof (char), size, pStream->fp);
if (write_len > 0)
(pStream->bytes_written += write_len);
return;
}
int file_outstream_create (char * fileName, nsmail_outputstream_t ** ppRetOutputStream)
{
FILE * fp;
nsmail_outputstream_t * pNewStream;
file_outstream_tracker_t * pTracker;
if (fileName == NULL || ppRetOutputStream == NULL)
{
return MIME_ERR_INVALIDPARAM;
}
if ((fp = fopen(fileName, "wb")) == (FILE *) NULL)
{
return MIME_ERR_CANTOPENFILE;
}
pNewStream = (nsmail_outputstream_t *) malloc (sizeof (nsmail_outputstream_t));
if (pNewStream == NULL)
{
return MIME_ERR_OUTOFMEMORY;
}
pTracker = (file_outstream_tracker_t *) malloc (sizeof (file_outstream_tracker_t));
if (pTracker == NULL)
{
return MIME_ERR_OUTOFMEMORY;
}
pTracker->file_name = (char *) strdup (fileName);
pTracker->fp = fp;
pTracker->bytes_written = 0;
pNewStream->rock = (void *) pTracker;
pNewStream->write = file_outstream_write;
/* pNewStream->rewind = file_instream_rewind; */
pNewStream->close = file_outstream_close;
*ppRetOutputStream = pNewStream;
return 0;
}
void file_outstream_close (void * rock)
{
file_outstream_tracker_t * pStream;
if (rock == NULL)
{
return;
}
pStream = (file_outstream_tracker_t *) rock;
if (pStream->fp == NULL)
{
free (rock);
return;
}
fclose (pStream->fp);
free (pStream->file_name);
free (rock);
/* rock = NULL; */
}
/* ------------------------------- decoding ---------------------------- */
/*
* carson, Jan 8,98
*
* Base64 Decodes data from input buffer and writes to Output buffer
*
* params :
*
* char *szInput : input buffer
* char *szOutput : output buffer
* int nInputBufferSize : input buffer size
* BOOLEAN bFirstBuffer : TRUE if first buffer
* BOOLEAN bLastBuffer : TRUE if last buffer
*
* return : number of decoded bytes
*/
int base64Decoder( char *szInput, char *szOutput, int nInputBufferSize, BOOLEAN bFirstBuffer, BOOLEAN bLastBuffer )
{
int add_bits;
int mask;
int out_byte = 0;
int out_bits = 0;
int i;
int byte_pos = 0;
if ( szInput == NULL || szOutput == NULL )
{
return MIME_ERR_INVALIDPARAM;
}
/* Make translation table if it doesn't exist already */
if ( !( base64.xlate_table_made ) )
{
for ( i = 0; i < 256; i++ )
base64.xlate[i] = 127;
for (i = 0; base64.digits[i]; i++)
{
base64.xlate[base64.digits[i]] = i;
}
base64.xlate_table_made = 1;
}
/* Queue up relevant bits */
for (i = 0; szInput[i] && i < nInputBufferSize; i++ )
{
/* too small for us to decode */
if ( i + 4 > nInputBufferSize )
break;
add_bits = base64.xlate[(unsigned char) szInput[i]];
if (add_bits >= 64)
continue;
out_byte = (out_byte << 6) + add_bits;
out_bits += 6;
/* If the queue has gotten big enough, put into the buffer */
if (out_bits == 24)
{
szOutput[byte_pos++] = (out_byte & 0xFF0000) >> 16;
szOutput[byte_pos++] = (out_byte & 0x00FF00) >> 8;
szOutput[byte_pos++] = (out_byte & 0x0000FF);
out_bits = 0;
out_byte = 0;
}
}
/* Handle any bits still in the queue */
while (out_bits >= 8)
{
if (out_bits == 8)
{
szOutput[byte_pos++] = out_byte;
out_byte = 0;
}
else
{
mask = out_bits == 8 ? 0xFF : (0xFF << (out_bits - 8));
szOutput[byte_pos++] = (out_byte & mask) >> (out_bits - 8);
out_byte &= ~mask;
}
out_bits -= 8;
}
/* Ignore any remaining bits */
return out_byte ? BASE64_SOMELEFT : byte_pos;
}
/*
* carson, Jan 8,98
*
* Base64 Decodes data from input buffer and writes to Output buffer
*
* params :
*
* char *szInput : input buffer
* char *szOutput : output buffer
* int nInputBufferSize : input buffer size
* int nMaxBufferSize : max output buffer size
* int *pOut_byte : leftover byte
* int *pOut_bits : leftover bits
*
* return : number of decoded bytes
*/
int decodeBase64( char *szInput, char *szOutput, int nInputBufferSize, int nMaxBufferSize, int *pOut_byte, int *pOut_bits )
{
int add_bits;
int mask;
int out_byte = 0;
int out_bits = 0;
int i;
int byte_pos = 0;
if ( szInput == NULL || szOutput == NULL )
{
return MIME_ERR_INVALIDPARAM;
}
/* dynamic parsing */
if ( pOut_byte != NULL && pOut_bits != NULL )
{
out_byte = *pOut_byte;
out_bits = *pOut_bits;
}
/* Make translation table if it doesn't exist already */
if (!(base64.xlate_table_made))
{
for ( i = 0; i < 256; i++ )
base64.xlate[i] = 127;
for (i = 0; base64.digits[i]; i++)
{
base64.xlate[base64.digits[i]] = i;
}
base64.xlate_table_made = 1;
}
/* Queue up relevant bits */
for (i = 0; szInput[i] && i < nInputBufferSize; i++)
{
add_bits = base64.xlate[(unsigned char) szInput[i]];
if (add_bits >= 64)
continue;
out_byte = (out_byte << 6) + add_bits;
out_bits += 6;
/* If the queue has gotten big enough, put into the buffer */
if (out_bits == 24)
{
if (byte_pos + 2 >= nMaxBufferSize )
return BASE64_NOFIT;
szOutput[byte_pos++] = (out_byte & 0xFF0000) >> 16;
szOutput[byte_pos++] = (out_byte & 0x00FF00) >> 8;
szOutput[byte_pos++] = (out_byte & 0x0000FF);
out_bits = 0;
out_byte = 0;
}
}
/* Handle any bits still in the queue */
if ( pOut_byte == NULL || pOut_bits == NULL )
{
while (out_bits >= 8)
{
if (byte_pos >= nMaxBufferSize )
return BASE64_NOFIT;
if (out_bits == 8)
{
szOutput[byte_pos++] = out_byte;
out_byte = 0;
}
else
{
mask = out_bits == 8 ? 0xFF : (0xFF << (out_bits - 8));
szOutput[byte_pos++] = (out_byte & mask) >> (out_bits - 8);
out_byte &= ~mask;
}
out_bits -= 8;
}
/* Ignore any remaining bits */
return out_byte ? BASE64_SOMELEFT : byte_pos;
}
/* dynamic parsing */
else
{
*pOut_byte = out_byte;
*pOut_bits = out_bits;
return byte_pos;
}
}
/*
* carson, Jan 8,98
*
* Base64 Decodes data from vector and writes to Output buffer
*
* params :
*
* int nStart : start element in vector
* int nEnd : end element in vector
* Vector *v : input vector
* char *szOutput : output buffer
* int nMaxBufferSize : max output buffer size
* int *pOut_byte : leftover byte
* int *pOut_bits : leftover bits
*
* return : number of decoded bytes
*/
int decodeBase64Vector( int nStart, int nEnd, Vector *v, char **szDecodedBuffer, int nRawMessageSize, int *pOut_byte, int *pOut_bits )
{
int add_bits;
int mask;
int out_byte = 0;
int out_bits = 0;
int byte_pos = 0;
int i, j, nLen;
char *szLine;
char *szOutput;
if ( v == NULL || szDecodedBuffer == NULL )
{
return MIME_ERR_INVALIDPARAM;
}
/* dynamic parsing */
if ( pOut_byte != NULL && pOut_bits != NULL )
{
out_byte = *pOut_byte;
out_bits = *pOut_bits;
}
/* Make translation table if it doesn't exist already */
if (!(base64.xlate_table_made))
{
for (i = 0; i < 256; i++)
base64.xlate[i] = 127;
for (i = 0; base64.digits[i]; i++)
{
base64.xlate[base64.digits[i]] = i;
}
base64.xlate_table_made = 1;
}
szOutput = (char *) malloc( nRawMessageSize + 1 );
if ( szOutput == NULL )
{
#ifdef ERRORLOG
errorLog( "baseBase64Vector()", MIME_ERR_OUTOFMEMORY );
#endif
return 0;
}
*szDecodedBuffer = szOutput;
for ( j = nStart; j <= nEnd; j++ )
{
szLine = (char *) Vector_elementAt( v, j );
nLen = strlen( szLine );
/* Queue up relevant bits */
for (i = 0; szLine[i] && i < nLen; i++)
{
add_bits = base64.xlate[(unsigned char) szLine[i]];
if (add_bits >= 64)
continue;
out_byte = (out_byte << 6) + add_bits;
out_bits += 6;
/* If the queue has gotten big enough, put into the buffer */
if (out_bits == 24)
{
if (byte_pos + 2 >= nRawMessageSize )
return BASE64_NOFIT;
szOutput[byte_pos++] = (out_byte & 0xFF0000) >> 16;
szOutput[byte_pos++] = (out_byte & 0x00FF00) >> 8;
szOutput[byte_pos++] = (out_byte & 0x0000FF);
out_bits = 0;
out_byte = 0;
}
}
}
/* Handle any bits still in the queue */
if ( pOut_byte == NULL || pOut_bits == NULL )
{
while (out_bits >= 8)
{
if (byte_pos >= nRawMessageSize )
return BASE64_NOFIT;
if (out_bits == 8)
{
szOutput[byte_pos++] = out_byte;
out_byte = 0;
}
else
{
mask = out_bits == 8 ? 0xFF : (0xFF << (out_bits - 8));
szOutput[byte_pos++] = (out_byte & mask) >> (out_bits - 8);
out_byte &= ~mask;
}
out_bits -= 8;
}
/* Ignore any remaining bits */
return out_byte ? BASE64_SOMELEFT : byte_pos;
}
/* dynamic parsing */
else
{
*pOut_byte = out_byte;
*pOut_bits = out_bits;
return byte_pos;
}
}
/*
* carson, Jan 8,98
* decode quoted printable
*
* param :
*
* char *szInput : input buffer
* char *szOutput : output buffer
* int MaxBufferSize : max buffer size
*
* return : number of decoded bytes
*/
int decodeQP( char *szInput, char *szOutput, int nMaxBufferSize )
{
char ch;
int i = 0;
int j = 0;
if ( szInput == NULL || szOutput == NULL )
return MIME_ERR_INVALIDPARAM;
for ( ch = szInput[i]; ch != 0 && j < nMaxBufferSize; i++ )
{
if ( ( ch >= 33 && ch <= 60 ) || ( ch >= 62 && ch <= 126 ) || ( ch == 9 || ch == 32 ) )
{
szOutput[j++] = ch;
}
else if ( ch == '=' )
{
szOutput[j++] = nConvertHexToDec( szInput[++i], szInput[++i] );
}
}
szOutput[j] = 0;
return j;
}
/* New routine prasad 3/31/98 */
int decodeQPVector (int nStart, int nEnd, Vector *v, char **ppDecodedBuffer,
int nRawMessageSize, char *pLeftOverBytes, int *nNoOfLeftOverBytes)
{
char token[3], ch;
char *pLine, *pOutput, *pInput;
int i = 0, j, ii=0, nLen = 0, written=0;
if (v == NULL || pLeftOverBytes == NULL || nNoOfLeftOverBytes == NULL || ppDecodedBuffer == NULL)
{
return MIME_ERR_INVALIDPARAM;
}
pOutput = (char *) malloc (nRawMessageSize + 1);
if (pOutput == NULL)
return MIME_ERR_OUTOFMEMORY;
memset (pOutput, 0, (nRawMessageSize + 1));
*ppDecodedBuffer = pOutput;
/* get each line */
for (ii = nStart; ii <= nEnd; ii++)
{
pLine = (char *) Vector_elementAt( v, ii );
nLen += strlen (pLine);
if (ii == nStart)
{
if (*nNoOfLeftOverBytes > 0)
{
strncpy (pOutput, pLeftOverBytes, *nNoOfLeftOverBytes);
nLen += *nNoOfLeftOverBytes;
}
strcat (pOutput, pLine);
/* see if this helps! */
strcat (pOutput, "\r\n");
nLen += 2;
}
else
{
strcat (pOutput, pLine);
/* see if this helps! */
strcat (pOutput, "\r\n");
nLen += 2;
}
/* Don't free() pLine. It is freed by caller as part of freeing the vector */
}
pInput = pOutput;
written=0;
i=0;
/* first time do it outside the loop */
while (i < 3 && nLen > 0)
{
token [i++] = *pInput;
pInput++;
nLen--;
}
while (nLen > 0 || i != 0)
{
while (i < 3 && nLen > 0)
{
token [i++] = *pInput;
pInput++;
nLen--;
}
if (i < 3) /* did not get enough for a token */
{
if (i == 2 && token [0] == CR && token [1] == LF)
{
*pOutput++ = token[0]; written++;
*pOutput++ = token[1]; written++;
*nNoOfLeftOverBytes = 0;
}
else
{
for (j=0; j < i; j++)
pLeftOverBytes [j] = token [j];;
*nNoOfLeftOverBytes = i;
}
if (written > 0)
*pOutput++ = 0; /* null terminate it */
return (written);
}
i = 0;
if (token [0] == '=')
{
unsigned char c = 0;
if (token[1] >= '0' && token[1] <= '9')
c = token[1] - '0';
else if (token[1] >= 'A' && token[1] <= 'F')
c = token[1] - ('A' - 10);
else if (token[1] >= 'a' && token[1] <= 'f')
c = token[1] - ('a' - 10);
/*else if (token[1] == CR || token[1] == LF)*/
else if (token[1] == CR || token[1] == LF)
{
/* =\n means ignore the newline. */
if (token[1] == CR && token[2] == LF)
; /* swallow all three chars */
else
{
pInput--; /* put the third char back */
nLen++;
}
continue;
}
else
{
/* = followed by something other than hex or newline -
pass it through unaltered, I guess.
*/
if (pInput > pOutput) { *pOutput++ = token[0]; written++; }
if (pInput > pOutput) { *pOutput++ = token[1]; written++; }
if (pInput > pOutput) { *pOutput++ = token[2]; written++; }
continue;
}
/* Second hex digit */
c = (c << 4);
if (token[2] >= '0' && token[2] <= '9')
c += token[2] - '0';
else if (token[2] >= 'A' && token[2] <= 'F')
c += token[2] - ('A' - 10);
else if (token[2] >= 'a' && token[2] <= 'f')
c += token[2] - ('a' - 10);
else
{
/* We got =xy where "x" was hex and "y" was not, so
treat that as a literal "=", x, and y. */
if (pInput > pOutput) { *pOutput++ = token[0]; written++; }
if (pInput > pOutput) { *pOutput++ = token[1]; written++; }
if (pInput > pOutput) { *pOutput++ = token[2]; written++; }
continue;
}
*pOutput++ = (char) c;
written++;
}
else
{
*pOutput++ = token[0];
written++;
token[0] = token[1];
token[1] = token[2];
i = 2;
}
}
if (written > 0)
*pOutput++ = 0; /* null terminate it */
return written;
}
/*
* carson, Jan 8,98
* QuotedPrintable Decodes data from vector, write decoded data to szOutput
*
* params :
*
* int nStart : starting element in vector
* int nEndt : ending element in vector
* Vector *v : vector
* char *szOutput : output buffer
* int MaxBufferSize : max buffer size
*
* return : number of decoded bytes
*/
int decodeQPVectorOrig( int nStart, int nEnd, Vector *v, char **szDecodedBuffer, int nRawMessageSize, char *szLeftOverBytes, int *nNoOfLeftOverBytes )
{
char ch;
int i = 0;
int j = 0;
int ii, nLen;
char *szLine;
char achBuffer[96];
boolean bAppendLeftOverBytes = FALSE;
char *szOutput;
if ( v == NULL || szLeftOverBytes == NULL || nNoOfLeftOverBytes == NULL || szDecodedBuffer == NULL )
{
return MIME_ERR_INVALIDPARAM;
}
szOutput = (char *) malloc( nRawMessageSize + 1 );
if ( szOutput == NULL )
{
#ifdef ERRORLOG
errorLog( "baseQPVector()", MIME_ERR_OUTOFMEMORY );
#endif
return MIME_ERR_OUTOFMEMORY;
}
*szDecodedBuffer = szOutput;
/* get each line */
for ( ii = nStart; ii <= nEnd; ii++ )
{
szLine = (char *) Vector_elementAt( v, ii );
nLen = strlen( szLine );
if ( !bAppendLeftOverBytes )
{
if ( *nNoOfLeftOverBytes > 0 )
{
strncpy( achBuffer, szLeftOverBytes, *nNoOfLeftOverBytes );
achBuffer[ *nNoOfLeftOverBytes ] = 0;
strcat( achBuffer, szLine );
nLen = nLen + *nNoOfLeftOverBytes;
szLine = achBuffer;
}
bAppendLeftOverBytes = TRUE;
}
/* enumerate through each char */
for ( i = 0, ch = szLine[i]; ch != 0 && i < nLen && j < nRawMessageSize; ch = szLine[++i] )
{
if ( ( ch >= 33 && ch <= 60 ) || ( ch >= 62 && ch <= 126 ) || ( ch == 9 || ch == 32 ) )
{
szOutput[j++] = ch;
}
else if ( ch == '=' )
{
if ( i + 2 < nLen )
{
szOutput[j++] = nConvertHexToDec( szLine[++i], szLine[++i] );
}
/* get more data */
else if ( ii <= nEnd )
{
strcpy( achBuffer, &szLine[i+1] );
szLine = (char *) Vector_elementAt( v, ++ii );
strcat( achBuffer, szLine );
nLen = strlen( achBuffer );
szLine = achBuffer;
i = -1;
}
/* save it for next time */
else
{
szLeftOverBytes[0] = ch; *nNoOfLeftOverBytes = 1;
if ( i+1 < nLen )
szLeftOverBytes[1] = ch; *nNoOfLeftOverBytes = 2;
}
}
}
}
szOutput[j] = 0;
return j;
}
/* ---------------------------------- log support ------------------------------------- */
/*
* carsonl, jan 8,98
* create new log
*
* parameter :
*
* char *szFilename : name of log file
*
* return : instance of log object
*/
errorLog_t *errorLog_new( char *szFilename )
{
errorLog_t *pLog;
if ( szFilename == NULL )
return NULL;
pLog = (errorLog_t*) malloc( sizeof( errorLog_t ) );
/* initialize log file */
if ( pLog != NULL )
{
pLog->m_pFile = fopen( szFilename, "a" );
if ( pLog->m_pFile == NULL )
{
free( pLog );
pLog = NULL;
}
else
{
strcpy( pLog->m_achFilename, szFilename );
pLog->m_bActive = TRUE;
}
}
return pLog;
}
/*
* carsonl, jan 8,98
* error logger
*
* parameter :
*
* char *pOwner : caller
* int nError : error No
*
* return : nothing
* NOTE : will only write to log file if m_bActive flag is set to TRUE ( default )
*/
void errorLog2( errorLog_t *pLog, char *szOwner, int nError )
{
static char buffer[128];
char *szError;
if ( pLog == NULL || pLog->m_pFile == NULL || szOwner == NULL )
return;
if ( !pLog->m_bActive )
return;
switch( nError )
{
case MIME_ERR_EOF: szError = "End of file"; break;
case MIME_ERR_INVALIDPARAM: szError = "Invalid parameter"; break;
case MIME_ERR_ENCODE: szError = "encoding"; break;
case MIME_ERR_UNEXPECTED: szError = "unexpected"; break;
case MIME_ERR_OUTOFMEMORY: szError = "out of memory"; break;
case MIME_ERR_IO: szError = "I/O"; break;
case MIME_ERR_IO_READ: szError = "I/O read"; break;
case MIME_ERR_IO_WRITE: szError = "I/O write"; break;
case MIME_ERR_PARSE: szError = "parse"; break;
case MIME_ERR_INVALID_INDEX: szError = "invalid index"; break;
case MIME_ERR_UNINITIALIZED: szError = "unintialized"; break;
case MIME_ERR_CANTOPENFILE: szError = "can't open file"; break;
case MIME_ERR_CANT_SET: szError = "can't set"; break;
case MIME_ERR_ALREADY_SET: szError = "already set"; break;
case MIME_ERR_CANT_DELETE: szError = "can't delete"; break;
case MIME_ERR_CANT_ADD: szError = "can't add"; break;
case MIME_ERR_NO_HEADERS: szError = "no headers"; break;
case MIME_ERR_NOT_SET: szError = "not set"; break;
case MIME_ERR_NO_BODY: szError = "no body"; break;
case MIME_ERR_NOT_FOUND: szError = "not found"; break;
case MIME_ERR_NO_CONTENT_SUBTYPE: szError = "no content subtype"; break;
case MIME_ERR_INVALID_ENCODING: szError = "invalid encoding"; break;
case MIME_ERR_INVALID_BASICPART: szError = "invalid basicpart"; break;
case MIME_ERR_INVALID_MULTIPART: szError = "invalid multipart"; break;
case MIME_ERR_INVALID_MESSAGEPART: szError = "invalid messagepart"; break;
case MIME_ERR_INVALID_MESSAGE: szError = "invalid message"; break;
case MIME_ERR_INVALID_CONTENTTYPE: szError = "invalid content type"; break;
case MIME_ERR_INVALID_CONTENTID: szError = "invalid content ID"; break;
case MIME_ERR_NO_DATA: szError = "no data"; break;
case MIME_ERR_NOTIMPL: szError = "not implemented"; break;
case MIME_ERR_EMPTY_BODY: szError = "empty body"; break;
case MIME_ERR_UNSUPPORTED_PARTIAL_SUBTYPE: szError = "partial subtype not supported";
case MIME_ERR_MAX_NESTED_PARTS_REACHED : szError = "maximum number of nested parts reached.";
default: szError = "Undefined error"; break;
}
sprintf( buffer, "ERROR : %s error called from %s\n", szError, szOwner );
fwrite( buffer, sizeof(char), strlen( buffer ), pLog->m_pFile );
}
/*
* carsonl, jan 8,98
* error logger
*
* parameter :
*
* char *pOwner : caller
* int nError : error No
*
* return : nothing
* NOTE : will only write to log file if m_bActive flag is set to TRUE ( default )
*/
void errorLogMsg2( errorLog_t *pLog, char *szMsg )
{
static char buffer[128];
if ( pLog == NULL || pLog->m_pFile == NULL || szMsg == NULL )
return;
if ( !pLog->m_bActive )
return;
sprintf( buffer, "ERROR : %s\n", szMsg );
fwrite( buffer, sizeof(char), strlen( buffer ), pLog->m_pFile );
}
/*
* carsonl, jan 8,98
* free log object
*
* parameter :
*
* char *pLog : log object to free
* int nError : error No
*
* return : nothing
*/
void errorLog_free( errorLog_t *pLog )
{
if ( pLog != NULL )
{
if ( pLog->m_pFile != NULL )
fclose( pLog->m_pFile );
free( pLog );
}
}
/*
* carsonl, jan 8,98
* init log
*
* parameter :
*
* char *szFilename : log filename
*
* return : nothing
*/
void initErrorLog( char *szFilename ) { g_pLog = errorLog_new( szFilename ); }
/*
* carsonl, jan 8,98
* close log file
*
* parameter : none
*
* return : nothing
*/
void closeErrorLog() { if ( g_pLog != NULL ) errorLog_free( g_pLog ); }
/*
* carsonl, jan 8,98
* log error
*
* parameter :
*
* char *pOwner : caller
* int nError : error No
*
* return : nothing
*/
void errorLog( char *szOwner, int nError )
{
if ( g_pLog == NULL )
g_pLog = errorLog_new( LOG_FILE );
errorLog2( g_pLog, szOwner, nError );
}
/*
* carsonl, jan 8,98
* log error
*
* parameter :
*
* char *pOwner : caller
* int nError : error No
*
* return : nothing
*/
void errorLogMsg( char *szMsg )
{
if ( g_pLog == NULL )
g_pLog = errorLog_new( LOG_FILE );
errorLogMsg2( g_pLog, szMsg );
}
/*
* carsonl, jan 8,98
* turn error log on
*
* parameter : none
*
* return : nothing
*/
void errorLogOn() { if ( g_pLog == NULL ) g_pLog->m_bActive = TRUE; }
/*
* carsonl, jan 8,98
* turn error log off
*
* parameter : none
*
* return : nothing
*/
void errorLogOff() { if ( g_pLog == NULL ) g_pLog->m_bActive = FALSE; }