add reply cmd
[mailx.git] / send.c
blob54af4f7389fdc67a024381b7a88ad4e85cc2e396
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 static int isaddr(int c)
16 return isalpha(c) || isdigit(c) || strchr("_.-@", c);
19 static char *cut_addr(char *dst, char *src)
21 while (*src && !isaddr(*src))
22 src++;
23 while (isaddr(*src))
24 *dst++ = *src++;
25 *dst++ = '\0';
26 return src;
29 static int parse_addr(char **recips, int size, char *s, int len)
31 int n = 0;
32 char *d = s + len;
33 while (n < size && s < d && *(s = cut_addr(recips[n], s)))
34 if (strchr(recips[n], '@'))
35 n++;
36 return n;
39 static int mail_recips(char **recips, int size, char *s)
41 struct mail mail = {{0}};
42 char *to, *cc;
43 int n = 0;
44 mail_read(&mail, s);
45 if ((to = mail_hdr(&mail, "To:")))
46 n += parse_addr(recips + n, size - n, to + 3, hdr_len(to) - 3);
47 if ((cc = mail_hdr(&mail, "CC:")))
48 n += parse_addr(recips + n, size - n, cc + 3, hdr_len(cc) - 3);
49 return n;
52 static char *put_from_(char *s)
54 time_t t;
55 time(&t);
56 s = put_str(s, "From ");
57 s = put_str(s, getlogin());
58 s += strftime(s, MAXLINE, " %a %b %d %H:%M:%S %Y\n", localtime(&t));
59 return s;
62 static char *put_date(char *s)
64 long tz;
65 time_t t;
66 time(&t);
67 tzset();
68 s = put_str(s, "Date: ");
69 s += strftime(s, MAXLINE, "%a, %d %b %Y %H:%M:%S ", localtime(&t));
70 tz = abs(timezone);
71 *s++ = timezone < 0 ? '-' : '+';
72 s = put_intz(s, tz / 3600, 2);
73 s = put_intz(s, (tz % 3600) / 60, 2);
74 s = put_str(s, "\n");
75 return s;
78 static char *put_id(char *s)
80 time_t t;
81 time(&t);
82 s = put_str(s, "Message-ID: <");
83 s += strftime(s, MAXLINE, "%Y%d%m%H%M%S", localtime(&t));
84 s = put_str(s, "@" HOSTNAME ">\n");
85 return s;
88 static char *put_from(char *s)
90 return FROM ? put_str(s, "From: " FROM "\n") : s;
93 static char *put_to(char *s, char **to, int n)
95 int i;
96 s = put_str(s, "To: ");
97 s = put_str(s, to[0]);
98 for (i = 1; i < n; i++) {
99 s = put_str(s, ",\n\t");
100 s = put_str(s, to[i]);
102 s = put_str(s, "\n");
103 return s;
106 static char *put_subj(char *s, char *subj)
108 s = put_str(s, "Subject: ");
109 s = put_str(s, subj);
110 s = put_str(s, "\n");
111 return s;
114 void draft_init(struct draft *draft, char **to, int nto, char *subj)
116 char *s = draft->mail;
117 s = put_from_(s);
118 s = put_date(s);
119 s = put_id(s);
120 s = put_from(s);
121 if (to && nto)
122 s = put_to(s, to, nto);
123 if (subj)
124 s = put_subj(s, subj);
125 draft->len = s - draft->mail;
128 static char *hdr_val(char *hdr)
130 hdr = strchr(hdr, ':') + 1;
131 while (isspace(*hdr))
132 hdr++;
133 return hdr;
136 static char *put_replysubj(char *s, char *subj)
138 subj = hdr_val(subj);
139 s = put_str(s, "Subject: ");
140 if (tolower(subj[0]) != 'r' || tolower(subj[1]) != 'e')
141 s = put_str(s, "Re: ");
142 s = put_mem(s, subj, hdr_len(subj));
143 return s;
146 static char *put_replyto(char *s, char *id, char *ref)
148 s = put_str(s, "In-Reply-To: ");
149 id = hdr_val(id);
150 s = put_mem(s, id, hdr_len(id));
151 s = put_str(s, "References: ");
152 s = put_mem(s, id, hdr_len(id));
153 if (ref) {
154 ref = hdr_val(ref);
155 s = put_str(s, "\t");
156 s = put_mem(s, ref, hdr_len(ref));
158 return s;
161 static char *put_reply(char *s, char *from, char *to, char *cc)
163 if (from) {
164 from = hdr_val(from);
165 s = put_str(s, "To: ");
166 s = put_mem(s, from, hdr_len(from));
168 if (to || cc) {
169 s = put_str(s, "Cc: ");
170 if (to) {
171 to = hdr_val(to);
172 s = put_mem(s, to, hdr_len(to));
174 if (cc) {
175 cc = hdr_val(cc);
176 if (to)
177 s = put_str(s, "\t");
178 s = put_mem(s, cc, hdr_len(cc));
181 return s;
184 void draft_reply(struct draft *draft, struct mail *mail)
186 char *s = draft->mail;
187 char *id_hdr = mail_hdr(mail, "Message-ID:");
188 char *ref_hdr = mail_hdr(mail, "References:");
189 char *from_hdr = mail_hdr(mail, "From:");
190 char *subj_hdr = mail_hdr(mail, "Subject:");
191 char *to_hdr = mail_hdr(mail, "To:");
192 char *cc_hdr = mail_hdr(mail, "CC:");
194 s = put_from_(s);
195 s = put_date(s);
196 s = put_id(s);
197 s = put_from(s);
198 if (subj_hdr)
199 s = put_replysubj(s, subj_hdr);
200 if (id_hdr)
201 s = put_replyto(s, id_hdr, ref_hdr);
202 s = put_reply(s, from_hdr, to_hdr, cc_hdr);
203 draft->len = s - draft->mail;
206 void draft_edit(struct draft *draft)
208 char *edit_argv[] = {EDITOR, DRAFT, NULL};
209 int fd;
210 if ((fd = open(DRAFT, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR)) == -1)
211 return;
212 xwrite(fd, draft->mail, draft->len);
213 close(fd);
214 exec_file(EDITOR, edit_argv);
215 if ((fd = open(DRAFT, O_RDONLY)) == -1)
216 return;
217 draft->len = xread(fd, draft->mail, sizeof(draft->mail) - 1);
218 close(fd);
219 draft->mail[draft->len] = '\0';
220 unlink(DRAFT);
223 void draft_send(struct draft *draft)
225 char recips[MAXRECP][MAXLINE];
226 char *send_argv[MAXRECP + 3] = {SENDMAIL, "-i"};
227 char *beg = strchr(draft->mail, '\n') + 1;
228 char *end = draft->mail + draft->len;
229 int i;
230 for (i = 0; i < MAXRECP; i++)
231 send_argv[i + 2] = recips[i];
232 send_argv[2 + mail_recips(send_argv + 2, MAXRECP, draft->mail)] = NULL;
233 exec_pipe(SENDMAIL, send_argv, beg, end - beg);
236 void draft_save(struct draft *draft, char *path)
238 struct mail mail = {{0}};
239 int fd = open(path, O_WRONLY | O_APPEND | O_CREAT, S_IRUSR | S_IWUSR);
240 if (fd < -1)
241 return;
242 mail_read(&mail, draft->mail);
243 mail_write(&mail, fd);
244 close(fd);