imap-based new upas/fs

This commit is contained in:
rsc 2006-02-15 12:39:09 +00:00
parent 1ea614ffaf
commit 941e17134e
15 changed files with 4168 additions and 0 deletions

318
src/cmd/upas/nfs/box.c Normal file
View file

@ -0,0 +1,318 @@
#include "a.h"
enum
{
BoxSubChunk = 16,
BoxChunk = 64,
MsgChunk = 256,
PartChunk = 4,
PartSubChunk = 4,
};
Box **boxes;
uint nboxes;
Box *rootbox;
int boxid;
Box*
boxbyname(char *name)
{
int i;
/* LATER: replace with hash table */
for(i=0; i<nboxes; i++)
if(boxes[i] && strcmp(boxes[i]->name, name) == 0)
return boxes[i];
return nil;
}
Box*
subbox(Box *b, char *elem)
{
int i;
for(i=0; i<b->nsub; i++)
if(b->sub[i] && strcmp(b->sub[i]->elem, elem) == 0)
return b->sub[i];
return nil;
}
Box*
boxbyid(uint id)
{
int i;
/* LATER: replace with binary search */
for(i=0; i<nboxes; i++)
if(boxes[i] && boxes[i]->id == id)
return boxes[i];
return nil;
}
Box*
boxcreate(char *name)
{
char *p;
Box *b, *bb;
if((b = boxbyname(name)) != nil)
return b;
b = emalloc(sizeof *b);
b->id = ++boxid;
b->time = time(0);
b->name = estrdup(name);
b->uidnext = 1;
p = strrchr(b->name, '/');
if(p){
*p = 0;
bb = boxcreate(b->name);
*p = '/';
b->elem = p+1;
}else{
bb = rootbox;
b->elem = b->name;
}
if(nboxes%BoxChunk == 0)
boxes = erealloc(boxes, (nboxes+BoxChunk)*sizeof boxes[0]);
boxes[nboxes++] = b;
if(bb->nsub%BoxSubChunk == 0)
bb->sub = erealloc(bb->sub, (bb->nsub+BoxSubChunk)*sizeof bb->sub[0]);
bb->sub[bb->nsub++] = b;
b->parent = bb;
return b;
}
void
boxfree(Box *b)
{
int i;
if(b == nil)
return;
for(i=0; i<b->nmsg; i++)
msgfree(b->msg[i]);
free(b->msg);
free(b);
}
Part*
partcreate(Msg *m, Part *pp)
{
Part *p;
if(m->npart%PartChunk == 0)
m->part = erealloc(m->part, (m->npart+PartChunk)*sizeof m->part[0]);
p = emalloc(sizeof *p);
p->msg = m;
p->ix = m->npart;
m->part[m->npart++] = p;
if(pp){
if(pp->nsub%PartSubChunk == 0)
pp->sub = erealloc(pp->sub, (pp->nsub+PartSubChunk)*sizeof pp->sub[0]);
p->pix = pp->nsub;
p->parent = pp;
pp->sub[pp->nsub++] = p;
}
return p;
}
void
partfree(Part *p)
{
int i;
if(p == nil)
return;
for(i=0; i<p->nsub; i++)
partfree(p->sub[i]);
free(p->sub);
hdrfree(p->hdr);
free(p->type);
free(p->idstr);
free(p->desc);
free(p->encoding);
free(p->charset);
free(p->raw);
free(p->rawheader);
free(p->rawbody);
free(p->mimeheader);
free(p->body);
free(p);
}
void
msgfree(Msg *m)
{
int i;
if(m == nil)
return;
for(i=0; i<m->npart; i++)
free(m->part[i]);
free(m->part);
free(m);
}
void
msgplumb(Msg *m, int delete)
{
static int fd = -1;
Plumbmsg p;
Plumbattr a[10];
char buf[256], date[40];
int ai;
if(m == nil || m->npart < 1 || m->part[0]->hdr == nil)
return;
if(m->box && strcmp(m->box->name, "mbox") != 0)
return;
p.src = "mailfs";
p.dst = "seemail";
p.wdir = "/";
p.type = "text";
ai = 0;
a[ai].name = "filetype";
a[ai].value = "mail";
a[++ai].name = "mailtype";
a[ai].value = delete?"delete":"new";
a[ai-1].next = &a[ai];
if(m->part[0]->hdr->from){
a[++ai].name = "sender";
a[ai].value = m->part[0]->hdr->from;
a[ai-1].next = &a[ai];
}
if(m->part[0]->hdr->subject){
a[++ai].name = "subject";
a[ai].value = m->part[0]->hdr->subject;
a[ai-1].next = &a[ai];
}
if(m->part[0]->hdr->digest){
a[++ai].name = "digest";
a[ai].value = m->part[0]->hdr->digest;
a[ai-1].next = &a[ai];
}
strcpy(date, ctime(m->date));
date[strlen(date)-1] = 0; /* newline */
a[++ai].name = "date";
a[ai].value = date;
a[ai-1].next = &a[ai];
a[ai].next = nil;
p.attr = a;
snprint(buf, sizeof buf, "Mail/%s/%ud", m->box->name, m->id);
p.ndata = strlen(buf);
p.data = buf;
if(fd < 0)
fd = plumbopen("send", OWRITE);
if(fd < 0)
return;
plumbsend(fd, &p);
}
Msg*
msgcreate(Box *box)
{
Msg *m;
m = emalloc(sizeof *m);
m->box = box;
partcreate(m, nil);
m->part[0]->type = estrdup("message/rfc822");
if(box->nmsg%MsgChunk == 0)
box->msg = erealloc(box->msg, (box->nmsg+MsgChunk)*sizeof box->msg[0]);
m->ix = box->nmsg++;
box->msg[m->ix] = m;
m->id = ++box->msgid;
return m;
}
Msg*
msgbyimapuid(Box *box, uint uid, int docreate)
{
int i;
Msg *msg;
if(box == nil)
return nil;
/* LATER: binary search or something */
for(i=0; i<box->nmsg; i++)
if(box->msg[i]->imapuid == uid)
return box->msg[i];
if(!docreate)
return nil;
msg = msgcreate(box);
msg->imapuid = uid;
return msg;
}
Msg*
msgbyid(Box *box, uint id)
{
int i;
if(box == nil)
return nil;
/* LATER: binary search or something */
for(i=0; i<box->nmsg; i++)
if(box->msg[i]->id == id)
return box->msg[i];
return nil;
}
Part*
partbyid(Msg *m, uint id)
{
if(m == nil)
return nil;
if(id >= m->npart)
return nil;
return m->part[id];
}
Part*
subpart(Part *p, uint a)
{
if(p == nil || a >= p->nsub)
return nil;
return p->sub[a];
}
void
hdrfree(Hdr *h)
{
if(h == nil)
return;
free(h->date);
free(h->subject);
free(h->from);
free(h->sender);
free(h->replyto);
free(h->to);
free(h->cc);
free(h->bcc);
free(h->inreplyto);
free(h->messageid);
free(h->digest);
free(h);
}
void
boxinit(void)
{
rootbox = emalloc(sizeof *rootbox);
rootbox->name = estrdup("");
rootbox->time = time(0);
}

