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 void
make_in_reply_to(compose_env_t * env,mu_message_t msg)20 make_in_reply_to (compose_env_t *env, mu_message_t msg)
21 {
22 char *value = NULL;
23
24 mu_rfc2822_in_reply_to (msg, &value);
25 compose_header_set (env, MU_HEADER_IN_REPLY_TO, value,
26 COMPOSE_REPLACE);
27 free (value);
28 }
29
30 void
make_references(compose_env_t * env,mu_message_t msg)31 make_references (compose_env_t *env, mu_message_t msg)
32 {
33 char *value = NULL;
34
35 mu_rfc2822_references (msg, &value);
36 compose_header_set (env, MU_HEADER_REFERENCES, value, COMPOSE_REPLACE);
37 free (value);
38 }
39
40 /*
41 * r[eply] [message]
42 * r[espond] [message]
43 * Reply to all recipients of the message. Save to record.
44 * reply_all = 1, send_to = 0
45 * R[eply] [msglist]
46 * R[espond] [msglist]
47 * Reply to the sender of each message in msglist. Save to record.
48 * reply_all = 0, send_to = 0
49 * fo[llowup] message
50 * Reply to all recipients of the message. Save by name.
51 * reply_all = 1, send_to = 1
52 * F[ollowup] msglist
53 * Reply to the sender of each message in msglist. Save by name.
54 * reply_all = 0, send_to = 1
55 */
56
57 static void
compose_set_address(compose_env_t * env,char const * hname,char const * input)58 compose_set_address (compose_env_t *env, char const *hname, char const *input)
59 {
60 struct mu_address hint = MU_ADDRESS_HINT_INITIALIZER;
61 mu_address_t iaddr, oaddr = NULL, ap;
62 char *result = NULL;
63
64 if (mu_address_create_hint (&iaddr, input, &hint, 0))
65 result = mu_strdup (input);
66 else
67 {
68 for (ap = iaddr; ap; ap = ap->next)
69 {
70 const char *email;
71 if (mu_address_sget_email (ap, 1, &email) || email == NULL)
72 continue;
73 if (!(mailvar_is_true (mailvar_name_metoo) &&
74 mail_is_my_name (email)))
75 mu_address_union (&oaddr, ap);
76 }
77 mu_address_destroy (&iaddr);
78 mu_address_aget_printable (oaddr, &result);
79 mu_address_destroy (&oaddr);
80 }
81 if (result && result[0])
82 {
83 compose_header_set (env, hname, result, COMPOSE_SINGLE_LINE);
84 free (result);
85 }
86 }
87
88 static void
compose_remove_personal(compose_env_t * env,char * hname)89 compose_remove_personal (compose_env_t *env, char *hname)
90 {
91 char const *value;
92
93 value = compose_header_get (env, hname, NULL);
94 if (value)
95 {
96 mu_address_t addr = NULL, ap;
97 struct mu_address hint = MU_ADDRESS_HINT_INITIALIZER;
98 char *result;
99
100 mu_address_create_hint (&addr, value, &hint, 0);
101 for (ap = addr; ap; ap = ap->next)
102 {
103 free (ap->printable);
104 ap->printable = NULL;
105 free (ap->comments);
106 ap->comments = NULL;
107 free (ap->personal);
108 ap->personal = NULL;
109 free (ap->route);
110 ap->route = NULL;
111 }
112 mu_address_aget_printable (addr, &result);
113 compose_header_set (env, hname, result, COMPOSE_REPLACE);
114 free (result);
115 mu_address_destroy (&addr);
116 }
117 }
118
119 /*
120 * r[eply] [message]
121 * r[espond] [message]
122 * fo[llowup] message
123 *
124 * Reply to all recipients of a single message
125 */
126 int
respond_all(int argc,char ** argv,int record_sender)127 respond_all (int argc, char **argv, int record_sender)
128 {
129 int status;
130 compose_env_t env;
131 mu_message_t msg;
132 mu_header_t hdr;
133 char const *str;
134 char *p;
135
136 msgset_t *msgset = NULL;
137
138 if (msgset_parse (argc, argv, MSG_NODELETED, &msgset))
139 return 1;
140
141 if (msgset->next)
142 {
143 mu_error (_("Can't reply to multiple messages at once"));
144 status = 1;
145 }
146 else if (util_get_message (mbox, msgset_msgno (msgset), &msg))
147 {
148 status = 1;
149 }
150 else
151 {
152 set_cursor (msgset_msgno (msgset));
153
154 mu_message_get_header (msg, &hdr);
155
156 compose_init (&env);
157
158 p = util_message_sender (msg, 0);
159 if (p)
160 {
161 compose_set_address (&env, MU_HEADER_TO, p);
162 free (p);
163 }
164
165 /* Add the rest of recipients */
166 if (mu_header_sget_value (hdr, MU_HEADER_TO, &str) == 0)
167 {
168 compose_set_address (&env, MU_HEADER_TO, str);
169 }
170
171 if (mu_header_sget_value (hdr, MU_HEADER_CC, &str) == 0)
172 {
173 compose_set_address (&env, MU_HEADER_CC, str);
174 }
175
176 /* Add header line */
177 //FIXME: decode
178 if (mu_header_aget_value (hdr, MU_HEADER_SUBJECT, &p) == 0)
179 {
180 char *subj = NULL;
181
182 if (mu_unre_subject (p, NULL))
183 util_strcat (&subj, util_reply_prefix ());
184 util_strcat (&subj, p);
185 free (p);
186 compose_header_set (&env, MU_HEADER_SUBJECT, subj, COMPOSE_REPLACE);
187 free (subj);
188 }
189 else
190 compose_header_set (&env, MU_HEADER_SUBJECT, "", COMPOSE_REPLACE);
191
192 if (!mailvar_is_true (mailvar_name_fullnames))
193 {
194 compose_remove_personal (&env, MU_HEADER_TO);
195 compose_remove_personal (&env, MU_HEADER_CC);
196 }
197
198 mu_printf ("To: %s\n", compose_header_get (&env, MU_HEADER_TO, ""));
199 str = compose_header_get (&env, MU_HEADER_CC, NULL);
200 if (str)
201 mu_printf ("Cc: %s\n", str);
202 mu_printf ("Subject: %s\n\n",
203 compose_header_get (&env, MU_HEADER_SUBJECT, ""));
204
205 make_in_reply_to (&env, msg);
206 make_references (&env, msg);
207 status = mail_compose_send (&env, record_sender);
208 compose_destroy (&env);
209 util_mark_read (msg);
210 }
211 msgset_free (msgset);
212
213 return status;
214 }
215
216 /*
217 * R[eply] [msglist]
218 * R[espond] [msglist]
219 * F[ollowup] msglist
220 *
221 * Reply to the sender of each message in msglist.
222 */
223 int
respond_msg(int argc,char ** argv,int record_sender)224 respond_msg (int argc, char **argv, int record_sender)
225 {
226 mu_message_t msg;
227 mu_header_t hdr;
228 compose_env_t env;
229 int status;
230 char *p;
231 char const *str;
232
233 msgset_t *msgset = NULL, *mp;
234
235 if (msgset_parse (argc, argv, MSG_NODELETED, &msgset))
236 return 1;
237
238 if (util_get_message (mbox, msgset_msgno (msgset), &msg))
239 {
240 status = 1;
241 }
242 else
243 {
244 size_t last;
245
246 set_cursor (msgset_msgno (msgset));
247
248 mu_message_get_header (msg, &hdr);
249
250 compose_init (&env);
251
252 for (mp = msgset; mp; mp = mp->next)
253 {
254 mu_message_t mesg;
255 last = msgset_msgno (mp);
256 if (util_get_message (mbox, last, &mesg) == 0)
257 {
258 p = util_message_sender (mesg, 0);
259 if (p)
260 {
261 compose_set_address (&env, MU_HEADER_TO, p);
262 free (p);
263 }
264 util_mark_read (mesg);
265 }
266 }
267
268 /* Add subject header */
269 if (mu_header_aget_value (hdr, MU_HEADER_SUBJECT, &p) == 0)
270 {
271 char *subj = NULL;
272
273 if (mu_unre_subject (p, NULL))
274 util_strcat (&subj, util_reply_prefix ());
275 util_strcat (&subj, p);
276 free (p);
277 compose_header_set (&env, MU_HEADER_SUBJECT, subj, COMPOSE_REPLACE);
278 free (subj);
279 }
280 else
281 compose_header_set (&env, MU_HEADER_SUBJECT, "", COMPOSE_REPLACE);
282
283 if (!mailvar_is_true (mailvar_name_fullnames))
284 {
285 compose_remove_personal (&env, MU_HEADER_TO);
286 compose_remove_personal (&env, MU_HEADER_CC);
287 }
288
289 mu_printf ("To: %s\n", compose_header_get (&env, MU_HEADER_TO, ""));
290 str = compose_header_get (&env, MU_HEADER_CC, NULL);
291 if (str)
292 mu_printf ("Cc: %s\n", str);
293 mu_printf ("Subject: %s\n\n",
294 compose_header_get (&env, MU_HEADER_SUBJECT, ""));
295
296 make_in_reply_to (&env, msg);
297 make_references (&env, msg);
298 status = mail_compose_send (&env, record_sender);
299 compose_destroy (&env);
300
301 set_cursor (last);
302 }
303 msgset_free (msgset);
304
305 return status;
306 }
307
308 int
mail_reply(int argc,char ** argv)309 mail_reply (int argc, char **argv)
310 {
311 int all = mu_islower (argv[0][0]);
312 if (mailvar_is_true (mailvar_name_flipr))
313 all = !all;
314 return (all ? respond_all : respond_msg) (argc, argv, 0);
315 }
316
317 int
mail_followup(int argc,char ** argv)318 mail_followup (int argc, char **argv)
319 {
320 int all = mu_islower (argv[0][0]);
321 return (all ? respond_all : respond_msg) (argc, argv, 1);
322 }
323