]> code.citadel.org Git - citadel.git/blob - libcitadel/lib/stringbuf.c
* copy statistic inforations too...
[citadel.git] / libcitadel / lib / stringbuf.c
1 #include <ctype.h>
2 #include <errno.h>
3 #include <string.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <stdio.h>
7 #include <sys/select.h>
8 #include <fcntl.h>
9 #define SHOW_ME_VAPPEND_PRINTF
10 #include <stdarg.h>
11 #include "libcitadel.h"
12
13
14 struct StrBuf {
15         char *buf;
16         long BufSize;
17         long BufUsed;
18         int ConstBuf;
19 };
20
21
22 inline const char *ChrPtr(const StrBuf *Str)
23 {
24         if (Str == NULL)
25                 return "";
26         return Str->buf;
27 }
28
29 inline int StrLength(const StrBuf *Str)
30 {
31         return (Str != NULL) ? Str->BufUsed : 0;
32 }
33
34 StrBuf* NewStrBuf(void)
35 {
36         StrBuf *NewBuf;
37
38         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
39         NewBuf->buf = (char*) malloc(SIZ);
40         NewBuf->buf[0] = '\0';
41         NewBuf->BufSize = SIZ;
42         NewBuf->BufUsed = 0;
43         NewBuf->ConstBuf = 0;
44         return NewBuf;
45 }
46
47 StrBuf* NewStrBufDup(const StrBuf *CopyMe)
48 {
49         StrBuf *NewBuf;
50         
51         if (CopyMe == NULL)
52                 return NewStrBuf();
53
54         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
55         NewBuf->buf = (char*) malloc(CopyMe->BufSize);
56         memcpy(NewBuf->buf, CopyMe->buf, CopyMe->BufUsed + 1);
57         NewBuf->BufUsed = CopyMe->BufUsed;
58         NewBuf->BufSize = CopyMe->BufSize;
59         return NewBuf;
60 }
61
62 StrBuf* NewStrBufPlain(const char* ptr, int nChars)
63 {
64         StrBuf *NewBuf;
65         size_t Siz = SIZ;
66         size_t CopySize;
67
68         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
69         if (nChars < 0)
70                 CopySize = strlen((ptr != NULL)?ptr:"");
71         else
72                 CopySize = nChars;
73
74         while (Siz <= CopySize)
75                 Siz *= 2;
76
77         NewBuf->buf = (char*) malloc(Siz);
78         NewBuf->BufSize = Siz;
79         if (ptr != NULL) {
80                 memcpy(NewBuf->buf, ptr, CopySize);
81                 NewBuf->buf[CopySize] = '\0';
82                 NewBuf->BufUsed = CopySize;
83         }
84         else {
85                 NewBuf->buf[0] = '\0';
86                 NewBuf->BufUsed = 0;
87         }
88         NewBuf->ConstBuf = 0;
89         return NewBuf;
90 }
91
92
93 StrBuf* _NewConstStrBuf(const char* StringConstant, size_t SizeOfStrConstant)
94 {
95         StrBuf *NewBuf;
96
97         NewBuf = (StrBuf*) malloc(sizeof(StrBuf));
98         NewBuf->buf = (char*) StringConstant;
99         NewBuf->BufSize = SizeOfStrConstant;
100         NewBuf->BufUsed = SizeOfStrConstant;
101         NewBuf->ConstBuf = 1;
102         return NewBuf;
103 }
104
105
106 static int IncreaseBuf(StrBuf *Buf, int KeepOriginal, int DestSize)
107 {
108         char *NewBuf;
109         size_t NewSize = Buf->BufSize * 2;
110
111         if (Buf->ConstBuf)
112                 return -1;
113                 
114         if (DestSize > 0)
115                 while (NewSize < DestSize)
116                         NewSize *= 2;
117
118         NewBuf= (char*) malloc(NewSize);
119         if (KeepOriginal)
120         {
121                 memcpy(NewBuf, Buf->buf, Buf->BufUsed);
122         }
123         else
124         {
125                 NewBuf[0] = '\0';
126                 Buf->BufUsed = 0;
127         }
128         free (Buf->buf);
129         Buf->buf = NewBuf;
130         Buf->BufSize *= 2;
131         return Buf->BufSize;
132 }
133
134 int FlushStrBuf(StrBuf *buf)
135 {
136         if (buf->ConstBuf)
137                 return -1;       
138         buf->buf[0] ='\0';
139         buf->BufUsed = 0;
140         return 0;
141 }
142
143 void FreeStrBuf (StrBuf **FreeMe)
144 {
145         if (*FreeMe == NULL)
146                 return;
147         if (!(*FreeMe)->ConstBuf) 
148                 free((*FreeMe)->buf);
149         free(*FreeMe);
150         *FreeMe = NULL;
151 }
152
153 void HFreeStrBuf (void *VFreeMe)
154 {
155         StrBuf *FreeMe = (StrBuf*)VFreeMe;
156         if (FreeMe == NULL)
157                 return;
158         if (!FreeMe->ConstBuf) 
159                 free(FreeMe->buf);
160         free(FreeMe);
161 }
162
163 long StrTol(const StrBuf *Buf)
164 {
165         if(Buf->BufUsed > 0)
166                 return atol(Buf->buf);
167         else
168                 return 0;
169 }
170
171 int StrToi(const StrBuf *Buf)
172 {
173         if(Buf->BufUsed > 0)
174                 return atoi(Buf->buf);
175         else
176                 return 0;
177 }
178
179 int StrBufPlain(StrBuf *Buf, const char* ptr, int nChars)
180 {
181         size_t Siz = Buf->BufSize;
182         size_t CopySize;
183
184         if (nChars < 0)
185                 CopySize = strlen(ptr);
186         else
187                 CopySize = nChars;
188
189         while (Siz <= CopySize)
190                 Siz *= 2;
191
192         if (Siz != Buf->BufSize)
193                 IncreaseBuf(Buf, 0, Siz);
194         memcpy(Buf->buf, ptr, CopySize);
195         Buf->buf[CopySize] = '\0';
196         Buf->BufUsed = CopySize;
197         Buf->ConstBuf = 0;
198         return CopySize;
199 }
200
201 void StrBufAppendBuf(StrBuf *Buf, const StrBuf *AppendBuf, size_t Offset)
202 {
203         if ((AppendBuf == NULL) || (Buf == NULL))
204                 return;
205
206         if (Buf->BufSize - Offset < AppendBuf->BufUsed + Buf->BufUsed)
207                 IncreaseBuf(Buf, 
208                             (Buf->BufUsed > 0), 
209                             AppendBuf->BufUsed + Buf->BufUsed);
210
211         memcpy(Buf->buf + Buf->BufUsed, 
212                AppendBuf->buf + Offset, 
213                AppendBuf->BufUsed - Offset);
214         Buf->BufUsed += AppendBuf->BufUsed - Offset;
215         Buf->buf[Buf->BufUsed] = '\0';
216 }
217
218
219 void StrBufAppendBufPlain(StrBuf *Buf, const char *AppendBuf, long AppendSize, size_t Offset)
220 {
221         long aps;
222
223         if ((AppendBuf == NULL) || (Buf == NULL))
224                 return;
225
226         if (AppendSize < 0 )
227                 aps = strlen(AppendBuf + Offset);
228         else
229                 aps = AppendSize - Offset;
230
231         if (Buf->BufSize < Buf->BufUsed + aps)
232                 IncreaseBuf(Buf, (Buf->BufUsed > 0), Buf->BufUsed + aps);
233
234         memcpy(Buf->buf + Buf->BufUsed, 
235                AppendBuf + Offset, 
236                aps);
237         Buf->BufUsed += aps;
238         Buf->buf[Buf->BufUsed] = '\0';
239 }
240
241
242 inline int StrBufNum_tokens(const StrBuf *source, char tok)
243 {
244         return num_tokens(source->buf, tok);
245 }
246
247
248 int StrBufSub(StrBuf *dest, const StrBuf *Source, size_t Offset, size_t nChars)
249 {
250         size_t NCharsRemain;
251         if (Offset > Source->BufUsed)
252         {
253                 FlushStrBuf(dest);
254                 return 0;
255         }
256         if (Offset + nChars < Source->BufUsed)
257         {
258                 if (nChars > dest->BufSize)
259                         IncreaseBuf(dest, 0, nChars + 1);
260                 memcpy(dest->buf, Source->buf + Offset, nChars);
261                 dest->BufUsed = nChars;
262                 dest->buf[dest->BufUsed] = '\0';
263                 return nChars;
264         }
265         NCharsRemain = Source->BufUsed - Offset;
266         if (NCharsRemain > dest->BufSize)
267                 IncreaseBuf(dest, 0, NCharsRemain + 1);
268         memcpy(dest->buf, Source->buf + Offset, NCharsRemain);
269         dest->BufUsed = NCharsRemain;
270         dest->buf[dest->BufUsed] = '\0';
271         return NCharsRemain;
272 }
273
274
275 void StrBufVAppendPrintf(StrBuf *Buf, const char *format, va_list ap)
276 {
277         size_t nWritten = Buf->BufSize + 1;
278         size_t Offset = Buf->BufUsed;
279         size_t newused = Offset + nWritten;
280         
281         while (newused >= Buf->BufSize) {
282                 nWritten = vsnprintf(Buf->buf + Offset, 
283                                      Buf->BufSize - Offset, 
284                                      format, ap);
285                 newused = Offset + nWritten;
286                 if (newused >= Buf->BufSize)
287                         IncreaseBuf(Buf, 1, 0);
288                 else
289                         Buf->BufUsed = Offset + nWritten ;
290
291         }
292 }
293
294 void StrBufPrintf(StrBuf *Buf, const char *format, ...)
295 {
296         size_t nWritten = Buf->BufSize + 1;
297         va_list arg_ptr;
298         
299         while (nWritten >= Buf->BufSize) {
300                 va_start(arg_ptr, format);
301                 nWritten = vsnprintf(Buf->buf, Buf->BufSize, format, arg_ptr);
302                 va_end(arg_ptr);
303                 Buf->BufUsed = nWritten ;
304                 if (nWritten >= Buf->BufSize)
305                         IncreaseBuf(Buf, 0, 0);
306         }
307 }
308
309
310 /**
311  * \brief a string tokenizer
312  * \param dest Destination StringBuffer
313  * \param Source StringBuffer to read into
314  * \param separator tokenizer param
315  * \returns -1 if not found, else length of token.
316  */
317 int StrBufExtract_token(StrBuf *dest, const StrBuf *Source, int parmnum, char separator)
318 {
319         const char *s, *e;              //* source * /
320         int len = 0;                    //* running total length of extracted string * /
321         int current_token = 0;          //* token currently being processed * /
322
323         if ((Source == NULL) || (Source->BufUsed ==0)) {
324                 return(-1);
325         }
326         s = Source->buf;
327         e = s + Source->BufUsed;
328         if (dest == NULL) {
329                 return(-1);
330         }
331
332         //cit_backtrace();
333         //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
334         dest->buf[0] = '\0';
335         dest->BufUsed = 0;
336
337         while ((s<e) && !IsEmptyStr(s)) {
338                 if (*s == separator) {
339                         ++current_token;
340                 }
341                 if (len >= dest->BufSize)
342                         if (!IncreaseBuf(dest, 1, -1))
343                                 break;
344                 if ( (current_token == parmnum) && 
345                      (*s != separator)) {
346                         dest->buf[len] = *s;
347                         ++len;
348                 }
349                 else if (current_token > parmnum) {
350                         break;
351                 }
352                 ++s;
353         }
354         
355         dest->buf[len] = '\0';
356         dest->BufUsed = len;
357                 
358         if (current_token < parmnum) {
359                 //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
360                 return(-1);
361         }
362         //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
363         return(len);
364 }
365
366
367 /*
368  * extract_int()  -  extract an int parm w/o supplying a buffer
369  */
370 int StrBufExtract_int(const StrBuf* Source, int parmnum, char separator)
371 {
372         StrBuf tmp;
373         char buf[64];
374         
375         tmp.buf = buf;
376         buf[0] = '\0';
377         tmp.BufSize = 64;
378         tmp.BufUsed = 0;
379         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
380                 return(atoi(buf));
381         else
382                 return 0;
383 }
384
385 /*
386  * extract_long()  -  extract an long parm w/o supplying a buffer
387  */
388 long StrBufExtract_long(const StrBuf* Source, int parmnum, char separator)
389 {
390         StrBuf tmp;
391         char buf[64];
392         
393         tmp.buf = buf;
394         buf[0] = '\0';
395         tmp.BufSize = 64;
396         tmp.BufUsed = 0;
397         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
398                 return(atoi(buf));
399         else
400                 return 0;
401 }
402
403
404 /*
405  * extract_unsigned_long() - extract an unsigned long parm
406  */
407 unsigned long StrBufExtract_unsigned_long(const StrBuf* Source, int parmnum, char separator)
408 {
409         StrBuf tmp;
410         char buf[64];
411         
412         tmp.buf = buf;
413         buf[0] = '\0';
414         tmp.BufSize = 64;
415         tmp.BufUsed = 0;
416         if (StrBufExtract_token(&tmp, Source, parmnum, separator) > 0)
417                 return(atoi(buf));
418         else 
419                 return 0;
420 }
421
422
423
424 /**
425  * \brief Input binary data from socket
426  * \param buf the buffer to get the input to
427  * \param bytes the maximal number of bytes to read
428  */
429 int StrBufTCP_read_line(StrBuf *buf, int *fd, int append, const char **Error)
430 {
431         int len, rlen, slen;
432
433         if (!append)
434                 FlushStrBuf(buf);
435
436         slen = len = buf->BufUsed;
437         while (1) {
438                 rlen = read(*fd, &buf->buf[len], 1);
439                 if (rlen < 1) {
440                         *Error = strerror(errno);
441                         
442                         close(*fd);
443                         *fd = -1;
444                         
445                         return -1;
446                 }
447                 if (buf->buf[len] == '\n')
448                         break;
449                 if (buf->buf[len] != '\r')
450                         len ++;
451                 if (!(len < buf->BufSize)) {
452                         buf->BufUsed = len;
453                         buf->buf[len+1] = '\0';
454                         IncreaseBuf(buf, 1, -1);
455                 }
456         }
457         buf->BufUsed = len;
458         buf->buf[len] = '\0';
459         return len - slen;
460 }
461
462 /**
463  * \brief Input binary data from socket
464  * \param buf the buffer to get the input to
465  * \param bytes the maximal number of bytes to read
466  */
467 int StrBufReadBLOB(StrBuf *Buf, int *fd, int append, long nBytes, const char **Error)
468 {
469         fd_set wset;
470         int fdflags;
471         int len, rlen, slen;
472         int nRead = 0;
473         char *ptr;
474
475         if ((Buf == NULL) || (*fd == -1))
476                 return -1;
477         if (!append)
478                 FlushStrBuf(Buf);
479         if (Buf->BufUsed + nBytes > Buf->BufSize)
480                 IncreaseBuf(Buf, 1, Buf->BufUsed + nBytes);
481
482         ptr = Buf->buf + Buf->BufUsed;
483
484         slen = len = Buf->BufUsed;
485
486         fdflags = fcntl(*fd, F_GETFL);
487
488         while (nRead < nBytes) {
489                if ((fdflags & O_NONBLOCK) == O_NONBLOCK) {
490                         FD_ZERO(&wset);
491                         FD_SET(*fd, &wset);
492                         if (select(*fd + 1, NULL, &wset, NULL, NULL) == -1) {
493                                 *Error = strerror(errno);
494                                 return -1;
495                         }
496                 }
497
498                 if ((rlen = read(*fd, 
499                                  ptr,
500                                  nBytes - nRead)) == -1) {
501                         close(*fd);
502                         *fd = -1;
503                         *Error = strerror(errno);
504                         return rlen;
505                 }
506                 nRead += rlen;
507                 Buf->BufUsed += rlen;
508         }
509         Buf->buf[Buf->BufUsed] = '\0';
510         return nRead;
511 }
512
513 void StrBufCutLeft(StrBuf *Buf, int nChars)
514 {
515         if (nChars >= Buf->BufUsed) {
516                 FlushStrBuf(Buf);
517                 return;
518         }
519         memmove(Buf->buf, Buf->buf + nChars, Buf->BufUsed - nChars);
520         Buf->BufUsed -= nChars;
521         Buf->buf[Buf->BufUsed] = '\0';
522 }
523
524 void StrBufCutRight(StrBuf *Buf, int nChars)
525 {
526         if (nChars >= Buf->BufUsed) {
527                 FlushStrBuf(Buf);
528                 return;
529         }
530         Buf->BufUsed -= nChars;
531         Buf->buf[Buf->BufUsed] = '\0';
532 }
533
534
535 /*
536  * string conversion function
537  */
538 void StrBufEUid_unescapize(StrBuf *target, const StrBuf *source) 
539 {
540         int a, b, len;
541         char hex[3];
542
543         if (target != NULL)
544                 FlushStrBuf(target);
545
546         if (source == NULL ||target == NULL)
547         {
548                 return;
549         }
550
551         len = source->BufUsed;
552         for (a = 0; a < len; ++a) {
553                 if (target->BufUsed >= target->BufSize)
554                         IncreaseBuf(target, 1, -1);
555
556                 if (source->buf[a] == '=') {
557                         hex[0] = source->buf[a + 1];
558                         hex[1] = source->buf[a + 2];
559                         hex[2] = 0;
560                         b = 0;
561                         sscanf(hex, "%02x", &b);
562                         target->buf[target->BufUsed] = b;
563                         target->buf[++target->BufUsed] = 0;
564                         a += 2;
565                 }
566                 else {
567                         target->buf[target->BufUsed] = source->buf[a];
568                         target->buf[++target->BufUsed] = 0;
569                 }
570         }
571 }
572
573
574 /*
575  * string conversion function
576  */
577 void StrBufEUid_escapize(StrBuf *target, const StrBuf *source) 
578 {
579         int i, len;
580
581         if (target != NULL)
582                 FlushStrBuf(target);
583
584         if (source == NULL ||target == NULL)
585         {
586                 return;
587         }
588
589         len = source->BufUsed;
590         for (i=0; i<len; ++i) {
591                 if (target->BufUsed + 4 >= target->BufSize)
592                         IncreaseBuf(target, 1, -1);
593                 if ( (isalnum(source->buf[i])) || 
594                      (source->buf[i]=='-') || 
595                      (source->buf[i]=='_') ) {
596                         target->buf[target->BufUsed++] = source->buf[i];
597                 }
598                 else {
599                         sprintf(&target->buf[target->BufUsed], 
600                                 "=%02X", 
601                                 (0xFF &source->buf[i]));
602                         target->BufUsed += 3;
603                 }
604         }
605         target->buf[target->BufUsed + 1] = '\0';
606 }
607
608 /*
609  * \brief uses the same calling syntax as compress2(), but it
610  * creates a stream compatible with HTTP "Content-encoding: gzip"
611  */
612 #ifdef HAVE_ZLIB
613 #define DEF_MEM_LEVEL 8 /*< memlevel??? */
614 #define OS_CODE 0x03    /*< unix */
615 int ZEXPORT compress_gzip(Bytef * dest,         /*< compressed buffer*/
616                           size_t * destLen,     /*< length of the compresed data */
617                           const Bytef * source, /*< source to encode */
618                           uLong sourceLen,      /*< length of source to encode */
619                           int level)            /*< compression level */
620 {
621         const int gz_magic[2] = { 0x1f, 0x8b }; /* gzip magic header */
622
623         /* write gzip header */
624         snprintf((char *) dest, *destLen, 
625                  "%c%c%c%c%c%c%c%c%c%c",
626                  gz_magic[0], gz_magic[1], Z_DEFLATED,
627                  0 /*flags */ , 0, 0, 0, 0 /*time */ , 0 /* xflags */ ,
628                  OS_CODE);
629
630         /* normal deflate */
631         z_stream stream;
632         int err;
633         stream.next_in = (Bytef *) source;
634         stream.avail_in = (uInt) sourceLen;
635         stream.next_out = dest + 10L;   // after header
636         stream.avail_out = (uInt) * destLen;
637         if ((uLong) stream.avail_out != *destLen)
638                 return Z_BUF_ERROR;
639
640         stream.zalloc = (alloc_func) 0;
641         stream.zfree = (free_func) 0;
642         stream.opaque = (voidpf) 0;
643
644         err = deflateInit2(&stream, level, Z_DEFLATED, -MAX_WBITS,
645                            DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
646         if (err != Z_OK)
647                 return err;
648
649         err = deflate(&stream, Z_FINISH);
650         if (err != Z_STREAM_END) {
651                 deflateEnd(&stream);
652                 return err == Z_OK ? Z_BUF_ERROR : err;
653         }
654         *destLen = stream.total_out + 10L;
655
656         /* write CRC and Length */
657         uLong crc = crc32(0L, source, sourceLen);
658         int n;
659         for (n = 0; n < 4; ++n, ++*destLen) {
660                 dest[*destLen] = (int) (crc & 0xff);
661                 crc >>= 8;
662         }
663         uLong len = stream.total_in;
664         for (n = 0; n < 4; ++n, ++*destLen) {
665                 dest[*destLen] = (int) (len & 0xff);
666                 len >>= 8;
667         }
668         err = deflateEnd(&stream);
669         return err;
670 }
671 #endif
672
673
674 /**
675  * Attention! If you feed this a Const String, you must maintain the uncompressed buffer yourself!
676  */
677 int CompressBuffer(StrBuf *Buf)
678 {
679 #ifdef HAVE_ZLIB
680         char *compressed_data = NULL;
681         size_t compressed_len, bufsize;
682         
683         bufsize = compressed_len = ((Buf->BufUsed * 101) / 100) + 100;
684         compressed_data = malloc(compressed_len);
685         
686         if (compress_gzip((Bytef *) compressed_data,
687                           &compressed_len,
688                           (Bytef *) Buf->buf,
689                           (uLongf) Buf->BufUsed, Z_BEST_SPEED) == Z_OK) {
690                 if (!ConstBuf)
691                         free(Buf->buf);
692                 Buf->buf = compressed_data;
693                 Buf->BufUsed = compressed_len;
694                 Buf->BufSize = bufsize;
695                 return 1;
696         } else {
697                 free(compressed_data);
698         }
699 #endif  /* HAVE_ZLIB */
700         return 0;
701 }
702
703 int StrBufDecodeBase64(StrBuf *Buf)
704 {
705         char *xferbuf;
706         size_t siz;
707         if (Buf == NULL) return -1;
708
709         xferbuf = (char*) malloc(Buf->BufSize);
710         siz = CtdlDecodeBase64(xferbuf,
711                                Buf->buf,
712                                Buf->BufUsed);
713         free(Buf->buf);
714         Buf->buf = xferbuf;
715         Buf->BufUsed = siz;
716         return siz;
717 }
718
719
720 /*   
721  * remove escaped strings from i.e. the url string (like %20 for blanks)
722  */
723 long StrBufUnescape(StrBuf *Buf, int StripBlanks)
724 {
725         int a, b;
726         char hex[3];
727         long len;
728
729         while ((Buf->BufUsed > 0) && (isspace(Buf->buf[Buf->BufUsed - 1]))){
730                 Buf->buf[Buf->BufUsed - 1] = '\0';
731                 Buf->BufUsed --;
732         }
733
734         a = 0; 
735         while (a < Buf->BufUsed) {
736                 if (Buf->buf[a] == '+')
737                         Buf->buf[a] = ' ';
738                 else if (Buf->buf[a] == '%') {
739                         /* don't let % chars through, rather truncate the input. */
740                         if (a + 2 > Buf->BufUsed) {
741                                 Buf->buf[a] = '\0';
742                                 Buf->BufUsed = a;
743                         }
744                         else {                  
745                                 hex[0] = Buf->buf[a + 1];
746                                 hex[1] = Buf->buf[a + 2];
747                                 hex[2] = 0;
748                                 b = 0;
749                                 sscanf(hex, "%02x", &b);
750                                 Buf->buf[a] = (char) b;
751                                 len = Buf->BufUsed - a - 2;
752                                 if (len > 0)
753                                         memmove(&Buf->buf[a + 1], &Buf->buf[a + 3], len);
754                         
755                                 Buf->BufUsed -=2;
756                         }
757                 }
758                 a++;
759         }
760         return a;
761 }
762
763
764 /**
765  * \brief       RFC2047-encode a header field if necessary.
766  *              If no non-ASCII characters are found, the string
767  *              will be copied verbatim without encoding.
768  *
769  * \param       target          Target buffer.
770  * \param       source          Source string to be encoded.
771  * \returns     encoded length; -1 if non success.
772  */
773 int StrBufRFC2047encode(StrBuf **target, const StrBuf *source)
774 {
775         const char headerStr[] = "=?UTF-8?Q?";
776         int need_to_encode = 0;
777         int i = 0;
778         unsigned char ch;
779
780         if ((source == NULL) || 
781             (target == NULL))
782             return -1;
783
784         while ((i < source->BufUsed) &&
785                (!IsEmptyStr (&source->buf[i])) &&
786                (need_to_encode == 0)) {
787                 if (((unsigned char) source->buf[i] < 32) || 
788                     ((unsigned char) source->buf[i] > 126)) {
789                         need_to_encode = 1;
790                 }
791                 i++;
792         }
793
794         if (!need_to_encode) {
795                 if (*target == NULL) {
796                         *target = NewStrBufPlain(source->buf, source->BufUsed);
797                 }
798                 else {
799                         FlushStrBuf(*target);
800                         StrBufAppendBuf(*target, source, 0);
801                 }
802                 return (*target)->BufUsed;
803         }
804         if (*target == NULL)
805                 *target = NewStrBufPlain(NULL, sizeof(headerStr) + source->BufUsed * 2);
806         else if (sizeof(headerStr) + source->BufUsed > (*target)->BufSize)
807                 IncreaseBuf(*target, sizeof(headerStr) + source->BufUsed, 0);
808         memcpy ((*target)->buf, headerStr, sizeof(headerStr) - 1);
809         (*target)->BufUsed = sizeof(headerStr) - 1;
810         for (i=0; (i < source->BufUsed); ++i) {
811                 if ((*target)->BufUsed + 4 > (*target)->BufSize)
812                         IncreaseBuf(*target, 1, 0);
813                 ch = (unsigned char) source->buf[i];
814                 if ((ch < 32) || (ch > 126) || (ch == 61)) {
815                         sprintf(&(*target)->buf[(*target)->BufUsed], "=%02X", ch);
816                         (*target)->BufUsed += 3;
817                 }
818                 else {
819                         (*target)->buf[(*target)->BufUsed] = ch;
820                         (*target)->BufUsed++;
821                 }
822         }
823         
824         if ((*target)->BufUsed + 4 > (*target)->BufSize)
825                 IncreaseBuf(*target, 1, 0);
826
827         (*target)->buf[(*target)->BufUsed++] = '?';
828         (*target)->buf[(*target)->BufUsed++] = '=';
829         (*target)->buf[(*target)->BufUsed] = '\0';
830         return (*target)->BufUsed;;
831 }
832
833 void StrBufReplaceChars(StrBuf *buf, char search, char replace)
834 {
835         long i;
836         if (buf == NULL)
837                 return;
838         for (i=0; i<buf->BufUsed; i++)
839                 if (buf->buf[i] == search)
840                         buf->buf[i] = replace;
841
842 }