source: trunk/third/nmh/uip/mhcachesbr.c @ 12455

Revision 12455, 8.7 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12454, which included commits to RCS files with non-trunk default branches.
Line 
1
2/*
3 * mhcachesbr.c -- routines to manipulate the MIME content cache
4 *
5 * $Id: mhcachesbr.c,v 1.1.1.1 1999-02-07 18:14:14 danw Exp $
6 */
7
8#include <h/mh.h>
9#include <fcntl.h>
10#include <h/signals.h>
11#include <h/md5.h>
12#include <errno.h>
13#include <setjmp.h>
14#include <signal.h>
15#include <zotnet/mts/mts.h>
16#include <zotnet/tws/tws.h>
17#include <h/mime.h>
18#include <h/mhparse.h>
19#include <h/mhcachesbr.h>
20
21#ifdef HAVE_SYS_WAIT_H
22# include <sys/wait.h>
23#endif
24
25
26extern int errno;
27extern int debugsw;
28
29extern pid_t xpid;      /* mhshowsbr.c or mhbuildsbr.c */
30
31/* cache policies */
32int rcachesw = CACHE_ASK;
33int wcachesw = CACHE_ASK;
34
35/*
36 * Location of public and private cache.  These must
37 * be set before these routines are called.
38 */
39char *cache_public;
40char *cache_private;
41
42
43/* mhparse.c (OR) mhbuildsbr.c */
44int pidcheck (int);
45
46/* mhmisc.c */
47int part_ok (CT, int);
48int type_ok (CT, int);
49int make_intermediates (char *);
50void content_error (char *, CT, char *, ...);
51void flush_errors (void);
52
53/*
54 * prototypes
55 */
56void cache_all_messages (CT *);
57int find_cache (CT, int, int *, char *, char *, int);
58
59/*
60 * static prototypes
61 */
62static void cache_content (CT);
63static int find_cache_aux (int, char *, char *, char *, int);
64static int find_cache_aux2 (char *, char *, char *, int);
65
66
67/*
68 * Top level entry point to cache content
69 * from a group of messages
70 */
71
72void
73cache_all_messages (CT *cts)
74{
75    CT ct, *ctp;
76
77    for (ctp = cts; *ctp; ctp++) {
78        ct = *ctp;
79        if (type_ok (ct, 1)) {
80            cache_content (ct);
81            if (ct->c_fp) {
82                fclose (ct->c_fp);
83                ct->c_fp = NULL;
84            }
85            if (ct->c_ceclosefnx)
86                (*ct->c_ceclosefnx) (ct);
87        }
88    }
89    flush_errors ();
90}
91
92
93/*
94 * Entry point to cache content from external sources.
95 */
96
97static void
98cache_content (CT ct)
99{
100    int cachetype;
101    char *file, cachefile[BUFSIZ];
102    CE ce = ct->c_cefile;
103
104    if (!ct->c_id) {
105        advise (NULL, "no %s: field in %s", ID_FIELD, ct->c_file);
106        return;
107    }
108
109    if (!ce) {
110        advise (NULL, "unable to decode %s", ct->c_file);
111        return;
112    }
113
114/* THIS NEEDS TO BE FIXED */
115#if 0
116    if (ct->c_ceopenfnx == openMail) {
117        advise (NULL, "a radish may no know Greek, but I do...");
118        return;
119    }
120#endif
121
122    if (find_cache (NULL, wcachesw != CACHE_NEVER ? wcachesw : CACHE_ASK,
123                    &cachetype, ct->c_id, cachefile, sizeof(cachefile))
124            == NOTOK) {
125        advise (NULL, "unable to cache %s's contents", ct->c_file);
126        return;
127    }
128    if (wcachesw != CACHE_NEVER && wcachesw != CACHE_ASK) {
129        fflush (stdout);
130        fprintf (stderr, "caching message %s as file %s\n", ct->c_file,
131                 cachefile);
132    }
133
134    if (ce->ce_file) {
135        int mask = umask (cachetype ? ~m_gmprot () : 0222);
136        FILE *fp;
137
138        if (debugsw)
139            fprintf (stderr, "caching by copying %s...\n", ce->ce_file);
140
141        file = NULL;
142        if ((*ct->c_ceopenfnx) (ct, &file) == NOTOK)
143            goto reset_umask;
144
145        if ((fp = fopen (cachefile, "w"))) {
146            int cc;
147            char buffer[BUFSIZ];
148            FILE *gp = ce->ce_fp;
149
150            fseek (gp, 0L, SEEK_SET);
151
152            while ((cc = fread (buffer, sizeof(*buffer), sizeof(buffer), gp))
153                       > 0)
154                fwrite (buffer, sizeof(*buffer), cc, fp);
155            fflush (fp);
156
157            if (ferror (gp)) {
158                admonish (ce->ce_file, "error reading");
159                unlink (cachefile);
160            } else {
161                if (ferror (fp)) {
162                    admonish (cachefile, "error writing");
163                    unlink (cachefile);
164                }
165            }
166            fclose (fp);
167        } else
168            content_error (cachefile, ct, "unable to fopen for writing");
169reset_umask:
170        umask (mask);
171    } else {
172        if (debugsw)
173            fprintf (stderr, "in place caching...\n");
174
175        file = cachefile;
176        if ((*ct->c_ceopenfnx) (ct, &file) != NOTOK)
177            chmod (cachefile, cachetype ? m_gmprot () : 0444);
178    }
179}
180
181
182int
183find_cache (CT ct, int policy, int *writing, char *id,
184        char *buffer, int buflen)
185{
186    int status = NOTOK;
187
188    if (id == NULL)
189        return NOTOK;
190    id = trimcpy (id);
191
192    if (debugsw)
193        fprintf (stderr, "find_cache %s(%d) %s %s\n", caches[policy].sw,
194                 policy, writing ? "writing" : "reading", id);
195
196    switch (policy) {
197        case CACHE_NEVER:
198        default:
199            break;
200
201        case CACHE_ASK:
202        case CACHE_PUBLIC:
203            if (cache_private
204                    && !writing
205                    && find_cache_aux (writing ? 2 : 0, cache_private, id,
206                                       buffer, buflen) == OK) {
207                if (access (buffer, R_OK) != NOTOK) {
208got_private:
209                    if (writing)
210                        *writing = 1;
211got_it:
212                    status = OK;
213                    break;
214                }
215            }
216            if (cache_public
217                    && find_cache_aux (writing ? 1 : 0, cache_public, id,
218                                       buffer, buflen) == OK) {
219                if (writing || access (buffer, R_OK) != NOTOK) {
220                    if (writing)
221                        *writing = 0;
222                    goto got_it;
223                }
224            }
225            break;
226
227        case CACHE_PRIVATE:
228            if (cache_private
229                    && find_cache_aux (writing ? 2 : 0, cache_private, id,
230                                       buffer, buflen) == OK) {
231                if (writing || access (buffer, R_OK) != NOTOK)
232                    goto got_private;
233            }
234            break;
235
236    }
237
238    if (status == OK && policy == CACHE_ASK) {
239        int len, buflen;
240        char *bp, query[BUFSIZ];
241
242        if (xpid) {
243            if (xpid < 0)
244                xpid = -xpid;
245            pidcheck (pidwait (xpid, NOTOK));
246            xpid = 0;
247        }
248
249        /* Get buffer ready to go */
250        bp = query;
251        buflen = sizeof(query);
252
253        /* Now, construct query */
254        if (writing) {
255            snprintf (bp, buflen, "Make cached, publically-accessible copy");
256        } else {
257            struct stat st;
258
259            snprintf (bp, buflen, "Use cached copy");
260            len = strlen (bp);
261            bp += len;
262            buflen -= len;
263
264            if (ct->c_partno) {
265                snprintf (bp, buflen, " of content %s", ct->c_partno);
266                len = strlen (bp);
267                bp += len;
268                buflen -= len;
269            }
270
271            stat (buffer, &st);
272            snprintf (bp, buflen, " (size %lu octets)",
273                            (unsigned long) st.st_size);
274        }
275        len = strlen (bp);
276        bp += len;
277        buflen -= len;
278
279        snprintf (bp, buflen, "\n    in file %s? ", buffer);
280
281        /* Now, check answer */
282        if (!getanswer (query))
283            status = NOTOK;
284    }
285
286    if (status == OK && writing) {
287        if (*writing && strchr(buffer, '/'))
288            make_intermediates (buffer);
289        unlink (buffer);
290    }
291
292    free (id);
293    return status;
294}
295
296
297static int
298find_cache_aux (int writing, char *directory, char *id,
299        char *buffer, int buflen)
300{
301    int mask, usemap;
302    char mapfile[BUFSIZ], mapname[BUFSIZ];
303    FILE *fp;
304    static int partno, pid;
305    static time_t clock = 0;
306
307#ifdef BSD42
308    usemap = strchr (id, '/') ? 1 : 0;
309#else
310    usemap = 1;
311#endif
312
313    if (debugsw)
314        fprintf (stderr, "find_cache_aux %s usemap=%d\n", directory, usemap);
315
316    snprintf (mapfile, sizeof(mapfile), "%s/cache.map", directory);
317    if (find_cache_aux2 (mapfile, id, mapname, sizeof(mapname)) == OK)
318        goto done_map;
319
320    if (!writing) {
321        if (usemap)
322            return NOTOK;
323
324use_raw:
325        snprintf (buffer, buflen, "%s/%s", directory, id);
326        return OK;
327    }
328
329    if (!usemap && access (mapfile, W_OK) == NOTOK)
330        goto use_raw;
331
332    if (clock != 0) {
333        time_t now;
334       
335        time (&now);
336        if (now > clock)
337            clock = 0;
338    } else {
339        pid = getpid ();
340    }
341
342    if (clock == 0) {
343        time (&clock);
344        partno = 0;
345    } else {
346        if (partno > 0xff) {
347            clock++;
348            partno = 0;
349        }
350    }
351
352    snprintf (mapname, sizeof(mapname), "%08x%04x%02x",
353                (unsigned int) (clock & 0xffffffff),
354                (unsigned int) (pid & 0xffff),
355                (unsigned int) (partno++ & 0xff));
356
357    if (debugsw)
358        fprintf (stderr, "creating mapping %s->%s\n", mapname, id);
359
360    make_intermediates (mapfile);
361    mask = umask (writing == 2 ? 0077 : 0);
362    if (!(fp = lkfopen (mapfile, "a")) && errno == ENOENT) {
363        int fd;
364
365        if ((fd = creat (mapfile, 0666)) != NOTOK) {
366            close (fd);
367            fp = lkfopen (mapfile, "a");
368        }
369    }
370    umask (mask);
371    if (!fp)
372        return NOTOK;
373    fprintf (fp, "%s: %s\n", mapname, id);
374    lkfclose (fp, mapfile);
375
376done_map:
377    if (*mapname == '/')
378        strncpy (buffer, mapname, buflen);
379    else
380        snprintf (buffer, buflen, "%s/%s", directory, mapname);
381    if (debugsw)
382        fprintf (stderr, "use %s\n", buffer);
383
384    return OK;
385}
386
387
388static int
389find_cache_aux2 (char *mapfile, char *id, char *mapname, int namelen)
390{
391    int state;
392    char buf[BUFSIZ], name[NAMESZ];
393    FILE *fp;
394
395    if (!(fp = lkfopen (mapfile, "r")))
396        return NOTOK;
397
398    for (state = FLD;;) {
399        int result;
400        char *cp, *dp;
401
402        switch (state = m_getfld (state, name, buf, sizeof(buf), fp)) {
403            case FLD:
404            case FLDPLUS:
405            case FLDEOF:
406                strncpy (mapname, name, namelen);
407                if (state != FLDPLUS)
408                    cp = buf;
409                else {
410                    cp = add (buf, NULL);
411                    while (state == FLDPLUS) {
412                        state = m_getfld (state, name, buf, sizeof(buf), fp);
413                        cp = add (buf, cp);
414                    }
415                }
416                dp = trimcpy (cp);
417                if (cp != buf)
418                    free (cp);
419                if (debugsw)
420                    fprintf (stderr, "compare %s to %s <- %s\n", id, dp,
421                             mapname);
422                result = strcmp (id, dp);
423                free (dp);
424                if (result == 0) {
425                    lkfclose (fp, mapfile);
426                    return OK;
427                }
428                if (state != FLDEOF)
429                    continue;
430                /* else fall... */
431
432            case BODY:
433            case BODYEOF:
434            case FILEEOF:
435            default:
436                break;
437        }
438        break;
439    }
440
441    lkfclose (fp, mapfile);
442    return NOTOK;
443}
Note: See TracBrowser for help on using the repository browser.