Plan 9 from Bell Labs’s /usr/web/sources/contrib/gabidiaz/wip/mboxfs/mbox.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#include "a.h"


#define IS_HEADER(p) ((p)[0]=='F'&&(p)[1]=='r'&&(p)[2]=='o'&&(p)[3]=='m'&&(p)[4]==' ')
#define IS_BODY(p) ((p)[0]=='\n'&&(p)[1]==0)
enum {
	HEADER,
	BOUNDARY,
	ENDBOUNDARY,
	REGULAR,
	ENDF,
};

void
initmsg(Message *m) 
{
	m->bcc=(*mbox_bcc);
	m->body=(*mbox_body);
	m->cc=(*mbox_cc);
	m->date=(*mbox_date);
	m->digest=(*mbox_digest);
	m->disposition=(*mbox_disposition);
	m->filename=(*mbox_filename);
	m->from=(*mbox_from);
	m->header=(*mbox_header);
	m->info=(*mbox_info);
	m->inreplyto=(*mbox_inreplyto);
	m->lines=(*mbox_lines);
	m->messageid=(*mbox_messageid);
	m->mimeheader=(*mbox_mimeheader);
	m->raw=(*mbox_raw);
	m->rawbody=(*mbox_rawbody);
	m->rawheader=(*mbox_rawheader);
	m->rawunix=(*mbox_rawunix);
	m->replyto=(*mbox_replyto);
	m->sender=(*mbox_sender);
	m->subject=(*mbox_subject);
	m->to=(*mbox_to);
	m->type=(*mbox_type);
	m->unixdate=(*mbox_unixdate);
	m->unixheader=(*mbox_unixheader);

}

void
initbox(Mailbox *b)
{
	b->sync=nil;
	b->open=(*mbox_open);
	b->fetch=(*mbox_fetch);
	b->purge=nil;
}


/* I/O routunes */

char*
getline(Biobuf *b) 
{
	int c;
	String *line;
	char *res;

	line=s_new();
	c=Bgetc(b);

	while(c > 0 && c != '\n' && c != '\r') {
		s_putc(line,c);
		c=Bgetc(b);
	}

	if (c == '\n' || c=='\r')
 		s_putc(line,'\n');

	if (s_len(line) > 0) {
		s_terminate(line);
		res=estrdup(s_to_c(line));
		setmalloctag(res,getcallerpc(&b));
		s_free(line);
		return res;
	}

	s_free(line);
	return nil;

}

vlong
getdigest(Message *m, char **buff)
{
	char *sdigest;
	uchar hash[SHA1dlen];

	sdigest=emalloc(SHA1dlen*2+1);
	sha1(m->cache->b, m->cache->l, hash, nil);

	for(int i = 0; i < SHA1dlen; i++)
		sprint(sdigest+2*i, "%2.2ux", hash[i]);

	sdigest[SHA1dlen+1]=0;
	*buff=sdigest;
	return (vlong)strlen(*buff);
}

vlong
getdatacache(Message *m, char **buff, vlong offset, vlong len) 
{
	uchar *pc;
	char *ptr;

	pc=m->cache->b+offset;

	ptr=emalloc(len);
	memcpy(ptr,pc,len);
	setmalloctag(ptr,getcallerpc(&m));
	*buff=ptr;

	return len;
}

vlong
getdatadisk(Message *m, char **buff, vlong offset, vlong len) 
{
	Mailbox *b;
	long n;
	char *ptr;

	b = m->b;

	if ( Bseek(&b->br,offset,SEEK_SET) != offset) {
		error(DEBUG,"getdatadisk(): error in Bseek (eof?)");
		return -1;
	}
	
	ptr=emalloc(len);

	if ( (n=Bread(&b->br,ptr,len)) != len ) {
		error(DEBUG,"getdatadisk(): error in Bread (eof?)");
		free(ptr);
		return -1;
	}

	setmalloctag(ptr,getcallerpc(&m));
	*buff=ptr;
	
	return (vlong)n;

}

vlong
getdata(Message *m, char **buff, vlong start, vlong end, vlong offset, vlong len)
{
	Message *root;
	char *cbuff;
	char *dbuff;
	int merge;
	vlong cstart, clen, cend, rlen;
	vlong dstart, dlen;

	rlen=0;
	merge=0;
	root=m->root;

	if (len == 0 ) {
		*buff=nil;
		return 0;
	}

	if ( len > end-start )
		len=end-start;

	cstart=(start+offset)-root->start;
	clen=len;
	cend=end-root->start;

	if ( cend > CACHELEN )
		cend=CACHELEN;

	rlen=0;

	/* if there is something in cache, read it */
	if ( cstart <  cend ) {
		if ( cstart+clen > cend ) {
			merge=1;
			clen=cend-cstart;
		}
		/* rlen is allways clen here */
		rlen=getdatacache(m, &cbuff, cstart,clen);
		if ( rlen <= 0 ) {
			error(DEBUG,"getdata(): I/O error %d\n", rlen);
			*buff=nil;
			return 0;
		} 
	}

	clen=rlen;

	/* if we have all, return */
	if ( clen == len ) {
			*buff=cbuff;
			return clen;
	}

	dstart=start+offset+clen;
	dlen=len-clen;

	if ( dstart < end ) {
		if ( dstart+dlen > end )
			dlen=end-dstart;
		rlen=getdatadisk(m,&dbuff,dstart,dlen);
		if ( rlen < 0 ) {
			*buff=nil;
			return 0;
		} else
			dlen=rlen;
	} else {
		*buff=nil;
		return 0;
	}

	if ( merge == 1 ) {
		*buff=emalloc(clen+dlen);
		memcpy(*buff,cbuff,clen);
		memcpy(*buff+clen,dbuff,dlen);
		free(cbuff);
		free(dbuff);
	} else {
		*buff=dbuff;
	}

	return clen+dlen;
}


char*
gethdr(Message *m, char *term)
{
	String *item;
	int pos;
	vlong hlen;
	char *r;
	char *hdr;

	item=s_newalloc(MAX_LINE);	// max line size rfc822


	hlen=m->hend-m->hstart;
	hlen=getdata(m,&hdr,m->hstart,m->hend,0,hlen);
	if ( hdr == nil ) {
		return nil;
	}

	pos=0;
	

	while(hdr[pos] != 0 && pos <= hlen) {
		if ( hdr[pos] == '\n' ) {
			if ( pos < hlen )
				pos++;
			if ( hdr[pos] != ' ' && hdr[pos] != '\t' ) {
				s_terminate(item);
				if (cistrncmp(s_to_c(item),term,strlen(term)) != 0 ) {
					s_free(item);
					item=s_newalloc(MAX_LINE);
				} else {
					break;
				}
			}
		} else {
			s_putc(item,hdr[pos]);
			pos++;
		}
	}

	if ( s_len(item) <= 0 ) {
		s_free(item);
		free(hdr);
		return nil;
	}

	s_terminate(item);
	r=estrdup(s_to_c(item));
	s_free(item);
	free(hdr);
	setmalloctag(r,getcallerpc(&m));
	return r;

}

vlong
getterm(Message *m, char **buff, char *term) 
{
	char *q,*aux,*resp;

	aux=gethdr(m,term);

	if ( aux == nil ) {
		*buff=nil;
		return 0;
	}
	
	q=strstr(aux,":");
	if(q!=nil) {
		q++;
		resp=strdup(q);
		free(aux);
		*buff=resp;
		return (vlong)strlen(resp);
	}
	
	free(aux);
	*buff=nil;
	return 0;

}

char*
nexttok(char *p,int c)
{
	char *q;
	q=p;

	while( *q != 0 && *q!=c)
		q++;

	return q;
}

char*
getattr(char *str, char *attr)
{
	String *val;
	char *v;
	char *q;

	val=s_new();
	q=strtok(str,";");
	while (q!=nil) {
		q++;	//skip ; 
		while( (*q == ' ' || *q == '\t') && *q != 0 )
			q++;
	
		if ( *q != 0 && cistrncmp(q,attr,strlen(attr)) == 0 ) {
			q+=strlen(attr)+1; 			// skip the = sign
			if (*q == '"')
				q++;

			while(*q!=0 && *q!='"') {
				s_putc(val,*q);
				q++;
			}
			
			if( s_len(val) <= 0) {
				s_free(val);
				return nil;
			}
			s_terminate(val);
			v=strdup(s_to_c(val));
			s_free(val);
			setmalloctag(v,getcallerpc(&str));
			return v;
		}
		q=strtok(nil,";");
	}
	s_free(val);
	return nil;
}

