Back to index

libcitadel  8.12
tools.c
Go to the documentation of this file.
00001 /*
00002  * A basic toolset containing miscellaneous functions for string manipluation,
00003  * encoding/decoding, and a bunch of other stuff.
00004  *
00005  * Copyright (c) 1987-2011 by the citadel.org team
00006  *
00007  * This program is open source software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 3 of the License, or
00010  * (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
00020  */
00021 
00022 
00023 #include <stdlib.h>
00024 #include <unistd.h>
00025 #include <stdio.h>
00026 #include <signal.h>
00027 #include <sys/types.h>
00028 #include <ctype.h>
00029 #include <string.h>
00030 #include <sys/stat.h>
00031 #include <errno.h>
00032 #include <limits.h>
00033 
00034 #if TIME_WITH_SYS_TIME
00035 # include <sys/time.h>
00036 # include <time.h>
00037 #else
00038 # if HAVE_SYS_TIME_H
00039 #  include <sys/time.h>
00040 # else
00041 #  include <time.h>
00042 # endif
00043 #endif
00044 
00045 #include "libcitadel.h"
00046 
00047 
00048 #define TRUE  1
00049 #define FALSE 0
00050 
00051 typedef unsigned char byte;       /* Byte type */
00052 
00053 /* Base64 encoding table */
00054 const byte etable[256] = {
00055        65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
00056        82, 83, 84, 85, 86, 87, 88, 89, 90, 97, 98, 99, 100, 101, 102, 103,
00057        104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117,
00058        118, 119, 120, 121, 122, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 43,
00059        47, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00060        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00061        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00062        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00063        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00064        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00065        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00066        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
00067        0, 0, 0, 0, 0, 0, 0, 0, 0
00068 };
00069 
00070 /* Base64 decoding table */
00071 const byte dtable[256] = {
00072        128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
00073        128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
00074        128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
00075        128, 62, 128, 128, 128, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
00076        128, 128, 128, 0, 128, 128, 128, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
00077        12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 128, 128, 128,
00078        128, 128, 128, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
00079        40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 128, 128, 128, 128,
00080        128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
00081        128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
00082        128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
00083        128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
00084        128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
00085        128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
00086        128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
00087        128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
00088        128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
00089        128, 128, 0
00090 };
00091 
00092 /*
00093  * copy a string into a buffer of a known size. abort if we exceed the limits
00094  *
00095  * dest       the targetbuffer
00096  * src the source string
00097  * n   the size od dest
00098  *
00099  * returns the number of characters copied if dest is big enough, -n if not.
00100  */
00101 int safestrncpy(char *dest, const char *src, size_t n)
00102 {
00103        int i = 0;
00104 
00105        if (dest == NULL || src == NULL) {
00106               fprintf(stderr, "safestrncpy: NULL argument\n");
00107               abort();
00108        }
00109 
00110        do {
00111               dest[i] = src[i];
00112               if (dest[i] == 0) return i;
00113               ++i;
00114        } while (i<n);
00115        dest[n - 1] = 0;
00116        return -i;
00117 }
00118 
00119 
00120 
00121 /*
00122  * num_tokens()  -  discover number of parameters/tokens in a string
00123  */
00124 int num_tokens(const char *source, char tok)
00125 {
00126        int count = 1;
00127        const char *ptr = source;
00128 
00129        if (source == NULL) {
00130               return (0);
00131        }
00132 
00133        while (*ptr != '\0') {
00134               if (*ptr++ == tok) {
00135                      ++count;
00136               }
00137        }
00138        
00139        return (count);
00140 }
00141 
00142 //extern void cit_backtrace(void);
00143 
00144 
00145 /*
00146  * extract_token() - a string tokenizer
00147  * returns -1 if not found, or length of token.
00148  */
00149 long extract_token(char *dest, const char *source, int parmnum, char separator, int maxlen)
00150 {
00151        const char *s;                     //* source * /
00152        int len = 0;                //* running total length of extracted string * /
00153        int current_token = 0;             //* token currently being processed * /
00154 
00155        s = source;
00156 
00157        if (dest == NULL) {
00158               return(-1);
00159        }
00160 
00161        //cit_backtrace();
00162        //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
00163        dest[0] = 0;
00164 
00165        if (s == NULL) {
00166               return(-1);
00167        }
00168        
00169        maxlen--;
00170 
00171        while (*s) {
00172               if (*s == separator) {
00173                      ++current_token;
00174               }
00175               if ( (current_token == parmnum) && 
00176                    (*s != separator) && 
00177                    (len < maxlen) ) {
00178                      dest[len] = *s;
00179                      ++len;
00180               }
00181               else if ((current_token > parmnum) || (len >= maxlen)) {
00182                      break;
00183               }
00184               ++s;
00185        }
00186 
00187        dest[len] = '\0';
00188        if (current_token < parmnum) {
00189               //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
00190               return(-1);
00191        }
00192        //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
00193        return(len);
00194 }
00195 //*/
00196 
00197 
00198 /*
00199  * extract_token() - a string tokenizer
00200  * /
00201 long extract_token(char *dest, const char *source, int parmnum, char separator, int maxlen)
00202 {
00203        char *d;             // dest
00204        const char *s;              // source
00205        int count = 0;
00206        int len = 0;
00207 
00208        
00209        //cit_backtrace();
00210        //lprintf (CTDL_DEBUG, "test >: n: %d sep: %c source: %s \n willi \n", parmnum, separator, source);
00211        strcpy(dest, "");
00212 
00213        //  Locate desired parameter 
00214        s = source;
00215        while (count < parmnum) {
00216               //  End of string, bail!
00217               if (!*s) {
00218                      s = NULL;
00219                      break;
00220               }
00221               if (*s == separator) {
00222                      count++;
00223               }
00224               s++;
00225        }
00226        if (!s) {
00227               //lprintf (CTDL_DEBUG,"test <!: %s\n", dest);
00228               return -1;           // Parameter not found
00229        }
00230        
00231        for (d = dest; *s && *s != separator && ++len<maxlen; s++, d++) {
00232               *d = *s;
00233        }
00234        *d = 0;
00235        //lprintf (CTDL_DEBUG,"test <: %d; %s\n", len, dest);
00236        return 0;
00237 }
00238 */
00239 
00240 
00241 /*
00242  * remove_token() - a tokenizer that kills, maims, and destroys
00243  */
00244 void remove_token(char *source, int parmnum, char separator)
00245 {
00246        char *d, *s;         /* dest, source */
00247        int count = 0;
00248 
00249        /* Find desired parameter */
00250        d = source;
00251        while (count < parmnum) {
00252               /* End of string, bail! */
00253               if (!*d) {
00254                      d = NULL;
00255                      break;
00256               }
00257               if (*d == separator) {
00258                      count++;
00259               }
00260               d++;
00261        }
00262        if (!d) return;             /* Parameter not found */
00263 
00264        /* Find next parameter */
00265        s = d;
00266        while (*s && *s != separator) {
00267               s++;
00268        }
00269 
00270        /* Hack and slash */
00271        if (*s)
00272               strcpy(d, ++s);
00273        else if (d == source)
00274               *d = 0;
00275        else
00276               *--d = 0;
00277        /*
00278        while (*s) {
00279               *d++ = *s++;
00280        }
00281        *d = 0;
00282        */
00283 }
00284 
00285 
00286 /*
00287  * extract_int()  -  extract an int parm w/o supplying a buffer
00288  */
00289 int extract_int(const char *source, int parmnum)
00290 {
00291        char buf[32];
00292        
00293        if (extract_token(buf, source, parmnum, '|', sizeof buf) > 0)
00294               return(atoi(buf));
00295        else
00296               return 0;
00297 }
00298 
00299 /*
00300  * extract_long()  -  extract an long parm w/o supplying a buffer
00301  */
00302 long extract_long(const char *source, int parmnum)
00303 {
00304        char buf[32];
00305        
00306        if (extract_token(buf, source, parmnum, '|', sizeof buf) > 0)
00307               return(atol(buf));
00308        else
00309               return 0;
00310 }
00311 
00312 
00313 /*
00314  * extract_unsigned_long() - extract an unsigned long parm
00315  */
00316 unsigned long extract_unsigned_long(const char *source, int parmnum)
00317 {
00318        char buf[32];
00319 
00320        if (extract_token(buf, source, parmnum, '|', sizeof buf) > 0)
00321               return strtoul(buf, NULL, 10);
00322        else 
00323               return 0;
00324 }
00325 
00326 
00327 /*
00328  * CtdlDecodeBase64() and CtdlEncodeBase64() are adaptations of code by John Walker.
00329  */
00330 
00331 size_t CtdlEncodeBase64(char *dest, const char *source, size_t sourcelen, int linebreaks)
00332 {
00333        int i, hiteof = FALSE;
00334        int spos = 0;
00335        int dpos = 0;
00336        int thisline = 0;
00337 
00338        while (!hiteof) {
00339               byte igroup[3], ogroup[4];
00340               int c, n;
00341 
00342               igroup[0] = igroup[1] = igroup[2] = 0;
00343               for (n = 0; n < 3; n++) {
00344                      if (spos >= sourcelen) {
00345                             hiteof = TRUE;
00346                             break;
00347                      }
00348                      c = source[spos++];
00349                      igroup[n] = (byte) c;
00350               }
00351               if (n > 0) {
00352                      ogroup[0] = etable[igroup[0] >> 2];
00353                      ogroup[1] =
00354                          etable[((igroup[0] & 3) << 4) |
00355                                (igroup[1] >> 4)];
00356                      ogroup[2] =
00357                          etable[((igroup[1] & 0xF) << 2) |
00358                                (igroup[2] >> 6)];
00359                      ogroup[3] = etable[igroup[2] & 0x3F];
00360 
00361                      /*
00362                       * Replace characters in output stream with "=" pad
00363                       * characters if fewer than three characters were
00364                       * read from the end of the input stream. 
00365                       */
00366 
00367                      if (n < 3) {
00368                             ogroup[3] = '=';
00369                             if (n < 2) {
00370                                    ogroup[2] = '=';
00371                             }
00372                      }
00373                      for (i = 0; i < 4; i++) {
00374                             dest[dpos++] = ogroup[i];
00375                             dest[dpos] = 0;
00376                      }
00377                      thisline += 4;
00378                      if ( (linebreaks) && (thisline > 70) ) {
00379                             dest[dpos++] = '\r';
00380                             dest[dpos++] = '\n';
00381                             dest[dpos] = 0;
00382                             thisline = 0;
00383                      }
00384               }
00385        }
00386        if ( (linebreaks) && (thisline > 70) ) {
00387               dest[dpos++] = '\r';
00388               dest[dpos++] = '\n';
00389               dest[dpos] = 0;
00390        }
00391 
00392        return(dpos);
00393 }
00394 
00395 
00396 
00397 /* 
00398  * Convert base64-encoded to binary.  Returns the length of the decoded data.
00399  * It will stop after reading 'length' bytes.
00400  */
00401 int CtdlDecodeBase64(char *dest, const char *source, size_t length)
00402 {
00403     int i, c;
00404     int dpos = 0;
00405     int spos = 0;
00406 
00407     while (TRUE) {
00408        byte a[4], b[4], o[3];
00409 
00410        for (i = 0; i < 4; i++) {
00411            if (spos >= length) {
00412               return(dpos);
00413            }
00414            c = source[spos++];
00415 
00416            if (c == 0) {
00417               if (i > 0) {
00418                   return(dpos);
00419               }
00420               return(dpos);
00421            }
00422            if (dtable[c] & 0x80) {
00423               /* Ignoring errors: discard invalid character. */
00424               i--;
00425               continue;
00426            }
00427            a[i] = (byte) c;
00428            b[i] = (byte) dtable[c];
00429        }
00430        o[0] = (b[0] << 2) | (b[1] >> 4);
00431        o[1] = (b[1] << 4) | (b[2] >> 2);
00432        o[2] = (b[2] << 6) | b[3];
00433         i = a[2] == '=' ? 1 : (a[3] == '=' ? 2 : 3);
00434        if (i>=1) dest[dpos++] = o[0];
00435        if (i>=2) dest[dpos++] = o[1];
00436        if (i>=3) dest[dpos++] = o[2];
00437        dest[dpos] = 0;
00438        if (i < 3) {
00439            return(dpos);
00440        }
00441     }
00442 }
00443 
00444 
00445 /*
00446  * if we send out non ascii subjects, we encode it this way.
00447  */
00448 char *rfc2047encode(char *line, long length)
00449 {
00450        char *AlreadyEncoded;
00451        char *result;
00452        long end;
00453 #define UTF8_HEADER "=?UTF-8?B?"
00454 
00455        /* check if we're already done */
00456        AlreadyEncoded = strstr(line, "=?");
00457        if ((AlreadyEncoded != NULL) &&
00458            ((strstr(AlreadyEncoded, "?B?") != NULL)||
00459             (strstr(AlreadyEncoded, "?Q?") != NULL)))
00460        {
00461               return strdup(line);
00462        }
00463 
00464        result = (char*) malloc(sizeof(UTF8_HEADER) + 4 + length * 2);
00465        strncpy (result, UTF8_HEADER, strlen (UTF8_HEADER));
00466        CtdlEncodeBase64(result + strlen(UTF8_HEADER), line, length, 0);
00467        end = strlen (result);
00468         result[end]='?';
00469        result[end+1]='=';
00470        result[end+2]='\0';
00471        return result;
00472 }
00473 
00474 /*
00475  * removes double slashes from pathnames
00476  * allows / disallows trailing slashes
00477  */
00478 void StripSlashes(char *Dir, int TrailingSlash)
00479 {
00480        char *a, *b;
00481 
00482        a = b = Dir;
00483 
00484        while (!IsEmptyStr(a)) {
00485               if (*a == '/') {
00486                      while (*a == '/')
00487                             a++;
00488                      *b = '/';
00489                      b++;
00490               }
00491               else {
00492                      *b = *a;
00493                      b++; a++;
00494               }
00495        }
00496        if ((TrailingSlash) && (*(b - 1) != '/')){
00497               *b = '/';
00498               b++;
00499        }
00500        *b = '\0';
00501 
00502 }
00503 
00504 /*
00505  * Strip leading and trailing spaces from a string
00506  */
00507 size_t striplt(char *buf) {
00508        char *first_nonspace = NULL;
00509        char *last_nonspace = NULL;
00510        char *ptr;
00511        size_t new_len = 0;
00512 
00513        if ((buf == NULL) || (*buf == '\0')) {
00514               return 0;
00515        }
00516 
00517        for (ptr=buf; *ptr!=0; ++ptr) {
00518               if (!isspace(*ptr)) {
00519                      if (!first_nonspace) {
00520                             first_nonspace = ptr;
00521                      }
00522                      last_nonspace = ptr;
00523               }
00524        }
00525 
00526        if ((!first_nonspace) || (!last_nonspace)) {
00527               buf[0] = 0;
00528               return 0;
00529        }
00530 
00531        new_len = last_nonspace - first_nonspace + 1;
00532        memmove(buf, first_nonspace, new_len);
00533        buf[new_len] = 0;
00534        return new_len;
00535 }
00536 
00537 
00544 int haschar(const char *st, int ch)
00545 {
00546        const char *ptr;
00547        int b;
00548        b = 0;
00549        ptr = st;
00550        while (!IsEmptyStr(ptr))
00551        {
00552               if (*ptr == ch)
00553                      ++b;
00554               ptr ++;
00555        }
00556        return (b);
00557 }
00558 
00559 
00560 
00561 
00562 
00563 /*
00564  * Format a date/time stamp for output 
00565  * seconds is whether to print the seconds
00566  */
00567 void fmt_date(char *buf, size_t n, time_t thetime, int seconds) {
00568        struct tm tm;
00569        int hour;
00570 
00571        /* Month strings for date conversions ... this needs to be localized eventually */
00572        char *fmt_date_months[12] = {
00573               "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
00574        };
00575 
00576        strcpy(buf, "");
00577        localtime_r(&thetime, &tm);
00578 
00579        hour = tm.tm_hour;
00580        if (hour == 0)       hour = 12;
00581        else if (hour > 12) hour = hour - 12;
00582 
00583        if (seconds) {
00584               snprintf(buf, n, "%s %d %4d %d:%02d:%02d%s",
00585                      fmt_date_months[tm.tm_mon],
00586                      tm.tm_mday,
00587                      tm.tm_year + 1900,
00588                      hour,
00589                      tm.tm_min,
00590                      tm.tm_sec,
00591                      ( (tm.tm_hour >= 12) ? "pm" : "am" )
00592               );
00593        } else {
00594               snprintf(buf, n, "%s %d %4d %d:%02d%s",
00595                      fmt_date_months[tm.tm_mon],
00596                      tm.tm_mday,
00597                      tm.tm_year + 1900,
00598                      hour,
00599                      tm.tm_min,
00600                      ( (tm.tm_hour >= 12) ? "pm" : "am" )
00601               );
00602        }
00603 }
00604 
00605 
00606 
00607 /*
00608  * Determine whether the specified message number is contained within the
00609  * specified sequence set.
00610  */
00611 int is_msg_in_sequence_set(const char *mset, long msgnum) {
00612        int num_sets;
00613        int s;
00614        char setstr[128], lostr[128], histr[128];
00615        long lo, hi;
00616 
00617        num_sets = num_tokens(mset, ',');
00618        for (s=0; s<num_sets; ++s) {
00619               extract_token(setstr, mset, s, ',', sizeof setstr);
00620 
00621               extract_token(lostr, setstr, 0, ':', sizeof lostr);
00622               if (num_tokens(setstr, ':') >= 2) {
00623                      extract_token(histr, setstr, 1, ':', sizeof histr);
00624                      if (!strcmp(histr, "*")) {
00625                             snprintf(histr, sizeof histr, "%ld", LONG_MAX);
00626                      }
00627               } 
00628               else {
00629                      strcpy(histr, lostr);
00630               }
00631               lo = atol(lostr);
00632               hi = atol(histr);
00633 
00634               if ((msgnum >= lo) && (msgnum <= hi)) return(1);
00635        }
00636 
00637        return(0);
00638 }
00639 
00647 char *memreadline(char *start, char *buf, int maxlen)
00648 {
00649        char ch;
00650        char *ptr;
00651        int len = 0;         
00653        ptr = start;
00654 
00655        while (1) {
00656               ch = *ptr++;
00657               if ((len + 1 < (maxlen)) && (ch != 13) && (ch != 10)) {
00658                      buf[len++] = ch;
00659               }
00660               if ((ch == 10) || (ch == 0)) {
00661                      buf[len] = 0;
00662                      return ptr;
00663               }
00664        }
00665 }
00666 
00667 
00676 char *memreadlinelen(char *start, char *buf, int maxlen, int *retlen)
00677 {
00678        char ch;
00679        char *ptr;
00680        int len = 0;         
00682        ptr = start;
00683 
00684        while (1) {
00685               ch = *ptr++;
00686               if ((len + 1 < (maxlen)) && (ch != 13) && (ch != 10)) {
00687                      buf[len++] = ch;
00688               }
00689               if ((ch == 10) || (ch == 0)) {
00690                      buf[len] = 0;
00691                      *retlen = len;
00692                      return ptr;
00693               }
00694        }
00695 }
00696 
00697 
00705 const char *cmemreadline(const char *start, char *buf, int maxlen)
00706 {
00707        char ch;
00708        const char *ptr;
00709        int len = 0;         
00711        ptr = start;
00712 
00713        while (1) {
00714               ch = *ptr++;
00715               if ((len + 1 < (maxlen)) && (ch != 13) && (ch != 10)) {
00716                      buf[len++] = ch;
00717               }
00718               if ((ch == 10) || (ch == 0)) {
00719                      buf[len] = 0;
00720                      return ptr;
00721               }
00722        }
00723 }
00724 
00725 
00734 const char *cmemreadlinelen(const char *start, char *buf, int maxlen, int *retlen)
00735 {
00736        char ch;
00737        const char *ptr;
00738        int len = 0;         
00740        ptr = start;
00741 
00742        while (1) {
00743               ch = *ptr++;
00744               if ((len + 1 < (maxlen)) && (ch != 13) && (ch != 10)) {
00745                      buf[len++] = ch;
00746               }
00747               if ((ch == 10) || (ch == 0)) {
00748                      buf[len] = 0;
00749                      *retlen = len;
00750                      return ptr;
00751               }
00752        }
00753 }
00754 
00755 
00756 
00757 
00758 /*
00759  * Strip a boundarized substring out of a string (for example, remove
00760  * parentheses and anything inside them).
00761  */
00762 int stripout(char *str, char leftboundary, char rightboundary) {
00763        int a;
00764         int lb = (-1);
00765         int rb = (-1);
00766 
00767         for (a = 0; a < strlen(str); ++a) {
00768                 if (str[a] == leftboundary) lb = a;
00769                 if (str[a] == rightboundary) rb = a;
00770         }
00771 
00772         if ( (lb > 0) && (rb > lb) ) {
00773                 strcpy(&str[lb - 1], &str[rb + 1]);
00774               return 1;
00775         }
00776 
00777         else if ( (lb == 0) && (rb > lb) ) {
00778                 strcpy(str, &str[rb + 1]);
00779               return 1;
00780         }
00781        return 0;
00782 }
00783 
00784 
00785 /*
00786  * Reduce a string down to a boundarized substring (for example, remove
00787  * parentheses and anything outside them).
00788  */
00789 long stripallbut(char *str, char leftboundary, char rightboundary) {
00790        long len = 0;
00791 
00792        char *lb = NULL;
00793        char *rb = NULL;
00794 
00795        lb = strrchr(str, leftboundary);
00796        if (lb != NULL) {
00797               ++lb;
00798               rb = strchr(str, rightboundary);
00799               if ((rb != NULL) && (rb >= lb))  {
00800                      *rb = 0;
00801                      fflush(stderr);
00802                      len = (long)rb - (long)lb;
00803                      memmove(str, lb, len);
00804                      str[len] = 0;
00805                      return(len);
00806               }
00807        }
00808 
00809        return (long)strlen(str);
00810 }
00811 
00812 
00813 char *myfgets(char *s, int size, FILE *stream) {
00814        char *ret = fgets(s, size, stream);
00815        char *nl;
00816 
00817        if (ret != NULL) {
00818               nl = strchr(s, '\n');
00819 
00820               if (nl != NULL)
00821                      *nl = 0;
00822        }
00823 
00824        return ret;
00825 }
00826 
00833 void urlesc(char *outbuf, size_t oblen, char *strbuf)
00834 {
00835        int a, b, c, len, eclen, olen;
00836        char *ec = " +#&;`'|*?-~<>^()[]{}/$\"\\";
00837 
00838        strcpy(outbuf, "");
00839        len = strlen(strbuf);
00840        eclen = strlen(ec);
00841        olen = 0;
00842        for (a = 0; a < len; ++a) {
00843               c = 0;
00844               for (b = 0; b < eclen; ++b) {
00845                      if (strbuf[a] == ec[b])
00846                             c = 1;
00847               }
00848               if (c == 1) {
00849                      snprintf(&outbuf[olen], oblen - olen, "%%%02x", strbuf[a]);
00850                      olen += 3;
00851               }
00852               else 
00853                      outbuf[olen ++] = strbuf[a];
00854        }
00855        outbuf[olen] = '\0';
00856 }
00857 
00858 
00859 
00860 /*
00861  * In our world, we want strcpy() to be able to work with overlapping strings.
00862  */
00863 #ifdef strcpy
00864 #undef strcpy
00865 #endif
00866 char *strcpy(char *dest, const char *src) {
00867        memmove(dest, src, (strlen(src) + 1) );
00868        return(dest);
00869 }
00870 
00871 
00872 /*
00873  * Generate a new, globally unique UID parameter for a calendar etc. object
00874  */
00875 void generate_uuid(char *buf) {
00876        static int seq = (-1);
00877        static int no_kernel_uuid = 0;
00878 
00879        /* If we are running on Linux then we have a kernelspace uuid generator available */
00880 
00881        if (no_kernel_uuid == 0) {
00882               FILE *fp;
00883               fp = fopen("/proc/sys/kernel/random/uuid", "rb");
00884               if (fp) {
00885                      int rv;
00886                      rv = fread(buf, 36, 1, fp);
00887                      fclose(fp);
00888                      if (rv == 1) return;
00889               }
00890        }
00891 
00892        /* If the kernel didn't provide us with a uuid, we generate a pseudo-random one */
00893 
00894        no_kernel_uuid = 1;
00895 
00896        if (seq == (-1)) {
00897               seq = (int)rand();
00898        }
00899        ++seq;
00900        seq = (seq % 0x0FFF) ;
00901 
00902        sprintf(buf, "%08lx-%04lx-4%03x-a%03x-%012lx",
00903               (long)time(NULL),
00904               (long)getpid(),
00905               seq,
00906               seq,
00907               (long)rand()
00908        );
00909 }
00910 
00911 /*
00912  * bmstrcasestr() -- case-insensitive substring search
00913  *
00914  * This uses the Boyer-Moore search algorithm and is therefore quite fast.
00915  * The code is roughly based on the strstr() replacement from 'tin' written
00916  * by Urs Jannsen.
00917  */
00918 inline static char *_bmstrcasestr_len(char *text, size_t textlen, const char *pattern, size_t patlen) {
00919 
00920        register unsigned char *p, *t;
00921        register int i, j, *delta;
00922        register size_t p1;
00923        int deltaspace[256];
00924 
00925        if (!text) return(NULL);
00926        if (!pattern) return(NULL);
00927 
00928        /* algorithm fails if pattern is empty */
00929        if ((p1 = patlen) == 0)
00930               return (text);
00931 
00932        /* code below fails (whenever i is unsigned) if pattern too long */
00933        if (p1 > textlen)
00934               return (NULL);
00935 
00936        /* set up deltas */
00937        delta = deltaspace;
00938        for (i = 0; i <= 255; i++)
00939               delta[i] = p1;
00940        for (p = (unsigned char *) pattern, i = p1; --i > 0;)
00941               delta[tolower(*p++)] = i;
00942 
00943        /*
00944         * From now on, we want patlen - 1.
00945         * In the loop below, p points to the end of the pattern,
00946         * t points to the end of the text to be tested against the
00947         * pattern, and i counts the amount of text remaining, not
00948         * including the part to be tested.
00949         */
00950        p1--;
00951        p = (unsigned char *) pattern + p1;
00952        t = (unsigned char *) text + p1;
00953        i = textlen - patlen;
00954        while(1) {
00955               if (tolower(p[0]) == tolower(t[0])) {
00956                      if (strncasecmp ((const char *)(p - p1), (const char *)(t - p1), p1) == 0) {
00957                             return ((char *)t - p1);
00958                      }
00959               }
00960               j = delta[tolower(t[0])];
00961               if (i < j)
00962                      break;
00963               i -= j;
00964               t += j;
00965        }
00966        return (NULL);
00967 }
00968 
00969 /*
00970  * bmstrcasestr() -- case-insensitive substring search
00971  *
00972  * This uses the Boyer-Moore search algorithm and is therefore quite fast.
00973  * The code is roughly based on the strstr() replacement from 'tin' written
00974  * by Urs Jannsen.
00975  */
00976 char *bmstrcasestr(char *text, const char *pattern) {
00977        size_t textlen;
00978        size_t patlen;
00979 
00980        if (!text) return(NULL);
00981        if (!pattern) return(NULL);
00982 
00983        textlen = strlen (text);
00984        patlen = strlen (pattern);
00985 
00986        return _bmstrcasestr_len(text, textlen, pattern, patlen);
00987 }
00988 
00989 char *bmstrcasestr_len(char *text, size_t textlen, const char *pattern, size_t patlen) {
00990        return _bmstrcasestr_len(text, textlen, pattern, patlen);
00991 }
00992 
00993 
00994 
00995 
00996 /*
00997  * bmstrcasestr() -- case-insensitive substring search
00998  *
00999  * This uses the Boyer-Moore search algorithm and is therefore quite fast.
01000  * The code is roughly based on the strstr() replacement from 'tin' written
01001  * by Urs Jannsen.
01002  */
01003 inline static const char *_cbmstrcasestr_len(const char *text, size_t textlen, const char *pattern, size_t patlen) {
01004 
01005        register unsigned char *p, *t;
01006        register int i, j, *delta;
01007        register size_t p1;
01008        int deltaspace[256];
01009 
01010        if (!text) return(NULL);
01011        if (!pattern) return(NULL);
01012 
01013        /* algorithm fails if pattern is empty */
01014        if ((p1 = patlen) == 0)
01015               return (text);
01016 
01017        /* code below fails (whenever i is unsigned) if pattern too long */
01018        if (p1 > textlen)
01019               return (NULL);
01020 
01021        /* set up deltas */
01022        delta = deltaspace;
01023        for (i = 0; i <= 255; i++)
01024               delta[i] = p1;
01025        for (p = (unsigned char *) pattern, i = p1; --i > 0;)
01026               delta[tolower(*p++)] = i;
01027 
01028        /*
01029         * From now on, we want patlen - 1.
01030         * In the loop below, p points to the end of the pattern,
01031         * t points to the end of the text to be tested against the
01032         * pattern, and i counts the amount of text remaining, not
01033         * including the part to be tested.
01034         */
01035        p1--;
01036        p = (unsigned char *) pattern + p1;
01037        t = (unsigned char *) text + p1;
01038        i = textlen - patlen;
01039        while(1) {
01040               if (tolower(p[0]) == tolower(t[0])) {
01041                      if (strncasecmp ((const char *)(p - p1), (const char *)(t - p1), p1) == 0) {
01042                             return ((char *)t - p1);
01043                      }
01044               }
01045               j = delta[tolower(t[0])];
01046               if (i < j)
01047                      break;
01048               i -= j;
01049               t += j;
01050        }
01051        return (NULL);
01052 }
01053 
01054 /*
01055  * bmstrcasestr() -- case-insensitive substring search
01056  *
01057  * This uses the Boyer-Moore search algorithm and is therefore quite fast.
01058  * The code is roughly based on the strstr() replacement from 'tin' written
01059  * by Urs Jannsen.
01060  */
01061 const char *cbmstrcasestr(const char *text, const char *pattern) {
01062        size_t textlen;
01063        size_t patlen;
01064 
01065        if (!text) return(NULL);
01066        if (!pattern) return(NULL);
01067 
01068        textlen = strlen (text);
01069        patlen = strlen (pattern);
01070 
01071        return _cbmstrcasestr_len(text, textlen, pattern, patlen);
01072 }
01073 
01074 const char *cbmstrcasestr_len(const char *text, size_t textlen, const char *pattern, size_t patlen) {
01075        return _cbmstrcasestr_len(text, textlen, pattern, patlen);
01076 }
01077 
01078 /*
01079  * Local replacement for controversial C library function that generates
01080  * names for temporary files.  Included to shut up compiler warnings.
01081  */
01082 void CtdlMakeTempFileName(char *name, int len) {
01083        int i = 0;
01084 
01085        while (i++, i < 100) {
01086               snprintf(name, len, "/tmp/ctdl.%04lx.%04x",
01087                      (long)getpid(),
01088                      rand()
01089               );
01090               if (!access(name, F_OK)) {
01091                      return;
01092               }
01093        }
01094 }
01095 
01096 
01097 
01098 /*
01099  * Determine whether the specified message number is contained within the specified set.
01100  * Returns nonzero if the specified message number is in the specified message set string.
01101  */
01102 int is_msg_in_mset(const char *mset, long msgnum) {
01103        int num_sets;
01104        int s;
01105        char setstr[SIZ], lostr[SIZ], histr[SIZ];       /* was 1024 */
01106        long lo, hi;
01107 
01108        /*
01109         * Now set it for all specified messages.
01110         */
01111        num_sets = num_tokens(mset, ',');
01112        for (s=0; s<num_sets; ++s) {
01113               extract_token(setstr, mset, s, ',', sizeof setstr);
01114 
01115               extract_token(lostr, setstr, 0, ':', sizeof lostr);
01116               if (num_tokens(setstr, ':') >= 2) {
01117                      extract_token(histr, setstr, 1, ':', sizeof histr);
01118                      if (!strcmp(histr, "*")) {
01119                             snprintf(histr, sizeof histr, "%ld", LONG_MAX);
01120                      }
01121               }
01122               else {
01123                      strcpy(histr, lostr);
01124               }
01125               lo = atol(lostr);
01126               hi = atol(histr);
01127 
01128               if ((msgnum >= lo) && (msgnum <= hi)) return(1);
01129        }
01130 
01131        return(0);
01132 }
01133 
01134 
01135 /*
01136  * searches for a pattern within a search string
01137  * returns position in string
01138  */
01139 int pattern2(char *search, char *patn)
01140 {
01141        int a;
01142        int len, plen;
01143        len = strlen (search);
01144        plen = strlen (patn);
01145        for (a = 0; a < len; ++a) {
01146               if (!strncasecmp(&search[a], patn, plen))
01147                      return (a);
01148        }
01149        return (-1);
01150 }
01151 
01152 
01153 /*
01154  * Strip leading and trailing spaces from a string; with premeasured and adjusted length.
01155  * buf - the string to modify
01156  * len - length of the string. 
01157  */
01158 void stripltlen(char *buf, int *len)
01159 {
01160        int delta = 0;
01161        if (*len == 0) return;
01162        while ((*len > delta) && (isspace(buf[delta]))){
01163               delta ++;
01164        }
01165        memmove (buf, &buf[delta], *len - delta + 1);
01166        (*len) -=delta;
01167 
01168        if (*len == 0) return;
01169        while (isspace(buf[(*len) - 1])){
01170               buf[--(*len)] = '\0';
01171        }
01172 }
01173 
01174 
01175 /*
01176  * Convert all whitespace characters in a supplied string to underscores
01177  */
01178 void convert_spaces_to_underscores(char *str)
01179 {
01180        int len;
01181        int i;
01182 
01183        if (!str) return;
01184 
01185        len = strlen(str);
01186        for (i=0; i<len; ++i) {
01187               if (isspace(str[i])) {
01188                      str[i] = '_';
01189               }
01190        }
01191 }
01192 
01193 
01194 /*
01195  * check whether the provided string needs to be qp encoded or not
01196  */
01197 int CheckEncode(const char *pch, long len, const char *pche)
01198 {
01199        if (pche == NULL)
01200               pche = pch + len;
01201        while (pch < pche) {
01202               if (((unsigned char) *pch < 32) || 
01203                   ((unsigned char) *pch > 126)) {
01204                      return 1;
01205               }
01206               pch++;
01207        }
01208        return 0;
01209 }
01210