#include <ctype.h>
#include <dirent.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

/*
 * Compare a string to a mask
 * Mask characters:
 *   @ - uppercase letter
 *   # - lowercase letter
 *   & - hex digit
 *   # - digit
 *   * - swallow remaining characters 
 *  <x> - exact match for any other character
 */
static int
checkmask(const char *data, const char *mask)
{
    int i, ch, d;

    for (i=0; mask[i] != '\0' && mask[i] != '*'; i++)
    {
	ch = mask[i];
	d = data[i];
	if (ch == '@')
	{
	    if (!isupper(d)) return 0;
	} else if (ch == '$')
	{
	    if (!islower(d)) return 0;
	} else if (ch == '#')
	{
	    if (!isdigit(d)) return 0;
	} else if (ch == '&')
	{
	    if (!isxdigit(d)) return 0;
	} else if (ch != d) return 0;
    }

    if (mask[i] == '*') return 1;
    else return (data[i] == '\0');
}

/*
 * Converts 8 hex digits to a time integer
 */
static int
hex2sec(const char *x)
{
    int i, ch;
    unsigned int j;

    for (i=0, j=0; i < 8; i++)
    {
	ch = x[i];
	j <<= 4;
	if (isdigit(ch)) j |= ch - '0';
	else if (isupper(ch)) j |= ch - ('A' - 10);
	else j |= ch - ('a' - 10);
    }
    if (j == 0xffffffff) return -1;  /* so that it works with 8-byte ints */
    else return j;
}

int
main(int argc, char **argv)
{
    int i, ver;
    DIR *d;
    struct dirent *e;
    const char *s;
    FILE *fp;
    char path[FILENAME_MAX+1];
    char line[1035];
    time_t date, lmod, expire;
    unsigned int len;
    struct tm ts;
    char sdate[30], slmod[30], sexpire[30];
    const char time_format[]="%e %b %Y %R";

    if (argc != 2)
    {
	printf("Usage: cls directory\n");
	exit(0);
    }

    d = opendir(argv[1]);
    if (d == NULL)
    {
	perror("opendir");
	exit(1);
    }

    for (;;)
    {
	e = readdir(d);
	if (e == NULL) break;
	s = e->d_name;
	if (s[0] == '.' || s[0] == '#') continue;
	sprintf(path, "%s/%s", argv[1], s);
	fp = fopen(path, "r");
	if (fp == NULL)
	{
	    perror("fopen");
	    continue;
	}
	if (fgets(line, 1034, fp) == NULL)
	{
	    perror("fgets");
	    fclose(fp);
	    continue;
	}
	if (!checkmask(line, "&&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&& &&&&&&&&\n"))
	{
	    fprintf(stderr, "Bad cache file\n");
	    fclose(fp);
	    continue;
	}
	date = hex2sec(line);
	lmod = hex2sec(line+9);
	expire = hex2sec(line+18);
	ver = hex2sec(line+27);
	len = hex2sec(line+35);
	if (fgets(line, 1034, fp) == NULL)
	{
	    perror("fgets");
	    fclose(fp);
	    continue;
	}
	fclose(fp);
	i = strlen(line);
	if (strncmp(line, "X-URL: ", 7) != 0 || line[i-1] != '\n')
	{
	    fprintf(stderr, "Bad cache file\n");
	    continue;
	}
	line[i-1] = '\0';
	if (date != -1)
	{
	    ts = *gmtime(&date);
	    strftime(sdate, 30, time_format, &ts);
	} else
	    strcpy(sdate, "-");

	if (lmod != -1)
	{	
	    ts = *gmtime(&lmod);
	    strftime(slmod, 30, time_format, &ts);
	} else
	    strcpy(slmod, "-");

	if (expire != -1)
	{
	    ts = *gmtime(&expire);
	    strftime(sexpire, 30, time_format, &ts);
	} else
	    strcpy(sexpire, "-");

	printf("%s: %d; %s  %s  %s\n", line+7, ver, sdate, slmod, sexpire);
    }

    closedir(d);
    return 0;
}
