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 #include "mail.h"
18 
19 #if !HAVE_DECL_ENVIRON
20 extern char **environ;
21 #endif
22 
23 /*
24  * ec[ho] string ...
25  */
26 
27 static int
echo_runcmd(char ** ret,const char * str,size_t len,char ** argv,void * closure)28 echo_runcmd (char **ret, const char *str, size_t len, char **argv, void *closure)
29 {
30   int rc;
31   mu_stream_t ps;
32   mu_stream_t outs;
33   size_t i;
34   int status = MU_WRDSE_OK;
35   char buf[128];
36   size_t n;
37 
38   *ret = NULL;
39   for (i = 0; argv[i]; i++)
40     ;
41   rc = mu_prog_stream_create (&ps, argv[0], i, argv, 0, NULL, MU_STREAM_READ);
42   if (rc)
43     {
44       mu_error (_("Can't run %s: %s"), argv[0], mu_strerror (rc));
45       return MU_WRDSE_USERERR;
46     }
47 
48   rc = mu_memory_stream_create (&outs, MU_STREAM_RDWR);
49   if (rc)
50     {
51       mu_diag_funcall (MU_DIAG_ERROR, "mu_memory_stream_create", NULL, rc);
52       mu_stream_destroy (&ps);
53       return MU_WRDSE_USERERR;
54     }
55 
56   while ((rc = mu_stream_read (ps, buf, sizeof (buf), &n)) == 0 && n > 0)
57     {
58       int wn = mu_stream_write (outs, buf, n, NULL);
59       if (wn)
60 	{
61 	  mu_error (_("error writing to temporary stream: %s"),
62 		    mu_strerror (wn));
63 	  status = MU_WRDSE_USERERR;
64 	  break;
65 	}
66     }
67 
68   if (status == MU_WRDSE_OK && rc)
69     {
70       mu_error (_("error reading %s output: %s"), argv[0], mu_strerror (rc));
71       status = MU_WRDSE_USERERR;
72     }
73 
74   mu_stream_destroy (&ps);
75 
76   if (status == MU_WRDSE_OK)
77     {
78       mu_off_t size;
79       char *p;
80 
81       mu_stream_size (outs, &size);
82       p = malloc (size + 1);
83       if (p)
84 	{
85 	  mu_stream_seek (outs, 0, MU_SEEK_SET, NULL);
86 	  rc = mu_stream_read (outs, p, size, NULL);
87 	  if (rc == 0)
88 	    {
89 	      p[size] = 0;
90 	      *ret = p;
91 	    }
92 	  else
93 	    {
94 	      free (p);
95 	      mu_error (_("error reading from temporary stream: %s"),
96 			mu_strerror (rc));
97 	      status = MU_WRDSE_USERERR;
98 	    }
99 	}
100       else
101 	status = MU_WRDSE_NOSPACE;
102     }
103 
104   mu_stream_destroy (&outs);
105 
106   return status;
107 }
108 
109 static int
echo(char * s,int * nl)110 echo (char *s, int *nl)
111 {
112   int rc;
113   struct mu_wordsplit ws;
114   int wsflags = MU_WRDSF_NOSPLIT | MU_WRDSF_QUOTE | MU_WRDSF_ENV;
115   size_t len;
116 
117   ws.ws_env = (const char **) environ;
118   ws.ws_command = echo_runcmd;
119 
120   rc = mu_wordsplit (s, &ws, wsflags);
121   switch (rc)
122     {
123     case MU_WRDSE_OK:
124       break;
125 
126     case MU_WRDSE_USERERR:
127       /* error message already displayed */
128       mu_wordsplit_free (&ws);
129       return 1;
130 
131     default:
132       mu_error ("%s", mu_wordsplit_strerror (&ws));
133       mu_wordsplit_free (&ws);
134       return 1;
135     }
136 
137   len = strlen (ws.ws_wordv[0]);
138   mu_stream_write (mu_strout, ws.ws_wordv[0], len, NULL);
139   *nl = len > 0 && ws.ws_wordv[0][len-1] == '\n';
140   mu_wordsplit_free (&ws);
141   return 0;
142 }
143 
144 int
mail_echo(int argc,char ** argv)145 mail_echo (int argc, char **argv)
146 {
147   if (argc > 1)
148     {
149       int i;
150       int nl = 0;
151       for (i = 1; i < argc; i++)
152 	{
153 	  if (i > 1)
154 	    mu_printf (" ");
155 	  if (echo (argv[i], &nl))
156 	    break;
157 	}
158       if (!nl)
159 	mu_printf ("\n");
160     }
161   return 0;
162 }
163