133
src/cmd/upas/nfs/box.h Normal file
View file

@ -0,0 +1,133 @@
enum
{
FlagJunk = 1<<0,
FlagNonJunk = 1<<1,
FlagReplied = 1<<2,
FlagFlagged = 1<<3,
FlagDeleted = 1<<4,
FlagDraft = 1<<5,
FlagSeen = 1<<6,
FlagNoInferiors = 1<<7,
FlagMarked = 1<<8,
FlagNoSelect = 1<<9,
FlagUnMarked = 1<<10,
};
typedef struct Box Box;
typedef struct Hdr Hdr;
typedef struct Msg Msg;
typedef struct Part Part;
struct Box
{
char* name; /* name of mailbox */
char* elem; /* last element in name */
uint ix; /* index in box[] array */
uint id; /* id shown in file system */
uint flags; /* FlagNoInferiors, etc. */
uint time; /* last update time */
uint msgid; /* last message id used */
Msg** msg; /* array of messages (can have nils) */
uint nmsg;
char* imapname; /* name on IMAP server */
u32int validity; /* IMAP validity number */
uint uidnext; /* IMAP expected next uid */
uint recent; /* IMAP first recent message */
uint exists; /* IMAP last message in box */
uint maxseen; /* maximum IMAP uid seen */
int mark;
uint imapinit; /* up-to-date w.r.t. IMAP */
Box* parent; /* in tree */
Box** sub;
uint nsub;
};
struct Hdr
{
/* LATER: store date as int, reformat for programs */
/* order known by fs.c */
char* date;
char* subject;
char* from;
char* sender;
char* replyto;
char* to;
char* cc;
char* bcc;
char* inreplyto;
char* messageid;
char* digest;
};
struct Msg
{
Box* box; /* mailbox containing msg */
uint ix; /* index in box->msg[] array */
uint id; /* id shown in file system */
uint imapuid; /* IMAP uid */
uint imapid; /* IMAP id */
uint flags; /* FlagDeleted etc. */
uint date; /* smtp envelope date */
uint size;
Part** part; /* message subparts - part[0] is root */
uint npart;
};
struct Part
{
Msg* msg; /* msg containing part */
uint ix; /* index in msg->part[] */
uint pix; /* id in parent->sub[] */
Part* parent; /* parent in structure */
Part** sub; /* children in structure */
uint nsub;
/* order known by fs.c */
char* type; /* e.g., "text/plain" */
char* idstr;
char* desc;
char* encoding;
char* charset;
char* raw;
char* rawheader;
char* rawbody;
char* mimeheader;
/* order known by fs.c */
uint size;
uint lines;
char* body;
uint nbody;
Hdr* hdr; /* RFC822 envelope for message/rfc822 */
};
void boxinit(void);
Box* boxbyname(char*);
Box* boxbyid(uint);
Box* boxcreate(char*);
void boxfree(Box*);
Box* subbox(Box*, char*);
Msg* msgcreate(Box*);
Part* partcreate(Msg*, Part*);
void hdrfree(Hdr*);
Msg* msgbyid(Box*, uint);
Msg* msgbyimapuid(Box*, uint, int);
void msgfree(Msg*);
void msgplumb(Msg*, int);
Part* partbyid(Msg*, uint);
Part* subpart(Part*, uint);
void partfree(Part*);
extern Box** boxes;
extern uint nboxes;
extern Box* rootbox;

