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
))
32 static int parse_addr(char **recips
, int size
, char *s
, int len
)
36 while (n
< size
&& s
< d
&& *(s
= cut_addr(recips
[n
], s
)))
37 if (strchr(recips
[n
], '@'))
42 static int mail_recips(char **recips
, int size
, char *s
)
44 struct mail mail
= {{0}};
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);
55 static char *put_from_(char *s
)
58 char *logname
= getenv("LOGNAME");
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
));
66 static char *put_date(char *s
)
70 s
= put_str(s
, "Date: ");
71 s
+= strftime(s
, MAXLINE
, "%a, %d %b %Y %H:%M:%S %z\n", localtime(&t
));
75 static char *put_id(char *s
)
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");
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
)
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
]);
100 s
= put_str(s
, "\n");
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");
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
;
124 s
= put_to(s
, to
, nto
);
126 s
= put_subj(s
, subj
);
129 draft
->len
= s
- draft
->mail
;
132 static char *hdr_val(char *hdr
)
134 hdr
= strchr(hdr
, ':') + 1;
135 while (isspace(*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
));
150 static char *put_replyto(char *s
, char *id
, char *ref
)
152 s
= put_str(s
, "In-Reply-To: ");
154 s
= put_mem(s
, id
, hdr_len(id
));
155 s
= put_str(s
, "References: ");
158 s
= put_mem(s
, ref
, hdr_len(ref
));
159 s
= put_str(s
, "\t");
161 s
= put_mem(s
, id
, hdr_len(id
));
165 static char *put_reply(char *s
, char *from
, char *to
, char *cc
)
168 from
= hdr_val(from
);
169 s
= put_str(s
, "To: ");
170 s
= put_mem(s
, from
, hdr_len(from
));
173 s
= put_str(s
, "Cc: ");
176 s
= put_mem(s
, to
, hdr_len(to
));
181 while (strchr("\r\n ", *(s
- 1)))
183 s
= put_str(s
, ",\n\t");
185 s
= put_mem(s
, cc
, hdr_len(cc
));
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");
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
));
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:");
227 s
= put_reply(s
, from_hdr
, to_hdr
, cc_hdr
);
229 s
= put_replysubj(s
, subj_hdr
);
232 s
= put_replyto(s
, id_hdr
, ref_hdr
);
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
};
242 if ((fd
= open(DRAFT
, O_WRONLY
| O_CREAT
, S_IRUSR
| S_IWUSR
)) == -1)
244 xwrite(fd
, draft
->mail
, draft
->len
);
246 edit_argv
[0] = editor
;
247 exec_file(editor
, edit_argv
);
248 if ((fd
= open(DRAFT
, O_RDONLY
)) == -1)
250 draft
->len
= xread(fd
, draft
->mail
, sizeof(draft
->mail
) - 1);
252 draft
->mail
[draft
->len
] = '\0';
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
;
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
)
275 if (!strncmp("\nFrom ", s
, 6)) {
276 write(fd
, beg
, s
- beg
+ 1);
280 r
= strchr(s
+ 1, '\n');
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
);
291 write_nofrom(fd
, draft
->mail
, draft
->len
);