Annotation of libwww/Library/src/HTWWWStr.c, revision 2.34

2.1       frystyk     1: /*                                                                  HTWWWStr.c
                      2: **     WWW RELATED STRING UTILITIES
                      3: **
                      4: **     (c) COPYRIGHT MIT 1995.
                      5: **     Please first read the full copyright statement in the file COPYRIGH.
2.34    ! frystyk     6: **     @(#) $Id: HTWWWStr.c,v 2.33 1999/02/13 18:33:49 frystyk Exp $
2.1       frystyk     7: **
                      8: **      Now 13 95      Spwaned from HTString.c
                      9: */
                     10: 
                     11: /* Library include files */
2.24      frystyk    12: #include "wwwsys.h"
2.10      frystyk    13: #include "WWWUtil.h"
2.1       frystyk    14: #include "HTParse.h"
2.17      frystyk    15: #include "HTInet.h"
2.11      frystyk    16: #include "HTUser.h"
2.1       frystyk    17: #include "HTWWWStr.h"                                   /* Implemented here */
                     18: 
                     19: PRIVATE char * months[12] = {
                     20:     "Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"
                     21: };
                     22: 
2.8       frystyk    23: #ifndef HAVE_STRFTIME
2.1       frystyk    24: PRIVATE char * wkdays[7] = {
2.28      frystyk    25:     "Sun","Mon","Tue","Wed","Thu","Fri","Sat"
2.1       frystyk    26: };
                     27: #endif
                     28: 
                     29: /* ------------------------------------------------------------------------- */
                     30: 
                     31: /*     Find next Field
                     32: **     ---------------
                     33: **     Finds the next RFC822 token in a string
                     34: **     On entry,
                     35: **     *pstr   points to a string containing a word separated
                     36: **             by white white space "," ";" or "=". The word
                     37: **             can optionally be quoted using <"> or "<" ">"
                     38: **             Comments surrrounded by '(' ')' are filtered out
                     39: **
                     40: **     On exit,
                     41: **     *pstr   has been moved to the first delimiter past the
                     42: **             field
                     43: **             THE STRING HAS BEEN MUTILATED by a 0 terminator
                     44: **
                     45: **     Returns a pointer to the first word or NULL on error
                     46: */
                     47: PUBLIC char * HTNextField (char ** pstr)
                     48: {
                     49:     char * p = *pstr;
                     50:     char * start = NULL;
2.14      frystyk    51:     if (!pstr || !*pstr) return NULL;
2.1       frystyk    52:     while (1) {
                     53:        /* Strip white space and other delimiters */
2.21      frystyk    54:        while (*p && (isspace((int) *p) || *p==',' || *p==';' || *p=='=')) p++;
2.1       frystyk    55:        if (!*p) {
                     56:            *pstr = p;
                     57:            return NULL;                                         /* No field */
                     58:        }
                     59: 
                     60:        if (*p == '"') {                                     /* quoted field */
                     61:            start = ++p;
                     62:            for(;*p && *p!='"'; p++)
                     63:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                     64:            break;                          /* kr95-10-9: needs to stop here */
                     65:        } else if (*p == '<') {                              /* quoted field */
                     66:            start = ++p;
                     67:            for(;*p && *p!='>'; p++)
                     68:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                     69:            break;                          /* kr95-10-9: needs to stop here */
                     70:        } else if (*p == '(') {                                   /* Comment */
                     71:            for(;*p && *p!=')'; p++)
                     72:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                     73:            p++;
                     74:        } else {                                              /* Spool field */
                     75:            start = p;
2.21      frystyk    76:            while(*p && !isspace((int) *p) && *p!=',' && *p!=';' && *p!='=')
2.1       frystyk    77:                p++;
                     78:            break;                                                 /* Got it */
                     79:        }
                     80:     }
2.22      frystyk    81:     if (*p) *p++ = '\0';
                     82:     *pstr = p;
                     83:     return start;
                     84: }
                     85: 
                     86: /*     Find next LWS delimited token
                     87: **     -----------------------------
                     88: **     On entry,
                     89: **     *pstr   points to a string containing a word separated
                     90: **             by white white space "," ";" or "=". The word
                     91: **             can optionally be quoted using <"> or "<" ">"
                     92: **             Comments surrrounded by '(' ')' are filtered out
                     93: **
                     94: **     On exit,
                     95: **     *pstr   has been moved to the first delimiter past the
                     96: **             field
                     97: **             THE STRING HAS BEEN MUTILATED by a 0 terminator
                     98: **
                     99: **     Returns a pointer to the first word or NULL on error
                    100: */
                    101: PUBLIC char * HTNextLWSToken (char ** pstr)
                    102: {
                    103:     char * p = *pstr;
                    104:     char * start = NULL;
                    105:     if (!pstr || !*pstr) return NULL;
                    106: 
                    107:     /* Strip initial white space  */
                    108:     while (*p && (isspace((int) *p))) p++;
                    109:     if (!*p) {
                    110:        *pstr = p;
                    111:        return NULL;                                     /* No field */
                    112:     }
                    113: 
                    114:     /* Now search for the next white space */
                    115:     start = p;
                    116:     while(*p && !isspace((int) *p)) p++;
                    117: 
2.1       frystyk   118:     if (*p) *p++ = '\0';
                    119:     *pstr = p;
                    120:     return start;
                    121: }
                    122: 
