Renamed all standard sequences (e.g. cur->c) and made them globally changeable
[mmh] / uip / scan.c
1 /*
2 ** scan.c -- display a one-line "scan" listing of folder or messages
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 <h/fmt_scan.h>
11 #include <h/scansbr.h>
12 #include <h/tws.h>
13 #include <h/mts.h>
14 #include <h/utils.h>
15 #include <errno.h>
16
17 static struct swit switches[] = {
18 #define CLRSW  0
19         { "clear", 0 },
20 #define NCLRSW  1
21         { "noclear", 0 },
22 #define FORMSW  2
23         { "form formatfile", 0 },
24 #define FMTSW  3
25         { "format string", 5 },
26 #define HEADSW  4
27         { "header", 0 },
28 #define NHEADSW  5
29         { "noheader", 0 },
30 #define WIDTHSW  6
31         { "width columns", 0 },
32 #define REVSW  7
33         { "reverse", 0 },
34 #define NREVSW  8
35         { "noreverse", 0 },
36 #define FILESW  9
37         { "file file", 4 },
38 #define VERSIONSW 10
39         { "version", 0 },
40 #define HELPSW  11
41         { "help", 0 },
42         { NULL, 0 }
43 };
44
45
46 /*
47 ** global for sbr/formatsbr.c - yech!
48 */
49 #ifdef LBL
50 extern struct msgs *fmt_current_folder;
51 #endif
52
53 /*
54 ** prototypes
55 */
56 void clear_screen(void);  /* from termsbr.c */
57
58
59 int
60 main(int argc, char **argv)
61 {
62         int clearflag = 0, hdrflag = 0, ontty;
63         int width = 0, revflag = 0;
64         int i, state, msgnum;
65         int seqnum[NUMATTRS], unseen, num_unseen_seq = 0;
66         char *cp, *maildir, *file = NULL, *folder = NULL;
67         char *form = NULL, *format = NULL, buf[BUFSIZ];
68         char **argp, *nfs, **arguments;
69         struct msgs_array msgs = { 0, 0, NULL };
70         struct msgs *mp;
71         FILE *in;
72
73 #ifdef LOCALE
74         setlocale(LC_ALL, "");
75 #endif
76         invo_name = mhbasename(argv[0]);
77
78         /* read user profile/context */
79         context_read();
80
81         mts_init(invo_name);
82         arguments = getarguments(invo_name, argc, argv, 1);
83         argp = arguments;
84
85         /*
86         ** Parse arguments
87         */
88         while ((cp = *argp++)) {
89                 if (*cp == '-') {
90                         switch (smatch(++cp, switches)) {
91                         case AMBIGSW:
92                                 ambigsw(cp, switches);
93                                 done(1);
94                         case UNKWNSW:
95                                 adios(NULL, "-%s unknown", cp);
96
97                         case HELPSW:
98                                 snprintf(buf, sizeof(buf), "%s [+folder] [msgs] [switches]", invo_name);
99                                 print_help(buf, switches, 1);
100                                 done(1);
101                         case VERSIONSW:
102                                 print_version(invo_name);
103                                 done(1);
104
105                         case CLRSW:
106                                 clearflag++;
107                                 continue;
108                         case NCLRSW:
109                                 clearflag = 0;
110                                 continue;
111
112                         case FORMSW:
113                                 if (!(form = *argp++) || *form == '-')
114                                         adios(NULL, "missing argument to %s",
115                                                         argp[-2]);
116                                 format = NULL;
117                                 continue;
118                         case FMTSW:
119                                 if (!(format = *argp++) || *format == '-')
120                                         adios(NULL, "missing argument to %s",
121                                                         argp[-2]);
122                                 form = NULL;
123                                 continue;
124
125                         case HEADSW:
126                                 hdrflag++;
127                                 continue;
128                         case NHEADSW:
129                                 hdrflag = 0;
130                                 continue;
131
132                         case WIDTHSW:
133                                 if (!(cp = *argp++) || *cp == '-')
134                                         adios(NULL, "missing argument to %s",
135                                                         argp[-2]);
136                                 width = atoi(cp);
137                                 continue;
138                         case REVSW:
139                                 revflag++;
140                                 continue;
141                         case NREVSW:
142                                 revflag = 0;
143                                 continue;
144
145                         case FILESW:
146                                 if (!(cp = *argp++) || (cp[0] == '-' && cp[1]))
147                                         adios(NULL, "missing argument to %s",
148                                                         argp[-2]);
149                                 if (strcmp(file = cp, "-")!=0)
150                                         file = getcpy(expanddir(cp));
151                                 continue;
152                         }
153                 }
154                 if (*cp == '+' || *cp == '@') {
155                         if (folder)
156                                 adios(NULL, "only one folder at a time!");
157                         else
158                                 folder = getcpy(expandfol(cp));
159                 } else
160                         app_msgarg(&msgs, cp);
161         }
162
163         /*
164         ** Get new format string.  Must be before chdir().
165         */
166         nfs = new_fs(form, format, FORMAT);
167
168         /*
169         ** We are scanning a maildrop file
170         */
171         if (file) {
172                 if (msgs.size)
173                         adios(NULL, "\"msgs\" not allowed with -file");
174                 if (folder)
175                         adios(NULL, "\"+folder\" not allowed with -file");
176
177                 /* check if "file" is really stdin */
178                 if (strcmp(file, "-") == 0) {
179                         in = stdin;
180                         file = "stdin";
181                 } else if (!(in = fopen(file, "r"))) {
182                         adios(file, "unable to open");
183                 }
184
185 #ifndef JLR
186                 if (hdrflag) {
187                         printf("FOLDER %s\t%s\n", file, dtimenow(1));
188                 }
189 #endif /* JLR */
190
191                 m_unknown(in);
192                 for (msgnum = 1; ; ++msgnum) {
193                         state = scan(in, msgnum, -1, nfs, width, 0, 0,
194                                         hdrflag ? file : NULL, 0L, 1);
195                         if (state != SCNMSG && state != SCNENC)
196                                 break;
197                 }
198                 fclose(in);
199                 done(0);
200         }
201
202         /*
203         ** We are scanning a folder
204         */
205
206         if (!msgs.size)
207                 app_msgarg(&msgs, seq_all);
208         if (!folder)
209                 folder = getcurfol();
210         maildir = toabsdir(folder);
211
212         if (chdir(maildir) == NOTOK)
213                 adios(maildir, "unable to change directory to");
214
215         /* read folder and create message structure */
216         if (!(mp = folder_read(folder)))
217                 adios(NULL, "unable to read folder %s", folder);
218
219         /* check for empty folder */
220         if (mp->nummsg == 0)
221                 adios(NULL, "no messages in %s", folder);
222
223         /* parse all the message ranges/sequences and set SELECTED */
224         for (msgnum = 0; msgnum < msgs.size; msgnum++)
225                 if (!m_convert(mp, msgs.msgs[msgnum]))
226                         done(1);
227         seq_setprev(mp);  /* set the Previous-Sequence */
228
229         context_replace(curfolder, folder);  /* update current folder */
230         seq_save(mp);  /* synchronize message sequences */
231         context_save();  /* save the context file */
232
233         /*
234         ** Get the sequence number for each `unseen' sequence
235         */
236         if (!(cp = context_find(usequence))) {
237                 cp = seq_unseen;  /* use default, if not set */
238         }
239         if (*cp) {
240                 char **ap, *dp;
241
242                 dp = getcpy(cp);
243                 ap = brkstring(dp, " ", "\n");
244                 for (i = 0; ap && *ap; i++, ap++) {
245                         seqnum[i] = seq_getnum(mp, *ap);
246                 }
247                 num_unseen_seq = i;
248                 if (dp) {
249                         free(dp);
250                 }
251         }
252
253         ontty = isatty(fileno(stdout));
254
255 #ifdef LBL
256         else
257                 fmt_current_folder = mp;
258 #endif
259
260         for (msgnum = revflag ? mp->hghsel : mp->lowsel;
261                  (revflag ? msgnum >= mp->lowsel : msgnum <= mp->hghsel);
262                  msgnum += (revflag ? -1 : 1)) {
263                 if (is_selected(mp, msgnum)) {
264                         if ((in = fopen(cp = m_name(msgnum), "r")) == NULL) {
265 #if 0
266                                 if (errno != EACCES)
267 #endif
268                                         admonish(cp, "unable to open message");
269 #if 0
270                                 else
271                                         printf("%*d  unreadable\n",
272                                                         DMAXFOLDER, msgnum);
273 #endif
274                                 continue;
275                         }
276
277 #ifndef JLR
278                         if (hdrflag) {
279                                 printf("FOLDER %s\t%s\n", folder, dtimenow(1));
280                         }
281 #endif /* JLR */
282
283                         /*
284                         ** Check if message is in any sequence given
285                         ** by Unseen-Sequence profile entry.
286                         */
287                         unseen = 0;
288                         for (i = 0; i < num_unseen_seq; i++) {
289                                 if (in_sequence(mp, seqnum[i], msgnum)) {
290                                         unseen = 1;
291                                         break;
292                                 }
293                         }
294
295                         switch (state = scan(in, msgnum, 0, nfs, width,
296                                                 msgnum == mp->curmsg, unseen,
297                                                 folder, 0L, 1)) {
298                         case SCNMSG:
299                         case SCNENC:
300                         case SCNERR:
301                                 break;
302
303                         default:
304                                 adios(NULL, "scan() botch(%d)", state);
305
306                         case SCNEOF:
307 #if 0
308                                 printf("%*d  empty\n", DMAXFOLDER, msgnum);
309 #else
310                                 advise(NULL, "message %d: empty", msgnum);
311 #endif
312                                 break;
313                         }
314                         hdrflag = 0;
315                         fclose(in);
316                         if (ontty)
317                                 fflush(stdout);
318                 }
319         }
320
321 #ifdef LBL
322         seq_save(mp);  /* because formatsbr might have made changes */
323 #endif
324
325         folder_free(mp);  /* free folder/message structure */
326         if (clearflag)
327                 clear_screen();
328
329         done(0);
330         return 1;
331 }