2 * Copyright (c) 1987-2013 by the citadel.org team
4 * This program is open source software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sys/select.h>
29 #include <sys/types.h>
30 #define SHOW_ME_VAPPEND_PRINTF
33 #include "libcitadel.h"
35 #include "b64/cencode.h"
36 #include "b64/cdecode.h"
52 int ZEXPORT compress_gzip(Bytef * dest, size_t * destLen,
53 const Bytef * source, uLong sourceLen, int level);
55 int BaseStrBufSize = 64;
58 const char *StrBufNOTNULL = ((char*) NULL) - 1;
60 const char HexList[256][3] = {
61 "00","01","02","03","04","05","06","07","08","09","0A","0B","0C","0D","0E","0F",
62 "10","11","12","13","14","15","16","17","18","19","1A","1B","1C","1D","1E","1F",
63 "20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F",
64 "30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3D","3E","3F",
65 "40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F",
66 "50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F",
67 "60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F",
68 "70","71","72","73","74","75","76","77","78","79","7A","7B","7C","7D","7E","7F",
69 "80","81","82","83","84","85","86","87","88","89","8A","8B","8C","8D","8E","8F",
70 "90","91","92","93","94","95","96","97","98","99","9A","9B","9C","9D","9E","9F",
71 "A0","A1","A2","A3","A4","A5","A6","A7","A8","A9","AA","AB","AC","AD","AE","AF",
72 "B0","B1","B2","B3","B4","B5","B6","B7","B8","B9","BA","BB","BC","BD","BE","BF",
73 "C0","C1","C2","C3","C4","C5","C6","C7","C8","C9","CA","CB","CC","CD","CE","CF",
74 "D0","D1","D2","D3","D4","D5","D6","D7","D8","D9","DA","DB","DC","DD","DE","DF",
75 "E0","E1","E2","E3","E4","E5","E6","E7","E8","E9","EA","EB","EC","ED","EE","EF",
76 "F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB","FC","FD","FE","FF"};
79 * @defgroup StrBuf Stringbuffer, A class for manipulating strings with dynamic buffers
80 * StrBuf is a versatile class, aiding the handling of dynamic strings
81 * * reduce de/reallocations
82 * * reduce the need to remeasure it
83 * * reduce scanning over the string (in @ref StrBuf_NextTokenizer "Tokenizers")
84 * * allow asyncroneous IO for line and Blob based operations
85 * * reduce the use of memove in those
86 * * Quick filling in several operations with append functions
90 * @defgroup StrBuf_DeConstructors Create/Destroy StrBufs
95 * @defgroup StrBuf_Cast Cast operators to interact with char* based code
97 * use these operators to interfere with code demanding char*;
98 * if you need to own the content, smash me. Avoid, since we loose the length information.
102 * @defgroup StrBuf_Filler Create/Replace/Append Content into a StrBuf
104 * operations to get your Strings into a StrBuf, manipulating them, or appending
107 * @defgroup StrBuf_NextTokenizer Fast tokenizer to pull tokens in sequence
109 * Quick tokenizer; demands of the user to pull its tokens in sequence
113 * @defgroup StrBuf_Tokenizer tokenizer Functions; Slow ones.
115 * versatile tokenizer; random access to tokens, but slower; Prefer the @ref StrBuf_NextTokenizer "Next Tokenizer"
119 * @defgroup StrBuf_BufferedIO Buffered IO with Asynchroneous reads and no unneeded memmoves (the fast ones)
121 * File IO to fill StrBufs; Works with work-buffer shared across several calls;
122 * External Cursor to maintain the current read position inside of the buffer
123 * the non-fast ones will use memove to keep the start of the buffer the read buffer (which is slower)
127 * @defgroup StrBuf_IO FileIO; Prefer @ref StrBuf_BufferedIO
133 * @defgroup StrBuf_DeEnCoder functions to translate the contents of a buffer
135 * these functions translate the content of a buffer into another representation;
136 * some are combined Fillers and encoders
140 * Private Structure for the Stringbuffer
143 char *buf; /**< the pointer to the dynamic buffer */
144 long BufSize; /**< how many spcae do we optain */
145 long BufUsed; /**< StNumber of Chars used excluding the trailing \\0 */
146 int ConstBuf; /**< are we just a wrapper arround a static buffer and musn't we be changed? */
148 long nIncreases; /**< for profiling; cound how many times we needed more */
149 char bt [SIZ]; /**< Stacktrace of last increase */
150 char bt_lastinc [SIZ]; /**< How much did we increase last time? */
155 static inline int Ctdl_GetUtf8SequenceLength(const char *CharS, const char *CharE);
156 static inline int Ctdl_IsUtf8SequenceStart(const char Char);
159 #ifdef HAVE_BACKTRACE
160 static void StrBufBacktrace(StrBuf *Buf, int which)
164 void *stack_frames[50];
169 pstart = pch = Buf->bt;
171 pstart = pch = Buf->bt_lastinc;
172 size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
173 strings = backtrace_symbols(stack_frames, size);
174 for (i = 0; i < size; i++) {
176 n = snprintf(pch, SIZ - (pch - pstart), "%s\\n", strings[i]);
178 n = snprintf(pch, SIZ - (pch - pstart), "%p\\n", stack_frames[i]);
187 void dbg_FreeStrBuf(StrBuf *FreeMe, char *FromWhere)
189 if (hFreeDbglog == -1){
190 pid_t pid = getpid();
192 snprintf(path, SIZ, "/tmp/libcitadel_strbuf_realloc.log.%d", pid);
193 hFreeDbglog = open(path, O_APPEND|O_CREAT|O_WRONLY);
195 if ((*FreeMe)->nIncreases > 0)
199 n = snprintf(buf, SIZ * 3, "%c+|%ld|%ld|%ld|%s|%s|\n",
201 (*FreeMe)->nIncreases,
205 (*FreeMe)->bt_lastinc);
206 n = write(hFreeDbglog, buf, n);
212 n = snprintf(buf, 128, "%c_|0|%ld%ld|\n",
216 n = write(hFreeDbglog, buf, n);
220 void dbg_IncreaseBuf(StrBuf *IncMe)
223 #ifdef HAVE_BACKTRACE
224 StrBufBacktrace(Buf, 1);
228 void dbg_Init(StrBuf *Buf)
232 Buf->bt_lastinc[0] = '\0';
233 #ifdef HAVE_BACKTRACE
234 StrBufBacktrace(Buf, 0);
240 #define dbg_FreeStrBuf(a, b)
241 #define dbg_IncreaseBuf(a)
248 * @brief swaps the contents of two StrBufs
249 * this is to be used to have cheap switched between a work-buffer and a target buffer
251 * @param B second one
253 static inline void SwapBuffers(StrBuf *A, StrBuf *B)
257 memcpy(&C, A, sizeof(*A));
258 memcpy(A, B, sizeof(*B));
259 memcpy(B, &C, sizeof(C));
264 * @ingroup StrBuf_Cast
265 * @brief Cast operator to Plain String
266 * @note if the buffer is altered by StrBuf operations, this pointer may become
267 * invalid. So don't lean on it after altering the buffer!
268 * Since this operation is considered cheap, rather call it often than risking
269 * your pointer to become invalid!
270 * @param Str the string we want to get the c-string representation for
271 * @returns the Pointer to the Content. Don't mess with it!
273 inline const char *ChrPtr(const StrBuf *Str)
281 * @ingroup StrBuf_Cast
282 * @brief since we know strlen()'s result, provide it here.
283 * @param Str the string to return the length to
284 * @returns contentlength of the buffer
286 inline int StrLength(const StrBuf *Str)
288 return (Str != NULL) ? Str->BufUsed : 0;
292 * @ingroup StrBuf_DeConstructors
293 * @brief local utility function to resize the buffer
294 * @param Buf the buffer whichs storage we should increase
295 * @param KeepOriginal should we copy the original buffer or just start over with a new one
296 * @param DestSize what should fit in after?
298 static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
301 size_t NewSize = Buf->BufSize * 2;
307 while ((NewSize <= DestSize) && (NewSize != 0))
313 NewBuf= (char*) malloc(NewSize);
317 if (KeepOriginal && (Buf->BufUsed > 0))
319 memcpy(NewBuf, Buf->buf, Buf->BufUsed);
328 Buf->BufSize = NewSize;
330 dbg_IncreaseBuf(Buf);
336 * @ingroup StrBuf_DeConstructors
337 * @brief shrink / increase an _EMPTY_ buffer to NewSize. Buffercontent is thoroughly ignored and flushed.
338 * @param Buf Buffer to shrink (has to be empty)
339 * @param ThreshHold if the buffer is bigger then this, its readjusted
340 * @param NewSize if we Shrink it, how big are we going to be afterwards?
342 void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize)
345 (Buf->BufUsed == 0) &&
346 (Buf->BufSize < ThreshHold)) {
348 Buf->buf = (char*) malloc(NewSize);
350 Buf->BufSize = NewSize;
355 * @ingroup StrBuf_DeConstructors
356 * @brief shrink long term buffers to their real size so they don't waste memory
357 * @param Buf buffer to shrink
358 * @param Force if not set, will just executed if the buffer is much to big; set for lifetime strings
359 * @returns physical size of the buffer
361 long StrBufShrinkToFit(StrBuf *Buf, int Force)
366 (Buf->BufUsed + (Buf->BufUsed / 3) > Buf->BufSize))
370 TmpBuf = (char*) malloc(Buf->BufUsed + 1);
374 memcpy (TmpBuf, Buf->buf, Buf->BufUsed + 1);
375 Buf->BufSize = Buf->BufUsed + 1;
383 * @ingroup StrBuf_DeConstructors
384 * @brief Allocate a new buffer with default buffer size
385 * @returns the new stringbuffer
387 StrBuf* NewStrBuf(void)
391 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
395 NewBuf->buf = (char*) malloc(BaseStrBufSize);
396 if (NewBuf->buf == NULL)
401 NewBuf->buf[0] = '\0';
402 NewBuf->BufSize = BaseStrBufSize;
404 NewBuf->ConstBuf = 0;
412 * @ingroup StrBuf_DeConstructors
413 * @brief Copy Constructor; returns a duplicate of CopyMe
414 * @param CopyMe Buffer to faxmilate
415 * @returns the new stringbuffer
417 StrBuf* NewStrBufDup(const StrBuf *CopyMe)
424 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
428 NewBuf->buf = (char*) malloc(CopyMe->BufSize);
429 if (NewBuf->buf == NULL)
435 memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1);
436 NewBuf->BufUsed = CopyMe->BufUsed;
437 NewBuf->BufSize = CopyMe->BufSize;
438 NewBuf->ConstBuf = 0;
446 * @ingroup StrBuf_DeConstructors
447 * @brief Copy Constructor; CreateRelpaceMe will contain CopyFlushMe afterwards.
448 * @param NoMe if non-NULL, we will use that buffer as value; KeepOriginal will abused as len.
449 * @param CopyFlushMe Buffer to faxmilate if KeepOriginal, or to move into CreateRelpaceMe if !KeepOriginal.
450 * @param CreateRelpaceMe If NULL, will be created, else Flushed and filled CopyFlushMe
451 * @param KeepOriginal should CopyFlushMe remain intact? or may we Steal its buffer?
452 * @returns the new stringbuffer
454 void NewStrBufDupAppendFlush(StrBuf **CreateRelpaceMe, StrBuf *CopyFlushMe, const char *NoMe, int KeepOriginal)
458 if (CreateRelpaceMe == NULL)
463 if (*CreateRelpaceMe != NULL)
464 StrBufPlain(*CreateRelpaceMe, NoMe, KeepOriginal);
466 *CreateRelpaceMe = NewStrBufPlain(NoMe, KeepOriginal);
470 if (CopyFlushMe == NULL)
472 if (*CreateRelpaceMe != NULL)
473 FlushStrBuf(*CreateRelpaceMe);
475 *CreateRelpaceMe = NewStrBuf();
480 * Randomly Chosen: bigger than 64 chars is cheaper to swap the buffers instead of copying.
481 * else *CreateRelpaceMe may use more memory than needed in a longer term, CopyFlushMe might
482 * be a big IO-Buffer...
484 if (KeepOriginal || (StrLength(CopyFlushMe) < 256))
486 if (*CreateRelpaceMe == NULL)
488 *CreateRelpaceMe = NewBuf = NewStrBufPlain(NULL, CopyFlushMe->BufUsed);
493 NewBuf = *CreateRelpaceMe;
496 StrBufAppendBuf(NewBuf, CopyFlushMe, 0);
500 if (*CreateRelpaceMe == NULL)
502 *CreateRelpaceMe = NewBuf = NewStrBufPlain(NULL, CopyFlushMe->BufUsed);
506 NewBuf = *CreateRelpaceMe;
507 SwapBuffers (NewBuf, CopyFlushMe);
510 FlushStrBuf(CopyFlushMe);
515 * @ingroup StrBuf_DeConstructors
516 * @brief create a new Buffer using an existing c-string
517 * this function should also be used if you want to pre-suggest
518 * the buffer size to allocate in conjunction with ptr == NULL
519 * @param ptr the c-string to copy; may be NULL to create a blank instance
520 * @param nChars How many chars should we copy; -1 if we should measure the length ourselves
521 * @returns the new stringbuffer
523 StrBuf* NewStrBufPlain(const char* ptr, int nChars)
526 size_t Siz = BaseStrBufSize;
529 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
534 CopySize = strlen((ptr != NULL)?ptr:"");
538 while ((Siz <= CopySize) && (Siz != 0))
547 NewBuf->buf = (char*) malloc(Siz);
548 if (NewBuf->buf == NULL)
553 NewBuf->BufSize = Siz;
555 memcpy(NewBuf->buf, ptr, CopySize);
556 NewBuf->buf[CopySize] = '\0';
557 NewBuf->BufUsed = CopySize;
560 NewBuf->buf[0] = '\0';
563 NewBuf->ConstBuf = 0;
571 * @ingroup StrBuf_DeConstructors
572 * @brief Set an existing buffer from a c-string
573 * @param Buf buffer to load
574 * @param ptr c-string to put into
575 * @param nChars set to -1 if we should work 0-terminated
576 * @returns the new length of the string
578 int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
593 CopySize = strlen(ptr);
597 while ((Siz <= CopySize) && (Siz != 0))
605 if (Siz != Buf->BufSize)
606 IncreaseBuf(Buf, 0, Siz);
607 memcpy(Buf->buf, ptr, CopySize);
608 Buf->buf[CopySize] = '\0';
609 Buf->BufUsed = CopySize;
616 * @ingroup StrBuf_DeConstructors
617 * @brief use strbuf as wrapper for a string constant for easy handling
618 * @param StringConstant a string to wrap
619 * @param SizeOfStrConstant should be sizeof(StringConstant)-1
621 StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
625 NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
628 NewBuf->buf = (char*) StringConstant;
629 NewBuf->BufSize = SizeOfStrConstant;
630 NewBuf->BufUsed = SizeOfStrConstant;
631 NewBuf->ConstBuf = 1;
640 * @ingroup StrBuf_DeConstructors
641 * @brief flush the content of a Buf; keep its struct
642 * @param buf Buffer to flush
644 int FlushStrBuf(StrBuf *buf)
646 if ((buf == NULL) || (buf->buf == NULL))
656 * @ingroup StrBuf_DeConstructors
657 * @brief wipe the content of a Buf thoroughly (overwrite it -> expensive); keep its struct
658 * @param buf Buffer to wipe
660 int FLUSHStrBuf(StrBuf *buf)
666 if (buf->BufUsed > 0) {
667 memset(buf->buf, 0, buf->BufUsed);
674 int hFreeDbglog = -1;
677 * @ingroup StrBuf_DeConstructors
678 * @brief Release a Buffer
679 * Its a double pointer, so it can NULL your pointer
680 * so fancy SIG11 appear instead of random results
681 * @param FreeMe Pointer Pointer to the buffer to free
683 void FreeStrBuf (StrBuf **FreeMe)
688 dbg_FreeStrBuf(FreeMe, 'F');
690 if (!(*FreeMe)->ConstBuf)
691 free((*FreeMe)->buf);
697 * @ingroup StrBuf_DeConstructors
698 * @brief flatten a Buffer to the Char * we return
699 * Its a double pointer, so it can NULL your pointer
700 * so fancy SIG11 appear instead of random results
701 * The Callee then owns the buffer and is responsible for freeing it.
702 * @param SmashMe Pointer Pointer to the buffer to release Buf from and free
703 * @returns the pointer of the buffer; Callee owns the memory thereafter.
705 char *SmashStrBuf (StrBuf **SmashMe)
709 if ((SmashMe == NULL) || (*SmashMe == NULL))
712 dbg_FreeStrBuf(SmashMe, 'S');
714 Ret = (*SmashMe)->buf;
721 * @ingroup StrBuf_DeConstructors
722 * @brief Release the buffer
723 * If you want put your StrBuf into a Hash, use this as Destructor.
724 * @param VFreeMe untyped pointer to a StrBuf. be shure to do the right thing [TM]
726 void HFreeStrBuf (void *VFreeMe)
728 StrBuf *FreeMe = (StrBuf*)VFreeMe;
732 dbg_FreeStrBuf(SmashMe, 'H');
734 if (!FreeMe->ConstBuf)
740 /*******************************************************************************
741 * Simple string transformations *
742 *******************************************************************************/
746 * @brief Wrapper around atol
748 long StrTol(const StrBuf *Buf)
753 return atol(Buf->buf);
760 * @brief Wrapper around atoi
762 int StrToi(const StrBuf *Buf)
766 if (Buf->BufUsed > 0)
767 return atoi(Buf->buf);
774 * @brief Checks to see if the string is a pure number
775 * @param Buf The buffer to inspect
776 * @returns 1 if its a pure number, 0, if not.
778 int StrBufIsNumber(const StrBuf *Buf) {
780 if ((Buf == NULL) || (Buf->BufUsed == 0)) {
783 strtoll(Buf->buf, &pEnd, 10);
784 if (pEnd == Buf->buf)
786 if ((pEnd != NULL) && (pEnd == Buf->buf + Buf->BufUsed))
788 if (Buf->buf == pEnd)
794 * @ingroup StrBuf_Filler
795 * @brief modifies a Single char of the Buf
796 * You can point to it via char* or a zero-based integer
797 * @param Buf The buffer to manipulate
798 * @param ptr char* to zero; use NULL if unused
799 * @param nThChar zero based pointer into the string; use -1 if unused
800 * @param PeekValue The Character to place into the position
802 long StrBufPeek(StrBuf *Buf, const char* ptr, long nThChar, char PeekValue)
807 nThChar = ptr - Buf->buf;
808 if ((nThChar < 0) || (nThChar > Buf->BufUsed))
810 Buf->buf[nThChar] = PeekValue;
815 * @ingroup StrBuf_Filler
816 * @brief modifies a range of chars of the Buf
817 * You can point to it via char* or a zero-based integer
818 * @param Buf The buffer to manipulate
819 * @param ptr char* to zero; use NULL if unused
820 * @param nThChar zero based pointer into the string; use -1 if unused
821 * @param nChars how many chars are to be flushed?
822 * @param PookValue The Character to place into that area
824 long StrBufPook(StrBuf *Buf, const char* ptr, long nThChar, long nChars, char PookValue)
829 nThChar = ptr - Buf->buf;
830 if ((nThChar < 0) || (nThChar > Buf->BufUsed))
832 if (nThChar + nChars > Buf->BufUsed)
833 nChars = Buf->BufUsed - nThChar;
835 memset(Buf->buf + nThChar, PookValue, nChars);
836 /* just to be shure... */
837 Buf->buf[Buf->BufUsed] = 0;
842 * @ingroup StrBuf_Filler
843 * @brief Append a StringBuffer to the buffer
844 * @param Buf Buffer to modify
845 * @param AppendBuf Buffer to copy at the end of our buffer
846 * @param Offset Should we start copying from an offset?
848 void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, unsigned long Offset)
850 if ((AppendBuf == NULL) || (AppendBuf->buf == NULL) ||
851 (Buf == NULL) || (Buf->buf == NULL))
854 if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed + 1)
857 AppendBuf->BufUsed + Buf->BufUsed);
859 memcpy(Buf->buf + Buf->BufUsed,
860 AppendBuf->buf + Offset,
861 AppendBuf->BufUsed - Offset);
862 Buf->BufUsed += AppendBuf->BufUsed - Offset;
863 Buf->buf[Buf->BufUsed] = '\0';
868 * @ingroup StrBuf_Filler
869 * @brief Append a C-String to the buffer
870 * @param Buf Buffer to modify
871 * @param AppendBuf Buffer to copy at the end of our buffer
872 * @param AppendSize number of bytes to copy; set to -1 if we should count it in advance
873 * @param Offset Should we start copying from an offset?
875 void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, unsigned long Offset)
878 long BufSizeRequired;
880 if ((AppendBuf == NULL) || (Buf == NULL))
884 aps = strlen(AppendBuf + Offset);
886 aps = AppendSize - Offset;
888 BufSizeRequired = Buf->BufUsed + aps + 1;
889 if (Buf->BufSize <= BufSizeRequired)
890 IncreaseBuf(Buf, (Buf->BufUsed > 0), BufSizeRequired);
892 memcpy(Buf->buf + Buf->BufUsed,
896 Buf->buf[Buf->BufUsed] = '\0';
900 * @ingroup StrBuf_Filler
901 * @brief sprintf like function appending the formated string to the buffer
902 * vsnprintf version to wrap into own calls
903 * @param Buf Buffer to extend by format and Params
904 * @param format printf alike format to add
905 * @param ap va_list containing the items for format
907 void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
915 if ((Buf == NULL) || (format == NULL))
918 BufSize = Buf->BufSize;
919 nWritten = Buf->BufSize + 1;
920 Offset = Buf->BufUsed;
921 newused = Offset + nWritten;
923 while (newused >= BufSize) {
925 nWritten = vsnprintf(Buf->buf + Offset,
926 Buf->BufSize - Offset,
929 newused = Offset + nWritten;
930 if (newused >= Buf->BufSize) {
931 if (IncreaseBuf(Buf, 1, newused) == -1)
932 return; /* TODO: error handling? */
933 newused = Buf->BufSize + 1;
936 Buf->BufUsed = Offset + nWritten;
937 BufSize = Buf->BufSize;
944 * @ingroup StrBuf_Filler
945 * @brief sprintf like function appending the formated string to the buffer
946 * @param Buf Buffer to extend by format and Params
947 * @param format printf alike format to add
949 void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...)
957 if ((Buf == NULL) || (format == NULL))
960 BufSize = Buf->BufSize;
961 nWritten = Buf->BufSize + 1;
962 Offset = Buf->BufUsed;
963 newused = Offset + nWritten;
965 while (newused >= BufSize) {
966 va_start(arg_ptr, format);
967 nWritten = vsnprintf(Buf->buf + Buf->BufUsed,
968 Buf->BufSize - Buf->BufUsed,
971 newused = Buf->BufUsed + nWritten;
972 if (newused >= Buf->BufSize) {
973 if (IncreaseBuf(Buf, 1, newused) == -1)
974 return; /* TODO: error handling? */
975 newused = Buf->BufSize + 1;
978 Buf->BufUsed += nWritten;
979 BufSize = Buf->BufSize;
986 * @ingroup StrBuf_Filler
987 * @brief sprintf like function putting the formated string into the buffer
988 * @param Buf Buffer to extend by format and Parameters
989 * @param format printf alike format to add
991 void StrBufPrintf(StrBuf *Buf, const char *format, ...)
996 if ((Buf == NULL) || (format == NULL))
999 nWritten = Buf->BufSize + 1;
1000 while (nWritten >= Buf->BufSize) {
1001 va_start(arg_ptr, format);
1002 nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
1004 if (nWritten >= Buf->BufSize) {
1005 if (IncreaseBuf(Buf, 0, 0) == -1)
1006 return; /* TODO: error handling? */
1007 nWritten = Buf->BufSize + 1;
1010 Buf->BufUsed = nWritten ;
1015 * @ingroup StrBuf_Filler
1016 * @brief Callback for cURL to append the webserver reply to a buffer
1017 * @param ptr pre-defined by the cURL API; see man 3 curl for mre info
1018 * @param size pre-defined by the cURL API; see man 3 curl for mre info
1019 * @param nmemb pre-defined by the cURL API; see man 3 curl for mre info
1020 * @param stream pre-defined by the cURL API; see man 3 curl for mre info
1022 size_t CurlFillStrBuf_callback(void *ptr, size_t size, size_t nmemb, void *stream)
1031 StrBufAppendBufPlain(Target, ptr, size * nmemb, 0);
1032 return size * nmemb;
1038 * @brief extracts a substring from Source into dest
1039 * @param dest buffer to place substring into
1040 * @param Source string to copy substring from
1041 * @param Offset chars to skip from start
1042 * @param nChars number of chars to copy
1043 * @returns the number of chars copied; may be different from nChars due to the size of Source
1045 int StrBufSub(StrBuf *dest, const StrBuf *Source, unsigned long Offset, size_t nChars)
1047 size_t NCharsRemain;
1048 if (Offset > Source->BufUsed)
1054 if (Offset + nChars < Source->BufUsed)
1056 if ((nChars >= dest->BufSize) &&
1057 (IncreaseBuf(dest, 0, nChars + 1) == -1))
1059 memcpy(dest->buf, Source->buf + Offset, nChars);
1060 dest->BufUsed = nChars;
1061 dest->buf[dest->BufUsed] = '\0';
1064 NCharsRemain = Source->BufUsed - Offset;
1065 if ((NCharsRemain >= dest->BufSize) &&
1066 (IncreaseBuf(dest, 0, NCharsRemain + 1) == -1))
1068 memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
1069 dest->BufUsed = NCharsRemain;
1070 dest->buf[dest->BufUsed] = '\0';
1071 return NCharsRemain;
1076 * @brief Cut nChars from the start of the string
1077 * @param Buf Buffer to modify
1078 * @param nChars how many chars should be skipped?
1080 void StrBufCutLeft(StrBuf *Buf, int nChars)
1082 if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1083 if (nChars >= Buf->BufUsed) {
1087 memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
1088 Buf->BufUsed -= nChars;
1089 Buf->buf[Buf->BufUsed] = '\0';
1094 * @brief Cut the trailing n Chars from the string
1095 * @param Buf Buffer to modify
1096 * @param nChars how many chars should be trunkated?
1098 void StrBufCutRight(StrBuf *Buf, int nChars)
1100 if ((Buf == NULL) || (Buf->BufUsed == 0) || (Buf->buf == NULL))
1103 if (nChars >= Buf->BufUsed) {
1107 Buf->BufUsed -= nChars;
1108 Buf->buf[Buf->BufUsed] = '\0';
1113 * @brief Cut the string after n Chars
1114 * @param Buf Buffer to modify
1115 * @param AfternChars after how many chars should we trunkate the string?
1116 * @param At if non-null and points inside of our string, cut it there.
1118 void StrBufCutAt(StrBuf *Buf, int AfternChars, const char *At)
1120 if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1122 AfternChars = At - Buf->buf;
1125 if ((AfternChars < 0) || (AfternChars >= Buf->BufUsed))
1127 Buf->BufUsed = AfternChars;
1128 Buf->buf[Buf->BufUsed] = '\0';
1134 * @brief Strip leading and trailing spaces from a string; with premeasured and adjusted length.
1135 * @param Buf the string to modify
1137 void StrBufTrim(StrBuf *Buf)
1140 if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1142 while ((Buf->BufUsed > 0) &&
1143 isspace(Buf->buf[Buf->BufUsed - 1]))
1147 Buf->buf[Buf->BufUsed] = '\0';
1149 if (Buf->BufUsed == 0) return;
1151 while ((Buf->BufUsed > delta) && (isspace(Buf->buf[delta]))){
1154 if (delta > 0) StrBufCutLeft(Buf, delta);
1158 * @brief changes all spaces in the string (tab, linefeed...) to Blank (0x20)
1159 * @param Buf the string to modify
1161 void StrBufSpaceToBlank(StrBuf *Buf)
1165 if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1168 pche = pch + Buf->BufUsed;
1177 void StrBufStripAllBut(StrBuf *Buf, char leftboundary, char rightboundary)
1182 if ((Buf == NULL) || (Buf->buf == NULL)) {
1186 pRight = strchr(Buf->buf, rightboundary);
1187 if (pRight != NULL) {
1188 StrBufCutAt(Buf, 0, pRight);
1191 pLeft = strrchr(ChrPtr(Buf), leftboundary);
1192 if (pLeft != NULL) {
1193 StrBufCutLeft(Buf, pLeft - Buf->buf + 1);
1199 * @ingroup StrBuf_Filler
1200 * @brief uppercase the contents of a buffer
1201 * @param Buf the buffer to translate
1203 void StrBufUpCase(StrBuf *Buf)
1207 if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1210 pche = pch + Buf->BufUsed;
1211 while (pch < pche) {
1212 *pch = toupper(*pch);
1219 * @ingroup StrBuf_Filler
1220 * @brief lowercase the contents of a buffer
1221 * @param Buf the buffer to translate
1223 void StrBufLowerCase(StrBuf *Buf)
1227 if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1230 pche = pch + Buf->BufUsed;
1231 while (pch < pche) {
1232 *pch = tolower(*pch);
1238 /*******************************************************************************
1239 * a tokenizer that kills, maims, and destroys *
1240 *******************************************************************************/
1243 * @ingroup StrBuf_Tokenizer
1244 * @brief Replace a token at a given place with a given length by another token with given length
1245 * @param Buf String where to work on
1246 * @param where where inside of the Buf is the search-token
1247 * @param HowLong How long is the token to be replaced
1248 * @param Repl Token to insert at 'where'
1249 * @param ReplLen Length of repl
1250 * @returns -1 if fail else length of resulting Buf
1252 int StrBufReplaceToken(StrBuf *Buf, long where, long HowLong,
1253 const char *Repl, long ReplLen)
1256 if ((Buf == NULL) ||
1257 (where > Buf->BufUsed) ||
1258 (where + HowLong > Buf->BufUsed))
1261 if (where + ReplLen - HowLong > Buf->BufSize)
1262 if (IncreaseBuf(Buf, 1, Buf->BufUsed + ReplLen) < 0)
1265 memmove(Buf->buf + where + ReplLen,
1266 Buf->buf + where + HowLong,
1267 Buf->BufUsed - where - HowLong);
1269 memcpy(Buf->buf + where,
1272 Buf->BufUsed += ReplLen - HowLong;
1274 return Buf->BufUsed;
1278 * @ingroup StrBuf_Tokenizer
1279 * @brief Counts the numbmer of tokens in a buffer
1280 * @param source String to count tokens in
1281 * @param tok Tokenizer char to count
1282 * @returns numbers of tokenizer chars found
1284 int StrBufNum_tokens(const StrBuf *source, char tok)
1288 if ((source == NULL) || (source->BufUsed == 0))
1290 if ((source->BufUsed == 1) && (*source->buf == tok))
1294 pche = pch + source->BufUsed;
1305 * @ingroup StrBuf_Tokenizer
1306 * @brief a string tokenizer
1307 * @param Source StringBuffer to read into
1308 * @param parmnum n'th Parameter to remove
1309 * @param separator tokenizer character
1310 * @returns -1 if not found, else length of token.
1312 int StrBufRemove_token(StrBuf *Source, int parmnum, char separator)
1315 char *d, *s, *end; /* dest, source */
1318 /* Find desired @parameter */
1319 end = Source->buf + Source->BufUsed;
1321 while ((d <= end) &&
1324 /* End of string, bail! */
1329 if (*d == separator) {
1334 if ((d == NULL) || (d >= end))
1335 return 0; /* @Parameter not found */
1337 /* Find next @parameter */
1339 while ((s <= end) &&
1340 (*s && *s != separator))
1344 if (*s == separator)
1348 /* Hack and slash */
1353 memmove(d, s, Source->BufUsed - (s - Source->buf));
1354 Source->BufUsed += ReducedBy;
1355 Source->buf[Source->BufUsed] = '\0';
1357 else if (d == Source->buf) {
1359 Source->BufUsed = 0;
1363 Source->BufUsed += ReducedBy;
1374 int StrBufExtract_tokenFromStr(StrBuf *dest, const char *Source, long SourceLen, int parmnum, char separator)
1376 const StrBuf Temp = {
1389 return StrBufExtract_token(dest, &Temp, parmnum, separator);
1393 * @ingroup StrBuf_Tokenizer
1394 * @brief a string tokenizer
1395 * @param dest Destination StringBuffer
1396 * @param Source StringBuffer to read into
1397 * @param parmnum n'th Parameter to extract
1398 * @param separator tokenizer character
1399 * @returns -1 if not found, else length of token.
1401 int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
1403 const char *s, *e; //* source * /
1404 int len = 0; //* running total length of extracted string * /
1405 int current_token = 0; //* token currently being processed * /
1408 dest->buf[0] = '\0';
1414 if ((Source == NULL) || (Source->BufUsed ==0)) {
1418 e = s + Source->BufUsed;
1421 //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
1423 while ((s < e) && !IsEmptyStr(s)) {
1424 if (*s == separator) {
1427 if (len >= dest->BufSize) {
1428 dest->BufUsed = len;
1429 if (IncreaseBuf(dest, 1, -1) < 0) {
1434 if ( (current_token == parmnum) &&
1435 (*s != separator)) {
1436 dest->buf[len] = *s;
1439 else if (current_token > parmnum) {
1445 dest->buf[len] = '\0';
1446 dest->BufUsed = len;
1448 if (current_token < parmnum) {
1449 //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
1452 //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
1461 * @ingroup StrBuf_Tokenizer
1462 * @brief a string tokenizer to fetch an integer
1463 * @param Source String containing tokens
1464 * @param parmnum n'th Parameter to extract
1465 * @param separator tokenizer character
1466 * @returns 0 if not found, else integer representation of the token
1468 int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
1478 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
1485 * @ingroup StrBuf_Tokenizer
1486 * @brief a string tokenizer to fetch a long integer
1487 * @param Source String containing tokens
1488 * @param parmnum n'th Parameter to extract
1489 * @param separator tokenizer character
1490 * @returns 0 if not found, else long integer representation of the token
1492 long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
1502 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
1510 * @ingroup StrBuf_Tokenizer
1511 * @brief a string tokenizer to fetch an unsigned long
1512 * @param Source String containing tokens
1513 * @param parmnum n'th Parameter to extract
1514 * @param separator tokenizer character
1515 * @returns 0 if not found, else unsigned long representation of the token
1517 unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
1528 if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0) {
1532 return (unsigned long) atol(pnum);
1541 * @ingroup StrBuf_NextTokenizer
1542 * @brief a string tokenizer; Bounds checker
1543 * function to make shure whether StrBufExtract_NextToken and friends have reached the end of the string.
1544 * @param Source our tokenbuffer
1545 * @param pStart the token iterator pointer to inspect
1546 * @returns whether the revolving pointer is inside of the search range
1548 int StrBufHaveNextToken(const StrBuf *Source, const char **pStart)
1550 if ((Source == NULL) ||
1551 (*pStart == StrBufNOTNULL) ||
1552 (Source->BufUsed == 0))
1556 if (*pStart == NULL)
1560 else if (*pStart > Source->buf + Source->BufUsed)
1564 else if (*pStart <= Source->buf)
1573 * @ingroup StrBuf_NextTokenizer
1574 * @brief a string tokenizer
1575 * @param dest Destination StringBuffer
1576 * @param Source StringBuffer to read into
1577 * @param pStart pointer to the end of the last token. Feed with NULL on start.
1578 * @param separator tokenizer
1579 * @returns -1 if not found, else length of token.
1581 int StrBufExtract_NextToken(StrBuf *dest, const StrBuf *Source, const char **pStart, char separator)
1583 const char *s; /* source */
1584 const char *EndBuffer; /* end stop of source buffer */
1585 int current_token = 0; /* token currently being processed */
1586 int len = 0; /* running total length of extracted string */
1588 if ((Source == NULL) ||
1589 (Source->BufUsed == 0) )
1591 *pStart = StrBufNOTNULL;
1597 EndBuffer = Source->buf + Source->BufUsed;
1601 dest->buf[0] = '\0';
1606 *pStart = EndBuffer + 1;
1610 if (*pStart == NULL)
1612 *pStart = Source->buf; /* we're starting to examine this buffer. */
1614 else if ((*pStart < Source->buf) ||
1615 (*pStart > EndBuffer ) )
1617 return -1; /* no more tokens to find. */
1621 /* start to find the next token */
1622 while ((s <= EndBuffer) &&
1623 (current_token == 0) )
1625 if (*s == separator)
1627 /* we found the next token */
1631 if (len >= dest->BufSize)
1633 /* our Dest-buffer isn't big enough, increase it. */
1634 dest->BufUsed = len;
1636 if (IncreaseBuf(dest, 1, -1) < 0) {
1637 /* WHUT? no more mem? bail out. */
1644 if ( (current_token == 0 ) && /* are we in our target token? */
1645 (!IsEmptyStr(s) ) &&
1646 (separator != *s) ) /* don't copy the token itself */
1648 dest->buf[len] = *s; /* Copy the payload */
1649 ++len; /* remember the bigger size. */
1655 /* did we reach the end? */
1656 if ((s > EndBuffer)) {
1657 EndBuffer = StrBufNOTNULL;
1658 *pStart = EndBuffer;
1661 *pStart = s; /* remember the position for the next run */
1664 /* sanitize our extracted token */
1665 dest->buf[len] = '\0';
1666 dest->BufUsed = len;
1673 * @ingroup StrBuf_NextTokenizer
1674 * @brief a string tokenizer
1675 * @param Source StringBuffer to read from
1676 * @param pStart pointer to the end of the last token. Feed with NULL.
1677 * @param separator tokenizer character
1678 * @param nTokens number of tokens to fastforward over
1679 * @returns -1 if not found, else length of token.
1681 int StrBufSkip_NTokenS(const StrBuf *Source, const char **pStart, char separator, int nTokens)
1683 const char *s, *EndBuffer; //* source * /
1684 int len = 0; //* running total length of extracted string * /
1685 int current_token = 0; //* token currently being processed * /
1687 if ((Source == NULL) ||
1688 (Source->BufUsed ==0)) {
1692 return Source->BufUsed;
1694 if (*pStart == NULL)
1695 *pStart = Source->buf;
1697 EndBuffer = Source->buf + Source->BufUsed;
1699 if ((*pStart < Source->buf) ||
1700 (*pStart > EndBuffer)) {
1708 //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
1710 while ((s < EndBuffer) && !IsEmptyStr(s)) {
1711 if (*s == separator) {
1714 if (current_token >= nTokens) {
1726 * @ingroup StrBuf_NextTokenizer
1727 * @brief a string tokenizer to fetch an integer
1728 * @param Source StringBuffer to read from
1729 * @param pStart Cursor on the tokenstring
1730 * @param separator tokenizer character
1731 * @returns 0 if not found, else integer representation of the token
1733 int StrBufExtractNext_int(const StrBuf* Source, const char **pStart, char separator)
1743 if (StrBufExtract_NextToken(&tmp, Source, pStart, separator) > 0)
1750 * @ingroup StrBuf_NextTokenizer
1751 * @brief a string tokenizer to fetch a long integer
1752 * @param Source StringBuffer to read from
1753 * @param pStart Cursor on the tokenstring
1754 * @param separator tokenizer character
1755 * @returns 0 if not found, else long integer representation of the token
1757 long StrBufExtractNext_long(const StrBuf* Source, const char **pStart, char separator)
1767 if (StrBufExtract_NextToken(&tmp, Source, pStart, separator) > 0)
1775 * @ingroup StrBuf_NextTokenizer
1776 * @brief a string tokenizer to fetch an unsigned long
1777 * @param Source StringBuffer to read from
1778 * @param pStart Cursor on the tokenstring
1779 * @param separator tokenizer character
1780 * @returns 0 if not found, else unsigned long representation of the token
1782 unsigned long StrBufExtractNext_unsigned_long(const StrBuf* Source, const char **pStart, char separator)
1793 if (StrBufExtract_NextToken(&tmp, Source, pStart, separator) > 0) {
1797 return (unsigned long) atol(pnum);
1807 /*******************************************************************************
1808 * Escape Appending *
1809 *******************************************************************************/
1812 * @ingroup StrBuf_DeEnCoder
1813 * @brief Escape a string for feeding out as a URL while appending it to a Buffer
1814 * @param OutBuf the output buffer
1815 * @param In Buffer to encode
1816 * @param PlainIn way in from plain old c strings
1818 void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
1820 const char *pch, *pche;
1824 if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
1826 if (PlainIn != NULL) {
1827 len = strlen(PlainIn);
1833 pche = pch + In->BufUsed;
1840 pt = OutBuf->buf + OutBuf->BufUsed;
1841 pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
1843 while (pch < pche) {
1845 IncreaseBuf(OutBuf, 1, -1);
1846 pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
1847 pt = OutBuf->buf + OutBuf->BufUsed;
1850 if((*pch >= 'a' && *pch <= 'z') ||
1851 (*pch >= '@' && *pch <= 'Z') || /* @ A-Z */
1852 (*pch >= '0' && *pch <= ':') || /* 0-9 : */
1853 (*pch == '!') || (*pch == '_') ||
1854 (*pch == ',') || (*pch == '.'))
1861 *(pt + 1) = HexList[(unsigned char)*pch][0];
1862 *(pt + 2) = HexList[(unsigned char)*pch][1];
1864 OutBuf->BufUsed += 3;
1872 * @ingroup StrBuf_DeEnCoder
1873 * @brief Escape a string for feeding out as a the username/password part of an URL while appending it to a Buffer
1874 * @param OutBuf the output buffer
1875 * @param In Buffer to encode
1876 * @param PlainIn way in from plain old c strings
1878 void StrBufUrlescUPAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
1880 const char *pch, *pche;
1884 if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
1886 if (PlainIn != NULL) {
1887 len = strlen(PlainIn);
1893 pche = pch + In->BufUsed;
1900 pt = OutBuf->buf + OutBuf->BufUsed;
1901 pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
1903 while (pch < pche) {
1905 IncreaseBuf(OutBuf, 1, -1);
1906 pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
1907 pt = OutBuf->buf + OutBuf->BufUsed;
1910 if((*pch >= 'a' && *pch <= 'z') ||
1911 (*pch >= 'A' && *pch <= 'Z') || /* A-Z */
1912 (*pch >= '0' && *pch <= ':') || /* 0-9 : */
1913 (*pch == '!') || (*pch == '_') ||
1914 (*pch == ',') || (*pch == '.'))
1921 *(pt + 1) = HexList[(unsigned char)*pch][0];
1922 *(pt + 2) = HexList[(unsigned char)*pch][1];
1924 OutBuf->BufUsed += 3;
1932 * @ingroup StrBuf_DeEnCoder
1933 * @brief append a string with characters having a special meaning in xml encoded to the buffer
1934 * @param OutBuf the output buffer
1935 * @param In Buffer to encode
1936 * @param PlainIn way in from plain old c strings
1937 * @param PlainInLen way in from plain old c strings; maybe you've got binary data or know the length?
1938 * @param OverrideLowChars should chars < 0x20 be replaced by _ or escaped as xml entity?
1940 void StrBufXMLEscAppend(StrBuf *OutBuf,
1942 const char *PlainIn,
1944 int OverrideLowChars)
1946 const char *pch, *pche;
1951 if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
1953 if (PlainIn != NULL) {
1955 len = strlen((const char*)PlainIn);
1962 pch = (const char*)In->buf;
1963 pche = pch + In->BufUsed;
1970 pt = OutBuf->buf + OutBuf->BufUsed;
1971 /**< we max append 6 chars at once plus the \0 */
1972 pte = OutBuf->buf + OutBuf->BufSize - 6;
1974 while (pch < pche) {
1976 OutBuf->BufUsed = pt - OutBuf->buf;
1977 IncreaseBuf(OutBuf, 1, -1);
1978 pte = OutBuf->buf + OutBuf->BufSize - 6;
1979 /**< we max append 3 chars at once plus the \0 */
1981 pt = OutBuf->buf + OutBuf->BufUsed;
1985 memcpy(pt, HKEY("<"));
1989 else if (*pch == '>') {
1990 memcpy(pt, HKEY(">"));
1994 else if (*pch == '&') {
1995 memcpy(pt, HKEY("&"));
1999 else if ((*pch >= 0x20) && (*pch <= 0x7F)) {
2003 else if (*pch < 0x20) {
2004 /* we probably shouldn't be doing this */
2005 if (OverrideLowChars)
2015 *pt = HexList[*(unsigned char*)pch][0];
2017 *pt = HexList[*(unsigned char*)pch][1];
2025 IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(pch, pche);
2028 while (IsUtf8Sequence > 0){
2039 *pt = HexList[*(unsigned char*)pch][0];
2041 *pt = HexList[*(unsigned char*)pch][1];
2050 OutBuf->BufUsed = pt - OutBuf->buf;
2055 * @ingroup StrBuf_DeEnCoder
2056 * @brief append a string in hex encoding to the buffer
2057 * @param OutBuf the output buffer
2058 * @param In Buffer to encode
2059 * @param PlainIn way in from plain old c strings
2060 * @param PlainInLen way in from plain old c strings; maybe you've got binary data or know the length?
2062 void StrBufHexEscAppend(StrBuf *OutBuf, const StrBuf *In, const unsigned char *PlainIn, long PlainInLen)
2064 const unsigned char *pch, *pche;
2068 if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
2070 if (PlainIn != NULL) {
2072 len = strlen((const char*)PlainIn);
2079 pch = (const unsigned char*)In->buf;
2080 pche = pch + In->BufUsed;
2087 pt = OutBuf->buf + OutBuf->BufUsed;
2088 pte = OutBuf->buf + OutBuf->BufSize - 3; /**< we max append 3 chars at once plus the \0 */
2090 while (pch < pche) {
2092 IncreaseBuf(OutBuf, 1, -1);
2093 pte = OutBuf->buf + OutBuf->BufSize - 3; /**< we max append 3 chars at once plus the \0 */
2094 pt = OutBuf->buf + OutBuf->BufUsed;
2097 *pt = HexList[*pch][0];
2099 *pt = HexList[*pch][1];
2100 pt ++; pch ++; OutBuf->BufUsed += 2;
2105 void StrBufBase64Append(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn, long PlainInLen, int linebreaks)
2112 if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
2114 if (PlainIn != NULL) {
2116 len = strlen(PlainIn);
2129 ExpectLen = ((len * 134) / 100) + OutBuf->BufUsed;
2131 if (ExpectLen > OutBuf->BufSize)
2132 if (IncreaseBuf(OutBuf, 1, ExpectLen) < ExpectLen)
2135 pt = OutBuf->buf + OutBuf->BufUsed;
2137 len = CtdlEncodeBase64(pt, pch, len, linebreaks);
2140 OutBuf->BufUsed += len;
2145 * @ingroup StrBuf_DeEnCoder
2146 * @brief append a string in hex encoding to the buffer
2147 * @param OutBuf the output buffer
2148 * @param In Buffer to encode
2149 * @param PlainIn way in from plain old c strings
2151 void StrBufHexescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
2153 StrBufHexEscAppend(OutBuf, In, (const unsigned char*) PlainIn, -1);
2157 * @ingroup StrBuf_DeEnCoder
2158 * @brief Append a string, escaping characters which have meaning in HTML.
2160 * @param Target target buffer
2161 * @param Source source buffer; set to NULL if you just have a C-String
2162 * @param PlainIn Plain-C string to append; set to NULL if unused
2163 * @param nbsp If nonzero, spaces are converted to non-breaking spaces.
2164 * @param nolinebreaks if set to 1, linebreaks are removed from the string.
2165 * if set to 2, linebreaks are replaced by <br/>
2167 long StrEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
2169 const char *aptr, *eiptr;
2173 if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
2176 if (PlainIn != NULL) {
2178 len = strlen(PlainIn);
2183 eiptr = aptr + Source->BufUsed;
2184 len = Source->BufUsed;
2190 bptr = Target->buf + Target->BufUsed;
2191 eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */
2193 while (aptr < eiptr){
2195 IncreaseBuf(Target, 1, -1);
2196 eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */
2197 bptr = Target->buf + Target->BufUsed;
2200 memcpy(bptr, "<", 4);
2202 Target->BufUsed += 4;
2204 else if (*aptr == '>') {
2205 memcpy(bptr, ">", 4);
2207 Target->BufUsed += 4;
2209 else if (*aptr == '&') {
2210 memcpy(bptr, "&", 5);
2212 Target->BufUsed += 5;
2214 else if (*aptr == '"') {
2215 memcpy(bptr, """, 6);
2217 Target->BufUsed += 6;
2219 else if (*aptr == '\'') {
2220 memcpy(bptr, "'", 5);
2222 Target->BufUsed += 5;
2224 else if (*aptr == LB) {
2229 else if (*aptr == RB) {
2234 else if (*aptr == QU) {
2239 else if ((*aptr == 32) && (nbsp == 1)) {
2240 memcpy(bptr, " ", 6);
2242 Target->BufUsed += 6;
2244 else if ((*aptr == '\n') && (nolinebreaks == 1)) {
2245 *bptr='\0'; /* nothing */
2247 else if ((*aptr == '\n') && (nolinebreaks == 2)) {
2248 memcpy(bptr, "<br/>", 11);
2250 Target->BufUsed += 11;
2254 else if ((*aptr == '\r') && (nolinebreaks != 0)) {
2255 *bptr='\0'; /* nothing */
2265 if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
2267 return Target->BufUsed;
2271 * @ingroup StrBuf_DeEnCoder
2272 * @brief Append a string, escaping characters which have meaning in HTML.
2273 * Converts linebreaks into blanks; escapes single quotes
2274 * @param Target target buffer
2275 * @param Source source buffer; set to NULL if you just have a C-String
2276 * @param PlainIn Plain-C string to append; set to NULL if unused
2278 void StrMsgEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
2280 const char *aptr, *eiptr;
2284 if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
2287 if (PlainIn != NULL) {
2289 len = strlen(PlainIn);
2294 eiptr = aptr + Source->BufUsed;
2295 len = Source->BufUsed;
2301 eptr = Target->buf + Target->BufSize - 8;
2302 tptr = Target->buf + Target->BufUsed;
2304 while (aptr < eiptr){
2306 IncreaseBuf(Target, 1, -1);
2307 eptr = Target->buf + Target->BufSize - 8;
2308 tptr = Target->buf + Target->BufUsed;
2311 if (*aptr == '\n') {
2315 else if (*aptr == '\r') {
2319 else if (*aptr == '\'') {
2325 Target->BufUsed += 5;
2338 * @ingroup StrBuf_DeEnCoder
2339 * @brief Append a string, escaping characters which have meaning in ICAL.
2341 * @param Target target buffer
2342 * @param Source source buffer; set to NULL if you just have a C-String
2343 * @param PlainIn Plain-C string to append; set to NULL if unused
2345 void StrIcalEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
2347 const char *aptr, *eiptr;
2351 if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
2354 if (PlainIn != NULL) {
2356 len = strlen(PlainIn);
2361 eiptr = aptr + Source->BufUsed;
2362 len = Source->BufUsed;
2368 eptr = Target->buf + Target->BufSize - 8;
2369 tptr = Target->buf + Target->BufUsed;
2371 while (aptr < eiptr){
2372 if(tptr + 3 >= eptr) {
2373 IncreaseBuf(Target, 1, -1);
2374 eptr = Target->buf + Target->BufSize - 8;
2375 tptr = Target->buf + Target->BufUsed;
2378 if (*aptr == '\n') {
2385 else if (*aptr == '\r') {
2392 else if (*aptr == ',') {
2408 * @ingroup StrBuf_DeEnCoder
2409 * @brief Append a string, escaping characters which have meaning in JavaScript strings .
2411 * @param Target target buffer
2412 * @param Source source buffer; set to NULL if you just have a C-String
2413 * @param PlainIn Plain-C string to append; set to NULL if unused
2414 * @returns size of result or -1
2416 long StrECMAEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
2418 const char *aptr, *eiptr;
2423 if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
2426 if (PlainIn != NULL) {
2428 len = strlen(PlainIn);
2433 eiptr = aptr + Source->BufUsed;
2434 len = Source->BufUsed;
2440 bptr = Target->buf + Target->BufUsed;
2441 eptr = Target->buf + Target->BufSize - 7; /* our biggest unit to put in... */
2443 while (aptr < eiptr){
2445 IncreaseBuf(Target, 1, -1);
2446 eptr = Target->buf + Target->BufSize - 7; /* our biggest unit to put in... */
2447 bptr = Target->buf + Target->BufUsed;
2451 memcpy(bptr, HKEY("\\n"));
2453 Target->BufUsed += 2;
2456 memcpy(bptr, HKEY("\\r"));
2458 Target->BufUsed += 2;
2465 Target->BufUsed += 2;
2468 if ((*(aptr + 1) == 'u') &&
2469 isxdigit(*(aptr + 2)) &&
2470 isxdigit(*(aptr + 3)) &&
2471 isxdigit(*(aptr + 4)) &&
2472 isxdigit(*(aptr + 5)))
2473 { /* oh, a unicode escaper. let it pass through. */
2474 memcpy(bptr, aptr, 6);
2477 Target->BufUsed += 6;
2485 Target->BufUsed += 2;
2493 Target->BufUsed += 2;
2500 Target->BufUsed += 2;
2507 Target->BufUsed += 2;
2510 IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(aptr, eiptr);
2511 while (IsUtf8Sequence > 0){
2514 if (--IsUtf8Sequence)
2522 if ((bptr == eptr - 1 ) && !IsEmptyStr(aptr) )
2524 return Target->BufUsed;
2528 * @ingroup StrBuf_DeEnCoder
2529 * @brief Append a string, escaping characters which have meaning in HTML + json.
2531 * @param Target target buffer
2532 * @param Source source buffer; set to NULL if you just have a C-String
2533 * @param PlainIn Plain-C string to append; set to NULL if unused
2534 * @param nbsp If nonzero, spaces are converted to non-breaking spaces.
2535 * @param nolinebreaks if set to 1, linebreaks are removed from the string.
2536 * if set to 2, linebreaks are replaced by <br/>
2538 long StrHtmlEcmaEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
2540 const char *aptr, *eiptr;
2543 int IsUtf8Sequence = 0;
2545 if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
2548 if (PlainIn != NULL) {
2550 len = strlen(PlainIn);
2555 eiptr = aptr + Source->BufUsed;
2556 len = Source->BufUsed;
2562 bptr = Target->buf + Target->BufUsed;
2563 eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */
2565 while (aptr < eiptr){
2567 IncreaseBuf(Target, 1, -1);
2568 eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in... */
2569 bptr = Target->buf + Target->BufUsed;
2573 memcpy(bptr, HKEY("<"));
2575 Target->BufUsed += 4;
2578 memcpy(bptr, HKEY(">"));
2580 Target->BufUsed += 4;
2583 memcpy(bptr, HKEY("&"));
2585 Target->BufUsed += 5;
2598 switch (nolinebreaks) {
2600 *bptr='\0'; /* nothing */
2603 memcpy(bptr, HKEY("<br/>"));
2605 Target->BufUsed += 11;
2608 memcpy(bptr, HKEY("\\n"));
2610 Target->BufUsed += 2;
2614 switch (nolinebreaks) {
2617 *bptr='\0'; /* nothing */
2620 memcpy(bptr, HKEY("\\r"));
2622 Target->BufUsed += 2;
2632 Target->BufUsed += 2;
2635 if ((*(aptr + 1) == 'u') &&
2636 isxdigit(*(aptr + 2)) &&
2637 isxdigit(*(aptr + 3)) &&
2638 isxdigit(*(aptr + 4)) &&
2639 isxdigit(*(aptr + 5)))
2640 { /* oh, a unicode escaper. let it pass through. */
2641 memcpy(bptr, aptr, 6);
2644 Target->BufUsed += 6;
2652 Target->BufUsed += 2;
2660 Target->BufUsed += 2;
2667 Target->BufUsed += 2;
2674 Target->BufUsed += 2;
2678 memcpy(bptr, HKEY(" "));
2680 Target->BufUsed += 6;
2684 IsUtf8Sequence = Ctdl_GetUtf8SequenceLength(aptr, eiptr);
2685 while (IsUtf8Sequence > 0){
2688 if (--IsUtf8Sequence)
2696 if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
2698 return Target->BufUsed;
2703 * @ingroup StrBuf_DeEnCoder
2704 * @brief replace all non-Ascii characters by another
2705 * @param Buf buffer to inspect
2706 * @param repl charater to stamp over non ascii chars
2708 void StrBufAsciify(StrBuf *Buf, const char repl)
2712 for (offset = 0; offset < Buf->BufUsed; offset ++)
2713 if (!isascii(Buf->buf[offset]))
2714 Buf->buf[offset] = repl;
2719 * @ingroup StrBuf_DeEnCoder
2720 * @brief unhide special chars hidden to the HTML escaper
2721 * @param target buffer to put the unescaped string in
2722 * @param source buffer to unescape
2724 void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source)
2729 if ((source == NULL) || (target == NULL) || (target->buf == NULL))
2735 FlushStrBuf(target);
2737 len = source->BufUsed;
2738 for (a = 0; a < len; ++a) {
2739 if (target->BufUsed >= target->BufSize)
2740 IncreaseBuf(target, 1, -1);
2742 if (source->buf[a] == '=') {
2743 hex[0] = source->buf[a + 1];
2744 hex[1] = source->buf[a + 2];
2747 sscanf(hex, "%02x", &b);
2748 target->buf[target->BufUsed] = b;
2749 target->buf[++target->BufUsed] = 0;
2753 target->buf[target->BufUsed] = source->buf[a];
2754 target->buf[++target->BufUsed] = 0;
2761 * @ingroup StrBuf_DeEnCoder
2762 * @brief hide special chars from the HTML escapers and friends
2763 * @param target buffer to put the escaped string in
2764 * @param source buffer to escape
2766 void StrBufEUid_escapize(StrBuf *target, const StrBuf *source)
2771 FlushStrBuf(target);
2773 if ((source == NULL) || (target == NULL) || (target->buf == NULL))
2778 len = source->BufUsed;
2779 for (i=0; i<len; ++i) {
2780 if (target->BufUsed + 4 >= target->BufSize)
2781 IncreaseBuf(target, 1, -1);
2782 if ( (isalnum(source->buf[i])) ||
2783 (source->buf[i]=='-') ||
2784 (source->buf[i]=='_') ) {
2785 target->buf[target->BufUsed++] = source->buf[i];
2788 sprintf(&target->buf[target->BufUsed],
2790 (0xFF &source->buf[i]));
2791 target->BufUsed += 3;
2794 target->buf[target->BufUsed + 1] = '\0';
2798 /*******************************************************************************
2799 * Quoted Printable de/encoding *
2800 *******************************************************************************/
2803 * @ingroup StrBuf_DeEnCoder
2804 * @brief decode a buffer from base 64 encoding; destroys original
2805 * @param Buf Buffor to transform
2807 int StrBufDecodeBase64(StrBuf *Buf)
2815 xferbuf = (char*) malloc(Buf->BufSize);
2816 if (xferbuf == NULL)
2820 siz = CtdlDecodeBase64(xferbuf,
2827 Buf->buf[Buf->BufUsed] = '\0';
2832 * @ingroup StrBuf_DeEnCoder
2833 * @brief decode a buffer from base 64 encoding; expects targetbuffer
2834 * @param BufIn Buffor to transform
2835 * @param BufOut Buffer to put result into
2837 int StrBufDecodeBase64To(const StrBuf *BufIn, StrBuf *BufOut)
2839 if ((BufIn == NULL) || (BufOut == NULL))
2842 if (BufOut->BufSize < BufIn->BufUsed)
2843 IncreaseBuf(BufOut, BufIn->BufUsed, 0);
2845 BufOut->BufUsed = CtdlDecodeBase64(BufOut->buf,
2848 return BufOut->BufUsed;
2851 void *StrBufNewStreamContext(eStreamType type)
2853 base64_decodestate *state;;
2858 state = (base64_decodestate*) malloc(sizeof(base64_decodestate));
2859 base64_init_decodestate(state);
2866 void StrBufDestroyStreamContext(eStreamType type, void **Stream)
2876 void StrBufStreamDecodeTo(StrBuf *Target, const StrBuf *In, const char* pIn, long pInLen, void *Stream)
2878 base64_decodestate *state = Stream;
2884 pInLen = In->BufUsed;
2886 if ((pIn == NULL) || (Stream == NULL))
2889 ExpectLen = (pInLen / 4) * 3;
2891 if (Target->BufSize - Target->BufUsed < ExpectLen)
2893 IncreaseBuf(Target, 1, Target->BufUsed + ExpectLen + 1);
2896 ExpectLen = base64_decode_block(pIn, pInLen, Target->buf + Target->BufUsed, state);
2897 Target->BufUsed += ExpectLen;
2898 Target->buf[Target->BufUsed] = '\0';
2902 * @ingroup StrBuf_DeEnCoder
2903 * @brief decode a buffer from base 64 encoding; destroys original
2904 * @param Buf Buffor to transform
2906 int StrBufDecodeHex(StrBuf *Buf)
2909 char *pch, *pche, *pchi;
2911 if (Buf == NULL) return -1;
2913 pch = pchi = Buf->buf;
2914 pche = pch + Buf->BufUsed;
2916 while (pchi < pche){
2917 ch = decode_hex(pchi);
2924 Buf->BufUsed = pch - Buf->buf;
2925 return Buf->BufUsed;
2929 * @ingroup StrBuf_DeEnCoder
2930 * @brief replace all chars >0x20 && < 0x7F with Mute
2931 * @param Mute char to put over invalid chars
2932 * @param Buf Buffor to transform
2934 int StrBufSanitizeAscii(StrBuf *Buf, const char Mute)
2938 if (Buf == NULL) return -1;
2939 pch = (unsigned char *)Buf->buf;
2940 while (pch < (unsigned char *)Buf->buf + Buf->BufUsed) {
2941 if ((*pch < 0x20) || (*pch > 0x7F))
2945 return Buf->BufUsed;
2950 * @ingroup StrBuf_DeEnCoder
2951 * @brief remove escaped strings from i.e. the url string (like %20 for blanks)
2952 * @param Buf Buffer to translate
2953 * @param StripBlanks Reduce several blanks to one?
2955 long StrBufUnescape(StrBuf *Buf, int StripBlanks)
2964 while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
2965 Buf->buf[Buf->BufUsed - 1] = '\0';
2970 while (a < Buf->BufUsed) {
2971 if (Buf->buf[a] == '+')
2973 else if (Buf->buf[a] == '%') {
2974 /* don't let % chars through, rather truncate the input. */
2975 if (a + 2 > Buf->BufUsed) {
2980 hex[0] = Buf->buf[a + 1];
2981 hex[1] = Buf->buf[a + 2];
2984 sscanf(hex, "%02x", &b);
2985 Buf->buf[a] = (char) b;
2986 len = Buf->BufUsed - a - 2;
2988 memmove(&Buf->buf[a + 1], &Buf->buf[a + 3], len);
3000 * @ingroup StrBuf_DeEnCoder
3001 * @brief RFC2047-encode a header field if necessary.
3002 * If no non-ASCII characters are found, the string
3003 * will be copied verbatim without encoding.
3005 * @param target Target buffer.
3006 * @param source Source string to be encoded.
3007 * @returns encoded length; -1 if non success.
3009 int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
3011 const char headerStr[] = "=?UTF-8?Q?";
3012 int need_to_encode = 0;
3016 if ((source == NULL) ||
3020 while ((i < source->BufUsed) &&
3021 (!IsEmptyStr (&source->buf[i])) &&
3022 (need_to_encode == 0)) {
3023 if (((unsigned char) source->buf[i] < 32) ||
3024 ((unsigned char) source->buf[i] > 126)) {
3030 if (!need_to_encode) {
3031 if (*target == NULL) {
3032 *target = NewStrBufPlain(source->buf, source->BufUsed);
3035 FlushStrBuf(*target);
3036 StrBufAppendBuf(*target, source, 0);
3039 return (*target)->BufUsed;
3043 if (*target == NULL)
3044 *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
3045 else if (sizeof(headerStr) + source->BufUsed >= (*target)->BufSize)
3046 IncreaseBuf(*target, sizeof(headerStr) + source->BufUsed, 0);
3047 memcpy ((*target)->buf, headerStr, sizeof(headerStr) - 1);
3048 (*target)->BufUsed = sizeof(headerStr) - 1;
3049 for (i=0; (i < source->BufUsed); ++i) {
3050 if ((*target)->BufUsed + 4 >= (*target)->BufSize)
3051 IncreaseBuf(*target, 1, 0);
3052 ch = (unsigned char) source->buf[i];
3061 sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
3062 (*target)->BufUsed += 3;
3066 (*target)->buf[(*target)->BufUsed] = '_';
3068 (*target)->buf[(*target)->BufUsed] = ch;
3069 (*target)->BufUsed++;
3073 if ((*target)->BufUsed + 4 >= (*target)->BufSize)
3074 IncreaseBuf(*target, 1, 0);
3076 (*target)->buf[(*target)->BufUsed++] = '?';
3077 (*target)->buf[(*target)->BufUsed++] = '=';
3078 (*target)->buf[(*target)->BufUsed] = '\0';
3079 return (*target)->BufUsed;;
3083 * @ingroup StrBuf_DeEnCoder
3084 * @brief Quoted-Printable encode a message; make it < 80 columns width.
3085 * @param source Source string to be encoded.
3086 * @returns buffer with encoded message.
3088 StrBuf *StrBufRFC2047encodeMessage(const StrBuf *EncodeMe)
3092 const char *ptr, *eptr;
3096 OutBuf = NewStrBufPlain(NULL, StrLength(EncodeMe) * 4);
3098 OEptr = OutBuf->buf + OutBuf->BufSize;
3099 ptr = EncodeMe->buf;
3100 eptr = EncodeMe->buf + EncodeMe->BufUsed;
3105 if (Optr + 4 >= OEptr)
3108 Offset = Optr - OutBuf->buf;
3109 OutBuf->BufUsed = Optr - OutBuf->buf;
3110 IncreaseBuf(OutBuf, 1, 0);
3111 Optr = OutBuf->buf + Offset;
3112 OEptr = OutBuf->buf + OutBuf->BufSize;
3116 /* ignore carriage returns */
3119 else if (*ptr == '\n') {
3120 /* hard line break */
3121 memcpy(Optr, HKEY("=0A"));
3126 else if (( (*ptr >= 32) && (*ptr <= 60) ) ||
3127 ( (*ptr >= 62) && (*ptr <= 126) ))
3138 *Optr = HexList[ch][0];
3140 *Optr = HexList[ch][1];
3147 /* soft line break */
3148 if (isspace(*(Optr - 1))) {
3153 *Optr = HexList[ch][0];
3155 *Optr = HexList[ch][1];
3167 OutBuf->BufUsed = Optr - OutBuf->buf;
3173 static void AddRecipient(StrBuf *Target,
3175 StrBuf *EmailAddress,
3180 if (StrLength(Target) > 0) StrBufAppendBufPlain(Target, HKEY(", "), 0);
3181 if (strchr(ChrPtr(UserName), ',') != NULL) QuoteMe = 1;
3183 if (QuoteMe) StrBufAppendBufPlain(Target, HKEY("\""), 0);
3184 StrBufRFC2047encode(&EncBuf, UserName);
3185 StrBufAppendBuf(Target, EncBuf, 0);
3186 if (QuoteMe) StrBufAppendBufPlain(Target, HKEY("\" "), 0);
3187 else StrBufAppendBufPlain(Target, HKEY(" "), 0);
3189 if (StrLength(EmailAddress) > 0){
3190 StrBufAppendBufPlain(Target, HKEY("<"), 0);
3191 StrBufAppendBuf(Target, EmailAddress, 0); /* TODO: what about IDN???? */
3192 StrBufAppendBufPlain(Target, HKEY(">"), 0);
3198 * \brief QP encode parts of an email TO/CC/BCC vector, and strip/filter invalid parts
3199 * \param Recp Source list of email recipients
3200 * \param UserName Temporary buffer for internal use; Please provide valid buffer.
3201 * \param EmailAddress Temporary buffer for internal use; Please provide valid buffer.
3202 * \param EncBuf Temporary buffer for internal use; Please provide valid buffer.
3203 * \returns encoded & sanitized buffer with the contents of Recp; Caller owns this memory.
3205 StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp,
3207 StrBuf *EmailAddress,
3211 const char *pch, *pche;
3212 const char *UserStart, *UserEnd, *EmailStart, *EmailEnd, *At;
3214 if ((Recp == NULL) || (StrLength(Recp) == 0))
3218 pche = pch + StrLength(Recp);
3220 if (!CheckEncode(pch, -1, pche))
3221 return NewStrBufDup(Recp);
3223 Target = NewStrBufPlain(NULL, StrLength(Recp));
3225 while ((pch != NULL) && (pch < pche))
3227 while (isspace(*pch)) pch++;
3228 UserEnd = EmailStart = EmailEnd = NULL;
3230 if ((*pch == '"') || (*pch == '\'')) {
3231 UserStart = pch + 1;
3233 UserEnd = strchr(UserStart, *pch);
3234 if (UserEnd == NULL)
3235 break; ///TODO: Userfeedback??
3236 EmailStart = UserEnd + 1;
3237 while (isspace(*EmailStart))
3239 if (UserEnd == UserStart) {
3240 UserStart = UserEnd = NULL;
3243 if (*EmailStart == '<') {
3245 EmailEnd = strchr(EmailStart, '>');
3246 if (EmailEnd == NULL)
3247 EmailEnd = strchr(EmailStart, ',');
3251 EmailEnd = strchr(EmailStart, ',');
3253 if (EmailEnd == NULL)
3260 EmailEnd = strchr(UserStart, ',');
3261 if (EmailEnd == NULL) {
3262 EmailEnd = strchr(pch, '>');
3264 if (EmailEnd != NULL) {
3274 while ((EmailEnd > UserStart) && !gt &&
3275 ((*EmailEnd == ',') ||
3276 (*EmailEnd == '>') ||
3277 (isspace(*EmailEnd))))
3279 if (*EmailEnd == '>')
3284 if (EmailEnd == UserStart)
3288 EmailStart = strchr(UserStart, '<');
3289 if ((EmailStart == NULL) || (EmailStart > EmailEnd))
3291 UserEnd = EmailStart;
3293 while ((UserEnd > UserStart) &&
3294 isspace (*(UserEnd - 1)))
3297 if (UserStart >= UserEnd)
3298 UserStart = UserEnd = NULL;
3300 else { /* this is a local recipient... no domain, just a realname */
3301 EmailStart = UserStart;
3302 At = strchr(EmailStart, '@');
3308 EmailStart = UserStart;
3314 if ((UserStart != NULL) && (UserEnd != NULL))
3315 StrBufPlain(UserName, UserStart, UserEnd - UserStart);
3316 else if ((UserStart != NULL) && (UserEnd == NULL))
3317 StrBufPlain(UserName, UserStart, UserEnd - UserStart);
3319 FlushStrBuf(UserName);
3321 if ((EmailStart != NULL) && (EmailEnd != NULL))
3322 StrBufPlain(EmailAddress, EmailStart, EmailEnd - EmailStart);
3323 else if ((EmailStart != NULL) && (EmailEnd == NULL))
3324 StrBufPlain(EmailAddress, EmailStart, EmailEnd - pche);
3326 FlushStrBuf(EmailAddress);
3328 AddRecipient(Target, UserName, EmailAddress, EncBuf);
3333 if ((pch != NULL) && (*pch == ','))
3335 if (pch != NULL) while (isspace(*pch))
3344 * @brief replaces all occurances of 'search' by 'replace'
3345 * @param buf Buffer to modify
3346 * @param search character to search
3347 * @param replace character to replace search by
3349 void StrBufReplaceChars(StrBuf *buf, char search, char replace)
3354 for (i=0; i<buf->BufUsed; i++)
3355 if (buf->buf[i] == search)
3356 buf->buf[i] = replace;
3362 * @brief removes all \\r s from the string, or replaces them with \n if its not a combination of both.
3363 * @param buf Buffer to modify
3365 void StrBufToUnixLF(StrBuf *buf)
3367 char *pche, *pchS, *pchT;
3371 pche = buf->buf + buf->BufUsed;
3372 pchS = pchT = buf->buf;
3378 if (*pchS != '\n') {
3387 buf->BufUsed = pchT - buf->buf;
3391 /*******************************************************************************
3392 * Iconv Wrapper; RFC822 de/encoding *
3393 *******************************************************************************/
3396 * @ingroup StrBuf_DeEnCoder
3397 * @brief Wrapper around iconv_open()
3398 * Our version adds aliases for non-standard Microsoft charsets
3399 * such as 'MS950', aliasing them to names like 'CP950'