257
src/cmd/upas/nfs/decode.c Normal file
View file

@ -0,0 +1,257 @@
/* Quick and dirty RFC 2047 */
#include "a.h"
static int
unhex1(char c)
{
if('0' <= c && c <= '9')
return c-'0';
if('a' <= c && c <= 'f')
return c-'a'+10;
if('A' <= c && c <= 'F')
return c-'A'+10;
return 15;
}
static int
unhex(char *s)
{
return unhex1(s[0])*16+unhex1(s[1]);
}
int
decqp(uchar *out, int lim, char *in, int n)
{
char *p, *ep;
uchar *eout, *out0;
out0 = out;
eout = out+lim;
for(p=in, ep=in+n; p<ep && out<eout; ){
if(*p == '_'){
*out++ = ' ';
p++;
}
else if(*p == '='){
if(p+1 >= ep)
break;
if(*(p+1) == '\n'){
p += 2;
continue;
}
if(p+3 > ep)
break;
*out++ = unhex(p+1);
p += 3;
}else
*out++ = *p++;
}
return out-out0;
}
char*
decode(int kind, char *s, int *len)
{
char *t;
int l;
if(s == nil)
return s;
switch(kind){
case QuotedPrintable:
l = strlen(s)+1;
t = emalloc(l);
l = decqp((uchar*)t, l, s, l-1);
*len = l;
t[l] = 0;
return t;
case Base64:
l = strlen(s)+1;
t = emalloc(l);
l = dec64((uchar*)t, l, s, l-1);
*len = l;
t[l] = 0;
return t;
default:
*len = strlen(s);
return estrdup(s);
}
}
struct {
char *mime;
char *tcs;
} tcstab[] = {
"iso-8859-2", "8859-2",
"iso-8859-3", "8859-3",
"iso-8859-4", "8859-4",
"iso-8859-5", "8859-5",
"iso-8859-6", "8859-6",
"iso-8859-7", "8859-7",
"iso-8859-8", "8859-8",
"iso-8859-9", "8859-9",
"iso-8859-10", "8859-10",
"iso-8859-15", "8859-15",
"big5", "big5",
"iso-2022-jp", "jis-kanji",
"windows-1251", "cp1251",
"koi8-r", "koi8",
};
char*
tcs(char *charset, char *s)
{
static char buf[4096];
int i, n;
int fd[3], p[2], pp[2];
uchar *us;
char *t, *u;
char *argv[4];
Rune r;
if(s == nil || charset == nil || *s == 0)
return s;
if(cistrcmp(charset, "utf-8") == 0)
return s;
if(cistrcmp(charset, "iso-8859-1") == 0 || cistrcmp(charset, "us-ascii") == 0){
latin1:
n = 0;
for(us=(uchar*)s; *us; us++)
n += runelen(*us);
n++;
t = emalloc(n);
for(us=(uchar*)s, u=t; *us; us++){
r = *us;
u += runetochar(u, &r);
}
*u = 0;
free(s);
return t;
}
for(i=0; i<nelem(tcstab); i++)
if(cistrcmp(charset, tcstab[i].mime) == 0)
goto tcs;
goto latin1;
tcs:
argv[0] = "tcs";
argv[1] = "-f";
argv[2] = charset;
argv[3] = nil;
if(pipe(p) < 0 || pipe(pp) < 0)
sysfatal("pipe: %r");
fd[0] = p[0];
fd[1] = pp[0];
fd[2] = dup(2, -1);
if(threadspawnl(fd, "tcs", "tcs", "-f", tcstab[i].tcs, nil) < 0){
close(p[0]);
close(p[1]);
close(pp[0]);
close(pp[1]);
close(fd[2]);
goto latin1;
}
close(p[0]);
close(pp[0]);
write(p[1], s, strlen(s));
close(p[1]);
n = readn(pp[1], buf, sizeof buf-1);
close(pp[1]);
if(n <= 0)
goto latin1;
free(s);
buf[n] = 0;
return estrdup(buf);
}
char*
unrfc2047(char *s)
{
char *p, *q, *t, *u, *v;
int len;
Rune r;
Fmt fmt;
if(s == nil)
return nil;
if(strstr(s, "=?") == nil)
return s;
fmtstrinit(&fmt);
for(p=s; *p; ){
/* =?charset?e?text?= */
if(*p=='=' && *(p+1)=='?'){
p += 2;
q = strchr(p, '?');
if(q == nil)
goto emit;
q++;
if(*q == '?' || *(q+1) != '?')
goto emit;
t = q+2;
u = strchr(t, '?');
if(u == nil || *(u+1) != '=')
goto emit;
switch(*q){
case 'q':
case 'Q':
*u = 0;
v = decode(QuotedPrintable, t, &len);
break;
case 'b':
case 'B':
*u = 0;
v = decode(Base64, t, &len);
break;
default:
goto emit;
}
*(q-1) = 0;
v = tcs(p, v);
fmtstrcpy(&fmt, v);
free(v);
p = u+2;
}
emit:
p += chartorune(&r, p);
fmtrune(&fmt, r);
}
p = fmtstrflush(&fmt);
if(p == nil)
sysfatal("out of memory");
free(s);
return p;
}
#ifdef TEST
char *test[] =
{
"hello world",
"hello =?iso-8859-1?q?this is some text?=",
"=?US-ASCII?Q?Keith_Moore?=",
"=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?=",
"=?ISO-8859-1?Q?Andr=E9?= Pirard",
"=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=",
"=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=",
"=?ISO-8859-1?Q?Olle_J=E4rnefors?=",
"=?iso-2022-jp?B?GyRCTTVKISRKP006SiRyS34kPyQ3JEZKcz03JCIkahsoQg==?=",
"=?UTF-8?B?Ik5pbHMgTy4gU2Vsw6VzZGFsIg==?="
};
void
threadmain(int argc, char **argv)
{
int i;
for(i=0; i<nelem(test); i++)
print("%s\n\t%s\n", test[i], unrfc2047(estrdup(test[i])));
threadexitsall(0);
}
#endif

