1 /* GNU Mailutils -- a suite of utilities for electronic mail
2    Copyright (C) 2011-2021 Free Software Foundation, Inc.
3 
4    GNU Mailutils is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3, or (at your option)
7    any later version.
8 
9    GNU Mailutils is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with GNU Mailutils.  If not, see <http://www.gnu.org/licenses/>. */
16 
17 #include <config.h>
18 #include <stdlib.h>
19 #include <mailutils/mailutils.h>
20 
21 mu_msgset_format_t format = mu_msgset_fmt_imap;
22 
23 static void
parse_msgrange(char const * arg,struct mu_msgrange * range)24 parse_msgrange (char const *arg, struct mu_msgrange *range)
25 {
26   size_t msgnum;
27   char *p;
28 
29   errno = 0;
30   msgnum = strtoul (arg, &p, 10);
31   range->msg_beg = msgnum;
32   if (*p == ':')
33     {
34       if (*++p == '*')
35 	msgnum = 0;
36       else
37 	{
38 	  msgnum = strtoul (p, &p, 10);
39 	  if (*p)
40 	    {
41 	      mu_error ("error in message range near %s", p);
42 	      exit (1);
43 	    }
44 	}
45     }
46   else if (*p == '*')
47     msgnum = 0;
48   else if (*p)
49     {
50       mu_error ("error in message range near %s", p);
51       exit (1);
52     }
53 
54   range->msg_end = msgnum;
55 }
56 
57 mu_msgset_t
parse_msgset(const char * arg)58 parse_msgset (const char *arg)
59 {
60   int rc;
61   mu_msgset_t msgset;
62   char *end;
63 
64   MU_ASSERT (mu_msgset_create (&msgset, NULL, MU_MSGSET_NUM));
65   if (arg)
66     {
67       rc = mu_msgset_parse_imap (msgset, MU_MSGSET_NUM, arg, &end);
68       if (rc)
69 	{
70 	  mu_error ("mu_msgset_parse_imap: %s near %s",
71 		    mu_strerror (rc), end);
72 	  exit (1);
73 	}
74     }
75   return msgset;
76 }
77 
78 static void
print_all(mu_msgset_t msgset)79 print_all (mu_msgset_t msgset)
80 {
81   MU_ASSERT (mu_stream_msgset_format (mu_strout, format, msgset));
82   mu_printf ("\n");
83 }
84 
85 static void
print_first(mu_msgset_t msgset)86 print_first (mu_msgset_t msgset)
87 {
88   size_t n;
89   MU_ASSERT (mu_msgset_first (msgset, &n));
90   printf ("%zu\n", n);
91 }
92 
93 static void
print_last(mu_msgset_t msgset)94 print_last (mu_msgset_t msgset)
95 {
96   size_t n;
97   MU_ASSERT (mu_msgset_last (msgset, &n));
98   printf ("%zu\n", n);
99 }
100 
101 static void
cli_msgset(struct mu_parseopt * po,struct mu_option * opt,char const * arg)102 cli_msgset (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
103 {
104   mu_msgset_t *msgset = opt->opt_ptr;
105   if (*msgset)
106     {
107       mu_parseopt_error (po, "message set already defined");
108       exit (po->po_exit_error);
109     }
110   *msgset = parse_msgset (arg);
111 }
112 
113 static void
cli_mh(struct mu_parseopt * po,struct mu_option * opt,char const * arg)114 cli_mh (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
115 {
116   format = mu_msgset_fmt_mh;
117 }
118 
119 static mu_msgset_t
get_msgset(struct mu_option * opt)120 get_msgset (struct mu_option *opt)
121 {
122   mu_msgset_t *msgset = opt->opt_ptr;
123   if (!*msgset)
124     {
125       *msgset = parse_msgset (NULL);
126     }
127   return *msgset;
128 }
129 
130 static void
cli_add(struct mu_parseopt * po,struct mu_option * opt,char const * arg)131 cli_add (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
132 {
133   struct mu_msgrange range;
134   parse_msgrange (arg, &range);
135   MU_ASSERT (mu_msgset_add_range (get_msgset (opt), range.msg_beg,
136 				  range.msg_end, MU_MSGSET_NUM));
137 }
138 
139 static void
cli_sub(struct mu_parseopt * po,struct mu_option * opt,char const * arg)140 cli_sub (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
141 {
142   struct mu_msgrange range;
143   parse_msgrange (arg, &range);
144   MU_ASSERT (mu_msgset_sub_range (get_msgset (opt), range.msg_beg,
145 				  range.msg_end, MU_MSGSET_NUM));
146 }
147 
148 static void
cli_addset(struct mu_parseopt * po,struct mu_option * opt,char const * arg)149 cli_addset (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
150 {
151   mu_msgset_t tset = parse_msgset (arg);
152   MU_ASSERT (mu_msgset_add (get_msgset (opt), tset));
153   mu_msgset_free (tset);
154 }
155 
156 static void
cli_subset(struct mu_parseopt * po,struct mu_option * opt,char const * arg)157 cli_subset (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
158 {
159   mu_msgset_t tset = parse_msgset (arg);
160   MU_ASSERT (mu_msgset_sub (get_msgset (opt), tset));
161   mu_msgset_free (tset);
162 }
163 
164 static void
cli_first(struct mu_parseopt * po,struct mu_option * opt,char const * arg)165 cli_first (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
166 {
167   void (**print) (mu_msgset_t) = opt->opt_ptr;
168   *print = print_first;
169 }
170 
171 static void
cli_last(struct mu_parseopt * po,struct mu_option * opt,char const * arg)172 cli_last (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
173 {
174   void (**print) (mu_msgset_t) = opt->opt_ptr;
175   *print = print_last;
176 }
177 
178 int
main(int argc,char ** argv)179 main (int argc, char **argv)
180 {
181   mu_msgset_t msgset = NULL;
182   void (*print) (mu_msgset_t) = print_all;
183 
184   struct mu_option options[] = {
185     { "mh", 0, NULL, MU_OPTION_DEFAULT,
186       "use MH message set format for output", mu_c_incr, NULL, cli_mh },
187     { "msgset", 0, "SET", MU_OPTION_DEFAULT,
188       "define message set", mu_c_string, &msgset, cli_msgset },
189     { "add", 0, "X[:Y]", MU_OPTION_DEFAULT,
190       "add range to message set", mu_c_string, &msgset, cli_add },
191     { "sub", 0, "X[:Y]", MU_OPTION_DEFAULT,
192       "subtract range from message set", mu_c_string, &msgset, cli_sub },
193     { "addset", 0, "SET", MU_OPTION_DEFAULT,
194       "add message set to message set", mu_c_string, &msgset, cli_addset },
195     { "subset", 0, "SET", MU_OPTION_DEFAULT,
196       "subtract message set from message set", mu_c_string, &msgset,
197       cli_subset },
198     { "first", 0, NULL, MU_OPTION_DEFAULT,
199       "print only first element from the resulting set",
200       mu_c_string, &print, cli_first },
201     { "last", 0, NULL, MU_OPTION_DEFAULT,
202       "print only last element from the resulting set",
203       mu_c_string, &print, cli_last },
204     MU_OPTION_END
205   };
206 
207   mu_set_program_name (argv[0]);
208   mu_cli_simple (argc, argv,
209 		 MU_CLI_OPTION_OPTIONS, options,
210 		 MU_CLI_OPTION_SINGLE_DASH,
211 		 MU_CLI_OPTION_PROG_DOC, "message set parser test utility",
212 		 MU_CLI_OPTION_END);
213 
214   if (!msgset)
215     {
216       mu_error ("nothing to do; try %s -help for assistance", mu_program_name);
217       exit (1);
218     }
219 
220   print (msgset);
221   mu_msgset_free (msgset);
222 
223   return 0;
224 }
225 
226 
227 
228 
229