17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <plumb.h>
57dd7cddfSDavid du Colombier #include <regexp.h>
67dd7cddfSDavid du Colombier #include <bio.h>
77dd7cddfSDavid du Colombier #include "faces.h"
87dd7cddfSDavid du Colombier
97dd7cddfSDavid du Colombier static int showfd = -1;
107dd7cddfSDavid du Colombier static int seefd = -1;
117dd7cddfSDavid du Colombier static int logfd = -1;
127dd7cddfSDavid du Colombier static char *user;
137dd7cddfSDavid du Colombier static char *logtag;
14*a3b78ba5SDavid du Colombier
15*a3b78ba5SDavid du Colombier char **maildirs;
16*a3b78ba5SDavid du Colombier int nmaildirs;
177dd7cddfSDavid du Colombier
187dd7cddfSDavid du Colombier void
initplumb(void)197dd7cddfSDavid du Colombier initplumb(void)
207dd7cddfSDavid du Colombier {
217dd7cddfSDavid du Colombier showfd = plumbopen("send", OWRITE);
227dd7cddfSDavid du Colombier seefd = plumbopen("seemail", OREAD);
237dd7cddfSDavid du Colombier
247dd7cddfSDavid du Colombier if(seefd < 0){
257dd7cddfSDavid du Colombier logfd = open("/sys/log/mail", OREAD);
267dd7cddfSDavid du Colombier seek(logfd, 0LL, 2);
277dd7cddfSDavid du Colombier user = getenv("user");
287dd7cddfSDavid du Colombier if(user == nil){
297dd7cddfSDavid du Colombier fprint(2, "faces: can't find user name: %r\n");
307dd7cddfSDavid du Colombier exits("$user");
317dd7cddfSDavid du Colombier }
327dd7cddfSDavid du Colombier logtag = emalloc(32+strlen(user)+1);
337dd7cddfSDavid du Colombier sprint(logtag, " delivered %s From ", user);
347dd7cddfSDavid du Colombier }
357dd7cddfSDavid du Colombier }
367dd7cddfSDavid du Colombier
375fab9909SDavid du Colombier void
addmaildir(char * dir)385fab9909SDavid du Colombier addmaildir(char *dir)
395fab9909SDavid du Colombier {
405fab9909SDavid du Colombier maildirs = erealloc(maildirs, (nmaildirs+1)*sizeof(char*));
415fab9909SDavid du Colombier maildirs[nmaildirs++] = dir;
425fab9909SDavid du Colombier }
435fab9909SDavid du Colombier
447dd7cddfSDavid du Colombier char*
attr(Face * f)457dd7cddfSDavid du Colombier attr(Face *f)
467dd7cddfSDavid du Colombier {
477dd7cddfSDavid du Colombier static char buf[128];
487dd7cddfSDavid du Colombier
497dd7cddfSDavid du Colombier if(f->str[Sdigest]){
507dd7cddfSDavid du Colombier snprint(buf, sizeof buf, "digest=%s", f->str[Sdigest]);
517dd7cddfSDavid du Colombier return buf;
527dd7cddfSDavid du Colombier }
537dd7cddfSDavid du Colombier return nil;
547dd7cddfSDavid du Colombier }
557dd7cddfSDavid du Colombier
567dd7cddfSDavid du Colombier void
showmail(Face * f)577dd7cddfSDavid du Colombier showmail(Face *f)
587dd7cddfSDavid du Colombier {
597dd7cddfSDavid du Colombier char *s;
607dd7cddfSDavid du Colombier int n;
617dd7cddfSDavid du Colombier
627dd7cddfSDavid du Colombier if(showfd<0 || f->str[Sshow]==nil || f->str[Sshow][0]=='\0')
637dd7cddfSDavid du Colombier return;
647dd7cddfSDavid du Colombier s = emalloc(128+strlen(f->str[Sshow])+1);
657dd7cddfSDavid du Colombier n = sprint(s, "faces\nshowmail\n/mail/fs/\ntext\n%s\n%ld\n%s", attr(f), strlen(f->str[Sshow]), f->str[Sshow]);
667dd7cddfSDavid du Colombier write(showfd, s, n);
677dd7cddfSDavid du Colombier free(s);
687dd7cddfSDavid du Colombier }
697dd7cddfSDavid du Colombier
707dd7cddfSDavid du Colombier char*
value(Plumbattr * attr,char * key,char * def)717dd7cddfSDavid du Colombier value(Plumbattr *attr, char *key, char *def)
727dd7cddfSDavid du Colombier {
737dd7cddfSDavid du Colombier char *v;
747dd7cddfSDavid du Colombier
757dd7cddfSDavid du Colombier v = plumblookup(attr, key);
767dd7cddfSDavid du Colombier if(v)
777dd7cddfSDavid du Colombier return v;
787dd7cddfSDavid du Colombier return def;
797dd7cddfSDavid du Colombier }
807dd7cddfSDavid du Colombier
817dd7cddfSDavid du Colombier void
setname(Face * f,char * sender)827dd7cddfSDavid du Colombier setname(Face *f, char *sender)
837dd7cddfSDavid du Colombier {
847dd7cddfSDavid du Colombier char *at, *bang;
857dd7cddfSDavid du Colombier char *p;
867dd7cddfSDavid du Colombier
877dd7cddfSDavid du Colombier /* works with UTF-8, although it's written as ASCII */
887dd7cddfSDavid du Colombier for(p=sender; *p!='\0'; p++)
897dd7cddfSDavid du Colombier *p = tolower(*p);
907dd7cddfSDavid du Colombier f->str[Suser] = sender;
917dd7cddfSDavid du Colombier at = strchr(sender, '@');
927dd7cddfSDavid du Colombier if(at){
937dd7cddfSDavid du Colombier *at++ = '\0';
947dd7cddfSDavid du Colombier f->str[Sdomain] = estrdup(at);
957dd7cddfSDavid du Colombier return;
967dd7cddfSDavid du Colombier }
977dd7cddfSDavid du Colombier bang = strchr(sender, '!');
987dd7cddfSDavid du Colombier if(bang){
997dd7cddfSDavid du Colombier *bang++ = '\0';
1007dd7cddfSDavid du Colombier f->str[Suser] = estrdup(bang);
1017dd7cddfSDavid du Colombier f->str[Sdomain] = sender;
1027dd7cddfSDavid du Colombier return;
1037dd7cddfSDavid du Colombier }
1047dd7cddfSDavid du Colombier }
1057dd7cddfSDavid du Colombier
1067dd7cddfSDavid du Colombier int
getc(void)1077dd7cddfSDavid du Colombier getc(void)
1087dd7cddfSDavid du Colombier {
1097dd7cddfSDavid du Colombier static uchar buf[512];
1107dd7cddfSDavid du Colombier static int nbuf = 0;
1117dd7cddfSDavid du Colombier static int i = 0;
1127dd7cddfSDavid du Colombier
1137dd7cddfSDavid du Colombier while(i == nbuf){
1147dd7cddfSDavid du Colombier i = 0;
1157dd7cddfSDavid du Colombier nbuf = read(logfd, buf, sizeof buf);
1167dd7cddfSDavid du Colombier if(nbuf == 0){
1177dd7cddfSDavid du Colombier sleep(15000);
1187dd7cddfSDavid du Colombier continue;
1197dd7cddfSDavid du Colombier }
1207dd7cddfSDavid du Colombier if(nbuf < 0)
1217dd7cddfSDavid du Colombier return -1;
1227dd7cddfSDavid du Colombier }
1237dd7cddfSDavid du Colombier return buf[i++];
1247dd7cddfSDavid du Colombier }
1257dd7cddfSDavid du Colombier
1267dd7cddfSDavid du Colombier char*
getline(char * buf,int n)1277dd7cddfSDavid du Colombier getline(char *buf, int n)
1287dd7cddfSDavid du Colombier {
1297dd7cddfSDavid du Colombier int i, c;
1307dd7cddfSDavid du Colombier
1317dd7cddfSDavid du Colombier for(i=0; i<n-1; i++){
1327dd7cddfSDavid du Colombier c = getc();
1337dd7cddfSDavid du Colombier if(c <= 0)
1347dd7cddfSDavid du Colombier return nil;
1357dd7cddfSDavid du Colombier if(c == '\n')
1367dd7cddfSDavid du Colombier break;
1377dd7cddfSDavid du Colombier buf[i] = c;
1387dd7cddfSDavid du Colombier }
1397dd7cddfSDavid du Colombier buf[i] = '\0';
1407dd7cddfSDavid du Colombier return buf;
1417dd7cddfSDavid du Colombier }
1427dd7cddfSDavid du Colombier
143d9306527SDavid du Colombier static char* months[] = {
144d9306527SDavid du Colombier "jan", "feb", "mar", "apr",
145d9306527SDavid du Colombier "may", "jun", "jul", "aug",
146d9306527SDavid du Colombier "sep", "oct", "nov", "dec"
147d9306527SDavid du Colombier };
1487dd7cddfSDavid du Colombier
149d9306527SDavid du Colombier static int
getmon(char * s)150d9306527SDavid du Colombier getmon(char *s)
151d9306527SDavid du Colombier {
152d9306527SDavid du Colombier int i;
153d9306527SDavid du Colombier
154d9306527SDavid du Colombier for(i=0; i<nelem(months); i++)
155d9306527SDavid du Colombier if(cistrcmp(months[i], s) == 0)
156d9306527SDavid du Colombier return i;
157d9306527SDavid du Colombier return -1;
158d9306527SDavid du Colombier }
159d9306527SDavid du Colombier
160d9306527SDavid du Colombier /* Fri Jul 23 14:05:14 EDT 1999 */
161d9306527SDavid du Colombier ulong
parsedatev(char ** a)162d9306527SDavid du Colombier parsedatev(char **a)
163d9306527SDavid du Colombier {
164d9306527SDavid du Colombier char *p;
165d9306527SDavid du Colombier Tm tm;
166d9306527SDavid du Colombier
167d9306527SDavid du Colombier memset(&tm, 0, sizeof tm);
168d9306527SDavid du Colombier if((tm.mon=getmon(a[1])) == -1)
169d9306527SDavid du Colombier goto Err;
170d9306527SDavid du Colombier tm.mday = strtol(a[2], &p, 10);
171d9306527SDavid du Colombier if(*p != '\0')
172d9306527SDavid du Colombier goto Err;
173d9306527SDavid du Colombier tm.hour = strtol(a[3], &p, 10);
174d9306527SDavid du Colombier if(*p != ':')
175d9306527SDavid du Colombier goto Err;
176d9306527SDavid du Colombier tm.min = strtol(p+1, &p, 10);
177d9306527SDavid du Colombier if(*p != ':')
178d9306527SDavid du Colombier goto Err;
179d9306527SDavid du Colombier tm.sec = strtol(p+1, &p, 10);
180d9306527SDavid du Colombier if(*p != '\0')
181d9306527SDavid du Colombier goto Err;
182d9306527SDavid du Colombier if(strlen(a[4]) != 3)
183d9306527SDavid du Colombier goto Err;
184d9306527SDavid du Colombier strcpy(tm.zone, a[4]);
185d9306527SDavid du Colombier if(strlen(a[5]) != 4)
186d9306527SDavid du Colombier goto Err;
187d9306527SDavid du Colombier tm.year = strtol(a[5], &p, 10);
188d9306527SDavid du Colombier if(*p != '\0')
189d9306527SDavid du Colombier goto Err;
190d9306527SDavid du Colombier tm.year -= 1900;
191d9306527SDavid du Colombier return tm2sec(&tm);
192d9306527SDavid du Colombier Err:
193d9306527SDavid du Colombier return time(0);
194d9306527SDavid du Colombier }
195d9306527SDavid du Colombier
196d9306527SDavid du Colombier ulong
parsedate(char * s)197d9306527SDavid du Colombier parsedate(char *s)
198d9306527SDavid du Colombier {
199d9306527SDavid du Colombier char *f[10];
200d9306527SDavid du Colombier int nf;
201d9306527SDavid du Colombier
202d9306527SDavid du Colombier nf = getfields(s, f, nelem(f), 1, " ");
203d9306527SDavid du Colombier if(nf < 6)
204d9306527SDavid du Colombier return time(0);
205d9306527SDavid du Colombier return parsedatev(f);
206d9306527SDavid du Colombier }
207d9306527SDavid du Colombier
208d9306527SDavid du Colombier /* achille Jul 23 14:05:15 delivered jmk From ms.com!bub Fri Jul 23 14:05:14 EDT 1999 (plan9.bell-labs.com!jmk) 1352 */
209d9306527SDavid du Colombier /* achille Oct 26 13:45:42 remote local!rsc From rsc Sat Oct 26 13:45:41 EDT 2002 (rsc) 170 */
210d9306527SDavid du Colombier int
parselog(char * s,char ** sender,ulong * xtime)211d9306527SDavid du Colombier parselog(char *s, char **sender, ulong *xtime)
212d9306527SDavid du Colombier {
213d9306527SDavid du Colombier char *f[20];
214d9306527SDavid du Colombier int nf;
215d9306527SDavid du Colombier
216d9306527SDavid du Colombier nf = getfields(s, f, nelem(f), 1, " ");
217d9306527SDavid du Colombier if(nf < 14)
2187dd7cddfSDavid du Colombier return 0;
219d9306527SDavid du Colombier if(strcmp(f[4], "delivered") == 0 && strcmp(f[5], user) == 0)
220d9306527SDavid du Colombier goto Found;
221d9306527SDavid du Colombier if(strcmp(f[4], "remote") == 0 && strncmp(f[5], "local!", 6) == 0 && strcmp(f[5]+6, user) == 0)
222d9306527SDavid du Colombier goto Found;
223d9306527SDavid du Colombier return 0;
224d9306527SDavid du Colombier
225d9306527SDavid du Colombier Found:
226d9306527SDavid du Colombier *sender = estrdup(f[7]);
227d9306527SDavid du Colombier *xtime = parsedatev(&f[8]);
2287dd7cddfSDavid du Colombier return 1;
2297dd7cddfSDavid du Colombier }
2307dd7cddfSDavid du Colombier
2317dd7cddfSDavid du Colombier int
logrecv(char ** sender,ulong * xtime)232d9306527SDavid du Colombier logrecv(char **sender, ulong *xtime)
2337dd7cddfSDavid du Colombier {
2347dd7cddfSDavid du Colombier char buf[4096];
2357dd7cddfSDavid du Colombier
2367dd7cddfSDavid du Colombier for(;;){
2377dd7cddfSDavid du Colombier if(getline(buf, sizeof buf) == nil)
2387dd7cddfSDavid du Colombier return 0;
239d9306527SDavid du Colombier if(parselog(buf, sender, xtime))
2407dd7cddfSDavid du Colombier return 1;
2417dd7cddfSDavid du Colombier }
2427dd7cddfSDavid du Colombier }
2437dd7cddfSDavid du Colombier
2447dd7cddfSDavid du Colombier char*
tweakdate(char * d)2457dd7cddfSDavid du Colombier tweakdate(char *d)
2467dd7cddfSDavid du Colombier {
2477dd7cddfSDavid du Colombier char e[8];
2487dd7cddfSDavid du Colombier
2497dd7cddfSDavid du Colombier /* d, date = "Mon Aug 2 23:46:55 EDT 1999" */
2509a747e4fSDavid du Colombier
2519a747e4fSDavid du Colombier if(strlen(d) < strlen("Mon Aug 2 23:46:55 EDT 1999"))
2529a747e4fSDavid du Colombier return estrdup("");
2537dd7cddfSDavid du Colombier if(strncmp(date, d, 4+4+3) == 0)
25459cc4ca5SDavid du Colombier snprint(e, sizeof e, "%.5s", d+4+4+3); /* 23:46 */
2557dd7cddfSDavid du Colombier else
25659cc4ca5SDavid du Colombier snprint(e, sizeof e, "%.6s", d+4); /* Aug 2 */
2577dd7cddfSDavid du Colombier return estrdup(e);
2587dd7cddfSDavid du Colombier }
2597dd7cddfSDavid du Colombier
2607dd7cddfSDavid du Colombier Face*
nextface(void)2617dd7cddfSDavid du Colombier nextface(void)
2627dd7cddfSDavid du Colombier {
2635fab9909SDavid du Colombier int i;
2647dd7cddfSDavid du Colombier Face *f;
2657dd7cddfSDavid du Colombier Plumbmsg *m;
266d9306527SDavid du Colombier char *t, *senderp, *showmailp, *digestp;
267d9306527SDavid du Colombier ulong xtime;
2687dd7cddfSDavid du Colombier
2697dd7cddfSDavid du Colombier f = emalloc(sizeof(Face));
2707dd7cddfSDavid du Colombier for(;;){
2717dd7cddfSDavid du Colombier if(seefd >= 0){
2727dd7cddfSDavid du Colombier m = plumbrecv(seefd);
2737dd7cddfSDavid du Colombier if(m == nil)
2747dd7cddfSDavid du Colombier killall("error on seemail plumb port");
2757dd7cddfSDavid du Colombier t = value(m->attr, "mailtype", "");
276*a3b78ba5SDavid du Colombier if(strcmp(t, "delete") == 0)
2777dd7cddfSDavid du Colombier delete(m->data, value(m->attr, "digest", nil));
278*a3b78ba5SDavid du Colombier else if(strcmp(t, "new") != 0)
2797dd7cddfSDavid du Colombier fprint(2, "faces: unknown plumb message type %s\n", t);
280*a3b78ba5SDavid du Colombier else for(i=0; i<nmaildirs; i++)
2816b6b9ac8SDavid du Colombier if(strncmp(m->data, maildirs[i], strlen(maildirs[i])) == 0)
2825fab9909SDavid du Colombier goto Found;
2837dd7cddfSDavid du Colombier plumbfree(m);
2847dd7cddfSDavid du Colombier continue;
2855fab9909SDavid du Colombier
2865fab9909SDavid du Colombier Found:
287d9306527SDavid du Colombier xtime = parsedate(value(m->attr, "date", date));
2887dd7cddfSDavid du Colombier digestp = value(m->attr, "digest", nil);
289d9306527SDavid du Colombier if(alreadyseen(digestp)){
2907dd7cddfSDavid du Colombier /* duplicate upas/fs can send duplicate messages */
2917dd7cddfSDavid du Colombier plumbfree(m);
2927dd7cddfSDavid du Colombier continue;
2937dd7cddfSDavid du Colombier }
2947dd7cddfSDavid du Colombier senderp = estrdup(value(m->attr, "sender", "???"));
2957dd7cddfSDavid du Colombier showmailp = estrdup(m->data);
2967dd7cddfSDavid du Colombier if(digestp)
2977dd7cddfSDavid du Colombier digestp = estrdup(digestp);
2987dd7cddfSDavid du Colombier plumbfree(m);
2997dd7cddfSDavid du Colombier }else{
300d9306527SDavid du Colombier if(logrecv(&senderp, &xtime) <= 0)
3017dd7cddfSDavid du Colombier killall("error reading log file");
3027dd7cddfSDavid du Colombier showmailp = estrdup("");
3037dd7cddfSDavid du Colombier digestp = nil;
3047dd7cddfSDavid du Colombier }
3057dd7cddfSDavid du Colombier setname(f, senderp);
306d9306527SDavid du Colombier f->time = xtime;
307d9306527SDavid du Colombier f->tm = *localtime(xtime);
3087dd7cddfSDavid du Colombier f->str[Sshow] = showmailp;
3097dd7cddfSDavid du Colombier f->str[Sdigest] = digestp;
3107dd7cddfSDavid du Colombier return f;
3117dd7cddfSDavid du Colombier }
3127dd7cddfSDavid du Colombier }
3137dd7cddfSDavid du Colombier
3147dd7cddfSDavid du Colombier char*
iline(char * data,char ** pp)3157dd7cddfSDavid du Colombier iline(char *data, char **pp)
3167dd7cddfSDavid du Colombier {
3177dd7cddfSDavid du Colombier char *p;
3187dd7cddfSDavid du Colombier
3197dd7cddfSDavid du Colombier for(p=data; *p!='\0' && *p!='\n'; p++)
3207dd7cddfSDavid du Colombier ;
3217dd7cddfSDavid du Colombier if(*p == '\n')
3227dd7cddfSDavid du Colombier *p++ = '\0';
3237dd7cddfSDavid du Colombier *pp = p;
3247dd7cddfSDavid du Colombier return data;
3257dd7cddfSDavid du Colombier }
3267dd7cddfSDavid du Colombier
3277dd7cddfSDavid du Colombier Face*
dirface(char * dir,char * num)3287dd7cddfSDavid du Colombier dirface(char *dir, char *num)
3297dd7cddfSDavid du Colombier {
3307dd7cddfSDavid du Colombier Face *f;
3317dd7cddfSDavid du Colombier char *from, *date;
3329a747e4fSDavid du Colombier char buf[1024], pwd[1024], *info, *p, *digest;
3337dd7cddfSDavid du Colombier int n, fd;
3349a747e4fSDavid du Colombier ulong len;
3357dd7cddfSDavid du Colombier
3367dd7cddfSDavid du Colombier /*
3377dd7cddfSDavid du Colombier * loadmbox leaves us in maildir, so we needn't
3387dd7cddfSDavid du Colombier * walk /mail/fs/mbox for each face; this makes startup
3397dd7cddfSDavid du Colombier * a fair bit quicker.
3407dd7cddfSDavid du Colombier */
3417dd7cddfSDavid du Colombier if(getwd(pwd, sizeof pwd) != nil && strcmp(pwd, dir) == 0)
3427dd7cddfSDavid du Colombier sprint(buf, "%s/info", num);
3437dd7cddfSDavid du Colombier else
3447dd7cddfSDavid du Colombier sprint(buf, "%s/%s/info", dir, num);
3459a747e4fSDavid du Colombier len = dirlen(buf);
3469a747e4fSDavid du Colombier if(len <= 0)
3479a747e4fSDavid du Colombier return nil;
3487dd7cddfSDavid du Colombier fd = open(buf, OREAD);
3497dd7cddfSDavid du Colombier if(fd < 0)
3507dd7cddfSDavid du Colombier return nil;
3519a747e4fSDavid du Colombier info = emalloc(len+1);
3529a747e4fSDavid du Colombier n = readn(fd, info, len);
3537dd7cddfSDavid du Colombier close(fd);
3549a747e4fSDavid du Colombier if(n < 0){
3559a747e4fSDavid du Colombier free(info);
3567dd7cddfSDavid du Colombier return nil;
3579a747e4fSDavid du Colombier }
3587dd7cddfSDavid du Colombier info[n] = '\0';
3597dd7cddfSDavid du Colombier f = emalloc(sizeof(Face));
3607dd7cddfSDavid du Colombier from = iline(info, &p); /* from */
3617dd7cddfSDavid du Colombier iline(p, &p); /* to */
3627dd7cddfSDavid du Colombier iline(p, &p); /* cc */
3637dd7cddfSDavid du Colombier iline(p, &p); /* replyto */
3647dd7cddfSDavid du Colombier date = iline(p, &p); /* date */
3657dd7cddfSDavid du Colombier setname(f, estrdup(from));
366d9306527SDavid du Colombier f->time = parsedate(date);
367d9306527SDavid du Colombier f->tm = *localtime(f->time);
3687dd7cddfSDavid du Colombier sprint(buf, "%s/%s", dir, num);
3697dd7cddfSDavid du Colombier f->str[Sshow] = estrdup(buf);
3707dd7cddfSDavid du Colombier iline(p, &p); /* subject */
3717dd7cddfSDavid du Colombier iline(p, &p); /* mime content type */
3727dd7cddfSDavid du Colombier iline(p, &p); /* mime disposition */
3737dd7cddfSDavid du Colombier iline(p, &p); /* filename */
3747dd7cddfSDavid du Colombier digest = iline(p, &p); /* digest */
3757dd7cddfSDavid du Colombier f->str[Sdigest] = estrdup(digest);
3769a747e4fSDavid du Colombier free(info);
3777dd7cddfSDavid du Colombier return f;
3787dd7cddfSDavid du Colombier }
379