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
))
33 static int parse_addr(char **recips
, int size
, char *s
, int len
)
37 while (n
< size
&& s
< d
&& *(s
= cut_addr(recips
[n
], s
)))
38 if (strchr(recips
[n
], '@'))
43 static int mail_recips(char **recips
, int size
, char *s
, char *e
)
45 struct mail mail
= {{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);
56 static char *put_from_(char *s
)
59 char *logname
= getenv("LOGNAME");
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
));
67 static char *put_date(char *s
)
71 s
= put_str(s
, "Date: ");
72 s
+= strftime(s
, MAXLINE
, "%a, %d %b %Y %H:%M:%S %z\n", localtime(&t
));
76 static char *put_id(char *s
)
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");
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
)
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");
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");
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
;
125 s
= put_to(s
, to
, nto
);
127 s
= put_subj(s
, subj
);
130 draft
->len
= s
- draft
->mail
;
133 static char *hdr_val(char *hdr
)
135 hdr
= strchr(hdr
, ':') + 1;
136 while (isspace(*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]))
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
));
166 static char *put_replyto(char *s
, char *id
, char *ref
)
168 s
= put_str(s
, "In-Reply-To: ");
170 s
= put_mem(s
, id
, hdr_len(id
));
171 s
= put_str(s
, "References: ");
174 s
= put_mem(s
, ref
, hdr_len(ref
));
175 s
= put_str(s
, "\t");
177 s
= put_mem(s
, id
, hdr_len(id
));
181 static char *put_reply(char *s
, char *from
, char *to
, char *cc
, char *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: ");
190 s
= put_hdr_append(s
, to
);
192 s
= put_hdr_append(s
, from
);
194 s
= put_hdr_append(s
, cc
);
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");
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
));
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:");
236 s
= put_reply(s
, from_hdr
, to_hdr
, cc_hdr
, rply_hdr
);
238 s
= put_replysubj(s
, subj_hdr
);
241 s
= put_replyto(s
, id_hdr
, ref_hdr
);
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
};
251 if ((fd
= open(DRAFT
, O_WRONLY
| O_CREAT
, S_IRUSR
| S_IWUSR
)) == -1)
253 xwrite(fd
, draft
->mail
, draft
->len
);
255 edit_argv
[0] = editor
;
256 exec_file(editor
, edit_argv
);
257 if ((fd
= open(DRAFT
, O_RDONLY
)) == -1)
259 draft
->len
= xread(fd
, draft
->mail
, sizeof(draft
->mail
) - 1);
261 draft
->mail
[draft
->len
] = '\0';
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
;
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
)
287 if (!strncmp("\nFrom ", s
, 6)) {
288 write(fd
, beg
, s
- beg
+ 1);
292 r
= strchr(s
+ 1, '\n');
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
);
303 write_nofrom(fd
, draft
->mail
, draft
->len
);