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 static void
expand_bang(char ** pbuf,const char * arg,const char * last)20 expand_bang (char **pbuf, const char *arg, const char *last)
21 {
22 char *tmp, *q;
23 const char *p;
24 size_t count = 0;
25
26 for (p = arg; *p; p++)
27 if (*p == '!')
28 count++;
29
30 if (count == 0)
31 {
32 *pbuf = mu_strdup (arg);
33 return;
34 }
35
36 if (!last)
37 {
38 mu_error (_("No previous command"));
39 return;
40 }
41
42 tmp = mu_alloc (strlen (arg) + count * (strlen (last) - 1) + 1);
43 for (p = arg, q = tmp; *p; )
44 {
45 if (*p == '!')
46 {
47 strcpy (q, last);
48 q += strlen (q);
49 p++;
50 }
51 else
52 *q++ = *p++;
53 }
54 *q = 0;
55
56 free (*pbuf);
57 *pbuf = tmp;
58 }
59
60 int
mail_execute(int shell,char * progname,int argc,char ** argv)61 mail_execute (int shell, char *progname, int argc, char **argv)
62 {
63 int xargc, i, status, rc;
64 char **xargv;
65 char *buf;
66 int expanded; /* Indicates whether argv has been bang-expanded */
67
68 if (argc == 0)
69 {
70 /* No arguments mean execute a copy of the user shell */
71 shell = 1;
72 }
73
74 xargc = argc;
75 if (shell && argc < 3)
76 xargc = 3;
77 xargv = mu_calloc (xargc + 1, sizeof (xargv[0]));
78
79 /* Expand arguments if required */
80 if (mailvar_is_true (mailvar_name_bang))
81 {
82 int i;
83 char *last = NULL;
84
85 mailvar_get (&last, mailvar_name_gnu_last_command,
86 mailvar_type_string, 0);
87 expand_bang (xargv, progname, last);
88 for (i = 1; i < argc; i++)
89 expand_bang (xargv + i, argv[i], last);
90 expanded = 1;
91 }
92 else
93 {
94 if (argc)
95 xargv[0] = progname;
96 for (i = 1; i < argc; i++)
97 xargv[i] = argv[i];
98 expanded = 0;
99 }
100
101 /* Reconstruct the command line and save it to gnu-last-command variable.
102 Important: use argc (not xargc)!
103 */
104 mu_argcv_string (argc, xargv, &buf);
105 mailvar_set (mailvar_name_gnu_last_command, buf, mailvar_type_string,
106 MOPTF_QUIET | MOPTF_OVERWRITE);
107
108 if (shell)
109 {
110 if (expanded)
111 {
112 for (i = 0; i < argc; i++)
113 free (xargv[i]);
114 expanded = 0;
115 }
116
117 xargv[0] = getenv ("SHELL");
118 if (argc == 0)
119 {
120 xargv[1] = NULL;
121 xargc = 1;
122 }
123 else
124 {
125 xargv[1] = "-c";
126 xargv[2] = buf;
127 xargv[3] = NULL;
128 xargc = 3;
129 }
130 }
131
132 rc = mu_spawnvp (xargv[0], xargv, &status);
133 if (rc)
134 {
135 mu_diag_funcall (MU_DIAG_ERROR, "mu_spawnvp", xargv[0], rc);
136 }
137 /* FIXME:
138 else if (status)
139 mu_diag_output (MU_DIAG_NOTICE, ....
140 */
141 free (buf);
142 if (expanded)
143 for (i = 0; i < argc; i++)
144 free (xargv[i]);
145 free (xargv);
146 return rc;
147 }
148
149 /*
150 * sh[ell] [command] -- GNU extension
151 * ![command] -- GNU extension
152 */
153
154 int
mail_shell(int argc,char ** argv)155 mail_shell (int argc, char **argv)
156 {
157 if (argv[0][0] == '!' && strlen (argv[0]) > 1)
158 return mail_execute (1, argv[0] + 1, argc, argv);
159 else if (argc > 1)
160 return mail_execute (0, argv[1], argc-1, argv+1);
161 else
162 return mail_execute (1, NULL, 0, NULL);
163 return 1;
164 }
165
166
167