send: read reply-to header
[mailx.git] / send.c
blob35282eabd26051a94d729450890169356bf73645
1 #include <ctype.h>
2 #include <fcntl.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <time.h>
6 #include <unistd.h>
7 #include <sys/stat.h>
8 #include <sys/types.h>
9 #include "config.h"
10 #include "mbox.h"
11 #include "util.h"
12 #include "send.h"
13 #include "str.h"
15 #define USERAGENT "git://repo.or.cz/mailx.git"
16 #define MAXLINE (1 << 7)
18 static int isaddr(int c)
20 return isalpha(c) || isdigit(c) || strchr("_.-@", c);
23 static char *cut_addr(char *dst, char *src)
25 while (*src && !isaddr(*src))
26 src++;
27 while (isaddr(*src))
28 *dst++ = *src++;
29 *dst++ = '\0';
30 return src;
33 static int parse_addr(char **recips, int size, char *s, int len)
35 int n = 0;
36 char *d = s + len;
37 while (n < size && s < d && *(s = cut_addr(recips[n], s)))
38 if (strchr(recips[n], '@'))
39 n++;
40 return n;
43 static int mail_recips(char **recips, int size, char *s, char *e)
45 struct mail mail = {{0}};
46 char *to, *cc;
47 int n = 0;
48 mail_read(&mail, s, e);
49 if ((to = mail_hdr(&mail, "To:")))
50 n += parse_addr(recips + n, size - n, to + 3, hdr_len(to) - 3);
51 if ((cc = mail_hdr(&mail, "CC:")))
52 n += parse_addr(recips + n, size - n, cc + 3, hdr_len(cc) - 3);
53 return n;
56 static char *put_from_(char *s)
58 time_t t;
59 char *logname = getenv("LOGNAME");
60 time(&t);
61 s = put_str(s, "From ");
62 s = put_str(s, logname ? logname : "me");
63 s += strftime(s, MAXLINE, " %a %b %d %H:%M:%S %Y\n", localtime(&t));
64 return s;
67 static char *put_date(char *s)
69 time_t t;
70 time(&t);
71 s = put_str(s, "Date: ");
72 s += strftime(s, MAXLINE, "%a, %d %b %Y %H:%M:%S %z\n", localtime(&t));
73 return s;
76 static char *put_id(char *s)
78 time_t t;
79 time(&t);
80 s = put_str(s, "Message-ID: <");
81 s += strftime(s, MAXLINE, "%Y%d%m%H%M%S", localtime(&t));
82 s = put_str(s, "@" HOSTNAME ">\n");
83 return s;
86 static char *put_from(char *s)
88 return FROM ? put_str(s, "From: " FROM "\n") : s;
91 static char *put_to(char *s, char **to, int n)
93 int i;
94 s = put_str(s, "To: ");
95 s = put_str(s, to[0]);
96 for (i = 1; i < n; i++) {
97 s = put_str(s, ",\n\t");
98 s = put_str(s, to[i]);
100 if (*(s - 1) != '\n')
101 s = put_str(s, "\n");
102 return s;
105 static char *put_subj(char *s, char *subj)
107 s = put_str(s, "Subject: ");
108 s = put_str(s, subj);
109 s = put_str(s, "\n");
110 return s;
113 static char *put_agent(char *s)
115 return put_str(s, "User-Agent: " USERAGENT "\n");
118 void draft_init(struct draft *draft, char **to, int nto, char *subj)
120 char *s = draft->mail;
121 s = put_from_(s);
122 s = put_date(s);
123 s = put_from(s);
124 if (to && nto)
125 s = put_to(s, to, nto);
126 if (subj)
127 s = put_subj(s, subj);
128 s = put_id(s);
129 s = put_agent(s);
130 draft->len = s - draft->mail;
133 static char *hdr_val(char *hdr)
135 hdr = strchr(hdr, ':') + 1;
136 while (isspace(*hdr))
137 hdr++;
138 return hdr;
141 static char *put_hdr(char *s, char *hdr)
143 char *r = hdr_val(hdr);
144 return put_mem(s, r, hdr_len(r));
147 static char *put_hdr_append(char *s, char *hdr)
149 char *r = hdr_val(hdr);
150 while (strchr(" \r\n", s[-1]))
151 s--;
152 s = put_str(s, s[-1] == ':' ? " " : ",\n\t");
153 return put_mem(s, r, hdr_len(r));
156 static char *put_replysubj(char *s, char *subj)
158 subj = hdr_val(subj);
159 s = put_str(s, "Subject: ");
160 if (tolower(subj[0]) != 'r' || tolower(subj[1]) != 'e')
161 s = put_str(s, "Re: ");
162 s = put_mem(s, subj, hdr_len(subj));
163 return s;
166 static char *put_replyto(char *s, char *id, char *ref)
168 s = put_str(s, "In-Reply-To: ");
169 id = hdr_val(id);
170 s = put_mem(s, id, hdr_len(id));
171 s = put_str(s, "References: ");
172 if (ref) {
173 ref = hdr_val(ref);
174 s = put_mem(s, ref, hdr_len(ref));
175 s = put_str(s, "\t");
177 s = put_mem(s, id, hdr_len(id));
178 return s;
181 static char *put_reply(char *s, char *from, char *to, char *cc, char *rply)
183 if (from || rply) {
184 s = put_str(s, "To: ");
185 s = put_hdr(s, rply ? rply : from);
187 if (to || cc || (rply && from)) {
188 s = put_str(s, "Cc: ");
189 if (to)
190 s = put_hdr_append(s, to);
191 if (rply && from)
192 s = put_hdr_append(s, from);
193 if (cc)
194 s = put_hdr_append(s, cc);
196 return s;
199 static char *quote_body(char *s, int size, struct mail *mail)
201 char *from = mail_hdr(mail, "From:");
202 char *r = mail->body;
203 char *rd = r + mail->body_len;
204 char *sd = s + size - 16;
205 s = put_str(s, "\n");
206 if (from) {
207 from = hdr_val(from);
208 s = put_mem(s, from, hdr_len(from) - 1);
209 s = put_str(s, " wrote:\n");
211 while (s < sd && r < rd) {
212 char *nl = memchr(r, '\n', rd - r);
213 s = put_str(s, "> ");
214 nl = nl ? nl + 1 : rd;
215 s = put_mem(s, r, MIN(sd - s, nl - r));
216 r = nl;
218 *s = '\0';
219 return s;
222 void draft_reply(struct draft *draft, struct mail *mail)
224 char *s = draft->mail;
225 char *id_hdr = mail_hdr(mail, "Message-ID:");
226 char *ref_hdr = mail_hdr(mail, "References:");
227 char *from_hdr = mail_hdr(mail, "From:");
228 char *subj_hdr = mail_hdr(mail, "Subject:");
229 char *to_hdr = mail_hdr(mail, "To:");
230 char *cc_hdr = mail_hdr(mail, "CC:");
231 char *rply_hdr = mail_hdr(mail, "Reply-To:");
233 s = put_from_(s);
234 s = put_date(s);
235 s = put_from(s);
236 s = put_reply(s, from_hdr, to_hdr, cc_hdr, rply_hdr);
237 if (subj_hdr)
238 s = put_replysubj(s, subj_hdr);
239 s = put_id(s);
240 if (id_hdr)
241 s = put_replyto(s, id_hdr, ref_hdr);
242 s = put_agent(s);
243 s = quote_body(s, sizeof(draft->mail) - (s - draft->mail), mail);
244 draft->len = s - draft->mail;
247 void draft_edit(struct draft *draft, char *editor)
249 char *edit_argv[] = {NULL, DRAFT, NULL};
250 int fd;
251 if ((fd = open(DRAFT, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) == -1)
252 return;
253 xwrite(fd, draft->mail, draft->len);
254 close(fd);
255 edit_argv[0] = editor;
256 exec_file(editor, edit_argv);
257 if ((fd = open(DRAFT, O_RDONLY)) == -1)
258 return;
259 draft->len = xread(fd, draft->mail, sizeof(draft->mail) - 1);
260 close(fd);
261 draft->mail[draft->len] = '\0';
262 unlink(DRAFT);
265 void draft_send(struct draft *draft)
267 char recips[MAXRECP][MAXLINE];
268 char *send_argv[MAXRECP + 3] = {SENDMAIL, "-i"};
269 char *beg = strchr(draft->mail, '\n') + 1;
270 char *end = draft->mail + draft->len;
271 int nrecips;
272 int i;
273 for (i = 0; i < MAXRECP; i++)
274 send_argv[i + 2] = recips[i];
275 nrecips = mail_recips(send_argv + 2, MAXRECP,
276 draft->mail, draft->mail + draft->len);
277 send_argv[2 + nrecips] = NULL;
278 exec_pipe(SENDMAIL, send_argv, beg, end - beg);
281 static void write_nofrom(int fd, char *s, int len)
283 char *beg = s;
284 char *d = s + len;
285 char *r;
286 while (s < d) {
287 if (!strncmp("\nFrom ", s, 6)) {
288 write(fd, beg, s - beg + 1);
289 write(fd, ">", 1);
290 beg = s + 1;
292 r = strchr(s + 1, '\n');
293 s = r ? r : d;
295 write(fd, beg, s - beg);
298 void draft_save(struct draft *draft, char *path)
300 int fd = open(path, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
301 if (fd < -1)
302 return;
303 write_nofrom(fd, draft->mail, draft->len);
304 write(fd, "\n", 1);
305 close(fd);