1 /* GNU Mailutils -- a suite of utilities for electronic mail
2    Copyright (C) 1999-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 /* MH scan command */
18 
19 #include <mh.h>
20 #ifdef HAVE_TERMCAP_H
21 # include <termcap.h>
22 #endif
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <time.h>
26 #include <mailutils/observer.h>
27 
28 static char prog_doc[] = N_("Produce a one line per message scan listing");
29 static char args_doc[] = N_("[MSGLIST]");
30 
31 static int clear;
32 
33 static int width;
34 static int reverse;
35 static int header;
36 
37 static mh_format_t format;
38 static mh_fvm_t fvm;
39 static mu_msgset_t msgset;
40 
41 static struct mu_option options[] = {
42   { "clear",   0, NULL, MU_OPTION_DEFAULT,
43     N_("clear screen after displaying the list"),
44     mu_c_bool, &clear },
45   { "form",    0, N_("FILE"),   MU_OPTION_DEFAULT,
46     N_("read format from given file"),
47     mu_c_string, &format, mh_opt_parse_formfile },
48   { "format",  0, N_("FORMAT"), MU_OPTION_DEFAULT,
49     N_("use this format string"),
50     mu_c_string, &format, mh_opt_parse_format },
51   { "header",  0, NULL,   MU_OPTION_DEFAULT,
52     N_("display header"),
53     mu_c_bool, &header },
54   { "width",   0, N_("NUMBER"), MU_OPTION_DEFAULT,
55     N_("set output width"),
56     mu_c_int, &width },
57   { "reverse",  0, NULL,   MU_OPTION_DEFAULT,
58     N_("list messages in reverse order"),
59     mu_c_bool, &reverse },
60   { "file",     0, N_("FILE"),   MU_OPTION_HIDDEN,
61     N_("[not yet implemented]"),
62     mu_c_string, NULL, mh_opt_notimpl },
63   MU_OPTION_END
64 };
65 
66 static void print_header (mu_mailbox_t mbox);
67 static void clear_screen (void);
68 
69 static int
list_message(size_t num MU_ARG_UNUSED,mu_message_t msg,void * data MU_ARG_UNUSED)70 list_message (size_t num MU_ARG_UNUSED, mu_message_t msg,
71 	      void *data MU_ARG_UNUSED)
72 {
73   mh_fvm_run (fvm, msg);
74   return 0;
75 }
76 
77 /* Observable Action this is called at every message discover.  */
78 static int
action(mu_observer_t o,size_t type,void * data,void * action_data)79 action (mu_observer_t o, size_t type, void *data, void *action_data)
80 {
81   static int counter;
82   mu_mailbox_t mbox;
83   mu_message_t msg = NULL;
84 
85   if (type == MU_EVT_MESSAGE_ADD)
86     {
87       mbox = mu_observer_get_owner (o);
88       counter++;
89       mu_mailbox_get_message (mbox, counter, &msg);
90       mh_fvm_run (fvm, msg);
91     }
92   return 0;
93 }
94 
95 int
main(int argc,char ** argv)96 main (int argc, char **argv)
97 {
98   mu_mailbox_t mbox;
99   int status;
100   size_t total = 0;
101 
102   mh_getopt (&argc, &argv, options, MH_GETOPT_DEFAULT_FOLDER,
103 	     args_doc, prog_doc, NULL);
104   if (!format)
105     format = mh_scan_format ();
106 
107   mh_fvm_create (&fvm, MH_FMT_FORCENL);
108   mh_fvm_set_format (fvm, format);
109   mh_fvm_set_width (fvm, width ? width : mh_width ());
110   mh_format_destroy (&format);
111 
112   mbox = mh_open_folder (mh_current_folder (), MU_STREAM_READ);
113 
114   if ((argc == 0 || strcmp (argv[0], "all") == 0) && !reverse)
115     {
116       /* Fast approach */
117       mu_observer_t observer;
118       mu_observable_t observable;
119 
120       print_header (mbox);
121 
122       mu_observer_create (&observer, mbox);
123       mu_observer_set_action (observer, action, mbox);
124       mu_mailbox_get_observable (mbox, &observable);
125       mu_observable_attach (observable, MU_EVT_MESSAGE_ADD, observer);
126 
127       status = mu_mailbox_scan (mbox, 1, &total);
128     }
129   else
130     {
131       mu_mailbox_messages_count (mbox, &total);
132       mh_msgset_parse (&msgset, mbox, argc, argv, "all");
133 
134       print_header (mbox);
135       status = mu_msgset_foreach_dir_message (msgset, reverse,
136 					      list_message, NULL);
137     }
138 
139   if (total == 0)
140     {
141       mu_url_t url = NULL;
142 
143       mu_mailbox_get_url (mbox, &url);
144       mu_error (_("no messages in %s"), mu_url_to_string (url));
145     }
146 
147   clear_screen ();
148   mh_fvm_destroy (&fvm);
149 
150   mh_global_save_state ();
151   mu_mailbox_close (mbox);
152   mu_mailbox_destroy (&mbox);
153 
154   return status;
155 }
156 
157 static void
print_header(mu_mailbox_t mbox)158 print_header (mu_mailbox_t mbox)
159 {
160   if (header)
161     {
162       mu_url_t url = NULL;
163       char datestr[64];
164       time_t t;
165 
166       mu_mailbox_get_url (mbox, &url);
167       time (&t);
168       strftime (datestr, sizeof datestr, "%c", localtime (&t));
169       printf (_("Folder %s  %s\n"), mu_url_to_string (url), datestr);
170     }
171 }
172 
173 #ifdef HAVE_TERMCAP_H
174 /* A subroutine for tputs */
175 int
putstdout(char c)176 putstdout(char c)
177 {
178   return putc(c, stdout);
179 }
180 #endif
181 
182 static void
clear_screen(void)183 clear_screen (void)
184 {
185   if (clear)
186     {
187 #ifdef HAVE_TERMCAP_H
188       if (isatty (1))
189 	{
190 	  char termcap_buf[1024];
191 	  char *buffer = termcap_buf;
192 	  char *termname;
193 
194 	  if ((termname = getenv("TERM")) == NULL)
195 	    /* No terminal; Try ansi */
196 	    termname = "ansi";
197 
198 	  if (tgetent(termcap_buf, termname) == 1)
199 	    {
200 	      char *clr = tgetstr ("cl", &buffer);
201 	      if (clr)
202 		{
203 		  tputs(clr, 1, (int (*)())putstdout);
204 		  return;
205 		}
206 	    }
207 	}
208 #endif
209       /* Fall back to formfeed */
210       fprintf (stdout, "\f");
211     }
212 }
213