imap-based new upas/fs
This commit is contained in:
parent
1ea614ffaf
commit
941e17134e
15 changed files with 4168 additions and 0 deletions
318
src/cmd/upas/nfs/box.c
Normal file
318
src/cmd/upas/nfs/box.c
Normal 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
133
src/cmd/upas/nfs/box.h
Normal 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
257
src/cmd/upas/nfs/decode.c
Normal 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
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
2
src/cmd/upas/nfs/fs.h
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
extern Srv fs;
|
||||
void fsinit0(void);
|
||||
1715
src/cmd/upas/nfs/imap.c
Normal file
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
23
src/cmd/upas/nfs/imap.h
Normal 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
68
src/cmd/upas/nfs/main.c
Normal 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
68
src/cmd/upas/nfs/mbox.c
Normal 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
18
src/cmd/upas/nfs/mkfile
Normal 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
9
src/cmd/upas/nfs/msg.c
Normal 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
217
src/cmd/upas/nfs/sx.c
Normal 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
31
src/cmd/upas/nfs/sx.h
Normal 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
37
src/cmd/upas/nfs/thread.c
Normal 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
13
src/cmd/upas/nfs/util.c
Normal 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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue