1 /* mark.c -- add message(s) to sequences in given folder
2  *        -- delete messages (s) from sequences in given folder
3  *        -- list sequences in given folder
4  *
5  * This code is Copyright (c) 2002, by the authors of nmh.  See the
6  * COPYRIGHT file in the root directory of the nmh distribution for
7  * complete copyright information.
8  */
9 
10 #include <h/mh.h>
11 #include <h/utils.h>
12 #include "../sbr/m_maildir.h"
13 
14 #define MARK_SWITCHES \
15     X("add", 0, ADDSW) \
16     X("delete", 0, DELSW) \
17     X("list", 0, LSTSW) \
18     X("sequence name", 0, SEQSW) \
19     X("public", 0, PUBLSW) \
20     X("nopublic", 0, NPUBLSW) \
21     X("zero", 0, ZEROSW) \
22     X("nozero", 0, NZEROSW) \
23     X("version", 0, VERSIONSW) \
24     X("help", 0, HELPSW) \
25     X("debug", -5, DEBUGSW) \
26 
27 #define X(sw, minchars, id) id,
28 DEFINE_SWITCH_ENUM(MARK);
29 #undef X
30 
31 #define X(sw, minchars, id) { sw, minchars, id },
32 DEFINE_SWITCH_ARRAY(MARK, switches);
33 #undef X
34 
35 /*
36  * static prototypes
37  */
38 static void print_debug (struct msgs *);
39 static void seq_printdebug (struct msgs *);
40 
41 
42 int
main(int argc,char ** argv)43 main (int argc, char **argv)
44 {
45     int addsw = 0, deletesw = 0, debugsw = 0;
46     int listsw = 0, publicsw = -1, zerosw = 0, msgnum;
47     unsigned int seqp = 0;
48     char *cp, *maildir, *folder = NULL, buf[BUFSIZ];
49     char **argp, **arguments;
50     svector_t seqs = svector_create (0);
51     struct msgs_array msgs = { 0, 0, NULL };
52     struct msgs *mp;
53 
54     if (nmh_init(argv[0], 1)) { return 1; }
55 
56     arguments = getarguments (invo_name, argc, argv, 1);
57     argp = arguments;
58 
59     /*
60      * Parse arguments
61      */
62     while ((cp = *argp++)) {
63 	if (*cp == '-') {
64 	    switch (smatch (++cp, switches)) {
65 	    case AMBIGSW:
66 		ambigsw (cp, switches);
67 		done (1);
68 	    case UNKWNSW:
69 		adios (NULL, "-%s unknown\n", cp);
70 
71 	    case HELPSW:
72 		snprintf (buf, sizeof(buf), "%s [+folder] [msgs] [switches]",
73 			  invo_name);
74 		print_help (buf, switches, 1);
75 		done (0);
76 	    case VERSIONSW:
77 		print_version(invo_name);
78 		done (0);
79 
80 	    case ADDSW:
81 		addsw++;
82 		deletesw = listsw = 0;
83 		continue;
84 	    case DELSW:
85 		deletesw++;
86 		addsw = listsw = 0;
87 		continue;
88 	    case LSTSW:
89 		listsw++;
90 		addsw = deletesw = 0;
91 		continue;
92 
93 	    case SEQSW:
94 		if (!(cp = *argp++) || *cp == '-')
95 		    adios (NULL, "missing argument to %s", argp[-2]);
96 
97 		svector_push_back (seqs, cp);
98 		seqp++;
99 		continue;
100 
101 	    case PUBLSW:
102 		publicsw = 1;
103 		continue;
104 	    case NPUBLSW:
105 		publicsw = 0;
106 		continue;
107 
108 	    case DEBUGSW:
109 		debugsw++;
110 		continue;
111 
112 	    case ZEROSW:
113 		zerosw++;
114 		continue;
115 	    case NZEROSW:
116 		zerosw = 0;
117 		continue;
118 	    }
119 	}
120 	if (*cp == '+' || *cp == '@') {
121 	    if (folder)
122 		adios (NULL, "only one folder at a time!");
123 	    else
124 		folder = pluspath (cp);
125 	} else
126 		app_msgarg(&msgs, cp);
127     }
128 
129     /*
130      * If we haven't specified -add, -delete, or -list,
131      * then use -add if a sequence was specified, else
132      * use -list.
133      */
134     if (!addsw && !deletesw && !listsw) {
135 	if (seqp)
136 	    addsw++;
137 	else
138 	    listsw++;
139     }
140 
141     if (!context_find ("path"))
142 	free (path ("./", TFOLDER));
143     if (!msgs.size)
144 	app_msgarg(&msgs, listsw ? "all" :"cur");
145     if (!folder)
146 	folder = getfolder (1);
147     maildir = m_maildir (folder);
148 
149     if (chdir (maildir) == NOTOK)
150 	adios (maildir, "unable to change directory to");
151 
152     /* read folder and create message structure */
153     if (!(mp = folder_read (folder, 1)))
154 	adios (NULL, "unable to read folder %s", folder);
155 
156     /* print some general debugging info */
157     if (debugsw)
158 	print_debug(mp);
159 
160     /* check for empty folder */
161     if (mp->nummsg == 0)
162 	adios (NULL, "no messages in %s", folder);
163 
164     /* parse all the message ranges/sequences and set SELECTED */
165     for (msgnum = 0; msgnum < msgs.size; msgnum++)
166 	if (!m_convert (mp, msgs.msgs[msgnum]))
167 	    done (1);
168 
169     if (publicsw == 1 && is_readonly(mp))
170 	adios (NULL, "folder %s is read-only, so -public not allowed", folder);
171 
172     /*
173      * Make sure at least one sequence has been
174      * specified if we are adding or deleting.
175      */
176     if (seqp == 0 && (addsw || deletesw))
177 	adios (NULL, "-%s requires at least one -sequence argument",
178 	       addsw ? "add" : "delete");
179 
180     /* Adding messages to sequences */
181     if (addsw) {
182 	for (seqp = 0; seqp < svector_size (seqs); seqp++)
183 	    if (!seq_addsel (mp, svector_at (seqs, seqp), publicsw, zerosw))
184 		done (1);
185     }
186 
187     /* Deleting messages from sequences */
188     if (deletesw) {
189 	for (seqp = 0; seqp < svector_size (seqs); seqp++)
190 	    if (!seq_delsel (mp, svector_at (seqs, seqp), publicsw, zerosw))
191 		done (1);
192     }
193 
194     /* Listing messages in sequences */
195     if (listsw) {
196 	if (seqp) {
197 	    /* print the sequences given */
198 	    for (seqp = 0; seqp < svector_size (seqs); seqp++)
199 		seq_print (mp, svector_at (seqs, seqp));
200 	} else {
201 	    /* else print them all */
202 	    seq_printall (mp);
203 	}
204 
205 	/* print debugging info about SELECTED messages */
206 	if (debugsw)
207 	    seq_printdebug (mp);
208     }
209 
210     svector_free (seqs);
211     seq_save (mp);			/* synchronize message sequences */
212     context_replace (pfolder, folder);	/* update current folder         */
213     context_save ();			/* save the context file         */
214     folder_free (mp);			/* free folder/message structure */
215     done (0);
216     return 1;
217 }
218 
219 
220 /*
221  * Print general debugging info
222  */
223 static void
print_debug(struct msgs * mp)224 print_debug (struct msgs *mp)
225 {
226     char buf[100];
227 
228     printf ("invo_name     = %s\n", invo_name);
229     printf ("mypath        = %s\n", mypath);
230     printf ("defpath       = %s\n", defpath);
231     printf ("ctxpath       = %s\n", ctxpath);
232     printf ("context flags = %s\n", snprintb (buf, sizeof(buf),
233 		(unsigned) ctxflags, DBITS));
234     printf ("foldpath      = %s\n", mp->foldpath);
235     printf ("folder flags  = %s\n\n", snprintb(buf, sizeof(buf),
236 		(unsigned) mp->msgflags, FBITS));
237     printf ("lowmsg=%d hghmsg=%d nummsg=%d curmsg=%d\n",
238 	mp->lowmsg, mp->hghmsg, mp->nummsg, mp->curmsg);
239     printf ("lowsel=%d hghsel=%d numsel=%d\n",
240 	mp->lowsel, mp->hghsel, mp->numsel);
241     printf ("lowoff=%d hghoff=%d\n\n", mp->lowoff, mp->hghoff);
242 }
243 
244 
245 /*
246  * Print debugging info about all the SELECTED
247  * messages and the sequences they are in.
248  * Due to limitations of snprintb(), only a limited
249  * number of sequences will be printed.  See the
250  * comments in sbr/seq_bits.c.
251  */
252 static void
seq_printdebug(struct msgs * mp)253 seq_printdebug (struct msgs *mp)
254 {
255     int msgnum;
256     char buf[BUFSIZ];
257 
258     putchar('\n');
259     for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
260 	if (is_selected (mp, msgnum))
261 	    printf ("%*d: %s\n", DMAXFOLDER, msgnum,
262 		    snprintb (buf, sizeof buf,
263 			      (unsigned) bvector_first_bits (msgstat (mp, msgnum)),
264 			      seq_bits (mp)));
265     }
266 }
267