X-Git-Url: https://code.citadel.org/?a=blobdiff_plain;f=libcitadel%2Flib%2Fstringbuf.c;h=ba7b4c1bac98afae6c92dc81eaff62fe285efec2;hb=c06a778e93095d5ec83f4fd58e2d7d8a0d1191e8;hp=f621255c8224363b10fd9a0ba31783f405e0aa58;hpb=a25aad2034f79b31c3fbe8442ff2847d5f322d68;p=citadel.git diff --git a/libcitadel/lib/stringbuf.c b/libcitadel/lib/stringbuf.c index f621255c8..ba7b4c1ba 100644 --- a/libcitadel/lib/stringbuf.c +++ b/libcitadel/lib/stringbuf.c @@ -1,3 +1,20 @@ +// Copyright (c) 1987-2022 by the citadel.org team +// +// This program is open source software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +#define _GNU_SOURCE #include "sysdep.h" #include #include @@ -10,8 +27,12 @@ #include #define SHOW_ME_VAPPEND_PRINTF #include + #include "libcitadel.h" +#include "b64/cencode.h" +#include "b64/cdecode.h" + #ifdef HAVE_ICONV #include #endif @@ -20,12 +41,23 @@ #include #endif +#ifdef UNDEF_MEMCPY +#undef memcpy +#endif + #ifdef HAVE_ZLIB #include int ZEXPORT compress_gzip(Bytef * dest, size_t * destLen, const Bytef * source, uLong sourceLen, int level); #endif int BaseStrBufSize = 64; +int EnableSplice = 0; +int ZLibCompressionRatio = -1; /* defaults to 6 */ +#ifdef HAVE_ZLIB +#define DEF_MEM_LEVEL 8 /*< memlevel??? */ +#define OS_CODE 0x03 /*< unix */ +const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */ +#endif const char *StrBufNOTNULL = ((char*) NULL) - 1; @@ -222,7 +254,7 @@ void dbg_Init(StrBuf *Buf) * @param A First one * @param B second one */ -static inline void SwapBuffers(StrBuf *A, StrBuf *B) +static inline void iSwapBuffers(StrBuf *A, StrBuf *B) { StrBuf C; @@ -232,6 +264,12 @@ static inline void SwapBuffers(StrBuf *A, StrBuf *B) } +void SwapBuffers(StrBuf *A, StrBuf *B) +{ + iSwapBuffers(A, B); +} + + /** * @ingroup StrBuf_Cast * @brief Cast operator to Plain String @@ -260,35 +298,37 @@ inline int StrLength(const StrBuf *Str) return (Str != NULL) ? Str->BufUsed : 0; } -/** - * @ingroup StrBuf_DeConstructors - * @brief local utility function to resize the buffer - * @param Buf the buffer whichs storage we should increase - * @param KeepOriginal should we copy the original buffer or just start over with a new one - * @param DestSize what should fit in after? - */ -static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize) -{ +// local utility function to resize the buffer +// Buf the buffer whichs storage we should increase +// KeepOriginal should we copy the original buffer or just start over with a new one +// DestSize what should fit in after? +static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize) { char *NewBuf; size_t NewSize = Buf->BufSize * 2; - if (Buf->ConstBuf) + if (Buf->ConstBuf) { return -1; + } - if (DestSize > 0) - while (NewSize <= DestSize) + if (DestSize > 0) { + while ((NewSize <= DestSize) && (NewSize != 0)) { NewSize *= 2; + } + } - NewBuf= (char*) malloc(NewSize); - if (NewBuf == NULL) + if (NewSize == 0) { return -1; + } - if (KeepOriginal && (Buf->BufUsed > 0)) - { + NewBuf = (char*) malloc(NewSize); + if (NewBuf == NULL) { + return -1; + } + + if (KeepOriginal && (Buf->BufUsed > 0)) { memcpy(NewBuf, Buf->buf, Buf->BufUsed); } - else - { + else { NewBuf[0] = '\0'; Buf->BufUsed = 0; } @@ -301,18 +341,13 @@ static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize) return Buf->BufSize; } -/** - * @ingroup StrBuf_DeConstructors - * @brief shrink / increase an _EMPTY_ buffer to NewSize. Buffercontent is thoroughly ignored and flushed. - * @param Buf Buffer to shrink (has to be empty) - * @param ThreshHold if the buffer is bigger then this, its readjusted - * @param NewSize if we Shrink it, how big are we going to be afterwards? - */ -void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize) -{ - if ((Buf != NULL) && - (Buf->BufUsed == 0) && - (Buf->BufSize < ThreshHold)) { + +// shrink / increase an _EMPTY_ buffer to NewSize. Buffercontent is thoroughly ignored and flushed. +// Buf Buffer to shrink (has to be empty) +// ThreshHold if the buffer is bigger then this, its readjusted +// NewSize if we Shrink it, how big are we going to be afterwards? +void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize) { + if ((Buf != NULL) && (Buf->BufUsed == 0) && (Buf->BufSize < ThreshHold)) { free(Buf->buf); Buf->buf = (char*) malloc(NewSize); Buf->BufUsed = 0; @@ -320,6 +355,7 @@ void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize) } } + /** * @ingroup StrBuf_DeConstructors * @brief shrink long term buffers to their real size so they don't waste memory @@ -334,7 +370,12 @@ long StrBufShrinkToFit(StrBuf *Buf, int Force) if (Force || (Buf->BufUsed + (Buf->BufUsed / 3) > Buf->BufSize)) { - char *TmpBuf = (char*) malloc(Buf->BufUsed + 1); + char *TmpBuf; + + TmpBuf = (char*) malloc(Buf->BufUsed + 1); + if (TmpBuf == NULL) + return -1; + memcpy (TmpBuf, Buf->buf, Buf->BufUsed + 1); Buf->BufSize = Buf->BufUsed + 1; free(Buf->buf); @@ -353,7 +394,15 @@ StrBuf* NewStrBuf(void) StrBuf *NewBuf; NewBuf = (StrBuf*) malloc(sizeof(StrBuf)); + if (NewBuf == NULL) + return NULL; + NewBuf->buf = (char*) malloc(BaseStrBufSize); + if (NewBuf->buf == NULL) + { + free(NewBuf); + return NULL; + } NewBuf->buf[0] = '\0'; NewBuf->BufSize = BaseStrBufSize; NewBuf->BufUsed = 0; @@ -378,7 +427,16 @@ StrBuf* NewStrBufDup(const StrBuf *CopyMe) return NewStrBuf(); NewBuf = (StrBuf*) malloc(sizeof(StrBuf)); + if (NewBuf == NULL) + return NULL; + NewBuf->buf = (char*) malloc(CopyMe->BufSize); + if (NewBuf->buf == NULL) + { + free(NewBuf); + return NULL; + } + memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1); NewBuf->BufUsed = CopyMe->BufUsed; NewBuf->BufSize = CopyMe->BufSize; @@ -451,7 +509,7 @@ void NewStrBufDupAppendFlush(StrBuf **CreateRelpaceMe, StrBuf *CopyFlushMe, cons } else NewBuf = *CreateRelpaceMe; - SwapBuffers (NewBuf, CopyFlushMe); + iSwapBuffers (NewBuf, CopyFlushMe); } if (!KeepOriginal) FlushStrBuf(CopyFlushMe); @@ -474,14 +532,23 @@ StrBuf* NewStrBufPlain(const char* ptr, int nChars) size_t CopySize; NewBuf = (StrBuf*) malloc(sizeof(StrBuf)); + if (NewBuf == NULL) + return NULL; + if (nChars < 0) CopySize = strlen((ptr != NULL)?ptr:""); else CopySize = nChars; - while (Siz <= CopySize) + while ((Siz <= CopySize) && (Siz != 0)) Siz *= 2; + if (Siz == 0) + { + free(NewBuf); + return NULL; + } + NewBuf->buf = (char*) malloc(Siz); if (NewBuf->buf == NULL) { @@ -532,9 +599,14 @@ int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars) else CopySize = nChars; - while (Siz <= CopySize) + while ((Siz <= CopySize) && (Siz != 0)) Siz *= 2; + if (Siz == 0) { + FlushStrBuf(Buf); + return -1; + } + if (Siz != Buf->BufSize) IncreaseBuf(Buf, 0, Siz); memcpy(Buf->buf, ptr, CopySize); @@ -556,6 +628,8 @@ StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant) StrBuf *NewBuf; NewBuf = (StrBuf*) malloc(sizeof(StrBuf)); + if (NewBuf == NULL) + return NULL; NewBuf->buf = (char*) StringConstant; NewBuf->BufSize = SizeOfStrConstant; NewBuf->BufUsed = SizeOfStrConstant; @@ -574,7 +648,7 @@ StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant) */ int FlushStrBuf(StrBuf *buf) { - if (buf == NULL) + if ((buf == NULL) || (buf->buf == NULL)) return -1; if (buf->ConstBuf) return -1; @@ -778,46 +852,42 @@ long StrBufPook(StrBuf *Buf, const char* ptr, long nThChar, long nChars, char Po */ void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, unsigned long Offset) { - if ((AppendBuf == NULL) || (Buf == NULL) || (AppendBuf->buf == NULL)) + if ((AppendBuf == NULL) || (AppendBuf->buf == NULL) || + (Buf == NULL) || (Buf->buf == NULL)) return; if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed + 1) - IncreaseBuf(Buf, - (Buf->BufUsed > 0), - AppendBuf->BufUsed + Buf->BufUsed); + IncreaseBuf(Buf, (Buf->BufUsed > 0), AppendBuf->BufUsed + Buf->BufUsed); - memcpy(Buf->buf + Buf->BufUsed, - AppendBuf->buf + Offset, - AppendBuf->BufUsed - Offset); + memcpy(Buf->buf + Buf->BufUsed, AppendBuf->buf + Offset, AppendBuf->BufUsed - Offset); Buf->BufUsed += AppendBuf->BufUsed - Offset; Buf->buf[Buf->BufUsed] = '\0'; } -/** - * @ingroup StrBuf_Filler - * @brief Append a C-String to the buffer - * @param Buf Buffer to modify - * @param AppendBuf Buffer to copy at the end of our buffer - * @param AppendSize number of bytes to copy; set to -1 if we should count it in advance - * @param Offset Should we start copying from an offset? - */ -void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, unsigned long Offset) -{ +// Append a C-String to the buffer +// Buf Buffer to modify +// AppendBuf Buffer to copy at the end of our buffer +// AppendSize number of bytes to copy; set to -1 if we should count it in advance +// Offset Should we start copying from an offset? +void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, unsigned long Offset) { long aps; long BufSizeRequired; if ((AppendBuf == NULL) || (Buf == NULL)) return; - if (AppendSize < 0 ) + if (AppendSize < 0) { aps = strlen(AppendBuf + Offset); - else + } + else { aps = AppendSize - Offset; + } BufSizeRequired = Buf->BufUsed + aps + 1; - if (Buf->BufSize <= BufSizeRequired) + if (Buf->BufSize <= BufSizeRequired) { IncreaseBuf(Buf, (Buf->BufUsed > 0), BufSizeRequired); + } memcpy(Buf->buf + Buf->BufUsed, AppendBuf + Offset, @@ -826,7 +896,7 @@ void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, u Buf->buf[Buf->BufUsed] = '\0'; } -/** +/* * @ingroup StrBuf_Filler * @brief sprintf like function appending the formated string to the buffer * vsnprintf version to wrap into own calls @@ -858,7 +928,8 @@ void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap) va_end(apl); newused = Offset + nWritten; if (newused >= Buf->BufSize) { - IncreaseBuf(Buf, 1, newused); + if (IncreaseBuf(Buf, 1, newused) == -1) + return; /* TODO: error handling? */ newused = Buf->BufSize + 1; } else { @@ -899,7 +970,8 @@ void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...) va_end(arg_ptr); newused = Buf->BufUsed + nWritten; if (newused >= Buf->BufSize) { - IncreaseBuf(Buf, 1, newused); + if (IncreaseBuf(Buf, 1, newused) == -1) + return; /* TODO: error handling? */ newused = Buf->BufSize + 1; } else { @@ -930,7 +1002,8 @@ void StrBufPrintf(StrBuf *Buf, const char *format, ...) nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr); va_end(arg_ptr); if (nWritten >= Buf->BufSize) { - IncreaseBuf(Buf, 0, 0); + if (IncreaseBuf(Buf, 0, 0) == -1) + return; /* TODO: error handling? */ nWritten = Buf->BufSize + 1; continue; } @@ -980,16 +1053,18 @@ int StrBufSub(StrBuf *dest, const StrBuf *Source, unsigned long Offset, size_t n } if (Offset + nChars < Source->BufUsed) { - if (nChars >= dest->BufSize) - IncreaseBuf(dest, 0, nChars + 1); + if ((nChars >= dest->BufSize) && + (IncreaseBuf(dest, 0, nChars + 1) == -1)) + return 0; memcpy(dest->buf, Source->buf + Offset, nChars); dest->BufUsed = nChars; dest->buf[dest->BufUsed] = '\0'; return nChars; } NCharsRemain = Source->BufUsed - Offset; - if (NCharsRemain >= dest->BufSize) - IncreaseBuf(dest, 0, NCharsRemain + 1); + if ((NCharsRemain >= dest->BufSize) && + (IncreaseBuf(dest, 0, NCharsRemain + 1) == -1)) + return 0; memcpy(dest->buf, Source->buf + Offset, NCharsRemain); dest->BufUsed = NCharsRemain; dest->buf[dest->BufUsed] = '\0'; @@ -1022,7 +1097,9 @@ void StrBufCutLeft(StrBuf *Buf, int nChars) */ void StrBufCutRight(StrBuf *Buf, int nChars) { - if ((Buf == NULL) || (Buf->BufUsed == 0)) return; + if ((Buf == NULL) || (Buf->BufUsed == 0) || (Buf->buf == NULL)) + return; + if (nChars >= Buf->BufUsed) { FlushStrBuf(Buf); return; @@ -1099,29 +1176,22 @@ void StrBufSpaceToBlank(StrBuf *Buf) void StrBufStripAllBut(StrBuf *Buf, char leftboundary, char rightboundary) { - const char *pBuff; const char *pLeft; const char *pRight; - if (Buf == NULL) + if ((Buf == NULL) || (Buf->buf == NULL)) { return; - pLeft = pBuff = Buf->buf; - while (pBuff != NULL) { - pLeft = pBuff; - pBuff = strchr(pBuff, leftboundary); - if (pBuff != NULL) - pBuff++; } - - if (pLeft != NULL) - pBuff = pLeft; - else - pBuff = Buf->buf; - pRight = strchr(pBuff, rightboundary); - if (pRight != NULL) + + pRight = strchr(Buf->buf, rightboundary); + if (pRight != NULL) { StrBufCutAt(Buf, 0, pRight); - if (pLeft != NULL) - StrBufCutLeft(Buf, pLeft - Buf->buf); + } + + pLeft = strrchr(ChrPtr(Buf), leftboundary); + if (pLeft != NULL) { + StrBufCutLeft(Buf, pLeft - Buf->buf + 1); + } } @@ -1301,6 +1371,23 @@ int StrBufRemove_token(StrBuf *Source, int parmnum, char separator) return ReducedBy; } +int StrBufExtract_tokenFromStr(StrBuf *dest, const char *Source, long SourceLen, int parmnum, char separator) +{ + const StrBuf Temp = { + (char*)Source, + SourceLen, + SourceLen, + 1 +#ifdef SIZE_DEBUG + , + 0, + "", + "" +#endif + }; + + return StrBufExtract_token(dest, &Temp, parmnum, separator); +} /** * @ingroup StrBuf_Tokenizer @@ -1333,7 +1420,7 @@ int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char se //cit_backtrace(); //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source); - while ((s: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source); - while ((sBufUsed; } + if (len == 0) + return; + + pt = OutBuf->buf + OutBuf->BufUsed; + pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */ + + while (pch < pche) { + if (pt >= pte) { + IncreaseBuf(OutBuf, 1, -1); + pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */ + pt = OutBuf->buf + OutBuf->BufUsed; + } + + if((*pch >= 'a' && *pch <= 'z') || + (*pch >= 'A' && *pch <= 'Z') || /* A-Z */ + (*pch >= '0' && *pch <= ':') || /* 0-9 : */ + (*pch == '!') || (*pch == '_') || + (*pch == ',') || (*pch == '.')) + { + *(pt++) = *(pch++); + OutBuf->BufUsed++; + } + else { + *pt = '%'; + *(pt + 1) = HexList[(unsigned char)*pch][0]; + *(pt + 2) = HexList[(unsigned char)*pch][1]; + pt += 3; + OutBuf->BufUsed += 3; + pch ++; + } + } + *pt = '\0'; +} + +/** + * @ingroup StrBuf_DeEnCoder + * @brief append a string with characters having a special meaning in xml encoded to the buffer + * @param OutBuf the output buffer + * @param In Buffer to encode + * @param PlainIn way in from plain old c strings + * @param PlainInLen way in from plain old c strings; maybe you've got binary data or know the length? + * @param OverrideLowChars should chars < 0x20 be replaced by _ or escaped as xml entity? + */ +void StrBufXMLEscAppend(StrBuf *OutBuf, + const StrBuf *In, + const char *PlainIn, + long PlainInLen, + int OverrideLowChars) +{ + const char *pch, *pche; + char *pt, *pte; + int IsUtf8Sequence; + int len; + + if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) ) + return; + if (PlainIn != NULL) { + if (PlainInLen < 0) + len = strlen((const char*)PlainIn); + else + len = PlainInLen; + pch = PlainIn; + pche = pch + len; + } + else { + pch = (const char*)In->buf; + pche = pch + In->BufUsed; + len = In->BufUsed; + } + + if (len == 0) + return; + + pt = OutBuf->buf + OutBuf->BufUsed; + /**< we max append 6 chars at once plus the \0 */ + pte = OutBuf->buf + OutBuf->BufSize - 6; + + while (pch < pche) { + if (pt >= pte) { + OutBuf->BufUsed = pt - OutBuf->buf; + IncreaseBuf(OutBuf, 1, -1); + pte = OutBuf->buf + OutBuf->BufSize - 6; + /**< we max append 3 chars at once plus the \0 */ + + pt = OutBuf->buf + OutBuf->BufUsed; + } + + if (*pch == '<') { + memcpy(pt, HKEY("<")); + pt += 4; + pch ++; + } + else if (*pch == '>') { + memcpy(pt, HKEY(">")); + pt += 4; + pch ++; + } + else if (*pch == '&') { + memcpy(pt, HKEY("&")); + pt += 5; + pch++; + } + else if ((*pch >= 0x20) && (*pch <= 0x7F)) { + *pt = *pch; + pt++; pch++; + } + else { + IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(pch, pche); + if (IsUtf8Sequence) + { + while ((IsUtf8Sequence > 0) && + (pch < pche)) + { + *pt = *pch; + pt ++; + pch ++; + --IsUtf8Sequence; + } + } + else + { + *pt = '&'; + pt++; + *pt = HexList[*(unsigned char*)pch][0]; + pt ++; + *pt = HexList[*(unsigned char*)pch][1]; + pt ++; pch ++; + *pt = '&'; + pt++; + pch ++; + } + } + } + *pt = '\0'; + OutBuf->BufUsed = pt - OutBuf->buf; +} + + +/** + * @ingroup StrBuf_DeEnCoder + * @brief append a string in hex encoding to the buffer + * @param OutBuf the output buffer + * @param In Buffer to encode + * @param PlainIn way in from plain old c strings + * @param PlainInLen way in from plain old c strings; maybe you've got binary data or know the length? + */ +void StrBufHexEscAppend(StrBuf *OutBuf, const StrBuf *In, const unsigned char *PlainIn, long PlainInLen) +{ + const unsigned char *pch, *pche; + char *pt, *pte; + int len; + + if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) ) + return; + if (PlainIn != NULL) { + if (PlainInLen < 0) + len = strlen((const char*)PlainIn); + else + len = PlainInLen; + pch = PlainIn; + pche = pch + len; + } + else { + pch = (const unsigned char*)In->buf; + pche = pch + In->BufUsed; + len = In->BufUsed; + } + if (len == 0) return; @@ -1820,14 +2075,65 @@ void StrBufHexescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn) pt = OutBuf->buf + OutBuf->BufUsed; } - *pt = HexList[(unsigned char)*pch][0]; + *pt = HexList[*pch][0]; pt ++; - *pt = HexList[(unsigned char)*pch][1]; + *pt = HexList[*pch][1]; pt ++; pch ++; OutBuf->BufUsed += 2; } *pt = '\0'; } +void StrBufBase64Append(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn, long PlainInLen, int linebreaks) +{ + const char *pch; + char *pt; + int len; + long ExpectLen; + + if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) ) + return; + if (PlainIn != NULL) { + if (PlainInLen < 0) + len = strlen(PlainIn); + else + len = PlainInLen; + pch = PlainIn; + } + else { + pch = In->buf; + len = In->BufUsed; + } + + if (len == 0) + return; + + ExpectLen = ((len * 134) / 100) + OutBuf->BufUsed; + + if (ExpectLen > OutBuf->BufSize) + if (IncreaseBuf(OutBuf, 1, ExpectLen) < ExpectLen) + return; + + pt = OutBuf->buf + OutBuf->BufUsed; + + len = CtdlEncodeBase64(pt, pch, len, linebreaks); + + pt += len; + OutBuf->BufUsed += len; + *pt = '\0'; +} + +/** + * @ingroup StrBuf_DeEnCoder + * @brief append a string in hex encoding to the buffer + * @param OutBuf the output buffer + * @param In Buffer to encode + * @param PlainIn way in from plain old c strings + */ +void StrBufHexescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn) +{ + StrBufHexEscAppend(OutBuf, In, (const unsigned char*) PlainIn, -1); +} + /** * @ingroup StrBuf_DeEnCoder * @brief Append a string, escaping characters which have meaning in HTML. @@ -2093,6 +2399,7 @@ long StrECMAEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn) const char *aptr, *eiptr; char *bptr, *eptr; long len; + int IsUtf8Sequence; if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) ) return -1; @@ -2112,31 +2419,83 @@ long StrECMAEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn) return -1; bptr = Target->buf + Target->BufUsed; - eptr = Target->buf + Target->BufSize - 3; /* our biggest unit to put in... */ + eptr = Target->buf + Target->BufSize - 7; /* our biggest unit to put in... */ while (aptr < eiptr){ if(bptr >= eptr) { IncreaseBuf(Target, 1, -1); - eptr = Target->buf + Target->BufSize - 3; + eptr = Target->buf + Target->BufSize - 7; /* our biggest unit to put in... */ bptr = Target->buf + Target->BufUsed; } - if (*aptr == '"') { + switch (*aptr) { + case '\n': + memcpy(bptr, HKEY("\\n")); + bptr += 2; + Target->BufUsed += 2; + break; + case '\r': + memcpy(bptr, HKEY("\\r")); + bptr += 2; + Target->BufUsed += 2; + break; + case '"': *bptr = '\\'; bptr ++; *bptr = '"'; bptr ++; Target->BufUsed += 2; - } else if (*aptr == '\\') { - *bptr = '\\'; - bptr ++; - *bptr = '\\'; - bptr ++; + break; + case '\\': + if ((*(aptr + 1) == 'u') && + isxdigit(*(aptr + 2)) && + isxdigit(*(aptr + 3)) && + isxdigit(*(aptr + 4)) && + isxdigit(*(aptr + 5))) + { /* oh, a unicode escaper. let it pass through. */ + memcpy(bptr, aptr, 6); + aptr += 5; + bptr +=6; + Target->BufUsed += 6; + } + else + { + *bptr = '\\'; + bptr ++; + *bptr = '\\'; + bptr ++; + Target->BufUsed += 2; + } + break; + case '\b': + *bptr = '\\'; + bptr ++; + *bptr = 'b'; + bptr ++; Target->BufUsed += 2; - } - else{ - *bptr = *aptr; - bptr++; - Target->BufUsed ++; + break; + case '\f': + *bptr = '\\'; + bptr ++; + *bptr = 'f'; + bptr ++; + Target->BufUsed += 2; + break; + case '\t': + *bptr = '\\'; + bptr ++; + *bptr = 't'; + bptr ++; + Target->BufUsed += 2; + break; + default: + IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(aptr, eiptr); + while (IsUtf8Sequence > 0){ + *bptr = *aptr; + Target->BufUsed ++; + if (--IsUtf8Sequence) + aptr++; + bptr++; + } } aptr ++; } @@ -2190,83 +2549,127 @@ long StrHtmlEcmaEscAppend(StrBuf *Target, const StrBuf *Source, const char *Plai eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */ bptr = Target->buf + Target->BufUsed; } - if (*aptr == '<') { - memcpy(bptr, "<", 4); + switch (*aptr) { + case '<': + memcpy(bptr, HKEY("<")); bptr += 4; Target->BufUsed += 4; - } - else if (*aptr == '>') { - memcpy(bptr, ">", 4); + break; + case '>': + memcpy(bptr, HKEY(">")); bptr += 4; Target->BufUsed += 4; - } - else if (*aptr == '&') { - memcpy(bptr, "&", 5); + break; + case '&': + memcpy(bptr, HKEY("&")); bptr += 5; Target->BufUsed += 5; - } - else if (*aptr == LB) { + break; + case LB: *bptr = '<'; bptr ++; Target->BufUsed ++; - } - else if (*aptr == RB) { + break; + case RB: *bptr = '>'; bptr ++; Target->BufUsed ++; - } - else if ((*aptr == 32) && (nbsp == 1)) { - memcpy(bptr, " ", 6); - bptr += 6; - Target->BufUsed += 6; - } - else if ((*aptr == '\n') && (nolinebreaks == 1)) { - *bptr='\0'; /* nothing */ - } - else if ((*aptr == '\n') && (nolinebreaks == 2)) { - memcpy(bptr, "<br/>", 11); - bptr += 11; - Target->BufUsed += 11; - } - - else if ((*aptr == '\r') && (nolinebreaks != 0)) { - *bptr='\0'; /* nothing */ - } - - else if ((*aptr == '"') || (*aptr == QU)) { + break; + case '\n': + switch (nolinebreaks) { + case 1: + *bptr='\0'; /* nothing */ + break; + case 2: + memcpy(bptr, HKEY("<br/>")); + bptr += 11; + Target->BufUsed += 11; + break; + default: + memcpy(bptr, HKEY("\\n")); + bptr += 2; + Target->BufUsed += 2; + } + break; + case '\r': + switch (nolinebreaks) { + case 1: + case 2: + *bptr='\0'; /* nothing */ + break; + default: + memcpy(bptr, HKEY("\\r")); + bptr += 2; + Target->BufUsed += 2; + break; + } + break; + case '"': + case QU: *bptr = '\\'; bptr ++; *bptr = '"'; bptr ++; Target->BufUsed += 2; - } else if (*aptr == '\\') { + break; + case '\\': + if ((*(aptr + 1) == 'u') && + isxdigit(*(aptr + 2)) && + isxdigit(*(aptr + 3)) && + isxdigit(*(aptr + 4)) && + isxdigit(*(aptr + 5))) + { /* oh, a unicode escaper. let it pass through. */ + memcpy(bptr, aptr, 6); + aptr += 5; + bptr +=6; + Target->BufUsed += 6; + } + else + { + *bptr = '\\'; + bptr ++; + *bptr = '\\'; + bptr ++; + Target->BufUsed += 2; + } + break; + case '\b': *bptr = '\\'; bptr ++; + *bptr = 'b'; + bptr ++; + Target->BufUsed += 2; + break; + case '\f': *bptr = '\\'; bptr ++; + *bptr = 'f'; + bptr ++; Target->BufUsed += 2; - } - else { - if (((unsigned char)*aptr) >= 0x20) - { - IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(aptr, eiptr); - + break; + case '\t': + *bptr = '\\'; + bptr ++; + *bptr = 't'; + bptr ++; + Target->BufUsed += 2; + break; + case 32: + if (nbsp == 1) { + memcpy(bptr, HKEY(" ")); + bptr += 6; + Target->BufUsed += 6; + break; + } + default: + IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(aptr, eiptr); + while (IsUtf8Sequence > 0){ *bptr = *aptr; Target->BufUsed ++; - while (IsUtf8Sequence > 1){ - if(bptr + IsUtf8Sequence >= eptr) { - IncreaseBuf(Target, 1, -1); - eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */ - bptr = Target->buf + Target->BufUsed - 1; - } - bptr++; aptr++; - IsUtf8Sequence --; - *bptr = *aptr; - Target->BufUsed ++; - } + if (--IsUtf8Sequence) + aptr++; bptr++; } - } aptr ++; } @@ -2276,6 +2679,23 @@ long StrHtmlEcmaEscAppend(StrBuf *Target, const StrBuf *Source, const char *Plai return Target->BufUsed; } + +/** + * @ingroup StrBuf_DeEnCoder + * @brief replace all non-Ascii characters by another + * @param Buf buffer to inspect + * @param repl charater to stamp over non ascii chars + */ +void StrBufAsciify(StrBuf *Buf, const char repl) +{ + long offset; + + for (offset = 0; offset < Buf->BufUsed; offset ++) + if (!isascii(Buf->buf[offset])) + Buf->buf[offset] = repl; + +} + /** * @ingroup StrBuf_DeEnCoder * @brief unhide special chars hidden to the HTML escaper @@ -2287,14 +2707,14 @@ void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source) int a, b, len; char hex[3]; - if (target != NULL) - FlushStrBuf(target); - - if (source == NULL ||target == NULL) + if ((source == NULL) || (target == NULL) || (target->buf == NULL)) { return; } + if (target != NULL) + FlushStrBuf(target); + len = source->BufUsed; for (a = 0; a < len; ++a) { if (target->BufUsed >= target->BufSize) @@ -2331,7 +2751,7 @@ void StrBufEUid_escapize(StrBuf *target, const StrBuf *source) if (target != NULL) FlushStrBuf(target); - if (source == NULL ||target == NULL) + if ((source == NULL) || (target == NULL) || (target->buf == NULL)) { return; } @@ -2369,9 +2789,14 @@ int StrBufDecodeBase64(StrBuf *Buf) { char *xferbuf; size_t siz; - if (Buf == NULL) return -1; + + if (Buf == NULL) + return -1; xferbuf = (char*) malloc(Buf->BufSize); + if (xferbuf == NULL) + return -1; + *xferbuf = '\0'; siz = CtdlDecodeBase64(xferbuf, Buf->buf, @@ -2379,16 +2804,291 @@ int StrBufDecodeBase64(StrBuf *Buf) free(Buf->buf); Buf->buf = xferbuf; Buf->BufUsed = siz; + + Buf->buf[Buf->BufUsed] = '\0'; return siz; } +/** + * @ingroup StrBuf_DeEnCoder + * @brief decode a buffer from base 64 encoding; expects targetbuffer + * @param BufIn Buffor to transform + * @param BufOut Buffer to put result into + */ +int StrBufDecodeBase64To(const StrBuf *BufIn, StrBuf *BufOut) +{ + if ((BufIn == NULL) || (BufOut == NULL)) + return -1; + + if (BufOut->BufSize < BufIn->BufUsed) + IncreaseBuf(BufOut, 0, BufIn->BufUsed); + + BufOut->BufUsed = CtdlDecodeBase64(BufOut->buf, + BufIn->buf, + BufIn->BufUsed); + return BufOut->BufUsed; +} + +typedef struct __z_enc_stream { + StrBuf OutBuf; + z_stream zstream; +} z_enc_stream; + +vStreamT *StrBufNewStreamContext(eStreamType type, const char **Err) +{ + base64_decodestate *state;; + *Err = NULL; + + switch (type) + { + case eBase64Decode: + case eBase64Encode: + state = (base64_decodestate*) malloc(sizeof(base64_decodestate)); + base64_init_decodestate(state); + return (vStreamT*) state; + break; + case eZLibDecode: + { + + z_enc_stream *stream; + int err; + + stream = (z_enc_stream *) malloc(sizeof(z_enc_stream)); + memset(stream, 0, sizeof(z_enc_stream)); + stream->OutBuf.BufSize = 4*SIZ; /// TODO 64 + stream->OutBuf.buf = (char*)malloc(stream->OutBuf.BufSize); + + err = inflateInit(&stream->zstream); + + if (err != Z_OK) { + StrBufDestroyStreamContext(type, (vStreamT**) &stream, Err); + *Err = zError(err); + return NULL; + } + return (vStreamT*) stream; + + } + case eZLibEncode: + { + z_enc_stream *stream; + int err; + + stream = (z_enc_stream *) malloc(sizeof(z_enc_stream)); + memset(stream, 0, sizeof(z_enc_stream)); + stream->OutBuf.BufSize = 4*SIZ; /// todo 64 + stream->OutBuf.buf = (char*)malloc(stream->OutBuf.BufSize); + /* write gzip header */ + stream->OutBuf.BufUsed = snprintf + (stream->OutBuf.buf, + stream->OutBuf.BufSize, + "%c%c%c%c%c%c%c%c%c%c", + gz_magic[0], gz_magic[1], Z_DEFLATED, + 0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ , + OS_CODE); + + err = deflateInit2(&stream->zstream, + ZLibCompressionRatio, + Z_DEFLATED, + -MAX_WBITS, + DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY); + if (err != Z_OK) { + StrBufDestroyStreamContext(type, (vStreamT**) &stream, Err); + *Err = zError(err); + return NULL; + } + return (vStreamT*) stream; + } + case eEmtyCodec: + /// TODO + + break; + } + return NULL; +} + +int StrBufDestroyStreamContext(eStreamType type, vStreamT **vStream, const char **Err) +{ + int err; + int rc = 0; + *Err = NULL; + + if ((vStream == NULL) || (*vStream==NULL)) { + *Err = strerror(EINVAL); + return EINVAL; + } + switch (type) + { + case eBase64Encode: + case eBase64Decode: + free(*vStream); + *vStream = NULL; + break; + case eZLibDecode: + { + z_enc_stream *stream = (z_enc_stream *)*vStream; + (void)inflateEnd(&stream->zstream); + free(stream->OutBuf.buf); + free(stream); + } + case eZLibEncode: + { + z_enc_stream *stream = (z_enc_stream *)*vStream; + err = deflateEnd(&stream->zstream); + if (err != Z_OK) { + *Err = zError(err); + rc = -1; + } + free(stream->OutBuf.buf); + free(stream); + *vStream = NULL; + break; + } + case eEmtyCodec: + break; /// TODO + } + return rc; +} + +int StrBufStreamTranscode(eStreamType type, IOBuffer *Target, IOBuffer *In, const char* pIn, long pInLen, vStreamT *vStream, int LastChunk, const char **Err) { + int rc = 0; + switch (type) + { + case eBase64Encode: + { + // ??? + } + break; + case eBase64Decode: + { + // ??? + } + break; + case eZLibEncode: + { + z_enc_stream *stream = (z_enc_stream *)vStream; + int org_outbuf_len = stream->OutBuf.BufUsed; + int err; + unsigned int chunkavail; + + if (In->ReadWritePointer != NULL) + { + stream->zstream.next_in = (Bytef *) In->ReadWritePointer; + stream->zstream.avail_in = (uInt) In->Buf->BufUsed - + (In->ReadWritePointer - In->Buf->buf); + } + else + { + stream->zstream.next_in = (Bytef *) In->Buf->buf; + stream->zstream.avail_in = (uInt) In->Buf->BufUsed; + } + + stream->zstream.next_out = (unsigned char*)stream->OutBuf.buf + stream->OutBuf.BufUsed; + stream->zstream.avail_out = chunkavail = (uInt) stream->OutBuf.BufSize - stream->OutBuf.BufUsed; + + err = deflate(&stream->zstream, (LastChunk) ? Z_FINISH : Z_NO_FLUSH); + + stream->OutBuf.BufUsed += (chunkavail - stream->zstream.avail_out); + + if (Target && (LastChunk || (stream->OutBuf.BufUsed != org_outbuf_len))) { + iSwapBuffers(Target->Buf, &stream->OutBuf); + } + + if (stream->zstream.avail_in == 0) { + FlushStrBuf(In->Buf); + In->ReadWritePointer = NULL; + } + else { + if (stream->zstream.avail_in < 64) { + memmove(In->Buf->buf, + In->Buf->buf + In->Buf->BufUsed - stream->zstream.avail_in, + stream->zstream.avail_in); + + In->Buf->BufUsed = stream->zstream.avail_in; + In->Buf->buf[In->Buf->BufUsed] = '\0'; + } + else { + In->ReadWritePointer = In->Buf->buf + (In->Buf->BufUsed - stream->zstream.avail_in); + } + } + rc = (LastChunk && (err != Z_FINISH)); + if (!rc && (err != Z_OK)) { + *Err = zError(err); + } + + } + break; + case eZLibDecode: { + z_enc_stream *stream = (z_enc_stream *)vStream; + int org_outbuf_len = stream->zstream.total_out; + int err; + + if ((stream->zstream.avail_out != 0) && (stream->zstream.next_in != NULL)) { + if (In->ReadWritePointer != NULL) { + stream->zstream.next_in = (Bytef *) In->ReadWritePointer; + stream->zstream.avail_in = (uInt) In->Buf->BufUsed - (In->ReadWritePointer - In->Buf->buf); + } + else { + stream->zstream.next_in = (Bytef *) In->Buf->buf; + stream->zstream.avail_in = (uInt) In->Buf->BufUsed; + } + } + + stream->zstream.next_out = (unsigned char*)stream->OutBuf.buf + stream->OutBuf.BufUsed; + stream->zstream.avail_out = (uInt) stream->OutBuf.BufSize - stream->OutBuf.BufUsed; + + err = inflate(&stream->zstream, Z_NO_FLUSH); + + ///assert(ret != Z_STREAM_ERROR); /* state not clobbered * / + switch (err) { + case Z_NEED_DICT: + err = Z_DATA_ERROR; /* and fall through */ + + case Z_DATA_ERROR: + *Err = zError(err); + case Z_MEM_ERROR: + (void)inflateEnd(&stream->zstream); + return err; + } + + stream->OutBuf.BufUsed += stream->zstream.total_out + org_outbuf_len; + + if (Target) iSwapBuffers(Target->Buf, &stream->OutBuf); + + if (stream->zstream.avail_in == 0) { + FlushStrBuf(In->Buf); + In->ReadWritePointer = NULL; + } + else { + if (stream->zstream.avail_in < 64) { + memmove(In->Buf->buf, + In->Buf->buf + In->Buf->BufUsed - stream->zstream.avail_in, + stream->zstream.avail_in); + + In->Buf->BufUsed = stream->zstream.avail_in; + In->Buf->buf[In->Buf->BufUsed] = '\0'; + } + else { + + In->ReadWritePointer = In->Buf->buf + (In->Buf->BufUsed - stream->zstream.avail_in); + } + } + } + break; + case eEmtyCodec: { + + } + break; /// TODO + } + return rc; +} + /** * @ingroup StrBuf_DeEnCoder * @brief decode a buffer from base 64 encoding; destroys original * @param Buf Buffor to transform */ -int StrBufDecodeHex(StrBuf *Buf) -{ +int StrBufDecodeHex(StrBuf *Buf) { unsigned int ch; char *pch, *pche, *pchi; @@ -2519,7 +3219,10 @@ int StrBufRFC2047encode(StrBuf **target, const StrBuf *source) FlushStrBuf(*target); StrBufAppendBuf(*target, source, 0); } - return (*target)->BufUsed; + if (*target != 0) + return (*target)->BufUsed; + else + return 0; } if (*target == NULL) *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2); @@ -2531,12 +3234,22 @@ int StrBufRFC2047encode(StrBuf **target, const StrBuf *source) if ((*target)->BufUsed + 4 >= (*target)->BufSize) IncreaseBuf(*target, 1, 0); ch = (unsigned char) source->buf[i]; - if ((ch < 32) || (ch > 126) || (ch == 61)) { + if ((ch < 32) || + (ch > 126) || + (ch == '=') || + (ch == '?') || + (ch == '_') || + (ch == '[') || + (ch == ']') ) + { sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch); (*target)->BufUsed += 3; } else { - (*target)->buf[(*target)->BufUsed] = ch; + if (ch == ' ') + (*target)->buf[(*target)->BufUsed] = '_'; + else + (*target)->buf[(*target)->BufUsed] = ch; (*target)->BufUsed++; } } @@ -2550,6 +3263,95 @@ int StrBufRFC2047encode(StrBuf **target, const StrBuf *source) return (*target)->BufUsed;; } +/** + * @ingroup StrBuf_DeEnCoder + * @brief Quoted-Printable encode a message; make it < 80 columns width. + * @param source Source string to be encoded. + * @returns buffer with encoded message. + */ +StrBuf *StrBufRFC2047encodeMessage(const StrBuf *EncodeMe) +{ + StrBuf *OutBuf; + char *Optr, *OEptr; + const char *ptr, *eptr; + unsigned char ch; + int LinePos; + + OutBuf = NewStrBufPlain(NULL, StrLength(EncodeMe) * 4); + Optr = OutBuf->buf; + OEptr = OutBuf->buf + OutBuf->BufSize; + ptr = EncodeMe->buf; + eptr = EncodeMe->buf + EncodeMe->BufUsed; + LinePos = 0; + + while (ptr < eptr) + { + if (Optr + 4 >= OEptr) + { + long Offset; + Offset = Optr - OutBuf->buf; + OutBuf->BufUsed = Optr - OutBuf->buf; + IncreaseBuf(OutBuf, 1, 0); + Optr = OutBuf->buf + Offset; + OEptr = OutBuf->buf + OutBuf->BufSize; + } + if (*ptr == '\r') + { + /* ignore carriage returns */ + ptr ++; + } + else if (*ptr == '\n') { + /* hard line break */ + memcpy(Optr, HKEY("=0A")); + Optr += 3; + LinePos += 3; + ptr ++; + } + else if (( (*ptr >= 32) && (*ptr <= 60) ) || + ( (*ptr >= 62) && (*ptr <= 126) )) + { + *Optr = *ptr; + Optr ++; + ptr ++; + LinePos ++; + } + else { + ch = *ptr; + *Optr = '='; + Optr ++; + *Optr = HexList[ch][0]; + Optr ++; + *Optr = HexList[ch][1]; + Optr ++; + LinePos += 3; + ptr ++; + } + + if (LinePos > 72) { + /* soft line break */ + if (isspace(*(Optr - 1))) { + ch = *(Optr - 1); + Optr --; + *Optr = '='; + Optr ++; + *Optr = HexList[ch][0]; + Optr ++; + *Optr = HexList[ch][1]; + Optr ++; + LinePos += 3; + } + *Optr = '='; + Optr ++; + *Optr = '\n'; + Optr ++; + LinePos = 0; + } + } + *Optr = '\0'; + OutBuf->BufUsed = Optr - OutBuf->buf; + + return OutBuf; +} static void AddRecipient(StrBuf *Target, @@ -2590,15 +3392,12 @@ StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp, StrBuf *EncBuf) { StrBuf *Target; - int need_to_encode; - const char *pch, *pche; const char *UserStart, *UserEnd, *EmailStart, *EmailEnd, *At; if ((Recp == NULL) || (StrLength(Recp) == 0)) return NULL; - need_to_encode = 0; pch = ChrPtr(Recp); pche = pch + StrLength(Recp); @@ -2609,10 +3408,8 @@ StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp, while ((pch != NULL) && (pch < pche)) { - int ColonOk = 0; - while (isspace(*pch)) pch++; - UserStart = UserEnd = EmailStart = EmailEnd = NULL; + UserEnd = EmailStart = EmailEnd = NULL; if ((*pch == '"') || (*pch == '\'')) { UserStart = pch + 1; @@ -2640,7 +3437,6 @@ StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp, if (EmailEnd == NULL) EmailEnd = pche; pch = EmailEnd + 1; - ColonOk = 1; } else { int gt = 0; @@ -2684,7 +3480,6 @@ StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp, EmailStart ++; if (UserStart >= UserEnd) UserStart = UserEnd = NULL; - At = strchr(EmailStart, '@'); } else { /* this is a local recipient... no domain, just a realname */ EmailStart = UserStart; @@ -2748,7 +3543,7 @@ void StrBufReplaceChars(StrBuf *buf, char search, char replace) /** * @ingroup StrBuf - * @brief removes all \r s from the string, or replaces them with \n if its not a combination of both. + * @brief removes all \\r s from the string, or replaces them with \n if its not a combination of both. * @param buf Buffer to modify */ void StrBufToUnixLF(StrBuf *buf) @@ -2863,6 +3658,9 @@ void StrBufConvert(StrBuf *ConvertBuf, StrBuf *TmpBuf, void *pic) size_t obuflen; /**< Length of output buffer */ + if ((ConvertBuf == NULL) || (TmpBuf == NULL)) + return; + /* since we're converting to utf-8, one glyph may take up to 6 bytes */ if (ConvertBuf->BufUsed * 6 >= TmpBuf->BufSize) IncreaseBuf(TmpBuf, 0, ConvertBuf->BufUsed * 6); @@ -2898,7 +3696,7 @@ TRYAGAIN: TmpBuf->buf[TmpBuf->BufUsed] = '\0'; /* little card game: wheres the red lady? */ - SwapBuffers(ConvertBuf, TmpBuf); + iSwapBuffers(ConvertBuf, TmpBuf); FlushStrBuf(TmpBuf); } #endif @@ -3045,9 +3843,12 @@ void StrBuf_RFC822_2_Utf8(StrBuf *Target, #endif const char *eptr; int passes = 0; - int i, len; + int i; int illegal_non_rfc2047_encoding = 0; + + if (DecodeMe == NULL) + return; /* Sometimes, badly formed messages contain strings which were simply * written out directly in some foreign character set instead of * using RFC2047 encoding. This is illegal but we will attempt to @@ -3055,7 +3856,6 @@ void StrBuf_RFC822_2_Utf8(StrBuf *Target, * charset to UTF-8 if we see any nonprintable characters. */ - len = StrLength(DecodeMe); for (i=0; iBufUsed; ++i) { if ((DecodeMe->buf[i] < 32) || (DecodeMe->buf[i] > 126)) { illegal_non_rfc2047_encoding = 1; @@ -3079,8 +3879,7 @@ void StrBuf_RFC822_2_Utf8(StrBuf *Target, } /* pre evaluate the first pair */ - nextend = end = NULL; - len = StrLength(DecodeMee); + end = NULL; start = strstr(DecodeMee->buf, "=?"); eptr = DecodeMee->buf + DecodeMee->BufUsed; if (start != NULL) @@ -3097,7 +3896,6 @@ void StrBuf_RFC822_2_Utf8(StrBuf *Target, nFront = start - DecodeMee->buf; StrBufAppendBufPlain(Target, DecodeMee->buf, nFront, 0); - len -= nFront; } /* * Since spammers will go to all sorts of absurd lengths to get their @@ -3180,19 +3978,24 @@ void StrBuf_RFC822_2_Utf8(StrBuf *Target, * @ingroup StrBuf * @brief evaluate the length of an utf8 special character sequence * @param Char the character to examine - * @returns width of utf8 chars in bytes + * @returns width of utf8 chars in bytes; if the sequence is broken 0 is returned; 1 if its simply ASCII. */ static inline int Ctdl_GetUtf8SequenceLength(const char *CharS, const char *CharE) { - int n = 1; - char test = (1<<7); - - while ((n < 8) && ((test & *CharS) != 0)) { - test = test << 1; + int n = 0; + unsigned char test = (1<<7); + + if ((*CharS & 0xC0) != 0xC0) + return 1; + + while ((n < 8) && + ((test & ((unsigned char)*CharS)) != 0)) + { + test = test >> 1; n ++; } if ((n > 6) || ((CharE - CharS) < n)) - n = 1; + n = 0; return n; } @@ -3205,7 +4008,7 @@ static inline int Ctdl_GetUtf8SequenceLength(const char *CharS, const char *Char static inline int Ctdl_IsUtf8SequenceStart(const char Char) { /** 11??.???? indicates an UTF8 Sequence. */ - return ((Char & 0xC0) != 0); + return ((Char & 0xC0) == 0xC0); } /** @@ -3262,11 +4065,11 @@ long StrBuf_Utf8StrCut(StrBuf *Buf, int maxlen) n++; aptr++; } - if (n > maxlen) { + if (n >= maxlen) { *aptr = '\0'; Buf->BufUsed = aptr - Buf->buf; return Buf->BufUsed; - } + } } return Buf->BufUsed; @@ -3280,10 +4083,6 @@ long StrBuf_Utf8StrCut(StrBuf *Buf, int maxlen) * wrapping ZLib * *******************************************************************************/ -#ifdef HAVE_ZLIB -#define DEF_MEM_LEVEL 8 /*< memlevel??? */ -#define OS_CODE 0x03 /*< unix */ - /** * @ingroup StrBuf_DeEnCoder * @brief uses the same calling syntax as compress2(), but it @@ -3294,14 +4093,13 @@ long StrBuf_Utf8StrCut(StrBuf *Buf, int maxlen) * @param sourceLen length of source to encode * @param level compression level */ +#ifdef HAVE_ZLIB int ZEXPORT compress_gzip(Bytef * dest, size_t * destLen, const Bytef * source, uLong sourceLen, int level) { - const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */ - /* write gzip header */ snprintf((char *) dest, *destLen, "%c%c%c%c%c%c%c%c%c%c", @@ -3532,6 +4330,10 @@ eReadState StrBufChunkSipLine(StrBuf *LineBuf, IOBuffer *FB) const char *aptr, *ptr, *eptr; char *optr, *xptr; + if ((FB == NULL) || (LineBuf == NULL) || (LineBuf->buf == NULL)) + return eReadFail; + + if ((FB->Buf == NULL) || (FB->ReadWritePointer == StrBufNOTNULL)) { FB->ReadWritePointer = StrBufNOTNULL; return eReadFail; @@ -3566,7 +4368,18 @@ eReadState StrBufChunkSipLine(StrBuf *LineBuf, IOBuffer *FB) optr --; if ((*(ptr - 1) != '\r') && (*(ptr - 1) != '\n')) { LineBuf->BufUsed = optr - LineBuf->buf; - *optr = '\0'; + *optr = '\0'; + if ((FB->ReadWritePointer != NULL) && + (FB->ReadWritePointer != FB->Buf->buf)) + { + /* Ok, the client application read all the data + it was interested in so far. Since there is more to read, + we now shrink the buffer, and move the rest over. + */ + StrBufCutLeft(FB->Buf, + FB->ReadWritePointer - FB->Buf->buf); + FB->ReadWritePointer = FB->Buf->buf; + } return eMustReadMore; } } @@ -3606,6 +4419,17 @@ eReadState StrBufCheckBuffer(IOBuffer *FB) return eReadSuccess; } +long IOBufferStrLength(IOBuffer *FB) +{ + if ((FB == NULL) || (FB->Buf == NULL)) + return 0; + if (FB->ReadWritePointer == NULL) + return StrLength(FB->Buf); + + return StrLength(FB->Buf) - (FB->ReadWritePointer - FB->Buf->buf); +} + + /******************************************************************************* * File I/O; Prefer buffered read since its faster! * *******************************************************************************/ @@ -3624,6 +4448,11 @@ int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error) { int len, rlen, slen; + if ((buf == NULL) || (buf->buf == NULL)) { + *Error = strerror(EINVAL); + return -1; + } + if (!append) FlushStrBuf(buf); @@ -3653,6 +4482,7 @@ int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error) return len - slen; } + /** * @ingroup StrBuf_BufferedIO * @brief Read a line from socket @@ -3730,10 +4560,11 @@ int StrBufTCP_read_buffered_line(StrBuf *Line, nSuccessLess = 0; buf->BufUsed += rlen; buf->buf[buf->BufUsed] = '\0'; - if (buf->BufUsed + 10 > buf->BufSize) { - IncreaseBuf(buf, 1, -1); - } pch = strchr(buf->buf, '\n'); + if ((pch == NULL) && + (buf->BufUsed + 10 > buf->BufSize) && + (IncreaseBuf(buf, 1, -1) == -1)) + return -1; continue; } @@ -3923,6 +4754,10 @@ int StrBufTCP_read_buffered_line_fast(StrBuf *Line, continue; } + else + { + nSuccessLess++; + } } *Pos = NULL; if (pLF != NULL) { @@ -3959,7 +4794,7 @@ static const char *ErrRBLF_BLOBPreConditionFailed="StrBufReadBLOB: Wrong argumen int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **Error) { int fdflags; - int len, rlen, slen; + int rlen; int nSuccessLess; int nRead = 0; char *ptr; @@ -3967,7 +4802,7 @@ int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **E struct timeval tv; fd_set rfds; - if ((Buf == NULL) || (*fd == -1)) + if ((Buf == NULL) || (Buf->buf == NULL) || (*fd == -1)) { *Error = ErrRBLF_BLOBPreConditionFailed; return -1; @@ -3979,8 +4814,6 @@ int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **E ptr = Buf->buf + Buf->BufUsed; - slen = len = Buf->BufUsed; - fdflags = fcntl(*fd, F_GETFL); IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK; nSuccessLess = 0; @@ -4049,24 +4882,24 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, int check, const char **Error) { - const char *pche; const char *pos; int fdflags; - int len = 0; - int rlen, slen; + int rlen = 0; int nRead = 0; int nAlreadyRead = 0; int IsNonBlock; char *ptr; fd_set rfds; - const char *pch; struct timeval tv; int nSuccessLess = 0; int MaxTries; - if ((Blob == NULL) || (*fd == -1) || (IOBuf == NULL) || (Pos == NULL)) + if ((Blob == NULL) || + (*fd == -1) || + (IOBuf == NULL) || + (Pos == NULL)) { - if (*Pos != NULL) + if (Pos != NULL) *Pos = NULL; *Error = ErrRBB_BLOBFPreConditionFailed; return -1; @@ -4079,18 +4912,14 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, pos = *Pos; - if (pos != NULL) - len = pos - IOBuf->buf; - rlen = IOBuf->BufUsed - len; + if (pos != NULL) { + rlen = pos - IOBuf->buf; + } + rlen = IOBuf->BufUsed - rlen; - if ((IOBuf->BufUsed > 0) && - (pos != NULL) && - (pos < IOBuf->buf + IOBuf->BufUsed)) + if ((IOBuf->BufUsed > 0) && (pos != NULL) && (pos < IOBuf->buf + IOBuf->BufUsed)) { - pche = IOBuf->buf + IOBuf->BufUsed; - pch = pos; - if (rlen < nBytes) { memcpy(Blob->buf + Blob->BufUsed, pos, rlen); Blob->BufUsed += rlen; @@ -4114,12 +4943,11 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, FlushStrBuf(IOBuf); *Pos = NULL; - if (IOBuf->BufSize < nBytes - nRead) + if (IOBuf->BufSize < nBytes - nRead) { IncreaseBuf(IOBuf, 0, nBytes - nRead); + } ptr = IOBuf->buf; - slen = len = Blob->BufUsed; - fdflags = fcntl(*fd, F_GETFL); IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK; if (IsNonBlock) @@ -4129,11 +4957,8 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, nBytes -= nRead; nRead = 0; - while ((nSuccessLess < MaxTries) && - (nRead < nBytes) && - (*fd != -1)) { - if (IsNonBlock) - { + while ((nSuccessLess < MaxTries) && (nRead < nBytes) && (*fd != -1)) { + if (IsNonBlock) { tv.tv_sec = 1; tv.tv_usec = 0; @@ -4143,8 +4968,9 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, *Error = strerror(errno); close (*fd); *fd = -1; - if (*Error == NULL) + if (*Error == NULL) { *Error = ErrRBLF_SelectFailed; + } return -1; } if (! FD_ISSET(*fd, &rfds) != 0) { @@ -4152,20 +4978,16 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, continue; } } - rlen = read(*fd, - ptr, - IOBuf->BufSize - (ptr - IOBuf->buf)); - if (rlen == -1) { + rlen = read(*fd, ptr, IOBuf->BufSize - (ptr - IOBuf->buf)); + // if (rlen == -1) { 2021feb27 ajc changed this, apparently we will always get at least 1 byte unless the connection is broken + if (rlen < 1) { close(*fd); *fd = -1; *Error = strerror(errno); return rlen; } else if (rlen == 0){ - if ((check == NNN_TERM) && - (nRead > 5) && - (strncmp(IOBuf->buf + IOBuf->BufUsed - 5, "\n000\n", 5) == 0)) - { + if ((check == NNN_TERM) && (nRead > 5) && (strncmp(IOBuf->buf + IOBuf->BufUsed - 5, "\n000\n", 5) == 0)) { StrBufPlain(Blob, HKEY("\n000\n")); StrBufCutRight(Blob, 5); return Blob->BufUsed; @@ -4209,14 +5031,18 @@ int StrBufReadBLOBBuffered(StrBuf *Blob, * @param Buf BLOB with lines of text... * @param Ptr moved arround to keep the next-line across several iterations * has to be &NULL on start; will be &NotNULL on end of buffer - * @returns size of copied buffer + * @returns size of remaining buffer */ -int StrBufSipLine(StrBuf *LineBuf, StrBuf *Buf, const char **Ptr) +int StrBufSipLine(StrBuf *LineBuf, const StrBuf *Buf, const char **Ptr) { const char *aptr, *ptr, *eptr; char *optr, *xptr; - if ((Buf == NULL) || (*Ptr == StrBufNOTNULL)) { + if ((Buf == NULL) || + (*Ptr == StrBufNOTNULL) || + (LineBuf == NULL)|| + (LineBuf->buf == NULL)) + { *Ptr = StrBufNOTNULL; return 0; } @@ -4289,12 +5115,54 @@ void StrBufStripSlashes(StrBuf *Dir, int RemoveTrailingSlash) b++; a++; } } - if ((RemoveTrailingSlash) && (*(b - 1) != '/')){ - *b = '/'; - b++; + if ((RemoveTrailingSlash) && + (b > Dir->buf) && + (*(b - 1) == '/')){ + b--; } *b = '\0'; Dir->BufUsed = b - Dir->buf; } +/* + * Decode a quoted-printable encoded StrBuf buffer "in place" + * This is possible because the decoded will always be shorter than the encoded + * so we don't have to worry about the buffer being to small. + */ +void StrBufDecodeQP(StrBuf *Buf) +{ + if (!Buf) { // sanity check #1 + return; + } + + int source_len = StrLength(Buf); + if (source_len < 1) { // sanity check #2 + return; + } + + int spos = 0; // source position + int tpos = 0; // target position + + while (spos < source_len) { + if (!strncmp(&Buf->buf[spos], "=\r\n", 3)) { + spos += 3; + } + else if (!strncmp(&Buf->buf[spos], "=\n", 2)) { + spos += 2; + } + else if (Buf->buf[spos] == '=') { + ++spos; + int ch; + sscanf(&Buf->buf[spos], "%02x", &ch); + Buf->buf[tpos++] = ch; + spos +=2; + } + else { + Buf->buf[tpos++] = Buf->buf[spos++]; + } + } + + Buf->buf[tpos] = 0; + Buf->BufUsed = tpos; +}