]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/upas/Mail/comp.c
bdf8c7aabeac9c910547ed93136522f53369b821
[plan9front.git] / sys / src / cmd / upas / Mail / comp.c
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <thread.h>
5 #include <regexp.h>
6
7 #include "mail.h"
8
9 typedef struct Fn       Fn;
10
11 struct Fn {
12         char *name;
13         void (*fn)(Comp *, char **, int);
14 };
15
16 void
17 execmarshal(void *p)
18 {
19         Comp *c;
20         char *av[8];
21         int na;
22
23         c = p;
24         rfork(RFFDG);
25         dup(c->fd[0], 0);
26         close(c->fd[0]);
27         close(c->fd[1]);
28
29         na = 0;
30         av[na++] = "marshal";
31         av[na++] = "-8";
32         if(savebox != nil){
33                 av[na++] = "-S";
34                 av[na++] = savebox;
35         }
36         if(c->rpath != nil){
37                 av[na++] = "-R";
38                 av[na++] = c->rpath;
39         }
40         av[na] = nil;
41         assert(na < nelem(av));
42         procexec(c->sync, "/bin/upas/marshal", av);
43 }
44
45 static void
46 postmesg(Comp *c, char **, int nf)
47 {
48         char *buf, wpath[64], *path;
49         int n, fd;
50         Mesg *m;
51
52         snprint(wpath, sizeof(wpath), "/mnt/acme/%d/body", c->id);
53         if(nf != 0){
54                 fprint(2, "Post: too many args\n");
55                 return;
56         }
57         if((fd = open(wpath, OREAD)) == -1){
58                 fprint(2, "open body: %r\n");
59                 return;
60         }
61         if(pipe(c->fd) == -1)
62                 sysfatal("pipe: %r\n");
63
64         c->sync = chancreate(sizeof(ulong), 0);
65         procrfork(execmarshal, c, Stack, RFNOTEG);
66         recvul(c->sync);
67         chanfree(c->sync);
68         close(c->fd[0]);
69
70         buf = emalloc(Bufsz);
71         while((n = read(fd, buf, Bufsz)) > 0)
72                 if(write(c->fd[1], buf, n) != n)
73                         break;
74         write(c->fd[1], "\n", 1);
75         close(c->fd[1]);
76         close(fd);
77         if(n == -1)
78                 return;
79
80         if(fprint(c->ctl, "name %s:Sent\n", c->path) == -1)
81                 sysfatal("write ctl: %r");
82         if(c->replyto != nil){
83                 if((m = mesglookup(c->rname, c->rdigest)) == nil)
84                         return;
85                 m->flags |= Fresp;
86                 path = estrjoin(mbox.path, "/", m->name, "/flags", nil);
87                 if((fd = open(path, OWRITE)) != -1){
88                         fprint(fd, "+a");
89                         close(fd);
90                 }
91                 mbredraw(m, 0, 0);
92                 free(path);
93         }
94         fprint(c->ctl, "clean\n");
95 }
96
97 static void
98 compquit(Comp *c, char **, int)
99 {
100         c->quitting = 1;
101 }
102
103 static Fn compfn[] = {
104         {"Post", postmesg},
105         {"Del", compquit},
106         {nil},
107 };
108
109 static void
110 compmain(void *cp)
111 {
112         char *f[32];
113         int nf;
114         Event ev;
115         Comp *c, **pc;
116         Fn *p;
117
118         c = cp;
119         c->quitting = 0;
120         c->qnext = mbox.opencomp;
121         mbox.opencomp = c;
122         fprint(c->ctl, "clean\n");
123         mbox.nopen++;
124         while(!c->quitting){
125                 if(winevent(c, &ev) != 'M')
126                         continue;
127                 if(strcmp(ev.text, "Del") == 0)
128                         break;
129                 switch(ev.type){
130                 case 'l':
131                 case 'L':
132                         if(matchmesg(&mbox, ev.text))
133                                 mesgopen(ev.text, nil);
134                         else
135                                 winreturn(c, &ev);
136                         break;
137                 case 'x':
138                 case 'X':
139                         if((nf = tokenize(ev.text, f, nelem(f))) == 0)
140                                 continue;
141                         for(p = compfn; p->fn != nil; p++)
142                                 if(strcmp(p->name, f[0]) == 0){
143                                         p->fn(c, &f[1], nf - 1);
144                                         break;
145                                 }
146                         if(p->fn == nil)
147                                 winreturn(c, &ev);
148                         break;
149                 break;
150                 }
151         }
152         for(pc = &mbox.opencomp; *pc != nil; pc = &(*pc)->qnext)
153                 if(*pc == c){
154                         *pc = c->qnext;
155                         break;
156                 }
157         mbox.nopen--;
158         c->qnext = nil;
159         winclose(c);
160         free(c->replyto);
161         free(c->rname);
162         free(c->rdigest);
163         free(c->rpath);
164         threadexits(nil);
165 }
166
167 static Biobuf*
168 openbody(Mesg *r)
169 {
170         Biobuf *f;
171         int q0, q1;
172         char *s;
173
174         assert(r->state & Sopen);
175
176         wingetsel(r, &q0, &q1);
177         if(q1 - q0 != 0){
178                 s = smprint("/mnt/acme/%d/xdata", r->id);
179                 f = Bopen(s, OREAD);
180                 free(s);
181         }else
182                 f = mesgopenbody(r);
183         return f;
184 }
185
186 int
187 strpcmp(void *a, void *b)
188 {
189         return strcmp(*(char**)a, *(char**)b);
190 }
191
192 void
193 show(Biobuf *fd, char *type, char **addrs, int naddrs)
194 {
195         char *sep;
196         int i, w;
197
198         w = 0;
199         sep = "";
200         if(naddrs == 0)
201                 return;
202         qsort(addrs, naddrs, sizeof(char*), strpcmp);
203         Bprint(fd, "%s: ", type);
204         for(i = 0; i < naddrs; i++){
205                 if(i > 0 && strcmp(addrs[i-1], addrs[i]) == 0)
206                         continue;
207                 w += Bprint(fd, "%s%s", sep, addrs[i]);
208                 sep = ", ";
209                 if(w > 50){
210                         w = 0;
211                         sep = "";
212                         Bprint(fd, "\n%s: ", type);
213                 }
214         }
215         Bprint(fd, "\n");
216 }
217
218 void
219 respondto(Biobuf *fd, char *to, Mesg *r, int all)
220 {
221         char *rpto, **addrs;
222         int n;
223
224         rpto = to;
225         if(r != nil)
226                 rpto = (strlen(r->replyto) > 0) ? r->replyto : r->from;
227         if(r == nil || !all){
228                 Bprint(fd, "To: %s\n", rpto);
229                 return;
230         }
231
232         n = 0;
233         addrs = emalloc(64*sizeof(char*));
234         n += tokenize(to, addrs+n, 64-n);
235         n += tokenize(rpto, addrs+n, 64-n);
236         n += tokenize(r->to, addrs+n, 64-n);
237         show(fd, "To", addrs, n);
238         n = tokenize(r->cc, addrs+n, 64-n);
239         show(fd, "CC", addrs, n);
240         free(addrs);
241 }
242
243 void
244 compose(char *to, Mesg *r, int all)
245 {
246         static int ncompose;
247         Biobuf *rfd, *wfd;
248         Comp *c;
249         char *ln;
250
251         c = emalloc(sizeof(Comp));
252         if(r != nil)
253                 c->path = esmprint("%s%s%s.%d", mbox.path, r->name, "Reply", ncompose++);
254         else
255                 c->path = esmprint("%sCompose.%d", mbox.path, ncompose++);
256         wininit(c, c->path);
257
258         wintagwrite(c, "Post |fmt ");
259         wfd = bwinopen(c, "body", OWRITE);
260         respondto(wfd, to, r, all);
261         if(r == nil)
262                 Bprint(wfd, "Subject: ");
263         else{
264                 if(r->messageid != nil)
265                         c->replyto = estrdup(r->messageid);
266                 c->rpath = estrjoin(mbox.path, r->name, nil);
267                 c->rname = estrdup(r->name);
268                 c->rdigest = estrdup(r->digest);
269                 Bprint(wfd, "Subject: ");
270                 if(r->subject != nil && cistrncmp(r->subject, "Re", 2) != 0)
271                         Bprint(wfd, "Re: ");
272                 Bprint(wfd, "%s\n\n", r->subject);
273                 Bprint(wfd, "Quoth %s:\n", r->fromcolon);
274                 rfd = openbody(r);
275                 if(rfd != nil){
276                         while((ln = Brdstr(rfd, '\n', 0)) != nil)
277                                 if(Bprint(wfd, "> %s", ln) == -1)
278                                         break;
279                         Bterm(rfd);
280                 }
281                 Bterm(wfd);
282         }
283         Bterm(wfd);
284         fprint(c->addr, "$");
285         fprint(c->ctl, "dot=addr");
286         threadcreate(compmain, c, Stack);
287 }