1259
src/cmd/upas/nfs/fs.c Normal file

File diff suppressed because it is too large Load diff

2
src/cmd/upas/nfs/fs.h Normal file
View file

@ -0,0 +1,2 @@
extern Srv fs;
void fsinit0(void);

1715
src/cmd/upas/nfs/imap.c Normal file

File diff suppressed because it is too large Load diff

23
src/cmd/upas/nfs/imap.h Normal file
View file

@ -0,0 +1,23 @@
typedef struct Imap Imap;
void imapcheckbox(Imap *z, Box *b);
Imap* imapconnect(char *server, int mode);
int imapcopylist(Imap *z, char *nbox, Msg **m, uint nm);
void imapfetchraw(Imap *z, Part *p);
void imapfetchrawbody(Imap *z, Part *p);
void imapfetchrawheader(Imap *z, Part *p);
void imapfetchrawmime(Imap *z, Part *p);
int imapflaglist(Imap *z, int op, int flag, Msg **m, uint nm);
void imaphangup(Imap *z, int ticks);
int imapremovelist(Imap *z, Msg **m, uint nm);
int imapsearchbox(Imap *z, Box *b, char *search, Msg ***mm);
extern int chattyimap;
enum
{
Unencrypted,
Starttls,
Tls,
Cmd
};

