if the StrBuf or its parts are NULL, we can't do any work.
[citadel] / libcitadel / lib / stringbuf.c
1 /*
2  * Copyright (c) 1987-2013 by the citadel.org team
3  *
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.
8  *
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.
13  *
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
17  */
18
19 #define _GNU_SOURCE
20 #include "sysdep.h"
21 #include <ctype.h>
22 #include <errno.h>
23 #include <string.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <sys/select.h>
28 #include <fcntl.h>
29 #include <sys/types.h>
30 #define SHOW_ME_VAPPEND_PRINTF
31 #include <stdarg.h>
32
33 #include "libcitadel.h"
34
35 #ifdef HAVE_ICONV
36 #include <iconv.h>
37 #endif
38
39 #ifdef HAVE_BACKTRACE
40 #include <execinfo.h>
41 #endif
42
43 #ifdef UNDEF_MEMCPY
44 #undef memcpy
45 #endif
46
47 #ifdef HAVE_ZLIB
48 #include <zlib.h>
49 int ZEXPORT compress_gzip(Bytef * dest, size_t * destLen,
50                           const Bytef * source, uLong sourceLen, int level);
51 #endif
52 int BaseStrBufSize = 64;
53 int EnableSplice = 0;
54
55 const char *StrBufNOTNULL = ((char*) NULL) - 1;
56
57 const char HexList[256][3] = {
58         "00","01","02","03","04","05","06","07","08","09","0A","0B","0C","0D","0E","0F",
59         "10","11","12","13","14","15","16","17","18","19","1A","1B","1C","1D","1E","1F",
60         "20","21","22","23","24","25","26","27","28","29","2A","2B","2C","2D","2E","2F",
61         "30","31","32","33","34","35","36","37","38","39","3A","3B","3C","3D","3E","3F",
62         "40","41","42","43","44","45","46","47","48","49","4A","4B","4C","4D","4E","4F",
63         "50","51","52","53","54","55","56","57","58","59","5A","5B","5C","5D","5E","5F",
64         "60","61","62","63","64","65","66","67","68","69","6A","6B","6C","6D","6E","6F",
65         "70","71","72","73","74","75","76","77","78","79","7A","7B","7C","7D","7E","7F",
66         "80","81","82","83","84","85","86","87","88","89","8A","8B","8C","8D","8E","8F",
67         "90","91","92","93","94","95","96","97","98","99","9A","9B","9C","9D","9E","9F",
68         "A0","A1","A2","A3","A4","A5","A6","A7","A8","A9","AA","AB","AC","AD","AE","AF",
69         "B0","B1","B2","B3","B4","B5","B6","B7","B8","B9","BA","BB","BC","BD","BE","BF",
70         "C0","C1","C2","C3","C4","C5","C6","C7","C8","C9","CA","CB","CC","CD","CE","CF",
71         "D0","D1","D2","D3","D4","D5","D6","D7","D8","D9","DA","DB","DC","DD","DE","DF",
72         "E0","E1","E2","E3","E4","E5","E6","E7","E8","E9","EA","EB","EC","ED","EE","EF",
73         "F0","F1","F2","F3","F4","F5","F6","F7","F8","F9","FA","FB","FC","FD","FE","FF"};
74
75 /**
76  * @defgroup StrBuf Stringbuffer, A class for manipulating strings with dynamic buffers
77  * StrBuf is a versatile class, aiding the handling of dynamic strings
78  *  * reduce de/reallocations
79  *  * reduce the need to remeasure it
80  *  * reduce scanning over the string (in @ref StrBuf_NextTokenizer "Tokenizers")
81  *  * allow asyncroneous IO for line and Blob based operations
82  *  * reduce the use of memove in those
83  *  * Quick filling in several operations with append functions
84  */
85
86 /**
87  * @defgroup StrBuf_DeConstructors Create/Destroy StrBufs
88  * @ingroup StrBuf
89  */
90
91 /**
92  * @defgroup StrBuf_Cast Cast operators to interact with char* based code
93  * @ingroup StrBuf
94  * use these operators to interfere with code demanding char*; 
95  * if you need to own the content, smash me. Avoid, since we loose the length information.
96  */
97
98 /**
99  * @defgroup StrBuf_Filler Create/Replace/Append Content into a StrBuf
100  * @ingroup StrBuf
101  * operations to get your Strings into a StrBuf, manipulating them, or appending
102  */
103 /**
104  * @defgroup StrBuf_NextTokenizer Fast tokenizer to pull tokens in sequence 
105  * @ingroup StrBuf
106  * Quick tokenizer; demands of the user to pull its tokens in sequence
107  */
108
109 /**
110  * @defgroup StrBuf_Tokenizer tokenizer Functions; Slow ones.
111  * @ingroup StrBuf
112  * versatile tokenizer; random access to tokens, but slower; Prefer the @ref StrBuf_NextTokenizer "Next Tokenizer"
113  */
114
115 /**
116  * @defgroup StrBuf_BufferedIO Buffered IO with Asynchroneous reads and no unneeded memmoves (the fast ones)
117  * @ingroup StrBuf
118  * File IO to fill StrBufs; Works with work-buffer shared across several calls;
119  * External Cursor to maintain the current read position inside of the buffer
120  * the non-fast ones will use memove to keep the start of the buffer the read buffer (which is slower) 
121  */
122
123 /**
124  * @defgroup StrBuf_IO FileIO; Prefer @ref StrBuf_BufferedIO
125  * @ingroup StrBuf
126  * Slow I/O; avoid.
127  */
128
129 /**
130  * @defgroup StrBuf_DeEnCoder functions to translate the contents of a buffer
131  * @ingroup StrBuf
132  * these functions translate the content of a buffer into another representation;
133  * some are combined Fillers and encoders
134  */
135
136 /**
137  * Private Structure for the Stringbuffer
138  */
139 struct StrBuf {
140         char *buf;         /**< the pointer to the dynamic buffer */
141         long BufSize;      /**< how many spcae do we optain */
142         long BufUsed;      /**< StNumber of Chars used excluding the trailing \\0 */
143         int ConstBuf;      /**< are we just a wrapper arround a static buffer and musn't we be changed? */
144 #ifdef SIZE_DEBUG
145         long nIncreases;   /**< for profiling; cound how many times we needed more */
146         char bt [SIZ];     /**< Stacktrace of last increase */
147         char bt_lastinc [SIZ]; /**< How much did we increase last time? */
148 #endif
149 };
150
151
152 static inline int Ctdl_GetUtf8SequenceLength(const char *CharS, const char *CharE);
153 static inline int Ctdl_IsUtf8SequenceStart(const char Char);
154
155 #ifdef SIZE_DEBUG
156 #ifdef HAVE_BACKTRACE
157 static void StrBufBacktrace(StrBuf *Buf, int which)
158 {
159         int n;
160         char *pstart, *pch;
161         void *stack_frames[50];
162         size_t size, i;
163         char **strings;
164
165         if (which)
166                 pstart = pch = Buf->bt;
167         else
168                 pstart = pch = Buf->bt_lastinc;
169         size = backtrace(stack_frames, sizeof(stack_frames) / sizeof(void*));
170         strings = backtrace_symbols(stack_frames, size);
171         for (i = 0; i < size; i++) {
172                 if (strings != NULL)
173                         n = snprintf(pch, SIZ - (pch - pstart), "%s\\n", strings[i]);
174                 else
175                         n = snprintf(pch, SIZ - (pch - pstart), "%p\\n", stack_frames[i]);
176                 pch += n;
177         }
178         free(strings);
179
180
181 }
182 #endif
183
184 void dbg_FreeStrBuf(StrBuf *FreeMe, char *FromWhere)
185 {
186         if (hFreeDbglog == -1){
187                 pid_t pid = getpid();
188                 char path [SIZ];
189                 snprintf(path, SIZ, "/tmp/libcitadel_strbuf_realloc.log.%d", pid);
190                 hFreeDbglog = open(path, O_APPEND|O_CREAT|O_WRONLY);
191         }
192         if ((*FreeMe)->nIncreases > 0)
193         {
194                 char buf[SIZ * 3];
195                 long n;
196                 n = snprintf(buf, SIZ * 3, "%c+|%ld|%ld|%ld|%s|%s|\n",
197                              FromWhere,
198                              (*FreeMe)->nIncreases,
199                              (*FreeMe)->BufUsed,
200                              (*FreeMe)->BufSize,
201                              (*FreeMe)->bt,
202                              (*FreeMe)->bt_lastinc);
203                 n = write(hFreeDbglog, buf, n);
204         }
205         else
206         {
207                 char buf[128];
208                 long n;
209                 n = snprintf(buf, 128, "%c_|0|%ld%ld|\n",
210                              FromWhere,
211                              (*FreeMe)->BufUsed,
212                              (*FreeMe)->BufSize);
213                 n = write(hFreeDbglog, buf, n);
214         }
215 }
216
217 void dbg_IncreaseBuf(StrBuf *IncMe)
218 {
219         Buf->nIncreases++;
220 #ifdef HAVE_BACKTRACE
221         StrBufBacktrace(Buf, 1);
222 #endif
223 }
224
225 void dbg_Init(StrBuf *Buf)
226 {
227         Buf->nIncreases = 0;
228         Buf->bt[0] = '\0';
229         Buf->bt_lastinc[0] = '\0';
230 #ifdef HAVE_BACKTRACE
231         StrBufBacktrace(Buf, 0);
232 #endif
233 }
234
235 #else
236 /* void it... */
237 #define dbg_FreeStrBuf(a, b)
238 #define dbg_IncreaseBuf(a)
239 #define dbg_Init(a)
240
241 #endif
242
243 /**
244  * @ingroup StrBuf
245  * @brief swaps the contents of two StrBufs
246  * this is to be used to have cheap switched between a work-buffer and a target buffer 
247  * @param A First one
248  * @param B second one
249  */
250 static inline void SwapBuffers(StrBuf *A, StrBuf *B)
251 {
252         StrBuf C;
253
254         memcpy(&C, A, sizeof(*A));
255         memcpy(A, B, sizeof(*B));
256         memcpy(B, &C, sizeof(C));
257
258 }
259
260 /** 
261  * @ingroup StrBuf_Cast
262  * @brief Cast operator to Plain String 
263  * @note if the buffer is altered by StrBuf operations, this pointer may become 
264  *  invalid. So don't lean on it after altering the buffer!
265  *  Since this operation is considered cheap, rather call it often than risking
266  *  your pointer to become invalid!
267  * @param Str the string we want to get the c-string representation for
268  * @returns the Pointer to the Content. Don't mess with it!
269  */
270 inline const char *ChrPtr(const StrBuf *Str)
271 {
272         if (Str == NULL)
273                 return "";
274         return Str->buf;
275 }
276
277 /**
278  * @ingroup StrBuf_Cast
279  * @brief since we know strlen()'s result, provide it here.
280  * @param Str the string to return the length to
281  * @returns contentlength of the buffer
282  */
283 inline int StrLength(const StrBuf *Str)
284 {
285         return (Str != NULL) ? Str->BufUsed : 0;
286 }
287
288 /**
289  * @ingroup StrBuf_DeConstructors
290  * @brief local utility function to resize the buffer
291  * @param Buf the buffer whichs storage we should increase
292  * @param KeepOriginal should we copy the original buffer or just start over with a new one
293  * @param DestSize what should fit in after?
294  */
295 static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
296 {
297         char *NewBuf;
298         size_t NewSize = Buf->BufSize * 2;
299
300         if (Buf->ConstBuf)
301                 return -1;
302                 
303         if (DestSize > 0)
304                 while ((NewSize <= DestSize) && (NewSize != 0))
305                         NewSize *= 2;
306
307         if (NewSize == 0)
308                 return -1;
309
310         NewBuf= (char*) malloc(NewSize);
311         if (NewBuf == NULL)
312                 return -1;
313
314         if (KeepOriginal && (Buf->BufUsed > 0))
315         {
316                 memcpy(NewBuf, Buf->buf, Buf->BufUsed);
317         }
318         else
319         {
320                 NewBuf[0] = '\0';
321                 Buf->BufUsed = 0;
322         }
323         free (Buf->buf);
324         Buf->buf = NewBuf;
325         Buf->BufSize = NewSize;
326
327         dbg_IncreaseBuf(Buf);
328
329         return Buf->BufSize;
330 }
331
332 /**
333  * @ingroup StrBuf_DeConstructors
334  * @brief shrink / increase an _EMPTY_ buffer to NewSize. Buffercontent is thoroughly ignored and flushed.
335  * @param Buf Buffer to shrink (has to be empty)
336  * @param ThreshHold if the buffer is bigger then this, its readjusted
337  * @param NewSize if we Shrink it, how big are we going to be afterwards?
338  */
339 void ReAdjustEmptyBuf(StrBuf *Buf, long ThreshHold, long NewSize)
340 {
341         if ((Buf != NULL) && 
342             (Buf->BufUsed == 0) &&
343             (Buf->BufSize < ThreshHold)) {
344                 free(Buf->buf);
345                 Buf->buf = (char*) malloc(NewSize);
346                 Buf->BufUsed = 0;
347                 Buf->BufSize = NewSize;
348         }
349 }
350
351 /**
352  * @ingroup StrBuf_DeConstructors
353  * @brief shrink long term buffers to their real size so they don't waste memory
354  * @param Buf buffer to shrink
355  * @param Force if not set, will just executed if the buffer is much to big; set for lifetime strings
356  * @returns physical size of the buffer
357  */
358 long StrBufShrinkToFit(StrBuf *Buf, int Force)
359 {
360         if (Buf == NULL)
361                 return -1;
362         if (Force || 
363             (Buf->BufUsed + (Buf->BufUsed / 3) > Buf->BufSize))
364         {
365                 char *TmpBuf;
366
367                 TmpBuf = (char*) malloc(Buf->BufUsed + 1);
368                 if (TmpBuf == NULL)
369                         return -1;
370
371                 memcpy (TmpBuf, Buf->buf, Buf->BufUsed + 1);
372                 Buf->BufSize = Buf->BufUsed + 1;
373                 free(Buf->buf);
374                 Buf->buf = TmpBuf;
375         }
376         return Buf->BufUsed;
377 }
378
379 /**
380  * @ingroup StrBuf_DeConstructors
381  * @brief Allocate a new buffer with default buffer size
382  * @returns the new stringbuffer
383  */
384 StrBuf* NewStrBuf(void)
385 {
386         StrBuf *NewBuf;
387
388         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
389         if (NewBuf == NULL)
390                 return NULL;
391
392         NewBuf->buf = (char*) malloc(BaseStrBufSize);
393         if (NewBuf->buf == NULL)
394         {
395                 free(NewBuf);
396                 return NULL;
397         }
398         NewBuf->buf[0] = '\0';
399         NewBuf->BufSize = BaseStrBufSize;
400         NewBuf->BufUsed = 0;
401         NewBuf->ConstBuf = 0;
402
403         dbg_Init (NewBuf);
404
405         return NewBuf;
406 }
407
408 /** 
409  * @ingroup StrBuf_DeConstructors
410  * @brief Copy Constructor; returns a duplicate of CopyMe
411  * @param CopyMe Buffer to faxmilate
412  * @returns the new stringbuffer
413  */
414 StrBuf* NewStrBufDup(const StrBuf *CopyMe)
415 {
416         StrBuf *NewBuf;
417         
418         if (CopyMe == NULL)
419                 return NewStrBuf();
420
421         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
422         if (NewBuf == NULL)
423                 return NULL;
424
425         NewBuf->buf = (char*) malloc(CopyMe->BufSize);
426         if (NewBuf->buf == NULL)
427         {
428                 free(NewBuf);
429                 return NULL;
430         }
431
432         memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1);
433         NewBuf->BufUsed = CopyMe->BufUsed;
434         NewBuf->BufSize = CopyMe->BufSize;
435         NewBuf->ConstBuf = 0;
436
437         dbg_Init(NewBuf);
438
439         return NewBuf;
440 }
441
442 /** 
443  * @ingroup StrBuf_DeConstructors
444  * @brief Copy Constructor; CreateRelpaceMe will contain CopyFlushMe afterwards.
445  * @param NoMe if non-NULL, we will use that buffer as value; KeepOriginal will abused as len.
446  * @param CopyFlushMe Buffer to faxmilate if KeepOriginal, or to move into CreateRelpaceMe if !KeepOriginal.
447  * @param CreateRelpaceMe If NULL, will be created, else Flushed and filled CopyFlushMe 
448  * @param KeepOriginal should CopyFlushMe remain intact? or may we Steal its buffer?
449  * @returns the new stringbuffer
450  */
451 void NewStrBufDupAppendFlush(StrBuf **CreateRelpaceMe, StrBuf *CopyFlushMe, const char *NoMe, int KeepOriginal)
452 {
453         StrBuf *NewBuf;
454         
455         if (CreateRelpaceMe == NULL)
456                 return;
457
458         if (NoMe != NULL)
459         {
460                 if (*CreateRelpaceMe != NULL)
461                         StrBufPlain(*CreateRelpaceMe, NoMe, KeepOriginal);
462                 else 
463                         *CreateRelpaceMe = NewStrBufPlain(NoMe, KeepOriginal);
464                 return;
465         }
466
467         if (CopyFlushMe == NULL)
468         {
469                 if (*CreateRelpaceMe != NULL)
470                         FlushStrBuf(*CreateRelpaceMe);
471                 else 
472                         *CreateRelpaceMe = NewStrBuf();
473                 return;
474         }
475
476         /* 
477          * Randomly Chosen: bigger than 64 chars is cheaper to swap the buffers instead of copying.
478          * else *CreateRelpaceMe may use more memory than needed in a longer term, CopyFlushMe might
479          * be a big IO-Buffer...
480          */
481         if (KeepOriginal || (StrLength(CopyFlushMe) < 256))
482         {
483                 if (*CreateRelpaceMe == NULL)
484                 {
485                         *CreateRelpaceMe = NewBuf = NewStrBufPlain(NULL, CopyFlushMe->BufUsed);
486                         dbg_Init(NewBuf);
487                 }
488                 else 
489                 {
490                         NewBuf = *CreateRelpaceMe;
491                         FlushStrBuf(NewBuf);
492                 }
493                 StrBufAppendBuf(NewBuf, CopyFlushMe, 0);
494         }
495         else
496         {
497                 if (*CreateRelpaceMe == NULL)
498                 {
499                         *CreateRelpaceMe = NewBuf = NewStrBufPlain(NULL, CopyFlushMe->BufUsed);
500                         dbg_Init(NewBuf);
501                 }
502                 else 
503                         NewBuf = *CreateRelpaceMe;
504                 SwapBuffers (NewBuf, CopyFlushMe);
505         }
506         if (!KeepOriginal)
507                 FlushStrBuf(CopyFlushMe);
508         return;
509 }
510
511 /**
512  * @ingroup StrBuf_DeConstructors
513  * @brief create a new Buffer using an existing c-string
514  * this function should also be used if you want to pre-suggest
515  * the buffer size to allocate in conjunction with ptr == NULL
516  * @param ptr the c-string to copy; may be NULL to create a blank instance
517  * @param nChars How many chars should we copy; -1 if we should measure the length ourselves
518  * @returns the new stringbuffer
519  */
520 StrBuf* NewStrBufPlain(const char* ptr, int nChars)
521 {
522         StrBuf *NewBuf;
523         size_t Siz = BaseStrBufSize;
524         size_t CopySize;
525
526         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
527         if (NewBuf == NULL)
528                 return NULL;
529
530         if (nChars < 0)
531                 CopySize = strlen((ptr != NULL)?ptr:"");
532         else
533                 CopySize = nChars;
534
535         while ((Siz <= CopySize) && (Siz != 0))
536                 Siz *= 2;
537
538         if (Siz == 0)
539         {
540                 free(NewBuf);
541                 return NULL;
542         }
543
544         NewBuf->buf = (char*) malloc(Siz);
545         if (NewBuf->buf == NULL)
546         {
547                 free(NewBuf);
548                 return NULL;
549         }
550         NewBuf->BufSize = Siz;
551         if (ptr != NULL) {
552                 memcpy(NewBuf->buf, ptr, CopySize);
553                 NewBuf->buf[CopySize] = '\0';
554                 NewBuf->BufUsed = CopySize;
555         }
556         else {
557                 NewBuf->buf[0] = '\0';
558                 NewBuf->BufUsed = 0;
559         }
560         NewBuf->ConstBuf = 0;
561
562         dbg_Init(NewBuf);
563
564         return NewBuf;
565 }
566
567 /**
568  * @ingroup StrBuf_DeConstructors
569  * @brief Set an existing buffer from a c-string
570  * @param Buf buffer to load
571  * @param ptr c-string to put into 
572  * @param nChars set to -1 if we should work 0-terminated
573  * @returns the new length of the string
574  */
575 int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
576 {
577         size_t Siz;
578         size_t CopySize;
579
580         if (Buf == NULL)
581                 return -1;
582         if (ptr == NULL) {
583                 FlushStrBuf(Buf);
584                 return -1;
585         }
586
587         Siz = Buf->BufSize;
588
589         if (nChars < 0)
590                 CopySize = strlen(ptr);
591         else
592                 CopySize = nChars;
593
594         while ((Siz <= CopySize) && (Siz != 0))
595                 Siz *= 2;
596
597         if (Siz == 0) {
598                 FlushStrBuf(Buf);
599                 return -1;
600         }
601
602         if (Siz != Buf->BufSize)
603                 IncreaseBuf(Buf, 0, Siz);
604         memcpy(Buf->buf, ptr, CopySize);
605         Buf->buf[CopySize] = '\0';
606         Buf->BufUsed = CopySize;
607         Buf->ConstBuf = 0;
608         return CopySize;
609 }
610
611
612 /**
613  * @ingroup StrBuf_DeConstructors
614  * @brief use strbuf as wrapper for a string constant for easy handling
615  * @param StringConstant a string to wrap
616  * @param SizeOfStrConstant should be sizeof(StringConstant)-1
617  */
618 StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
619 {
620         StrBuf *NewBuf;
621
622         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
623         if (NewBuf == NULL)
624                 return NULL;
625         NewBuf->buf = (char*) StringConstant;
626         NewBuf->BufSize = SizeOfStrConstant;
627         NewBuf->BufUsed = SizeOfStrConstant;
628         NewBuf->ConstBuf = 1;
629
630         dbg_Init(NewBuf);
631
632         return NewBuf;
633 }
634
635
636 /**
637  * @ingroup StrBuf_DeConstructors
638  * @brief flush the content of a Buf; keep its struct
639  * @param buf Buffer to flush
640  */
641 int FlushStrBuf(StrBuf *buf)
642 {
643         if ((buf == NULL) || (buf->buf == NULL))
644                 return -1;
645         if (buf->ConstBuf)
646                 return -1;       
647         buf->buf[0] ='\0';
648         buf->BufUsed = 0;
649         return 0;
650 }
651
652 /**
653  * @ingroup StrBuf_DeConstructors
654  * @brief wipe the content of a Buf thoroughly (overwrite it -> expensive); keep its struct
655  * @param buf Buffer to wipe
656  */
657 int FLUSHStrBuf(StrBuf *buf)
658 {
659         if (buf == NULL)
660                 return -1;
661         if (buf->ConstBuf)
662                 return -1;
663         if (buf->BufUsed > 0) {
664                 memset(buf->buf, 0, buf->BufUsed);
665                 buf->BufUsed = 0;
666         }
667         return 0;
668 }
669
670 #ifdef SIZE_DEBUG
671 int hFreeDbglog = -1;
672 #endif
673 /**
674  * @ingroup StrBuf_DeConstructors
675  * @brief Release a Buffer
676  * Its a double pointer, so it can NULL your pointer
677  * so fancy SIG11 appear instead of random results
678  * @param FreeMe Pointer Pointer to the buffer to free
679  */
680 void FreeStrBuf (StrBuf **FreeMe)
681 {
682         if (*FreeMe == NULL)
683                 return;
684
685         dbg_FreeStrBuf(FreeMe, 'F');
686
687         if (!(*FreeMe)->ConstBuf) 
688                 free((*FreeMe)->buf);
689         free(*FreeMe);
690         *FreeMe = NULL;
691 }
692
693 /**
694  * @ingroup StrBuf_DeConstructors
695  * @brief flatten a Buffer to the Char * we return 
696  * Its a double pointer, so it can NULL your pointer
697  * so fancy SIG11 appear instead of random results
698  * The Callee then owns the buffer and is responsible for freeing it.
699  * @param SmashMe Pointer Pointer to the buffer to release Buf from and free
700  * @returns the pointer of the buffer; Callee owns the memory thereafter.
701  */
702 char *SmashStrBuf (StrBuf **SmashMe)
703 {
704         char *Ret;
705
706         if ((SmashMe == NULL) || (*SmashMe == NULL))
707                 return NULL;
708         
709         dbg_FreeStrBuf(SmashMe, 'S');
710
711         Ret = (*SmashMe)->buf;
712         free(*SmashMe);
713         *SmashMe = NULL;
714         return Ret;
715 }
716
717 /**
718  * @ingroup StrBuf_DeConstructors
719  * @brief Release the buffer
720  * If you want put your StrBuf into a Hash, use this as Destructor.
721  * @param VFreeMe untyped pointer to a StrBuf. be shure to do the right thing [TM]
722  */
723 void HFreeStrBuf (void *VFreeMe)
724 {
725         StrBuf *FreeMe = (StrBuf*)VFreeMe;
726         if (FreeMe == NULL)
727                 return;
728
729         dbg_FreeStrBuf(SmashMe, 'H');
730
731         if (!FreeMe->ConstBuf) 
732                 free(FreeMe->buf);
733         free(FreeMe);
734 }
735
736
737 /*******************************************************************************
738  *                      Simple string transformations                          *
739  *******************************************************************************/
740
741 /**
742  * @ingroup StrBuf
743  * @brief Wrapper around atol
744  */
745 long StrTol(const StrBuf *Buf)
746 {
747         if (Buf == NULL)
748                 return 0;
749         if(Buf->BufUsed > 0)
750                 return atol(Buf->buf);
751         else
752                 return 0;
753 }
754
755 /**
756  * @ingroup StrBuf
757  * @brief Wrapper around atoi
758  */
759 int StrToi(const StrBuf *Buf)
760 {
761         if (Buf == NULL)
762                 return 0;
763         if (Buf->BufUsed > 0)
764                 return atoi(Buf->buf);
765         else
766                 return 0;
767 }
768
769 /**
770  * @ingroup StrBuf
771  * @brief Checks to see if the string is a pure number 
772  * @param Buf The buffer to inspect
773  * @returns 1 if its a pure number, 0, if not.
774  */
775 int StrBufIsNumber(const StrBuf *Buf) {
776         char * pEnd;
777         if ((Buf == NULL) || (Buf->BufUsed == 0)) {
778                 return 0;
779         }
780         strtoll(Buf->buf, &pEnd, 10);
781         if (pEnd == Buf->buf)
782                 return 0;
783         if ((pEnd != NULL) && (pEnd == Buf->buf + Buf->BufUsed))
784                 return 1;
785         if (Buf->buf == pEnd)
786                 return 0;
787         return 0;
788
789
790 /**
791  * @ingroup StrBuf_Filler
792  * @brief modifies a Single char of the Buf
793  * You can point to it via char* or a zero-based integer
794  * @param Buf The buffer to manipulate
795  * @param ptr char* to zero; use NULL if unused
796  * @param nThChar zero based pointer into the string; use -1 if unused
797  * @param PeekValue The Character to place into the position
798  */
799 long StrBufPeek(StrBuf *Buf, const char* ptr, long nThChar, char PeekValue)
800 {
801         if (Buf == NULL)
802                 return -1;
803         if (ptr != NULL)
804                 nThChar = ptr - Buf->buf;
805         if ((nThChar < 0) || (nThChar > Buf->BufUsed))
806                 return -1;
807         Buf->buf[nThChar] = PeekValue;
808         return nThChar;
809 }
810
811 /**
812  * @ingroup StrBuf_Filler
813  * @brief modifies a range of chars of the Buf
814  * You can point to it via char* or a zero-based integer
815  * @param Buf The buffer to manipulate
816  * @param ptr char* to zero; use NULL if unused
817  * @param nThChar zero based pointer into the string; use -1 if unused
818  * @param nChars how many chars are to be flushed?
819  * @param PookValue The Character to place into that area
820  */
821 long StrBufPook(StrBuf *Buf, const char* ptr, long nThChar, long nChars, char PookValue)
822 {
823         if (Buf == NULL)
824                 return -1;
825         if (ptr != NULL)
826                 nThChar = ptr - Buf->buf;
827         if ((nThChar < 0) || (nThChar > Buf->BufUsed))
828                 return -1;
829         if (nThChar + nChars > Buf->BufUsed)
830                 nChars =  Buf->BufUsed - nThChar;
831
832         memset(Buf->buf + nThChar, PookValue, nChars);
833         /* just to be shure... */
834         Buf->buf[Buf->BufUsed] = 0;
835         return nChars;
836 }
837
838 /**
839  * @ingroup StrBuf_Filler
840  * @brief Append a StringBuffer to the buffer
841  * @param Buf Buffer to modify
842  * @param AppendBuf Buffer to copy at the end of our buffer
843  * @param Offset Should we start copying from an offset?
844  */
845 void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, unsigned long Offset)
846 {
847         if ((AppendBuf == NULL) || (AppendBuf->buf == NULL) ||
848             (Buf == NULL) || (Buf->buf == NULL))
849                 return;
850
851         if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed + 1)
852                 IncreaseBuf(Buf, 
853                             (Buf->BufUsed > 0), 
854                             AppendBuf->BufUsed + Buf->BufUsed);
855
856         memcpy(Buf->buf + Buf->BufUsed, 
857                AppendBuf->buf + Offset, 
858                AppendBuf->BufUsed - Offset);
859         Buf->BufUsed += AppendBuf->BufUsed - Offset;
860         Buf->buf[Buf->BufUsed] = '\0';
861 }
862
863
864 /**
865  * @ingroup StrBuf_Filler
866  * @brief Append a C-String to the buffer
867  * @param Buf Buffer to modify
868  * @param AppendBuf Buffer to copy at the end of our buffer
869  * @param AppendSize number of bytes to copy; set to -1 if we should count it in advance
870  * @param Offset Should we start copying from an offset?
871  */
872 void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, unsigned long Offset)
873 {
874         long aps;
875         long BufSizeRequired;
876
877         if ((AppendBuf == NULL) || (Buf == NULL))
878                 return;
879
880         if (AppendSize < 0 )
881                 aps = strlen(AppendBuf + Offset);
882         else
883                 aps = AppendSize - Offset;
884
885         BufSizeRequired = Buf->BufUsed + aps + 1;
886         if (Buf->BufSize <= BufSizeRequired)
887                 IncreaseBuf(Buf, (Buf->BufUsed > 0), BufSizeRequired);
888
889         memcpy(Buf->buf + Buf->BufUsed, 
890                AppendBuf + Offset, 
891                aps);
892         Buf->BufUsed += aps;
893         Buf->buf[Buf->BufUsed] = '\0';
894 }
895
896 /**
897  * @ingroup StrBuf_Filler
898  * @brief sprintf like function appending the formated string to the buffer
899  * vsnprintf version to wrap into own calls
900  * @param Buf Buffer to extend by format and Params
901  * @param format printf alike format to add
902  * @param ap va_list containing the items for format
903  */
904 void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
905 {
906         va_list apl;
907         size_t BufSize;
908         size_t nWritten;
909         size_t Offset;
910         size_t newused;
911
912         if ((Buf == NULL)  || (format == NULL))
913                 return;
914
915         BufSize = Buf->BufSize;
916         nWritten = Buf->BufSize + 1;
917         Offset = Buf->BufUsed;
918         newused = Offset + nWritten;
919         
920         while (newused >= BufSize) {
921                 va_copy(apl, ap);
922                 nWritten = vsnprintf(Buf->buf + Offset, 
923                                      Buf->BufSize - Offset, 
924                                      format, apl);
925                 va_end(apl);
926                 newused = Offset + nWritten;
927                 if (newused >= Buf->BufSize) {
928                         if (IncreaseBuf(Buf, 1, newused) == -1)
929                                 return; /* TODO: error handling? */
930                         newused = Buf->BufSize + 1;
931                 }
932                 else {
933                         Buf->BufUsed = Offset + nWritten;
934                         BufSize = Buf->BufSize;
935                 }
936
937         }
938 }
939
940 /**
941  * @ingroup StrBuf_Filler
942  * @brief sprintf like function appending the formated string to the buffer
943  * @param Buf Buffer to extend by format and Params
944  * @param format printf alike format to add
945  */
946 void StrBufAppendPrintf(StrBuf *Buf, const char *format, ...)
947 {
948         size_t BufSize;
949         size_t nWritten;
950         size_t Offset;
951         size_t newused;
952         va_list arg_ptr;
953         
954         if ((Buf == NULL)  || (format == NULL))
955                 return;
956
957         BufSize = Buf->BufSize;
958         nWritten = Buf->BufSize + 1;
959         Offset = Buf->BufUsed;
960         newused = Offset + nWritten;
961
962         while (newused >= BufSize) {
963                 va_start(arg_ptr, format);
964                 nWritten = vsnprintf(Buf->buf + Buf->BufUsed, 
965                                      Buf->BufSize - Buf->BufUsed, 
966                                      format, arg_ptr);
967                 va_end(arg_ptr);
968                 newused = Buf->BufUsed + nWritten;
969                 if (newused >= Buf->BufSize) {
970                         if (IncreaseBuf(Buf, 1, newused) == -1)
971                                 return; /* TODO: error handling? */
972                         newused = Buf->BufSize + 1;
973                 }
974                 else {
975                         Buf->BufUsed += nWritten;
976                         BufSize = Buf->BufSize;
977                 }
978
979         }
980 }
981
982 /**
983  * @ingroup StrBuf_Filler
984  * @brief sprintf like function putting the formated string into the buffer
985  * @param Buf Buffer to extend by format and Parameters
986  * @param format printf alike format to add
987  */
988 void StrBufPrintf(StrBuf *Buf, const char *format, ...)
989 {
990         size_t nWritten;
991         va_list arg_ptr;
992         
993         if ((Buf == NULL)  || (format == NULL))
994                 return;
995
996         nWritten = Buf->BufSize + 1;
997         while (nWritten >= Buf->BufSize) {
998                 va_start(arg_ptr, format);
999                 nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
1000                 va_end(arg_ptr);
1001                 if (nWritten >= Buf->BufSize) {
1002                         if (IncreaseBuf(Buf, 0, 0) == -1)
1003                                 return; /* TODO: error handling? */
1004                         nWritten = Buf->BufSize + 1;
1005                         continue;
1006                 }
1007                 Buf->BufUsed = nWritten ;
1008         }
1009 }
1010
1011 /**
1012  * @ingroup StrBuf_Filler
1013  * @brief Callback for cURL to append the webserver reply to a buffer
1014  * @param ptr pre-defined by the cURL API; see man 3 curl for mre info
1015  * @param size pre-defined by the cURL API; see man 3 curl for mre info
1016  * @param nmemb pre-defined by the cURL API; see man 3 curl for mre info
1017  * @param stream pre-defined by the cURL API; see man 3 curl for mre info
1018  */
1019 size_t CurlFillStrBuf_callback(void *ptr, size_t size, size_t nmemb, void *stream)
1020 {
1021
1022         StrBuf *Target;
1023
1024         Target = stream;
1025         if (ptr == NULL)
1026                 return 0;
1027
1028         StrBufAppendBufPlain(Target, ptr, size * nmemb, 0);
1029         return size * nmemb;
1030 }
1031
1032
1033 /**
1034  * @ingroup StrBuf
1035  * @brief extracts a substring from Source into dest
1036  * @param dest buffer to place substring into
1037  * @param Source string to copy substring from
1038  * @param Offset chars to skip from start
1039  * @param nChars number of chars to copy
1040  * @returns the number of chars copied; may be different from nChars due to the size of Source
1041  */
1042 int StrBufSub(StrBuf *dest, const StrBuf *Source, unsigned long Offset, size_t nChars)
1043 {
1044         size_t NCharsRemain;
1045         if (Offset > Source->BufUsed)
1046         {
1047                 if (dest != NULL)
1048                         FlushStrBuf(dest);
1049                 return 0;
1050         }
1051         if (Offset + nChars < Source->BufUsed)
1052         {
1053                 if ((nChars >= dest->BufSize) && 
1054                     (IncreaseBuf(dest, 0, nChars + 1) == -1))
1055                         return 0;
1056                 memcpy(dest->buf, Source->buf + Offset, nChars);
1057                 dest->BufUsed = nChars;
1058                 dest->buf[dest->BufUsed] = '\0';
1059                 return nChars;
1060         }
1061         NCharsRemain = Source->BufUsed - Offset;
1062         if ((NCharsRemain  >= dest->BufSize) && 
1063             (IncreaseBuf(dest, 0, NCharsRemain + 1) == -1))
1064                 return 0;
1065         memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
1066         dest->BufUsed = NCharsRemain;
1067         dest->buf[dest->BufUsed] = '\0';
1068         return NCharsRemain;
1069 }
1070
1071 /**
1072  * @ingroup StrBuf
1073  * @brief Cut nChars from the start of the string
1074  * @param Buf Buffer to modify
1075  * @param nChars how many chars should be skipped?
1076  */
1077 void StrBufCutLeft(StrBuf *Buf, int nChars)
1078 {
1079         if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1080         if (nChars >= Buf->BufUsed) {
1081                 FlushStrBuf(Buf);
1082                 return;
1083         }
1084         memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
1085         Buf->BufUsed -= nChars;
1086         Buf->buf[Buf->BufUsed] = '\0';
1087 }
1088
1089 /**
1090  * @ingroup StrBuf
1091  * @brief Cut the trailing n Chars from the string
1092  * @param Buf Buffer to modify
1093  * @param nChars how many chars should be trunkated?
1094  */
1095 void StrBufCutRight(StrBuf *Buf, int nChars)
1096 {
1097         if ((Buf == NULL) || (Buf->BufUsed == 0) || (Buf->buf == NULL))
1098                 return;
1099
1100         if (nChars >= Buf->BufUsed) {
1101                 FlushStrBuf(Buf);
1102                 return;
1103         }
1104         Buf->BufUsed -= nChars;
1105         Buf->buf[Buf->BufUsed] = '\0';
1106 }
1107
1108 /**
1109  * @ingroup StrBuf
1110  * @brief Cut the string after n Chars
1111  * @param Buf Buffer to modify
1112  * @param AfternChars after how many chars should we trunkate the string?
1113  * @param At if non-null and points inside of our string, cut it there.
1114  */
1115 void StrBufCutAt(StrBuf *Buf, int AfternChars, const char *At)
1116 {
1117         if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1118         if (At != NULL){
1119                 AfternChars = At - Buf->buf;
1120         }
1121
1122         if ((AfternChars < 0) || (AfternChars >= Buf->BufUsed))
1123                 return;
1124         Buf->BufUsed = AfternChars;
1125         Buf->buf[Buf->BufUsed] = '\0';
1126 }
1127
1128
1129 /**
1130  * @ingroup StrBuf
1131  * @brief Strip leading and trailing spaces from a string; with premeasured and adjusted length.
1132  * @param Buf the string to modify
1133  */
1134 void StrBufTrim(StrBuf *Buf)
1135 {
1136         int delta = 0;
1137         if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1138
1139         while ((Buf->BufUsed > 0) &&
1140                isspace(Buf->buf[Buf->BufUsed - 1]))
1141         {
1142                 Buf->BufUsed --;
1143         }
1144         Buf->buf[Buf->BufUsed] = '\0';
1145
1146         if (Buf->BufUsed == 0) return;
1147
1148         while ((Buf->BufUsed > delta) && (isspace(Buf->buf[delta]))){
1149                 delta ++;
1150         }
1151         if (delta > 0) StrBufCutLeft(Buf, delta);
1152 }
1153 /**
1154  * @ingroup StrBuf
1155  * @brief changes all spaces in the string  (tab, linefeed...) to Blank (0x20)
1156  * @param Buf the string to modify
1157  */
1158 void StrBufSpaceToBlank(StrBuf *Buf)
1159 {
1160         char *pche, *pch;
1161
1162         if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1163
1164         pch = Buf->buf;
1165         pche = pch + Buf->BufUsed;
1166         while (pch < pche) 
1167         {
1168                 if (isspace(*pch))
1169                         *pch = ' ';
1170                 pch ++;
1171         }
1172 }
1173
1174 void StrBufStripAllBut(StrBuf *Buf, char leftboundary, char rightboundary)
1175 {
1176         const char *pLeft;
1177         const char *pRight;
1178
1179         if ((Buf == NULL) || (Buf->buf == NULL)) {
1180                 return;
1181         }
1182
1183         pRight = strchr(Buf->buf, rightboundary);
1184         if (pRight != NULL) {
1185                 StrBufCutAt(Buf, 0, pRight);
1186         }
1187         else {
1188                 StrBufCutAt(Buf, 0, Buf->buf);
1189                 return;
1190         }
1191
1192         pLeft = strrchr(ChrPtr(Buf), leftboundary);
1193         if (pLeft != NULL) {
1194                 StrBufCutLeft(Buf, pLeft - Buf->buf + 1);
1195         }
1196         else {
1197                 StrBufCutAt(Buf, 0, Buf->buf);
1198                 return;
1199         }
1200 }
1201
1202
1203 /**
1204  * @ingroup StrBuf_Filler
1205  * @brief uppercase the contents of a buffer
1206  * @param Buf the buffer to translate
1207  */
1208 void StrBufUpCase(StrBuf *Buf) 
1209 {
1210         char *pch, *pche;
1211
1212         if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1213
1214         pch = Buf->buf;
1215         pche = pch + Buf->BufUsed;
1216         while (pch < pche) {
1217                 *pch = toupper(*pch);
1218                 pch ++;
1219         }
1220 }
1221
1222
1223 /**
1224  * @ingroup StrBuf_Filler
1225  * @brief lowercase the contents of a buffer
1226  * @param Buf the buffer to translate
1227  */
1228 void StrBufLowerCase(StrBuf *Buf) 
1229 {
1230         char *pch, *pche;
1231
1232         if ((Buf == NULL) || (Buf->BufUsed == 0)) return;
1233
1234         pch = Buf->buf;
1235         pche = pch + Buf->BufUsed;
1236         while (pch < pche) {
1237                 *pch = tolower(*pch);
1238                 pch ++;
1239         }
1240 }
1241
1242
1243 /*******************************************************************************
1244  *           a tokenizer that kills, maims, and destroys                       *
1245  *******************************************************************************/
1246
1247 /**
1248  * @ingroup StrBuf_Tokenizer
1249  * @brief Replace a token at a given place with a given length by another token with given length
1250  * @param Buf String where to work on
1251  * @param where where inside of the Buf is the search-token
1252  * @param HowLong How long is the token to be replaced
1253  * @param Repl Token to insert at 'where'
1254  * @param ReplLen Length of repl
1255  * @returns -1 if fail else length of resulting Buf
1256  */
1257 int StrBufReplaceToken(StrBuf *Buf, long where, long HowLong, 
1258                        const char *Repl, long ReplLen)
1259 {
1260
1261         if ((Buf == NULL) || 
1262             (where > Buf->BufUsed) ||
1263             (where + HowLong > Buf->BufUsed))
1264                 return -1;
1265
1266         if (where + ReplLen - HowLong > Buf->BufSize)
1267                 if (IncreaseBuf(Buf, 1, Buf->BufUsed + ReplLen) < 0)
1268                         return -1;
1269
1270         memmove(Buf->buf + where + ReplLen, 
1271                 Buf->buf + where + HowLong,
1272                 Buf->BufUsed - where - HowLong);
1273                                                 
1274         memcpy(Buf->buf + where, 
1275                Repl, ReplLen);
1276
1277         Buf->BufUsed += ReplLen - HowLong;
1278
1279         return Buf->BufUsed;
1280 }
1281
1282 /**
1283  * @ingroup StrBuf_Tokenizer
1284  * @brief Counts the numbmer of tokens in a buffer
1285  * @param source String to count tokens in
1286  * @param tok    Tokenizer char to count
1287  * @returns numbers of tokenizer chars found
1288  */
1289 int StrBufNum_tokens(const StrBuf *source, char tok)
1290 {
1291         char *pch, *pche;
1292         long NTokens;
1293         if ((source == NULL) || (source->BufUsed == 0))
1294                 return 0;
1295         if ((source->BufUsed == 1) && (*source->buf == tok))
1296                 return 2;
1297         NTokens = 1;
1298         pch = source->buf;
1299         pche = pch + source->BufUsed;
1300         while (pch < pche)
1301         {
1302                 if (*pch == tok)
1303                         NTokens ++;
1304                 pch ++;
1305         }
1306         return NTokens;
1307 }
1308
1309 /**
1310  * @ingroup StrBuf_Tokenizer
1311  * @brief a string tokenizer
1312  * @param Source StringBuffer to read into
1313  * @param parmnum n'th Parameter to remove
1314  * @param separator tokenizer character
1315  * @returns -1 if not found, else length of token.
1316  */
1317 int StrBufRemove_token(StrBuf *Source, int parmnum, char separator)
1318 {
1319         int ReducedBy;
1320         char *d, *s, *end;              /* dest, source */
1321         int count = 0;
1322
1323         /* Find desired @parameter */
1324         end = Source->buf + Source->BufUsed;
1325         d = Source->buf;
1326         while ((d <= end) && 
1327                (count < parmnum))
1328         {
1329                 /* End of string, bail! */
1330                 if (!*d) {
1331                         d = NULL;
1332                         break;
1333                 }
1334                 if (*d == separator) {
1335                         count++;
1336                 }
1337                 d++;
1338         }
1339         if ((d == NULL) || (d >= end))
1340                 return 0;               /* @Parameter not found */
1341
1342         /* Find next @parameter */
1343         s = d;
1344         while ((s <= end) && 
1345                (*s && *s != separator))
1346         {
1347                 s++;
1348         }
1349         if (*s == separator)
1350                 s++;
1351         ReducedBy = d - s;
1352
1353         /* Hack and slash */
1354         if (s >= end) {
1355                 return 0;
1356         }
1357         else if (*s) {
1358                 memmove(d, s, Source->BufUsed - (s - Source->buf));
1359                 Source->BufUsed += ReducedBy;
1360                 Source->buf[Source->BufUsed] = '\0';
1361         }
1362         else if (d == Source->buf) {
1363                 *d = 0;
1364                 Source->BufUsed = 0;
1365         }
1366         else {
1367                 *--d = '\0';
1368                 Source->BufUsed += ReducedBy;
1369         }
1370         /*
1371         while (*s) {
1372                 *d++ = *s++;
1373         }
1374         *d = 0;
1375         */
1376         return ReducedBy;
1377 }
1378
1379 int StrBufExtract_tokenFromStr(StrBuf *dest, const char *Source, long SourceLen, int parmnum, char separator)
1380 {
1381         const StrBuf Temp = {
1382                 (char*)Source,
1383                 SourceLen,
1384                 SourceLen,
1385                 1
1386 #ifdef SIZE_DEBUG
1387                 ,
1388                 0,
1389                 "",
1390                 ""
1391 #endif
1392         };
1393
1394         return StrBufExtract_token(dest, &Temp, parmnum, separator);
1395 }
1396
1397 /**
1398  * @ingroup StrBuf_Tokenizer
1399  * @brief a string tokenizer
1400  * @param dest Destination StringBuffer
1401  * @param Source StringBuffer to read into
1402  * @param parmnum n'th Parameter to extract
1403  * @param separator tokenizer character
1404  * @returns -1 if not found, else length of token.
1405  */
1406 int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
1407 {
1408         const char *s, *e;              //* source * /
1409         int len = 0;                    //* running total length of extracted string * /
1410         int current_token = 0;          //* token currently being processed * /
1411          
1412         if (dest != NULL) {
1413                 dest->buf[0] = '\0';
1414                 dest->BufUsed = 0;
1415         }
1416         else
1417                 return(-1);
1418
1419         if ((Source == NULL) || (Source->BufUsed ==0)) {
1420                 return(-1);
1421         }
1422         s = Source->buf;
1423         e = s + Source->BufUsed;
1424
1425         //cit_backtrace();
1426         //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
1427
1428         while ((s < e) && !IsEmptyStr(s)) {
1429                 if (*s == separator) {
1430                         ++current_token;
1431                 }
1432                 if (len >= dest->BufSize) {
1433                         dest->BufUsed = len;
1434                         if (IncreaseBuf(dest, 1, -1) < 0) {
1435                                 dest->BufUsed --;
1436                                 break;
1437                         }
1438                 }
1439                 if ( (current_token == parmnum) && 
1440                      (*s != separator)) {
1441                         dest->buf[len] = *s;
1442                         ++len;
1443                 }
1444                 else if (current_token > parmnum) {
1445                         break;
1446                 }
1447                 ++s;
1448         }
1449         
1450         dest->buf[len] = '\0';
1451         dest->BufUsed = len;
1452                 
1453         if (current_token < parmnum) {
1454                 //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
1455                 return(-1);
1456         }
1457         //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
1458         return(len);
1459 }
1460
1461
1462
1463
1464
1465 /**
1466  * @ingroup StrBuf_Tokenizer
1467  * @brief a string tokenizer to fetch an integer
1468  * @param Source String containing tokens
1469  * @param parmnum n'th Parameter to extract
1470  * @param separator tokenizer character
1471  * @returns 0 if not found, else integer representation of the token
1472  */
1473 int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
1474 {
1475         StrBuf tmp;
1476         char buf[64];
1477         
1478         tmp.buf = buf;
1479         buf[0] = '\0';
1480         tmp.BufSize = 64;
1481         tmp.BufUsed = 0;
1482         tmp.ConstBuf = 1;
1483         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
1484                 return(atoi(buf));
1485         else
1486                 return 0;
1487 }
1488
1489 /**
1490  * @ingroup StrBuf_Tokenizer
1491  * @brief a string tokenizer to fetch a long integer
1492  * @param Source String containing tokens
1493  * @param parmnum n'th Parameter to extract
1494  * @param separator tokenizer character
1495  * @returns 0 if not found, else long integer representation of the token
1496  */
1497 long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
1498 {
1499         StrBuf tmp;
1500         char buf[64];
1501         
1502         tmp.buf = buf;
1503         buf[0] = '\0';
1504         tmp.BufSize = 64;
1505         tmp.BufUsed = 0;
1506         tmp.ConstBuf = 1;
1507         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
1508                 return(atoi(buf));
1509         else
1510                 return 0;
1511 }
1512
1513
1514 /**
1515  * @ingroup StrBuf_Tokenizer
1516  * @brief a string tokenizer to fetch an unsigned long
1517  * @param Source String containing tokens
1518  * @param parmnum n'th Parameter to extract
1519  * @param separator tokenizer character
1520  * @returns 0 if not found, else unsigned long representation of the token
1521  */
1522 unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
1523 {
1524         StrBuf tmp;
1525         char buf[64];
1526         char *pnum;
1527         
1528         tmp.buf = buf;
1529         buf[0] = '\0';
1530         tmp.BufSize = 64;
1531         tmp.BufUsed = 0;
1532         tmp.ConstBuf = 1;
1533         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0) {
1534                 pnum = &buf[0];
1535                 if (*pnum == '-')
1536                         pnum ++;
1537                 return (unsigned long) atol(pnum);
1538         }
1539         else 
1540                 return 0;
1541 }
1542
1543
1544
1545 /**
1546  * @ingroup StrBuf_NextTokenizer
1547  * @brief a string tokenizer; Bounds checker
1548  *  function to make shure whether StrBufExtract_NextToken and friends have reached the end of the string.
1549  * @param Source our tokenbuffer
1550  * @param pStart the token iterator pointer to inspect
1551  * @returns whether the revolving pointer is inside of the search range
1552  */
1553 int StrBufHaveNextToken(const StrBuf *Source, const char **pStart)
1554 {
1555         if ((Source == NULL) || 
1556             (*pStart == StrBufNOTNULL) ||
1557             (Source->BufUsed == 0))
1558         {
1559                 return 0;
1560         }
1561         if (*pStart == NULL)
1562         {
1563                 return 1;
1564         }
1565         else if (*pStart > Source->buf + Source->BufUsed)
1566         {
1567                 return 0;
1568         }
1569         else if (*pStart <= Source->buf)
1570         {
1571                 return 0;
1572         }
1573
1574         return 1;
1575 }
1576
1577 /**
1578  * @ingroup StrBuf_NextTokenizer
1579  * @brief a string tokenizer
1580  * @param dest Destination StringBuffer
1581  * @param Source StringBuffer to read into
1582  * @param pStart pointer to the end of the last token. Feed with NULL on start.
1583  * @param separator tokenizer 
1584  * @returns -1 if not found, else length of token.
1585  */
1586 int StrBufExtract_NextToken(StrBuf *dest, const StrBuf *Source, const char **pStart, char separator)
1587 {
1588         const char *s;          /* source */
1589         const char *EndBuffer;  /* end stop of source buffer */
1590         int current_token = 0;  /* token currently being processed */
1591         int len = 0;            /* running total length of extracted string */
1592
1593         if ((Source          == NULL) || 
1594             (Source->BufUsed == 0)      ) 
1595         {
1596                 *pStart = StrBufNOTNULL;
1597                 if (dest != NULL)
1598                         FlushStrBuf(dest);
1599                 return -1;
1600         }
1601          
1602         EndBuffer = Source->buf + Source->BufUsed;
1603
1604         if (dest != NULL) 
1605         {
1606                 dest->buf[0] = '\0';
1607                 dest->BufUsed = 0;
1608         }
1609         else
1610         {
1611                 *pStart = EndBuffer + 1;
1612                 return -1;
1613         }
1614
1615         if (*pStart == NULL)
1616         {
1617                 *pStart = Source->buf; /* we're starting to examine this buffer. */
1618         }
1619         else if ((*pStart < Source->buf) || 
1620                  (*pStart > EndBuffer  )   ) 
1621         {
1622                 return -1; /* no more tokens to find. */
1623         }
1624
1625         s = *pStart;
1626         /* start to find the next token */
1627         while ((s <= EndBuffer)      && 
1628                (current_token == 0) ) 
1629         {
1630                 if (*s == separator) 
1631                 {
1632                         /* we found the next token */
1633                         ++current_token;
1634                 }
1635
1636                 if (len >= dest->BufSize) 
1637                 {
1638                         /* our Dest-buffer isn't big enough, increase it. */
1639                         dest->BufUsed = len;
1640
1641                         if (IncreaseBuf(dest, 1, -1) < 0) {
1642                                 /* WHUT? no more mem? bail out. */
1643                                 s = EndBuffer;
1644                                 dest->BufUsed --;
1645                                 break;
1646                         }
1647                 }
1648
1649                 if ( (current_token == 0 ) &&   /* are we in our target token? */
1650                      (!IsEmptyStr(s)     ) &&
1651                      (separator     != *s)    ) /* don't copy the token itself */
1652                 {
1653                         dest->buf[len] = *s;    /* Copy the payload */
1654                         ++len;                  /* remember the bigger size. */
1655                 }
1656
1657                 ++s;
1658         }
1659
1660         /* did we reach the end? */
1661         if ((s > EndBuffer)) {
1662                 EndBuffer = StrBufNOTNULL;
1663                 *pStart = EndBuffer;
1664         }
1665         else {
1666                 *pStart = s;  /* remember the position for the next run */
1667         }
1668
1669         /* sanitize our extracted token */
1670         dest->buf[len] = '\0';
1671         dest->BufUsed  = len;
1672
1673         return (len);
1674 }
1675
1676
1677 /**
1678  * @ingroup StrBuf_NextTokenizer
1679  * @brief a string tokenizer
1680  * @param Source StringBuffer to read from
1681  * @param pStart pointer to the end of the last token. Feed with NULL.
1682  * @param separator tokenizer character
1683  * @param nTokens number of tokens to fastforward over
1684  * @returns -1 if not found, else length of token.
1685  */
1686 int StrBufSkip_NTokenS(const StrBuf *Source, const char **pStart, char separator, int nTokens)
1687 {
1688         const char *s, *EndBuffer;      //* source * /
1689         int len = 0;                    //* running total length of extracted string * /
1690         int current_token = 0;          //* token currently being processed * /
1691
1692         if ((Source == NULL) || 
1693             (Source->BufUsed ==0)) {
1694                 return(-1);
1695         }
1696         if (nTokens == 0)
1697                 return Source->BufUsed;
1698
1699         if (*pStart == NULL)
1700                 *pStart = Source->buf;
1701
1702         EndBuffer = Source->buf + Source->BufUsed;
1703
1704         if ((*pStart < Source->buf) || 
1705             (*pStart >  EndBuffer)) {
1706                 return (-1);
1707         }
1708
1709
1710         s = *pStart;
1711
1712         //cit_backtrace();
1713         //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
1714
1715         while ((s < EndBuffer) && !IsEmptyStr(s)) {
1716                 if (*s == separator) {
1717                         ++current_token;
1718                 }
1719                 if (current_token >= nTokens) {
1720                         break;
1721                 }
1722                 ++s;
1723         }
1724         *pStart = s;
1725         (*pStart) ++;
1726
1727         return(len);
1728 }
1729
1730 /**
1731  * @ingroup StrBuf_NextTokenizer
1732  * @brief a string tokenizer to fetch an integer
1733  * @param Source StringBuffer to read from
1734  * @param pStart Cursor on the tokenstring
1735  * @param separator tokenizer character
1736  * @returns 0 if not found, else integer representation of the token
1737  */
1738 int StrBufExtractNext_int(const StrBuf* Source, const char **pStart, char separator)
1739 {
1740         StrBuf tmp;
1741         char buf[64];
1742         
1743         tmp.buf = buf;
1744         buf[0] = '\0';
1745         tmp.BufSize = 64;
1746         tmp.BufUsed = 0;
1747         tmp.ConstBuf = 1;
1748         if (StrBufExtract_NextToken(&tmp, Source, pStart, separator) > 0)
1749                 return(atoi(buf));
1750         else
1751                 return 0;
1752 }
1753
1754 /**
1755  * @ingroup StrBuf_NextTokenizer
1756  * @brief a string tokenizer to fetch a long integer
1757  * @param Source StringBuffer to read from
1758  * @param pStart Cursor on the tokenstring
1759  * @param separator tokenizer character
1760  * @returns 0 if not found, else long integer representation of the token
1761  */
1762 long StrBufExtractNext_long(const StrBuf* Source, const char **pStart, char separator)
1763 {
1764         StrBuf tmp;
1765         char buf[64];
1766         
1767         tmp.buf = buf;
1768         buf[0] = '\0';
1769         tmp.BufSize = 64;
1770         tmp.BufUsed = 0;
1771         tmp.ConstBuf = 1;
1772         if (StrBufExtract_NextToken(&tmp, Source, pStart, separator) > 0)
1773                 return(atoi(buf));
1774         else
1775                 return 0;
1776 }
1777
1778
1779 /**
1780  * @ingroup StrBuf_NextTokenizer
1781  * @brief a string tokenizer to fetch an unsigned long
1782  * @param Source StringBuffer to read from
1783  * @param pStart Cursor on the tokenstring
1784  * @param separator tokenizer character
1785  * @returns 0 if not found, else unsigned long representation of the token
1786  */
1787 unsigned long StrBufExtractNext_unsigned_long(const StrBuf* Source, const char **pStart, char separator)
1788 {
1789         StrBuf tmp;
1790         char buf[64];
1791         char *pnum;
1792         
1793         tmp.buf = buf;
1794         buf[0] = '\0';
1795         tmp.BufSize = 64;
1796         tmp.BufUsed = 0;
1797         tmp.ConstBuf = 1;
1798         if (StrBufExtract_NextToken(&tmp, Source, pStart, separator) > 0) {
1799                 pnum = &buf[0];
1800                 if (*pnum == '-')
1801                         pnum ++;
1802                 return (unsigned long) atol(pnum);
1803         }
1804         else 
1805                 return 0;
1806 }
1807
1808
1809
1810
1811
1812 /*******************************************************************************
1813  *                             Escape Appending                                *
1814  *******************************************************************************/
1815
1816 /** 
1817  * @ingroup StrBuf_DeEnCoder
1818  * @brief Escape a string for feeding out as a URL while appending it to a Buffer
1819  * @param OutBuf the output buffer
1820  * @param In Buffer to encode
1821  * @param PlainIn way in from plain old c strings
1822  */
1823 void StrBufUrlescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
1824 {
1825         const char *pch, *pche;
1826         char *pt, *pte;
1827         int len;
1828         
1829         if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
1830                 return;
1831         if (PlainIn != NULL) {
1832                 len = strlen(PlainIn);
1833                 pch = PlainIn;
1834                 pche = pch + len;
1835         }
1836         else {
1837                 pch = In->buf;
1838                 pche = pch + In->BufUsed;
1839                 len = In->BufUsed;
1840         }
1841
1842         if (len == 0) 
1843                 return;
1844
1845         pt = OutBuf->buf + OutBuf->BufUsed;
1846         pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
1847
1848         while (pch < pche) {
1849                 if (pt >= pte) {
1850                         IncreaseBuf(OutBuf, 1, -1);
1851                         pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
1852                         pt = OutBuf->buf + OutBuf->BufUsed;
1853                 }
1854
1855                 if((*pch >= 'a' && *pch <= 'z') ||
1856                    (*pch >= '@' && *pch <= 'Z') || /* @ A-Z */
1857                    (*pch >= '0' && *pch <= ':') || /* 0-9 : */
1858                    (*pch == '!') || (*pch == '_') || 
1859                    (*pch == ',') || (*pch == '.'))
1860                 {
1861                         *(pt++) = *(pch++);
1862                         OutBuf->BufUsed++;
1863                 }                       
1864                 else {
1865                         *pt = '%';
1866                         *(pt + 1) = HexList[(unsigned char)*pch][0];
1867                         *(pt + 2) = HexList[(unsigned char)*pch][1];
1868                         pt += 3;
1869                         OutBuf->BufUsed += 3;
1870                         pch ++;
1871                 }
1872         }
1873         *pt = '\0';
1874 }
1875
1876 /** 
1877  * @ingroup StrBuf_DeEnCoder
1878  * @brief Escape a string for feeding out as a the username/password part of an URL while appending it to a Buffer
1879  * @param OutBuf the output buffer
1880  * @param In Buffer to encode
1881  * @param PlainIn way in from plain old c strings
1882  */
1883 void StrBufUrlescUPAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
1884 {
1885         const char *pch, *pche;
1886         char *pt, *pte;
1887         int len;
1888         
1889         if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
1890                 return;
1891         if (PlainIn != NULL) {
1892                 len = strlen(PlainIn);
1893                 pch = PlainIn;
1894                 pche = pch + len;
1895         }
1896         else {
1897                 pch = In->buf;
1898                 pche = pch + In->BufUsed;
1899                 len = In->BufUsed;
1900         }
1901
1902         if (len == 0) 
1903                 return;
1904
1905         pt = OutBuf->buf + OutBuf->BufUsed;
1906         pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
1907
1908         while (pch < pche) {
1909                 if (pt >= pte) {
1910                         IncreaseBuf(OutBuf, 1, -1);
1911                         pte = OutBuf->buf + OutBuf->BufSize - 4; /**< we max append 3 chars at once plus the \0 */
1912                         pt = OutBuf->buf + OutBuf->BufUsed;
1913                 }
1914
1915                 if((*pch >= 'a' && *pch <= 'z') ||
1916                    (*pch >= 'A' && *pch <= 'Z') || /* A-Z */
1917                    (*pch >= '0' && *pch <= ':') || /* 0-9 : */
1918                    (*pch == '!') || (*pch == '_') || 
1919                    (*pch == ',') || (*pch == '.'))
1920                 {
1921                         *(pt++) = *(pch++);
1922                         OutBuf->BufUsed++;
1923                 }                       
1924                 else {
1925                         *pt = '%';
1926                         *(pt + 1) = HexList[(unsigned char)*pch][0];
1927                         *(pt + 2) = HexList[(unsigned char)*pch][1];
1928                         pt += 3;
1929                         OutBuf->BufUsed += 3;
1930                         pch ++;
1931                 }
1932         }
1933         *pt = '\0';
1934 }
1935
1936 /** 
1937  * @ingroup StrBuf_DeEnCoder
1938  * @brief append a string in hex encoding to the buffer
1939  * @param OutBuf the output buffer
1940  * @param In Buffer to encode
1941  * @param PlainIn way in from plain old c strings
1942  * @param PlainInLen way in from plain old c strings; maybe you've got binary data or know the length?
1943  */
1944 void StrBufHexEscAppend(StrBuf *OutBuf, const StrBuf *In, const unsigned char *PlainIn, long PlainInLen)
1945 {
1946         const unsigned char *pch, *pche;
1947         char *pt, *pte;
1948         int len;
1949         
1950         if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
1951                 return;
1952         if (PlainIn != NULL) {
1953                 if (PlainInLen < 0)
1954                         len = strlen((const char*)PlainIn);
1955                 else
1956                         len = PlainInLen;
1957                 pch = PlainIn;
1958                 pche = pch + len;
1959         }
1960         else {
1961                 pch = (const unsigned char*)In->buf;
1962                 pche = pch + In->BufUsed;
1963                 len = In->BufUsed;
1964         }
1965
1966         if (len == 0) 
1967                 return;
1968
1969         pt = OutBuf->buf + OutBuf->BufUsed;
1970         pte = OutBuf->buf + OutBuf->BufSize - 3; /**< we max append 3 chars at once plus the \0 */
1971
1972         while (pch < pche) {
1973                 if (pt >= pte) {
1974                         IncreaseBuf(OutBuf, 1, -1);
1975                         pte = OutBuf->buf + OutBuf->BufSize - 3; /**< we max append 3 chars at once plus the \0 */
1976                         pt = OutBuf->buf + OutBuf->BufUsed;
1977                 }
1978
1979                 *pt = HexList[*pch][0];
1980                 pt ++;
1981                 *pt = HexList[*pch][1];
1982                 pt ++; pch ++; OutBuf->BufUsed += 2;
1983         }
1984         *pt = '\0';
1985 }
1986
1987 void StrBufBase64Append(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn, long PlainInLen, int linebreaks)
1988 {
1989         const char *pch;
1990         char *pt;
1991         int len;
1992         long ExpectLen;
1993         
1994         if (((In == NULL) && (PlainIn == NULL)) || (OutBuf == NULL) )
1995                 return;
1996         if (PlainIn != NULL) {
1997                 if (PlainInLen < 0)
1998                         len = strlen(PlainIn);
1999                 else
2000                         len = PlainInLen;
2001                 pch = PlainIn;
2002         }
2003         else {
2004                 pch = In->buf;
2005                 len = In->BufUsed;
2006         }
2007
2008         if (len == 0) 
2009                 return;
2010
2011         ExpectLen = ((len * 134) / 100) + OutBuf->BufUsed;
2012
2013         if (ExpectLen > OutBuf->BufSize)
2014                 if (IncreaseBuf(OutBuf, 1, ExpectLen) < ExpectLen)
2015                         return;
2016
2017         pt = OutBuf->buf + OutBuf->BufUsed;
2018
2019         len = CtdlEncodeBase64(pt, pch, len, linebreaks);
2020
2021         pt += len;
2022         OutBuf->BufUsed += len;
2023         *pt = '\0';
2024 }
2025
2026 /** 
2027  * @ingroup StrBuf_DeEnCoder
2028  * @brief append a string in hex encoding to the buffer
2029  * @param OutBuf the output buffer
2030  * @param In Buffer to encode
2031  * @param PlainIn way in from plain old c strings
2032  */
2033 void StrBufHexescAppend(StrBuf *OutBuf, const StrBuf *In, const char *PlainIn)
2034 {
2035         StrBufHexEscAppend(OutBuf, In, (const unsigned char*) PlainIn, -1);
2036 }
2037
2038 /**
2039  * @ingroup StrBuf_DeEnCoder
2040  * @brief Append a string, escaping characters which have meaning in HTML.  
2041  *
2042  * @param Target        target buffer
2043  * @param Source        source buffer; set to NULL if you just have a C-String
2044  * @param PlainIn       Plain-C string to append; set to NULL if unused
2045  * @param nbsp          If nonzero, spaces are converted to non-breaking spaces.
2046  * @param nolinebreaks  if set to 1, linebreaks are removed from the string.
2047  *                      if set to 2, linebreaks are replaced by &ltbr/&gt
2048  */
2049 long StrEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
2050 {
2051         const char *aptr, *eiptr;
2052         char *bptr, *eptr;
2053         long len;
2054
2055         if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
2056                 return -1;
2057
2058         if (PlainIn != NULL) {
2059                 aptr = PlainIn;
2060                 len = strlen(PlainIn);
2061                 eiptr = aptr + len;
2062         }
2063         else {
2064                 aptr = Source->buf;
2065                 eiptr = aptr + Source->BufUsed;
2066                 len = Source->BufUsed;
2067         }
2068
2069         if (len == 0) 
2070                 return -1;
2071
2072         bptr = Target->buf + Target->BufUsed;
2073         eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in...  */
2074
2075         while (aptr < eiptr){
2076                 if(bptr >= eptr) {
2077                         IncreaseBuf(Target, 1, -1);
2078                         eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in...  */
2079                         bptr = Target->buf + Target->BufUsed;
2080                 }
2081                 if (*aptr == '<') {
2082                         memcpy(bptr, "&lt;", 4);
2083                         bptr += 4;
2084                         Target->BufUsed += 4;
2085                 }
2086                 else if (*aptr == '>') {
2087                         memcpy(bptr, "&gt;", 4);
2088                         bptr += 4;
2089                         Target->BufUsed += 4;
2090                 }
2091                 else if (*aptr == '&') {
2092                         memcpy(bptr, "&amp;", 5);
2093                         bptr += 5;
2094                         Target->BufUsed += 5;
2095                 }
2096                 else if (*aptr == '"') {
2097                         memcpy(bptr, "&quot;", 6);
2098                         bptr += 6;
2099                         Target->BufUsed += 6;
2100                 }
2101                 else if (*aptr == '\'') {
2102                         memcpy(bptr, "&#39;", 5);
2103                         bptr += 5;
2104                         Target->BufUsed += 5;
2105                 }
2106                 else if (*aptr == LB) {
2107                         *bptr = '<';
2108                         bptr ++;
2109                         Target->BufUsed ++;
2110                 }
2111                 else if (*aptr == RB) {
2112                         *bptr = '>';
2113                         bptr ++;
2114                         Target->BufUsed ++;
2115                 }
2116                 else if (*aptr == QU) {
2117                         *bptr ='"';
2118                         bptr ++;
2119                         Target->BufUsed ++;
2120                 }
2121                 else if ((*aptr == 32) && (nbsp == 1)) {
2122                         memcpy(bptr, "&nbsp;", 6);
2123                         bptr += 6;
2124                         Target->BufUsed += 6;
2125                 }
2126                 else if ((*aptr == '\n') && (nolinebreaks == 1)) {
2127                         *bptr='\0';     /* nothing */
2128                 }
2129                 else if ((*aptr == '\n') && (nolinebreaks == 2)) {
2130                         memcpy(bptr, "&lt;br/&gt;", 11);
2131                         bptr += 11;
2132                         Target->BufUsed += 11;
2133                 }
2134
2135
2136                 else if ((*aptr == '\r') && (nolinebreaks != 0)) {
2137                         *bptr='\0';     /* nothing */
2138                 }
2139                 else{
2140                         *bptr = *aptr;
2141                         bptr++;
2142                         Target->BufUsed ++;
2143                 }
2144                 aptr ++;
2145         }
2146         *bptr = '\0';
2147         if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
2148                 return -1;
2149         return Target->BufUsed;
2150 }
2151
2152 /**
2153  * @ingroup StrBuf_DeEnCoder
2154  * @brief Append a string, escaping characters which have meaning in HTML.  
2155  * Converts linebreaks into blanks; escapes single quotes
2156  * @param Target        target buffer
2157  * @param Source        source buffer; set to NULL if you just have a C-String
2158  * @param PlainIn       Plain-C string to append; set to NULL if unused
2159  */
2160 void StrMsgEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
2161 {
2162         const char *aptr, *eiptr;
2163         char *tptr, *eptr;
2164         long len;
2165
2166         if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
2167                 return ;
2168
2169         if (PlainIn != NULL) {
2170                 aptr = PlainIn;
2171                 len = strlen(PlainIn);
2172                 eiptr = aptr + len;
2173         }
2174         else {
2175                 aptr = Source->buf;
2176                 eiptr = aptr + Source->BufUsed;
2177                 len = Source->BufUsed;
2178         }
2179
2180         if (len == 0) 
2181                 return;
2182
2183         eptr = Target->buf + Target->BufSize - 8; 
2184         tptr = Target->buf + Target->BufUsed;
2185         
2186         while (aptr < eiptr){
2187                 if(tptr >= eptr) {
2188                         IncreaseBuf(Target, 1, -1);
2189                         eptr = Target->buf + Target->BufSize - 8; 
2190                         tptr = Target->buf + Target->BufUsed;
2191                 }
2192                
2193                 if (*aptr == '\n') {
2194                         *tptr = ' ';
2195                         Target->BufUsed++;
2196                 }
2197                 else if (*aptr == '\r') {
2198                         *tptr = ' ';
2199                         Target->BufUsed++;
2200                 }
2201                 else if (*aptr == '\'') {
2202                         *(tptr++) = '&';
2203                         *(tptr++) = '#';
2204                         *(tptr++) = '3';
2205                         *(tptr++) = '9';
2206                         *tptr = ';';
2207                         Target->BufUsed += 5;
2208                 } else {
2209                         *tptr = *aptr;
2210                         Target->BufUsed++;
2211                 }
2212                 tptr++; aptr++;
2213         }
2214         *tptr = '\0';
2215 }
2216
2217
2218
2219 /**
2220  * @ingroup StrBuf_DeEnCoder
2221  * @brief Append a string, escaping characters which have meaning in ICAL.  
2222  * [\n,] 
2223  * @param Target        target buffer
2224  * @param Source        source buffer; set to NULL if you just have a C-String
2225  * @param PlainIn       Plain-C string to append; set to NULL if unused
2226  */
2227 void StrIcalEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
2228 {
2229         const char *aptr, *eiptr;
2230         char *tptr, *eptr;
2231         long len;
2232
2233         if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
2234                 return ;
2235
2236         if (PlainIn != NULL) {
2237                 aptr = PlainIn;
2238                 len = strlen(PlainIn);
2239                 eiptr = aptr + len;
2240         }
2241         else {
2242                 aptr = Source->buf;
2243                 eiptr = aptr + Source->BufUsed;
2244                 len = Source->BufUsed;
2245         }
2246
2247         if (len == 0) 
2248                 return;
2249
2250         eptr = Target->buf + Target->BufSize - 8; 
2251         tptr = Target->buf + Target->BufUsed;
2252         
2253         while (aptr < eiptr){
2254                 if(tptr + 3 >= eptr) {
2255                         IncreaseBuf(Target, 1, -1);
2256                         eptr = Target->buf + Target->BufSize - 8; 
2257                         tptr = Target->buf + Target->BufUsed;
2258                 }
2259                
2260                 if (*aptr == '\n') {
2261                         *tptr = '\\';
2262                         Target->BufUsed++;
2263                         tptr++;
2264                         *tptr = 'n';
2265                         Target->BufUsed++;
2266                 }
2267                 else if (*aptr == '\r') {
2268                         *tptr = '\\';
2269                         Target->BufUsed++;
2270                         tptr++;
2271                         *tptr = 'r';
2272                         Target->BufUsed++;
2273                 }
2274                 else if (*aptr == ',') {
2275                         *tptr = '\\';
2276                         Target->BufUsed++;
2277                         tptr++;
2278                         *tptr = ',';
2279                         Target->BufUsed++;
2280                 } else {
2281                         *tptr = *aptr;
2282                         Target->BufUsed++;
2283                 }
2284                 tptr++; aptr++;
2285         }
2286         *tptr = '\0';
2287 }
2288
2289 /**
2290  * @ingroup StrBuf_DeEnCoder
2291  * @brief Append a string, escaping characters which have meaning in JavaScript strings .  
2292  *
2293  * @param Target        target buffer
2294  * @param Source        source buffer; set to NULL if you just have a C-String
2295  * @param PlainIn       Plain-C string to append; set to NULL if unused
2296  * @returns size of result or -1
2297  */
2298 long StrECMAEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn)
2299 {
2300         const char *aptr, *eiptr;
2301         char *bptr, *eptr;
2302         long len;
2303         int IsUtf8Sequence;
2304
2305         if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
2306                 return -1;
2307
2308         if (PlainIn != NULL) {
2309                 aptr = PlainIn;
2310                 len = strlen(PlainIn);
2311                 eiptr = aptr + len;
2312         }
2313         else {
2314                 aptr = Source->buf;
2315                 eiptr = aptr + Source->BufUsed;
2316                 len = Source->BufUsed;
2317         }
2318
2319         if (len == 0) 
2320                 return -1;
2321
2322         bptr = Target->buf + Target->BufUsed;
2323         eptr = Target->buf + Target->BufSize - 7; /* our biggest unit to put in...  */
2324
2325         while (aptr < eiptr){
2326                 if(bptr >= eptr) {
2327                         IncreaseBuf(Target, 1, -1);
2328                         eptr = Target->buf + Target->BufSize - 7; /* our biggest unit to put in...  */
2329                         bptr = Target->buf + Target->BufUsed;
2330                 }
2331                 switch (*aptr) {
2332                 case '\n':
2333                         memcpy(bptr, HKEY("\\n"));
2334                         bptr += 2;
2335                         Target->BufUsed += 2;                           
2336                         break;
2337                 case '\r':
2338                         memcpy(bptr, HKEY("\\r"));
2339                         bptr += 2;
2340                         Target->BufUsed += 2;
2341                         break;
2342                 case '"':
2343                         *bptr = '\\';
2344                         bptr ++;
2345                         *bptr = '"';
2346                         bptr ++;
2347                         Target->BufUsed += 2;
2348                         break;
2349                 case '\\':
2350                         if ((*(aptr + 1) == 'u') &&
2351                             isxdigit(*(aptr + 2)) &&
2352                             isxdigit(*(aptr + 3)) &&
2353                             isxdigit(*(aptr + 4)) &&
2354                             isxdigit(*(aptr + 5)))
2355                         { /* oh, a unicode escaper. let it pass through. */
2356                                 memcpy(bptr, aptr, 6);
2357                                 aptr += 5;
2358                                 bptr +=6;
2359                                 Target->BufUsed += 6;
2360                         }
2361                         else 
2362                         {
2363                                 *bptr = '\\';
2364                                 bptr ++;
2365                                 *bptr = '\\';
2366                                 bptr ++;
2367                                 Target->BufUsed += 2;
2368                         }
2369                         break;
2370                 case '\b':
2371                         *bptr = '\\';
2372                         bptr ++;
2373                         *bptr = 'b';
2374                         bptr ++;
2375                         Target->BufUsed += 2;
2376                         break;
2377                 case '\f':
2378                         *bptr = '\\';
2379                         bptr ++;
2380                         *bptr = 'f';
2381                         bptr ++;
2382                         Target->BufUsed += 2;
2383                         break;
2384                 case '\t':
2385                         *bptr = '\\';
2386                         bptr ++;
2387                         *bptr = 't';
2388                         bptr ++;
2389                         Target->BufUsed += 2;
2390                         break;
2391                 default:
2392                         IsUtf8Sequence =  Ctdl_GetUtf8SequenceLength(aptr, eiptr);
2393                         while (IsUtf8Sequence > 0){
2394                                 *bptr = *aptr;
2395                                 Target->BufUsed ++;
2396                                 if (--IsUtf8Sequence)
2397                                         aptr++;
2398                                 bptr++;
2399                         }
2400                 }
2401                 aptr ++;
2402         }
2403         *bptr = '\0';
2404         if ((bptr == eptr - 1 ) && !IsEmptyStr(aptr) )
2405                 return -1;
2406         return Target->BufUsed;
2407 }
2408
2409 /**
2410  * @ingroup StrBuf_DeEnCoder
2411  * @brief Append a string, escaping characters which have meaning in HTML + json.  
2412  *
2413  * @param Target        target buffer
2414  * @param Source        source buffer; set to NULL if you just have a C-String
2415  * @param PlainIn       Plain-C string to append; set to NULL if unused
2416  * @param nbsp          If nonzero, spaces are converted to non-breaking spaces.
2417  * @param nolinebreaks  if set to 1, linebreaks are removed from the string.
2418  *                      if set to 2, linebreaks are replaced by &ltbr/&gt
2419  */
2420 long StrHtmlEcmaEscAppend(StrBuf *Target, const StrBuf *Source, const char *PlainIn, int nbsp, int nolinebreaks)
2421 {
2422         const char *aptr, *eiptr;
2423         char *bptr, *eptr;
2424         long len;
2425         int IsUtf8Sequence = 0;
2426
2427         if (((Source == NULL) && (PlainIn == NULL)) || (Target == NULL) )
2428                 return -1;
2429
2430         if (PlainIn != NULL) {
2431                 aptr = PlainIn;
2432                 len = strlen(PlainIn);
2433                 eiptr = aptr + len;
2434         }
2435         else {
2436                 aptr = Source->buf;
2437                 eiptr = aptr + Source->BufUsed;
2438                 len = Source->BufUsed;
2439         }
2440
2441         if (len == 0) 
2442                 return -1;
2443
2444         bptr = Target->buf + Target->BufUsed;
2445         eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in...  */
2446
2447         while (aptr < eiptr){
2448                 if(bptr >= eptr) {
2449                         IncreaseBuf(Target, 1, -1);
2450                         eptr = Target->buf + Target->BufSize - 11; /* our biggest unit to put in...  */
2451                         bptr = Target->buf + Target->BufUsed;
2452                 }
2453                 switch (*aptr) {
2454                 case '<':
2455                         memcpy(bptr, HKEY("&lt;"));
2456                         bptr += 4;
2457                         Target->BufUsed += 4;
2458                         break;
2459                 case '>':
2460                         memcpy(bptr, HKEY("&gt;"));
2461                         bptr += 4;
2462                         Target->BufUsed += 4;
2463                         break;
2464                 case '&':
2465                         memcpy(bptr, HKEY("&amp;"));
2466                         bptr += 5;
2467                         Target->BufUsed += 5;
2468                         break;
2469                 case LB:
2470                         *bptr = '<';
2471                         bptr ++;
2472                         Target->BufUsed ++;
2473                         break;
2474                 case RB:
2475                         *bptr = '>';
2476                         bptr ++;
2477                         Target->BufUsed ++;
2478                         break;
2479                 case '\n':
2480                         switch (nolinebreaks) {
2481                         case 1:
2482                                 *bptr='\0';     /* nothing */
2483                                 break;
2484                         case 2:
2485                                 memcpy(bptr, HKEY("&lt;br/&gt;"));
2486                                 bptr += 11;
2487                                 Target->BufUsed += 11;
2488                                 break;
2489                         default:
2490                                 memcpy(bptr, HKEY("\\n"));
2491                                 bptr += 2;
2492                                 Target->BufUsed += 2;                           
2493                         }
2494                         break;
2495                 case '\r':
2496                         switch (nolinebreaks) {
2497                         case 1:
2498                         case 2:
2499                                 *bptr='\0';     /* nothing */
2500                                 break;
2501                         default:
2502                                 memcpy(bptr, HKEY("\\r"));
2503                                 bptr += 2;
2504                                 Target->BufUsed += 2;
2505                                 break;
2506                         }
2507                         break;
2508                 case '"':
2509                 case QU:
2510                         *bptr = '\\';
2511                         bptr ++;
2512                         *bptr = '"';
2513                         bptr ++;
2514                         Target->BufUsed += 2;
2515                         break;
2516                 case '\\':
2517                         if ((*(aptr + 1) == 'u') &&
2518                             isxdigit(*(aptr + 2)) &&
2519                             isxdigit(*(aptr + 3)) &&
2520                             isxdigit(*(aptr + 4)) &&
2521                             isxdigit(*(aptr + 5)))
2522                         { /* oh, a unicode escaper. let it pass through. */
2523                                 memcpy(bptr, aptr, 6);
2524                                 aptr += 5;
2525                                 bptr +=6;
2526                                 Target->BufUsed += 6;
2527                         }
2528                         else 
2529                         {
2530                                 *bptr = '\\';
2531                                 bptr ++;
2532                                 *bptr = '\\';
2533                                 bptr ++;
2534                                 Target->BufUsed += 2;
2535                         }
2536                         break;
2537                 case '\b':
2538                         *bptr = '\\';
2539                         bptr ++;
2540                         *bptr = 'b';
2541                         bptr ++;
2542                         Target->BufUsed += 2;
2543                         break;
2544                 case '\f':
2545                         *bptr = '\\';
2546                         bptr ++;
2547                         *bptr = 'f';
2548                         bptr ++;
2549                         Target->BufUsed += 2;
2550                         break;
2551                 case '\t':
2552                         *bptr = '\\';
2553                         bptr ++;
2554                         *bptr = 't';
2555                         bptr ++;
2556                         Target->BufUsed += 2;
2557                         break;
2558                 case  32:
2559                         if (nbsp == 1) {
2560                                 memcpy(bptr, HKEY("&nbsp;"));
2561                                 bptr += 6;
2562                                 Target->BufUsed += 6;
2563                                 break;
2564                         }
2565                 default:
2566                         IsUtf8Sequence =  Ctdl_GetUtf8SequenceLength(aptr, eiptr);
2567                         while (IsUtf8Sequence > 0){
2568                                 *bptr = *aptr;
2569                                 Target->BufUsed ++;
2570                                 if (--IsUtf8Sequence)
2571                                         aptr++;
2572                                 bptr++;
2573                         }
2574                 }
2575                 aptr ++;
2576         }
2577         *bptr = '\0';
2578         if ((bptr = eptr - 1 ) && !IsEmptyStr(aptr) )
2579                 return -1;
2580         return Target->BufUsed;
2581 }
2582
2583
2584 /**
2585  * @ingroup StrBuf_DeEnCoder
2586  * @brief replace all non-Ascii characters by another
2587  * @param Buf buffer to inspect
2588  * @param repl charater to stamp over non ascii chars
2589  */
2590 void StrBufAsciify(StrBuf *Buf, const char repl)
2591 {
2592         long offset;
2593
2594         for (offset = 0; offset < Buf->BufUsed; offset ++)
2595                 if (!isascii(Buf->buf[offset]))
2596                         Buf->buf[offset] = repl;
2597         
2598 }
2599
2600 /**
2601  * @ingroup StrBuf_DeEnCoder
2602  * @brief unhide special chars hidden to the HTML escaper
2603  * @param target buffer to put the unescaped string in
2604  * @param source buffer to unescape
2605  */
2606 void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source) 
2607 {
2608         int a, b, len;
2609         char hex[3];
2610
2611         if ((source == NULL) || (target == NULL) || (target->buf == NULL))
2612         {
2613                 return;
2614         }
2615
2616         if (target != NULL)
2617                 FlushStrBuf(target);
2618
2619         len = source->BufUsed;
2620         for (a = 0; a < len; ++a) {
2621                 if (target->BufUsed >= target->BufSize)
2622                         IncreaseBuf(target, 1, -1);
2623
2624                 if (source->buf[a] == '=') {
2625                         hex[0] = source->buf[a + 1];
2626                         hex[1] = source->buf[a + 2];
2627                         hex[2] = 0;
2628                         b = 0;
2629                         sscanf(hex, "%02x", &b);
2630                         target->buf[target->BufUsed] = b;
2631                         target->buf[++target->BufUsed] = 0;
2632                         a += 2;
2633                 }
2634                 else {
2635                         target->buf[target->BufUsed] = source->buf[a];
2636                         target->buf[++target->BufUsed] = 0;
2637                 }
2638         }
2639 }
2640
2641
2642 /**
2643  * @ingroup StrBuf_DeEnCoder
2644  * @brief hide special chars from the HTML escapers and friends
2645  * @param target buffer to put the escaped string in
2646  * @param source buffer to escape
2647  */
2648 void StrBufEUid_escapize(StrBuf *target, const StrBuf *source) 
2649 {
2650         int i, len;
2651
2652         if (target != NULL)
2653                 FlushStrBuf(target);
2654
2655         if ((source == NULL) || (target == NULL) || (target->buf == NULL))
2656         {
2657                 return;
2658         }
2659
2660         len = source->BufUsed;
2661         for (i=0; i<len; ++i) {
2662                 if (target->BufUsed + 4 >= target->BufSize)
2663                         IncreaseBuf(target, 1, -1);
2664                 if ( (isalnum(source->buf[i])) || 
2665                      (source->buf[i]=='-') || 
2666                      (source->buf[i]=='_') ) {
2667                         target->buf[target->BufUsed++] = source->buf[i];
2668                 }
2669                 else {
2670                         sprintf(&target->buf[target->BufUsed], 
2671                                 "=%02X", 
2672                                 (0xFF &source->buf[i]));
2673                         target->BufUsed += 3;
2674                 }
2675         }
2676         target->buf[target->BufUsed + 1] = '\0';
2677 }
2678
2679
2680 /*******************************************************************************
2681  *                      Quoted Printable de/encoding                           *
2682  *******************************************************************************/
2683
2684 /**
2685  * @ingroup StrBuf_DeEnCoder
2686  * @brief decode a buffer from base 64 encoding; destroys original
2687  * @param Buf Buffor to transform
2688  */
2689 int StrBufDecodeBase64(StrBuf *Buf)
2690 {
2691         char *xferbuf;
2692         size_t siz;
2693
2694         if (Buf == NULL)
2695                 return -1;
2696
2697         xferbuf = (char*) malloc(Buf->BufSize);
2698         if (xferbuf == NULL)
2699                 return -1;
2700
2701         *xferbuf = '\0';
2702         siz = CtdlDecodeBase64(xferbuf,
2703                                Buf->buf,
2704                                Buf->BufUsed);
2705         free(Buf->buf);
2706         Buf->buf = xferbuf;
2707         Buf->BufUsed = siz;
2708         return siz;
2709 }
2710
2711 /**
2712  * @ingroup StrBuf_DeEnCoder
2713  * @brief decode a buffer from base 64 encoding; destroys original
2714  * @param Buf Buffor to transform
2715  */
2716 int StrBufDecodeHex(StrBuf *Buf)
2717 {
2718         unsigned int ch;
2719         char *pch, *pche, *pchi;
2720
2721         if (Buf == NULL) return -1;
2722
2723         pch = pchi = Buf->buf;
2724         pche = pch + Buf->BufUsed;
2725
2726         while (pchi < pche){
2727                 ch = decode_hex(pchi);
2728                 *pch = ch;
2729                 pch ++;
2730                 pchi += 2;
2731         }
2732
2733         *pch = '\0';
2734         Buf->BufUsed = pch - Buf->buf;
2735         return Buf->BufUsed;
2736 }
2737
2738 /**
2739  * @ingroup StrBuf_DeEnCoder
2740  * @brief replace all chars >0x20 && < 0x7F with Mute
2741  * @param Mute char to put over invalid chars
2742  * @param Buf Buffor to transform
2743  */
2744 int StrBufSanitizeAscii(StrBuf *Buf, const char Mute)
2745 {
2746         unsigned char *pch;
2747
2748         if (Buf == NULL) return -1;
2749         pch = (unsigned char *)Buf->buf;
2750         while (pch < (unsigned char *)Buf->buf + Buf->BufUsed) {
2751                 if ((*pch < 0x20) || (*pch > 0x7F))
2752                         *pch = Mute;
2753                 pch ++;
2754         }
2755         return Buf->BufUsed;
2756 }
2757
2758
2759 /**
2760  * @ingroup StrBuf_DeEnCoder
2761  * @brief remove escaped strings from i.e. the url string (like %20 for blanks)
2762  * @param Buf Buffer to translate
2763  * @param StripBlanks Reduce several blanks to one?
2764  */
2765 long StrBufUnescape(StrBuf *Buf, int StripBlanks)
2766 {
2767         int a, b;
2768         char hex[3];
2769         long len;
2770
2771         if (Buf == NULL)
2772                 return -1;
2773
2774         while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
2775                 Buf->buf[Buf->BufUsed - 1] = '\0';
2776                 Buf->BufUsed --;
2777         }
2778
2779         a = 0; 
2780         while (a < Buf->BufUsed) {
2781                 if (Buf->buf[a] == '+')
2782                         Buf->buf[a] = ' ';
2783                 else if (Buf->buf[a] == '%') {
2784                         /* don't let % chars through, rather truncate the input. */
2785                         if (a + 2 > Buf->BufUsed) {
2786                                 Buf->buf[a] = '\0';
2787                                 Buf->BufUsed = a;
2788                         }
2789                         else {                  
2790                                 hex[0] = Buf->buf[a + 1];
2791                                 hex[1] = Buf->buf[a + 2];
2792                                 hex[2] = 0;
2793                                 b = 0;
2794                                 sscanf(hex, "%02x", &b);
2795                                 Buf->buf[a] = (char) b;
2796                                 len = Buf->BufUsed - a - 2;
2797                                 if (len > 0)
2798                                         memmove(&Buf->buf[a + 1], &Buf->buf[a + 3], len);
2799                         
2800                                 Buf->BufUsed -=2;
2801                         }
2802                 }
2803                 a++;
2804         }
2805         return a;
2806 }
2807
2808
2809 /**
2810  * @ingroup StrBuf_DeEnCoder
2811  * @brief       RFC2047-encode a header field if necessary.
2812  *              If no non-ASCII characters are found, the string
2813  *              will be copied verbatim without encoding.
2814  *
2815  * @param       target          Target buffer.
2816  * @param       source          Source string to be encoded.
2817  * @returns     encoded length; -1 if non success.
2818  */
2819 int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
2820 {
2821         const char headerStr[] = "=?UTF-8?Q?";
2822         int need_to_encode = 0;
2823         int i = 0;
2824         unsigned char ch;
2825
2826         if ((source == NULL) || 
2827             (target == NULL))
2828             return -1;
2829
2830         while ((i < source->BufUsed) &&
2831                (!IsEmptyStr (&source->buf[i])) &&
2832                (need_to_encode == 0)) {
2833                 if (((unsigned char) source->buf[i] < 32) || 
2834                     ((unsigned char) source->buf[i] > 126)) {
2835                         need_to_encode = 1;
2836                 }
2837                 i++;
2838         }
2839
2840         if (!need_to_encode) {
2841                 if (*target == NULL) {
2842                         *target = NewStrBufPlain(source->buf, source->BufUsed);
2843                 }
2844                 else {
2845                         FlushStrBuf(*target);
2846                         StrBufAppendBuf(*target, source, 0);
2847                 }
2848                 if (*target != 0)
2849                         return (*target)->BufUsed;
2850                 else
2851                         return 0;
2852         }
2853         if (*target == NULL)
2854                 *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
2855         else if (sizeof(headerStr) + source->BufUsed >= (*target)->BufSize)
2856                 IncreaseBuf(*target, sizeof(headerStr) + source->BufUsed, 0);
2857         memcpy ((*target)->buf, headerStr, sizeof(headerStr) - 1);
2858         (*target)->BufUsed = sizeof(headerStr) - 1;
2859         for (i=0; (i < source->BufUsed); ++i) {
2860                 if ((*target)->BufUsed + 4 >= (*target)->BufSize)
2861                         IncreaseBuf(*target, 1, 0);
2862                 ch = (unsigned char) source->buf[i];
2863                 if ((ch  <  32) || 
2864                     (ch  > 126) || 
2865                     (ch ==  61) ||
2866                     (ch == '=') ||
2867                     (ch == '?') ||
2868                     (ch == '_') ||
2869                     (ch == '[') ||
2870                     (ch == ']')   )
2871                 {
2872                         sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
2873                         (*target)->BufUsed += 3;
2874                 }
2875                 else {
2876                         if (ch == ' ')
2877                                 (*target)->buf[(*target)->BufUsed] = '_';
2878                         else
2879                                 (*target)->buf[(*target)->BufUsed] = ch;
2880                         (*target)->BufUsed++;
2881                 }
2882         }
2883         
2884         if ((*target)->BufUsed + 4 >= (*target)->BufSize)
2885                 IncreaseBuf(*target, 1, 0);
2886
2887         (*target)->buf[(*target)->BufUsed++] = '?';
2888         (*target)->buf[(*target)->BufUsed++] = '=';
2889         (*target)->buf[(*target)->BufUsed] = '\0';
2890         return (*target)->BufUsed;;
2891 }
2892
2893
2894
2895 static void AddRecipient(StrBuf *Target, 
2896                          StrBuf *UserName, 
2897                          StrBuf *EmailAddress, 
2898                          StrBuf *EncBuf)
2899 {
2900         int QuoteMe = 0;
2901
2902         if (StrLength(Target) > 0) StrBufAppendBufPlain(Target, HKEY(", "), 0);
2903         if (strchr(ChrPtr(UserName), ',') != NULL) QuoteMe = 1;
2904
2905         if (QuoteMe)  StrBufAppendBufPlain(Target, HKEY("\""), 0);
2906         StrBufRFC2047encode(&EncBuf, UserName);
2907         StrBufAppendBuf(Target, EncBuf, 0);
2908         if (QuoteMe)  StrBufAppendBufPlain(Target, HKEY("\" "), 0);
2909         else          StrBufAppendBufPlain(Target, HKEY(" "), 0);
2910
2911         if (StrLength(EmailAddress) > 0){
2912                 StrBufAppendBufPlain(Target, HKEY("<"), 0);
2913                 StrBufAppendBuf(Target, EmailAddress, 0); /* TODO: what about IDN???? */
2914                 StrBufAppendBufPlain(Target, HKEY(">"), 0);
2915         }
2916 }
2917
2918
2919 /**
2920  * \brief QP encode parts of an email TO/CC/BCC vector, and strip/filter invalid parts
2921  * \param Recp Source list of email recipients
2922  * \param UserName Temporary buffer for internal use; Please provide valid buffer.
2923  * \param EmailAddress Temporary buffer for internal use; Please provide valid buffer.
2924  * \param EncBuf Temporary buffer for internal use; Please provide valid buffer.
2925  * \returns encoded & sanitized buffer with the contents of Recp; Caller owns this memory.
2926  */
2927 StrBuf *StrBufSanitizeEmailRecipientVector(const StrBuf *Recp, 
2928                                            StrBuf *UserName, 
2929                                            StrBuf *EmailAddress,
2930                                            StrBuf *EncBuf)
2931 {
2932         StrBuf *Target;
2933         const char *pch, *pche;
2934         const char *UserStart, *UserEnd, *EmailStart, *EmailEnd, *At;
2935
2936         if ((Recp == NULL) || (StrLength(Recp) == 0))
2937                 return NULL;
2938
2939         pch = ChrPtr(Recp);
2940         pche = pch + StrLength(Recp);
2941
2942         if (!CheckEncode(pch, -1, pche))
2943                 return NewStrBufDup(Recp);
2944
2945         Target = NewStrBufPlain(NULL, StrLength(Recp));
2946
2947         while ((pch != NULL) && (pch < pche))
2948         {
2949                 while (isspace(*pch)) pch++;
2950                 UserEnd = EmailStart = EmailEnd = NULL;
2951                 
2952                 if ((*pch == '"') || (*pch == '\'')) {
2953                         UserStart = pch + 1;
2954                         
2955                         UserEnd = strchr(UserStart, *pch);
2956                         if (UserEnd == NULL) 
2957                                 break; ///TODO: Userfeedback??
2958                         EmailStart = UserEnd + 1;
2959                         while (isspace(*EmailStart))
2960                                 EmailStart++;
2961                         if (UserEnd == UserStart) {
2962                                 UserStart = UserEnd = NULL;
2963                         }
2964                         
2965                         if (*EmailStart == '<') {
2966                                 EmailStart++;
2967                                 EmailEnd = strchr(EmailStart, '>');
2968                                 if (EmailEnd == NULL)
2969                                         EmailEnd = strchr(EmailStart, ',');
2970                                 
2971                         }
2972                         else {
2973                                 EmailEnd = strchr(EmailStart, ',');
2974                         }
2975                         if (EmailEnd == NULL)
2976                                 EmailEnd = pche;
2977                         pch = EmailEnd + 1;
2978                 }
2979                 else {
2980                         int gt = 0;
2981                         UserStart = pch;
2982                         EmailEnd = strchr(UserStart, ',');
2983                         if (EmailEnd == NULL) {
2984                                 EmailEnd = strchr(pch, '>');
2985                                 pch = NULL;
2986                                 if (EmailEnd != NULL) {
2987                                         gt = 1;
2988                                 }
2989                                 else {
2990                                         EmailEnd = pche;
2991                                 }
2992                         }
2993                         else {
2994
2995                                 pch = EmailEnd + 1;
2996                                 while ((EmailEnd > UserStart) && !gt &&
2997                                        ((*EmailEnd == ',') ||
2998                                         (*EmailEnd == '>') ||
2999                                         (isspace(*EmailEnd))))
3000                                 {
3001                                         if (*EmailEnd == '>')
3002                                                 gt = 1;
3003                                         else 
3004                                                 EmailEnd--;
3005                                 }
3006                                 if (EmailEnd == UserStart)
3007                                         break;
3008                         }
3009                         if (gt) {
3010                                 EmailStart = strchr(UserStart, '<');
3011                                 if ((EmailStart == NULL) || (EmailStart > EmailEnd))
3012                                         break;
3013                                 UserEnd = EmailStart;
3014
3015                                 while ((UserEnd > UserStart) && 
3016                                        isspace (*(UserEnd - 1)))
3017                                         UserEnd --;
3018                                 EmailStart ++;
3019                                 if (UserStart >= UserEnd)
3020                                         UserStart = UserEnd = NULL;
3021                         }
3022                         else { /* this is a local recipient... no domain, just a realname */
3023                                 EmailStart = UserStart;
3024                                 At = strchr(EmailStart, '@');
3025                                 if (At == NULL) {
3026                                         UserEnd = EmailEnd;
3027                                         EmailEnd = NULL;
3028                                 }
3029                                 else {
3030                                         EmailStart = UserStart;
3031                                         UserStart = NULL;
3032                                 }
3033                         }
3034                 }
3035
3036                 if ((UserStart != NULL) && (UserEnd != NULL))
3037                         StrBufPlain(UserName, UserStart, UserEnd - UserStart);
3038                 else if ((UserStart != NULL) && (UserEnd == NULL))
3039                         StrBufPlain(UserName, UserStart, UserEnd - UserStart);
3040                 else
3041                         FlushStrBuf(UserName);
3042
3043                 if ((EmailStart != NULL) && (EmailEnd != NULL))
3044                         StrBufPlain(EmailAddress, EmailStart, EmailEnd - EmailStart);
3045                 else if ((EmailStart != NULL) && (EmailEnd == NULL))
3046                         StrBufPlain(EmailAddress, EmailStart, EmailEnd - pche);
3047                 else 
3048                         FlushStrBuf(EmailAddress);
3049
3050                 AddRecipient(Target, UserName, EmailAddress, EncBuf);
3051
3052                 if (pch == NULL)
3053                         break;
3054                 
3055                 if ((pch != NULL) && (*pch == ','))
3056                         pch ++;
3057                 if (pch != NULL) while (isspace(*pch))
3058                         pch ++;
3059         }
3060         return Target;
3061 }
3062
3063
3064 /**
3065  * @ingroup StrBuf
3066  * @brief replaces all occurances of 'search' by 'replace'
3067  * @param buf Buffer to modify
3068  * @param search character to search
3069  * @param replace character to replace search by
3070  */
3071 void StrBufReplaceChars(StrBuf *buf, char search, char replace)
3072 {
3073         long i;
3074         if (buf == NULL)
3075                 return;
3076         for (i=0; i<buf->BufUsed; i++)
3077                 if (buf->buf[i] == search)
3078                         buf->buf[i] = replace;
3079
3080 }
3081
3082 /**
3083  * @ingroup StrBuf
3084  * @brief removes all \\r s from the string, or replaces them with \n if its not a combination of both.
3085  * @param buf Buffer to modify
3086  */
3087 void StrBufToUnixLF(StrBuf *buf)
3088 {
3089         char *pche, *pchS, *pchT;
3090         if (buf == NULL)
3091                 return;
3092
3093         pche = buf->buf + buf->BufUsed;
3094         pchS = pchT = buf->buf;
3095         while (pchS < pche)
3096         {
3097                 if (*pchS == '\r')
3098                 {
3099                         pchS ++;
3100                         if (*pchS != '\n') {
3101                                 *pchT = '\n';
3102                                 pchT++;
3103                         }
3104                 }
3105                 *pchT = *pchS;
3106                 pchT++; pchS++;
3107         }
3108         *pchT = '\0';
3109         buf->BufUsed = pchT - buf->buf;
3110 }
3111
3112
3113 /*******************************************************************************
3114  *                 Iconv Wrapper; RFC822 de/encoding                           *
3115  *******************************************************************************/
3116
3117 /**
3118  * @ingroup StrBuf_DeEnCoder
3119  * @brief Wrapper around iconv_open()
3120  * Our version adds aliases for non-standard Microsoft charsets
3121  * such as 'MS950', aliasing them to names like 'CP950'
3122  *
3123  * @param tocode        Target encoding
3124  * @param fromcode      Source encoding
3125  * @param pic           anonimized pointer to iconv struct
3126  */
3127 void  ctdl_iconv_open(const char *tocode, const char *fromcode, void *pic)
3128 {
3129 #ifdef HAVE_ICONV
3130         iconv_t ic = (iconv_t)(-1) ;
3131         ic = iconv_open(tocode, fromcode);
3132         if (ic == (iconv_t)(-1) ) {
3133                 char alias_fromcode[64];
3134                 if ( (strlen(fromcode) == 5) && (!strncasecmp(fromcode, "MS", 2)) ) {
3135                         safestrncpy(alias_fromcode, fromcode, sizeof alias_fromcode);
3136                         alias_fromcode[0] = 'C';
3137                         alias_fromcode[1] = 'P';
3138                         ic = iconv_open(tocode, alias_fromcode);
3139                 }
3140         }
3141         *(iconv_t *)pic = ic;
3142 #endif
3143 }
3144
3145
3146 /**
3147  * @ingroup StrBuf_DeEnCoder
3148  * @brief find one chunk of a RFC822 encoded string
3149  * @param Buffer where to search
3150  * @param bptr where to start searching
3151  * @returns found position, NULL if none.
3152  */
3153 static inline const char *FindNextEnd (const StrBuf *Buf, const char *bptr)
3154 {
3155         const char * end;
3156         /* Find the next ?Q? */
3157         if (Buf->BufUsed - (bptr - Buf->buf)  < 6)
3158                 return NULL;
3159
3160         end = strchr(bptr + 2, '?');
3161
3162         if (end == NULL)
3163                 return NULL;
3164
3165         if ((Buf->BufUsed - (end - Buf->buf) > 3) &&
3166             (((*(end + 1) == 'B') || (*(end + 1) == 'Q')) ||
3167              ((*(end + 1) == 'b') || (*(end + 1) == 'q'))) && 
3168             (*(end + 2) == '?')) {
3169                 /* skip on to the end of the cluster, the next ?= */
3170                 end = strstr(end + 3, "?=");
3171         }
3172         else
3173                 /* sort of half valid encoding, try to find an end. */
3174                 end = strstr(bptr, "?=");
3175         return end;
3176 }
3177
3178
3179
3180 /**
3181  * @ingroup StrBuf_DeEnCoder
3182  * @brief convert one buffer according to the preselected iconv pointer PIC
3183  * @param ConvertBuf buffer we need to translate
3184  * @param TmpBuf To share a workbuffer over several iterations. prepare to have it filled with useless stuff afterwards.
3185  * @param pic Pointer to the iconv-session Object
3186  */
3187 void StrBufConvert(StrBuf *ConvertBuf, StrBuf *TmpBuf, void *pic)
3188 {
3189 #ifdef HAVE_ICONV
3190         long trycount = 0;
3191         size_t siz;
3192         iconv_t ic;
3193         char *ibuf;                     /**< Buffer of characters to be converted */
3194         char *obuf;                     /**< Buffer for converted characters */
3195         size_t ibuflen;                 /**< Length of input buffer */
3196         size_t obuflen;                 /**< Length of output buffer */
3197
3198
3199         if ((ConvertBuf == NULL) || (TmpBuf == NULL))
3200                 return;
3201
3202         /* since we're converting to utf-8, one glyph may take up to 6 bytes */
3203         if (ConvertBuf->BufUsed * 6 >= TmpBuf->BufSize)
3204                 IncreaseBuf(TmpBuf, 0, ConvertBuf->BufUsed * 6);
3205 TRYAGAIN:
3206         ic = *(iconv_t*)pic;
3207         ibuf = ConvertBuf->buf;
3208         ibuflen = ConvertBuf->BufUsed;
3209         obuf = TmpBuf->buf;
3210         obuflen = TmpBuf->BufSize;
3211         
3212         siz = iconv(ic, &ibuf, &ibuflen, &obuf, &obuflen);
3213
3214         if (siz < 0) {
3215                 if (errno == E2BIG) {
3216                         trycount ++;                    
3217                         IncreaseBuf(TmpBuf, 0, 0);
3218                         if (trycount < 5) 
3219                                 goto TRYAGAIN;
3220
3221                 }
3222                 else if (errno == EILSEQ){ 
3223                         /* hm, invalid utf8 sequence... what to do now? */
3224                         /* An invalid multibyte sequence has been encountered in the input */
3225                 }
3226                 else if (errno == EINVAL) {
3227                         /* An incomplete multibyte sequence has been encountered in the input. */
3228                 }
3229
3230                 FlushStrBuf(TmpBuf);
3231         }
3232         else {
3233                 TmpBuf->BufUsed = TmpBuf->BufSize - obuflen;
3234                 TmpBuf->buf[TmpBuf->BufUsed] = '\0';
3235                 
3236                 /* little card game: wheres the red lady? */
3237                 SwapBuffers(ConvertBuf, TmpBuf);
3238                 FlushStrBuf(TmpBuf);
3239         }
3240 #endif
3241 }
3242
3243
3244 /**
3245  * @ingroup StrBuf_DeEnCoder
3246  * @brief catches one RFC822 encoded segment, and decodes it.
3247  * @param Target buffer to fill with result
3248  * @param DecodeMe buffer with stuff to process
3249  * @param SegmentStart points to our current segment in DecodeMe
3250  * @param SegmentEnd Points to the end of our current segment in DecodeMe
3251  * @param ConvertBuf Workbuffer shared between several iterations. Random content; needs to be valid
3252  * @param ConvertBuf2 Workbuffer shared between several iterations. Random content; needs to be valid
3253  * @param FoundCharset Characterset to default decoding to; if we find another we will overwrite it.
3254  */
3255 inline static void DecodeSegment(StrBuf *Target, 
3256                                  const StrBuf *DecodeMe, 
3257                                  const char *SegmentStart, 
3258                                  const char *SegmentEnd, 
3259                                  StrBuf *ConvertBuf,
3260                                  StrBuf *ConvertBuf2, 
3261                                  StrBuf *FoundCharset)
3262 {
3263         StrBuf StaticBuf;
3264         char charset[128];
3265         char encoding[16];
3266 #ifdef HAVE_ICONV
3267         iconv_t ic = (iconv_t)(-1);
3268 #else
3269         void *ic = NULL;
3270 #endif
3271         /* Now we handle foreign character sets properly encoded
3272          * in RFC2047 format.
3273          */
3274         StaticBuf.buf = (char*) SegmentStart; /*< it will just be read there... */
3275         StaticBuf.BufUsed = SegmentEnd - SegmentStart;
3276         StaticBuf.BufSize = DecodeMe->BufSize - (SegmentStart - DecodeMe->buf);
3277         extract_token(charset, SegmentStart, 1, '?', sizeof charset);
3278         if (FoundCharset != NULL) {
3279                 FlushStrBuf(FoundCharset);
3280                 StrBufAppendBufPlain(FoundCharset, charset, -1, 0);
3281         }
3282         extract_token(encoding, SegmentStart, 2, '?', sizeof encoding);
3283         StrBufExtract_token(ConvertBuf, &StaticBuf, 3, '?');
3284         
3285         *encoding = toupper(*encoding);
3286         if (*encoding == 'B') { /**< base64 */
3287                 if (ConvertBuf2->BufSize < ConvertBuf->BufUsed)
3288                         IncreaseBuf(ConvertBuf2, 0, ConvertBuf->BufUsed);
3289                 ConvertBuf2->BufUsed = CtdlDecodeBase64(ConvertBuf2->buf, 
3290                                                         ConvertBuf->buf, 
3291                                                         ConvertBuf->BufUsed);
3292         }
3293         else if (*encoding == 'Q') {    /**< quoted-printable */
3294                 long pos;
3295                 
3296                 pos = 0;
3297                 while (pos < ConvertBuf->BufUsed)
3298                 {
3299                         if (ConvertBuf->buf[pos] == '_') 
3300                                 ConvertBuf->buf[pos] = ' ';
3301                         pos++;
3302                 }
3303                 
3304                 if (ConvertBuf2->BufSize < ConvertBuf->BufUsed)
3305                         IncreaseBuf(ConvertBuf2, 0, ConvertBuf->BufUsed);
3306
3307                 ConvertBuf2->BufUsed = CtdlDecodeQuotedPrintable(
3308                         ConvertBuf2->buf, 
3309                         ConvertBuf->buf,
3310                         ConvertBuf->BufUsed);
3311         }
3312         else {
3313                 StrBufAppendBuf(ConvertBuf2, ConvertBuf, 0);
3314         }
3315 #ifdef HAVE_ICONV
3316         ctdl_iconv_open("UTF-8", charset, &ic);
3317         if (ic != (iconv_t)(-1) ) {             
3318 #endif
3319                 StrBufConvert(ConvertBuf2, ConvertBuf, &ic);
3320                 StrBufAppendBuf(Target, ConvertBuf2, 0);
3321 #ifdef HAVE_ICONV
3322                 iconv_close(ic);
3323         }
3324         else {
3325                 StrBufAppendBufPlain(Target, HKEY("(unreadable)"), 0);
3326         }
3327 #endif
3328 }
3329
3330 /**
3331  * @ingroup StrBuf_DeEnCoder
3332  * @brief Handle subjects with RFC2047 encoding such as: [deprecated old syntax!]
3333  * =?koi8-r?B?78bP0s3Mxc7JxSDXz9rE1dvO2c3JINvB0sHNySDP?=
3334  * @param Target where to put the decoded string to 
3335  * @param DecodeMe buffer with encoded string
3336  * @param DefaultCharset if we don't find one, which should we use?
3337  * @param FoundCharset overrides DefaultCharset if non-empty; If we find a charset inside of the string, 
3338  *        put it here for later use where no string might be known.
3339  */
3340 void StrBuf_RFC822_to_Utf8(StrBuf *Target, const StrBuf *DecodeMe, const StrBuf* DefaultCharset, StrBuf *FoundCharset)
3341 {
3342         StrBuf *ConvertBuf;
3343         StrBuf *ConvertBuf2;
3344         ConvertBuf = NewStrBufPlain(NULL, StrLength(DecodeMe));
3345         ConvertBuf2 = NewStrBufPlain(NULL, StrLength(DecodeMe));
3346         
3347         StrBuf_RFC822_2_Utf8(Target, 
3348                              DecodeMe, 
3349                              DefaultCharset, 
3350                              FoundCharset, 
3351                              ConvertBuf, 
3352                              ConvertBuf2);
3353         FreeStrBuf(&ConvertBuf);
3354         FreeStrBuf(&ConvertBuf2);
3355 }
3356
3357 /**
3358  * @ingroup StrBuf_DeEnCoder
3359  * @brief Handle subjects with RFC2047 encoding such as:
3360  * =?koi8-r?B?78bP0s3Mxc7JxSDXz9rE1dvO2c3JINvB0sHNySDP?=
3361  * @param Target where to put the decoded string to 
3362  * @param DecodeMe buffer with encoded string
3363  * @param DefaultCharset if we don't find one, which should we use?
3364  * @param FoundCharset overrides DefaultCharset if non-empty; If we find a charset inside of the string, 
3365  *        put it here for later use where no string might be known.
3366  * @param ConvertBuf workbuffer. feed in, you shouldn't care about its content.
3367  * @param ConvertBuf2 workbuffer. feed in, you shouldn't care about its content.
3368  */
3369 void StrBuf_RFC822_2_Utf8(StrBuf *Target, 
3370                           const StrBuf *DecodeMe, 
3371                           const StrBuf* DefaultCharset, 
3372                           StrBuf *FoundCharset, 
3373                           StrBuf *ConvertBuf, 
3374                           StrBuf *ConvertBuf2)
3375 {
3376         StrBuf *DecodedInvalidBuf = NULL;
3377         const StrBuf *DecodeMee = DecodeMe;
3378         const char *start, *end, *next, *nextend, *ptr = NULL;
3379 #ifdef HAVE_ICONV
3380         iconv_t ic = (iconv_t)(-1) ;
3381 #endif
3382         const char *eptr;
3383         int passes = 0;
3384         int i;
3385         int illegal_non_rfc2047_encoding = 0;
3386
3387
3388         if (DecodeMe == NULL)
3389                 return;
3390         /* Sometimes, badly formed messages contain strings which were simply
3391          *  written out directly in some foreign character set instead of
3392          *  using RFC2047 encoding.  This is illegal but we will attempt to
3393          *  handle it anyway by converting from a user-specified default
3394          *  charset to UTF-8 if we see any nonprintable characters.
3395          */
3396         
3397         for (i=0; i<DecodeMe->BufUsed; ++i) {
3398                 if ((DecodeMe->buf[i] < 32) || (DecodeMe->buf[i] > 126)) {
3399                         illegal_non_rfc2047_encoding = 1;
3400                         break;
3401                 }
3402         }
3403
3404         if ((illegal_non_rfc2047_encoding) &&
3405             (strcasecmp(ChrPtr(DefaultCharset), "UTF-8")) && 
3406             (strcasecmp(ChrPtr(DefaultCharset), "us-ascii")) )
3407         {
3408 #ifdef HAVE_ICONV
3409                 ctdl_iconv_open("UTF-8", ChrPtr(DefaultCharset), &ic);
3410                 if (ic != (iconv_t)(-1) ) {
3411                         DecodedInvalidBuf = NewStrBufDup(DecodeMe);
3412                         StrBufConvert(DecodedInvalidBuf, ConvertBuf, &ic);///TODO: don't void const?
3413                         DecodeMee = DecodedInvalidBuf;