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