]> diplodocus.org Git - nmh/blob - sbr/seq_read.c
e63f8101db3020df59828c5932992f4b72f622d0
[nmh] / sbr / seq_read.c
1 /* seq_read.c -- read the .mh_sequence file and
2 * -- initialize sequence information
3 *
4 * This code is Copyright (c) 2002, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
7 */
8
9 #include "h/mh.h"
10 #include "seq_read.h"
11 #include "ssequal.h"
12 #include "trimcpy.h"
13 #include "getcpy.h"
14 #include "m_atoi.h"
15 #include "brkstring.h"
16 #include "error.h"
17 #include "h/utils.h"
18 #include "lock_file.h"
19
20 /*
21 * static prototypes
22 */
23 static int seq_init (struct msgs *, char *, char *);
24 static int seq_public (struct msgs *, int, int *);
25 static void seq_private (struct msgs *);
26
27
28 /*
29 * Get the sequence information for this folder from
30 * .mh_sequences (or equivalent specified in .mh_profile)
31 * or context file (for private sequences).
32 */
33
34 int
35 seq_read (struct msgs *mp, int lockflag)
36 {
37 int failed_to_lock = 0;
38
39 /*
40 * Initialize the list of sequence names. Go ahead and
41 * add the "cur" sequence to the list of sequences.
42 */
43 svector_push_back (mp->msgattrs, getcpy (current));
44 make_all_public (mp); /* initially, make all public */
45
46 /* If folder is empty, don't scan for sequence information */
47 if (mp->nummsg == 0)
48 return OK;
49
50 /* Initialize the public sequences */
51 if (seq_public (mp, lockflag, &failed_to_lock) == NOTOK) {
52 if (failed_to_lock) return NOTOK;
53 }
54
55 /* Initialize the private sequences */
56 seq_private (mp);
57
58 return OK;
59 }
60
61
62 /*
63 * read folder's sequences file for public sequences
64 */
65
66 static int
67 seq_public (struct msgs *mp, int lockflag, int *failed_to_lock)
68 {
69 int state;
70 char *cp, seqfile[PATH_MAX];
71 char name[NAMESZ], field[NMH_BUFSIZ];
72 FILE *fp;
73 m_getfld_state_t gstate;
74
75 /*
76 * If mh_seq == NULL or if *mh_seq == '\0' (the user has defined
77 * the "mh-sequences" profile entry, but left it empty),
78 * then just return, and do not initialize any public sequences.
79 */
80 if (mh_seq == NULL || *mh_seq == '\0')
81 return OK;
82
83 /* get filename of sequence file */
84 snprintf (seqfile, sizeof(seqfile), "%s/%s", mp->foldpath, mh_seq);
85
86 if ((fp = lkfopendata (seqfile, lockflag ? "r+" : "r", failed_to_lock))
87 == NULL)
88 return NOTOK;
89
90 /* Use m_getfld2 to scan sequence file */
91 gstate = m_getfld_state_init(fp);
92 for (;;) {
93 int fieldsz = sizeof field;
94 switch (state = m_getfld2(&gstate, name, field, &fieldsz)) {
95 case FLD:
96 case FLDPLUS:
97 if (state == FLDPLUS) {
98 cp = mh_xstrdup(field);
99 while (state == FLDPLUS) {
100 fieldsz = sizeof field;
101 state = m_getfld2(&gstate, name, field, &fieldsz);
102 cp = add (field, cp);
103 }
104 seq_init (mp, mh_xstrdup(name), trimcpy (cp));
105 free (cp);
106 } else {
107 seq_init (mp, mh_xstrdup(name), trimcpy (field));
108 }
109 continue;
110
111 case BODY:
112 lkfclosedata (fp, seqfile);
113 die("no blank lines are permitted in %s", seqfile);
114 break;
115
116 case FILEEOF:
117 break;
118
119 default:
120 lkfclosedata (fp, seqfile);
121 die("%s is poorly formatted", seqfile);
122 }
123 break; /* break from for loop */
124 }
125 m_getfld_state_destroy (&gstate);
126
127 if (lockflag) {
128 mp->seqhandle = fp;
129 mp->seqname = mh_xstrdup(seqfile);
130 } else {
131 lkfclosedata (fp, seqfile);
132 }
133
134 return OK;
135 }
136
137
138 /*
139 * Scan profile/context list for private sequences.
140 *
141 * We search the context list for all keys that look like
142 * "atr-seqname-folderpath", and add them as private sequences.
143 */
144
145 static void
146 seq_private (struct msgs *mp)
147 {
148 int i, j, alen, plen;
149 char *cp;
150 struct node *np;
151
152 alen = LEN("atr-");
153 plen = strlen (mp->foldpath) + 1;
154
155 for (np = m_defs; np; np = np->n_next) {
156 if (ssequal ("atr-", np->n_name)
157 && (j = strlen (np->n_name) - plen) > alen
158 && *(np->n_name + j) == '-'
159 && strcmp (mp->foldpath, np->n_name + j + 1) == 0) {
160 cp = mh_xstrdup(np->n_name + alen);
161 *(cp + j - alen) = '\0';
162 if ((i = seq_init (mp, cp, getcpy (np->n_field))) != -1)
163 make_seq_private (mp, i);
164 }
165 }
166 }
167
168
169 /*
170 * Add the name of sequence to the list of folder sequences.
171 * Then parse the list of message ranges for this
172 * sequence, and setup the various bit flags for each
173 * message in the sequence.
174 *
175 * Return internal index for the sequence if successful.
176 * Return -1 on error.
177 */
178
179 static int
180 seq_init (struct msgs *mp, char *name, char *field)
181 {
182 unsigned int i;
183 int j, k, is_current;
184 char *cp, **ap;
185
186 /*
187 * Check if this is "cur" sequence,
188 * so we can do some special things.
189 */
190 is_current = !strcmp (current, name);
191
192 /*
193 * Search for this sequence name to see if we've seen
194 * it already. If we've seen this sequence before,
195 * then clear the bit for this sequence from all the
196 * messages in this folder.
197 */
198 for (i = 0; i < svector_size (mp->msgattrs); i++) {
199 if (!strcmp (svector_at (mp->msgattrs, i), name)) {
200 for (j = mp->lowmsg; j <= mp->hghmsg; j++)
201 clear_sequence (mp, i, j);
202 break;
203 }
204 }
205
206 /*
207 * If we've already seen this sequence name, just free the
208 * name string. Else add it to the list of sequence names.
209 */
210 if (svector_at (mp->msgattrs, i)) {
211 free (name);
212 } else {
213 svector_push_back (mp->msgattrs, name);
214 }
215
216 /*
217 * Split up the different message ranges at whitespace
218 */
219 for (ap = brkstring (field, " ", "\n"); *ap; ap++) {
220 if ((cp = strchr(*ap, '-')))
221 *cp++ = '\0';
222 if ((j = m_atoi (*ap)) > 0) {
223 k = cp ? m_atoi (cp) : j;
224
225 /*
226 * Keep mp->curmsg and "cur" sequence in synch. Unlike
227 * other sequences, this message doesn't need to exist.
228 * Think about the series of command (rmm; next) to
229 * understand why this can be the case. But if it does
230 * exist, we will still set the bit flag for it like
231 * other sequences.
232 */
233 if (is_current)
234 mp->curmsg = j;
235 /*
236 * We iterate through messages in this range
237 * and flip on bit for this sequence.
238 */
239 for (; j <= k; j++) {
240 if (j >= mp->lowmsg && j <= mp->hghmsg && does_exist(mp, j))
241 add_sequence (mp, i, j);
242 }
243 }
244 }
245
246 free (field); /* free string containing message ranges */
247 return i;
248 }