002e42f2de2421e284751ac27406f5b5377e7f4e
[mmh] / dropsbr.c
1 /* dropsbr.c - write to a mailbox */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: dropsbr.c,v 1.19 1995/12/07 18:59:08 jromine Exp $";
4 #endif  /* lint */
5
6 #include <stdio.h>
7 #ifndef MMDFONLY
8 #include "../h/mh.h"
9 #include "../h/dropsbr.h"
10 #include "../zotnet/mts.h"
11 #else   /* MMDFONLY */
12 #include "dropsbr.h"
13 #include "strings.h"
14 #include "mmdfonly.h"
15 #endif  /* MMDFONLY */
16 #include <errno.h>
17 #include <sys/types.h>
18 #include <sys/stat.h>
19 #if     (defined(BSD42) || defined(SOCKETS)) && defined(NTOHLSWAP)
20 #include <netinet/in.h>
21 #else
22 #define ntohl(n) (n)
23 #endif
24
25
26 #define MMDF    1
27 #define UUCP    2
28
29 /* \f */
30
31 static  int     mbx_style = MMDF;
32
33 static int      mbx_create(), mbx_chk(), map_open();
34
35 extern int  errno;
36
37 off_t   lseek ();
38
39 /* \f */
40
41 int     mbx_mmdf () {
42     int     style = mbx_style;
43
44     mbx_style = MMDF;
45     return style;
46 }
47
48
49 int     mbx_uucp () {
50     int     style = mbx_style;
51
52     mbx_style = UUCP;
53     return style;
54 }
55
56 /* \f */
57
58 int     mbx_open (file, uid, gid, mode)
59 char   *file;
60 int     uid,
61         gid,
62         mode;
63 {
64     int     clear,
65             fd;
66
67     if ((fd = mbx_Xopen (file, uid, gid, mode, &clear)) == NOTOK)
68         return fd;
69
70     if (!clear)
71         switch (mbx_style) {
72             case MMDF: 
73             default: 
74                 if (mbx_chk (fd) == NOTOK) {
75                     (void) close (fd);
76                     return NOTOK;
77                 }
78                 break;
79
80             case UUCP: 
81                 if (lseek (fd, (off_t)0, 2) == (off_t) NOTOK) {
82                     (void) close (fd);
83                     return NOTOK;
84                 }
85                 break;
86         }
87
88     return fd;
89 }
90
91 /* \f */
92
93 int     mbx_Xopen (file, uid, gid, mode, clear)
94 char   *file;
95 int     uid,
96         gid,
97         mode,
98        *clear;
99 {
100     register int j;
101     int     count,
102             fd;
103     struct stat st;
104
105     for (*clear = 0, count = 4, j = 0; count > 0; count--)
106         if ((fd = lkopen (file, 6)) == NOTOK)
107             switch (errno) {
108                 case ENOENT: 
109                     if (mbx_create (file, uid, gid, mode) == NOTOK)
110                         return NOTOK;
111                     (*clear)++;
112                     break;
113
114 #ifdef  BSD42
115                 case EWOULDBLOCK:
116 #endif  /* BSD42 */
117                 case ETXTBSY: 
118                     j = errno;
119                     sleep (5);
120                     break;
121
122                 default: 
123                     return NOTOK;
124             }
125         else {
126             *clear = fstat (fd, &st) != NOTOK && st.st_size == (off_t)0;
127             break;
128         }
129
130     errno = j;
131     return fd;
132 }
133
134 /* \f */
135
136 static int  mbx_create (file, uid, gid, mode)
137 char   *file;
138 int     uid,
139         gid,
140         mode;
141 {
142     int     fd;
143
144     if ((fd = creat (file, 0600)) == NOTOK)
145         return NOTOK;
146
147     (void) close (fd);
148     (void) chown (file, uid, gid);
149     (void) chmod (file, mode);
150
151     return OK;
152 }
153
154
155 static int  mbx_chk (fd)
156 int     fd;
157 {
158     int     count;
159     char    ldelim[BUFSIZ];
160
161     count = strlen (mmdlm2);
162
163     if (lseek (fd, (off_t) (-count), 2) == (off_t) NOTOK
164             || read (fd, ldelim, count) != count)
165         return NOTOK;
166     ldelim[count] = 0;
167
168     if (strcmp (ldelim, mmdlm2)
169             && write (fd, "\n", 1) != 1
170             && write (fd, mmdlm2, count) != count)
171         return NOTOK;
172
173     return OK;
174 }
175
176 /* \f */
177
178 int     mbx_read (fp, pos, drops, noisy)
179 register FILE  *fp;
180 register long   pos;
181 struct drop **drops;
182 int     noisy;
183 {
184     register int    len,
185                     size;
186     register long     ld1,
187                     ld2;
188     register char  *bp;
189     char    buffer[BUFSIZ];
190     register struct drop   *cp,
191                            *dp,
192                            *ep,
193                            *pp;
194
195     pp = (struct drop  *) calloc ((unsigned) (len = MAXFOLDER), sizeof *dp);
196     if (pp == NULL) {
197         if (noisy)
198             admonish (NULLCP, "unable to allocate drop storage");
199         return NOTOK;
200     }
201
202     ld1 = (long) strlen (mmdlm1);
203     ld2 = (long) strlen (mmdlm2);
204
205     (void) fseek (fp, pos, 0);
206     for (ep = (dp = pp) + len - 1; fgets (buffer, sizeof buffer, fp);) {
207         size = 0;
208         if (strcmp (buffer, mmdlm1) == 0)
209             pos += ld1, dp -> d_start = (long) pos;
210         else {
211             dp -> d_start = (long)pos , pos += (long) strlen (buffer);
212             for (bp = buffer; *bp; bp++, size++)
213                 if (*bp == '\n')
214                     size++;
215         }
216
217         while (fgets (buffer, sizeof buffer, fp) != NULL)
218             if (strcmp (buffer, mmdlm2) == 0)
219                 break;
220             else {
221                 pos += (long) strlen (buffer);
222                 for (bp = buffer; *bp; bp++, size++)
223                     if (*bp == '\n')
224                         size++;
225             }
226
227         if (dp -> d_start != (long) pos) {
228             dp -> d_id = 0;
229             dp -> d_size = (long) size;
230             dp -> d_stop = (long) pos;
231             dp++;
232         }
233         pos += ld2;
234
235         if (dp >= ep) {
236             register int    curlen = dp - pp;
237
238             cp = (struct drop  *) realloc ((char *) pp,
239                                     (unsigned) (len += MAXFOLDER) * sizeof *pp);
240             if (cp == NULL) {
241                 if (noisy)
242                     admonish (NULLCP, "unable to allocate drop storage");
243                 free ((char *) pp);
244                 return 0;
245             }
246             dp = cp + curlen, ep = (pp = cp) + len - 1;
247         }
248     }
249
250     if (dp == pp)
251         free ((char *) pp);
252     else
253         *drops = pp;
254     return (dp - pp);
255 }
256
257 /* \f */
258
259 int     mbx_write (mailbox, md, fp, id, last, pos, stop, mapping, noisy)
260 char   *mailbox;
261 register FILE *fp;
262 int     md,
263         id,
264         mapping,
265         noisy;
266 long    last;
267 register long   pos,
268                 stop;
269 {
270     register int    i,
271                     j,
272                     size;
273     long            start,
274                     off;
275     register char  *cp;
276     char    buffer[BUFSIZ];
277
278     off = (long) lseek (md, (off_t)0, 1);
279     j = strlen (mmdlm1);
280     if (write (md, mmdlm1, j) != j)
281         return NOTOK;
282     start = (long) lseek (md, (off_t)0, 1);
283     size = 0;
284
285     (void) fseek (fp, pos, 0);
286     while (fgets (buffer, sizeof buffer, fp) != NULL && pos < stop) {
287         i = strlen (buffer);
288         for (j = 0; (j = stringdex (mmdlm1, buffer)) >= 0; buffer[j]++)
289             continue;
290         for (j = 0; (j = stringdex (mmdlm2, buffer)) >= 0; buffer[j]++)
291             continue;
292         if (write (md, buffer, i) != i)
293             return NOTOK;
294         pos += (long) i;
295         if (mapping)
296             for (cp = buffer; i-- > 0; size++)
297                 if (*cp++ == '\n')
298                     size++;
299     }
300
301     stop = (long) lseek (md, (off_t)0, 1);
302     j = strlen (mmdlm2);
303     if (write (md, mmdlm2, j) != j)
304         return NOTOK;
305     if (mapping)
306         (void) map_write (mailbox, md, id, last, start, stop, off, size, noisy);
307
308     return OK;
309 }
310
311 /* \f */
312
313 int     mbx_copy (mailbox, md, fd, mapping, text, noisy)
314 char   *mailbox;
315 int     md,
316         fd,
317         mapping,
318         noisy;
319 char   *text;
320 {
321     register int    i,
322                     j,
323                     size;
324     long           start,
325                     stop,
326                     pos;
327     register char  *cp;
328     char    buffer[BUFSIZ];
329     register FILE  *fp;
330
331     pos = (long) lseek (md, (off_t)0, 1);
332     size = 0;
333
334     switch (mbx_style) {
335         case MMDF: 
336         default: 
337             j = strlen (mmdlm1);
338             if (write (md, mmdlm1, j) != j)
339                 return NOTOK;
340             start = (long) lseek (md, (off_t)0, 1);
341
342             if (text) {
343                 i = strlen (text);
344                 if (write (md, text, i) != i)
345                     return NOTOK;
346                 for (cp = text; *cp++; size++)
347                     if (*cp == '\n')
348                         size++;
349             }
350                     
351             while ((i = read (fd, buffer, sizeof buffer)) > 0) {
352                 for (j = 0;
353                         (j = stringdex (mmdlm1, buffer)) >= 0;
354                         buffer[j]++)
355                     continue;
356                 for (j = 0;
357                         (j = stringdex (mmdlm2, buffer)) >= 0;
358                         buffer[j]++)
359                     continue;
360                 if (write (md, buffer, i) != i)
361                     return NOTOK;
362                 if (mapping)
363                     for (cp = buffer; i-- > 0; size++)
364                         if (*cp++ == '\n')
365                             size++;
366             }
367
368             stop = (long) lseek (md, (off_t)0, 1);
369             j = strlen (mmdlm2);
370             if (write (md, mmdlm2, j) != j)
371                 return NOTOK;
372             if (mapping)
373                 (void) map_write (mailbox, md, 0, (long)0, start, stop, pos, size,
374                             noisy);
375
376             return (i != NOTOK ? OK : NOTOK);
377
378         case UUCP:              /* I hate this... */
379             if ((j = dup (fd)) == NOTOK)
380                 return NOTOK;
381             if ((fp = fdopen (j, "r")) == NULL) {
382                 (void) close (j);
383                 return NOTOK;
384             }
385             start = (long) lseek (md, (off_t)0, 1);
386
387             if (text) {
388                 i = strlen (text);
389                 if (write (md, text, i) != i)
390                     return NOTOK;
391                 for (cp = text; *cp++; size++)
392                     if (*cp == '\n')
393                         size++;
394             }
395                     
396             for (j = 0; fgets (buffer, sizeof buffer, fp) != NULL; j++) {
397                 if (j != 0 && strncmp (buffer, "From ", 5) == 0) {
398                     (void) write (md, ">", 1);
399                     size++;
400                 }
401                 i = strlen (buffer);
402                 if (write (md, buffer, i) != i) {
403                     (void) fclose (fp);
404                     return NOTOK;
405                 }
406                 if (mapping)
407                     for (cp = buffer; i-- > 0; size++)
408                         if (*cp++ == '\n')
409                             size++;
410             }
411             if (write (md, "\n", 1) != 1) {
412                 (void) fclose (fp);
413                 return NOTOK;
414             }
415             if (mapping) size += 2;
416
417             (void) fclose (fp);
418             (void) (long) lseek (fd, (off_t)0, 2);
419             stop = (long) lseek (md, (off_t)0, 1);
420             if (mapping)
421                 (void) map_write (mailbox, md, 0, (long)0, start, stop, pos, size,
422                             noisy);
423
424             return OK;
425     }
426 }
427
428 /* \f */
429
430 int     mbx_size (md, start, stop)
431 int     md;
432 long    start,
433         stop;
434 {
435     register int    i,
436                     fd;
437     register long   pos;
438     register FILE  *fp;
439
440     if ((fd = dup (md)) == NOTOK || (fp = fdopen (fd, "r")) == NULL) {
441         if (fd != NOTOK)
442             (void) close (fd);
443         return NOTOK;
444     }
445
446     (void) fseek (fp, start, 0);
447     for (i = 0, pos = stop - start; pos-- > 0; i++)
448         if (fgetc (fp) == '\n')
449             i++;
450
451     (void) fclose (fp);
452
453     return i;
454 }
455
456 /* \f */
457
458 int     mbx_close (mailbox, md)
459 char   *mailbox;
460 int     md;
461 {
462     (void) lkclose (md, mailbox);
463
464     return OK;
465 }
466
467 /* \f */
468
469 /* This function is performed implicitly by getbbent.c:
470
471                 bb -> bb_map = map_name (bb -> bb_file);
472 */
473
474 char    *map_name (file)
475 register char   *file;
476 {
477     register char  *cp;
478     static char buffer[BUFSIZ];
479
480     if ((cp = r1bindex (file, '/')) == file)
481         (void) sprintf (buffer, ".%s.map", cp);
482     else
483         (void) sprintf (buffer, "%.*s.%s.map", cp - file, file, cp);
484
485     return buffer;
486 }
487
488 /* \f */
489
490 int     map_read (file, pos, drops, noisy)
491 char   *file;
492 long    pos;
493 struct drop **drops;
494 int     noisy;
495 {
496     register int    i, j,
497                     md,
498                     msgp;
499     register char  *cp;
500     struct drop d;
501     register struct drop   *mp,
502                            *dp;
503
504     if ((md = open (cp = map_name (file), 0)) == NOTOK
505             || map_chk (cp, md, mp = &d, pos, noisy)) {
506         if (md != NOTOK)
507             (void) close (md);
508         return 0;
509     }
510
511     msgp = mp -> d_id;
512     dp = (struct drop  *) calloc ((unsigned) (msgp + 1), sizeof *dp);
513     if (dp == NULL) {
514         (void) close (md);
515         return 0;
516     }
517
518     bcopy ((char *) mp, (char *) dp, sizeof *dp);
519
520     (void) lseek (md, (off_t) sizeof *mp, 0);
521     if ((i = read (md, (char *) (dp + 1), msgp * sizeof *dp)) < sizeof *dp) {
522         i = 0;
523         free ((char *) dp);
524     }
525     else {
526 #ifdef  NTOHLSWAP
527         register struct drop *tdp;
528         for (j = 0, tdp = dp; j < i / sizeof(*dp); j++, tdp++) {
529             tdp->d_id = ntohl(tdp->d_id);
530             tdp->d_size = ntohl(tdp->d_size);
531             tdp->d_start = ntohl(tdp->d_start);
532             tdp->d_stop = ntohl(tdp->d_stop);
533         }
534 #endif
535         *drops = dp;
536     }
537
538     (void) close (md);
539
540     return (i / sizeof *dp);
541 }
542
543 /* \f */
544
545 int     map_write (mailbox, md, id, last, start, stop, pos, size, noisy)
546 register char   *mailbox;
547 int     md,
548         id,
549         size,
550         noisy;
551 long   last,
552         start,
553         stop,
554         pos;
555 {
556     register int    i;
557     int     clear,
558             fd,
559             td;
560     char   *file;
561     register struct drop   *dp;
562     struct drop    d1,
563                    d2,
564                   *rp;
565     register FILE *fp;
566
567     if ((fd = map_open (file = map_name (mailbox), &clear, md)) == NOTOK)
568         return NOTOK;
569
570     if (!clear && map_chk (file, fd, &d1, pos, noisy)) {
571         (void) unlink (file);
572         (void) mbx_close (file, fd);
573         if ((fd = map_open (file, &clear, md)) == NOTOK)
574             return NOTOK;
575         clear++;
576     }
577
578     if (clear) {
579         if ((td = dup (md)) == NOTOK || (fp = fdopen (td, "r")) == NULL) {
580             if (noisy)
581                 admonish (file, "unable to %s", td != NOTOK ? "fdopen" : "dup");
582             if (td != NOTOK)
583                 (void) close (td);
584             (void) mbx_close (file, fd);
585             return NOTOK;
586         }
587
588         switch (i = mbx_read (fp, 0L, &rp, noisy)) {
589             case NOTOK:
590                 (void) fclose (fp);
591                 (void) mbx_close (file, fd);
592                 return NOTOK;
593
594             case OK:
595                 break;
596
597             default:
598                 d1.d_id = 0;
599                 for (dp = rp; i-- >0; dp++) {
600                     if (dp -> d_start == start)
601                         dp -> d_id = id;
602                     (void) lseek (fd, (off_t) (++d1.d_id * sizeof *dp), 0);
603                     if (write (fd, (char *) dp, sizeof *dp) != sizeof *dp) {
604                         if (noisy)
605                             admonish (file, "write error");
606                         (void) mbx_close (file, fd);
607                         (void) fclose (fp);
608                         return NOTOK;
609                     }
610                 }
611                 free ((char *) rp);
612                 break;
613         }
614     }
615     else {
616         if (last == 0)
617             last = d1.d_start;
618         dp = &d2;
619         dp -> d_id = id;
620         dp -> d_size = (long) (size ? size : mbx_size (fd, start, stop));
621         dp -> d_start = (long) start;
622         dp -> d_stop = (long) stop;
623         (void) lseek (fd, (off_t) (++d1.d_id * sizeof *dp), 0);
624         if (write (fd, (char *) dp, sizeof *dp) != sizeof *dp) {
625             if (noisy)
626                 admonish (file, "write error");
627             (void) mbx_close (file, fd);
628             return NOTOK;
629         }
630     }
631
632     dp = &d1;
633     dp -> d_size = DRVRSN;
634     dp -> d_start = (long) last;
635     dp -> d_stop = (long) lseek (md, (off_t)0, 1);
636
637     (void) lseek (fd, (off_t)0, 0);
638     if (write (fd, (char *) dp, sizeof *dp) != sizeof *dp) {
639         if (noisy)
640             admonish (file, "write error");
641         (void) mbx_close (file, fd);
642         return NOTOK;
643     }
644
645     (void) mbx_close (file, fd);
646
647     return OK;
648 }
649
650 /* \f */
651
652 static int  map_open (file, clear, md)
653 char   *file;
654 int    *clear,
655         md;
656 {
657     int     mode;
658     struct  stat st;
659
660     mode = fstat (md, &st) != NOTOK ? (int) (st.st_mode & 0777) : m_gmprot ();
661     return mbx_Xopen (file, st.st_uid, st.st_gid, mode, clear);
662 }
663
664 /* \f */
665
666 int  map_chk (file, fd, dp, pos, noisy)
667 char   *file;
668 int     fd,
669         noisy;
670 register struct drop *dp;
671 long    pos;
672 {
673     long    count;
674     struct drop d, tmpd;
675     register struct drop    *dl;
676
677     if (read (fd, (char *) &tmpd, sizeof *dp) != sizeof *dp) {
678 #ifdef  notdef
679         admonish (NULLCP, "%s: missing or partial index", file);
680 #endif  /* notdef */
681         return NOTOK;
682     }
683 #ifndef NTOHLSWAP
684     *dp = tmpd;         /* if ntohl(n)=(n), can use struct assign */
685 #else
686     dp->d_id = ntohl(tmpd.d_id);
687     dp->d_size = ntohl(tmpd.d_size);
688     dp->d_start = ntohl(tmpd.d_start);
689     dp->d_stop = ntohl(tmpd.d_stop);
690 #endif
691     
692     if (dp -> d_size != DRVRSN) {
693         if (noisy)
694             admonish (NULLCP, "%s: version mismatch (%d != %d)", file,
695                                 dp->d_size, DRVRSN);
696         return NOTOK;
697     }
698
699     if (dp -> d_stop != (long) pos) {
700         if (noisy && pos != (long)0)
701             admonish (NULLCP,
702                     "%s: pointer mismatch or incomplete index (%ld!=%ld)", 
703                     file, dp -> d_stop, (long) pos);
704         return NOTOK;
705     }
706
707     if ((long) ((dp -> d_id + 1) * sizeof *dp) != (long) lseek (fd, (off_t)0, 2)) {
708         if (noisy)
709             admonish (NULLCP, "%s: corrupt index(1)", file);
710         return NOTOK;
711     }
712
713     dl = &d;
714     count = (long) strlen (mmdlm2);
715     (void) lseek (fd, (off_t) (dp -> d_id * sizeof *dp), 0);
716     if (read (fd, (char *) dl, sizeof *dl) != sizeof *dl
717             || (ntohl(dl -> d_stop) != dp -> d_stop
718                 && ntohl(dl -> d_stop) + count != dp -> d_stop)) {
719         if (noisy)
720             admonish (NULLCP, "%s: corrupt index(2)", file);
721         return NOTOK;
722     }
723
724     return OK;
725 }