mk: sort messages by date or thread
[neatmail.git] / pg.c
blobd60cb03530332aae7aefaa8ba1e90514d261bdd8
1 #include <ctype.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <time.h>
6 #include "mail.h"
8 #define USERAGENT "neatmail (git://repo.or.cz/neatmail.git)"
10 static void msg_new(char **msg, long *msglen);
11 static int msg_reply(char *msg, long msglen, char **mod, long *modlen);
12 static int msg_forward(char *msg, long msglen, char **mod, long *modlen);
14 static char *segment(char *d, char *s, int m)
16 char *r = strchr(s, m);
17 char *e = r ? r + 1 : strchr(s, '\0');
18 memcpy(d, s, e - s);
19 d[e - s] = '\0';
20 return e;
23 static int msg_filter(char *msg, long msglen, char **mod, long *modlen, char *hdrs)
25 struct sbuf *sb = sbuf_make();
26 char *hdr = malloc(strlen(hdrs) + 1);
27 char *s = msg;
28 char *e = msg + msglen;
29 while ((hdrs = segment(hdr, hdrs, ':')) && hdr[0]) {
30 char *val = msg_get(msg, msglen, hdr);
31 if (val)
32 sbuf_mem(sb, val, hdrlen(val, msg + msglen - val));
34 free(hdr);
35 while (s + 1 < e && (s[0] != '\n' || s[1] != '\n'))
36 s++;
37 s++;
38 sbuf_mem(sb, s, e - s);
39 *modlen = sbuf_len(sb);
40 *mod = sbuf_done(sb);
41 return 0;
44 static char *usage =
45 "usage: neatmail pg [options] mbox msg\n\n"
46 "options:\n"
47 " -h hdrs \tthe list of headers to include\n"
48 " -m \tdecode mime message\n"
49 " -r \tgenerate a reply\n"
50 " -f \tgenerate a forward\n"
51 " -n \tgenerate a new message\n";
53 int pg(char *argv[])
55 char *mbox, *addr;
56 char *msg, *mod;
57 char *hdrs = NULL;
58 long msglen, modlen;
59 int demime = 0;
60 int reply = 0;
61 int forward = 0;
62 int newmsg = 0;
63 int i;
64 for (i = 0; argv[i] && argv[i][0] == '-'; i++) {
65 if (argv[i][1] == 'm')
66 demime = 1;
67 if (argv[i][1] == 'r')
68 reply = 1;
69 if (argv[i][1] == 'n')
70 newmsg = 1;
71 if (argv[i][1] == 'f')
72 forward = 1;
73 if (argv[i][1] == 'h') {
74 hdrs = argv[i][2] ? argv[i] + 2 : argv[++i];
75 continue;
78 if (newmsg) {
79 msg_new(&msg, &msglen);
80 xwrite(1, msg, msglen);
81 free(msg);
82 return 0;
84 if (!argv[i] || !argv[i + 1]) {
85 printf("%s", usage);
86 return 1;
88 mbox = argv[i];
89 addr = argv[i + 1];
90 if (!mbox_ith(mbox, atoi(addr), &msg, &msglen)) {
91 if (demime && !msg_demime(msg, msglen, &mod, &modlen)) {
92 free(msg);
93 msg = mod;
94 msglen = modlen;
96 if (reply && !msg_reply(msg, msglen, &mod, &modlen)) {
97 free(msg);
98 msg = mod;
99 msglen = modlen;
101 if (hdrs && !msg_filter(msg, msglen, &mod, &modlen, hdrs)) {
102 free(msg);
103 msg = mod;
104 msglen = modlen;
106 if (forward && !msg_forward(msg, msglen, &mod, &modlen)) {
107 free(msg);
108 msg = mod;
109 msglen = modlen;
111 xwrite(1, msg, msglen);
112 free(msg);
114 return 0;
117 static void put_from_(struct sbuf *sb)
119 char buf[128];
120 time_t t;
121 time(&t);
122 strftime(buf, sizeof(buf), "%a %b %d %H:%M:%S %Y", localtime(&t));
123 sbuf_printf(sb, "From %s %s\n",
124 getenv("LOGNAME") ? getenv("LOGNAME") : "me", buf);
127 static void put_date(struct sbuf *sb)
129 char buf[128];
130 time_t t;
131 time(&t);
132 strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", localtime(&t));
133 sbuf_printf(sb, "Date: %s\n", buf);
136 static void put_id(struct sbuf *sb)
138 char buf[128];
139 char host[32] = "neatmail";
140 time_t t;
141 time(&t);
142 strftime(buf, sizeof(buf), "%Y%d%m%H%M%S", localtime(&t));
143 sbuf_printf(sb, "Message-ID: <%s.%s>\n", host, buf);
146 static void put_agent(struct sbuf *sb)
148 sbuf_printf(sb, "User-Agent: " USERAGENT "\n");
151 static void msg_new(char **msg, long *msglen)
153 struct sbuf *sb = sbuf_make();
154 put_from_(sb);
155 sbuf_printf(sb, "From: \n");
156 sbuf_printf(sb, "To: \n");
157 sbuf_printf(sb, "Subject: \n");
158 put_id(sb);
159 put_date(sb);
160 put_agent(sb);
161 sbuf_chr(sb, '\n');
162 *msglen = sbuf_len(sb);
163 *msg = sbuf_done(sb);
166 static char *hdr_val(char *hdr)
168 hdr = strchr(hdr, ':') + 1;
169 while (isspace(*hdr))
170 hdr++;
171 return hdr;
174 static int hdr_len(char *hdr)
176 int l = hdrlen(hdr, 1024);
177 while (l > 0 && strchr(" \r\n", (unsigned char) hdr[l - 1]))
178 l--;
179 return l;
182 static void put_subjreply(struct sbuf *sb, char *subj)
184 subj = hdr_val(subj);
185 sbuf_str(sb, "Subject: ");
186 if (tolower(subj[0]) != 'r' || tolower(subj[1]) != 'e')
187 sbuf_str(sb, "Re: ");
188 sbuf_mem(sb, subj, hdr_len(subj));
189 sbuf_str(sb, "\n");
192 static void put_subjfwd(struct sbuf *sb, char *subj)
194 subj = hdr_val(subj);
195 sbuf_str(sb, "Subject: ");
196 sbuf_str(sb, "Fwd: ");
197 sbuf_mem(sb, subj, hdr_len(subj));
198 sbuf_str(sb, "\n");
201 static void put_replyto(struct sbuf *sb, char *id, char *ref)
203 id = hdr_val(id);
204 sbuf_str(sb, "In-Reply-To: ");
205 sbuf_mem(sb, id, hdr_len(id));
206 sbuf_str(sb, "\n");
207 sbuf_str(sb, "References: ");
208 if (ref) {
209 ref = hdr_val(ref);
210 sbuf_mem(sb, ref, hdr_len(ref));
211 sbuf_str(sb, "\n\t");
213 sbuf_mem(sb, id, hdr_len(id));
214 sbuf_str(sb, "\n");
217 static void put_reply(struct sbuf *sb, char *from, char *to, char *cc, char *rply)
219 if (from || rply) {
220 char *hdr = rply ? rply : from;
221 hdr = hdr_val(hdr);
222 sbuf_str(sb, "To: ");
223 sbuf_mem(sb, hdr, hdr_len(hdr));
224 sbuf_str(sb, "\n");
226 if (to || cc || (rply && from)) {
227 int n = 0;
228 sbuf_str(sb, "Cc: ");
229 if (to) {
230 to = hdr_val(to);
231 if (n++)
232 sbuf_str(sb, "\n\t");
233 sbuf_mem(sb, to, hdr_len(to));
235 if (rply && from) {
236 from = hdr_val(from);
237 if (n++)
238 sbuf_str(sb, "\n\t");
239 sbuf_mem(sb, from, hdr_len(from));
241 if (cc) {
242 cc = hdr_val(cc);
243 if (n++)
244 sbuf_str(sb, "\n\t");
245 sbuf_mem(sb, cc, hdr_len(cc));
247 sbuf_str(sb, "\n");
251 static void quote_body(struct sbuf *sb, char *msg, long msglen)
253 char *from = msg_get(msg, msglen, "From:");
254 char *s = msg;
255 char *e = msg + msglen;
256 while (s + 1 < e && (s[0] != '\n' || s[1] != '\n'))
257 s++;
258 s += 2;
259 sbuf_chr(sb, '\n');
260 if (from) {
261 from = hdr_val(from);
262 sbuf_mem(sb, from, hdr_len(from));
263 sbuf_str(sb, " wrote:\n");
265 while (s < e) {
266 char *r = memchr(s, '\n', e - s);
267 if (!r)
268 break;
269 sbuf_str(sb, "> ");
270 sbuf_mem(sb, s, r - s + 1);
271 s = r + 1;
275 static int msg_reply(char *msg, long msglen, char **mod, long *modlen)
277 struct sbuf *sb = sbuf_make();
278 char *id_hdr = msg_get(msg, msglen, "Message-ID:");
279 char *ref_hdr = msg_get(msg, msglen, "References:");
280 char *from_hdr = msg_get(msg, msglen, "From:");
281 char *subj_hdr = msg_get(msg, msglen, "Subject:");
282 char *to_hdr = msg_get(msg, msglen, "To:");
283 char *cc_hdr = msg_get(msg, msglen, "CC:");
284 char *rply_hdr = msg_get(msg, msglen, "Reply-To:");
285 put_from_(sb);
286 put_date(sb);
287 sbuf_printf(sb, "From: \n");
288 put_reply(sb, from_hdr, to_hdr, cc_hdr, rply_hdr);
289 if (subj_hdr)
290 put_subjreply(sb, subj_hdr);
291 put_id(sb);
292 if (id_hdr)
293 put_replyto(sb, id_hdr, ref_hdr);
294 put_agent(sb);
295 quote_body(sb, msg, msglen);
296 *modlen = sbuf_len(sb);
297 *mod = sbuf_done(sb);
298 return 0;
301 static int msg_forward(char *msg, long msglen, char **mod, long *modlen)
303 struct sbuf *sb = sbuf_make();
304 char *subj_hdr = msg_get(msg, msglen, "Subject:");
305 put_from_(sb);
306 put_date(sb);
307 sbuf_printf(sb, "From: \n");
308 sbuf_printf(sb, "To: \n");
309 put_subjfwd(sb, subj_hdr);
310 put_id(sb);
311 put_agent(sb);
312 sbuf_str(sb, "\n-------- Original Message --------\n");
313 sbuf_mem(sb, msg, msglen);
314 *modlen = sbuf_len(sb);
315 *mod = sbuf_done(sb);
316 return 0;