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