2.16      frystyk   123: /*     Find next Name-value pair
                    124: **     -------------------------
                    125: **     This is the same as HTNextField but it does not look for '=' as a
                    126: **     separator so if there is a name-value pair then both parts are
                    127: **     returned.
                    128: **     Returns a pointer to the first word or NULL on error
                    129: */
                    130: PUBLIC char * HTNextPair (char ** pstr)
                    131: {
                    132:     char * p = *pstr;
                    133:     char * start = NULL;
                    134:     if (!pstr || !*pstr) return NULL;
                    135:     while (1) {
                    136:        /* Strip white space and other delimiters */
                    137:        while (*p && (*p==',' || *p==';')) p++;
                    138:        if (!*p) {
                    139:            *pstr = p;
                    140:            return NULL;                                         /* No field */
                    141:        }
                    142: 
                    143:        if (*p == '"') {                                     /* quoted field */
                    144:            start = ++p;
                    145:            for(;*p && *p!='"'; p++)
                    146:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                    147:            break;                          /* kr95-10-9: needs to stop here */
                    148:        } else if (*p == '<') {                              /* quoted field */
                    149:            start = ++p;
                    150:            for(;*p && *p!='>'; p++)
                    151:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                    152:            break;                          /* kr95-10-9: needs to stop here */
                    153:        } else if (*p == '(') {                                   /* Comment */
                    154:            for(;*p && *p!=')'; p++)
                    155:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                    156:            p++;
                    157:        } else {                                              /* Spool field */
                    158:            start = p;
                    159:            while(*p && *p!=',' && *p!=';')
2.20      frystyk   160:                p++;
2.33      frystyk   161:            break;                                                 /* Got it */
                    162:        }
                    163:     }
                    164:     if (*p) *p++ = '\0';
                    165:     *pstr = p;
                    166:     return start;
                    167: }
                    168: 
                    169: /*     Find next element in a comma separated string
                    170: **     ---------------------------------------------
                    171: **     This is the same as HTNextPair but it does not look for anything
                    172: **     else than ',' as separator
                    173: **     Returns a pointer to the first word or NULL on error
                    174: */
                    175: PUBLIC char * HTNextElement (char ** pstr)
                    176: {
                    177:     char * p = *pstr;
                    178:     char * start = NULL;
                    179:     if (!pstr || !*pstr) return NULL;
                    180: 
                    181:     /* Strip white space and other delimiters */
                    182:     while (*p && ((isspace((int) *p)) || *p==',')) p++;
                    183:     if (!*p) {
                    184:        *pstr = p;
                    185:        return NULL;                                             /* No field */
                    186:     }
                    187:     start = p;
                    188:     while (1) {
                    189:        if (*p == '"') {                                     /* quoted field */
                    190:            for(;*p && *p!='"'; p++)
                    191:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                    192:            p++;
                    193:        } else if (*p == '<') {                              /* quoted field */
                    194:            for(;*p && *p!='>'; p++)
                    195:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                    196:            p++;
                    197:        } else if (*p == '(') {                                   /* Comment */
                    198:            for(;*p && *p!=')'; p++)
                    199:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                    200:            p++;
                    201:        } else {                                              /* Spool field */
                    202:            while (*p && *p!=',') p++;
2.20      frystyk   203:            break;                                                 /* Got it */
                    204:        }
                    205:     }
                    206:     if (*p) *p++ = '\0';
                    207:     *pstr = p;
                    208:     return start;
                    209: }
                    210: 
                    211: /*     Find next "/" delimied segment
                    212: **     ------------------------------
                    213: **     This is the same as HTNextField but it includes "/" as a delimiter.
                    214: **     Returns a pointer to the first segment or NULL on error
                    215: */
                    216: PUBLIC char * HTNextSegment (char ** pstr)
                    217: {
                    218:     char * p = *pstr;
                    219:     char * start = NULL;
                    220:     if (!pstr || !*pstr) return NULL;
                    221:     while (1) {
                    222:        /* Strip white space and other delimiters */
2.21      frystyk   223:        while (*p && (isspace((int) *p) || *p==',' || *p==';' || *p=='=' || *p=='/')) p++;
2.20      frystyk   224:        if (!*p) {
                    225:            *pstr = p;
                    226:            return NULL;                                         /* No field */
                    227:        }
                    228: 
                    229:        if (*p == '"') {                                     /* quoted field */
                    230:            start = ++p;
                    231:            for(;*p && *p!='"'; p++)
                    232:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                    233:            break;                          /* kr95-10-9: needs to stop here */
                    234:        } else if (*p == '<') {                              /* quoted field */
                    235:            start = ++p;
                    236:            for(;*p && *p!='>'; p++)
                    237:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                    238:            break;                          /* kr95-10-9: needs to stop here */
                    239:        } else if (*p == '(') {                                   /* Comment */
                    240:            for(;*p && *p!=')'; p++)
                    241:                if (*p == '\\' && *(p+1)) p++;         /* Skip escaped chars */
                    242:            p++;
                    243:        } else {                                              /* Spool field */
                    244:            start = p;
2.21      frystyk   245:            while(*p && !isspace((int) *p) && *p!=',' && *p!=';' && *p!='=' && *p!='/')
2.16      frystyk   246:                p++;
                    247:            break;                                                 /* Got it */
                    248:        }
                    249:     }
                    250:     if (*p) *p++ = '\0';
                    251:     *pstr = p;
                    252:     return start;
                    253: }
                    254: 