68
src/cmd/upas/nfs/main.c Normal file
View file

@ -0,0 +1,68 @@
/*
TO DO
can get disposition info out of imap extended structure if needed
sizes in stat/ls ?
translate character sets in =? subjects
fetch headers, bodies on demand
cache headers, bodies on disk
cache message information on disk across runs
body.jpg
*/
#include "a.h"
Imap *imap;
void
usage(void)
{
fprint(2, "usage: mailfs [-t] server\n");
threadexitsall("usage");
}
void
threadmain(int argc, char **argv)
{
char *server;
int mode;
mode = Unencrypted;
ARGBEGIN{
default:
usage();
case 'D':
chatty9p++;
break;
case 'V':
chattyimap++;
break;
case 't':
mode = Tls;
break;
case 'x':
mode = Cmd;
break;
}ARGEND
quotefmtinstall();
fmtinstall('$', sxfmt);
if(argc != 1)
usage();
server = argv[0];
mailthreadinit();
boxinit();
fsinit0();
if((imap = imapconnect(server, mode)) == nil)
sysfatal("imapconnect: %r");
threadpostmountsrv(&fs, "mail", nil, 0);
}

68
src/cmd/upas/nfs/mbox.c Normal file
View file

@ -0,0 +1,68 @@
#include "a.h"
Mailbox *hash[123];
Mailbox **box;
uint nbox;
static void
markboxes(int mark)
{
Mailbox *b;
for(i=0; i<nbox; i++)
if(box[i])
box[i]->mark = mark;
}
static void
sweepboxes(void)
{
Mailbox *b;
for(i=0; i<nbox; i++)
if(box[i] && box[i]->mark){
freembox(box[i]);
box[i] = nil;
}
}
static Mailbox*
mboxbyname(char *name)
{
int i;
for(i=0; i<nbox; i++)
if(box[i] && strcmp(box[i]->name, name) == 0)
return box[i];
return nil;
}
static Mailbox*
mboxbyid(int id)
{
if(id < 0 || id >= nbox)
return nil;
return box[id];
}
static Mailbox*
mboxcreate(char *name)
{
Mailbox *b;
b = emalloc(sizeof *b);
b->name = estrdup(name);
if(nbox%64 == 0)
box = erealloc(box, (nbox+64)*sizeof box[0]);
box[nbox++] = b;
return b;
}
void
mboxupdate(void)
{
markboxes();
if(imapcmd("LIST \"\" *") < 0)
return;
sweepboxes();
}

