Example #1
0
/* Body state. */
int
imap_state_body(struct account *a, struct fetch_ctx *fctx)
{
	struct fetch_imap_data	*data = a->data;
	struct mail		*m = fctx->mail;
	struct fetch_imap_mail	*aux;
	char			*line, *ptr;
	u_int			 n;

	if (imap_getln(a, fctx, IMAP_UNTAGGED, &line) != 0)
		return (FETCH_ERROR);
	if (line == NULL)
		return (FETCH_BLOCK);

	if (sscanf(line, "* %u FETCH (", &n) != 1)
		return (imap_invalid(a, line));
	if ((ptr = strstr(line, "BODY[] {")) == NULL)
		return (imap_invalid(a, line));

	if (sscanf(ptr, "BODY[] {%zu}", &data->size) != 1)
		return (imap_invalid(a, line));
	data->lines = 0;

	/* Fill in local data. */
	aux = xcalloc(1, sizeof *aux);
	aux->uid = ARRAY_FIRST(&data->wanted);
	m->auxdata = aux;
	m->auxfree = imap_free;
	ARRAY_REMOVE(&data->wanted, 0);

	/* Open the mail. */
	if (mail_open(m, data->size) != 0) {
		log_warnx("%s: failed to create mail", a->name);
		return (FETCH_ERROR);
	}
	m->size = 0;

	/* Tag mail. */
	default_tags(&m->tags, data->src);
	if (data->server.host != NULL) {
		add_tag(&m->tags, "server", "%s", data->server.host);
		add_tag(&m->tags, "port", "%s", data->server.port);
	}
	add_tag(&m->tags, "server_uid", "%u", aux->uid);
	add_tag(&m->tags,
	    "folder", "%s", ARRAY_ITEM(data->folders, data->folder));

	/* If we already know the mail is oversize, start off flushing it. */
	data->flushing = data->size > conf.max_size;

	fctx->state = imap_state_line;
	return (FETCH_AGAIN);
}
Example #2
0
/* Fetch mail from stdin. */
int
fetch_stdin_state_mail(struct account *a, struct fetch_ctx *fctx)
{
	struct mail	*m = fctx->mail;
	struct io	*io;
	char		*line, *cause;

	/* Open io for stdin. */
	io = io_create(STDIN_FILENO, NULL, IO_LF);
	if (conf.debug > 3 && !conf.syslog)
		io->dup_fd = STDOUT_FILENO;

	/* Initialise the mail. */
	if (mail_open(m, IO_BLOCKSIZE) != 0) {
		log_warn("%s: failed to create mail", a->name);
		goto error;
	}
	m->size = 0;

	/* Add default tags. */
	default_tags(&m->tags, NULL);

	/* Loop reading the mail. */
	for (;;) {
		/*
		 * There can only be one mail on stdin so reentrancy is
		 * irrelevent. This is a good thing since we want to check for
		 * close which means end of mail.
		 */
		switch (io_pollline2(io,
		    &line, &fctx->lbuf, &fctx->llen, conf.timeout, &cause)) {
		case 0:
			/* Normal close is fine. */
			goto out;
		case -1:
			if (errno == EAGAIN)
				continue;
			log_warnx("%s: %s", a->name, cause);
			xfree(cause);
			goto error;
		}

		if (append_line(m, line, strlen(line)) != 0) {
			log_warn("%s: failed to resize mail", a->name);
			goto error;
		}
		if (m->size > conf.max_size)
			break;
	}

out:
	if (io != NULL)
		io_free(io);

	fctx->state = fetch_stdin_state_exit;
	return (FETCH_MAIL);


error:
	if (io != NULL)
		io_free(io);

	return (FETCH_ERROR);
}
Example #3
0
/* Mail state. Find and read mail file. */
int
fetch_mbox_state_mail(struct account *a, struct fetch_ctx *fctx)
{
	struct fetch_mbox_data		*data = a->data;
	struct mail			*m = fctx->mail;
	struct fetch_mbox_mbox		*fmbox;
	struct fetch_mbox_mail		*aux;
	char				*line, *ptr, *lptr;
	size_t				 llen;
	int				 flushing;

	/* Find current mbox and check for EOF. */
	fmbox = ARRAY_ITEM(&data->fmboxes, data->index);
	if (data->off == fmbox->size) {
		fctx->state = fetch_mbox_state_next;
		return (FETCH_AGAIN);
	}

	/* Open the mail. */
	if (mail_open(m, IO_BLOCKSIZE) != 0) {
		log_warn("%s: failed to create mail", a->name);
		mail_destroy(m);
		return (FETCH_ERROR);
	}

	/* Create aux data. */
	aux = xmalloc(sizeof *aux);
	aux->off = data->off;
	aux->size = 0;
	aux->fmbox = fmbox;
	if (++fmbox->reference == 0)
		fatalx("reference count overflow");
	m->auxdata = aux;
	m->auxfree = fetch_mbox_free;

	/* Tag mail. */
	default_tags(&m->tags, NULL);
	add_tag(&m->tags, "mbox", "%s", xbasename(fmbox->path));
	add_tag(&m->tags, "mbox_path", "%s", xdirname(fmbox->path));
	add_tag(&m->tags, "mbox_file", "%s", fmbox->path);

	/*
	 * We start at a "From " line and include it in the mail (it can be
	 * trimmed later with minimal penalty).
	 */
	flushing = 0;
	for (;;) {
		/* Check for EOF. */
		if (data->off == fmbox->size) {
			aux->size = data->off - aux->off;
			break;
		}

		/* Locate the EOL. */
		line = fmbox->base + data->off;
		ptr = memchr(line, '\n', fmbox->size - data->off);
		if (ptr == NULL) {
			ptr = fmbox->base + fmbox->size;
			data->off = fmbox->size;
		} else
			data->off += ptr - line + 1;

		/* Check if the line is "From ". */
		if (line > fmbox->base &&
		    ptr - line >= 5 && strncmp(line, "From ", 5) == 0) {
			/* End of mail. */
			aux->size = (line - fmbox->base) - aux->off;
			break;
		}

		/* Trim >s from From. */
		if (*line == '>') {
			lptr = line;
			llen = ptr - line;
			while (*lptr == '>' && llen > 0) {
				lptr++;
				llen--;
			}

			if (llen >= 5 && strncmp(lptr, "From ", 5) == 0)
				line++;
		}

		if (flushing)
			continue;
		if (append_line(m, line, ptr - line) != 0) {
			log_warn("%s: failed to resize mail", a->name);
			mail_destroy(m);
			return (FETCH_ERROR);
		}
		if (m->size > conf.max_size)
			flushing = 1;
	}
	fmbox->total++;

	/*
	 * Check if there was a blank line between the mails and remove it if
	 * so.
	 */
	if (aux->size >= 2 &&
	    fmbox->base[aux->off + aux->size - 1] == '\n' &&
	    fmbox->base[aux->off + aux->size - 2] == '\n') {
		aux->size -= 2;
		m->size -= 2;
	}

	return (FETCH_MAIL);
}