2.1       frystyk   255: /*
2.14      frystyk   256: **     Find the next s-expression token from a string of characters.
                    257: **     We return the name of this expression and the param points to the
                    258: **     parameters. 
                    259: **
                    260: **     NOTE: The string has been mutilated by '/0's
                    261: */
                    262: PUBLIC char * HTNextSExp (char ** exp, char ** param)
                    263: {
                    264:     char * p = *exp;
                    265:     char * name = NULL;
                    266:     if (!exp || !*exp) return NULL;
2.21      frystyk   267:     while (*p && isspace((int) *p)) p++;               /* Strip leading white space */
2.14      frystyk   268:     if (!*p) {
                    269:        *exp = p;
                    270:        return NULL;                                             /* No field */
                    271:     }
                    272:     if (*p == '{') {                                        /* Open bracket */
                    273:        int cnt = 1;
                    274:        /*
                    275:        **  Look for name of this expression. If we find a token then search
                    276:        **  for the rest of the expression and remove the end '}'
                    277:        */
                    278:        p++;
                    279:        if ((name = HTNextField(&p)) == NULL) return NULL;
2.21      frystyk   280:        while (*p && isspace((int) *p)) p++;
2.14      frystyk   281:        *param = p;
                    282:        while (*p) {
                    283:            if (*p == '{') cnt++;
                    284:            if (*p == '}') cnt--;
                    285:            if (!cnt) {
                    286:                *p = '\0';
                    287:                break;
                    288:            }
                    289:            p++;
                    290:        }
                    291:     }
                    292:     return name;
                    293: }
                    294: 
                    295: /*
2.1       frystyk   296: **     Returns a Message-ID string including the open '<' and the closing '>'.
                    297: **     The format of the string is:
                    298: **
                    299: **             "<" time-in-sec "Z" process-id "@" FQDN ">"
                    300: **
                    301: **     or on systems that doesn't have process-id:
                    302: **
                    303: **             "<" time-in-sec "Z" user "@" FQDN ">"
                    304: **
                    305: **     Returns a pointer to the MessageID
                    306: */
2.11      frystyk   307: PUBLIC const char * HTMessageIdStr (HTUserProfile * up)
2.1       frystyk   308: {
                    309:     static char buf[80];
                    310:     time_t sectime = time(NULL);
2.8       frystyk   311: #ifdef HAVE_GETPID
2.11      frystyk   312:     const char * address = HTUserProfile_fqdn(up);
2.1       frystyk   313: #else
2.11      frystyk   314:     const char * address = HTUserProfile_email(up);
2.8       frystyk   315: #endif /* HAVE_GETPID */
2.1       frystyk   316:     if (!address) address = tmpnam(NULL);
                    317:     if ((!address || !*address) && sectime < 0) {
2.34    ! frystyk   318:        HTTRACE(CORE_TRACE, "MessageID...  Can't make a unique MessageID\n");
2.1       frystyk   319:        return "";
                    320:     }
2.8       frystyk   321: #ifdef HAVE_GETPID
2.23      frystyk   322:     sprintf(buf, "<%ldZ%ld@%s>", (long)sectime, (long)getpid(), address ? address : "@@@");
2.1       frystyk   323: #else
                    324:     sprintf(buf, "<%ldZ%s>", sectime, address ? address : "@@@");
2.8       frystyk   325: #endif /* HAVE_GETPID */
2.1       frystyk   326: 
                    327:     *(buf+79) = '\0';
                    328:     return buf;
                    329: }
                    330: 
                    331: /*     Date and Time Parser
                    332: **     --------------------
                    333: **     These functions are taken from the server written by Ari Luotonen
                    334: */
2.14      frystyk   335: #if 0
2.8       frystyk   336: PRIVATE int make_num (const char *  s)
2.1       frystyk   337: {
                    338:     if (*s >= '0' && *s <= '9')
                    339:        return 10 * (*s - '0') + *(s+1) - '0';
                    340:     else
                    341:        return *(s+1) - '0';
                    342: }
2.14      frystyk   343: #endif
                    344: PRIVATE int make_month (char * s, char ** ends)
