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