char*
getval(char *str)
{
	char *q;
	String *item;
	char *v;

	q=str;
	item=s_new();

	while(*q == ' ' || *q == '\t')
		q++;

	while(*q != ';' && *q != 0) {
		s_putc(item,*q);
		q++;
	}
	
	if( s_len(item) <= 0 ) {
		s_free(item);
		return nil;
	}
	s_terminate(item);
	v=strdup(s_to_c(item));
	s_free(item);
	setmalloctag(v,getcallerpc(&str));

	return v;

}


int
cache(Message *m, char *buff, int len)
{

	if ( buff == nil )
		return 0;

	if ( m->cache->l >= CACHELEN )
		return 0;

	if ( (m->cache->l+len) > CACHELEN )
		len=CACHELEN-m->cache->l;
			
	memcpy(&m->cache->b[m->cache->l],buff,len);
	m->cache->l+=len;

	return 1;
}


/* parsing functions */
char*
parsedate(Message *m) 
{
	char *str;
	char *p, *q;
	Tm tm;
	char *date;
	char *resp;

	getterm(m,&str, "Received");

	if ( str == nil )
		return nil;

	if((q = strchr(str, ';')) != nil){
		p = q;
		while((p = strchr(p, '\n')) != nil){
			if(p[1] != ' ' && p[1] != '\t' && p[1] != '\n')
				break;
			p++;
		}
		
		if ( strtotm(q+1,&tm) <0) {
			free(str);
			return nil;
		}
	} else {
		free(str);
		return nil;
	}

	date = asctime(&tm);
	if(q = strchr(date, '\n'))
		*q = '\0';

	free(str);

	resp=estrdup(date);
	return resp;
}



int
isbox(Mailbox *b)
{
	char *line;
	vlong pos;

	pos=Boffset(&b->br);

	line=getline(&b->br);
	if ( line == nil )
			return 0;
	/* A mbox file each msg should start with 
			From <email> <date>
		  we just check the From<space> */
	Bseek(&b->br, pos, SEEK_SET);

	if (IS_HEADER(line)) {
		free(line);
		return 1;
	 }else {
		free(line);
		return 0;
	}
}



int
islike(char *b1, char *b2)
{
	if ( b1 != nil && b2 != nil)
		return cistrncmp(b1,b2,strlen(b2));
	else
		return -1;
}


int
skipnewlines(Message *m)
{
	Mailbox *b;
	char *line;
	vlong pos;
	
	b=m->b;

	while( (line=getline(&b->br)) !=nil) {
			if ( line[0]!='\n')
				break;
			cache(m,line,strlen(line));
			free(line);
	}
	if (line != nil) {
		pos=Boffset(&b->br)-strlen(line);
		Bseek(&b->br,pos,SEEK_SET);
		free(line);
	}
	return 1;

}

int
ismark(Message *m, char *s, int lastnl)
{	

		if ( s == nil )
			return ENDF;

		if (lastnl == '\n' && IS_HEADER(s))
			return HEADER;

		if (islike(s,m->mime.endboundary) == 0 )
			return ENDBOUNDARY;
 
		if (islike(s,m->mime.boundary) == 0) 
			return BOUNDARY;

	return REGULAR;

}