2.1       frystyk   345: {
2.14      frystyk   346:     char * ptr = s;
2.21      frystyk   347:     while (!isalpha((int) *ptr)) ptr++;
2.14      frystyk   348:     if (*ptr) {
                    349:        int i;
                    350:        *ends = ptr+3;          
                    351:        for (i=0; i<12; i++)
                    352:            if (!strncasecomp(months[i], ptr, 3)) return i;
                    353:     }
2.1       frystyk   354:     return 0;
                    355: }
                    356: 
                    357: /*
                    358: **     Parse a str in GMT format to a local time time_t representation
                    359: **     Four formats are accepted:
                    360: **
                    361: **             Wkd, 00 Mon 0000 00:00:00 GMT           (rfc1123)
                    362: **             Weekday, 00-Mon-00 00:00:00 GMT         (rfc850)
                    363: **             Wkd Mon 00 00:00:00 0000 GMT            (ctime)
                    364: **             1*DIGIT                                 (delta-seconds)
                    365: */
2.16      frystyk   366: PUBLIC time_t HTParseTime (const char * str, HTUserProfile * up, BOOL expand)
2.1       frystyk   367: {
2.14      frystyk   368:     char * s;
2.1       frystyk   369:     struct tm tm;
                    370:     time_t t;
                    371: 
                    372:     if (!str) return 0;
                    373: 
                    374:     if ((s = strchr(str, ','))) {       /* Thursday, 10-Jun-93 01:29:59 GMT */
                    375:        s++;                            /* or: Thu, 10 Jan 1993 01:29:59 GMT */
                    376:        while (*s && *s==' ') s++;
                    377:        if (strchr(s,'-')) {                                 /* First format */
2.34    ! frystyk   378:            HTTRACE(CORE_TRACE, "Format...... Weekday, 00-Mon-00 00:00:00 GMT\n");
2.1       frystyk   379:            if ((int)strlen(s) < 18) {
2.34    ! frystyk   380:                HTTRACE(CORE_TRACE, "ERROR....... Not a valid time format \"%s\"\n" _ s);
2.1       frystyk   381:                return 0;
                    382:            }
2.14      frystyk   383:            tm.tm_mday = strtol(s, &s, 10);
                    384:            tm.tm_mon = make_month(s, &s);
2.16      frystyk   385:            tm.tm_year = strtol(++s, &s, 10);
2.14      frystyk   386:            tm.tm_hour = strtol(s, &s, 10);
                    387:            tm.tm_min = strtol(++s, &s, 10);
                    388:            tm.tm_sec = strtol(++s, &s, 10);
                    389: 
2.1       frystyk   390:        } else {                                            /* Second format */
2.34    ! frystyk   391:            HTTRACE(CORE_TRACE, "Format...... Wkd, 00 Mon 0000 00:00:00 GMT\n");
2.1       frystyk   392:            if ((int)strlen(s) < 20) {
2.34    ! frystyk   393:                HTTRACE(CORE_TRACE, "ERROR....... Not a valid time format \"%s\"\n" _ s);
2.1       frystyk   394:                return 0;
                    395:            }
2.14      frystyk   396:            tm.tm_mday = strtol(s, &s, 10);
                    397:            tm.tm_mon = make_month(s, &s);
                    398:            tm.tm_year = strtol(s, &s, 10) - 1900;
                    399:            tm.tm_hour = strtol(s, &s, 10);
                    400:            tm.tm_min = strtol(++s, &s, 10);
                    401:            tm.tm_sec = strtol(++s, &s, 10);
2.1       frystyk   402:        }
2.21      frystyk   403:     } else if (isdigit((int) *str)) {
2.19      frystyk   404: 
                    405:        if (strchr(str, 'T')) {                 /* ISO (limited format) date string */
2.34    ! frystyk   406:            HTTRACE(CORE_TRACE, "Format...... YYYY.MM.DDThh:mmStzWkd\n");
2.19      frystyk   407:            s = (char *) str;
                    408:            while (*s && *s==' ') s++;
                    409:            if ((int)strlen(s) < 21) {
2.34    ! frystyk   410:                HTTRACE(CORE_TRACE, "ERROR....... Not a valid time format `%s\'\n" _ s);
2.19      frystyk   411:                return 0;
                    412:            }
                    413:            tm.tm_year = strtol(s, &s, 10) - 1900;
                    414:            tm.tm_mon  = strtol(++s, &s, 10);
                    415:            tm.tm_mday = strtol(++s, &s, 10);
                    416:            tm.tm_hour = strtol(++s, &s, 10);
                    417:            tm.tm_min  = strtol(++s, &s, 10);
                    418:            tm.tm_sec  = strtol(++s, &s, 10);
                    419: 
                    420:        } else {                                            /* delta seconds */
                    421:            t = expand ? time(NULL) + atol(str) : atol(str);
2.34    ! frystyk   422: 
        !           423: #ifdef HTDEBUG
2.19      frystyk   424:            if (CORE_TRACE) {
                    425:                if (expand) {
2.1       frystyk   426: #ifdef HT_REENTRANT
2.19      frystyk   427:                    char buffer[CTIME_MAX];
2.34    ! frystyk   428:                    HTTRACE(CORE_TRACE, "Time string. Delta-time %s parsed to %ld seconds, or in local time: %s" _
        !           429:                            str _ (long) t _ (char *) ctime_r(&t, buffer, CTIME_MAX));
2.1       frystyk   430: #else
2.34    ! frystyk   431:                    HTTRACE(CORE_TRACE, "Time string. Delta-time %s parsed to %ld seconds, or in local time: %s" _
        !           432:                            str _ (long) t _ ctime(&t));
        !           433: #endif /* HT_REENTRANT */
2.19      frystyk   434:                } else {
2.34    ! frystyk   435:                    HTTRACE(CORE_TRACE, "Time string. Delta-time %s parsed to %ld seconds\n" _ str _ (long) t);
2.19      frystyk   436:                }
2.16      frystyk   437:            }
2.34    ! frystyk   438: #endif /* HT_DEBUG */
2.19      frystyk   439:            return t;
2.1       frystyk   440:        }
                    441: 
                    442:     } else {         /* Try the other format:  Wed Jun  9 01:29:59 1993 GMT */
2.34    ! frystyk   443:        HTTRACE(CORE_TRACE, "Format...... Wkd Mon 00 00:00:00 0000 GMT\n");
2.14      frystyk   444:        s = (char *) str;
2.1       frystyk   445:        while (*s && *s==' ') s++;
2.34    ! frystyk   446:        HTTRACE(CORE_TRACE, "Trying...... The Wrong time format: %s\n" _ s);
2.1       frystyk   447:        if ((int)strlen(s) < 24) {
2.34    ! frystyk   448:            HTTRACE(CORE_TRACE, "ERROR....... Not a valid time format \"%s\"\n" _ s);
2.1       frystyk   449:            return 0;
                    450:        }
2.14      frystyk   451:        tm.tm_mon = make_month(s, &s);
                    452:        tm.tm_mday = strtol(s, &s, 10);
                    453:        tm.tm_hour = strtol(s, &s, 10);
                    454:        tm.tm_min = strtol(++s, &s, 10);
                    455:        tm.tm_sec = strtol(++s, &s, 10);
                    456:        tm.tm_year = strtol(s, &s, 10) - 1900;
2.1       frystyk   457:     }
                    458:     if (tm.tm_sec  < 0  ||  tm.tm_sec  > 59  ||
                    459:        tm.tm_min  < 0  ||  tm.tm_min  > 59  ||
                    460:        tm.tm_hour < 0  ||  tm.tm_hour > 23  ||
                    461:        tm.tm_mday < 1  ||  tm.tm_mday > 31  ||
                    462:        tm.tm_mon  < 0  ||  tm.tm_mon  > 11  ||
                    463:        tm.tm_year <70  ||  tm.tm_year >120) {
2.34    ! frystyk   464:        HTTRACE(CORE_TRACE, "ERROR....... Parsed illegal time: %02d.%02d.%02d %02d:%02d:%02d\n" _ 
        !           465:               tm.tm_mday _ tm.tm_mon+1 _ tm.tm_year _ 
        !           466:               tm.tm_hour _ tm.tm_min _ tm.tm_sec);
2.1       frystyk   467:        return 0;
                    468:     }
                    469: 
2.30      frystyk   470: #if 0
2.8       frystyk   471: #if defined(HAVE_TIMEZONE) && defined(HAVE_ALTZONE)
2.1       frystyk   472:     tm.tm_isdst = daylight;                   /* Already taken into account */
2.34    ! frystyk   473:     HTTRACE(CORE_TRACE, "Time string. Daylight is %s\n" _
2.30      frystyk   474:            daylight>0 ? "on" : daylight==0 ? "off" : "unknown");
                    475: #endif
2.1       frystyk   476: #else
2.30      frystyk   477:     /* Let mktime decide whether we have DST or not */
2.1       frystyk   478:     tm.tm_isdst = -1;
                    479: #endif
                    480: 
2.8       frystyk   481: #ifdef HAVE_MKTIME
2.1       frystyk   482:     t = mktime(&tm);
2.17      frystyk   483:     t += (up ? HTUserProfile_timezone(up) : HTGetTimeZoneOffset());
2.1       frystyk   484: #else
2.8       frystyk   485: #ifdef HAVE_TIMEGM
2.1       frystyk   486:     t = timegm(&tm);
                    487: #else
2.8       frystyk   488: #error "Neither mktime nor timegm defined"
                    489: #endif /* HAVE_TIMEGM */
                    490: #endif /* HAVE_MKTIME */
2.1       frystyk   491: 
2.34    ! frystyk   492:     HTTRACE(CORE_TRACE, "Time string. %s parsed to %ld calendar time or `%s' in local time\n" _ 
        !           493:                str _ (long) t _ ctime(&t));
2.1       frystyk   494:     return t;
                    495: }
                    496: 
                    497: /*
                    498: **     Returns a string pointer to a static area of the current calendar
                    499: **     time in RFC 1123 format, for example
                    500: **
                    501: **             Sun, 06 Nov 1994 08:49:37 GMT
                    502: **
                    503: **     The result can be given in both local and GMT dependent on the flag
                    504: */
