/**
* @ingroup StrBuf_DeConstructors
- * @brief shrink an _EMPTY_ buffer if its Buffer superseeds threshhold to NewSize. Buffercontent is thoroughly ignored and flushed.
+ * @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 > ThreshHold)) {
+ if ((Buf != NULL) &&
+ (Buf->BufUsed == 0) &&
+ (Buf->BufSize < ThreshHold)) {
free(Buf->buf);
Buf->buf = (char*) malloc(NewSize);
Buf->BufUsed = 0;
*/
int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
{
- size_t Siz = Buf->BufSize;
+ size_t Siz;
size_t CopySize;
+ if (Buf == NULL)
+ return -1;
+ if (ptr == NULL) {
+ FlushStrBuf(Buf);
+ return -1;
+ }
+
+ Siz = Buf->BufSize;
+
if (nChars < 0)
CopySize = strlen(ptr);
else
return 0;
return 0;
}
+
/**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
* @brief modifies a Single char of the Buf
* You can point to it via char* or a zero-based integer
* @param Buf The buffer to manipulate
}
/**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
+ * @brief modifies a range of chars of the Buf
+ * You can point to it via char* or a zero-based integer
+ * @param Buf The buffer to manipulate
+ * @param ptr char* to zero; use NULL if unused
+ * @param nThChar zero based pointer into the string; use -1 if unused
+ * @param nChars how many chars are to be flushed?
+ * @param PookValue The Character to place into that area
+ */
+long StrBufPook(StrBuf *Buf, const char* ptr, long nThChar, long nChars, char PookValue)
+{
+ if (Buf == NULL)
+ return -1;
+ if (ptr != NULL)
+ nThChar = ptr - Buf->buf;
+ if ((nThChar < 0) || (nThChar > Buf->BufUsed))
+ return -1;
+ if (nThChar + nChars > Buf->BufUsed)
+ nChars = Buf->BufUsed - nThChar;
+
+ memset(Buf->buf + nThChar, PookValue, nChars);
+ /* just to be shure... */
+ Buf->buf[Buf->BufUsed] = 0;
+ return nChars;
+}
+
+/**
+ * @ingroup StrBuf_Filler
* @brief Append a StringBuffer to the buffer
* @param Buf Buffer to modify
* @param AppendBuf Buffer to copy at the end of our buffer
/**
- * @ingroup StrBuf
+ * @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
}
/**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
* @brief sprintf like function appending the formated string to the buffer
* vsnprintf version to wrap into own calls
* @param Buf Buffer to extend by format and Params
}
/**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
* @brief sprintf like function appending the formated string to the buffer
* @param Buf Buffer to extend by format and Params
* @param format printf alike format to add
}
/**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
* @brief sprintf like function putting the formated string into the buffer
* @param Buf Buffer to extend by format and Parameters
* @param format printf alike format to add
}
/**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
* @brief Callback for cURL to append the webserver reply to a buffer
* @param ptr pre-defined by the cURL API; see man 3 curl for mre info
* @param size pre-defined by the cURL API; see man 3 curl for mre info
size_t NCharsRemain;
if (Offset > Source->BufUsed)
{
- FlushStrBuf(dest);
+ if (dest != NULL)
+ FlushStrBuf(dest);
return 0;
}
if (Offset + nChars < Source->BufUsed)
int delta = 0;
if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
+ while ((Buf->BufUsed > 0) &&
+ isspace(Buf->buf[Buf->BufUsed - 1]))
+ {
+ Buf->BufUsed --;
+ }
+ Buf->buf[Buf->BufUsed] = '\0';
+
+ if (Buf->BufUsed == 0) return;
+
while ((Buf->BufUsed > delta) && (isspace(Buf->buf[delta]))){
delta ++;
}
if (delta > 0) StrBufCutLeft(Buf, delta);
+}
- if (Buf->BufUsed == 0) return;
- while (isspace(Buf->buf[Buf->BufUsed - 1])){
- Buf->BufUsed --;
+void StrBufStripAllBut(StrBuf *Buf, char leftboundary, char rightboundary)
+{
+ const char *pBuff;
+ const char *pLeft;
+ const char *pRight;
+
+ if (Buf == NULL)
+ return;
+ pLeft = pBuff = Buf->buf;
+ while (pBuff != NULL) {
+ pLeft = pBuff;
+ pBuff = strchr(pBuff, leftboundary);
+ if (pBuff != NULL)
+ pBuff++;
}
- Buf->buf[Buf->BufUsed] = '\0';
+
+ if (pLeft != NULL)
+ pBuff = pLeft;
+ else
+ pBuff = Buf->buf;
+ pRight = strchr(pBuff, rightboundary);
+ if (pRight != NULL)
+ StrBufCutAt(Buf, 0, pRight);
+ if (pLeft != NULL)
+ StrBufCutLeft(Buf, pLeft - Buf->buf);
}
+
/**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
* @brief uppercase the contents of a buffer
* @param Buf the buffer to translate
*/
/**
- * @ingroup StrBuf
+ * @ingroup StrBuf_Filler
* @brief lowercase the contents of a buffer
* @param Buf the buffer to translate
*/
* a tokenizer that kills, maims, and destroys *
*******************************************************************************/
+/**
+ * @ingroup StrBuf_Tokenizer
+ * @brief Replace a token at a given place with a given length by another token with given length
+ * @param Buf String where to work on
+ * @param where where inside of the Buf is the search-token
+ * @param HowLong How long is the token to be replaced
+ * @param Repl Token to insert at 'where'
+ * @param ReplLen Length of repl
+ * @returns -1 if fail else length of resulting Buf
+ */
+int StrBufReplaceToken(StrBuf *Buf, long where, long HowLong,
+ const char *Repl, long ReplLen)
+{
+
+ if ((Buf == NULL) ||
+ (where > Buf->BufUsed) ||
+ (where + HowLong > Buf->BufUsed))
+ return -1;
+
+ if (where + ReplLen - HowLong > Buf->BufSize)
+ if (IncreaseBuf(Buf, 1, Buf->BufUsed + ReplLen) < 0)
+ return -1;
+
+ memmove(Buf->buf + where + ReplLen,
+ Buf->buf + where + HowLong,
+ Buf->BufUsed - where - HowLong);
+
+ memcpy(Buf->buf + where,
+ Repl, ReplLen);
+
+ Buf->BufUsed += ReplLen - HowLong;
+
+ return Buf->BufUsed;
+}
+
/**
* @ingroup StrBuf_Tokenizer
* @brief Counts the numbmer of tokens in a buffer
(*pch >= '@' && *pch <= 'Z') || /* @ A-Z */
(*pch >= '0' && *pch <= ':') || /* 0-9 : */
(*pch == '!') || (*pch == '_') ||
- (*pch == ',') || (*pch == '.') ||
- (*pch == ','))
+ (*pch == ',') || (*pch == '.'))
{
*(pt++) = *(pch++);
OutBuf->BufUsed++;
if (Buf == NULL) return -1;
xferbuf = (char*) malloc(Buf->BufSize);
+ *xferbuf = '\0';
siz = CtdlDecodeBase64(xferbuf,
Buf->buf,
Buf->BufUsed);
return (*target)->BufUsed;;
}
+
+
+static void AddRecipient(StrBuf *Target,
+ StrBuf *UserName,
+ StrBuf *EmailAddress,
+ StrBuf *EncBuf)
+{
+ int QuoteMe = 0;
+
+ if (StrLength(Target) > 0) StrBufAppendBufPlain(Target, HKEY(", "), 0);
+ if (strchr(ChrPtr(UserName), ',') != NULL) QuoteMe = 1;
+
+ if (QuoteMe) StrBufAppendBufPlain(Target, HKEY("\""), 0);
+ StrBufRFC2047encode(&EncBuf, UserName);
+ StrBufAppendBuf(Target, EncBuf, 0);
+ if (QuoteMe) StrBufAppendBufPlain(Target, HKEY("\" "), 0);
+ else StrBufAppendBufPlain(Target, HKEY(" "), 0);
+
+ if (StrLength(EmailAddress) > 0){
+ StrBufAppendBufPlain(Target, HKEY("<"), 0);
+ StrBufAppendBuf(Target, EmailAddress, 0); /* TODO: what about IDN???? */
+ StrBufAppendBufPlain(Target, HKEY(">"), 0);
+ }
+}
+
+
+/**
+ * \brief QP encode parts of an email TO/CC/BCC vector, and strip/filter invalid parts
+ * \param Recp Source list of email recipients
+ * \param UserName Temporary buffer for internal use; Please provide valid buffer.
+ * \param EmailAddress Temporary buffer for internal use; Please provide valid buffer.
+ * \param EncBuf Temporary buffer for internal use; Please provide valid buffer.
+ * \returns encoded & sanitized buffer with the contents of Recp; Caller owns this memory.
+ */
+StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp,
+ StrBuf *UserName,
+ StrBuf *EmailAddress,
+ 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);
+
+ if (!CheckEncode(pch, -1, pche))
+ return NewStrBufDup(Recp);
+
+ Target = NewStrBufPlain(NULL, StrLength(Recp));
+
+ while ((pch != NULL) && (pch < pche))
+ {
+ int ColonOk = 0;
+
+ while (isspace(*pch)) pch++;
+ UserStart = UserEnd = EmailStart = EmailEnd = NULL;
+
+ if ((*pch == '"') || (*pch == '\'')) {
+ UserStart = pch + 1;
+
+ UserEnd = strchr(UserStart, *pch);
+ if (UserEnd == NULL)
+ break; ///TODO: Userfeedback??
+ EmailStart = UserEnd + 1;
+ while (isspace(*EmailStart))
+ EmailStart++;
+ if (UserEnd == UserStart) {
+ UserStart = UserEnd = NULL;
+ }
+
+ if (*EmailStart == '<') {
+ EmailStart++;
+ EmailEnd = strchr(EmailStart, '>');
+ if (EmailEnd == NULL)
+ EmailEnd = strchr(EmailStart, ',');
+
+ }
+ else {
+ EmailEnd = strchr(EmailStart, ',');
+ }
+ if (EmailEnd == NULL)
+ EmailEnd = pche;
+ pch = EmailEnd + 1;
+ ColonOk = 1;
+ }
+ else {
+ int gt = 0;
+ UserStart = pch;
+ EmailEnd = strchr(UserStart, ',');
+ if (EmailEnd == NULL) {
+ EmailEnd = strchr(pch, '>');
+ pch = NULL;
+ if (EmailEnd != NULL) {
+ gt = 1;
+ EmailEnd --;
+ }
+ else {
+ EmailEnd = pche;
+ }
+ }
+ else {
+
+ pch = EmailEnd + 1;
+ while ((EmailEnd > UserStart) && !gt &&
+ ((*EmailEnd == ',') ||
+ (*EmailEnd == '>') ||
+ (isspace(*EmailEnd))))
+ {
+ if (*EmailEnd == '>')
+ gt = 1;
+ else
+ EmailEnd--;
+ }
+ if (EmailEnd == UserStart)
+ break;
+ }
+ if (gt) {
+ EmailStart = strchr(UserStart, '<');
+ if ((EmailStart == NULL) || (EmailStart > EmailEnd))
+ break;
+ UserEnd = EmailStart - 1;
+ EmailStart ++;
+ if (UserStart >= UserEnd)
+ UserStart = UserEnd = NULL;
+ At = strchr(EmailStart, '@');
+ }
+ else { /* this is a local recipient... no domain, just a realname */
+ EmailStart = UserStart;
+ At = strchr(EmailStart, '@');
+ if (At == NULL) {
+ UserEnd = EmailEnd;
+ EmailEnd = NULL;
+ }
+ else {
+ EmailStart = UserStart;
+ UserStart = NULL;
+ }
+ }
+ }
+
+ if ((UserStart != NULL) && (UserEnd != NULL))
+ StrBufPlain(UserName, UserStart, UserEnd - UserStart);
+ else if ((UserStart != NULL) && (UserEnd == NULL))
+ StrBufPlain(UserName, UserStart, UserEnd - UserStart);
+ else
+ FlushStrBuf(UserName);
+
+ if ((EmailStart != NULL) && (EmailEnd != NULL))
+ StrBufPlain(EmailAddress, EmailStart, EmailEnd - EmailStart);
+ else if ((EmailStart != NULL) && (EmailEnd == NULL))
+ StrBufPlain(EmailAddress, EmailStart, EmailEnd - pche);
+ else
+ FlushStrBuf(EmailAddress);
+
+ AddRecipient(Target, UserName, EmailAddress, EncBuf);
+
+ if (pch == NULL)
+ break;
+
+ if ((pch != NULL) && (*pch == ','))
+ pch ++;
+ if (pch != NULL) while (isspace(*pch))
+ pch ++;
+ }
+ return Target;
+}
+
+
/**
* @ingroup StrBuf
* @brief replaces all occurances of 'search' by 'replace'
}
+/**
+ * @ingroup StrBuf
+ * @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)
+{
+ char *pche, *pchS, *pchT;
+ if (buf == NULL)
+ return;
+
+ pche = buf->buf + buf->BufUsed;
+ pchS = pchT = buf->buf;
+ while (pchS < pche)
+ {
+ if (*pchS == '\r')
+ {
+ pchS ++;
+ if (*pchS != '\n') {
+ *pchT = '\n';
+ pchT++;
+ }
+ }
+ *pchT = *pchS;
+ pchT++; pchS++;
+ }
+ *pchT = '\0';
+ buf->BufUsed = pchT - buf->buf;
+}
+
/*******************************************************************************
* Iconv Wrapper; RFC822 de/encoding *
if (IOBuf->BufUsed + 10 > IOBuf->BufSize)
{
- long apos;
+ long apos = 0;
if (pLF != NULL) apos = pLF - IOBuf->buf;
IncreaseBuf(IOBuf, 1, -1);
}
const char *ErrRBB_BLOBFPreConditionFailed = "StrBufReadBLOBBuffered: to many selects; aborting.";
-const char *ErrRBB_too_many_selects = "StrBufReadBLOBBuffered: to many selects; aborting.";
+const char *ErrRBB_too_many_selects = "StrBufReadBLOBBuffered: to many selects; aborting.";
/**
* @ingroup StrBuf_BufferedIO
* @brief Input binary data from socket
{
const char *pche;
const char *pos;
- int nSelects = 0;
- int SelRes;
int fdflags;
int len = 0;
int rlen, slen;
fd_set rfds;
const char *pch;
struct timeval tv;
- int nSuccessLess;
+ int nSuccessLess = 0;
+ int MaxTries;
if ((Blob == NULL) || (*fd == -1) || (IOBuf == NULL) || (Pos == NULL))
{
pos = *Pos;
- if (pos > 0)
+ if (pos != NULL)
len = pos - IOBuf->buf;
rlen = IOBuf->BufUsed - len;
fdflags = fcntl(*fd, F_GETFL);
IsNonBlock = (fdflags & O_NONBLOCK) == O_NONBLOCK;
+ if (IsNonBlock)
+ MaxTries = 1000;
+ else
+ MaxTries = 100000;
- SelRes = 1;
nBytes -= nRead;
nRead = 0;
- while ((nRead < nBytes) &&
+ while ((nSuccessLess < MaxTries) &&
+ (nRead < nBytes) &&
(*fd != -1)) {
if (IsNonBlock)
{
continue;
}
}
- nSuccessLess = 0;
rlen = read(*fd,
ptr,
- nBytes - nRead);
+ IOBuf->BufSize - (ptr - IOBuf->buf));
if (rlen == -1) {
close(*fd);
*fd = -1;
return rlen;
}
else if (rlen == 0){
- nSuccessLess ++;
if ((check == NNN_TERM) &&
(nRead > 5) &&
(strncmp(IOBuf->buf + IOBuf->BufUsed - 5, "\n000\n", 5) == 0))
StrBufCutRight(Blob, 5);
return Blob->BufUsed;
}
- if (nSelects > 10) {
+ else if (!IsNonBlock)
+ nSuccessLess ++;
+ else if (nSuccessLess > MaxTries) {
FlushStrBuf(IOBuf);
*Error = ErrRBB_too_many_selects;
return -1;
}
}
else if (rlen > 0) {
+ nSuccessLess = 0;
nRead += rlen;
ptr += rlen;
IOBuf->BufUsed += rlen;
}
}
+ if (nSuccessLess >= MaxTries) {
+ FlushStrBuf(IOBuf);
+ *Error = ErrRBB_too_many_selects;
+ return -1;
+ }
+
if (nRead > nBytes) {
*Pos = IOBuf->buf + nBytes;
}