+/*
+ * Copyright (c) 1987-2013 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 <ctype.h>
#include <errno.h>
#include <sys/types.h>
#define SHOW_ME_VAPPEND_PRINTF
#include <stdarg.h>
+
#include "libcitadel.h"
+#include "b64/cencode.h"
+#include "b64/cdecode.h"
+
#ifdef HAVE_ICONV
#include <iconv.h>
#endif
#include <execinfo.h>
#endif
+#ifdef UNDEF_MEMCPY
+#undef memcpy
+#endif
+
#ifdef HAVE_ZLIB
#include <zlib.h>
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;
return -1;
if (DestSize > 0)
- while (NewSize <= DestSize)
+ while ((NewSize <= DestSize) && (NewSize != 0))
NewSize *= 2;
+ if (NewSize == 0)
+ return -1;
+
NewBuf= (char*) malloc(NewSize);
if (NewBuf == NULL)
return -1;
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);
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;
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;
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)
{
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);
StrBuf *NewBuf;
NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
+ if (NewBuf == NULL)
+ return NULL;
NewBuf->buf = (char*) StringConstant;
NewBuf->BufSize = SizeOfStrConstant;
NewBuf->BufUsed = SizeOfStrConstant;
*/
int FlushStrBuf(StrBuf *buf)
{
- if (buf == NULL)
+ if ((buf == NULL) || (buf->buf == NULL))
return -1;
if (buf->ConstBuf)
return -1;
*/
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)
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 {
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 {
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;
}
}
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';
*/
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;
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);
+ }
}
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
//cit_backtrace();
//lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
- while ((s<e) && !IsEmptyStr(s)) {
+ while ((s < e) && !IsEmptyStr(s)) {
if (*s == separator) {
++current_token;
}
//cit_backtrace();
//lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
- while ((s<EndBuffer) && !IsEmptyStr(s)) {
+ while ((s < EndBuffer) && !IsEmptyStr(s)) {
if (*s == separator) {
++current_token;
}
/**
* @ingroup StrBuf_DeEnCoder
- * @brief append a string in hex encoding to the buffer
+ * @brief Escape a string for feeding out as a the username/password part of an URL while appending it to a 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)
+void StrBufUrlescUPAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
{
const char *pch, *pche;
char *pt, *pte;
len = In->BufUsed;
}
+ 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 if (*pch < 0x20) {
+ /* we probably shouldn't be doing this */
+ if (OverrideLowChars)
+ {
+ *pt = '_';
+ pt ++;
+ pch ++;
+ }
+ else
+ {
+ *pt = '&';
+ pt++;
+ *pt = HexList[*(unsigned char*)pch][0];
+ pt ++;
+ *pt = HexList[*(unsigned char*)pch][1];
+ pt ++; pch ++;
+ *pt = '&';
+ pt++;
+ pch ++;
+ }
+ }
+ else {
+ IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(pch, pche);
+ if (IsUtf8Sequence)
+ {
+ while (IsUtf8Sequence > 0){
+ *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;
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.
const char *aptr, *eiptr;
char *bptr, *eptr;
long len;
+ int IsUtf8Sequence;
if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
return -1;
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 == '\\') {
+ 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{
- *bptr = *aptr;
- bptr++;
- Target->BufUsed ++;
+ 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 ++;
}
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;
+ break;
+ case '\t':
*bptr = '\\';
bptr ++;
+ *bptr = 't';
+ bptr ++;
Target->BufUsed += 2;
- }
- else {
- if (((unsigned char)*aptr) >= 0x20)
- {
- IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(aptr, eiptr);
-
+ 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 ++;
}
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
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)
if (target != NULL)
FlushStrBuf(target);
- if (source == NULL ||target == NULL)
+ if ((source == NULL) || (target == NULL) || (target->buf == NULL))
{
return;
}
{
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,
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, BufIn->BufUsed, 0);
+
+ 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;
+
+void *StrBufNewStreamContext(eStreamType type)
+{
+ base64_decodestate *state;;
+
+ switch (type)
+ {
+ case eBase64Decode:
+ case eBase64Encode:
+ state = (base64_decodestate*) malloc(sizeof(base64_decodestate));
+ base64_init_decodestate(state);
+ return 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)
+ return NULL;/// tODO cleanup
+ return 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);
+*/
+ err = deflateInit(&stream->zstream,
+ ZLibCompressionRatio);
+
+ if (err != Z_OK)
+ return NULL;/// tODO cleanup
+ return stream;
+ }
+ case eEmtyCodec:
+ /// TODO
+
+ break;
+ }
+ return NULL;
+}
+
+void StrBufDestroyStreamContext(eStreamType type, void **vStream)
+{
+ 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;
+ free(stream->OutBuf.buf);
+ free(stream);
+// todo more?
+ *vStream = NULL;
+ break;
+ }
+ case eEmtyCodec:
+ break; /// TODO
+ }
+}
+
+void StrBufStreamTranscode(eStreamType type, IOBuffer *Target, IOBuffer *In, const char* pIn, long pInLen, void *vStream, int LastChunk)
+{
+
+ switch (type)
+ {
+ case eBase64Encode:
+ {
+ /// TODO
+/*
+ // base64_decodestate *state = (base64_decodestate*)vStream;
+ long ExpectLen;
+
+ if (In != NULL)
+ {
+ pIn = In->buf;
+ pInLen = In->BufUsed;
+ }
+ if ((In == NULL) || (vStream == NULL))
+ return;
+
+ ExpectLen = (pInLen / 4) * 3;
+
+ if (Target->BufSize - Target->BufUsed < ExpectLen)
+ {
+ IncreaseBuf(Target, 1, Target->BufUsed + ExpectLen + 1);
+ }
+
+ //// ExpectLen = base64_encode_block(pIn, pInLen, Target->buf + Target->BufUsed, state);
+ Target->BufUsed += ExpectLen;
+ Target->buf[Target->BufUsed] = '\0';
+*/
+ }
+ break;
+ case eBase64Decode:
+ {
+/*
+ base64_decodestate *state = (base64_decodestate *)vStream;
+ long ExpectLen;
+
+ if (In != NULL)
+ {
+ pIn = In->buf;
+ pInLen = In->BufUsed;
+ }
+ if ((pIn == NULL) || (vStream == NULL))
+ return;
+
+ ExpectLen = (pInLen / 4) * 3;
+
+ if (Target->BufSize - Target->BufUsed < ExpectLen)
+ {
+ IncreaseBuf(Target, 1, Target->BufUsed + ExpectLen + 1);
+ }
+
+ ExpectLen = base64_decode_block(pIn, pInLen, Target->buf + Target->BufUsed, state);
+ Target->BufUsed += ExpectLen;
+ Target->buf[Target->BufUsed] = '\0';
+*/
+ }
+ break;
+ case eZLibEncode:
+ {
+ z_enc_stream *stream = (z_enc_stream *)vStream;
+ int org_outbuf_len = stream->zstream.total_out;
+ 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);
+ /// todo + org_outbuf_len;
+
+ if (Target) SwapBuffers(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 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:
+ fprintf(stderr, "sanoteuh\n");
+ case Z_MEM_ERROR:
+ (void)inflateEnd(&stream->zstream);
+ return err;
+ }
+
+ stream->OutBuf.BufUsed += stream->zstream.total_out + org_outbuf_len;
+
+ if (Target) SwapBuffers(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
+ }
+}
+
/**
* @ingroup StrBuf_DeEnCoder
* @brief decode a buffer from base 64 encoding; destroys original
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);
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++;
}
}
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,
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);
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;
if (EmailEnd == NULL)
EmailEnd = pche;
pch = EmailEnd + 1;
- ColonOk = 1;
}
else {
int gt = 0;
EmailStart ++;
if (UserStart >= UserEnd)
UserStart = UserEnd = NULL;
- At = strchr(EmailStart, '@');
}
else { /* this is a local recipient... no domain, just a realname */
EmailStart = UserStart;
/**
* @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)
return NULL;
if ((Buf->BufUsed - (end - Buf->buf) > 3) &&
- ((*(end + 1) == 'B') || (*(end + 1) == 'Q')) &&
+ (((*(end + 1) == 'B') || (*(end + 1) == 'Q')) ||
+ ((*(end + 1) == 'b') || (*(end + 1) == 'q'))) &&
(*(end + 2) == '?')) {
/* skip on to the end of the cluster, the next ?= */
end = strstr(end + 3, "?=");
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);
#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
* charset to UTF-8 if we see any nonprintable characters.
*/
- len = StrLength(DecodeMe);
for (i=0; i<DecodeMe->BufUsed; ++i) {
if ((DecodeMe->buf[i] < 32) || (DecodeMe->buf[i] > 126)) {
illegal_non_rfc2047_encoding = 1;
}
/* 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)
- end = FindNextEnd (DecodeMee, start);
+ end = FindNextEnd (DecodeMee, start + 2);
else {
StrBufAppendBuf(Target, DecodeMee, 0);
FreeStrBuf(&DecodedInvalidBuf);
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
* @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;
}
static inline int Ctdl_IsUtf8SequenceStart(const char Char)
{
/** 11??.???? indicates an UTF8 Sequence. */
- return ((Char & 0xC0) != 0);
+ return ((Char & 0xC0) == 0xC0);
}
/**
* 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
* @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",
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;
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;
}
}
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);
+}
+
+inline static void FDIOBufferFlush(FDIOBuffer *FDB)
+{
+ memset(FDB, 0, sizeof(FDIOBuffer));
+ FDB->OtherFD = -1;
+ FDB->SplicePipe[0] = -1;
+ FDB->SplicePipe[1] = -1;
+}
+
+void FDIOBufferInit(FDIOBuffer *FDB, IOBuffer *IO, int FD, long TotalSendSize)
+{
+ FDIOBufferFlush(FDB);
+
+ FDB->TotalSendSize = TotalSendSize;
+ if (TotalSendSize > 0)
+ FDB->ChunkSize = TotalSendSize;
+ else
+ {
+ TotalSendSize = SIZ * 10;
+ FDB->ChunkSize = TotalSendSize;
+ }
+ FDB->IOB = IO;
+
+#ifdef LINUX_SPLICE
+ if (EnableSplice)
+ pipe(FDB->SplicePipe);
+ else
+#endif
+ FDB->ChunkBuffer = NewStrBufPlain(NULL, TotalSendSize+ 1);
+
+ FDB->OtherFD = FD;
+}
+
+void FDIOBufferDelete(FDIOBuffer *FDB)
+{
+#ifdef LINUX_SPLICE
+ if (EnableSplice)
+ {
+ if (FDB->SplicePipe[0] > 0)
+ close(FDB->SplicePipe[0]);
+ if (FDB->SplicePipe[1] > 0)
+ close(FDB->SplicePipe[1]);
+ }
+ else
+#endif
+ FreeStrBuf(&FDB->ChunkBuffer);
+
+ if (FDB->OtherFD > 0)
+ close(FDB->OtherFD);
+ FDIOBufferFlush(FDB);
+}
+
+int FileSendChunked(FDIOBuffer *FDB, const char **Err)
+{
+ ssize_t sent, pipesize;
+
+ if (FDB->TotalSendSize > 0)
+ {
+#ifdef LINUX_SPLICE
+ if (EnableSplice)
+ {
+ if (FDB->PipeSize == 0)
+ {
+ pipesize = splice(FDB->OtherFD,
+ &FDB->TotalSentAlready,
+ FDB->SplicePipe[1],
+ NULL,
+ FDB->ChunkSendRemain,
+ SPLICE_F_MOVE);
+
+ if (pipesize == -1)
+ {
+ *Err = strerror(errno);
+ return pipesize;
+ }
+ FDB->PipeSize = pipesize;
+ }
+ sent = splice(FDB->SplicePipe[0],
+ NULL,
+ FDB->IOB->fd,
+ NULL,
+ FDB->PipeSize,
+ SPLICE_F_MORE | SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
+ if (sent == -1)
+ {
+ *Err = strerror(errno);
+ return sent;
+ }
+ FDB->PipeSize -= sent;
+ FDB->ChunkSendRemain -= sent;
+ return sent;
+ }
+ else
+#endif
+ {
+ char *pRead;
+ long nRead = 0;
+
+ pRead = FDB->ChunkBuffer->buf;
+ while ((FDB->ChunkBuffer->BufUsed < FDB->TotalSendSize) && (nRead >= 0))
+ {
+ nRead = read(FDB->OtherFD, pRead, FDB->TotalSendSize - FDB->ChunkBuffer->BufUsed);
+ if (nRead > 0) {
+ FDB->ChunkBuffer->BufUsed += nRead;
+ FDB->ChunkBuffer->buf[FDB->ChunkBuffer->BufUsed] = '\0';
+ }
+ else if (nRead == 0) {}
+ else return nRead;
+ }
+
+ nRead = write(FDB->IOB->fd,
+ FDB->ChunkBuffer->buf + FDB->TotalSentAlready,
+ FDB->ChunkBuffer->BufUsed - FDB->TotalSentAlready);
+
+ if (nRead >= 0) {
+ FDB->TotalSentAlready += nRead;
+ FDB->ChunkSendRemain -= nRead;
+ return FDB->ChunkSendRemain;
+ }
+ else {
+ return nRead;
+ }
+ }
+ }
+ else
+ {
+#ifdef LINUX_SPLICE
+ if (EnableSplice)
+ {
+ if (FDB->PipeSize == 0)
+ {
+ pipesize = splice(FDB->OtherFD,
+ &FDB->TotalSentAlready,
+ FDB->SplicePipe[1],
+ NULL,
+ SIZ * 10,
+ SPLICE_F_MOVE);
+
+ if (pipesize == -1)
+ {
+ *Err = strerror(errno);
+ return pipesize;
+ }
+ FDB->PipeSize = pipesize;
+ if (pipesize == 0)
+ return -1;
+ }
+ sent = splice(FDB->SplicePipe[0],
+ NULL,
+ FDB->IOB->fd,
+ NULL,
+ FDB->PipeSize,
+ SPLICE_F_MORE | SPLICE_F_MOVE | SPLICE_F_NONBLOCK);
+ if (sent == -1)
+ {
+ *Err = strerror(errno);
+ return sent;
+ }
+ FDB->PipeSize -= sent;
+ FDB->ChunkSendRemain -= sent;
+ return sent;
+ }
+ else
+#endif
+ {
+ char *pRead;
+ long nRead = 0;
+
+ pRead = FDB->ChunkBuffer->buf;
+ while ((FDB->ChunkSendRemain == 0) &&
+ (FDB->ChunkBuffer->BufUsed < FDB->ChunkBuffer->BufSize) &&
+ (nRead >= 0))
+ {
+ FDB->TotalSentAlready = 0;
+ nRead = read(FDB->OtherFD, pRead, FDB->ChunkBuffer->BufSize - FDB->ChunkBuffer->BufUsed);
+ if (nRead > 0) {
+ FDB->ChunkBuffer->BufUsed += nRead;
+ FDB->ChunkBuffer->buf[FDB->ChunkBuffer->BufUsed] = '\0';
+ FDB->ChunkSendRemain += nRead;
+ }
+ else if (nRead == 0)
+ {
+ return -1;
+ }
+ else
+ {
+ *Err = strerror(errno);
+ return nRead;
+ }
+ }
+
+ nRead = write(FDB->IOB->fd,
+ FDB->ChunkBuffer->buf + FDB->TotalSentAlready,
+ FDB->ChunkBuffer->BufUsed - FDB->TotalSentAlready);
+
+ if (nRead >= 0) {
+ FDB->TotalSentAlready += nRead;
+ FDB->ChunkSendRemain -= nRead;
+ if (FDB->ChunkSendRemain == 0)
+ {
+ FDB->ChunkBuffer->BufUsed = 0;
+ FDB->TotalSentAlready = 0;
+ }
+ return FDB->ChunkSendRemain;
+ }
+ else {
+ return nRead;
+ }
+ }
+ }
+}
+
+int FileRecvChunked(FDIOBuffer *FDB, const char **Err)
+{
+ ssize_t sent, pipesize;
+
+#ifdef LINUX_SPLICE
+ if (EnableSplice)
+ {
+ if (FDB->PipeSize == 0)
+ {
+ pipesize = splice(FDB->IOB->fd,
+ NULL,
+ FDB->SplicePipe[1],
+ NULL,
+ FDB->ChunkSendRemain,
+ SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
+
+ if (pipesize == -1)
+ {
+ *Err = strerror(errno);
+ return pipesize;
+ }
+ FDB->PipeSize = pipesize;
+ }
+
+ sent = splice(FDB->SplicePipe[0],
+ NULL,
+ FDB->OtherFD,
+ &FDB->TotalSentAlready,
+ FDB->PipeSize,
+ SPLICE_F_MORE | SPLICE_F_MOVE);
+
+ if (sent == -1)
+ {
+ *Err = strerror(errno);
+ return sent;
+ }
+ FDB->PipeSize -= sent;
+ FDB->ChunkSendRemain -= sent;
+ return sent;
+ }
+ else
+#endif
+ {
+ sent = read(FDB->IOB->fd, FDB->ChunkBuffer->buf, FDB->ChunkSendRemain);
+ if (sent > 0) {
+ int nWritten = 0;
+ int rc;
+
+ FDB->ChunkBuffer->BufUsed = sent;
+
+ while (nWritten < FDB->ChunkBuffer->BufUsed) {
+ rc = write(FDB->OtherFD, FDB->ChunkBuffer->buf + nWritten, FDB->ChunkBuffer->BufUsed - nWritten);
+ if (rc < 0) {
+ *Err = strerror(errno);
+ return rc;
+ }
+ nWritten += rc;
+
+ }
+ FDB->ChunkBuffer->BufUsed = 0;
+ FDB->TotalSentAlready += sent;
+ FDB->ChunkSendRemain -= sent;
+ return FDB->ChunkSendRemain;
+ }
+ else if (sent < 0) {
+ *Err = strerror(errno);
+ return sent;
+ }
+ return 0;
+ }
+}
+
+int FileMoveChunked(FDIOBuffer *FDB, const char **Err)
+{
+ ssize_t sent, pipesize;
+
+#ifdef LINUX_SPLICE
+ if (EnableSplice)
+ {
+ if (FDB->PipeSize == 0)
+ {
+ pipesize = splice(FDB->IOB->fd,
+ &FDB->TotalReadAlready,
+ FDB->SplicePipe[1],
+ NULL,
+ FDB->ChunkSendRemain,
+ SPLICE_F_MORE | SPLICE_F_MOVE|SPLICE_F_NONBLOCK);
+
+ if (pipesize == -1)
+ {
+ *Err = strerror(errno);
+ return pipesize;
+ }
+ FDB->PipeSize = pipesize;
+ }
+
+ sent = splice(FDB->SplicePipe[0],
+ NULL,
+ FDB->OtherFD,
+ &FDB->TotalSentAlready,
+ FDB->PipeSize,
+ SPLICE_F_MORE | SPLICE_F_MOVE);
+
+ if (sent == -1)
+ {
+ *Err = strerror(errno);
+ return sent;
+ }
+ FDB->PipeSize -= sent;
+ FDB->ChunkSendRemain -= sent;
+ return sent;
+ }
+ else
+#endif
+ {
+ sent = read(FDB->IOB->fd, FDB->ChunkBuffer->buf, FDB->ChunkSendRemain);
+ if (sent > 0) {
+ int nWritten = 0;
+ int rc;
+
+ FDB->ChunkBuffer->BufUsed = sent;
+
+ while (nWritten < FDB->ChunkBuffer->BufUsed) {
+ rc = write(FDB->OtherFD, FDB->ChunkBuffer->buf + nWritten, FDB->ChunkBuffer->BufUsed - nWritten);
+ if (rc < 0) {
+ *Err = strerror(errno);
+ return rc;
+ }
+ nWritten += rc;
+
+ }
+ FDB->ChunkBuffer->BufUsed = 0;
+ FDB->TotalSentAlready += sent;
+ FDB->ChunkSendRemain -= sent;
+ return FDB->ChunkSendRemain;
+ }
+ else if (sent < 0) {
+ *Err = strerror(errno);
+ return sent;
+ }
+ return 0;
+ }
+}
+
+eReadState WriteIOBAlreadyRead(FDIOBuffer *FDB, const char **Error)
+{
+ int IsNonBlock;
+ int fdflags;
+ long rlen;
+ long should_write;
+ int nSuccessLess = 0;
+ struct timeval tv;
+ fd_set rfds;
+
+ fdflags = fcntl(FDB->OtherFD, F_GETFL);
+ IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
+
+ while ((FDB->IOB->ReadWritePointer - FDB->IOB->Buf->buf < FDB->IOB->Buf->BufUsed) &&
+ (FDB->ChunkSendRemain > 0))
+ {
+ if (IsNonBlock){
+ tv.tv_sec = 1; /* selectresolution; */
+ tv.tv_usec = 0;
+
+ FD_ZERO(&rfds);
+ FD_SET(FDB->OtherFD, &rfds);
+ if (select(FDB->OtherFD + 1, NULL, &rfds, NULL, &tv) == -1) {
+ *Error = strerror(errno);
+ return eReadFail;
+ }
+ }
+ if (IsNonBlock && ! FD_ISSET(FDB->OtherFD, &rfds)) {
+ nSuccessLess ++;
+ continue;
+ }
+
+ should_write = FDB->IOB->Buf->BufUsed -
+ (FDB->IOB->ReadWritePointer - FDB->IOB->Buf->buf);
+ if (should_write > FDB->ChunkSendRemain)
+ should_write = FDB->ChunkSendRemain;
+
+ rlen = write(FDB->OtherFD,
+ FDB->IOB->ReadWritePointer,
+ should_write);
+ if (rlen < 1) {
+ *Error = strerror(errno);
+
+ return eReadFail;
+ }
+ FDB->TotalSentAlready += rlen;
+ FDB->IOB->ReadWritePointer += rlen;
+ FDB->ChunkSendRemain -= rlen;
+ }
+ if (FDB->IOB->ReadWritePointer >= FDB->IOB->Buf->buf + FDB->IOB->Buf->BufUsed)
+ {
+ FlushStrBuf(FDB->IOB->Buf);
+ FDB->IOB->ReadWritePointer = NULL;
+ }
+
+ if (FDB->ChunkSendRemain == 0)
+ return eReadSuccess;
+ else
+ return eMustReadMore;
+}
+
/*******************************************************************************
* File I/O; Prefer buffered read since its faster! *
*******************************************************************************/
{
int len, rlen, slen;
+ if ((buf == NULL) || (buf->buf == NULL)) {
+ *Error = strerror(EINVAL);
+ return -1;
+ }
+
if (!append)
FlushStrBuf(buf);
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;
}
continue;
}
+ else
+ {
+ nSuccessLess++;
+ }
}
*Pos = NULL;
if (pLF != NULL) {
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;
struct timeval tv;
fd_set rfds;
- if ((Buf == NULL) || (*fd == -1))
+ if ((Buf == NULL) || (Buf->buf == NULL) || (*fd == -1))
{
*Error = ErrRBLF_BLOBPreConditionFailed;
return -1;
ptr = Buf->buf + Buf->BufUsed;
- slen = len = Buf->BufUsed;
-
fdflags = fcntl(*fd, F_GETFL);
IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
nSuccessLess = 0;
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;
pos = *Pos;
if (pos != NULL)
- len = pos - IOBuf->buf;
- rlen = IOBuf->BufUsed - len;
+ rlen = pos - IOBuf->buf;
+ rlen = IOBuf->BufUsed - rlen;
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;
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)
* @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;
}
b++; a++;
}
}
- if ((RemoveTrailingSlash) && (*(b - 1) != '/')){
- *b = '/';
- b++;
+ if ((RemoveTrailingSlash) &&
+ (b > Dir->buf) &&
+ (*(b - 1) == '/')){
+ b--;
}
*b = '\0';
Dir->BufUsed = b - Dir->buf;