2.8       frystyk   505: PUBLIC const char *HTDateTimeStr (time_t * calendar, BOOL local)
2.1       frystyk   506: {
                    507:     static char buf[40];
                    508: 
2.8       frystyk   509: #ifdef HAVE_STRFTIME
2.1       frystyk   510:     if (local) {
                    511:        /*
                    512:        ** Solaris 2.3 has a bug so we _must_ use reentrant version
                    513:        ** Thomas Maslen <tmaslen@verity.com>
                    514:        */
                    515: #if defined(HT_REENTRANT) || defined(SOLARIS)
                    516:        struct tm loctime;
                    517:        localtime_r(calendar, &loctime);
                    518:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", &loctime);
                    519: #else
                    520:        struct tm *loctime = localtime(calendar);
                    521:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S", loctime);
                    522: #endif /* SOLARIS || HT_REENTRANT */
                    523:     } else {
                    524: #if defined(HT_REENTRANT) || defined(SOLARIS)
                    525:        struct tm gmt;
                    526:        gmtime_r(calendar, &gmt);
                    527:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", &gmt);
                    528: #else
                    529:        struct tm *gmt = gmtime(calendar);
                    530:        strftime(buf, 40, "%a, %d %b %Y %H:%M:%S GMT", gmt);
                    531: #endif /* SOLARIS || HT_REENTRANT */
                    532:     }
                    533: #else
                    534:     if (local) {
                    535: #if defined(HT_REENTRANT)
                    536:        struct tm loctime;
                    537:        localtime_r(calendar, &loctime);
                    538: #else
                    539:        struct tm *loctime = localtime(calendar);
                    540: #endif /* HT_REENTRANT */
2.24      frystyk   541:        sprintf(buf,"%s, %02d %s %04d %02d:%02d:%02d",
2.12      frystyk   542:                wkdays[loctime->tm_wday],
                    543:                loctime->tm_mday,
                    544:                months[loctime->tm_mon],
2.24      frystyk   545:                loctime->tm_year + 1900,
2.12      frystyk   546:                loctime->tm_hour,
                    547:                loctime->tm_min,
                    548:                loctime->tm_sec);
2.1       frystyk   549:     } else {
                    550: #if defined(HT_REENTRANT) || defined(SOLARIS)
                    551:        struct tm gmt;
                    552:        gmtime_r(calendar, &gmt);
                    553: #else
                    554:        struct tm *gmt = gmtime(calendar);
                    555: #endif
2.24      frystyk   556:        sprintf(buf,"%s, %02d %s %04d %02d:%02d:%02d GMT",
2.1       frystyk   557:                wkdays[gmt->tm_wday],
                    558:                gmt->tm_mday,
                    559:                months[gmt->tm_mon],
2.24      frystyk   560:                gmt->tm_year + 1900,
2.1       frystyk   561:                gmt->tm_hour,
                    562:                gmt->tm_min,
                    563:                gmt->tm_sec);
                    564:     }
                    565: #endif
                    566:     return buf;
                    567: }
                    568: 
                    569: /*     HTDateDirStr
                    570: **     ------------
                    571: **     Generates a date string used in directory listings
                    572: */
                    573: PUBLIC BOOL HTDateDirStr (time_t * time, char * str, int len)
                    574: {
2.8       frystyk   575: #ifdef HAVE_STRFTIME
2.1       frystyk   576: #if defined(HT_REENTRANT) || defined(SOLARIS)
                    577:     struct tm loctime;
                    578:     localtime_r(time, &loctime);
2.29      frystyk   579:     strftime(str, len, "%d-%b-%Y %H:%M", &loctime);
2.1       frystyk   580:     return YES;
                    581: #else
2.29      frystyk   582:     strftime(str, len, "%d-%b-%Y %H:%M", localtime(time));
2.1       frystyk   583:     return YES;
                    584: #endif /* HT_REENTRANT || SOLARIS */
                    585: #else
                    586:     if (len >= 16) {
                    587:        struct tm *loctime = localtime(time);
2.12      frystyk   588:        sprintf(str,"%02d-%s-%02d %02d:%02d",
2.1       frystyk   589:                loctime->tm_mday,
                    590:                months[loctime->tm_mon],
                    591:                loctime->tm_year % 100,
                    592:                loctime->tm_hour,
                    593:                loctime->tm_min);
                    594:        return YES;
                    595:     }
                    596:     return NO;
2.8       frystyk   597: #endif /* HAVE_STRFTIME */             
2.1       frystyk   598: }
                    599: 
                    600: /*                                                             HTNumToStr
                    601: **     Converts a long (byte count) to a string
                    602: **     ----------------------------------------
                    603: **     This function was a PAIN!  In computer-world 1K is 1024 bytes
                    604: **     and 1M is 1024K -- however, sprintf() still formats in base-10.
                    605: **     Therefore I output only until 999, and then start using the
                    606: **     next unit.  This doesn't work wrong, it's just a feature.
                    607: **     The "str" must be large enough to contain the result.
                    608: */
                    609: PUBLIC void HTNumToStr (unsigned long n, char * str, int len)
                    610: {
                    611:     double size = n/1024.0;
                    612:     if (len < 6) {
                    613:        *str = '\0';
                    614:        return;
                    615:     }
                    616:     if (n < 1000)
                    617:        sprintf(str, "%dK", n>0 ? 1 : 0);
                    618:     else if (size + 0.999 < 1000)
                    619:        sprintf(str, "%dK", (int)(size + 0.5));
                    620:     else if ((size /= 1024) < 9.9)
                    621:        sprintf(str, "%.1fM", (size + 0.05));
                    622:     else if (size < 1000)
                    623:        sprintf(str, "%dM", (int)(size + 0.5));
                    624:     else if ((size /= 1024) < 9.9)
                    625:        sprintf(str, "%.1fG", (size + 0.05));
                    626:     else
                    627:        sprintf(str, "%dG", (int)(size + 0.5));
2.12      frystyk   628: }
                    629: 
                    630: /*
                    631: **     Matches MIME constructions for content-types and others like
                    632: **     them, for example "text/html", "text/plain". It can also match
                    633: **     wild cards like "text/<star>" and "<star>/<star>. We use <star>
                    634: **     instead of * in order note to make C like comments :-)
                    635: */
                    636: PUBLIC BOOL HTMIMEMatch (HTAtom * tmplate, HTAtom * actual)
                    637: {
                    638:     const char *t, *a;
                    639:     char *st, *sa;
                    640:     BOOL match = NO;
                    641: 
                    642:     if (tmplate && actual && (t = HTAtom_name(tmplate))) {
                    643:        if (!strcmp(t, "*"))
                    644:            return YES;
                    645: 
                    646:        if (strchr(t, '*') &&
                    647:            (a = HTAtom_name(actual)) &&
                    648:            (st = strchr(t, '/')) && (sa = strchr(a,'/'))) {
                    649: 
                    650:            *sa = 0;
                    651:            *st = 0;
                    652: 
                    653:            if ((*(st-1)=='*' &&
                    654:                 (*(st+1)=='*' || !strcasecomp(st+1, sa+1))) ||
                    655:                (*(st+1)=='*' && !strcasecomp(t,a)))
                    656:                match = YES;
                    657: 
                    658:            *sa = '/';
                    659:            *st = '/';
                    660:        }    
                    661:     }
                    662:     return match;
2.1       frystyk   663: }
                    664: 
                    665: /*     Convert file URLs into a local representation
                    666: **     ---------------------------------------------
                    667: **     The URL has already been translated through the rules in get_physical
                    668: **     in HTAccess.c and all we need to do now is to map the path to a local
                    669: **     representation, for example if must translate '/' to the ones that
                    670: **     turn the wrong way ;-)
                    671: **     Returns:
                    672: **             OK:     local file (that must be freed by caller)
                    673: **             Error:  NULL
                    674: */