int
parsemime(Message *m)
{
	char *str;
	char *aux;
	int l,r;

	r=0;

	l=getterm(m,&str,"Content-Type:");
	if ( l > 0 ) {
		m->mime.type=getval(str);
		aux=getattr(str,"boundary");
		if ( aux != nil ) {
			m->mime.boundary=smprint("--%s",aux);
			m->mime.endboundary=smprint("--%s--",aux);
			free(aux);
			r=1;
		}
		free(str);
	}

	l=getterm(m,&str,"Content-Disposition:");
	if ( l  > 0) {
		m->mime.disposition=getval(str);
		m->mime.filename=getattr(str,"filename");
		free(str);
	}

	l=getterm(m,&str,"Content-Transfer-Encoding:");
	if (l  > 0){
		m->mime.encoding=getval(str);
		free(str);
	}

	return r;

}
int
parsehdr(Message *m)
{
	Mailbox *b;
	char *line;
	int linelen;
	b=m->b;

	m->hstart=Boffset(&b->br);

	while( (line=getline(&b->br) ) != nil ) {
		m->linecount++;
		linelen=strlen(line);
		if ( cache(m, line, linelen) == 0 )
			error(DEBUG,"parsehdr(): error caching line\n");

		if ( line[0] == '\n' ) {	// end of header is an empty line
			m->hend=Boffset(&b->br);
			free(line);
			return 1;
		}
		free(line);
	}

	m->hend=Boffset(&b->br);
	return 0;
}

int
parsebody(Message *m)
{
	Mailbox *b;
	char *line;
	int linelen;
	vlong pos;
	int lastnl;
	int q;
	b=m->b;
	
	m->bstart=Boffset(&b->br);
	lastnl=0;

	while ( (line=getline(&b->br) ) != nil ) {
		m->linecount++;
		linelen=strlen(line);
		
		q=ismark(m,line,lastnl);
		if ( q != REGULAR ) {
			pos=Boffset(&b->br)-linelen;
			Bseek(&b->br,pos,SEEK_SET);
			m->bend=pos;
			m->end=m->bend;
			free(line);
			
			return q;
		}
		cache(m, line, linelen);
		lastnl=line[0];
		free(line);
	}

	m->bend=Boffset(&b->br);
	m->end=m->bend;

	return 0;

}



void
copymimeboundary(Message *m1, Message *m2)
{

	if ( m1 != nil && m2 != nil && m1==m2 )
		return;

	if (m2->mime.boundary != nil )
		m1->mime.boundary=strdup(m2->mime.boundary);

	if (m2->mime.endboundary != nil )
		m1->mime.endboundary=strdup(m2->mime.endboundary);


}
int
findboundary(Message *m)
{
	Mailbox *b;
	char *line;
	int lastnl,q;

	b=m->b;
	lastnl=0;
	while ( (line=getline(&b->br) ) != nil ) {
		q=ismark(m,line,lastnl);
		cache(m,line,strlen(line));
		if ( q != REGULAR && q != HEADER ) {
			free(line);
			return q;
		}
		lastnl=line[0];
		free(line);
	}

	return ENDF;

}


Message*
parseparts(Mailbox *b, Message *last)
{
	Message *m, *part, *next;
	int r, nparts;

	m=newmsg(Boffset(&b->br)); 
	initmsg(m);
	m->b=last->b;
	m->id=last->id+1;
	m->cache=last->cache;
	m->root=last->root;


	r=parsehdr(m);
	if ( r==0 ) {
		freem(m);
		return nil;
	}

	r=parsemime(m);
 	if (r == 0 && last != nil )
		copymimeboundary(m,last);

	part=nil;
	if ( islike(m->mime.type,"multipart/") == 0) {
		
		skipnewlines(m);
		do {
			r=findboundary(m);
		} while ( r != BOUNDARY && r != ENDF);

		if (  r == ENDF )
			return nil;

		m->bstart=Boffset(&b->br);
		nparts=0;

		do {
			if ( (next=parseparts(b,m) ) == nil)
				break;
			
			nparts++;
			next->id=nparts;
			
			if ( nparts == 1 ) {
				m=ptoend(m,next);
				part=next;
			} else 
				part=mtoend(part,next);	
			
		} while ( next->status == BOUNDARY );


		do {
			r=findboundary(m);
		} while ( r != BOUNDARY && r != ENDBOUNDARY && r != ENDF);

		if (  r == ENDF )
			return nil;

		m->status=r;
		
		skipnewlines(m);
		m->end=Boffset(&b->br);

	} else
		m->status=parsebody(m);

	return m;

}


/* interface to fs module */

/* message operations */
vlong
mbox_date(Message *m, char **buff)
{
	*buff=parsedate(m);
	if ( *buff != nil )
		return strlen(*buff);
	else
		return 0;
}