18
src/cmd/upas/nfs/mkfile Normal file
View file

@ -0,0 +1,18 @@
<$PLAN9/src/mkhdr
TARG=mailfs
OFILES=\
box.$O\
decode.$O\
fs.$O\
imap.$O\
main.$O\
sx.$O\
thread.$O\
util.$O\
HFILES=a.h box.h imap.h sx.h
<$PLAN9/src/mkone

9
src/cmd/upas/nfs/msg.c Normal file
View file

@ -0,0 +1,9 @@
#include "a.h"
something about a cache of msgs here
cache flushes optionally to disk
before being tossed out
reload from disk, then from server

217
src/cmd/upas/nfs/sx.c Normal file
View file

@ -0,0 +1,217 @@
#include "a.h"
Sx *Brdsx1(Biobuf*);
Sx*
Brdsx(Biobuf *b)
{
Sx **sx, *x;
int nsx;
nsx = 0;
sx = nil;
while((x = Brdsx1(b)) != nil){
sx = erealloc(sx, (nsx+1)*sizeof sx[0]);
sx[nsx++] = x;
}
x = emalloc(sizeof *x);
x->sx = sx;
x->nsx = nsx;
x->type = SxList;
return x;
}
int
sxwalk(Sx *sx)
{
int i, n;
if(sx == nil)
return 1;
switch(sx->type){
default:
case SxAtom:
case SxString:
case SxNumber:
return 1;
case SxList:
n = 0;
for(i=0; i<sx->nsx; i++)
n += sxwalk(sx->sx[i]);
return n;
}
}
void
freesx(Sx *sx)
{
int i;
if(sx == nil)
return;
switch(sx->type){
case SxAtom:
case SxString:
free(sx->data);
break;
case SxList:
for(i=0; i<sx->nsx; i++)
freesx(sx->sx[i]);
free(sx->sx);
break;
}
free(sx);
}
Sx*
Brdsx1(Biobuf *b)
{
int c, len, nbr;
char *s;
vlong n;
Sx *x;
c = Bgetc(b);
if(c == ' ')
c = Bgetc(b);
if(c < 0)
return nil;
if(c == '\r')
c = Bgetc(b);
if(c == '\n')
return nil;
if(c == ')'){ /* end of list */
Bungetc(b);
return nil;
}
if(c == '('){ /* parenthesized list */
x = Brdsx(b);
c = Bgetc(b);
if(c != ')') /* oops! not good */
Bungetc(b);
return x;
}
if(c == '{'){ /* length-prefixed string */
len = 0;
while((c = Bgetc(b)) >= 0 && isdigit(c))
len = len*10 + c-'0';
if(c != '}') /* oops! not good */
Bungetc(b);
c = Bgetc(b);
if(c != '\r') /* oops! not good */
;
c = Bgetc(b);
if(c != '\n') /* oops! not good */
;
x = emalloc(sizeof *x);
x->data = emalloc(len+1);
if(Bread(b, x->data, len) != len)
; /* oops! */
x->data[len] = 0;
x->ndata = len;
x->type = SxString;
return x;
}
if(c == '"'){ /* quoted string */
s = nil;
len = 0;
while((c = Bgetc(b)) >= 0 && c != '"'){
if(c == '\\')
c = Bgetc(b);
s = erealloc(s, len+1);
s[len++] = c;
}
s = erealloc(s, len+1);
s[len] = 0;
x = emalloc(sizeof *x);
x->data = s;
x->ndata = len;
x->type = SxString;
return x;
}
if(isdigit(c)){ /* number */
n = c-'0';;
while((c = Bgetc(b)) >= 0 && isdigit(c))
n = n*10 + c-'0';
Bungetc(b);
x = emalloc(sizeof *x);
x->number = n;
x->type = SxNumber;
return x;
}
/* atom */
len = 1;
s = emalloc(1);
s[0] = c;
nbr = 0;
while((c = Bgetc(b)) >= 0 && c > ' ' && !strchr("(){}", c)){
/* allow embedded brackets as in BODY[] */
if(c == '['){
if(s[0] == '[')
break;
else
nbr++;
}
if(c == ']'){
if(nbr > 0)
nbr--;
else
break;
}
s = erealloc(s, len+1);
s[len++] = c;
}
if(c != ' ')
Bungetc(b);
s = erealloc(s, len+1);
s[len] = 0;
x = emalloc(sizeof *x);
x->type = SxAtom;
x->data = s;
x->ndata = len;
return x;
}
int
sxfmt(Fmt *fmt)
{
int i, paren;
Sx *sx;
sx = va_arg(fmt->args, Sx*);
if(sx == nil)
return 0;
switch(sx->type){
case SxAtom:
case SxString:
return fmtprint(fmt, "%q", sx->data);
case SxNumber:
return fmtprint(fmt, "%lld", sx->number);
case SxList:
paren = !(fmt->flags&FmtSharp);
if(paren)
fmtrune(fmt, '(');
for(i=0; i<sx->nsx; i++){
if(i)
fmtrune(fmt, ' ');
fmtprint(fmt, "%$", sx->sx[i]);
}
if(paren)
return fmtrune(fmt, ')');
return 0;
default:
return fmtstrcpy(fmt, "?");
}
}
int
oksx(Sx *sx)
{
return sx->nsx >= 2
&& sx->sx[1]->type == SxAtom
&& cistrcmp(sx->sx[1]->data, "OK") == 0;
}