2.11      frystyk   675: PUBLIC char * HTWWWToLocal (const char * url, const char * base,
                    676:                            HTUserProfile * up)
2.1       frystyk   677: {
                    678:     if (url) {
                    679:        char * access = HTParse(url, base, PARSE_ACCESS);
                    680:        char * host = HTParse(url, base, PARSE_HOST);
                    681:        char * path = HTParse(url, base, PARSE_PATH+PARSE_PUNCTUATION);
2.11      frystyk   682:        const char * myhost = HTUserProfile_fqdn(up);
2.1       frystyk   683: 
                    684:        /* Find out if this is a reference to the local file system */
2.16      frystyk   685:        if ((*access && strcmp(access, "file") && strcmp(access, "cache")) ||
                    686:             (*host && strcasecomp(host, "localhost") &&
                    687:              myhost && strcmp(host, myhost))) {
2.34    ! frystyk   688:            HTTRACE(CORE_TRACE, "LocalName... Not on local file system\n");
2.5       frystyk   689:            HT_FREE(access);
                    690:            HT_FREE(host);
                    691:            HT_FREE(path);
2.1       frystyk   692:            return NULL;
                    693:        } else {
                    694:            char *ptr;
                    695:            if ((ptr = strchr(path, ';')) || (ptr = strchr(path, '?')))
                    696:                *ptr = '\0';
                    697:        
                    698:            /*
                    699:            ** Do whatever translation is required here in order to fit your
                    700:            ** platform _before_ the path is unescaped.
                    701:            */
                    702: #ifdef VMS
                    703:            HTVMS_checkDecnet(path);
                    704: #endif
2.3       frystyk   705: #ifdef WWW_MSWINDOWS
2.27      frystyk   706:            /* An absolute pathname with logical drive */
2.25      frystyk   707:             if (*path == '/' && path[2] == ':') {
2.27      frystyk   708:                char *orig=path, *dest=path+1;
2.25      frystyk   709:                while((*orig++ = *dest++));
                    710: 
                    711:            /* A network host */
                    712:             } else if (*host && strcasecomp(host, "localhost")) {
                    713:                char * newpath = NULL;
                    714:                StrAllocMCopy(&newpath, "//", host, path, NULL);
                    715:                HT_FREE(path);
                    716:                path = newpath;
2.27      frystyk   717:            }
                    718: 
                    719:            /* Convert '/' to '\' */
                    720:            {
                    721:                char *p = path;
                    722:                while (*p) {
                    723:                    if (*p=='/') *p='\\';
                    724:                    p++;
                    725:                }
2.25      frystyk   726:            }
2.1       frystyk   727: #endif
                    728:            
                    729:            HTUnEscape(path);             /* Take out the escaped characters */
2.34    ! frystyk   730:            HTTRACE(CORE_TRACE, "Node........ `%s' means path `%s'\n" _ url _ path);
2.5       frystyk   731:            HT_FREE(access);
                    732:            HT_FREE(host);
2.1       frystyk   733:            return path;
                    734:        }
                    735:     }
                    736:     return NULL;
                    737: }
                    738: 
                    739: /*     Convert a local file name into a URL
                    740: **     ------------------------------------
                    741: **     Generates a WWW URL name from a local file name or NULL if error.
                    742: **     Returns:
                    743: **             OK:     local file (that must be freed by caller)
                    744: **             Error:  NULL
                    745: */