vlong
mbox_from(Message *m,char **buff) 
{
	char *str;
	vlong len;

	len=getterm(m, &str, "From:");
	*buff=addrrfc(str);
	free(str);
	if (*buff !=nil)
		return strlen(*buff);

	return 0;
}

vlong
mbox_to(Message *m, char **buff) 
{
	char *str;
	vlong len;

	len=getterm(m, &str, "To:");
	*buff=addrrfc(str);
	free(str);
	if (*buff !=nil)
		return strlen(*buff);

	return 0;
}

vlong
mbox_inreplyto(Message *m,char **buff) 
{
	char *str;
	vlong len;

	len=getterm(m, &str, "In-Reply-To:");
	*buff=addrrfc(str);
	free(str);
	if (*buff !=nil)
		return strlen(*buff);

	return 0;
}

vlong
mbox_replyto(Message *m, char **buff) 
{
	char *str;
	vlong len;

	len=getterm(m, &str, "Reply-To:");
	*buff=addrrfc(str);
	free(str);
	if (*buff !=nil)
		return strlen(*buff);

	return 0;
}

vlong
mbox_sender(Message *m,char **buff) 
{
	char *str;
	vlong len;

	len=getterm(m, &str, "Sender:");
	*buff=addrrfc(str);
	free(str);
	if (*buff !=nil)
		return strlen(*buff);

	return 0;
}
vlong
mbox_bcc(Message* m,char **buff) 
{
	char *str;
	vlong len;

	len=getterm(m, &str, "Bcc:");
	*buff=addrrfc(str);
	free(str);
	if (*buff !=nil)
		return strlen(*buff);

	return 0;
}

vlong
mbox_cc(Message* m,char **buff)
 {
	char *str;
	vlong len;

	len=getterm(m, &str, "Cc:");
	*buff=addrrfc(str);
	free(str);
	if (*buff !=nil)
		return strlen(*buff);

	return 0;
}

vlong
mbox_subject(Message *m, char **buff) 
{
	return getterm(m,buff,"Subject:");
}

vlong
mbox_messageid(Message *m, char **buff) 
{
	return getterm(m,buff, "Message-ID:");
}

vlong
mbox_disposition(Message *, char **buff) 
{
	*buff=nil;
	return 0;
}

vlong
mbox_filename(Message*,char **buff)
{
	*buff=nil;
	return 0;
}

vlong
mbox_digest(Message *m, char**buff) 
{
	return getdigest(m,buff);
}

vlong
mbox_lines(Message *m, char **buff) 
{
	*buff=smprint("%d",m->linecount);
	return (vlong)strlen(*buff);
}

vlong
mbox_header(Message *m ,char **buff) 
{
	Fmt info;
	char *s;
	char *a;
	fmtstrinit(&info);

	getterm(m,&s,"From:");
	if ( s!= nil ) {
		a=addrrfc(s);
		fmtprint(&info,"From: %s\n",a);
		free(a);
		free(s);
	}

	getterm(m,&s,"To:");
	if ( s!= nil ) {
		a=addrrfc(s);
		fmtprint(&info,"To: %s\n",a);
		free(a);
		free(s);
	}

	getterm(m,&s,"Cc:");
	if ( s!= nil ) {
		a=addrrfc(s);
		fmtprint(&info,"Cc: %s\n",a);
		free(a);
		free(s);
	}

	getterm(m,&s,"Reply-To:");
	if ( s!= nil ) {
		a=addrrfc(s);
		fmtprint(&info,"Reply-To: %s\n",a);
		free(a);
		free(s);
	}

	s=parsedate(m);
	if ( s!= nil ) {
		fmtprint(&info,"Date: %s\n",s);
		free(s);
	}

	getterm(m,&s, "Subject:");
	if ( s!= nil ) {
		a=stringconvert(s);
		fmtprint(&info,"Subject: %s\n",a);
		free(a);
		free(s);
	}

	getterm(m,&s,"Bcc:");
	if ( s!= nil ) {
		a=addrrfc(s);
		fmtprint(&info,"Bcc: %s\n",a);
		free(a);
		free(s);
	}

	getterm(m,&s,"In-Reply-To:");
	if ( s!= nil ) {
		a=addrrfc(s);
		fmtprint(&info,"In-Reply-To: %s\n",a);
		free(a);
		free(s);
	}


	*buff=fmtstrflush(&info);

	return (vlong)strlen(*buff);

}

/* used by nedmail client
          sender address
          recipient addresses
          cc addresses
          reply address
          envelope date
          subject
          MIME content type
          MIME disposition
          filename
          SHA1 digest
          bcc addresses
          in-reply-to: contents
          RFC822 date
          message senders
          message id
          number of lines in body
	
	if not found a \n is returned;
*/
vlong
mbox_info(Message*m, char **buff)
{
	Fmt info;
	char *s;
	char *aux;
	fmtstrinit(&info);

	getterm(m,&s,"From:");
	aux=addrrfc(s);
	if ( aux != nil )
		fmtprint(&info,"%s\n",aux);
	else 
		fmtprint(&info,"\n");
	free(s); free(aux);

	getterm(m,&s,"To:");
	aux=addrrfc(s);
	if ( aux != nil )
		fmtprint(&info,"%s\n",aux);
	else 
		fmtprint(&info,"\n");
	free(s); free(aux);

	getterm(m,&s,"Cc:");
	aux=addrrfc(s);
	if ( aux != nil )
		fmtprint(&info,"%s\n",aux);
	else 
		fmtprint(&info,"\n");
	free(s); free(aux);

	getterm(m,&s,"Reply-To:");
	aux=addrrfc(s);
	if ( aux != nil )
		fmtprint(&info,"%s\n",aux);
	else 
		fmtprint(&info,"\n");
	free(s); free(aux);

	s=parsedate(m);
	if ( s != nil )
		fmtprint(&info,"%s\n",s);
	else 
		fmtprint(&info,"\n");
	free(s);

	getterm(m,&s, "Subject:");
	aux=stringconvert(s);
	if ( aux != nil )
		fmtprint(&info,"%s\n",aux);
	else 
		fmtprint(&info,"\n");
	free(s);free(aux);

	if (m->mime.type != nil )
		fmtprint(&info,"%s\n",m->mime.type);
	else
		fmtprint(&info,"\n");

	if (m->mime.disposition != nil )
		fmtprint(&info,"%s\n",m->mime.disposition);
	else
		fmtprint(&info,"\n");

	if ( m->mime.filename != nil )
		fmtprint(&info,"%s\n",m->mime.filename);
	else
		fmtprint(&info,"\n");

	getdigest(m,&s);
	if ( s != nil )
		fmtprint(&info,"%s\n",s);
	else 
		fmtprint(&info,"\n");
	free(s);

	getterm(m,&s,"Bcc:");
	aux=addrrfc(s);
	if ( aux != nil )
		fmtprint(&info,"%s\n",aux);
	else 
		fmtprint(&info,"\n");
	free(s); free(aux);

	getterm(m,&s,"In-Reply-To:");
	aux=addrrfc(s);
	if ( aux != nil )
		fmtprint(&info,"%s\n",aux);
	else 
		fmtprint(&info,"\n");
	free(s); free(aux);

	s=parsedate(m);
	if ( s != nil )
		fmtprint(&info,"%s\n",s);
	else 
		fmtprint(&info,"\n");
	free(s);

	getterm(m,&s,"From:");
	aux=stringconvert(s);
	if ( aux != nil )
		fmtprint(&info,"%s\n",aux);
	else 
		fmtprint(&info,"\n");
	free(s); free(aux);

	getterm(m,&s,"Message-ID:");
	if ( s != nil )
		fmtprint(&info,"%s\n",s);
	else 
		fmtprint(&info,"\n");
	free(s);
	
	fmtprint(&info,"%8.d\n",m->linecount);

	*buff=fmtstrflush(&info);

	return (vlong)strlen(*buff);

}

vlong
mbox_mimeheader(Message*,char **buff)
{
	*buff=nil;
	return 0;
}

vlong
mbox_raw(Message *m,char **buff, vlong offset, vlong len) {
	return getdata(m, buff, m->start, m->end, offset, len);
}

