Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / local / lbl / sbr / m_gmsg.c
1 /* m_gmsg.c - read a folder */
2
3 #include "../h/mh.h"
4 #include <stdio.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <ctype.h>
8 #ifndef BSD42
9 #ifndef SYS5
10 #include <ndir.h>
11 #else   SYS5
12 #include <dir.h>
13 #endif  SYS5
14 #else   BSD42
15 #include <sys/dir.h>
16 #endif  BSD42
17
18
19 #define NINFO   (MAXFOLDER / 5) /* PLEASE be non-trivial... */
20 struct info {
21     int     msgno;
22     int   stats;
23 };
24
25 static int m_getatr(), m_setatr();
26
27 static int  len;
28 static struct info *head;
29
30 /* \f */
31
32 struct msgs *
33 m_gmsg(name)
34         register char *name;
35 {
36 #ifdef  COMPAT
37     register int    cur,
38                     fd;
39 #endif  COMPAT
40     register int    i,
41                     j;
42     register struct info *rover,
43                          *tail;
44 #ifdef  COMPAT
45     register char  *cp;
46     char    buffer[BUFSIZ];
47 #endif  COMPAT
48     register struct msgs   *mp;
49     register struct direct *dp;
50     register    DIR * dd;
51     struct stat st;
52
53     if ((dd = opendir (name = m_mailpath (name))) == NULL) {
54         free (name);
55         return NULL;
56     }
57     (void) fstat (dd->dd_fd, &st);
58
59     mp = (struct msgs  *) malloc (MSIZE (mp, 0, 0));
60     if (mp == NULL)
61         adios (NULLCP, "unable to allocate folder storage");
62     mp->lowmsg = mp->hghmsg = mp->nummsg = 0;
63     mp->curmsg = 0;
64     mp->lowsel = mp->hghsel = mp->numsel = 0;
65     mp->foldpath = name;
66     mp->msgflags = NULL;
67     if (st.st_uid != getuid () || access (name, 02) == NOTOK)
68         mp->msgflags |= READONLY;
69 #ifdef  COMPAT
70     cur = 0;
71 #endif  COMPAT
72     j = strlen (SBACKUP);
73     if (head == NULL)
74         if ((head = (struct info *)
75                 malloc ((unsigned) ((len = NINFO) * sizeof *head))) == NULL)
76             adios (NULLCP, "unable to allocate info storage");
77     tail = (rover = head) + len;
78
79     while (dp = readdir (dd))
80         if (i = m_atoi (dp->d_name)) {
81             if (rover >= tail) {
82                 register int curlen = tail - head;
83
84                 if ((tail = (struct info *) realloc ((char *) head,
85                              (unsigned) ((len += NINFO) * sizeof *head)))
86                         == NULL)
87                     adios (NULLCP, "unable to allocate info storage");
88                 else
89                     rover = tail + curlen, head = tail, tail += len;
90             }
91             if (i > mp->hghmsg)
92                 mp->hghmsg = i;
93             mp->nummsg++;
94             if (mp->lowmsg == 0 || i < mp->lowmsg)
95                 mp->lowmsg = i;
96             rover->msgno = i;
97             rover->stats = EXISTS;
98 #ifdef  notdef
99             rover->stats &= ~DELETED;
100 #endif  notdef
101             rover++;
102         }
103         else
104             switch (dp->d_name[0]) {
105                 case '.': 
106                     continue;
107
108                 case ',': 
109 #ifdef  notdef
110                     if ((i = m_atoi (dp->d_name + 1)) {
111                         register struct info *l;
112
113                         for (l = head; l < rover; l++)
114                             if (l->msgno == i) {
115                                 if (!(l->stats & EXISTS))
116                                     l->stats |= DELETED;
117                                 break;
118                             }
119                     }
120 #endif  notdef
121                     continue;
122
123 #ifdef  MHE
124                 case '+': 
125                     continue;
126 #endif  MHE
127
128 #ifdef  UCI
129                 case '_': 
130                 case '#': 
131                     continue;
132 #endif  UCI
133
134                 default: 
135 #ifdef  COMPAT
136                     if (strcmp (dp->d_name, current) == 0) {
137                         cur++;
138                         continue;
139                     }
140 #endif  COMPAT
141                     if (strcmp (dp->d_name, LINK) == 0
142                             || strncmp (dp->d_name, SBACKUP, j) == 0)
143                         continue;
144                     mp->msgflags |= OTHERS;
145                     continue;
146             }
147
148     closedir (dd);
149
150 /* \f */
151
152 #ifdef  COMPAT
153     (void) sprintf (buffer, "%s-%s", current, name);
154     if (cp = m_find (buffer)) {
155         i = m_atoi (cp);
156         (void) m_delete(buffer);
157         if (i > 0)
158             mp->curmsg = i;
159     }
160     if (mp->curmsg == 0 && cur && (fd = open (current, 0)) != NOTOK) {
161             if ((i = read (fd, buffer, sizeof buffer)) > 0) {
162                 if (cp = index (buffer, '\n'))
163                     *cp = NULL;
164                 if ((i = m_atoi (buffer)) > 0)
165                     mp->curmsg = i;
166             }
167             (void) close (fd);
168         }
169     if (cur && !(mp->msgflags & READONLY)){     /* sneaky... */
170         (void) sprintf (buffer, "%s/%s", name, current);
171         (void) unlink (buffer);
172     }
173 #endif  COMPAT
174
175 #ifndef MTR
176     mp->lowoff = 1;
177 #else   MTR
178     mp->lowoff = mp->lowmsg;
179 #endif  MTR
180     mp->hghoff = mp->hghmsg + 1;/* for "new" in m_convert */
181
182     mp = (struct msgs  *)
183                 realloc ((char *) mp, MSIZE (mp, mp->lowoff, mp->hghoff));
184     if (mp == NULL)
185         adios (NULLCP, "unable to allocate folder storage");
186 #ifndef MTR
187     for (i = mp->lowmsg; i <= mp->hghmsg; i++)
188         mp->msgstats[i] = 0;
189 #else   MTR
190     mp->msgstats = (int *)
191                 calloc ((unsigned) 1, MSIZEX (mp, mp->lowmsg, mp->hghmsg));
192     if (mp->msgstats == NULL)
193         adios (NULLCP, "unable to allocate messages storage");
194     mp->msgstats = (mp->msgbase = mp->msgstats) - mp->lowoff;
195     if (mp->msgstats < 0)
196         adios (NULLCP, "m_gmsg() botch -- you lose big");
197 #endif  MTR
198     for (tail = head; tail < rover; tail++)
199         mp->msgstats[tail->msgno] = tail->stats;
200     m_getatr (mp);
201
202     return mp;
203 }
204
205 /* \f */
206
207 static int
208 m_getatr(mp)
209         register struct msgs *mp;
210 {
211     int     alen,
212             bits,
213             i,
214             j,
215             plen,
216             state;
217     register char  *cp;
218     char    name[NAMESZ],
219             field[BUFSIZ];
220     register struct node   *np;
221     register    FILE * fp;
222
223     bits = FFATTRSLOT;
224
225     mp->msgattrs[0] = getcpy (current);
226     mp->msgattrs[1] = NULL;
227     mp->attrstats = 0;  /* initially, all public */
228
229     m_getdefs ();
230     if (mh_seq == NULL || *mh_seq == NULL)
231         goto private_only;
232
233     (void) sprintf (field, "%s/%s", mp->foldpath, mh_seq);
234     if (fp = fopen (field, "r")) {
235         for (state = FLD;;) {
236             switch (state = m_getfld (state, name, field, sizeof field, fp)) {
237                 case FLDPLUS: 
238                         /*
239                          * sequence was too big for buffer: back up
240                          * to a word break.
241                          */
242                         for (cp = &field[sizeof(field)-2]; !isspace(*cp); --cp)
243                                 ;
244                         if (i = cp - &field[sizeof(field)-2]) {
245                                 *cp = 0;
246                                 fseek(fp, i, 1);
247                         }
248                         /*FALL THROUGH*/
249                 case FLD: 
250                     (void) m_setatr (mp, name, field);
251                     continue;
252
253                 case FLDEOF: 
254                     (void) m_setatr (mp, name, field);
255                     break;
256
257                 case BODY: 
258                 case BODYEOF: 
259                     adios (NULLCP,
260                             "no blank lines are permitted in %s/%s",
261                             mp->foldpath, mh_seq);/* fall */
262
263                 case FILEEOF:
264                     break;
265
266                 default: 
267                     adios (NULLCP, "%s/%s is poorly formatted",
268                             mp->foldpath, mh_seq);
269             }
270             break;
271         }
272         (void) fclose (fp);
273     }
274
275 private_only: ;
276     alen = strlen ("atr-");
277     plen = strlen (mp->foldpath) + 1;
278
279     for (np = m_defs; np; np = np->n_next)
280         if (ssequal ("atr-", np->n_name)
281                 && (j = strlen (np->n_name) - plen) > alen
282                 && *(np->n_name + j) == '-'
283                 && strcmp (mp->foldpath, np->n_name + j + 1) == 0) {
284             cp = getcpy (np->n_name + alen);
285             *(cp + j - alen) = NULL;
286             if ((i = m_setatr (mp, cp, np->n_field)) != NOTOK)
287                 mp->attrstats |= 1 << (bits + i);/* private */
288             free(cp);
289         }
290 }
291
292 /* \f */
293
294 static int
295 m_setatr(mp, name, field)
296         register struct msgs *mp;
297         register char *name, *field;
298 {
299     register int bits, slot, first, last;
300     register char *cp;
301
302     if (strcmp (current, name) == 0) {
303         mp->curmsg = atoi(field);
304         return (0);
305     }
306
307     for (slot = 0; mp->msgattrs[slot]; slot++)
308         if (strcmp(mp->msgattrs[slot], name) == 0)
309             break;
310
311     if (slot >= NATTRS)
312         return NOTOK;
313
314     if (mp->msgattrs[slot] == NULL) {
315         mp->msgattrs[slot] = getcpy(name);
316         mp->msgattrs[slot + 1] = NULL;
317     }
318
319     bits = 1 << (FFATTRSLOT + slot);
320
321     for (cp = field; *cp; ) {
322         while (isspace(*cp))
323                 ++cp;
324         if (! isdigit(*cp))
325                 return (NOTOK);
326         for (first = 0; isdigit(*cp); ++cp)
327                 first = (first * 10) + (*cp - '0');
328         if (first == 0)
329                 return (NOTOK);
330         if (*cp++ == '-') {
331                 /* have a range of msgs */
332                 for (last = 0; isdigit(*cp); ++cp)
333                         last = (last * 10) + (*cp - '0');
334                 if (last < first) {
335                         advise(NULLCP,
336                                "seq %s msg range bad: first (%d) > last (%d)",
337                                name, first, last);
338                         continue;
339                 }
340                 if (last < mp->lowmsg)
341                         continue;
342                 if (last > mp->hghmsg)
343                         last = mp->hghmsg;
344                 if (first < mp->lowmsg)
345                         first = mp->lowmsg;
346         } else {
347                 if (first < mp->lowmsg)
348                         continue;
349                 last = first;
350         }
351         for ( ; first <= last; ++first)
352                 if (mp->msgstats[first] & EXISTS)
353                         mp->msgstats[first] |= bits;
354     }
355     return slot;
356 }