2.32      frystyk   746: PUBLIC char * HTLocalToWWW (const char * local, const char * access)
2.1       frystyk   747: {
2.25      frystyk   748:     char * escaped = NULL;
2.32      frystyk   749:     const char * scheme = (access && *access) ? access : "file:"; 
2.1       frystyk   750:     if (local && *local) {
2.26      frystyk   751: #ifdef VMS 
2.25      frystyk   752:         char * unescaped = NULL;
                    753:         if ((unescaped = (char *) HT_MALLOC(strlen(local) + 10)) == NULL)
                    754:             HT_OUTOFMEM("HTLocalToWWW");
2.32      frystyk   755:         strcpy(unescaped, scheme);          /* We get an absolute file name */
2.26      frystyk   756: 
2.1       frystyk   757:        /* convert directory name to Unix-style syntax */
                    758:        {
                    759:            char * disk = strchr (local, ':');
                    760:            char * dir = strchr (local, '[');
                    761:            if (disk) {
                    762:                *disk = '\0';
2.25      frystyk   763:                strcat(unescaped, "/");
                    764:                strcat(unescaped, local);
2.1       frystyk   765:            }
                    766:            if (dir) {
                    767:                char *p;
                    768:                *dir = '/';     /* Convert leading '[' */
                    769:                for (p = dir ; *p != ']'; ++p)
                    770:                    if (*p == '.') *p = '/';
                    771:                *p = '\0';      /* Cut on final ']' */
2.25      frystyk   772:                strcat(unescaped, dir);
2.1       frystyk   773:            }
                    774:        }
2.26      frystyk   775:         escaped = HTEscape(unescaped, URL_DOSFILE);
2.25      frystyk   776:         HT_FREE(unescaped);
                    777: 
2.1       frystyk   778: #else  /* not VMS */
                    779: #ifdef WIN32
2.26      frystyk   780:         char * unescaped = NULL;
                    781:         if ((unescaped = (char *) HT_MALLOC(strlen(local) + 10)) == NULL)
                    782:             HT_OUTOFMEM("HTLocalToWWW");
2.32      frystyk   783:         strcpy(unescaped, scheme);          /* We get an absolute file name */
2.25      frystyk   784:         if (strchr(local, ':')) strcat(unescaped, "/");
                    785:         {
                    786:             const char *p = local;
                    787:             char *q = unescaped+strlen(unescaped);
                    788:             while (*p) {
                    789:                 if (*p=='\\') {
                    790:                     *q++='/';
                    791:                 } else
                    792:                     *q++=*p;
                    793:                 p++;
                    794:             }
                    795:             *q = '\0';
                    796:        }
                    797:         escaped = HTEscape(unescaped, URL_DOSFILE);
                    798:         HT_FREE(unescaped);
                    799: 
                    800: #else  /* Unix */
2.26      frystyk   801:         char * escaped_path = HTEscape(local, URL_PATH);
2.32      frystyk   802:        escaped = StrAllocMCopy(&escaped, scheme, escaped_path, NULL);
2.26      frystyk   803:         HT_FREE(escaped_path);
2.25      frystyk   804: 
2.1       frystyk   805: #endif /* not WIN32 */
                    806: #endif /* not VMS */
                    807:     }
2.25      frystyk   808:     return escaped;
2.1       frystyk   809: }

Webmaster