vlong
mbox_rawbody(Message *m,char **buff, vlong offset, vlong len) {
	return getdata(m, buff, m->bstart, m->bend, offset, len);
}

vlong
mbox_body(Message *m,char **buff, vlong offset, vlong len) 
{
	return getdata(m, buff, m->bstart, m->bend, offset, len);
}

vlong
mbox_rawheader(Message *m,char **buff, vlong offset, vlong len) 
{
	return getdata(m, buff, m->hstart, m->hend, offset, len);
}

vlong
mbox_rawunix(Message *m,char **buff, vlong offset, vlong len) 
{
	return getdata(m, buff, m->start, m->end, offset, len);
}

vlong
mbox_type(Message *m,char **buff) {
	return getterm(m,buff, "Content-Type:");
}

vlong
mbox_unixdate(Message *m,char **buff) 
{
	*buff=parsedate(m);
	if ( *buff != nil )
		return strlen(*buff);
	else
		return 0;
}

vlong
mbox_unixheader(Message *m,char **buff) 
{
	char *str;

	str=gethdr(m,"From ");
	if ( str == nil )
		return 0;

	*buff=smprint("%s\n",str);
	free(str);

	return strlen(*buff);
}

/* box operations */



int
mbox_fetch(Mailbox *b) 
{
	Message *m, *part, *next;
	int r, np;

	if ( ! isbox(b) )
		error(FATAL,"mbox_fetch(): error in mbox format\n");

	do {
		m=newmsg(Boffset(&b->br));
		initmsg(m);
		m->b=b;
		m->id=b->idc+1;
		m->cache=emalloc(sizeof *b->msgs->cache);
		m->cache->l=0;
		m->root=m;


		r=parsehdr(m);
		if ( r==0 ) {
			freem(m);
			break;
		}

		r=parsemime(m);
		np=1;
		part=m;
		m->bstart=Boffset(&b->br);
		if ( islike(m->mime.type,"multipart/") == 0) {
			do {
				next=parseparts(b,m);
				if ( next == nil )
					break;

				next->id=np;

				if ( np == 1) {
					m=ptoend(m,next);
					part=next;
				} else
					part=mtoend(part,next);

			
				r=findboundary(m);
				skipnewlines(m);
			
				np++;
			} while ( r == BOUNDARY);
			
		} else
			r=parsebody(m);

		m->bend=Boffset(&b->br);
		m->end=m->bend;
		b->msgs=mtofront(b->msgs,m);
		b->idc++;
	} while ( r != ENDF  );

	return 1;

}

int
mbox_open(Mailbox *b) 
{

	if ( b->file == nil )
		error(FATAL,"mbox_open(): b->name == nil");

	b->r=open(b->file,OREAD);
	b->w=open(b->file,ORDWR);
	b->idc=0;

	if ( b->r < 0 || b->w < 0 )
		error(FATAL,"Error opening %s\n",b->file);
	
	Binit(&b->br, b->r,OREAD);
	Binit(&b->bw,b->w,OWRITE);

	return 1;
}



int
mbox_delete(Message *m) {
	Dir *d;	
	int c;
	vlong from, to, rpos, wpos, offset, newlen;
	Biobuf *r,*w;

	r=&m->b->br;
	w=&m->b->bw;

	from=m->start;
	to=m->end;

	offset=to-from;
	if (offset <=0 )
		return -1;

	d=dirfstat(Bfildes(r));
	if ( d == nil ) 
		return -1;

	if ( from > d->length || from < 0 || to > d->length || to < 0 ) {
		free(d);
		return -1;
	}

	rpos = Bseek(r, to, SEEK_SET);

	if ( rpos == Beof) {
		free(d);
		return -1;
	}

	wpos=Bseek(w,from, SEEK_SET);

	if ( wpos == Beof) {
		free(d);
		return -1;
	}

	newlen=d->length-to;

	for(vlong i=0; i<newlen; i++){
		c=Bgetc(r);
		if ( c != ENDF ) {
			if ( Bputc(w,c) == ENDF){
				free(d);
				return -1;
			}
		} else {
			free(d);
			return -1;
		}
	}

	d->length = newlen;
	dirfwstat(Bfildes(w),d);
	free(d);
	return 1;

}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.