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