2045 lines
40 KiB
C
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( <ime );
|
|
ptm = localtime( <ime );
|
|
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; }
|
|
|
|
|