📄 imap4.c
字号:
if(imap->mustssl){ memset(&conn, 0, sizeof conn); sfd = tlsClient(imap->fd, &conn); if(sfd < 0) sysfatal("tlsClient: %r"); if(conn.cert==nil || conn.certlen <= 0) sysfatal("server did not provide TLS certificate"); sha1(conn.cert, conn.certlen, digest, nil); if(!imap->thumb || !okThumbprint(digest, imap->thumb)){ fmtinstall('H', encodefmt); sysfatal("server certificate %.*H not recognized", SHA1dlen, digest); } free(conn.cert); close(imap->fd); imap->fd = sfd; if(imap->debug){ char fn[128]; int fd; snprint(fn, sizeof fn, "%s/ctl", conn.dir); fd = open(fn, ORDWR); if(fd < 0) fprint(2, "opening ctl: %r\n"); if(fprint(fd, "debug") < 0) fprint(2, "writing ctl: %r\n"); close(fd); } } Binit(&imap->bin, imap->fd, OREAD); Binit(&imap->bout, imap->fd, OWRITE); if(err = imap4login(imap)) { close(imap->fd); return err; } return nil;}//// close connection//static voidimap4hangup(Imap *imap){ imap4cmd(imap, "LOGOUT"); imap4resp(imap); close(imap->fd);}//// download a single message//static char*imap4fetch(Mailbox *mb, Message *m){ int i; char *p, *s, sdigest[2*SHA1dlen+1]; Imap *imap; imap = mb->aux; imap->size = 0; if(!isokay(s = imap4resp(imap))) return s; p = imap->base; if(p == nil) return "did not get message body"; removecr(p); free(m->start); m->start = p; m->end = p+strlen(p); m->bend = m->rbend = m->end; m->header = m->start; imap->base = nil; imap->data = nil; parse(m, 0, mb, 1); // digest headers sha1((uchar*)m->start, m->end - m->start, m->digest, nil); for(i = 0; i < SHA1dlen; i++) sprint(sdigest+2*i, "%2.2ux", m->digest[i]); m->sdigest = s_copy(sdigest); return nil;}//// check for new messages on imap4 server// download new messages, mark deleted messages//static char*imap4read(Imap *imap, Mailbox *mb, int doplumb){ char *s; int i, ignore, nnew, t; Message *m, *next, **l; imap4cmd(imap, "STATUS %Z (MESSAGES UIDVALIDITY)", imap->mbox); if(!isokay(s = imap4resp(imap))) return s; imap->nuid = 0; imap->uid = erealloc(imap->uid, imap->nmsg*sizeof(imap->uid[0])); imap->muid = imap->nmsg; if(imap->nmsg > 0){ imap4cmd(imap, "UID FETCH 1:* UID"); if(!isokay(s = imap4resp(imap))) return s; } l = &mb->root->part; for(i=0; i<imap->nuid; i++){ ignore = 0; while(*l != nil){ if((*l)->imapuid == imap->uid[i]){ ignore = 1; l = &(*l)->next; break; }else{ // old mail, we don't have it anymore if(doplumb) mailplumb(mb, *l, 1); (*l)->inmbox = 0; (*l)->deleted = 1; l = &(*l)->next; } } if(ignore) continue; // new message m = newmessage(mb->root); m->mallocd = 1; m->inmbox = 1; m->imapuid = imap->uid[i]; // add to chain, will download soon *l = m; l = &m->next; } // whatever is left at the end of the chain is gone while(*l != nil){ if(doplumb) mailplumb(mb, *l, 1); (*l)->inmbox = 0; (*l)->deleted = 1; l = &(*l)->next; } // download new messages t = imap->tag; if(pipeline) switch(rfork(RFPROC|RFMEM)){ case -1: sysfatal("rfork: %r"); default: break; case 0: for(m = mb->root->part; m != nil; m = m->next){ if(m->start != nil) continue; if(imap->debug) fprint(2, "9X%d UID FETCH %lud (UID RFC822.SIZE BODY[])\r\n", t, (ulong)m->imapuid); Bprint(&imap->bout, "9X%d UID FETCH %lud (UID RFC822.SIZE BODY[])\r\n", t++, (ulong)m->imapuid); } Bflush(&imap->bout); _exits(nil); } nnew = 0; for(m=mb->root->part; m!=nil; m=next){ next = m->next; if(m->start != nil) continue; if(!pipeline){ Bprint(&imap->bout, "9X%lud UID FETCH %lud (UID RFC822.SIZE BODY[])\r\n", (ulong)imap->tag, (ulong)m->imapuid); Bflush(&imap->bout); } if(s = imap4fetch(mb, m)){ // message disappeared? unchain fprint(2, "download %lud: %s\n", (ulong)m->imapuid, s); delmessage(mb, m); mb->root->subname--; continue; } nnew++; if(doplumb) mailplumb(mb, m, 0); } if(pipeline) waitpid(); if(nnew || mb->vers == 0){ mb->vers++; henter(PATH(0, Qtop), mb->name, (Qid){PATH(mb->id, Qmbox), mb->vers, QTDIR}, nil, mb); } return nil;}//// sync mailbox//static voidimap4purge(Imap *imap, Mailbox *mb){ int ndel; Message *m, *next; ndel = 0; for(m=mb->root->part; m!=nil; m=next){ next = m->next; if(m->deleted && m->refs==0){ if(m->inmbox && (ulong)(m->imapuid>>32)==imap->validity){ imap4cmd(imap, "UID STORE %lud +FLAGS (\\Deleted)", (ulong)m->imapuid); if(isokay(imap4resp(imap))){ ndel++; delmessage(mb, m); } }else delmessage(mb, m); } } if(ndel){ imap4cmd(imap, "EXPUNGE"); imap4resp(imap); }}//// connect to imap4 server, sync mailbox//static char*imap4sync(Mailbox *mb, int doplumb){ char *err; Imap *imap; imap = mb->aux; if(err = imap4dial(imap)){ mb->waketime = time(0) + imap->refreshtime; return err; } if((err = imap4read(imap, mb, doplumb)) == nil){ imap4purge(imap, mb); mb->d->atime = mb->d->mtime = time(0); } /* * don't hang up; leave connection open for next time. */ // imap4hangup(imap); mb->waketime = time(0) + imap->refreshtime; return err;}static char Eimap4ctl[] = "bad imap4 control message";static char*imap4ctl(Mailbox *mb, int argc, char **argv){ int n; Imap *imap; imap = mb->aux; if(argc < 1) return Eimap4ctl; if(argc==1 && strcmp(argv[0], "debug")==0){ imap->debug = 1; return nil; } if(argc==1 && strcmp(argv[0], "nodebug")==0){ imap->debug = 0; return nil; } if(argc==1 && strcmp(argv[0], "thumbprint")==0){ if(imap->thumb) freeThumbprints(imap->thumb); imap->thumb = initThumbprints("/sys/lib/tls/mail", "/sys/lib/tls/mail.exclude"); } if(strcmp(argv[0], "refresh")==0){ if(argc==1){ imap->refreshtime = 60; return nil; } if(argc==2){ n = atoi(argv[1]); if(n < 15) return Eimap4ctl; imap->refreshtime = n; return nil; } } return Eimap4ctl;}//// free extra memory associated with mb//static voidimap4close(Mailbox *mb){ Imap *imap; imap = mb->aux; free(imap->freep); free(imap->base); free(imap->uid); if(imap->fd >= 0) close(imap->fd); free(imap);}//// open mailboxes of the form /imap/host/user//char*imap4mbox(Mailbox *mb, char *path){ char *f[10]; int mustssl, nf; Imap *imap; quotefmtinstall(); fmtinstall('Z', doublequote); if(strncmp(path, "/imap/", 6) != 0 && strncmp(path, "/imaps/", 7) != 0) return Enotme; mustssl = (strncmp(path, "/imaps/", 7) == 0); path = strdup(path); if(path == nil) return "out of memory"; nf = getfields(path, f, 5, 0, "/"); if(nf < 3){ free(path); return "bad imap path syntax /imap[s]/system[/user[/mailbox]]"; } imap = emalloc(sizeof(*imap)); imap->fd = -1; imap->debug = debug; imap->freep = path; imap->mustssl = mustssl; imap->host = f[2]; if(nf < 4) imap->user = nil; else imap->user = f[3]; if(nf < 5) imap->mbox = "Inbox"; else imap->mbox = f[4]; imap->thumb = initThumbprints("/sys/lib/tls/mail", "/sys/lib/tls/mail.exclude"); mb->aux = imap; mb->sync = imap4sync; mb->close = imap4close; mb->ctl = imap4ctl; mb->d = emalloc(sizeof(*mb->d)); //mb->fetch = imap4fetch; return nil;}//// Formatter for %"// Use double quotes to protect white space, frogs, \ and "//enum{ Qok = 0, Qquote, Qbackslash,};static intneedtoquote(Rune r){ if(r >= Runeself) return Qquote; if(r <= ' ') return Qquote; if(r=='\\' || r=='"') return Qbackslash; return Qok;}intdoublequote(Fmt *f){ char *s, *t; int w, quotes; Rune r; s = va_arg(f->args, char*); if(s == nil || *s == '\0') return fmtstrcpy(f, "\"\""); quotes = 0; for(t=s; *t; t+=w){ w = chartorune(&r, t); quotes |= needtoquote(r); } if(quotes == 0) return fmtstrcpy(f, s); fmtrune(f, '"'); for(t=s; *t; t+=w){ w = chartorune(&r, t); if(needtoquote(r) == Qbackslash) fmtrune(f, '\\'); fmtrune(f, r); } return fmtrune(f, '"');}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -