#include <mail_util.h>
#include <stdlib.h>
#include <strings.h>
#include <stdio.h>
#define __USE_GNU
#include <regex.h>
#include <ctype.h>
#include <errno.h>
#include <FindDirectory.h>
#include <List.h>
#include <Locker.h>
#include <parsedate.h>
#include <Path.h>
#include <String.h>
#include <UTF8.h>
#include <mail_encoding.h>
#include <AttributeUtilities.h>
#include <CharacterSet.h>
#include <CharacterSetRoster.h>
using namespace BPrivate;
#define CRLF "\r\n"
struct CharsetConversionEntry {
const char *charset;
uint32 flavor;
};
extern const CharsetConversionEntry mail_charsets[] = {
{"iso-8859-1", B_ISO1_CONVERSION},
{"iso-8859-2", B_ISO2_CONVERSION},
{"iso-8859-3", B_ISO3_CONVERSION},
{"iso-8859-4", B_ISO4_CONVERSION},
{"iso-8859-5", B_ISO5_CONVERSION},
{"iso-8859-6", B_ISO6_CONVERSION},
{"iso-8859-7", B_ISO7_CONVERSION},
{"iso-8859-8", B_ISO8_CONVERSION},
{"iso-8859-9", B_ISO9_CONVERSION},
{"iso-8859-10", B_ISO10_CONVERSION},
{"iso-8859-13", B_ISO13_CONVERSION},
{"iso-8859-14", B_ISO14_CONVERSION},
{"iso-8859-15", B_ISO15_CONVERSION},
{"shift_jis", B_SJIS_CONVERSION},
{"shift-jis", B_SJIS_CONVERSION},
{"iso-2022-jp", B_JIS_CONVERSION},
{"euc-jp", B_EUC_CONVERSION},
{"euc-kr", B_EUC_KR_CONVERSION},
{"ksc5601", B_EUC_KR_CONVERSION},
{"ks_c_5601-1987", B_EUC_KR_CONVERSION},
{"koi8-r", B_KOI8R_CONVERSION},
{"windows-1251",B_MS_WINDOWS_1251_CONVERSION},
{"windows-1252",B_MS_WINDOWS_CONVERSION},
{"dos-437", B_MS_DOS_CONVERSION},
{"dos-866", B_MS_DOS_866_CONVERSION},
{"x-mac-roman", B_MAC_ROMAN_CONVERSION},
{"big5", 24},
{"gb18030", 25},
{"gb2312", 25},
{"gbk", 25},
{"us-ascii", B_MAIL_US_ASCII_CONVERSION},
{"utf-8", B_MAIL_UTF8_CONVERSION },
{NULL, (uint32) -1}
};
static int32 gLocker = 0;
static size_t gNsub = 1;
static re_pattern_buffer gRe;
static re_pattern_buffer *gRebuf = NULL;
static unsigned char gTranslation[256];
static int
handle_non_rfc2047_encoding(char **buffer, size_t *bufferLength,
size_t *sourceLength)
{
char *string = *buffer;
int32 length = *sourceLength;
int32 i;
for (i = 0;i < length;i++)
if (string[i] & 0x80)
break;
if (i == length)
return false;
int32 singletons = 0,doubles = 0;
for (i = 0;i < length;i++)
{
if (string[i] & 0x80)
{
if ((string[i + 1] & 0x80) == 0)
singletons++;
else doubles++;
i++;
}
}
if (singletons != 0)
{
int32 state = 0;
int32 destLength = length * 4 + 1;
int32 destBufferLength = destLength;
char *dest = (char*)malloc(destLength);
if (dest == NULL)
return 0;
if (convert_to_utf8(B_ISO1_CONVERSION, string, &length,dest,
&destLength, &state) == B_OK) {
*buffer = dest;
*bufferLength = destBufferLength;
*sourceLength = destLength;
return true;
}
free(dest);
return false;
}
return true;
}
status_t
write_read_attr(BNode& node, read_flags flag)
{
if (node.WriteAttr(B_MAIL_ATTR_READ, B_INT32_TYPE, 0, &flag, sizeof(int32))
< 0)
return B_ERROR;
BString currentStatus;
if (node.ReadAttrString(B_MAIL_ATTR_STATUS, ¤tStatus) == B_OK
&& currentStatus.ICompare("New") != 0
&& currentStatus.ICompare("Read") != 0
&& currentStatus.ICompare("Seen") != 0) {
return B_OK;
}
BString statusString = flag == B_READ ? "Read"
: flag == B_SEEN ? "Seen" : "New";
if (node.WriteAttrString(B_MAIL_ATTR_STATUS, &statusString) < 0)
return B_ERROR;
return B_OK;
}
status_t
read_read_attr(BNode& node, read_flags& flag)
{
if (node.ReadAttr(B_MAIL_ATTR_READ, B_INT32_TYPE, 0, &flag, sizeof(int32))
== sizeof(int32))
return B_OK;
BString statusString;
if (node.ReadAttrString(B_MAIL_ATTR_STATUS, &statusString) == B_OK) {
if (statusString.ICompare("New") == 0)
flag = B_UNREAD;
else
flag = B_READ;
return B_OK;
}
return B_ERROR;
}
status_t
mail_convert_to_utf8(uint32 srcEncoding, const char *src, int32 *srcLen,
char *dst, int32 *dstLen, int32 *state, char substitute)
{
int32 copyAmount;
char *originalDst = dst;
status_t returnCode = -1;
if (srcEncoding == B_MAIL_UTF8_CONVERSION) {
copyAmount = *srcLen;
if (*dstLen < copyAmount)
copyAmount = *dstLen;
memcpy (dst, src, copyAmount);
*srcLen = copyAmount;
*dstLen = copyAmount;
returnCode = B_OK;
} else if (srcEncoding == B_MAIL_US_ASCII_CONVERSION) {
int32 i;
unsigned char letter;
copyAmount = *srcLen;
if (*dstLen < copyAmount)
copyAmount = *dstLen;
for (i = 0; i < copyAmount; i++) {
letter = *src++;
if (letter > 0x80U)
*dst++ = letter - 0x80U;
else if (letter == 0x80U)
*dst++ = substitute;
else
*dst++ = letter;
}
*srcLen = copyAmount;
*dstLen = copyAmount;
returnCode = B_OK;
} else
returnCode = convert_to_utf8 (srcEncoding, src, srcLen,
dst, dstLen, state, substitute);
if (returnCode == B_OK) {
int32 i;
for (i = 0; i < *dstLen; i++)
if (originalDst[i] == 0)
originalDst[i] = substitute;
}
return returnCode;
}
status_t
mail_convert_from_utf8(uint32 dstEncoding, const char *src, int32 *srcLen,
char *dst, int32 *dstLen, int32 *state, char substitute)
{
int32 copyAmount;
status_t errorCode;
int32 originalDstLen = *dstLen;
int32 tempDstLen;
int32 tempSrcLen;
if (dstEncoding == B_MAIL_UTF8_CONVERSION) {
copyAmount = *srcLen;
if (*dstLen < copyAmount)
copyAmount = *dstLen;
memcpy (dst, src, copyAmount);
*srcLen = copyAmount;
*dstLen = copyAmount;
return B_OK;
}
if (dstEncoding == B_MAIL_US_ASCII_CONVERSION) {
int32 characterLength;
int32 dstRemaining = *dstLen;
unsigned char letter;
int32 srcRemaining = *srcLen;
if (srcRemaining <= *state) {
*state -= srcRemaining;
*dstLen = 0;
return B_OK;
}
srcRemaining -= *state;
src += *state;
*state = 0;
while (true) {
if (srcRemaining <= 0 || dstRemaining <= 0)
break;
letter = *src;
if (letter < 0x80)
characterLength = 1;
else if (letter < 0xC0)
characterLength = 1;
else if (letter < 0xE0)
characterLength = 2;
else if (letter < 0xF0)
characterLength = 3;
else if (letter < 0xF8)
characterLength = 4;
else if (letter < 0xFC)
characterLength = 5;
else if (letter < 0xFE)
characterLength = 6;
else
characterLength = 1;
if (letter < 0x80)
*dst++ = *src;
else
*dst++ = substitute;
dstRemaining--;
if (srcRemaining < characterLength) {
*state = characterLength - srcRemaining;
srcRemaining = 0;
} else {
src += characterLength;
srcRemaining -= characterLength;
}
}
*srcLen = *srcLen - srcRemaining;
*dstLen = *dstLen - dstRemaining;
return B_OK;
}
errorCode = convert_from_utf8(dstEncoding, src, srcLen, dst, dstLen, state,
substitute);
if (errorCode != B_OK)
return errorCode;
if (dstEncoding != B_JIS_CONVERSION)
return B_OK;
tempDstLen = originalDstLen - *dstLen;
if (tempDstLen < 3)
return B_OK;
tempSrcLen = 1;
errorCode = convert_from_utf8(dstEncoding, "a", &tempSrcLen,
dst + *dstLen, &tempDstLen, state, substitute);
if (errorCode != B_OK)
return errorCode;
*dstLen += tempDstLen - 1 ;
return B_OK;
}
ssize_t
rfc2047_to_utf8(char **bufp, size_t *bufLen, size_t strLen)
{
char *head, *tail;
char *charset, *encoding, *end;
ssize_t ret = B_OK;
if (bufp == NULL || *bufp == NULL)
return -1;
char *string = *bufp;
if (handle_non_rfc2047_encoding(bufp,bufLen,&strLen))
return strLen;
if (strLen == 0)
strLen = strlen(*bufp);
char lastChar = (*bufp)[strLen];
(*bufp)[strLen] = '\0';
bool encodedWordFoundPreviously = false;
for (head = tail = string;
((charset = strstr(tail, "=?")) != NULL)
&& (((encoding = strchr(charset + 2, '?')) != NULL)
&& encoding[1] && (encoding[2] == '?') && encoding[3])
&& (end = strstr(encoding + 3, "?=")) != NULL;
tail = end)
{
bool nonSpaceFound = false;
for (int i = 0; i < charset-tail; i++) {
if (!isspace (tail[i])) {
nonSpaceFound = true;
break;
}
}
if (!encodedWordFoundPreviously || nonSpaceFound) {
if (string != tail && tail != charset)
memmove(string, tail, charset-tail);
string += charset-tail;
}
tail = charset;
encodedWordFoundPreviously = true;
charset += 2;
encoding += 1;
end += 2;
size_t cLen = encoding - 1 - charset;
bool base64encoded = toupper(*encoding) == 'B';
uint32 convertID = B_MAIL_NULL_CONVERSION;
char charsetName[cLen + 1];
memcpy(charsetName, charset, cLen);
charsetName[cLen] = '\0';
if (strcasecmp(charsetName, "us-ascii") == 0) {
convertID = B_MAIL_US_ASCII_CONVERSION;
} else if (strcasecmp(charsetName, "utf-8") == 0) {
convertID = B_MAIL_UTF8_CONVERSION;
} else {
const BCharacterSet* charSet
= BCharacterSetRoster::FindCharacterSetByName(charsetName);
if (charSet != NULL) {
convertID = charSet->GetConversionID();
}
}
if (convertID == B_MAIL_NULL_CONVERSION) {
if (string != tail && tail != end)
memmove(string, tail, end-tail);
string += end-tail;
continue;
}
char *src = encoding+2;
int32 srcLen = end - 2 - src;
srcLen = !base64encoded ? decode_qp(src, src, srcLen, 1)
: decode_base64(src, src, srcLen);
int32 dstLen = end-string + *bufLen-strLen;
char *dst = (char*)malloc(dstLen);
int32 cvLen = srcLen;
int32 convState = 0;
ret = mail_convert_to_utf8(convertID, src, &cvLen, dst, &dstLen,
&convState);
if (ret != B_OK) {
free(dst);
if (string != tail && tail != end)
memmove(string, tail, end-tail);
string += end-tail;
continue;
}
else {
if (dstLen > end-string) {
memmove(string+dstLen, end, strLen - (end-head) + 1);
strLen += string+dstLen - end;
end = string + dstLen;
}
memcpy(string, dst, dstLen);
string += dstLen;
free(dst);
continue;
}
}
size_t tailLen = strLen - (tail - head);
memmove(string, tail, tailLen+1);
string += tailLen;
(*bufp)[strLen] = lastChar;
return ret < B_OK ? ret : string-head;
}
ssize_t
utf8_to_rfc2047 (char **bufp, ssize_t length, uint32 charset, char encoding)
{
struct word {
BString originalWord;
BString convertedWord;
bool needsEncoding;
void ConvertWordToCharset (uint32 charset) {
int32 state = 0;
int32 originalLength = originalWord.Length();
int32 convertedLength = originalLength * 5 + 1;
char *convertedBuffer = convertedWord.LockBuffer (convertedLength);
mail_convert_from_utf8 (charset, originalWord.String(),
&originalLength, convertedBuffer, &convertedLength, &state);
for (int i = 0; i < convertedLength; i++) {
if ((convertedBuffer[i] & (1 << 7)) ||
(convertedBuffer[i] >= 0 && convertedBuffer[i] < 32)) {
needsEncoding = true;
break;
}
}
convertedWord.UnlockBuffer (convertedLength);
};
};
struct word *currentWord;
BList words;
const char *source = *bufp;
const char *bufEnd = *bufp + length;
const char *specialChars = "\"()<>@,";
while (source < bufEnd) {
currentWord = new struct word;
currentWord->needsEncoding = false;
int wordEnd = 0;
while (source + wordEnd < bufEnd && isspace (source[wordEnd]))
wordEnd++;
if (source + wordEnd < bufEnd &&
strchr (specialChars, source[wordEnd]) != NULL) {
wordEnd++;
} else {
while (source + wordEnd < bufEnd) {
if (isspace(source[wordEnd]) ||
strchr (specialChars, source[wordEnd]) != NULL)
break;
if (wordEnd > 51 &&
0xC0 == (0xC0 & (unsigned int) source[wordEnd])) {
currentWord->needsEncoding = true;
break;
}
wordEnd++;
}
}
currentWord->originalWord.SetTo (source, wordEnd);
currentWord->ConvertWordToCharset (charset);
words.AddItem(currentWord);
source += wordEnd;
}
struct word *run;
for (int32 i = 0; (currentWord = (struct word *) words.ItemAt (i)) != NULL; i++) {
if (!currentWord->needsEncoding)
continue;
for (int32 g = i+1; (run = (struct word *) words.ItemAt (g)) != NULL; g++) {
if (!run->needsEncoding)
break;
if ((currentWord->convertedWord.Length() + run->convertedWord.Length() <= 53)) {
currentWord->originalWord.Append (run->originalWord);
currentWord->ConvertWordToCharset (charset);
words.RemoveItem(g);
delete run;
g--;
} else
break;
}
}
BString rfc2047;
bool previousWordNeededEncoding = false;
const char *charset_dec = "none-bug";
for (int32 i = 0; mail_charsets[i].charset != NULL; i++) {
if (mail_charsets[i].flavor == charset) {
charset_dec = mail_charsets[i].charset;
break;
}
}
while ((currentWord = (struct word *)words.RemoveItem((int32)0)) != NULL) {
if ((encoding != quoted_printable && encoding != base64) ||
!currentWord->needsEncoding) {
rfc2047.Append (currentWord->convertedWord);
} else {
if (previousWordNeededEncoding)
rfc2047 << ' ';
else {
if (currentWord->originalWord.Length() > 1 &&
isspace (currentWord->originalWord[0])) {
rfc2047 << currentWord->originalWord[0];
currentWord->originalWord.Remove (0 , 1 );
currentWord->ConvertWordToCharset (charset);
}
}
char *encoded = NULL;
ssize_t encoded_len = 0;
int32 convertedLength = currentWord->convertedWord.Length ();
const char *convertedBuffer = currentWord->convertedWord.String ();
switch (encoding) {
case quoted_printable:
encoded = (char *) malloc (convertedLength * 3);
encoded_len = encode_qp (encoded, convertedBuffer, convertedLength, true );
break;
case base64:
encoded = (char *) malloc (convertedLength * 2);
encoded_len = encode_base64 (encoded, convertedBuffer, convertedLength, true );
break;
default:
encoded = (char *) convertedBuffer;
encoded_len = convertedLength;
break;
}
rfc2047 << "=?" << charset_dec << '?' << encoding << '?';
rfc2047.Append (encoded, encoded_len);
rfc2047 << "?=";
if (encoding == quoted_printable || encoding == base64)
free(encoded);
}
previousWordNeededEncoding = currentWord->needsEncoding;
delete currentWord;
}
free(*bufp);
ssize_t finalLength = rfc2047.Length ();
*bufp = (char *) (malloc (finalLength + 1));
memcpy (*bufp, rfc2047.String(), finalLength);
(*bufp)[finalLength] = 0;
return finalLength;
}
void
FoldLineAtWhiteSpaceAndAddCRLF(BString &string)
{
int inputLength = string.Length();
int lineStartIndex;
const int maxLineLength = 78;
BString output;
int splitIndex;
int tempIndex;
lineStartIndex = 0;
while (true) {
if (lineStartIndex + maxLineLength >= inputLength) {
if (lineStartIndex < inputLength) {
output.Insert (string, lineStartIndex ,
inputLength - lineStartIndex ,
output.Length() );
output.Append (CRLF);
}
break;
}
tempIndex = lineStartIndex + maxLineLength;
if (tempIndex > inputLength)
tempIndex = inputLength;
splitIndex = string.FindLast (", ", tempIndex);
if (splitIndex >= lineStartIndex)
splitIndex++;
if (splitIndex <= lineStartIndex)
splitIndex = string.FindLast (" ", tempIndex);
if (splitIndex <= lineStartIndex)
splitIndex = string.FindLast ("\t", tempIndex);
if (splitIndex <= lineStartIndex)
splitIndex = string.FindFirst (" ", lineStartIndex + 1);
if (splitIndex <= lineStartIndex)
splitIndex = string.FindFirst ("\t", lineStartIndex + 1);
if (splitIndex <= lineStartIndex) {
if (lineStartIndex < inputLength) {
output.Insert (string, lineStartIndex ,
inputLength - lineStartIndex ,
output.Length() );
output.Append (CRLF);
}
break;
}
output.Insert (string, lineStartIndex ,
splitIndex - lineStartIndex ,
output.Length() );
output.Append (CRLF);
lineStartIndex = splitIndex;
}
string.SetTo (output);
}
ssize_t
readfoldedline(FILE *file, char **buffer, size_t *buflen)
{
ssize_t len = buflen && *buflen ? *buflen : 0;
char * buf = buffer && *buffer ? *buffer : NULL;
ssize_t cnt = 0;
int c;
while (true) {
if (buf == NULL || cnt + 2 >= len) {
char *temp = (char *)realloc(buf, len + 64);
if (temp == NULL) {
cnt = ENOMEM;
break;
}
len += 64;
buf = temp;
}
if ((c = fgetc(file)) == EOF) {
if (ferror (file)) {
cnt = errno;
if (cnt >= 0)
cnt = -1;
} else {
if (cnt > 0) {
buf[cnt++] = '\n';
if (buf[cnt-2] == '\r') {
buf[cnt-2] = '\n';
--cnt;
}
}
}
break;
}
buf[cnt++] = c;
if (c == '\n') {
if (cnt >= 2 && buf[cnt-2] == '\r') {
buf[cnt-2] = '\n';
--cnt;
}
if (cnt <= 1)
break;
c = fgetc(file);
if (c == ' ' || c == '\t')
buf[cnt-1] = c;
else {
ungetc(c,file);
break;
}
}
}
if (buf != NULL && cnt >= 0)
buf[cnt] = '\0';
if (buffer)
*buffer = buf;
else if (buf)
free(buf);
if (buflen)
*buflen = len;
return cnt;
}
ssize_t
readfoldedline(BPositionIO &in, char **buffer, size_t *buflen)
{
ssize_t len = buflen && *buflen ? *buflen : 0;
char * buf = buffer && *buffer ? *buffer : NULL;
ssize_t cnt = 0;
char c;
status_t errorCode;
while (true) {
if (buf == NULL || cnt + 2 >= len) {
char *temp = (char *)realloc(buf, len + 64);
if (temp == NULL) {
cnt = ENOMEM;
break;
}
len += 64;
buf = temp;
}
errorCode = in.Read (&c,1);
if (errorCode != 1) {
if (errorCode < 0) {
cnt = errorCode;
} else {
if (cnt > 0) {
buf[cnt++] = '\n';
if (buf[cnt-2] == '\r') {
buf[cnt-2] = '\n';
--cnt;
}
}
}
break;
}
buf[cnt++] = c;
if (c == '\n') {
if (cnt >= 2 && buf[cnt-2] == '\r') {
buf[cnt-2] = '\n';
--cnt;
}
if (cnt <= 1)
break;
errorCode = in.Read(&c,1);
if (errorCode == 1) {
if (c == ' ' || c == '\t')
buf[cnt-1] = c;
else {
in.Seek(-1,SEEK_CUR);
break;
}
} else if (errorCode < 0) {
cnt = errorCode;
break;
} else
break;
}
}
if (buf != NULL && cnt >= 0)
buf[cnt] = '\0';
if (buffer)
*buffer = buf;
else if (buf)
free(buf);
if (buflen)
*buflen = len;
return cnt;
}
ssize_t
nextfoldedline(const char** header, char **buffer, size_t *buflen)
{
ssize_t len = buflen && *buflen ? *buflen : 0;
char * buf = buffer && *buffer ? *buffer : NULL;
ssize_t cnt = 0;
char c;
while (true)
{
if (buf == NULL || cnt + 2 >= len)
{
char *temp = (char *)realloc(buf, len + 64);
if (temp == NULL) {
cnt = ENOMEM;
break;
}
len += 64;
buf = temp;
}
if ((c = *(*header)++) == 0) {
if (cnt > 0) {
buf[cnt++] = '\n';
if (buf[cnt-2] == '\r') {
buf[cnt-2] = '\n';
--cnt;
}
}
break;
}
buf[cnt++] = c;
if (c == '\n') {
if (cnt >= 2 && buf[cnt-2] == '\r') {
buf[cnt-2] = '\n';
--cnt;
}
if (cnt <= 1)
break;
c = *(*header)++;
if (c == ' ' || c == '\t')
buf[cnt-1] = c;
else {
(*header)--;
break;
}
}
}
if (buf != NULL && cnt >= 0)
buf[cnt] = '\0';
if (buffer)
*buffer = buf;
else if (buf)
free(buf);
if (buflen)
*buflen = len;
return cnt;
}
void
trim_white_space(BString &string)
{
int32 i;
int32 length = string.Length();
char *buffer = string.LockBuffer(length + 1);
while (length > 0 && isspace(buffer[length - 1]))
length--;
buffer[length] = '\0';
for (i = 0; buffer[i] && isspace(buffer[i]); i++) {}
if (i != 0) {
length -= i;
memmove(buffer,buffer + i,length + 1);
}
string.UnlockBuffer(length);
}
void
extract_address_name(BString &header)
{
BString name;
const char *start = header.String();
const char *stop = start + strlen (start);
for (int i = 0; i <= 3; i++) {
const char *p1 = NULL, *p2 = NULL;
switch (i) {
case 0:
if ((p1 = strchr(start,'(')) != NULL) {
p1++;
size_t nest = 1;
for (p2 = p1; p2 < stop; ++p2)
{
if (*p2 == ')')
--nest;
else if (*p2 == '(')
++nest;
if (nest <= 0)
break;
}
if (nest != 0)
p2 = NULL;
}
break;
case 1:
if ((p1 = strchr(start, '\"')) != NULL)
p2 = strchr(++p1, '\"');
break;
case 2:
p1 = start;
if (name.Length() == 0)
p2 = strchr(start, '<');
break;
case 3:
p1 = start;
if (name.Length() == 0)
p2 = stop;
break;
}
if (p2 != NULL) {
while (p1 < p2 && (isspace (*p1)))
++p1;
while (p1 < p2 && (isspace (p2[-1])))
--p2;
int newLength = p2 - p1;
if (name.Length() < newLength)
name.SetTo(p1, newLength);
}
}
int32 lessIndex = name.FindFirst('<');
int32 greaterIndex = name.FindLast('>');
if (lessIndex == 0) {
if (greaterIndex > 0)
name.Remove(greaterIndex, 1);
name.Remove(lessIndex, 1);
} else if (lessIndex > 0 && lessIndex < greaterIndex) {
name.Remove(lessIndex, greaterIndex - lessIndex + 1);
}
trim_white_space(name);
header = name;
}
void
SubjectToThread (BString &string)
{
#define U8C \
"[\302-\337][\200-\277]" \
"|\340[\302-\337][\200-\277]" \
"|[\341-\357][\200-\277][\200-\277]" \
"|\360[\220-\277][\200-\277][\200-\277]" \
"|[\361-\367][\200-\277][\200-\277][\200-\277]" \
"|\370[\210-\277][\200-\277][\200-\277][\200-\277]" \
"|[\371-\373][\200-\277][\200-\277][\200-\277][\200-\277]" \
"|\374[\204-\277][\200-\277][\200-\277][\200-\277][\200-\277]" \
"|\375[\200-\277][\200-\277][\200-\277][\200-\277][\200-\277]"
#define PATTERN \
"^ +" \
"|^(\\[[^]]*\\])(\\<| +| *(\\<(\\w|" U8C "){2,3} *(\\[[^\\]]*\\])? *:)+ *)" \
"|^( +| *(\\<(\\w|" U8C "){2,3} *(\\[[^\\]]*\\])? *:)+ *)" \
"| *\\(fwd\\) *$"
if (gRebuf == NULL && atomic_add(&gLocker, 1) == 0) {
for (int i=0; i<256; ++i) gTranslation[i]=i;
for (int i='a'; i<='z'; ++i) gTranslation[i]=toupper(i);
gRe.translate = gTranslation;
gRe.regs_allocated = REGS_FIXED;
re_syntax_options = RE_SYNTAX_POSIX_EXTENDED;
const char *pattern = PATTERN;
for (unsigned int i=0; pattern[i] != 0; ++i)
{
if (pattern[i] == '\\')
++i;
else if (pattern[i] == '(')
++gNsub;
}
const char *err = re_compile_pattern(pattern,strlen(pattern),&gRe);
if (err == NULL)
gRebuf = &gRe;
else
fprintf(stderr, "Failed to compile the regex: %s\n", err);
} else {
int32 tries = 200;
while (gRebuf == NULL && tries-- > 0)
snooze(10000);
}
if (gRebuf) {
struct re_registers regs;
regs.num_regs = gNsub;
regs.start = (regoff_t*)malloc(gNsub*sizeof(regoff_t));
regs.end = (regoff_t*)malloc(gNsub*sizeof(regoff_t));
for (int start = 0; (start = re_search(gRebuf, string.String(),
string.Length(), 0, string.Length(), ®s)) >= 0;) {
if (start == regs.start[1])
start = regs.start[2];
string.Remove(start,regs.end[0]-start);
if (start)
string.Insert(' ',1,start);
if (regs.end[0] - start <= 1)
break;
}
free(regs.start);
free(regs.end);
}
trim_white_space(string);
}
time_t
ParseDateWithTimeZone(const char *DateString)
{
time_t currentTime;
time_t dateAsTime;
char tempDateString[80];
char tempZoneString[6];
time_t zoneDeltaTime;
int zoneIndex;
char *zonePntr;
strncpy (tempDateString, DateString, sizeof (tempDateString));
tempDateString[sizeof (tempDateString) - 1] = 0;
zonePntr = tempDateString + strlen (tempDateString) - 1;
while (zonePntr >= tempDateString && isspace (*zonePntr))
*zonePntr-- = 0;
if (zonePntr < tempDateString)
return -1;
if (tempDateString[strlen(tempDateString)-1] == ')')
{
zonePntr = strrchr (tempDateString, '(');
if (zonePntr != NULL)
{
*zonePntr-- = 0;
while (zonePntr >= tempDateString && isspace (*zonePntr))
*zonePntr-- = 0;
if (zonePntr < tempDateString)
return -1;
}
}
for (zoneIndex = strlen (tempDateString); zoneIndex >= 0; zoneIndex--)
{
zonePntr = tempDateString + zoneIndex;
if (zonePntr[0] == '+' || zonePntr[0] == '-')
{
if (zonePntr[1] >= '0' && zonePntr[1] <= '9' &&
zonePntr[2] >= '0' && zonePntr[2] <= '9' &&
zonePntr[3] >= '0' && zonePntr[3] <= '9' &&
zonePntr[4] >= '0' && zonePntr[4] <= '9')
break;
}
}
if (zoneIndex >= 0)
{
memcpy (tempZoneString, zonePntr, 5);
tempZoneString [5] = 0;
strcpy (zonePntr, "GMT");
}
else
strcpy (tempZoneString, "+0000");
time (¤tTime);
dateAsTime = parsedate (tempDateString, currentTime);
if (dateAsTime == (time_t) -1)
return -1;
zoneDeltaTime = 60 * atol (tempZoneString + 3);
tempZoneString[3] = 0;
zoneDeltaTime += atol (tempZoneString + 1) * 60 * 60;
if (tempZoneString[0] == '+')
zoneDeltaTime = 0 - zoneDeltaTime;
dateAsTime += zoneDeltaTime;
return dateAsTime;
}
status_t
parse_header(BMessage &headers, BPositionIO &input)
{
char *buffer = NULL;
size_t bufferSize = 0;
int32 length;
while ((length = readfoldedline(input, &buffer, &bufferSize)) >= 2) {
--length;
length = rfc2047_to_utf8(&buffer, &bufferSize, length);
buffer[length] = '\0';
const char *delimiter = strstr(buffer, ":");
if (delimiter == NULL)
continue;
BString header(buffer, delimiter - buffer);
header.CapitalizeEachWord();
delimiter++;
while (isspace(*delimiter))
delimiter++;
headers.AddString(header.String(), delimiter);
}
free(buffer);
return B_OK;
}
status_t
extract_from_header(const BString& header, const BString& field,
BString& target)
{
int32 headerLength = header.Length();
int32 fieldEndPos = 0;
while (true) {
int32 pos = header.IFindFirst(field, fieldEndPos);
if (pos < 0)
return B_BAD_VALUE;
fieldEndPos = pos + field.Length();
if (pos != 0 && header.ByteAt(pos - 1) != '\n')
continue;
if (header.ByteAt(fieldEndPos) == ':')
break;
}
fieldEndPos++;
int32 crPos = fieldEndPos;
while (true) {
fieldEndPos = crPos;
crPos = header.FindFirst('\n', crPos);
if (crPos < 0)
crPos = headerLength;
BString temp;
header.CopyInto(temp, fieldEndPos, crPos - fieldEndPos);
if (header.ByteAt(crPos - 1) == '\r') {
temp.Truncate(temp.Length() - 1);
temp += " ";
}
target += temp;
crPos++;
if (crPos >= headerLength)
break;
char nextByte = header.ByteAt(crPos);
if (nextByte != ' ' && nextByte != '\t')
break;
crPos++;
}
size_t bufferSize = target.Length();
char* buffer = target.LockBuffer(bufferSize);
size_t length = rfc2047_to_utf8(&buffer, &bufferSize, bufferSize);
target.UnlockBuffer(length);
trim_white_space(target);
return B_OK;
}
void
extract_address(BString &address)
{
const char *string = address.String();
int32 first;
if ((first = address.FindFirst('"')) >= 0) {
int32 last = first + 1;
while (string[last] && string[last] != '"')
last++;
if (string[last] == '"')
address.Remove(first, last + 1 - first);
}
if ((first = address.FindFirst('<')) >= 0) {
int32 last = address.FindFirst('>');
if (last >= 0) {
address.Truncate(last);
address.Remove(0, first + 1);
return;
}
}
if ((first = address.FindFirst('(')) >= 0) {
int32 last = first + 1;
while (string[last] && string[last] != ')')
last++;
if (string[last] == ')')
address.Remove(first, last + 1 - first);
}
trim_white_space(address);
}
void
get_address_list(BList &list, const char *string,
void (*cleanupFunc)(BString &))
{
if (string == NULL || !string[0])
return;
const char *start = string;
while (true) {
if (string[0] == '"') {
const char *quoteEnd = ++string;
while (quoteEnd[0] && quoteEnd[0] != '"')
quoteEnd++;
if (!quoteEnd[0])
quoteEnd = string;
string = quoteEnd + 1;
}
if (string[0] == ',' || string[0] == '\0') {
BString address(start, string - start);
trim_white_space(address);
if (cleanupFunc)
cleanupFunc(address);
list.AddItem(strdup(address.String()));
start = string + 1;
}
if (!string[0])
break;
string++;
}
}
status_t
CopyMailFolderAttributes(const char* targetPath)
{
BPath path;
status_t status = find_directory(B_USER_SETTINGS_DIRECTORY, &path);
if (status != B_OK)
return status;
path.Append("Tracker");
path.Append("DefaultQueryTemplates");
path.Append("text_x-email");
BNode source(path.Path());
BNode target(targetPath);
return BPrivate::CopyAttributes(source, target);
}