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

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

Webmaster