send: escape From_ in mail body
[mailx.git] / send.c
blob218181c0c62a1971f0fd8d7def417c592ba423f6
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 "config.h"
9 #include "mbox.h"
10 #include "util.h"
11 #include "send.h"
12 #include "str.h"
14 #define USERAGENT "git://repo.or.cz/mailx.git"
16 static int isaddr(int c)
18 return isalpha(c) || isdigit(c) || strchr("_.-@", c);
21 static char *cut_addr(char *dst, char *src)
23 while (*src && !isaddr(*src))
24 src++;
25 while (isaddr(*src))
26 *dst++ = *src++;
27 *dst++ = '\0';
28 return src;
31 static int parse_addr(char **recips, int size, char *s, int len)
33 int n = 0;
34 char *d = s + len;
35 while (n < size && s < d && *(s = cut_addr(recips[n], s)))
36 if (strchr(recips[n], '@'))
37 n++;
38 return n;
41 static int mail_recips(char **recips, int size, char *s)
43 struct mail mail = {{0}};
44 char *to, *cc;
45 int n = 0;
46 mail_read(&mail, s);
47 if ((to = mail_hdr(&mail, "To:")))
48 n += parse_addr(recips + n, size - n, to + 3, hdr_len(to) - 3);
49 if ((cc = mail_hdr(&mail, "CC:")))
50 n += parse_addr(recips + n, size - n, cc + 3, hdr_len(cc) - 3);
51 return n;
54 static char *put_from_(char *s)
56 time_t t;
57 time(&t);
58 s = put_str(s, "From ");
59 s = put_str(s, getlogin());
60 s += strftime(s, MAXLINE, " %a %b %d %H:%M:%S %Y\n", localtime(&t));
61 return s;
64 static char *put_date(char *s)
66 long tz;
67 time_t t;
68 time(&t);
69 tzset();
70 s = put_str(s, "Date: ");
71 s += strftime(s, MAXLINE, "%a, %d %b %Y %H:%M:%S ", localtime(&t));
72 tz = abs(timezone);
73 *s++ = timezone < 0 ? '-' : '+';
74 s = put_intz(s, tz / 3600, 2);
75 s = put_intz(s, (tz % 3600) / 60, 2);
76 s = put_str(s, "\n");
77 return s;
80 static char *put_id(char *s)
82 time_t t;
83 time(&t);
84 s = put_str(s, "Message-ID: <");
85 s += strftime(s, MAXLINE, "%Y%d%m%H%M%S", localtime(&t));
86 s = put_str(s, "@" HOSTNAME ">\n");
87 return s;
90 static char *put_from(char *s)
92 return FROM ? put_str(s, "From: " FROM "\n") : s;
95 static char *put_to(char *s, char **to, int n)
97 int i;
98 s = put_str(s, "To: ");
99 s = put_str(s, to[0]);
100 for (i = 1; i < n; i++) {
101 s = put_str(s, ",\n\t");
102 s = put_str(s, to[i]);
104 s = put_str(s, "\n");
105 return s;
108 static char *put_subj(char *s, char *subj)
110 s = put_str(s, "Subject: ");
111 s = put_str(s, subj);
112 s = put_str(s, "\n");
113 return s;
116 static char *put_agent(char *s)
118 return put_str(s, "User-Agent: " USERAGENT "\n");
121 void draft_init(struct draft *draft, char **to, int nto, char *subj)
123 char *s = draft->mail;
124 s = put_from_(s);
125 s = put_date(s);
126 s = put_from(s);
127 if (to && nto)
128 s = put_to(s, to, nto);
129 if (subj)
130 s = put_subj(s, subj);
131 s = put_id(s);
132 s = put_agent(s);
133 draft->len = s - draft->mail;
136 static char *hdr_val(char *hdr)
138 hdr = strchr(hdr, ':') + 1;
139 while (isspace(*hdr))
140 hdr++;
141 return hdr;
144 static char *put_replysubj(char *s, char *subj)
146 subj = hdr_val(subj);
147 s = put_str(s, "Subject: ");
148 if (tolower(subj[0]) != 'r' || tolower(subj[1]) != 'e')
149 s = put_str(s, "Re: ");
150 s = put_mem(s, subj, hdr_len(subj));
151 return s;
154 static char *put_replyto(char *s, char *id, char *ref)
156 s = put_str(s, "In-Reply-To: ");
157 id = hdr_val(id);
158 s = put_mem(s, id, hdr_len(id));
159 s = put_str(s, "References: ");
160 if (ref) {
161 ref = hdr_val(ref);
162 s = put_mem(s, ref, hdr_len(ref));
163 s = put_str(s, "\t");
165 s = put_mem(s, id, hdr_len(id));
166 return s;
169 static char *put_reply(char *s, char *from, char *to, char *cc)
171 if (from) {
172 from = hdr_val(from);
173 s = put_str(s, "To: ");
174 s = put_mem(s, from, hdr_len(from));
176 if (to || cc) {
177 s = put_str(s, "Cc: ");
178 if (to) {
179 to = hdr_val(to);
180 s = put_mem(s, to, hdr_len(to));
182 if (cc) {
183 cc = hdr_val(cc);
184 if (to)
185 s = put_str(s, "\t");
186 s = put_mem(s, cc, hdr_len(cc));
189 return s;
192 void draft_reply(struct draft *draft, struct mail *mail)
194 char *s = draft->mail;
195 char *id_hdr = mail_hdr(mail, "Message-ID:");
196 char *ref_hdr = mail_hdr(mail, "References:");
197 char *from_hdr = mail_hdr(mail, "From:");
198 char *subj_hdr = mail_hdr(mail, "Subject:");
199 char *to_hdr = mail_hdr(mail, "To:");
200 char *cc_hdr = mail_hdr(mail, "CC:");
202 s = put_from_(s);
203 s = put_date(s);
204 s = put_from(s);
205 s = put_reply(s, from_hdr, to_hdr, cc_hdr);
206 if (subj_hdr)
207 s = put_replysubj(s, subj_hdr);
208 s = put_id(s);
209 if (id_hdr)
210 s = put_replyto(s, id_hdr, ref_hdr);
211 s = put_agent(s);
212 draft->len = s - draft->mail;
215 void draft_edit(struct draft *draft)
217 char *edit_argv[] = {EDITOR, DRAFT, NULL};
218 int fd;
219 if ((fd = open(DRAFT, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) == -1)
220 return;
221 xwrite(fd, draft->mail, draft->len);
222 close(fd);
223 exec_file(EDITOR, edit_argv);
224 if ((fd = open(DRAFT, O_RDONLY)) == -1)
225 return;
226 draft->len = xread(fd, draft->mail, sizeof(draft->mail) - 1);
227 close(fd);
228 draft->mail[draft->len] = '\0';
229 unlink(DRAFT);
232 void draft_send(struct draft *draft)
234 char recips[MAXRECP][MAXLINE];
235 char *send_argv[MAXRECP + 3] = {SENDMAIL, "-i"};
236 char *beg = strchr(draft->mail, '\n') + 1;
237 char *end = draft->mail + draft->len;
238 int i;
239 for (i = 0; i < MAXRECP; i++)
240 send_argv[i + 2] = recips[i];
241 send_argv[2 + mail_recips(send_argv + 2, MAXRECP, draft->mail)] = NULL;
242 exec_pipe(SENDMAIL, send_argv, beg, end - beg);
245 static void write_nofrom(int fd, char *s, int len)
247 char *beg = s;
248 char *d = s + len;
249 char *r;
250 while (s < d) {
251 if (!strncmp("\nFrom ", s, 6)) {
252 write(fd, beg, s - beg + 1);
253 write(fd, ">", 1);
254 beg = s + 1;
256 r = strchr(s + 1, '\n');
257 s = r ? r : d;
259 write(fd, beg, s - beg);
262 void draft_save(struct draft *draft, char *path)
264 int fd = open(path, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
265 if (fd < -1)
266 return;
267 write_nofrom(fd, draft->mail, draft->len);
268 close(fd);