source: trunk/third/nmh/uip/pick.c @ 12455

Revision 12455, 7.3 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12454, which included commits to RCS files with non-trunk default branches.
Line 
1
2/*
3 * pick.c -- search for messages by content
4 *
5 * $Id: pick.c,v 1.1.1.1 1999-02-07 18:14:15 danw Exp $
6 */
7
8#include <h/mh.h>
9#include <zotnet/tws/tws.h>
10#include <h/picksbr.h>
11
12/*
13 * We allocate space for messages (msgs array)
14 * this number of elements at a time.
15 */
16#define MAXMSGS  256
17
18
19static struct swit switches[] = {
20#define ANDSW                   0
21    { "and", 0 },
22#define ORSW                    1
23    { "or", 0 },
24#define NOTSW                   2
25    { "not", 0 },
26#define LBRSW                   3
27    { "lbrace", 0 },
28#define RBRSW                   4
29    { "rbrace", 0 },
30#define CCSW                    5
31    { "cc  pattern", 0 },
32#define DATESW                  6
33    { "date  pattern", 0 },
34#define FROMSW                  7
35    { "from  pattern", 0 },
36#define SRCHSW                  8
37    { "search  pattern", 0 },
38#define SUBJSW                  9
39    { "subject  pattern", 0 },
40#define TOSW                   10
41    { "to  pattern", 0 },
42#define OTHRSW                 11
43    { "-othercomponent  pattern", 0 },
44#define AFTRSW                 12
45    { "after date", 0 },
46#define BEFRSW                 13
47    { "before date", 0 },
48#define DATFDSW                14
49    { "datefield field", 5 },
50#define SEQSW                  15
51    { "sequence name", 0 },
52#define PUBLSW                 16
53    { "public", 0 },
54#define NPUBLSW                17
55    { "nopublic", 0 },
56#define ZEROSW                 18
57    { "zero", 0 },
58#define NZEROSW                19
59    { "nozero", 0 },
60#define LISTSW                 20
61    { "list", 0 },
62#define NLISTSW                21
63    { "nolist", 0 },
64#define VERSIONSW              22
65    { "version", 0 },
66#define HELPSW                 23
67    { "help", 4 },
68    { NULL, 0 }
69};
70
71static int listsw = 0;
72
73
74int
75main (int argc, char **argv)
76{
77    int publicsw = -1, zerosw = 1, seqp = 0, vecp = 0;
78    int nummsgs, maxmsgs, lo, hi, msgnum;
79    char *maildir, *folder = NULL, buf[100];
80    char *cp, **argp, **arguments;
81    char **msgs, *seqs[NUMATTRS + 1], *vec[MAXARGS];
82    struct msgs *mp;
83    register FILE *fp;
84
85#ifdef LOCALE
86    setlocale(LC_ALL, "");
87#endif
88    invo_name = r1bindex (argv[0], '/');
89
90    /* read user profile/context */
91    context_read();
92
93    arguments = getarguments (invo_name, argc, argv, 1);
94    argp = arguments;
95
96    /*
97     * Allocate the initial space to record message
98     * names, ranges, and sequences.
99     */
100    nummsgs = 0;
101    maxmsgs = MAXMSGS;
102    if (!(msgs = (char **) malloc ((size_t) (maxmsgs * sizeof(*msgs)))))
103        adios (NULL, "unable to allocate storage");
104
105    while ((cp = *argp++)) {
106        if (*cp == '-') {
107            if (*++cp == '-') {
108                vec[vecp++] = --cp;
109                goto pattern;
110            }
111            switch (smatch (cp, switches)) {
112            case AMBIGSW:
113                ambigsw (cp, switches);
114                done (1);
115            case UNKWNSW:
116                adios (NULL, "-%s unknown", cp);
117
118            case HELPSW:
119                snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]",
120                          invo_name);
121                print_help (buf, switches, 1);
122                listsw = 0;     /* HACK */
123                done (1);
124            case VERSIONSW:
125                print_version(invo_name);
126                done (1);
127
128            case CCSW:
129            case DATESW:
130            case FROMSW:
131            case SUBJSW:
132            case TOSW:
133            case DATFDSW:
134            case AFTRSW:
135            case BEFRSW:
136            case SRCHSW:
137                vec[vecp++] = --cp;
138            pattern:
139                if (!(cp = *argp++))/* allow -xyz arguments */
140                    adios (NULL, "missing argument to %s", argp[-2]);
141                vec[vecp++] = cp;
142                continue;
143            case OTHRSW:
144                adios (NULL, "internal error!");
145
146            case ANDSW:
147            case ORSW:
148            case NOTSW:
149            case LBRSW:
150            case RBRSW:
151                vec[vecp++] = --cp;
152                continue;
153
154            case SEQSW:
155                if (!(cp = *argp++) || *cp == '-')
156                    adios (NULL, "missing argument to %s", argp[-2]);
157
158                /* check if too many sequences specified */
159                if (seqp >= NUMATTRS)
160                    adios (NULL, "too many sequences (more than %d) specified", NUMATTRS);
161                seqs[seqp++] = cp;
162                listsw = 0;
163                continue;
164            case PUBLSW:
165                publicsw = 1;
166                continue;
167            case NPUBLSW:
168                publicsw = 0;
169                continue;
170            case ZEROSW:
171                zerosw++;
172                continue;
173            case NZEROSW:
174                zerosw = 0;
175                continue;
176
177            case LISTSW:
178                listsw++;
179                continue;
180            case NLISTSW:
181                listsw = 0;
182                continue;
183            }
184        }
185        if (*cp == '+' || *cp == '@') {
186            if (folder)
187                adios (NULL, "only one folder at a time!");
188            else
189                folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
190        } else {
191            /*
192             * Check if we need to allocate more space
193             * for message name/ranges/sequences.
194             */
195            if (nummsgs >= maxmsgs) {
196                maxmsgs += MAXMSGS;
197                if (!(msgs = (char **) realloc (msgs,
198                                                (size_t) (maxmsgs * sizeof(*msgs)))))
199                    adios (NULL, "unable to reallocate msgs storage");
200            }
201            msgs[nummsgs++] = cp;
202        }
203    }
204    vec[vecp] = NULL;
205
206    if (!context_find ("path"))
207        free (path ("./", TFOLDER));
208
209    /*
210     * If we didn't specify which messages to search,
211     * then search the whole folder.
212     */
213    if (!nummsgs)
214        msgs[nummsgs++] = "all";
215
216    if (!folder)
217        folder = getfolder (1);
218    maildir = m_maildir (folder);
219
220    if (chdir (maildir) == NOTOK)
221        adios (maildir, "unable to change directory to");
222
223    /* read folder and create message structure */
224    if (!(mp = folder_read (folder)))
225        adios (NULL, "unable to read folder %s", folder);
226
227    /* check for empty folder */
228    if (mp->nummsg == 0)
229        adios (NULL, "no messages in %s", folder);
230
231    /* parse all the message ranges/sequences and set SELECTED */
232    for (msgnum = 0; msgnum < nummsgs; msgnum++)
233        if (!m_convert (mp, msgs[msgnum]))
234            done (1);
235    seq_setprev (mp);   /* set the previous-sequence */
236
237    /*
238     * If we aren't saving the results to a sequence,
239     * we need to list the results.
240     */
241    if (seqp == 0)
242        listsw++;
243
244    if (publicsw == 1 && is_readonly(mp))
245        adios (NULL, "folder %s is read-only, so -public not allowed", folder);
246
247    if (!pcompile (vec, NULL))
248        done (1);
249
250    lo = mp->lowsel;
251    hi = mp->hghsel;
252
253    /*
254     * Scan through all the SELECTED messages and check for a
255     * match.  If the message does not match, then unselect it.
256     */
257    for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
258        if (is_selected (mp, msgnum)) {
259            if ((fp = fopen (cp = m_name (msgnum), "r")) == NULL)
260                admonish (cp, "unable to read message");
261            if (fp && pmatches (fp, msgnum, 0L, 0L)) {
262                if (msgnum < lo)
263                    lo = msgnum;
264                if (msgnum > hi)
265                    hi = msgnum;
266            } else {
267                /* if it doesn't match, then unselect it */
268                unset_selected (mp, msgnum);
269                mp->numsel--;
270            }
271            if (fp)
272                fclose (fp);
273        }
274    }
275
276    mp->lowsel = lo;
277    mp->hghsel = hi;
278
279    if (mp->numsel <= 0)
280        adios (NULL, "no messages match specification");
281
282    seqs[seqp] = NULL;
283
284    /*
285     * Add the matching messages to sequences
286     */
287    for (seqp = 0; seqs[seqp]; seqp++)
288        if (!seq_addsel (mp, seqs[seqp], publicsw, zerosw))
289            done (1);
290
291    /*
292     * Print the name of all the matches
293     */
294    if (listsw) {
295        for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
296            if (is_selected (mp, msgnum))
297                printf ("%s\n", m_name (msgnum));
298    } else {
299        printf ("%d hit%s\n", mp->numsel, mp->numsel == 1 ? "" : "s");
300    }
301
302    context_replace (pfolder, folder);  /* update current folder         */
303    seq_save (mp);                      /* synchronize message sequences */
304    context_save ();                    /* save the context file         */
305    folder_free (mp);                   /* free folder/message structure */
306    done (0);
307}
308
309
310void
311done (int status)
312{
313    if (listsw && status && !isatty (fileno (stdout)))
314        printf ("0\n");
315    exit (status);
316}
Note: See TracBrowser for help on using the repository browser.