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