⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 imap4.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include "common.h"#include <ctype.h>#include <plumb.h>#include <libsec.h>#include <auth.h>#include "dat.h"#pragma varargck argpos imap4cmd 2#pragma varargck	type	"Z"	char*int	doublequote(Fmt*);int	pipeline = 1;static char Eio[] = "i/o error";typedef struct Imap Imap;struct Imap {	char *freep;	// free this to free the strings below	char *host;	char *user;	char *mbox;	int mustssl;	int refreshtime;	int debug;	ulong tag;	ulong validity;	int nmsg;	int size;	char *base;	char *data;	vlong *uid;	int nuid;	int muid;	Thumbprint *thumb;	// open network connection	Biobuf bin;	Biobuf bout;	int fd;};static char*removecr(char *s){	char *r, *w;	for(r=w=s; *r; r++)		if(*r != '\r')			*w++ = *r;	*w = '\0';	return s;}//// send imap4 command//static voidimap4cmd(Imap *imap, char *fmt, ...){	char buf[128], *p;	va_list va;	va_start(va, fmt);	p = buf+sprint(buf, "9X%lud ", imap->tag);	vseprint(p, buf+sizeof(buf), fmt, va);	va_end(va);	p = buf+strlen(buf);	if(p > (buf+sizeof(buf)-3))		sysfatal("imap4 command too long");	if(imap->debug)		fprint(2, "-> %s\n", buf);	strcpy(p, "\r\n");	Bwrite(&imap->bout, buf, strlen(buf));	Bflush(&imap->bout);}enum {	OK,	NO,	BAD,	BYE,	EXISTS,	STATUS,	FETCH,	UNKNOWN,};static char *verblist[] = {[OK]		"OK",[NO]		"NO",[BAD]	"BAD",[BYE]	"BYE",[EXISTS]	"EXISTS",[STATUS]	"STATUS",[FETCH]	"FETCH",};static intverbcode(char *verb){	int i;	char *q;	if(q = strchr(verb, ' '))		*q = '\0';	for(i=0; i<nelem(verblist); i++)		if(verblist[i] && strcmp(verblist[i], verb)==0){			if(q)				*q = ' ';			return i;		}	if(q)		*q = ' ';	return UNKNOWN;}static voidstrupr(char *s){	for(; *s; s++)		if('a' <= *s && *s <= 'z')			*s += 'A'-'a';}static voidimapgrow(Imap *imap, int n){	int i;	if(imap->data == nil){		imap->base = emalloc(n+1);			imap->data = imap->base;		imap->size = n+1;	}	if(n >= imap->size){		// friggin microsoft - reallocate		i = imap->data - imap->base;		imap->base = erealloc(imap->base, i+n+1);		imap->data = imap->base + i;		imap->size = n+1;	}}//// get imap4 response line.  there might be various // data or other informational lines mixed in.//static char*imap4resp(Imap *imap){	char *line, *p, *ep, *op, *q, *r, *en, *verb;	int i, n;	static char error[256];	while(p = Brdline(&imap->bin, '\n')){		ep = p+Blinelen(&imap->bin);		while(ep > p && (ep[-1]=='\n' || ep[-1]=='\r'))			*--ep = '\0';				if(imap->debug)			fprint(2, "<- %s\n", p);		strupr(p);		switch(p[0]){		case '+':			if(imap->tag == 0)				fprint(2, "unexpected: %s\n", p);			break;		// ``unsolicited'' information; everything happens here.		case '*':			if(p[1]!=' ')				continue;			p += 2;			line = p;			n = strtol(p, &p, 10);			if(*p==' ')				p++;			verb = p;						if(p = strchr(verb, ' '))				p++;			else				p = verb+strlen(verb);			switch(verbcode(verb)){			case OK:			case NO:			case BAD:				// human readable text at p;				break;			case BYE:				// early disconnect				// human readable text at p;				break;			// * 32 EXISTS			case EXISTS:				imap->nmsg = n;				break;			// * STATUS Inbox (MESSAGES 2 UIDVALIDITY 960164964)			case STATUS:				if(q = strstr(p, "MESSAGES"))					imap->nmsg = atoi(q+8);				if(q = strstr(p, "UIDVALIDITY"))					imap->validity = strtoul(q+11, 0, 10);				break;			case FETCH:				// * 1 FETCH (uid 8889 RFC822.SIZE 3031 body[] {3031}				// <3031 bytes of data> 				// )				if(strstr(p, "RFC822.SIZE") && strstr(p, "BODY[]")){					if((q = strchr(p, '{')) 					&& (n=strtol(q+1, &en, 0), *en=='}')){						if(imap->data == nil || n >= imap->size)							imapgrow(imap, n);						if((i = Bread(&imap->bin, imap->data, n)) != n){							snprint(error, sizeof error,								"short read %d != %d: %r\n",								i, n);							return error;						}						if(imap->debug)							fprint(2, "<- read %d bytes\n", n);						imap->data[n] = '\0';						if(imap->debug)							fprint(2, "<- %s\n", imap->data);						imap->data += n;						imap->size -= n;						p = Brdline(&imap->bin, '\n');						if(imap->debug)							fprint(2, "<- ignoring %.*s\n",								Blinelen(&imap->bin), p);					}else if((q = strchr(p, '"')) && (r = strchr(q+1, '"'))){						*r = '\0';						q++;						n = r-q;						if(imap->data == nil || n >= imap->size)							imapgrow(imap, n);						memmove(imap->data, q, n);						imap->data[n] = '\0';						imap->data += n;						imap->size -= n;					}else						return "confused about FETCH response";					break;				}				// * 1 FETCH (UID 1 RFC822.SIZE 511)				if(q=strstr(p, "RFC822.SIZE")){					imap->size = atoi(q+11);					break;				}				// * 1 FETCH (UID 1 RFC822.HEADER {496}				// <496 bytes of data> 				// )				// * 1 FETCH (UID 1 RFC822.HEADER "data")				if(strstr(p, "RFC822.HEADER") || strstr(p, "RFC822.TEXT")){					if((q = strchr(p, '{')) 					&& (n=strtol(q+1, &en, 0), *en=='}')){						if(imap->data == nil || n >= imap->size)							imapgrow(imap, n);						if((i = Bread(&imap->bin, imap->data, n)) != n){							snprint(error, sizeof error,								"short read %d != %d: %r\n",								i, n);							return error;						}						if(imap->debug)							fprint(2, "<- read %d bytes\n", n);						imap->data[n] = '\0';						if(imap->debug)							fprint(2, "<- %s\n", imap->data);						imap->data += n;						imap->size -= n;						p = Brdline(&imap->bin, '\n');						if(imap->debug)							fprint(2, "<- ignoring %.*s\n",								Blinelen(&imap->bin), p);					}else if((q = strchr(p, '"')) && (r = strchr(q+1, '"'))){						*r = '\0';						q++;						n = r-q;						if(imap->data == nil || n >= imap->size)							imapgrow(imap, n);						memmove(imap->data, q, n);						imap->data[n] = '\0';						imap->data += n;						imap->size -= n;					}else						return "confused about FETCH response";					break;				}				// * 1 FETCH (UID 1)				// * 2 FETCH (UID 6)				if(q = strstr(p, "UID")){					if(imap->nuid < imap->muid)						imap->uid[imap->nuid++] = ((vlong)imap->validity<<32)|strtoul(q+3, nil, 10);					break;				}			}			if(imap->tag == 0)				return line;			break;		case '9':		// response to our message			op = p;			if(p[1]=='X' && strtoul(p+2, &p, 10)==imap->tag){				while(*p==' ')					p++;				imap->tag++;				return p;			}			fprint(2, "expected %lud; got %s\n", imap->tag, op);			break;		default:			if(imap->debug || *p)				fprint(2, "unexpected line: %s\n", p);		}	}	snprint(error, sizeof error, "i/o error: %r\n");	return error;}static intisokay(char *resp){	return strncmp(resp, "OK", 2)==0;}//// log in to IMAP4 server, select mailbox, no SSL at the moment//static char*imap4login(Imap *imap){	char *s;	UserPasswd *up;	imap->tag = 0;	s = imap4resp(imap);	if(!isokay(s))		return "error in initial IMAP handshake";	if(imap->user != nil)		up = auth_getuserpasswd(auth_getkey, "proto=pass service=imap server=%q user=%q", imap->host, imap->user);	else		up = auth_getuserpasswd(auth_getkey, "proto=pass service=imap server=%q", imap->host);	if(up == nil)		return "cannot find IMAP password";	imap->tag = 1;	imap4cmd(imap, "LOGIN %Z %Z", up->user, up->passwd);	free(up);	if(!isokay(s = imap4resp(imap)))		return s;	imap4cmd(imap, "SELECT %Z", imap->mbox);	if(!isokay(s = imap4resp(imap)))		return s;	return nil;}//// push tls onto a connection//intmypushtls(int fd){	int p[2];	char buf[10];	if(pipe(p) < 0)		return -1;	switch(fork()){	case -1:		close(p[0]);		close(p[1]);		return -1;	case 0:		close(p[1]);		dup(p[0], 0);		dup(p[0], 1);		sprint(buf, "/fd/%d", fd);		execl("/bin/tlsrelay", "tlsrelay", "-f", buf, nil);		_exits(nil);	default:		break;	}	close(fd);	close(p[0]);	return p[1];}//// dial and handshake with the imap server//static char*imap4dial(Imap *imap){	char *err, *port;	uchar digest[SHA1dlen];	int sfd;	TLSconn conn;	if(imap->fd >= 0){		imap4cmd(imap, "noop");		if(isokay(imap4resp(imap)))			return nil;		close(imap->fd);		imap->fd = -1;	}	if(imap->mustssl)		port = "imaps";	else		port = "imap";	if((imap->fd = dial(netmkaddr(imap->host, "net", port), 0, 0, 0)) < 0)		return geterrstr();

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -