initial faces (John Cummings)
This commit is contained in:
parent
663ddde9d0
commit
b330c942b4
7 changed files with 1909 additions and 0 deletions
30
src/cmd/faces/dblook.c
Normal file
30
src/cmd/faces/dblook.c
Normal file
|
|
@ -0,0 +1,30 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include <plumb.h>
|
||||||
|
#include <regexp.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <9pclient.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include "faces.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
threadmain(int argc, char **argv)
|
||||||
|
{
|
||||||
|
Face f;
|
||||||
|
char *q;
|
||||||
|
|
||||||
|
if(argc != 3){
|
||||||
|
fprint(2, "usage: dblook name domain\n");
|
||||||
|
threadexitsall("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
q = findfile(&f, argv[2], argv[1]);
|
||||||
|
print("%s\n", q);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
killall(char *s)
|
||||||
|
{
|
||||||
|
USED(s);
|
||||||
|
}
|
||||||
562
src/cmd/faces/facedb.c
Normal file
562
src/cmd/faces/facedb.c
Normal file
|
|
@ -0,0 +1,562 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include <plumb.h>
|
||||||
|
#include <regexp.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <9pclient.h>
|
||||||
|
#include "faces.h"
|
||||||
|
|
||||||
|
enum /* number of deleted faces to cache */
|
||||||
|
{
|
||||||
|
Nsave = 20,
|
||||||
|
};
|
||||||
|
|
||||||
|
static Facefile *facefiles;
|
||||||
|
static int nsaved;
|
||||||
|
static char *facedom;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loading the files is slow enough on a dial-up line to be worth this trouble
|
||||||
|
*/
|
||||||
|
typedef struct Readcache Readcache;
|
||||||
|
struct Readcache {
|
||||||
|
char *file;
|
||||||
|
char *data;
|
||||||
|
long mtime;
|
||||||
|
long rdtime;
|
||||||
|
Readcache *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Readcache *rcache;
|
||||||
|
|
||||||
|
ulong
|
||||||
|
dirlen(char *s)
|
||||||
|
{
|
||||||
|
Dir *d;
|
||||||
|
ulong len;
|
||||||
|
|
||||||
|
d = dirstat(s);
|
||||||
|
if(d == nil)
|
||||||
|
return 0;
|
||||||
|
len = d->length;
|
||||||
|
free(d);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong
|
||||||
|
fsdirlen(CFsys *fs,char *s)
|
||||||
|
{
|
||||||
|
Dir *d;
|
||||||
|
ulong len;
|
||||||
|
|
||||||
|
d = fsdirstat(fs,s);
|
||||||
|
if(d == nil)
|
||||||
|
return 0;
|
||||||
|
len = d->length;
|
||||||
|
free(d);
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong
|
||||||
|
dirmtime(char *s)
|
||||||
|
{
|
||||||
|
Dir *d;
|
||||||
|
ulong t;
|
||||||
|
|
||||||
|
d = dirstat(s);
|
||||||
|
if(d == nil)
|
||||||
|
return 0;
|
||||||
|
t = d->mtime;
|
||||||
|
free(d);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
doreadfile(char *s)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
int fd, n;
|
||||||
|
ulong len;
|
||||||
|
|
||||||
|
len = dirlen(s);
|
||||||
|
if(len == 0)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
p = malloc(len+1);
|
||||||
|
if(p == nil)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
if((fd = open(s, OREAD)) < 0
|
||||||
|
|| (n = readn(fd, p, len)) < 0) {
|
||||||
|
close(fd);
|
||||||
|
free(p);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
p[n] = '\0';
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
readfile(char *s)
|
||||||
|
{
|
||||||
|
Readcache *r, **l;
|
||||||
|
char *p;
|
||||||
|
ulong mtime;
|
||||||
|
|
||||||
|
for(l=&rcache, r=*l; r; l=&r->next, r=*l) {
|
||||||
|
if(strcmp(r->file, s) != 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if it's less than 30 seconds since we read it, or it
|
||||||
|
* hasn't changed, send back our copy
|
||||||
|
*/
|
||||||
|
if(time(0) - r->rdtime < 30)
|
||||||
|
return strdup(r->data);
|
||||||
|
if(dirmtime(s) == r->mtime) {
|
||||||
|
r->rdtime = time(0);
|
||||||
|
return strdup(r->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* out of date, remove this and fall out of loop */
|
||||||
|
*l = r->next;
|
||||||
|
free(r->file);
|
||||||
|
free(r->data);
|
||||||
|
free(r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* add to cache */
|
||||||
|
mtime = dirmtime(s);
|
||||||
|
if(mtime == 0)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
if((p = doreadfile(s)) == nil)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
r = malloc(sizeof(*r));
|
||||||
|
if(r == nil)
|
||||||
|
return nil;
|
||||||
|
r->mtime = mtime;
|
||||||
|
r->file = estrdup(s);
|
||||||
|
r->data = p;
|
||||||
|
r->rdtime = time(0);
|
||||||
|
r->next = rcache;
|
||||||
|
rcache = r;
|
||||||
|
return strdup(r->data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static char*
|
||||||
|
translatedomain(char *dom)
|
||||||
|
{
|
||||||
|
static char buf[200];
|
||||||
|
char *p, *ep, *q, *nextp, *file;
|
||||||
|
char *bbuf, *ebuf;
|
||||||
|
Reprog *exp;
|
||||||
|
|
||||||
|
if(dom == nil || *dom == 0)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
if((file = readfile(unsharp("#9/lib/face/.machinelist"))) == nil)
|
||||||
|
return dom;
|
||||||
|
|
||||||
|
for(p=file; p; p=nextp) {
|
||||||
|
if(nextp = strchr(p, '\n'))
|
||||||
|
*nextp++ = '\0';
|
||||||
|
|
||||||
|
if(*p == '#' || (q = strpbrk(p, " \t")) == nil || q-p > sizeof(buf)-2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bbuf = buf+1;
|
||||||
|
ebuf = buf+(1+(q-p));
|
||||||
|
strncpy(bbuf, p, ebuf-bbuf);
|
||||||
|
*ebuf = 0;
|
||||||
|
if(*bbuf != '^')
|
||||||
|
*--bbuf = '^';
|
||||||
|
if(ebuf[-1] != '$') {
|
||||||
|
*ebuf++ = '$';
|
||||||
|
*ebuf = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((exp = regcomp(bbuf)) == nil){
|
||||||
|
fprint(2, "bad regexp in machinelist: %s\n", bbuf);
|
||||||
|
killall("regexp");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(regexec(exp, dom, 0, 0)){
|
||||||
|
free(exp);
|
||||||
|
ep = p+strlen(p);
|
||||||
|
q += strspn(q, " \t");
|
||||||
|
if(ep-q+2 > sizeof buf) {
|
||||||
|
fprint(2, "huge replacement in machinelist: %.*s\n", utfnlen(q, ep-q), q);
|
||||||
|
exits("bad big replacement");
|
||||||
|
}
|
||||||
|
strncpy(buf, q, ep-q);
|
||||||
|
ebuf = buf+(ep-q);
|
||||||
|
*ebuf = 0;
|
||||||
|
while(ebuf > buf && (ebuf[-1] == ' ' || ebuf[-1] == '\t'))
|
||||||
|
*--ebuf = 0;
|
||||||
|
free(file);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
free(exp);
|
||||||
|
}
|
||||||
|
free(file);
|
||||||
|
|
||||||
|
return dom;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
tryfindpicture_user(char *dom, char *user, int depth)
|
||||||
|
{
|
||||||
|
static char buf[200];
|
||||||
|
char *p, *q, *nextp, *file, *usr;
|
||||||
|
usr = getuser();
|
||||||
|
|
||||||
|
sprint(buf, "/usr/%s/lib/face/48x48x%d/.dict", usr, depth);
|
||||||
|
if((file = readfile(buf)) == nil)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
snprint(buf, sizeof buf, "%s/%s", dom, user);
|
||||||
|
|
||||||
|
for(p=file; p; p=nextp) {
|
||||||
|
if(nextp = strchr(p, '\n'))
|
||||||
|
*nextp++ = '\0';
|
||||||
|
|
||||||
|
if(*p == '#' || (q = strpbrk(p, " \t")) == nil)
|
||||||
|
continue;
|
||||||
|
*q++ = 0;
|
||||||
|
|
||||||
|
if(strcmp(buf, p) == 0) {
|
||||||
|
q += strspn(q, " \t");
|
||||||
|
q = buf+snprint(buf, sizeof buf, "/usr/%s/lib/face/48x48x%d/%s", usr, depth, q);
|
||||||
|
while(q > buf && (q[-1] == ' ' || q[-1] == '\t'))
|
||||||
|
*--q = 0;
|
||||||
|
free(file);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(file);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
tryfindpicture_global(char *dom, char *user, int depth)
|
||||||
|
{
|
||||||
|
static char buf[200];
|
||||||
|
char *p, *q, *nextp, *file;
|
||||||
|
|
||||||
|
sprint(buf, "#9/lib/face/48x48x%d/.dict", depth);
|
||||||
|
if((file = readfile(unsharp(buf))) == nil)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
snprint(buf, sizeof buf, "%s/%s", dom, user);
|
||||||
|
|
||||||
|
for(p=file; p; p=nextp) {
|
||||||
|
if(nextp = strchr(p, '\n'))
|
||||||
|
*nextp++ = '\0';
|
||||||
|
|
||||||
|
if(*p == '#' || (q = strpbrk(p, " \t")) == nil)
|
||||||
|
continue;
|
||||||
|
*q++ = 0;
|
||||||
|
|
||||||
|
if(strcmp(buf, p) == 0) {
|
||||||
|
q += strspn(q, " \t");
|
||||||
|
q = buf+snprint(buf, sizeof buf, "#9/lib/face/48x48x%d/%s", depth, q);
|
||||||
|
while(q > buf && (q[-1] == ' ' || q[-1] == '\t'))
|
||||||
|
*--q = 0;
|
||||||
|
free(file);
|
||||||
|
return unsharp(buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(file);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
tryfindpicture(char *dom, char *user, int depth)
|
||||||
|
{
|
||||||
|
char* result;
|
||||||
|
|
||||||
|
if((result = tryfindpicture_user(dom, user, depth)) != nil)
|
||||||
|
return result;
|
||||||
|
|
||||||
|
return tryfindpicture_global(dom, user, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
tryfindfile(char *dom, char *user, int depth)
|
||||||
|
{
|
||||||
|
char *p, *q;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
for(p=dom; p; (p=strchr(p, '.')) && p++)
|
||||||
|
if(q = tryfindpicture(p, user, depth))
|
||||||
|
return q;
|
||||||
|
depth >>= 1;
|
||||||
|
if(depth == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
findfile(Face *f, char *dom, char *user)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
int depth;
|
||||||
|
|
||||||
|
if(facedom == nil){
|
||||||
|
facedom = getenv("facedom");
|
||||||
|
if(facedom == nil)
|
||||||
|
facedom = DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
dom = translatedomain(dom);
|
||||||
|
if(dom == nil)
|
||||||
|
dom = facedom;
|
||||||
|
|
||||||
|
if(screen == nil)
|
||||||
|
depth = 8;
|
||||||
|
else
|
||||||
|
depth = screen->depth;
|
||||||
|
|
||||||
|
if(depth > 8)
|
||||||
|
depth = 8;
|
||||||
|
|
||||||
|
f->unknown = 0;
|
||||||
|
if(p = tryfindfile(dom, user, depth))
|
||||||
|
return p;
|
||||||
|
f->unknown = 1;
|
||||||
|
p = tryfindfile(dom, "unknown", depth);
|
||||||
|
if(p != nil || strcmp(dom, facedom)==0)
|
||||||
|
return p;
|
||||||
|
return tryfindfile("unknown", "unknown", depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
clearsaved(void)
|
||||||
|
{
|
||||||
|
Facefile *f, *next, **lf;
|
||||||
|
|
||||||
|
lf = &facefiles;
|
||||||
|
for(f=facefiles; f!=nil; f=next){
|
||||||
|
next = f->next;
|
||||||
|
if(f->ref > 0){
|
||||||
|
*lf = f;
|
||||||
|
lf = &(f->next);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(f->image != display->black && f->image != display->white)
|
||||||
|
freeimage(f->image);
|
||||||
|
free(f->file);
|
||||||
|
free(f);
|
||||||
|
}
|
||||||
|
*lf = nil;
|
||||||
|
nsaved = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freefacefile(Facefile *f)
|
||||||
|
{
|
||||||
|
if(f==nil || f->ref-->1)
|
||||||
|
return;
|
||||||
|
if(++nsaved > Nsave)
|
||||||
|
clearsaved();
|
||||||
|
}
|
||||||
|
|
||||||
|
static Image*
|
||||||
|
myallocimage(ulong chan)
|
||||||
|
{
|
||||||
|
Image *img;
|
||||||
|
img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, DNofill);
|
||||||
|
if(img == nil){
|
||||||
|
clearsaved();
|
||||||
|
img = allocimage(display, Rect(0,0,Facesize,Facesize), chan, 0, DNofill);
|
||||||
|
if(img == nil)
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static Image*
|
||||||
|
readbit(int fd, ulong chan)
|
||||||
|
{
|
||||||
|
char buf[4096], hx[4], *p;
|
||||||
|
uchar data[Facesize*Facesize]; /* more than enough */
|
||||||
|
int nhx, i, n, ndata, nbit;
|
||||||
|
Image *img;
|
||||||
|
|
||||||
|
n = readn(fd, buf, sizeof buf);
|
||||||
|
if(n <= 0)
|
||||||
|
return nil;
|
||||||
|
if(n >= sizeof buf)
|
||||||
|
n = sizeof(buf)-1;
|
||||||
|
buf[n] = '\0';
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
nhx = 0;
|
||||||
|
nbit = chantodepth(chan);
|
||||||
|
ndata = (Facesize*Facesize*nbit)/8;
|
||||||
|
p = buf;
|
||||||
|
while(n < ndata) {
|
||||||
|
p = strpbrk(p+1, "0123456789abcdefABCDEF");
|
||||||
|
if(p == nil)
|
||||||
|
break;
|
||||||
|
if(p[0] == '0' && p[1] == 'x')
|
||||||
|
continue;
|
||||||
|
|
||||||
|
hx[nhx] = *p;
|
||||||
|
if(++nhx == 2) {
|
||||||
|
hx[nhx] = 0;
|
||||||
|
i = strtoul(hx, 0, 16);
|
||||||
|
data[n++] = i;
|
||||||
|
nhx = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(n < ndata)
|
||||||
|
return allocimage(display, Rect(0,0,Facesize,Facesize), CMAP8, 0, 0x88888888);
|
||||||
|
|
||||||
|
img = myallocimage(chan);
|
||||||
|
if(img == nil)
|
||||||
|
return nil;
|
||||||
|
loadimage(img, img->r, data, ndata);
|
||||||
|
return img;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Facefile*
|
||||||
|
readface(char *fn)
|
||||||
|
{
|
||||||
|
int x, y, fd;
|
||||||
|
uchar bits;
|
||||||
|
uchar *p;
|
||||||
|
Image *mask;
|
||||||
|
Image *face;
|
||||||
|
char buf[16];
|
||||||
|
uchar data[Facesize*Facesize];
|
||||||
|
uchar mdata[(Facesize*Facesize)/8];
|
||||||
|
Facefile *f;
|
||||||
|
Dir *d;
|
||||||
|
|
||||||
|
for(f=facefiles; f!=nil; f=f->next){
|
||||||
|
if(strcmp(fn, f->file) == 0){
|
||||||
|
if(f->image == nil)
|
||||||
|
break;
|
||||||
|
if(time(0) - f->rdtime >= 30) {
|
||||||
|
if(dirmtime(fn) != f->mtime){
|
||||||
|
f = nil;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
f->rdtime = time(0);
|
||||||
|
}
|
||||||
|
f->ref++;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((fd = open(fn, OREAD)) < 0)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
if(readn(fd, buf, sizeof buf) != sizeof buf){
|
||||||
|
close(fd);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
seek(fd, 0, 0);
|
||||||
|
|
||||||
|
mask = nil;
|
||||||
|
if(buf[0] == '0' && buf[1] == 'x'){
|
||||||
|
/* greyscale faces are just masks that we draw black through! */
|
||||||
|
if(buf[2+8] == ',') /* ldepth 1 */
|
||||||
|
mask = readbit(fd, GREY2);
|
||||||
|
else
|
||||||
|
mask = readbit(fd, GREY1);
|
||||||
|
face = display->black;
|
||||||
|
}else{
|
||||||
|
face = readimage(display, fd, 0);
|
||||||
|
if(face == nil)
|
||||||
|
goto Done;
|
||||||
|
else if(face->chan == GREY4 || face->chan == GREY8){ /* greyscale: use inversion as mask */
|
||||||
|
mask = myallocimage(face->chan);
|
||||||
|
/* okay if mask is nil: that will copy the image white background and all */
|
||||||
|
if(mask == nil)
|
||||||
|
goto Done;
|
||||||
|
|
||||||
|
/* invert greyscale image */
|
||||||
|
draw(mask, mask->r, display->white, nil, ZP);
|
||||||
|
gendraw(mask, mask->r, display->black, ZP, face, face->r.min);
|
||||||
|
freeimage(face);
|
||||||
|
face = display->black;
|
||||||
|
}else if(face->depth == 8){ /* snarf the bytes back and do a fill. */
|
||||||
|
mask = myallocimage(GREY1);
|
||||||
|
if(mask == nil)
|
||||||
|
goto Done;
|
||||||
|
if(unloadimage(face, face->r, data, Facesize*Facesize) != Facesize*Facesize){
|
||||||
|
freeimage(mask);
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
bits = 0;
|
||||||
|
p = mdata;
|
||||||
|
for(y=0; y<Facesize; y++){
|
||||||
|
for(x=0; x<Facesize; x++){
|
||||||
|
bits <<= 1;
|
||||||
|
if(data[Facesize*y+x] != 0xFF)
|
||||||
|
bits |= 1;
|
||||||
|
if((x&7) == 7)
|
||||||
|
*p++ = bits&0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(loadimage(mask, mask->r, mdata, sizeof mdata) != sizeof mdata){
|
||||||
|
freeimage(mask);
|
||||||
|
goto Done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Done:
|
||||||
|
/* always add at beginning of list, so updated files don't collide in cache */
|
||||||
|
if(f == nil){
|
||||||
|
f = emalloc(sizeof(Facefile));
|
||||||
|
f->file = estrdup(fn);
|
||||||
|
d = dirfstat(fd);
|
||||||
|
if(d != nil){
|
||||||
|
f->mtime = d->mtime;
|
||||||
|
free(d);
|
||||||
|
}
|
||||||
|
f->next = facefiles;
|
||||||
|
facefiles = f;
|
||||||
|
}
|
||||||
|
f->ref++;
|
||||||
|
f->image = face;
|
||||||
|
f->mask = mask;
|
||||||
|
f->rdtime = time(0);
|
||||||
|
close(fd);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
findbit(Face *f)
|
||||||
|
{
|
||||||
|
char *fn;
|
||||||
|
|
||||||
|
fn = findfile(f, f->str[Sdomain], f->str[Suser]);
|
||||||
|
if(fn) {
|
||||||
|
if(strstr(fn, "unknown"))
|
||||||
|
f->unknown = 1;
|
||||||
|
f->file = readface(fn);
|
||||||
|
}
|
||||||
|
if(f->file){
|
||||||
|
f->bit = f->file->image;
|
||||||
|
f->mask = f->file->mask;
|
||||||
|
}else{
|
||||||
|
/* if returns nil, this is still ok: draw(nil) works */
|
||||||
|
f->bit = allocimage(display, Rect(0,0,1,1), CMAP8, 1, DYellow);
|
||||||
|
replclipr(f->bit, 1, Rect(0, 0, Facesize, Facesize));
|
||||||
|
f->mask = nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
68
src/cmd/faces/faces.h
Normal file
68
src/cmd/faces/faces.h
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
enum /* face strings */
|
||||||
|
{
|
||||||
|
Suser,
|
||||||
|
Sdomain,
|
||||||
|
Sshow,
|
||||||
|
Sdigest,
|
||||||
|
Nstring
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Facesize = 48,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct Face Face;
|
||||||
|
typedef struct Facefile Facefile;
|
||||||
|
|
||||||
|
struct Face
|
||||||
|
{
|
||||||
|
Image *bit; /* unless there's an error, this is file->image */
|
||||||
|
Image *mask; /* unless there's an error, this is file->mask */
|
||||||
|
char *str[Nstring];
|
||||||
|
int recent;
|
||||||
|
ulong time;
|
||||||
|
Tm tm;
|
||||||
|
int unknown;
|
||||||
|
Facefile *file;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loading the files is slow enough on a dial-up line to be worth this trouble
|
||||||
|
*/
|
||||||
|
struct Facefile
|
||||||
|
{
|
||||||
|
Image *image;
|
||||||
|
Image *mask;
|
||||||
|
ulong mtime;
|
||||||
|
ulong rdtime;
|
||||||
|
int ref;
|
||||||
|
char *file;
|
||||||
|
Facefile *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern char date[];
|
||||||
|
extern char *maildir;
|
||||||
|
extern char **maildirs;
|
||||||
|
extern int nmaildirs;
|
||||||
|
extern CFsys *upasfs;
|
||||||
|
|
||||||
|
Face* nextface(void);
|
||||||
|
void findbit(Face*);
|
||||||
|
void freeface(Face*);
|
||||||
|
void initplumb(void);
|
||||||
|
void killall(char*);
|
||||||
|
void showmail(Face*);
|
||||||
|
void delete(char*, char*);
|
||||||
|
void freefacefile(Facefile*);
|
||||||
|
Face* dirface(char*, char*);
|
||||||
|
void resized(void);
|
||||||
|
int alreadyseen(char*);
|
||||||
|
ulong dirlen(char*);
|
||||||
|
ulong fsdirlen(CFsys*, char*);
|
||||||
|
|
||||||
|
void *emalloc(ulong);
|
||||||
|
void *erealloc(void*, ulong);
|
||||||
|
char *estrdup(char*);
|
||||||
|
char *findfile(Face*, char*, char*);
|
||||||
|
void addmaildir(char*);
|
||||||
783
src/cmd/faces/main.c
Normal file
783
src/cmd/faces/main.c
Normal file
|
|
@ -0,0 +1,783 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include <plumb.h>
|
||||||
|
#include <regexp.h>
|
||||||
|
//jpc #include <event.h> /* for support routines only */
|
||||||
|
#include <bio.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <mouse.h>
|
||||||
|
#include <cursor.h>
|
||||||
|
#include <9pclient.h>
|
||||||
|
#include "faces.h"
|
||||||
|
|
||||||
|
int history = 0; /* use old interface, showing history of mailbox rather than current state */
|
||||||
|
int initload = 0; /* initialize program with contents of mail box */
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Facesep = 6, /* must be even to avoid damaging background stipple */
|
||||||
|
Infolines = 9,
|
||||||
|
|
||||||
|
HhmmTime = 18*60*60, /* max age of face to display hh:mm time */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Mainp,
|
||||||
|
Timep,
|
||||||
|
Mousep,
|
||||||
|
NPROC
|
||||||
|
};
|
||||||
|
|
||||||
|
int pids[NPROC];
|
||||||
|
char *procnames[] = {
|
||||||
|
"main",
|
||||||
|
"time",
|
||||||
|
"mouse"
|
||||||
|
};
|
||||||
|
|
||||||
|
Rectangle leftright = {0, 0, 20, 15};
|
||||||
|
|
||||||
|
uchar leftdata[] = {
|
||||||
|
0x00, 0x80, 0x00, 0x01, 0x80, 0x00, 0x03, 0x80,
|
||||||
|
0x00, 0x07, 0x80, 0x00, 0x0f, 0x00, 0x00, 0x1f,
|
||||||
|
0xff, 0xf0, 0x3f, 0xff, 0xf0, 0xff, 0xff, 0xf0,
|
||||||
|
0x3f, 0xff, 0xf0, 0x1f, 0xff, 0xf0, 0x0f, 0x00,
|
||||||
|
0x00, 0x07, 0x80, 0x00, 0x03, 0x80, 0x00, 0x01,
|
||||||
|
0x80, 0x00, 0x00, 0x80, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
uchar rightdata[] = {
|
||||||
|
0x00, 0x10, 0x00, 0x00, 0x18, 0x00, 0x00, 0x1c,
|
||||||
|
0x00, 0x00, 0x1e, 0x00, 0x00, 0x0f, 0x00, 0xff,
|
||||||
|
0xff, 0x80, 0xff, 0xff, 0xc0, 0xff, 0xff, 0xf0,
|
||||||
|
0xff, 0xff, 0xc0, 0xff, 0xff, 0x80, 0x00, 0x0f,
|
||||||
|
0x00, 0x00, 0x1e, 0x00, 0x00, 0x1c, 0x00, 0x00,
|
||||||
|
0x18, 0x00, 0x00, 0x10, 0x00
|
||||||
|
};
|
||||||
|
|
||||||
|
CFsys *upasfs;
|
||||||
|
Mousectl *mousectl;
|
||||||
|
Image *blue; /* full arrow */
|
||||||
|
Image *bgrnd; /* pale blue background color */
|
||||||
|
Image *left; /* left-pointing arrow mask */
|
||||||
|
Image *right; /* right-pointing arrow mask */
|
||||||
|
Font *tinyfont;
|
||||||
|
Font *mediumfont;
|
||||||
|
Font *datefont;
|
||||||
|
int first, last; /* first and last visible face; last is first invisible */
|
||||||
|
int nfaces;
|
||||||
|
int mousefd;
|
||||||
|
int nacross;
|
||||||
|
int ndown;
|
||||||
|
|
||||||
|
char date[64];
|
||||||
|
Face **faces;
|
||||||
|
char *maildir = "/mail/fs/mbox";
|
||||||
|
ulong now;
|
||||||
|
|
||||||
|
Point datep = { 8, 6 };
|
||||||
|
Point facep = { 8, 6+0+4 }; /* 0 updated to datefont->height in init() */
|
||||||
|
Point enddate; /* where date ends on display; used to place arrows */
|
||||||
|
Rectangle leftr; /* location of left arrow on display */
|
||||||
|
Rectangle rightr; /* location of right arrow on display */
|
||||||
|
void updatetimes(void);
|
||||||
|
|
||||||
|
void
|
||||||
|
setdate(void)
|
||||||
|
{
|
||||||
|
now = time(nil);
|
||||||
|
strcpy(date, ctime(now));
|
||||||
|
date[4+4+3+5] = '\0'; /* change from Thu Jul 22 14:28:43 EDT 1999\n to Thu Jul 22 14:28 */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
init(void)
|
||||||
|
{
|
||||||
|
#if 0
|
||||||
|
mousefd = open("/dev/mouse", OREAD);
|
||||||
|
if(mousefd < 0){
|
||||||
|
fprint(2, "faces: can't open mouse: %r\n");
|
||||||
|
threadexitsall("mouse");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
upasfs = nsmount("upasfs",nil);
|
||||||
|
mousectl = initmouse(nil,screen);
|
||||||
|
initplumb();
|
||||||
|
|
||||||
|
/* make background color */
|
||||||
|
bgrnd = allocimagemix(display, DPalebluegreen, DWhite);
|
||||||
|
blue = allocimage(display, Rect(0,0,1,1), screen->chan, 1, 0x008888FF); /* blue-green */
|
||||||
|
left = allocimage(display, leftright, GREY1, 0, DWhite);
|
||||||
|
right = allocimage(display, leftright, GREY1, 0, DWhite);
|
||||||
|
if(bgrnd==nil || blue==nil || left==nil || right==nil){
|
||||||
|
fprint(2, "faces: can't create images: %r\n");
|
||||||
|
threadexitsall("image");
|
||||||
|
}
|
||||||
|
|
||||||
|
loadimage(left, leftright, leftdata, sizeof leftdata);
|
||||||
|
loadimage(right, leftright, rightdata, sizeof rightdata);
|
||||||
|
|
||||||
|
/* initialize little fonts */
|
||||||
|
tinyfont = openfont(display, "/lib/font/bit/misc/ascii.5x7.font");
|
||||||
|
if(tinyfont == nil)
|
||||||
|
tinyfont = font;
|
||||||
|
mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font");
|
||||||
|
if(mediumfont == nil)
|
||||||
|
mediumfont = font;
|
||||||
|
datefont = font;
|
||||||
|
|
||||||
|
facep.y += datefont->height;
|
||||||
|
if(datefont->height & 1) /* stipple parity */
|
||||||
|
facep.y++;
|
||||||
|
faces = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drawtime(void)
|
||||||
|
{
|
||||||
|
Rectangle r;
|
||||||
|
|
||||||
|
r.min = addpt(screen->r.min, datep);
|
||||||
|
if(eqpt(enddate, ZP)){
|
||||||
|
enddate = r.min;
|
||||||
|
enddate.x += stringwidth(datefont, "Wed May 30 22:54"); /* nice wide string */
|
||||||
|
enddate.x += Facesep; /* for safety */
|
||||||
|
}
|
||||||
|
r.max.x = enddate.x;
|
||||||
|
r.max.y = enddate.y+datefont->height;
|
||||||
|
draw(screen, r, bgrnd, nil, ZP);
|
||||||
|
string(screen, r.min, display->black, ZP, datefont, date);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
timeproc(void *dummy)
|
||||||
|
{
|
||||||
|
for(;;){
|
||||||
|
lockdisplay(display);
|
||||||
|
drawtime();
|
||||||
|
updatetimes();
|
||||||
|
flushimage(display, 1);
|
||||||
|
unlockdisplay(display);
|
||||||
|
sleep(60000);
|
||||||
|
setdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
alreadyseen(char *digest)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Face *f;
|
||||||
|
|
||||||
|
if(!digest)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* can do accurate check */
|
||||||
|
for(i=0; i<nfaces; i++){
|
||||||
|
f = faces[i];
|
||||||
|
if(f->str[Sdigest]!=nil && strcmp(digest, f->str[Sdigest])==0)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
torune(Rune *r, char *s, int nr)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<nr-1 && *s!='\0'; i++)
|
||||||
|
s += chartorune(r+i, s);
|
||||||
|
r[i] = L'\0';
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
center(Font *f, Point p, char *s, Image *color)
|
||||||
|
{
|
||||||
|
int i, n, dx;
|
||||||
|
Rune rbuf[32];
|
||||||
|
char sbuf[32*UTFmax+1];
|
||||||
|
|
||||||
|
dx = stringwidth(f, s);
|
||||||
|
if(dx > Facesize){
|
||||||
|
n = torune(rbuf, s, nelem(rbuf));
|
||||||
|
for(i=0; i<n; i++){
|
||||||
|
dx = runestringnwidth(f, rbuf, i+1);
|
||||||
|
if(dx > Facesize)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sprint(sbuf, "%.*S", i, rbuf);
|
||||||
|
s = sbuf;
|
||||||
|
dx = stringwidth(f, s);
|
||||||
|
}
|
||||||
|
p.x += (Facesize-dx)/2;
|
||||||
|
string(screen, p, color, ZP, f, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle
|
||||||
|
facerect(int index) /* index is geometric; 0 is always upper left face */
|
||||||
|
{
|
||||||
|
Rectangle r;
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
x = index % nacross;
|
||||||
|
y = index / nacross;
|
||||||
|
r.min = addpt(screen->r.min, facep);
|
||||||
|
r.min.x += x*(Facesize+Facesep);
|
||||||
|
r.min.y += y*(Facesize+Facesep+2*mediumfont->height);
|
||||||
|
r.max = addpt(r.min, Pt(Facesize, Facesize));
|
||||||
|
r.max.y += 2*mediumfont->height;
|
||||||
|
/* simple fix to avoid drawing off screen, allowing customers to use position */
|
||||||
|
if(index<0 || index>=nacross*ndown)
|
||||||
|
r.max.x = r.min.x;
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *mon = "JanFebMarAprMayJunJulAugSepOctNovDec";
|
||||||
|
char*
|
||||||
|
facetime(Face *f, int *recent)
|
||||||
|
{
|
||||||
|
static char buf[30];
|
||||||
|
|
||||||
|
if((long)(now - f->time) > HhmmTime){
|
||||||
|
*recent = 0;
|
||||||
|
sprint(buf, "%.3s %2d", mon+3*f->tm.mon, f->tm.mday);
|
||||||
|
return buf;
|
||||||
|
}else{
|
||||||
|
*recent = 1;
|
||||||
|
sprint(buf, "%02d:%02d", f->tm.hour, f->tm.min);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drawface(Face *f, int i)
|
||||||
|
{
|
||||||
|
char *tstr;
|
||||||
|
Rectangle r;
|
||||||
|
Point p;
|
||||||
|
|
||||||
|
if(f == nil)
|
||||||
|
return;
|
||||||
|
if(i<first || i>=last)
|
||||||
|
return;
|
||||||
|
r = facerect(i-first);
|
||||||
|
draw(screen, r, bgrnd, nil, ZP);
|
||||||
|
draw(screen, r, f->bit, f->mask, ZP);
|
||||||
|
r.min.y += Facesize;
|
||||||
|
center(mediumfont, r.min, f->str[Suser], display->black);
|
||||||
|
r.min.y += mediumfont->height;
|
||||||
|
tstr = facetime(f, &f->recent);
|
||||||
|
center(mediumfont, r.min, tstr, display->black);
|
||||||
|
if(f->unknown){
|
||||||
|
r.min.y -= mediumfont->height + tinyfont->height + 2;
|
||||||
|
for(p.x=-1; p.x<=1; p.x++)
|
||||||
|
for(p.y=-1; p.y<=1; p.y++)
|
||||||
|
center(tinyfont, addpt(r.min, p), f->str[Sdomain], display->white);
|
||||||
|
center(tinyfont, r.min, f->str[Sdomain], display->black);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
updatetimes(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Face *f;
|
||||||
|
|
||||||
|
for(i=0; i<nfaces; i++){
|
||||||
|
f = faces[i];
|
||||||
|
if(f == nil)
|
||||||
|
continue;
|
||||||
|
if(((long)(now - f->time) <= HhmmTime) != f->recent)
|
||||||
|
drawface(f, i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setlast(void)
|
||||||
|
{
|
||||||
|
last = first+nacross*ndown;
|
||||||
|
if(last > nfaces)
|
||||||
|
last = nfaces;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
drawarrows(void)
|
||||||
|
{
|
||||||
|
Point p;
|
||||||
|
|
||||||
|
p = enddate;
|
||||||
|
p.x += Facesep;
|
||||||
|
if(p.x & 1)
|
||||||
|
p.x++; /* align background texture */
|
||||||
|
leftr = rectaddpt(leftright, p);
|
||||||
|
p.x += Dx(leftright) + Facesep;
|
||||||
|
rightr = rectaddpt(leftright, p);
|
||||||
|
draw(screen, leftr, first>0? blue : bgrnd, left, leftright.min);
|
||||||
|
draw(screen, rightr, last<nfaces? blue : bgrnd, right, leftright.min);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
addface(Face *f) /* always adds at 0 */
|
||||||
|
{
|
||||||
|
Face **ofaces;
|
||||||
|
Rectangle r0, r1, r;
|
||||||
|
int y, nx, ny;
|
||||||
|
|
||||||
|
if(f == nil)
|
||||||
|
return;
|
||||||
|
lockdisplay(display);
|
||||||
|
if(first != 0){
|
||||||
|
first = 0;
|
||||||
|
resized();
|
||||||
|
}
|
||||||
|
findbit(f);
|
||||||
|
|
||||||
|
nx = nacross;
|
||||||
|
ny = (nfaces+(nx-1)) / nx;
|
||||||
|
|
||||||
|
for(y=ny; y>=0; y--){
|
||||||
|
/* move them along */
|
||||||
|
r0 = facerect(y*nx+0);
|
||||||
|
r1 = facerect(y*nx+1);
|
||||||
|
r = r1;
|
||||||
|
r.max.x = r.min.x + (nx - 1)*(Facesize+Facesep);
|
||||||
|
draw(screen, r, screen, nil, r0.min);
|
||||||
|
/* copy one down from row above */
|
||||||
|
if(y != 0){
|
||||||
|
r = facerect((y-1)*nx+nx-1);
|
||||||
|
draw(screen, r0, screen, nil, r.min);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ofaces = faces;
|
||||||
|
faces = emalloc((nfaces+1)*sizeof(Face*));
|
||||||
|
memmove(faces+1, ofaces, nfaces*(sizeof(Face*)));
|
||||||
|
free(ofaces);
|
||||||
|
nfaces++;
|
||||||
|
setlast();
|
||||||
|
drawarrows();
|
||||||
|
faces[0] = f;
|
||||||
|
drawface(f, 0);
|
||||||
|
flushimage(display, 1);
|
||||||
|
unlockdisplay(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
void
|
||||||
|
loadmboxfaces(char *maildir)
|
||||||
|
{
|
||||||
|
int dirfd;
|
||||||
|
Dir *d;
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
dirfd = open(maildir, OREAD);
|
||||||
|
if(dirfd >= 0){
|
||||||
|
chdir(maildir);
|
||||||
|
while((n = dirread(dirfd, &d)) > 0){
|
||||||
|
for(i=0; i<n; i++)
|
||||||
|
addface(dirface(maildir, d[i].name));
|
||||||
|
free(d);
|
||||||
|
}
|
||||||
|
close(dirfd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void
|
||||||
|
loadmboxfaces(char *maildir)
|
||||||
|
{
|
||||||
|
CFid *dirfd;
|
||||||
|
Dir *d;
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
dirfd = fsopen(upasfs,maildir, OREAD);
|
||||||
|
if(dirfd != nil){
|
||||||
|
//jpc chdir(maildir);
|
||||||
|
while((n = fsdirread(dirfd, &d)) > 0){
|
||||||
|
for(i=0; i<n; i++) {
|
||||||
|
addface(dirface(maildir, d[i].name));
|
||||||
|
}
|
||||||
|
free(d);
|
||||||
|
}
|
||||||
|
fsclose(dirfd);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
error("cannot open %s: %r",maildir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freeface(Face *f)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if(f->file!=nil && f->bit!=f->file->image)
|
||||||
|
freeimage(f->bit);
|
||||||
|
freefacefile(f->file);
|
||||||
|
for(i=0; i<Nstring; i++)
|
||||||
|
free(f->str[i]);
|
||||||
|
free(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
delface(int j)
|
||||||
|
{
|
||||||
|
Rectangle r0, r1, r;
|
||||||
|
int nx, ny, x, y;
|
||||||
|
|
||||||
|
if(j < first)
|
||||||
|
first--;
|
||||||
|
else if(j < last){
|
||||||
|
nx = nacross;
|
||||||
|
ny = (nfaces+(nx-1)) / nx;
|
||||||
|
x = (j-first)%nx;
|
||||||
|
for(y=(j-first)/nx; y<ny; y++){
|
||||||
|
if(x != nx-1){
|
||||||
|
/* move them along */
|
||||||
|
r0 = facerect(y*nx+x);
|
||||||
|
r1 = facerect(y*nx+x+1);
|
||||||
|
r = r0;
|
||||||
|
r.max.x = r.min.x + (nx - x - 1)*(Facesize+Facesep);
|
||||||
|
draw(screen, r, screen, nil, r1.min);
|
||||||
|
}
|
||||||
|
if(y != ny-1){
|
||||||
|
/* copy one up from row below */
|
||||||
|
r = facerect((y+1)*nx);
|
||||||
|
draw(screen, facerect(y*nx+nx-1), screen, nil, r.min);
|
||||||
|
}
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
if(last < nfaces) /* first off-screen becomes visible */
|
||||||
|
drawface(faces[last], last-1);
|
||||||
|
else{
|
||||||
|
/* clear final spot */
|
||||||
|
r = facerect(last-first-1);
|
||||||
|
draw(screen, r, bgrnd, nil, r.min);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
freeface(faces[j]);
|
||||||
|
memmove(faces+j, faces+j+1, (nfaces-(j+1))*sizeof(Face*));
|
||||||
|
nfaces--;
|
||||||
|
setlast();
|
||||||
|
drawarrows();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
dodelete(int i)
|
||||||
|
{
|
||||||
|
Face *f;
|
||||||
|
|
||||||
|
f = faces[i];
|
||||||
|
if(history){
|
||||||
|
free(f->str[Sshow]);
|
||||||
|
f->str[Sshow] = estrdup("");
|
||||||
|
}else{
|
||||||
|
delface(i);
|
||||||
|
flushimage(display, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
delete(char *s, char *digest)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Face *f;
|
||||||
|
|
||||||
|
lockdisplay(display);
|
||||||
|
for(i=0; i<nfaces; i++){
|
||||||
|
f = faces[i];
|
||||||
|
if(digest != nil){
|
||||||
|
if(f->str[Sdigest]!=nil && strcmp(digest, f->str[Sdigest]) == 0){
|
||||||
|
dodelete(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(f->str[Sshow] && strcmp(s, f->str[Sshow]) == 0){
|
||||||
|
dodelete(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unlockdisplay(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
faceproc(void)
|
||||||
|
{
|
||||||
|
for(;;)
|
||||||
|
addface(nextface());
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
resized(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
nacross = (Dx(screen->r)-2*facep.x+Facesep)/(Facesize+Facesep);
|
||||||
|
for(ndown=1; rectinrect(facerect(ndown*nacross), screen->r); ndown++)
|
||||||
|
;
|
||||||
|
setlast();
|
||||||
|
draw(screen, screen->r, bgrnd, nil, ZP);
|
||||||
|
enddate = ZP;
|
||||||
|
drawtime();
|
||||||
|
for(i=0; i<nfaces; i++)
|
||||||
|
drawface(faces[i], i);
|
||||||
|
drawarrows();
|
||||||
|
flushimage(display, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
eresized(int new)
|
||||||
|
{
|
||||||
|
lockdisplay(display);
|
||||||
|
if(new && getwindow(display, Refnone) < 0) {
|
||||||
|
fprint(2, "can't reattach to window\n");
|
||||||
|
killall("reattach");
|
||||||
|
}
|
||||||
|
resized();
|
||||||
|
unlockdisplay(display);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
int
|
||||||
|
getmouse(Mouse *m)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
static int eof;
|
||||||
|
char buf[128];
|
||||||
|
|
||||||
|
if(eof)
|
||||||
|
return 0;
|
||||||
|
for(;;){
|
||||||
|
n = read(mousefd, buf, sizeof(buf));
|
||||||
|
if(n <= 0){
|
||||||
|
/* so callers needn't check return value every time */
|
||||||
|
eof = 1;
|
||||||
|
m->buttons = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//jpc n = eatomouse(m, buf, n);
|
||||||
|
if(n > 0)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
int
|
||||||
|
getmouse(Mouse *m)
|
||||||
|
{
|
||||||
|
static int eof;
|
||||||
|
|
||||||
|
if(eof)
|
||||||
|
return 0;
|
||||||
|
if( readmouse(mousectl) < 0 ) {
|
||||||
|
eof = 1;
|
||||||
|
m->buttons = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
*m = mousectl->m;
|
||||||
|
/* m->buttons = mousectl->m.buttons;
|
||||||
|
m->xy.x = mousectl->m.xy.x;
|
||||||
|
m->xy.y = mousectl->m.xy.y;
|
||||||
|
m->msec = mousectl->m.msec; */
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Clicksize = 3, /* pixels */
|
||||||
|
};
|
||||||
|
|
||||||
|
int
|
||||||
|
scroll(int but, Point p)
|
||||||
|
{
|
||||||
|
int delta;
|
||||||
|
|
||||||
|
delta = 0;
|
||||||
|
lockdisplay(display);
|
||||||
|
if(ptinrect(p, leftr) && first>0){
|
||||||
|
if(but == 2)
|
||||||
|
delta = -first;
|
||||||
|
else{
|
||||||
|
delta = nacross;
|
||||||
|
if(delta > first)
|
||||||
|
delta = first;
|
||||||
|
delta = -delta;
|
||||||
|
}
|
||||||
|
}else if(ptinrect(p, rightr) && last<nfaces){
|
||||||
|
if(but == 2)
|
||||||
|
delta = (nfaces-nacross*ndown) - first;
|
||||||
|
else{
|
||||||
|
delta = nacross;
|
||||||
|
if(delta > nfaces-last)
|
||||||
|
delta = nfaces-last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
first += delta;
|
||||||
|
last += delta;
|
||||||
|
unlockdisplay(display);
|
||||||
|
if(delta)
|
||||||
|
eresized(0);
|
||||||
|
return delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
click(int button, Mouse *m)
|
||||||
|
{
|
||||||
|
Point p;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
p = m->xy;
|
||||||
|
while(m->buttons == (1<<(button-1)))
|
||||||
|
getmouse(m);
|
||||||
|
if(m->buttons)
|
||||||
|
return;
|
||||||
|
if(abs(p.x-m->xy.x)>Clicksize || abs(p.y-m->xy.y)>Clicksize)
|
||||||
|
return;
|
||||||
|
switch(button){
|
||||||
|
case 1:
|
||||||
|
if(scroll(1, p))
|
||||||
|
break;
|
||||||
|
if(history){
|
||||||
|
/* click clears display */
|
||||||
|
lockdisplay(display);
|
||||||
|
for(i=0; i<nfaces; i++)
|
||||||
|
freeface(faces[i]);
|
||||||
|
free(faces);
|
||||||
|
faces=nil;
|
||||||
|
nfaces = 0;
|
||||||
|
unlockdisplay(display);
|
||||||
|
eresized(0);
|
||||||
|
return;
|
||||||
|
}else{
|
||||||
|
for(i=first; i<last; i++) /* clear vwhois faces */
|
||||||
|
if(ptinrect(p, facerect(i-first))
|
||||||
|
&& strstr(faces[i]->str[Sshow], "/XXXvwhois")){
|
||||||
|
delface(i);
|
||||||
|
flushimage(display, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
scroll(2, p);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
scroll(3, p);
|
||||||
|
lockdisplay(display);
|
||||||
|
for(i=first; i<last; i++)
|
||||||
|
if(ptinrect(p, facerect(i-first))){
|
||||||
|
showmail(faces[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
unlockdisplay(display);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
mouseproc(void *dummy)
|
||||||
|
{
|
||||||
|
Mouse mouse;
|
||||||
|
|
||||||
|
while(getmouse(&mouse)){
|
||||||
|
if(mouse.buttons == 1)
|
||||||
|
click(1, &mouse);
|
||||||
|
else if(mouse.buttons == 2)
|
||||||
|
click(2, &mouse);
|
||||||
|
else if(mouse.buttons == 4)
|
||||||
|
click(3, &mouse);
|
||||||
|
|
||||||
|
while(mouse.buttons)
|
||||||
|
getmouse(&mouse);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
killall(char *s)
|
||||||
|
{
|
||||||
|
int i, pid;
|
||||||
|
|
||||||
|
pid = getpid();
|
||||||
|
for(i=0; i<NPROC; i++)
|
||||||
|
if(pids[i] && pids[i]!=pid)
|
||||||
|
postnote(PNPROC, pids[i], "kill");
|
||||||
|
threadexitsall(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
startproc(void (*f)(void), int index)
|
||||||
|
{
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
switch(pid = rfork(RFPROC|RFNOWAIT)){ //jpc removed |RFMEM
|
||||||
|
case -1:
|
||||||
|
fprint(2, "faces: fork failed: %r\n");
|
||||||
|
killall("fork failed");
|
||||||
|
case 0:
|
||||||
|
f();
|
||||||
|
fprint(2, "faces: %s process exits\n", procnames[index]);
|
||||||
|
if(index >= 0)
|
||||||
|
killall("process died");
|
||||||
|
threadexitsall(nil);
|
||||||
|
}
|
||||||
|
if(index >= 0)
|
||||||
|
pids[index] = pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(void)
|
||||||
|
{
|
||||||
|
fprint(2, "usage: faces [-hi] [-m maildir] -W winsize\n");
|
||||||
|
threadexitsall("usage");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
threadmain(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ARGBEGIN{
|
||||||
|
case 'h':
|
||||||
|
history++;
|
||||||
|
break;
|
||||||
|
case 'i':
|
||||||
|
initload++;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
addmaildir(EARGF(usage()));
|
||||||
|
maildir = nil;
|
||||||
|
break;
|
||||||
|
case 'W':
|
||||||
|
winsize = EARGF(usage());
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
usage();
|
||||||
|
}ARGEND
|
||||||
|
|
||||||
|
if(initdraw(nil, nil, "faces") < 0){
|
||||||
|
fprint(2, "faces: initdraw failed: %r\n");
|
||||||
|
threadexitsall("initdraw");
|
||||||
|
}
|
||||||
|
if(maildir)
|
||||||
|
addmaildir(maildir);
|
||||||
|
init();
|
||||||
|
unlockdisplay(display); /* initdraw leaves it locked */
|
||||||
|
display->locking = 1; /* tell library we're using the display lock */
|
||||||
|
setdate();
|
||||||
|
eresized(0);
|
||||||
|
|
||||||
|
pids[Mainp] = getpid();
|
||||||
|
pids[Timep] = proccreate(timeproc, nil, 16000);
|
||||||
|
pids[Mousep] = proccreate(mouseproc, nil, 16000);
|
||||||
|
if(initload)
|
||||||
|
for(i = 0; i < nmaildirs; i++)
|
||||||
|
loadmboxfaces(maildirs[i]);
|
||||||
|
faceproc();
|
||||||
|
fprint(2, "faces: %s process exits\n", procnames[Mainp]);
|
||||||
|
killall(nil);
|
||||||
|
}
|
||||||
26
src/cmd/faces/mkfile
Normal file
26
src/cmd/faces/mkfile
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<$PLAN9/src/mkhdr
|
||||||
|
|
||||||
|
# default domain for faces, overridden by $facedom
|
||||||
|
DEFAULT=\"astro\"
|
||||||
|
|
||||||
|
TARG=faces
|
||||||
|
|
||||||
|
OFILES=main.$O\
|
||||||
|
facedb.$O\
|
||||||
|
plumb.$O\
|
||||||
|
util.$O\
|
||||||
|
|
||||||
|
HFILES=faces.h\
|
||||||
|
|
||||||
|
BIN=$PLAN9/bin
|
||||||
|
|
||||||
|
UPDATE=\
|
||||||
|
mkfile\
|
||||||
|
$HFILES\
|
||||||
|
${OFILES:%.$O=%.c}\
|
||||||
|
|
||||||
|
<$PLAN9/src/mkone
|
||||||
|
CFLAGS=$CFLAGS '-DDEFAULT='$DEFAULT
|
||||||
|
|
||||||
|
$O.dblook: dblook.$O facedb.$O util.$O
|
||||||
|
$LD -o $target $prereq
|
||||||
398
src/cmd/faces/plumb.c
Normal file
398
src/cmd/faces/plumb.c
Normal file
|
|
@ -0,0 +1,398 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include <plumb.h>
|
||||||
|
#include <regexp.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <9pclient.h>
|
||||||
|
#include "faces.h"
|
||||||
|
|
||||||
|
static int showfd = -1;
|
||||||
|
static int seefd = -1;
|
||||||
|
static int logfd = -1;
|
||||||
|
static char *user;
|
||||||
|
static char *logtag;
|
||||||
|
|
||||||
|
char **maildirs;
|
||||||
|
int nmaildirs;
|
||||||
|
|
||||||
|
void
|
||||||
|
initplumb(void)
|
||||||
|
{
|
||||||
|
showfd = plumbopen("send", OWRITE);
|
||||||
|
seefd = plumbopen("seemail", OREAD);
|
||||||
|
|
||||||
|
if(seefd < 0){
|
||||||
|
logfd = open(unsharp("#9/log/mail"), OREAD);
|
||||||
|
seek(logfd, 0LL, 2);
|
||||||
|
user = getenv("user");
|
||||||
|
if(user == nil){
|
||||||
|
fprint(2, "faces: can't find user name: %r\n");
|
||||||
|
exits("$user");
|
||||||
|
}
|
||||||
|
logtag = emalloc(32+strlen(user)+1);
|
||||||
|
sprint(logtag, " delivered %s From ", user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
addmaildir(char *dir)
|
||||||
|
{
|
||||||
|
maildirs = erealloc(maildirs, (nmaildirs+1)*sizeof(char*));
|
||||||
|
maildirs[nmaildirs++] = dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
attr(Face *f)
|
||||||
|
{
|
||||||
|
static char buf[128];
|
||||||
|
|
||||||
|
if(f->str[Sdigest]){
|
||||||
|
snprint(buf, sizeof buf, "digest=%s", f->str[Sdigest]);
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
showmail(Face *f)
|
||||||
|
{
|
||||||
|
Plumbmsg pm;
|
||||||
|
Plumbattr a;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
if(showfd<0 || f->str[Sshow]==nil || f->str[Sshow][0]=='\0')
|
||||||
|
return;
|
||||||
|
s = emalloc(strlen("/mail/fs")+1+strlen(f->str[Sshow]));
|
||||||
|
sprint(s,"/mail/fs/%s",f->str[Sshow]);
|
||||||
|
pm.src = "faces";
|
||||||
|
pm.dst = "showmail";
|
||||||
|
pm.wdir = "/mail/fs";
|
||||||
|
pm.type = "text";
|
||||||
|
a.name = "digest";
|
||||||
|
a.value = f->str[Sdigest];
|
||||||
|
a.next = nil;
|
||||||
|
pm.attr = &a;
|
||||||
|
pm.ndata = strlen(s);
|
||||||
|
pm.data = s;
|
||||||
|
plumbsend(showfd,&pm);
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
value(Plumbattr *attr, char *key, char *def)
|
||||||
|
{
|
||||||
|
char *v;
|
||||||
|
|
||||||
|
v = plumblookup(attr, key);
|
||||||
|
if(v)
|
||||||
|
return v;
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setname(Face *f, char *sender)
|
||||||
|
{
|
||||||
|
char *at, *bang;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
/* works with UTF-8, although it's written as ASCII */
|
||||||
|
for(p=sender; *p!='\0'; p++)
|
||||||
|
*p = tolower(*p);
|
||||||
|
f->str[Suser] = sender;
|
||||||
|
at = strchr(sender, '@');
|
||||||
|
if(at){
|
||||||
|
*at++ = '\0';
|
||||||
|
f->str[Sdomain] = estrdup(at);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bang = strchr(sender, '!');
|
||||||
|
if(bang){
|
||||||
|
*bang++ = '\0';
|
||||||
|
f->str[Suser] = estrdup(bang);
|
||||||
|
f->str[Sdomain] = sender;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
getc(void)
|
||||||
|
{
|
||||||
|
static uchar buf[512];
|
||||||
|
static int nbuf = 0;
|
||||||
|
static int i = 0;
|
||||||
|
|
||||||
|
while(i == nbuf){
|
||||||
|
i = 0;
|
||||||
|
nbuf = read(logfd, buf, sizeof buf);
|
||||||
|
if(nbuf == 0){
|
||||||
|
sleep(15000);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(nbuf < 0)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return buf[i++];
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
getline(char *buf, int n)
|
||||||
|
{
|
||||||
|
int i, c;
|
||||||
|
|
||||||
|
for(i=0; i<n-1; i++){
|
||||||
|
c = getc();
|
||||||
|
if(c <= 0)
|
||||||
|
return nil;
|
||||||
|
if(c == '\n')
|
||||||
|
break;
|
||||||
|
buf[i] = c;
|
||||||
|
}
|
||||||
|
buf[i] = '\0';
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* months[] = {
|
||||||
|
"jan", "feb", "mar", "apr",
|
||||||
|
"may", "jun", "jul", "aug",
|
||||||
|
"sep", "oct", "nov", "dec"
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
getmon(char *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<nelem(months); i++)
|
||||||
|
if(cistrcmp(months[i], s) == 0)
|
||||||
|
return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fri Jul 23 14:05:14 EDT 1999 */
|
||||||
|
ulong
|
||||||
|
parsedatev(char **a)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
Tm tm;
|
||||||
|
|
||||||
|
memset(&tm, 0, sizeof tm);
|
||||||
|
if((tm.mon=getmon(a[1])) == -1)
|
||||||
|
goto Err;
|
||||||
|
tm.mday = strtol(a[2], &p, 10);
|
||||||
|
if(*p != '\0')
|
||||||
|
goto Err;
|
||||||
|
tm.hour = strtol(a[3], &p, 10);
|
||||||
|
if(*p != ':')
|
||||||
|
goto Err;
|
||||||
|
tm.min = strtol(p+1, &p, 10);
|
||||||
|
if(*p != ':')
|
||||||
|
goto Err;
|
||||||
|
tm.sec = strtol(p+1, &p, 10);
|
||||||
|
if(*p != '\0')
|
||||||
|
goto Err;
|
||||||
|
if(strlen(a[4]) != 3)
|
||||||
|
goto Err;
|
||||||
|
strcpy(tm.zone, a[4]);
|
||||||
|
if(strlen(a[5]) != 4)
|
||||||
|
goto Err;
|
||||||
|
tm.year = strtol(a[5], &p, 10);
|
||||||
|
if(*p != '\0')
|
||||||
|
goto Err;
|
||||||
|
tm.year -= 1900;
|
||||||
|
return tm2sec(&tm);
|
||||||
|
Err:
|
||||||
|
return time(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ulong
|
||||||
|
parsedate(char *s)
|
||||||
|
{
|
||||||
|
char *f[10];
|
||||||
|
int nf;
|
||||||
|
|
||||||
|
nf = getfields(s, f, nelem(f), 1, " ");
|
||||||
|
if(nf < 6)
|
||||||
|
return time(0);
|
||||||
|
return parsedatev(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 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 */
|
||||||
|
/* achille Oct 26 13:45:42 remote local!rsc From rsc Sat Oct 26 13:45:41 EDT 2002 (rsc) 170 */
|
||||||
|
int
|
||||||
|
parselog(char *s, char **sender, ulong *xtime)
|
||||||
|
{
|
||||||
|
char *f[20];
|
||||||
|
int nf;
|
||||||
|
|
||||||
|
nf = getfields(s, f, nelem(f), 1, " ");
|
||||||
|
if(nf < 14)
|
||||||
|
return 0;
|
||||||
|
if(strcmp(f[4], "delivered") == 0 && strcmp(f[5], user) == 0)
|
||||||
|
goto Found;
|
||||||
|
if(strcmp(f[4], "remote") == 0 && strncmp(f[5], "local!", 6) == 0 && strcmp(f[5]+6, user) == 0)
|
||||||
|
goto Found;
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
Found:
|
||||||
|
*sender = estrdup(f[7]);
|
||||||
|
*xtime = parsedatev(&f[8]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
logrecv(char **sender, ulong *xtime)
|
||||||
|
{
|
||||||
|
char buf[4096];
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
if(getline(buf, sizeof buf) == nil)
|
||||||
|
return 0;
|
||||||
|
if(parselog(buf, sender, xtime))
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
tweakdate(char *d)
|
||||||
|
{
|
||||||
|
char e[8];
|
||||||
|
|
||||||
|
/* d, date = "Mon Aug 2 23:46:55 EDT 1999" */
|
||||||
|
|
||||||
|
if(strlen(d) < strlen("Mon Aug 2 23:46:55 EDT 1999"))
|
||||||
|
return estrdup("");
|
||||||
|
if(strncmp(date, d, 4+4+3) == 0)
|
||||||
|
snprint(e, sizeof e, "%.5s", d+4+4+3); /* 23:46 */
|
||||||
|
else
|
||||||
|
snprint(e, sizeof e, "%.6s", d+4); /* Aug 2 */
|
||||||
|
return estrdup(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
Face*
|
||||||
|
nextface(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Face *f;
|
||||||
|
Plumbmsg *m;
|
||||||
|
char *t, *senderp, *showmailp, *digestp;
|
||||||
|
ulong xtime;
|
||||||
|
|
||||||
|
f = emalloc(sizeof(Face));
|
||||||
|
for(;;){
|
||||||
|
if(seefd >= 0){
|
||||||
|
m = plumbrecv(seefd);
|
||||||
|
if(m == nil)
|
||||||
|
killall("error on seemail plumb port");
|
||||||
|
t = value(m->attr, "mailtype", "");
|
||||||
|
if(strcmp(t, "delete") == 0)
|
||||||
|
delete(m->data, value(m->attr, "digest", nil));
|
||||||
|
else if(strcmp(t, "new") != 0)
|
||||||
|
fprint(2, "faces: unknown plumb message type %s\n", t);
|
||||||
|
else for(i=0; i<nmaildirs; i++) {
|
||||||
|
if(strncmp(m->data,"/mail/fs/",strlen("/mail/fs/")) == 0)
|
||||||
|
m->data += strlen("/mail/fs/");
|
||||||
|
if(strncmp(m->data, maildirs[i], strlen(maildirs[i])) == 0)
|
||||||
|
goto Found;
|
||||||
|
}
|
||||||
|
plumbfree(m);
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Found:
|
||||||
|
xtime = parsedate(value(m->attr, "date", date));
|
||||||
|
digestp = value(m->attr, "digest", nil);
|
||||||
|
if(alreadyseen(digestp)){
|
||||||
|
/* duplicate upas/fs can send duplicate messages */
|
||||||
|
plumbfree(m);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
senderp = estrdup(value(m->attr, "sender", "???"));
|
||||||
|
showmailp = estrdup(m->data);
|
||||||
|
if(digestp)
|
||||||
|
digestp = estrdup(digestp);
|
||||||
|
plumbfree(m);
|
||||||
|
}else{
|
||||||
|
if(logrecv(&senderp, &xtime) <= 0)
|
||||||
|
killall("error reading log file");
|
||||||
|
showmailp = estrdup("");
|
||||||
|
digestp = nil;
|
||||||
|
}
|
||||||
|
setname(f, senderp);
|
||||||
|
f->time = xtime;
|
||||||
|
f->tm = *localtime(xtime);
|
||||||
|
f->str[Sshow] = showmailp;
|
||||||
|
f->str[Sdigest] = digestp;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
iline(char *data, char **pp)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
for(p=data; *p!='\0' && *p!='\n'; p++)
|
||||||
|
;
|
||||||
|
if(*p == '\n')
|
||||||
|
*p++ = '\0';
|
||||||
|
*pp = p;
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
Face*
|
||||||
|
dirface(char *dir, char *num)
|
||||||
|
{
|
||||||
|
Face *f;
|
||||||
|
char *from, *date;
|
||||||
|
char buf[1024], *info, *p, *digest;
|
||||||
|
int n;
|
||||||
|
ulong len;
|
||||||
|
CFid *fid;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/*
|
||||||
|
* loadmbox leaves us in maildir, so we needn't
|
||||||
|
* walk /mail/fs/mbox for each face; this makes startup
|
||||||
|
* a fair bit quicker.
|
||||||
|
*/
|
||||||
|
if(getwd(pwd, sizeof pwd) != nil && strcmp(pwd, dir) == 0)
|
||||||
|
sprint(buf, "%s/info", num);
|
||||||
|
else
|
||||||
|
sprint(buf, "%s/%s/info", dir, num);
|
||||||
|
#endif
|
||||||
|
sprint(buf, "%s/%s/info", dir, num);
|
||||||
|
len = fsdirlen(upasfs, buf);
|
||||||
|
if(len <= 0)
|
||||||
|
return nil;
|
||||||
|
fid = fsopen(upasfs,buf, OREAD);
|
||||||
|
if(fid == nil)
|
||||||
|
return nil;
|
||||||
|
info = emalloc(len+1);
|
||||||
|
n = fsreadn(fid, info, len);
|
||||||
|
fsclose(fid);
|
||||||
|
if(n < 0){
|
||||||
|
free(info);
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
info[n] = '\0';
|
||||||
|
f = emalloc(sizeof(Face));
|
||||||
|
from = iline(info, &p); /* from */
|
||||||
|
iline(p, &p); /* to */
|
||||||
|
iline(p, &p); /* cc */
|
||||||
|
iline(p, &p); /* replyto */
|
||||||
|
date = iline(p, &p); /* date */
|
||||||
|
setname(f, estrdup(from));
|
||||||
|
f->time = parsedate(date);
|
||||||
|
f->tm = *localtime(f->time);
|
||||||
|
sprint(buf, "%s/%s", dir, num);
|
||||||
|
f->str[Sshow] = estrdup(buf);
|
||||||
|
iline(p, &p); /* subject */
|
||||||
|
iline(p, &p); /* mime content type */
|
||||||
|
iline(p, &p); /* mime disposition */
|
||||||
|
iline(p, &p); /* filename */
|
||||||
|
digest = iline(p, &p); /* digest */
|
||||||
|
f->str[Sdigest] = estrdup(digest);
|
||||||
|
free(info);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
42
src/cmd/faces/util.c
Normal file
42
src/cmd/faces/util.c
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <draw.h>
|
||||||
|
#include <plumb.h>
|
||||||
|
#include <9pclient.h>
|
||||||
|
#include "faces.h"
|
||||||
|
|
||||||
|
void*
|
||||||
|
emalloc(ulong sz)
|
||||||
|
{
|
||||||
|
void *v;
|
||||||
|
v = malloc(sz);
|
||||||
|
if(v == nil) {
|
||||||
|
fprint(2, "out of memory allocating %ld\n", sz);
|
||||||
|
exits("mem");
|
||||||
|
}
|
||||||
|
memset(v, 0, sz);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
erealloc(void *v, ulong sz)
|
||||||
|
{
|
||||||
|
v = realloc(v, sz);
|
||||||
|
if(v == nil) {
|
||||||
|
fprint(2, "out of memory allocating %ld\n", sz);
|
||||||
|
exits("mem");
|
||||||
|
}
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
estrdup(char *s)
|
||||||
|
{
|
||||||
|
char *t;
|
||||||
|
if((t = strdup(s)) == nil) {
|
||||||
|
fprint(2, "out of memory in strdup(%.10s)\n", s);
|
||||||
|
exits("mem");
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue