📄 rfc822.cpp
字号:
/*
* Functions to aide manipulation of MIME RFC822 headers.
*
* Filename: RFC822.cpp
*
* Last Edited: July 15, 1996
*
* Author: Scott Manjourides
*
* Portions adopted from code originally written by Stever Dorner.
* Copyright 1995, 1996 QUALCOMM Inc.
*
* Send comments and questions to <emsapi-info@qualcomm.com>
*/
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <istream.h> // ifstream class
#include <fstream.h> // ofstream class
#include "rfc822.h"
/* ========================================================================= */
const char *kRFC822_MustBeQuoted = "()<>@,;:\\\"/[]?= ";
const char *kRFC822_MustBeEscaped = "\\\"";
const char *kRFC822_EOL = "\r\n";
/* ========================================================================= */
#define safefree(p) { if (p) { free(p); (p) = NULL; } }
/* ========================================================================= */
/*
* Find next RFC822 token in given string, copying it into a newly created
* string. Advance pointer past token and any following whitespace.
*
* NOTE: The user of this function is responsible for freeing returned
* string.
*
* Args:
* cpp [IN/OUT] Handle (pointer-to-pointer) of RFC822 string to extract from
*
* Returns: String containing next token, NULL if error.
* Moves cpp to first non-whitespace character AFTER extracted token
*/
char *rfc822_extract_token(char **cpp)
{
char *start, *cp = *cpp;
cp = rfc822_skipws(cp); // Skip white space
start = cp;
cp = rfc822_skipword(cp); // Skip word
if (cp > start)
{
const int len = cp - start;
char *buf = (char *) malloc(len + 1);
if (buf)
{
rfc822_unquote_strcpy(buf, start, len);
*cpp = rfc822_skipws(cp);
return (buf);
}
}
return (NULL); // No token to extract
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* Advances to next non-whitespace character in string. This includes
* ignoring RFC822 comments.
*
* Args:
* cp [IN] RFC822 string
*
* Returns: Pointer to next non-whitespace character.
*/
char *rfc822_skipws(char *cp)
{
do {
while (*cp == ' ') // Skip spaces
cp++;
if (*cp == '(') // A comment?
{
int nested = 1;
while ((*++cp) && (nested)) // Find end of comment
{
switch (*cp)
{
case '(': nested++;
break;
case ')': nested--;
break;
case '\\': // Escape character
if ((*(cp+1)) != '\0') // Check for end-of-string
cp++;
break;
case '\"': // Quote inside comment
while ((*cp) && (*++cp != '\"')) // Go 'til end of quote
if ((*cp == '\\') && ((*(cp+1)) != '\0'))
cp++; // Escaped character inside quote -- inside comment (eeek!)
break;
}
}
}
} while (*cp == ' ');
return cp;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* Advances to next character in string directly after the current token.
* The first character must be the beginning of a valid token or end of
* string (ie. all whitespace must be skipped BEFORE calling this function).
*
* Args:
* cp [IN] RFC822 string
*
* Returns: Pointer to next valid whitespace character.
*/
char *rfc822_skipword(char *cp)
{
int bInQuotes = 0;
// First character must be a quote to be valid double-quoted string
if (*cp == '\"')
{
bInQuotes = 1;
cp++;
}
while (*cp)
{
if (strchr(kRFC822_MustBeQuoted, *cp))
{
if (!bInQuotes) // Found a character that should be double-quoted, but is not
return (cp);
// Now we know we are inside a double-quoted string
switch (*cp)
{
case '\"': return (cp+1); // End double-quote
break;
case '\\': cp++; // Escape character, skip next
break;
default: // nothing
break;
}
}
cp++;
}
return (cp);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* Calculates the length of the given text string if it were converted
* to an RFC822 string.
*
* Args:
* cp [IN] Text string
*
* Returns: Equivalent RFC822 length of given text.
*/
unsigned int rfc822_quoted_strlen(char *cp)
{
unsigned int len = 0, bQuoted = 0;
while (*cp)
{
len++;
if ((!bQuoted) && (strchr(kRFC822_MustBeQuoted, *cp) != NULL))
bQuoted = 1;
if (strchr(kRFC822_MustBeEscaped, *cp) != NULL)
len++, bQuoted = 1;
cp++;
}
if (bQuoted)
len += 2; // Quotes
return (len);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* Copies and converts the source text string to a destination
* RFC822 string. The source must be NULL terminated, and the
* destination will be NULL terminated.
*
* Args:
* dst [OUT] RFC822 string
* src [IN] Text string
*
* Returns: Pointer to destination NULL termination.
*/
char *rfc822_quote_strcpy(char *dst, const char *src)
{
const unsigned int bQuoted = ( strpbrk(src, kRFC822_MustBeQuoted) ? 1 : 0 );
if (bQuoted)
*dst++ = '\"';
while (*src)
{
if (strchr(kRFC822_MustBeEscaped, *src) != NULL)
*dst++ = '\\';
*dst++ = *src++;
}
if (bQuoted)
*dst++ = '\"';
*dst = '\0';
return (dst);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* Copies and converts the source RFC822 string to a destination
* text string. The source must be NULL terminated, and the
* destination will be NULL terminated.
*
* Args:
* dst [OUT] Text string
* src [IN] RFC822 string
* len [IN] Maximum charcters to copy; Zero implies whole string
*
* Returns: Pointer to destination NULL termination.
*/
char *rfc822_unquote_strcpy(char *dst, const char *src, unsigned int len)
{
// If 'len' is provided (ie. >0) then only len chars will be copied
// Otherwise, copy 'til end-of-string
char *end;
unsigned int bEscaped = 0;
end = strchr(src, '\0');
if ((len > 0) && ((src + len) < end))
end = (char *) src + len;
while (src < end)
{
if (bEscaped)
bEscaped = 0;
else
{
switch (*src)
{
case '\\': bEscaped = 1;
case '\"': src++;
continue;
break;
}
}
*dst++ = *src++;
}
*dst = '\0';
return dst;
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* Finds and extracts a header line from a full multi-lined header. All
* unfolding (removing newlines) is done before header line is returned.
*
* NOTE: The user of this function is responsible for freeing the
* returned string.
*
* Args:
* pFullHeader [IN] Pointer to a full RFC822 header, including newlines
* pLinePrefix [IN] Prefix of header line to extract
*
* Returns: Extracted header line string; dynamically allocated.
*/
char *rfc822_extract_header(const char *pFullHeader, const char *pLinePrefix)
{
const char *kNewline = "\r\n";
const unsigned int kNewlineLen = (2);
const unsigned int nPreLen = strlen(pLinePrefix);
char *pStart, *pEnd, *pBuf, *pPos, *pRetBuf;
if (nPreLen < 1)
return (NULL);
pStart = (char *) pFullHeader;
/* Find first 'line' which matches prefix */
while ((pStart) && (strnicmp(pStart, pLinePrefix, nPreLen) != 0))
if (pStart = strstr(pStart, kNewline))
pStart += kNewlineLen;
if (!pStart)
return (NULL); /* Not found */
/* Find the end of this header line */
for (pEnd = strstr(pStart, kNewline); (pEnd != NULL); pEnd = strstr(pEnd, kNewline))
{
pPos = pEnd + kNewlineLen;
/* Does header line continue on next line? */
if ((*pPos == ' ') || (*pPos == '\t'))
pEnd = pPos;
else
break;
}
/* If we ran off the end of the string, then the end is the last char in the string */
if (pEnd == NULL)
pEnd = strchr(pStart, '\0');
pBuf = pRetBuf = (char *) malloc(pEnd - pStart + 1); /* Max length of output string */
for (pPos = pStart; pPos < pEnd; pPos++)
{
if (strncmp(pPos, kNewline, kNewlineLen) == 0) /* We're at a newline */
pPos += kNewlineLen; /* Skip over newline */
*pBuf++ = *pPos;
}
*pBuf = '\0';
return (pRetBuf);
}
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
/*
* Reads and returns the RFC822 header from input file. This is defined
* here as reading until the first blank line from current file
* position. The blank line is discarded.
*
* NOTE: The user of this function is responsible for freeing the
* returned string.
*
* Args:
* inFile [IN] Input file stream; already open
*
* Returns: Complete multi-lined RFC822 header; dynamically allocated.
* The file pointer is left immediately after the first read blank line.
*/
char *rfc822_read_header(ifstream& inFile)
{
// We don't know how big the header is, but we know each line
// must be less than 1024 chars. We use 'kBlockSize' to
// increase the memory of the header while ensuring that
// there is at least kBlockSize available for each read.
const unsigned int kBlockSize = 1024;
char *pBuf, *pPos, *cp;
unsigned int nBufSize, nStrLen;
if ((!inFile.good()) || (inFile.eof()))
return NULL;
nStrLen = nBufSize = 0;
pBuf = NULL;
while ((inFile.good()) && (!inFile.eof()))
{
if ((nBufSize - nStrLen) < (kBlockSize + 1))
{
nBufSize += kBlockSize;
if ((cp = (char *) realloc(pBuf, nBufSize)) == NULL)
{
safefree(pBuf);
return (NULL); // Out of memory?
}
pPos = (pBuf = cp) + nStrLen;
}
// Get next line
cp = pPos;
while ((inFile.good()) && (!inFile.eof()))
if ((*cp++ = inFile.get()) == '\n')
{
*cp = '\0';
break;
}
/* inFile.getline(pPos, kBlockSize); */
/* getline() strips '\n' chars! Yuck! */
if (strcmp(pPos, kRFC822_EOL) == 0) /* Empty line */
break;
pPos = strchr(pPos, '\0');
nStrLen = pPos - pBuf;
}
// Null terminate the header string
*pPos = '\0';
// Chop off any excess allocated memory
if (cp = (char *) realloc(pBuf, strlen(pBuf) + 1))
pBuf = cp;
return (pBuf);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -