Пример #1
0
//
// check for new messages on pop server
// UIDL is not required by RFC 1939, but 
// netscape requires it, so almost every server supports it.
// we'll use it to make our lives easier.
//
static char*
pop3read(Pop *pop, Mailbox *mb, int doplumb)
{
	char *s, *p, *uidl, *f[2];
	int mesgno, ignore, nnew;
	Message *m, *next, **l;

	// Some POP servers disallow UIDL if the maildrop is empty.
	pop3cmd(pop, "STAT");
	if(!isokay(s = pop3resp(pop)))
		return s;

	// fetch message listing; note messages to grab
	l = &mb->root->part;
	if(strncmp(s, "+OK 0 ", 6) != 0) {
		pop3cmd(pop, "UIDL");
		if(!isokay(s = pop3resp(pop)))
			return s;

		for(;;){
			p = pop3resp(pop);
			if(strcmp(p, ".") == 0 || strcmp(p, "unexpected eof") == 0)
				break;

			if(tokenize(p, f, 2) != 2)
				continue;

			mesgno = atoi(f[0]);
			uidl = f[1];
			if(strlen(uidl) > 75)	// RFC 1939 says 70 characters max
				continue;

			ignore = 0;
			while(*l != nil) {
				if(strcmp((*l)->uidl, uidl) == 0) {
					// matches mail we already have, note mesgno for deletion
					(*l)->mesgno = mesgno;
					ignore = 1;
					l = &(*l)->next;
					break;
				} else {
					// old mail no longer in box mark deleted
					if(doplumb)
						mailplumb(mb, *l, 1);
					(*l)->inmbox = 0;
					(*l)->deleted = 1;
					l = &(*l)->next;
				}
			}
			if(ignore)
				continue;

			m = newmessage(mb->root);
			m->mallocd = 1;
			m->inmbox = 1;
			m->mesgno = mesgno;
			strcpy(m->uidl, uidl);

			// chain in; will fill in message later
			*l = m;
			l = &m->next;
		}
	}

	// whatever is left has been removed from the mbox, mark as deleted
	while(*l != nil) {
		if(doplumb)
			mailplumb(mb, *l, 1);
		(*l)->inmbox = 0;
		(*l)->deleted = 1;
		l = &(*l)->next;
	}

	// download new messages
	nnew = 0;
	if(pop->pipeline){
		switch(rfork(RFPROC|RFMEM)){
		case -1:
			fprint(2, "rfork: %r\n");
			pop->pipeline = 0;

		default:
			break;

		case 0:
			for(m = mb->root->part; m != nil; m = m->next){
				if(m->start != nil)
					continue;
				Bprint(&pop->bout, "LIST %d\r\nRETR %d\r\n", m->mesgno, m->mesgno);
			}
			Bflush(&pop->bout);
			_exits(nil);
		}
	}

	for(m = mb->root->part; m != nil; m = next) {
		next = m->next;

		if(m->start != nil)
			continue;

		if(s = pop3download(pop, m)) {
			// message disappeared? unchain
			fprint(2, "download %d: %s\n", m->mesgno, s);
			delmessage(mb, m);
			mb->root->subname--;
			continue;
		}
		nnew++;
		parse(m, 0, mb, 1);

		if(doplumb)
			mailplumb(mb, m, 0);
	}
	if(pop->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;	
}
Пример #2
0
//
//  read in the mailbox and parse into messages.
//
static char*
_readmbox(Mailbox *mb, int doplumb, Mlock *lk)
{
	int fd, n;
	String *tmp;
	Dir *d;
	static char err[128];
	Message *m, **l;
	Inbuf *inb;
	char *x;

	l = &mb->root->part;

	/*
	 *  open the mailbox.  If it doesn't exist, try the temporary one.
	 */
	n = 0;
retry:
	fd = open(mb->path, OREAD);
	if(fd < 0){
		rerrstr(err, sizeof(err));
		if(strstr(err, "exclusive lock") != 0 && n++ < 20){
			sleep(500);	/* wait for lock to go away */
			goto retry;
		}
		if(strstr(err, "exist") != 0){
			tmp = s_copy(mb->path);
			s_append(tmp, ".tmp");
			if(sysrename(s_to_c(tmp), mb->path) == 0){
				s_free(tmp);
				goto retry;
			}
			s_free(tmp);
		}
		return err;
	}

	/*
	 *  a new qid.path means reread the mailbox, while
	 *  a new qid.vers means read any new messages
	 */
	d = dirfstat(fd);
	if(d == nil){
		close(fd);
		errstr(err, sizeof(err));
		return err;
	}
	if(mb->d != nil){
		if(d->qid.path == mb->d->qid.path && d->qid.vers == mb->d->qid.vers){
			close(fd);
			free(d);
			return nil;
		}
		if(d->qid.path == mb->d->qid.path){
			while(*l != nil)
				l = &(*l)->next;
			seek(fd, mb->d->length, 0);
		}
		free(mb->d);
	}
	mb->d = d;
	mb->vers++;
	henter(PATH(0, Qtop), mb->name,
		(Qid){PATH(mb->id, Qmbox), mb->vers, QTDIR}, nil, mb);

	inb = emalloc(sizeof(Inbuf));
	inb->rptr = inb->wptr = inb->data;
	inb->fd = fd;

	//  read new messages
	snprint(err, sizeof err, "reading '%s'", mb->path);
	logmsg(err, nil);
	for(;;){
		if(lk != nil)
			syslockrefresh(lk);
		m = newmessage(mb->root);
		m->mallocd = 1;
		m->inmbox = 1;
		if(readmessage(m, inb) < 0){
			delmessage(mb, m);
			mb->root->subname--;
			break;
		}

		// merge mailbox versions
		while(*l != nil){
			if(memcmp((*l)->digest, m->digest, SHA1dlen) == 0){
				// matches mail we already read, discard
				logmsg("duplicate", *l);
				delmessage(mb, m);
				mb->root->subname--;
				m = nil;
				l = &(*l)->next;
				break;
			} else {
				// old mail no longer in box, mark deleted
				logmsg("disappeared", *l);
				if(doplumb)
					mailplumb(mb, *l, 1);
				(*l)->inmbox = 0;
				(*l)->deleted = 1;
				l = &(*l)->next;
			}
		}
		if(m == nil)
			continue;

		x = strchr(m->start, '\n');
		if(x == nil)
			m->header = m->end;
		else
			m->header = x + 1;
		m->mheader = m->mhend = m->header;
		parseunix(m);
		parse(m, 0, mb, 0);
		logmsg("new", m);

		/* chain in */
		*l = m;
		l = &m->next;
		if(doplumb)
			mailplumb(mb, m, 0);

	}
	logmsg("mbox read", nil);

	// whatever is left has been removed from the mbox, mark deleted
	while(*l != nil){
		if(doplumb)
			mailplumb(mb, *l, 1);
		(*l)->inmbox = 0;
		(*l)->deleted = 1;
		l = &(*l)->next;
	}

	close(fd);
	free(inb);
	return nil;
}
Пример #3
0
//
// 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;
}