1 /* GNU Mailutils -- a suite of utilities for electronic mail
2    Copyright (C) 2010-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 #if defined(HAVE_CONFIG_H)
18 # include <config.h>
19 #endif
20 #include <stdlib.h>
21 #include <string.h>
22 #include <mailutils/mailutils.h>
23 #include "mu.h"
24 
25 char filter_docstring[] = N_("apply a chain of filters to the input");
26 static char filter_args_doc[] = N_("[~]NAME [ARGS] [+ [~]NAME [ARGS]...]");
27 
28 static int filter_mode = MU_FILTER_ENCODE;
29 static int newline_option = 0;
30 static int list_option;
31 
32 static void
set_encode_mode(struct mu_parseopt * po,struct mu_option * opt,char const * arg)33 set_encode_mode (struct mu_parseopt *po, struct mu_option *opt,
34 		 char const *arg)
35 {
36   filter_mode = MU_FILTER_ENCODE;
37 }
38 
39 static void
set_decode_mode(struct mu_parseopt * po,struct mu_option * opt,char const * arg)40 set_decode_mode (struct mu_parseopt *po, struct mu_option *opt,
41 		 char const *arg)
42 {
43   filter_mode = MU_FILTER_DECODE;
44 }
45 
46 static struct mu_option filter_options[] = {
47   { "encode", 'e', NULL, MU_OPTION_DEFAULT,
48     N_("encode the input (default)"),
49     mu_c_string, NULL, set_encode_mode },
50   { "decode", 'd', NULL, MU_OPTION_DEFAULT,
51     N_("decode the input"),
52     mu_c_string, NULL, set_decode_mode },
53   { "newline", 'n', NULL, MU_OPTION_DEFAULT,
54     N_("print additional newline"),
55     mu_c_bool, &newline_option },
56   { "list", 'L', NULL, MU_OPTION_DEFAULT,
57     N_("list supported filters"),
58     mu_c_bool, &list_option },
59   MU_OPTION_END
60 };
61 
62 static int
filter_printer(void * item,void * data)63 filter_printer (void *item, void *data)
64 {
65   mu_filter_record_t rec = item;
66   printf ("%s\n", rec->name);
67   return 0;
68 }
69 
70 static int
list_filters(void)71 list_filters (void)
72 {
73   mu_list_t list;
74   int rc = mu_filter_get_list (&list);
75 
76   if (rc)
77     {
78       mu_diag_funcall (MU_DIAG_ERROR, "mu_filter_get_list", NULL, rc);
79       return 1;
80     }
81   return mu_list_foreach (list, filter_printer, NULL);
82 }
83 
84 static int
negate_filter_mode(int mode)85 negate_filter_mode (int mode)
86 {
87   if (mode == MU_FILTER_DECODE)
88     return MU_FILTER_ENCODE;
89   else if (mode == MU_FILTER_ENCODE)
90     return MU_FILTER_DECODE;
91   abort ();
92 }
93 
94 int
main(int argc,char ** argv)95 main (int argc, char **argv)
96 {
97   int rc;
98   mu_stream_t flt, prev_stream;
99   const char *fltname;
100   int mode;
101 
102   mu_action_getopt (&argc, &argv, filter_options, filter_docstring,
103 		    filter_args_doc);
104 
105   if (list_option)
106     {
107       if (argc)
108 	{
109 	  mu_error (_("excess arguments"));
110 	  return 1;
111 	}
112       return list_filters ();
113     }
114 
115   if (argc == 0)
116     {
117       mu_error (_("what filter do you want?"));
118       return 1;
119     }
120 
121   prev_stream = mu_strin;
122   mu_stream_ref (mu_strin);
123   do
124     {
125       int i;
126 
127       fltname = argv[0];
128       if (fltname[0] == '~')
129 	{
130 	  mode = negate_filter_mode (filter_mode);
131 	  fltname++;
132 	}
133       else
134 	mode = filter_mode;
135 
136       for (i = 1; i < argc; i++)
137 	if (strcmp (argv[i], "+") == 0)
138 	  break;
139 
140       rc = mu_filter_create_args (&flt, prev_stream, fltname,
141 				  i, (const char **)argv,
142 				  mode, MU_STREAM_READ);
143       mu_stream_unref (prev_stream);
144       if (rc)
145 	{
146 	  mu_error (_("cannot open filter stream: %s"), mu_strerror (rc));
147 	  return 1;
148 	}
149       prev_stream = flt;
150       argc -= i;
151       argv += i;
152       if (argc)
153 	{
154 	  argc--;
155 	  argv++;
156 	}
157     }
158   while (argc);
159 
160   rc = mu_stream_copy (mu_strout, flt, 0, NULL);
161 
162   if (rc)
163     {
164       mu_error ("%s", mu_strerror (rc));
165       return 1;
166     }
167 
168   if (newline_option)
169     mu_stream_write (mu_strout, "\n", 1, NULL);
170 
171   mu_stream_destroy (&flt);
172   mu_stream_flush (mu_strout);
173 
174   return 0;
175 }
176