31
src/cmd/upas/nfs/sx.h Normal file
View file

@ -0,0 +1,31 @@
/*
* S-expressions as used by IMAP.
*/
enum
{
SxUnknown = 0,
SxAtom,
SxString,
SxNumber,
SxList,
};
typedef struct Sx Sx;
struct Sx
{
int type;
char *data;
int ndata;
vlong number;
Sx **sx;
int nsx;
};
Sx* Brdsx(Biobuf*);
Sx* Brdsx1(Biobuf*);
void freesx(Sx*);
int oksx(Sx*);
int sxfmt(Fmt*);
int sxwalk(Sx*);

37
src/cmd/upas/nfs/thread.c Normal file
View file

@ -0,0 +1,37 @@
#include "a.h"
typedef struct New New;
struct New
{
void (*fn)(void*);
void *arg;
};
Channel *mailthreadchan;
void
mailthread(void (*fn)(void*), void *arg)
{
New n;
n.fn = fn;
n.arg = arg;
send(mailthreadchan, &n);
}
void
mailproc(void *v)
{
New n;
while(recv(mailthreadchan, &n) == 1)
threadcreate(n.fn, n.arg, STACK);
}
void
mailthreadinit(void)
{
mailthreadchan = chancreate(sizeof(New), 0);
proccreate(mailproc, nil, STACK);
}

13
src/cmd/upas/nfs/util.c Normal file
View file

@ -0,0 +1,13 @@
#include "a.h"
void
warn(char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
fprint(2, "warning: ");
vfprint(2, fmt, arg);
fprint(2, "\n");
va_end(arg);
}