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
))
31 static int parse_addr(char **recips
, int size
, char *s
, int len
)
35 while (n
< size
&& s
< d
&& *(s
= cut_addr(recips
[n
], s
)))
36 if (strchr(recips
[n
], '@'))
41 static int mail_recips(char **recips
, int size
, char *s
)
43 struct mail mail
= {{0}};
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);
54 static char *put_from_(char *s
)
57 char *logname
= getlogin();
59 s
= put_str(s
, "From ");
60 s
= put_str(s
, logname
? logname
: "me");
61 s
+= strftime(s
, MAXLINE
, " %a %b %d %H:%M:%S %Y\n", localtime(&t
));
65 static char *put_date(char *s
)
71 s
= put_str(s
, "Date: ");
72 s
+= strftime(s
, MAXLINE
, "%a, %d %b %Y %H:%M:%S ", localtime(&t
));
74 *s
++ = timezone
< 0 ? '-' : '+';
75 s
= put_intz(s
, tz
/ 3600, 2);
76 s
= put_intz(s
, (tz
% 3600) / 60, 2);
81 static char *put_id(char *s
)
85 s
= put_str(s
, "Message-ID: <");
86 s
+= strftime(s
, MAXLINE
, "%Y%d%m%H%M%S", localtime(&t
));
87 s
= put_str(s
, "@" HOSTNAME
">\n");
91 static char *put_from(char *s
)
93 return FROM
? put_str(s
, "From: " FROM
"\n") : s
;
96 static char *put_to(char *s
, char **to
, int n
)
99 s
= put_str(s
, "To: ");
100 s
= put_str(s
, to
[0]);
101 for (i
= 1; i
< n
; i
++) {
102 s
= put_str(s
, ",\n\t");
103 s
= put_str(s
, to
[i
]);
105 if (*(s
- 1) != '\n')
106 s
= put_str(s
, "\n");
110 static char *put_subj(char *s
, char *subj
)
112 s
= put_str(s
, "Subject: ");
113 s
= put_str(s
, subj
);
114 s
= put_str(s
, "\n");
118 static char *put_agent(char *s
)
120 return put_str(s
, "User-Agent: " USERAGENT
"\n");
123 void draft_init(struct draft
*draft
, char **to
, int nto
, char *subj
)
125 char *s
= draft
->mail
;
130 s
= put_to(s
, to
, nto
);
132 s
= put_subj(s
, subj
);
135 draft
->len
= s
- draft
->mail
;
138 static char *hdr_val(char *hdr
)
140 hdr
= strchr(hdr
, ':') + 1;
141 while (isspace(*hdr
))
146 static char *put_replysubj(char *s
, char *subj
)
148 subj
= hdr_val(subj
);
149 s
= put_str(s
, "Subject: ");
150 if (tolower(subj
[0]) != 'r' || tolower(subj
[1]) != 'e')
151 s
= put_str(s
, "Re: ");
152 s
= put_mem(s
, subj
, hdr_len(subj
));
156 static char *put_replyto(char *s
, char *id
, char *ref
)
158 s
= put_str(s
, "In-Reply-To: ");
160 s
= put_mem(s
, id
, hdr_len(id
));
161 s
= put_str(s
, "References: ");
164 s
= put_mem(s
, ref
, hdr_len(ref
));
165 s
= put_str(s
, "\t");
167 s
= put_mem(s
, id
, hdr_len(id
));
171 static char *put_reply(char *s
, char *from
, char *to
, char *cc
)
174 from
= hdr_val(from
);
175 s
= put_str(s
, "To: ");
176 s
= put_mem(s
, from
, hdr_len(from
));
179 s
= put_str(s
, "Cc: ");
182 s
= put_mem(s
, to
, hdr_len(to
));
187 while (strchr("\r\n ", *(s
- 1)))
189 s
= put_str(s
, ",\n\t");
191 s
= put_mem(s
, cc
, hdr_len(cc
));
197 static char *quote_body(char *s
, int size
, struct mail
*mail
)
199 char *from
= mail_hdr(mail
, "From:");
200 char *r
= mail
->body
;
201 char *rd
= r
+ mail
->body_len
;
202 char *sd
= s
+ size
- 16;
203 s
= put_str(s
, "\n");
205 from
= hdr_val(from
);
206 s
= put_mem(s
, from
, hdr_len(from
) - 1);
207 s
= put_str(s
, " wrote:\n");
209 while (s
< sd
&& r
< rd
) {
210 char *nl
= memchr(r
, '\n', rd
- r
);
211 s
= put_str(s
, "> ");
212 nl
= nl
? nl
+ 1 : rd
;
213 s
= put_mem(s
, r
, MIN(sd
- s
, nl
- r
));
220 void draft_reply(struct draft
*draft
, struct mail
*mail
)
222 char *s
= draft
->mail
;
223 char *id_hdr
= mail_hdr(mail
, "Message-ID:");
224 char *ref_hdr
= mail_hdr(mail
, "References:");
225 char *from_hdr
= mail_hdr(mail
, "From:");
226 char *subj_hdr
= mail_hdr(mail
, "Subject:");
227 char *to_hdr
= mail_hdr(mail
, "To:");
228 char *cc_hdr
= mail_hdr(mail
, "CC:");
233 s
= put_reply(s
, from_hdr
, to_hdr
, cc_hdr
);
235 s
= put_replysubj(s
, subj_hdr
);
238 s
= put_replyto(s
, id_hdr
, ref_hdr
);
240 s
= quote_body(s
, sizeof(draft
->mail
) - (s
- draft
->mail
), mail
);
241 draft
->len
= s
- draft
->mail
;
244 void draft_edit(struct draft
*draft
, char *editor
)
246 char *edit_argv
[] = {NULL
, DRAFT
, NULL
};
248 if ((fd
= open(DRAFT
, O_WRONLY
| O_CREAT
, S_IRUSR
| S_IWUSR
)) == -1)
250 xwrite(fd
, draft
->mail
, draft
->len
);
252 edit_argv
[0] = editor
;
253 exec_file(editor
, edit_argv
);
254 if ((fd
= open(DRAFT
, O_RDONLY
)) == -1)
256 draft
->len
= xread(fd
, draft
->mail
, sizeof(draft
->mail
) - 1);
258 draft
->mail
[draft
->len
] = '\0';
262 void draft_send(struct draft
*draft
)
264 char recips
[MAXRECP
][MAXLINE
];
265 char *send_argv
[MAXRECP
+ 3] = {SENDMAIL
, "-i"};
266 char *beg
= strchr(draft
->mail
, '\n') + 1;
267 char *end
= draft
->mail
+ draft
->len
;
269 for (i
= 0; i
< MAXRECP
; i
++)
270 send_argv
[i
+ 2] = recips
[i
];
271 send_argv
[2 + mail_recips(send_argv
+ 2, MAXRECP
, draft
->mail
)] = NULL
;
272 exec_pipe(SENDMAIL
, send_argv
, beg
, end
- beg
);
275 static void write_nofrom(int fd
, char *s
, int len
)
281 if (!strncmp("\nFrom ", s
, 6)) {
282 write(fd
, beg
, s
- beg
+ 1);
286 r
= strchr(s
+ 1, '\n');
289 write(fd
, beg
, s
- beg
);
292 void draft_save(struct draft
*draft
, char *path
)
294 int fd
= open(path
, O_WRONLY
| O_APPEND
| O_CREAT
, S_IRUSR
| S_IWUSR
);
297 write_nofrom(fd
, draft
->mail
, draft
->len
);