mbox: simplify mail_start()
[mailx.git] / send.c
blob92d456408a5c4185c877a873a52927a39a4acd7c
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"
17 static int isaddr(int c)
19 return isalpha(c) || isdigit(c) || strchr("_.-@", c);
22 static char *cut_addr(char *dst, char *src)
24 while (*src && !isaddr(*src))
25 src++;
26 while (isaddr(*src))
27 *dst++ = *src++;
28 *dst++ = '\0';
29 return src;
32 static int parse_addr(char **recips, int size, char *s, int len)
34 int n = 0;
35 char *d = s + len;
36 while (n < size && s < d && *(s = cut_addr(recips[n], s)))
37 if (strchr(recips[n], '@'))
38 n++;
39 return n;
42 static int mail_recips(char **recips, int size, char *s)
44 struct mail mail = {{0}};
45 char *to, *cc;
46 int n = 0;
47 mail_read(&mail, s);
48 if ((to = mail_hdr(&mail, "To:")))
49 n += parse_addr(recips + n, size - n, to + 3, hdr_len(to) - 3);
50 if ((cc = mail_hdr(&mail, "CC:")))
51 n += parse_addr(recips + n, size - n, cc + 3, hdr_len(cc) - 3);
52 return n;
55 static char *put_from_(char *s)
57 time_t t;
58 char *logname = getenv("LOGNAME");
59 time(&t);
60 s = put_str(s, "From ");
61 s = put_str(s, logname ? logname : "me");
62 s += strftime(s, MAXLINE, " %a %b %d %H:%M:%S %Y\n", localtime(&t));
63 return s;
66 static char *put_date(char *s)
68 time_t t;
69 time(&t);
70 s = put_str(s, "Date: ");
71 s += strftime(s, MAXLINE, "%a, %d %b %Y %H:%M:%S %z\n", localtime(&t));
72 return s;
75 static char *put_id(char *s)
77 time_t t;
78 time(&t);
79 s = put_str(s, "Message-ID: <");
80 s += strftime(s, MAXLINE, "%Y%d%m%H%M%S", localtime(&t));
81 s = put_str(s, "@" HOSTNAME ">\n");
82 return s;
85 static char *put_from(char *s)
87 return FROM ? put_str(s, "From: " FROM "\n") : s;
90 static char *put_to(char *s, char **to, int n)
92 int i;
93 s = put_str(s, "To: ");
94 s = put_str(s, to[0]);
95 for (i = 1; i < n; i++) {
96 s = put_str(s, ",\n\t");
97 s = put_str(s, to[i]);
99 if (*(s - 1) != '\n')
100 s = put_str(s, "\n");
101 return s;
104 static char *put_subj(char *s, char *subj)
106 s = put_str(s, "Subject: ");
107 s = put_str(s, subj);
108 s = put_str(s, "\n");
109 return s;
112 static char *put_agent(char *s)
114 return put_str(s, "User-Agent: " USERAGENT "\n");
117 void draft_init(struct draft *draft, char **to, int nto, char *subj)
119 char *s = draft->mail;
120 s = put_from_(s);
121 s = put_date(s);
122 s = put_from(s);
123 if (to && nto)
124 s = put_to(s, to, nto);
125 if (subj)
126 s = put_subj(s, subj);
127 s = put_id(s);
128 s = put_agent(s);
129 draft->len = s - draft->mail;
132 static char *hdr_val(char *hdr)
134 hdr = strchr(hdr, ':') + 1;
135 while (isspace(*hdr))
136 hdr++;
137 return hdr;
140 static char *put_replysubj(char *s, char *subj)
142 subj = hdr_val(subj);
143 s = put_str(s, "Subject: ");
144 if (tolower(subj[0]) != 'r' || tolower(subj[1]) != 'e')
145 s = put_str(s, "Re: ");
146 s = put_mem(s, subj, hdr_len(subj));
147 return s;
150 static char *put_replyto(char *s, char *id, char *ref)
152 s = put_str(s, "In-Reply-To: ");
153 id = hdr_val(id);
154 s = put_mem(s, id, hdr_len(id));
155 s = put_str(s, "References: ");
156 if (ref) {
157 ref = hdr_val(ref);
158 s = put_mem(s, ref, hdr_len(ref));
159 s = put_str(s, "\t");
161 s = put_mem(s, id, hdr_len(id));
162 return s;
165 static char *put_reply(char *s, char *from, char *to, char *cc)
167 if (from) {
168 from = hdr_val(from);
169 s = put_str(s, "To: ");
170 s = put_mem(s, from, hdr_len(from));
172 if (to || cc) {
173 s = put_str(s, "Cc: ");
174 if (to) {
175 to = hdr_val(to);
176 s = put_mem(s, to, hdr_len(to));
178 if (cc) {
179 cc = hdr_val(cc);
180 if (to) {
181 while (strchr("\r\n ", *(s - 1)))
182 s--;
183 s = put_str(s, ",\n\t");
185 s = put_mem(s, cc, hdr_len(cc));
188 return s;
191 static char *quote_body(char *s, int size, struct mail *mail)
193 char *from = mail_hdr(mail, "From:");
194 char *r = mail->body;
195 char *rd = r + mail->body_len;
196 char *sd = s + size - 16;
197 s = put_str(s, "\n");
198 if (from) {
199 from = hdr_val(from);
200 s = put_mem(s, from, hdr_len(from) - 1);
201 s = put_str(s, " wrote:\n");
203 while (s < sd && r < rd) {
204 char *nl = memchr(r, '\n', rd - r);
205 s = put_str(s, "> ");
206 nl = nl ? nl + 1 : rd;
207 s = put_mem(s, r, MIN(sd - s, nl - r));
208 r = nl;
210 *s = '\0';
211 return s;
214 void draft_reply(struct draft *draft, struct mail *mail)
216 char *s = draft->mail;
217 char *id_hdr = mail_hdr(mail, "Message-ID:");
218 char *ref_hdr = mail_hdr(mail, "References:");
219 char *from_hdr = mail_hdr(mail, "From:");
220 char *subj_hdr = mail_hdr(mail, "Subject:");
221 char *to_hdr = mail_hdr(mail, "To:");
222 char *cc_hdr = mail_hdr(mail, "CC:");
224 s = put_from_(s);
225 s = put_date(s);
226 s = put_from(s);
227 s = put_reply(s, from_hdr, to_hdr, cc_hdr);
228 if (subj_hdr)
229 s = put_replysubj(s, subj_hdr);
230 s = put_id(s);
231 if (id_hdr)
232 s = put_replyto(s, id_hdr, ref_hdr);
233 s = put_agent(s);
234 s = quote_body(s, sizeof(draft->mail) - (s - draft->mail), mail);
235 draft->len = s - draft->mail;
238 void draft_edit(struct draft *draft, char *editor)
240 char *edit_argv[] = {NULL, DRAFT, NULL};
241 int fd;
242 if ((fd = open(DRAFT, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) == -1)
243 return;
244 xwrite(fd, draft->mail, draft->len);
245 close(fd);
246 edit_argv[0] = editor;
247 exec_file(editor, edit_argv);
248 if ((fd = open(DRAFT, O_RDONLY)) == -1)
249 return;
250 draft->len = xread(fd, draft->mail, sizeof(draft->mail) - 1);
251 close(fd);
252 draft->mail[draft->len] = '\0';
253 unlink(DRAFT);
256 void draft_send(struct draft *draft)
258 char recips[MAXRECP][MAXLINE];
259 char *send_argv[MAXRECP + 3] = {SENDMAIL, "-i"};
260 char *beg = strchr(draft->mail, '\n') + 1;
261 char *end = draft->mail + draft->len;
262 int i;
263 for (i = 0; i < MAXRECP; i++)
264 send_argv[i + 2] = recips[i];
265 send_argv[2 + mail_recips(send_argv + 2, MAXRECP, draft->mail)] = NULL;
266 exec_pipe(SENDMAIL, send_argv, beg, end - beg);
269 static void write_nofrom(int fd, char *s, int len)
271 char *beg = s;
272 char *d = s + len;
273 char *r;
274 while (s < d) {
275 if (!strncmp("\nFrom ", s, 6)) {
276 write(fd, beg, s - beg + 1);
277 write(fd, ">", 1);
278 beg = s + 1;
280 r = strchr(s + 1, '\n');
281 s = r ? r : d;
283 write(fd, beg, s - beg);
286 void draft_save(struct draft *draft, char *path)
288 int fd = open(path, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
289 if (fd < -1)
290 return;
291 write_nofrom(fd, draft->mail, draft->len);
292 write(fd, "\n", 1);
293 close(fd);