--- cups-1.1.23/cups/dest.c.dest-cache-v2 2005-01-03 19:29:45.000000000 +0000 +++ cups-1.1.23/cups/dest.c 2006-01-10 17:52:39.000000000 +0000 @@ -45,7 +45,10 @@ #include "string.h" #include #include - +#include +#include +#include +#include /* * Local functions... @@ -204,6 +207,146 @@ /* + * cupsGetDestsCache() - get cached dests list + * return -1 on errors + */ + +int /* O - Number of destinations */ +cupsGetDestsCache(cups_dest_t **dests, /* O - Destinations */ + char *cache, /* I - Cache file name */ + off_t size) /* I - Cache file size */ +{ + int i,j; /* looping variables */ + int fd; /* file descriptor */ + int c; /* characters written */ + int offset=0; /* offset into cache file size */ + char *buf; /* cache buffer */ + char word[4096]; /* buffer for 'words' which need copied */ + int num_dests=0; /* number of destinations */ + + if ((buf = malloc((size_t)size+1)) == NULL) + return 0; + memset((void *)buf, 0, (size_t)size+1); + if ((fd = open(cache,O_RDONLY)) > 0) + { + + /* read the cache */ + if ((c = read(fd,(void *)buf,(size_t)size)) < size) + { + close(fd); + free(buf); + return(-1); + } + + /* find the number of destinations in the cache and set up structure */ + strcpy(word,buf); + offset += strlen(word) + 1; + num_dests = atoi(word); + if (((*dests) = (cups_dest_t *)malloc(sizeof(cups_dest_t) * num_dests)) == NULL) + { + free(buf); + close(fd); + return(-1); + } + + /* populate the destinations structure */ + for (i=0; i < num_dests; i++) + { + if (((*dests)[i].name = malloc(strlen(&buf[offset])+1)) == NULL) + return(-1); + strcpy((*dests)[i].name, &buf[offset]); + offset += strlen((*dests)[i].name) +1; + + if (((*dests)[i].instance = malloc(strlen(&buf[offset])+1)) == NULL) + return(-1); + strcpy((*dests)[i].instance, &buf[offset]); + offset += strlen((*dests)[i].instance) +1; + + /* get number of options */ + strcpy(word, &buf[offset]); + offset += strlen(word)+1; + (*dests)[i].is_default = atoi(word); + + + /* get number of options */ + strcpy(word, &buf[offset]); + offset += strlen(word)+1; + (*dests)[i].num_options = atoi(word); + + if (((*dests)[i].options = malloc(sizeof(cups_option_t) * (*dests)[i].num_options)) == NULL) + { + free(buf); + free(dests); + close(fd); + return(-1); + } + + /* fill options structure */ + for (j=0; j < (*dests)[i].num_options; j++) + { + if (((*dests)[i].options[j].name = malloc(strlen(&buf[offset])+1)) == NULL) + return(-1); + strcpy((*dests)[i].options[j].name, &buf[offset]); + offset += strlen((*dests)[i].options[j].name) +1; + + if (((*dests)[i].options[j].value = malloc(strlen(&buf[offset])+1)) == NULL) + return(-1); + strcpy((*dests)[i].options[j].value, &buf[offset]); + offset += strlen((*dests)[i].options[j].value) +1; + } + } + close(fd); + free(buf); + } + return(num_dests); +} + + +void +cupsSaveDests(int num_dests, /* I - Number of destinations */ + cups_dest_t **dests, /* I - Destinations */ + char *cache) /* I - Cache file name */ +{ + int i,j; /* looping variables */ + int fd; /* file descriptor */ + char buf[4096]; /* string buffer */ + char tmpfn[4096]; /* temporary name to write new cache to */ + int c; + sprintf(tmpfn,"%s-%l",cache,random()); + + if ((fd = open(cache,O_WRONLY|O_CREAT|O_TRUNC)) > 0) + { + sprintf(buf, "%d",num_dests); + c = write(fd, (void *)buf, strlen(buf)+1); + for (i=0; i < num_dests; i++) + { + c = write(fd, (void *)(*dests)[i].name, strlen((*dests)[i].name)+1); + if ((*dests)[i].instance != NULL) + { + write(fd, (void *)(*dests)[i].instance, strlen((*dests)[i].instance)); + } + else + { + write(fd, (void *)"\0", 1); + } + sprintf(buf, "%d",(*dests)[i].is_default); + write(fd, (void *)buf, strlen(buf)+1); + sprintf(buf, "%d",(*dests)[i].num_options); + write(fd, (void *)buf, strlen(buf)+1); + for (j=0; j < (*dests)[i].num_options; j++) + { + write(fd, (void *)(*dests)[i].options[j].name, strlen((*dests)[i].options[j].name)+1); + write(fd, (void *)(*dests)[i].options[j].value, strlen((*dests)[i].options[j].value)+1); + } + } + close(fd); + rename(tmpfn,cache); + } +} + + + +/* * 'cupsGetDests()' - Get the list of destinations. */ @@ -211,8 +354,44 @@ cupsGetDests(cups_dest_t **dests) /* O - Destinations */ { int num_dests; /* Number of destinations */ + int use_cache; /* whether to use local cacheing */ + int cache_timeout=0; /* timeout for cache */ http_t *http; /* HTTP connection */ + struct timeb cur_time; /* current time */ + struct stat cache_stats; /* buffer for local cache of dests */ + char *cups_server; /* cups_server name */ + char cache_filename[4096]; /* file name for dest cache */ + + /* + * Check for local cache file, if it exists and is upt to date, use + * it in preference to generating a new query to the CUPS server + * General strategy is to fail silently on problems with the cache + * and fall back to normal lookups. + */ + if (getenv("CUPS_DESTCACHE") != NULL) + { + cache_timeout = atoi(getenv("CUPS_DESTCACHE")); + /* check to make sure .cups dir exists in users home directory */ + sprintf(cache_filename,"%s/.cups",getenv("HOME")); + mkdir(cache_filename, S_IRWXU | S_IRWXG | S_IROTH); + sprintf(cache_filename,"%s/%s-%s",getenv("HOME"),".cups/dest-cache", cupsServer()); + if ((cache_timeout) && + (!stat(cache_filename, &cache_stats))) + { + ftime(&cur_time); + if (cur_time.time - cache_stats.st_mtime <= cache_timeout) + { + num_dests = cupsGetDestsCache(dests, cache_filename, cache_stats.st_size); + /* + * if we have destinations, there were no errors, else fall + * back to old server check + */ + if (num_dests > 0) + return (num_dests); + } + } + } /* * Connect to the CUPS server and get the destination list and options... @@ -225,6 +404,9 @@ if (http) httpClose(http); + if (cache_timeout) + cupsSaveDests(num_dests, dests, cache_filename); + return (num_dests); }