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