int mail_receive(struct mail *m, struct msg *msg, int destroy) { struct mail *mm = &msg->data.mail; mm->idx = m->idx; mm->tags = m->tags; m->tags = NULL; mm->attach = m->attach; m->attach = NULL; mm->auxfree = m->auxfree; m->auxfree = NULL; mm->auxdata = m->auxdata; m->auxdata = NULL; if (destroy) mail_destroy(m); else mail_close(m); memcpy(m, mm, sizeof *m); if ((m->base = shm_reopen(&m->shm)) == NULL) return (-1); SHM_REGISTER(&m->shm); m->data = m->base + m->off; ARRAY_INIT(&m->wrapped); m->wrapchar = '\0'; return (0); }
void child_deliver_action_hook(pid_t pid, struct account *a, struct msg *msg, struct child_deliver_data *data, int *result) { struct actitem *ti = data->actitem; struct deliver_ctx *dctx = data->dctx; struct mail *m = data->mail; struct mail *md = &dctx->wr_mail; /* Check if this is the parent. */ if (pid != 0) { /* Use new mail if necessary. */ if (ti->deliver->type != DELIVER_WRBACK) { xfree(dctx); return; } if (*result != DELIVER_SUCCESS) mail_destroy(md); else { mail_close(md); if (mail_receive(m, msg, 0) != 0) { log_warn("parent_deliver: can't receive mail"); *result = DELIVER_FAILURE; } } xfree(dctx); return; } dctx->udata = xmalloc(sizeof *dctx->udata); dctx->udata->uid = data->uid; dctx->udata->gid = data->gid; dctx->udata->name = xstrdup(find_tag(m->tags, "user")); dctx->udata->home = xstrdup(find_tag(m->tags, "home")); log_debug2("%s: deliver user is: %s (%lu/%lu), home is: %s", a->name, dctx->udata->name, (u_long) dctx->udata->uid, (u_long) dctx->udata->gid, dctx->udata->home); /* This is the child. do the delivery. */ *result = ti->deliver->deliver(dctx, ti); if (ti->deliver->type != DELIVER_WRBACK || *result != DELIVER_SUCCESS) { user_free(dctx->udata); return; } user_free(dctx->udata); mail_send(md, msg); log_debug2("%s: using new mail, size %zu", a->name, md->size); }
void parent_fetch_action(struct child *child, struct children *children, struct deliver_ctx *dctx, struct msg *msg) { struct actitem *ti = msg->data.actitem; struct mail *m = dctx->mail; struct mail *md = &dctx->wr_mail; struct child_deliver_data *data; uid_t uid = msg->data.uid; gid_t gid = msg->data.gid; memset(md, 0, sizeof *md); /* * If writing back, open a new mail now and set its ownership so it * can be accessed by the child. */ if (ti->deliver->type == DELIVER_WRBACK) { if (mail_open(md, IO_BLOCKSIZE) != 0) { log_warn("parent: failed to create mail"); parent_fetch_error(child, msg); return; } if (geteuid() == 0 && shm_owner(&md->shm, conf.child_uid, conf.child_gid) != 0) { mail_destroy(md); log_warn("parent: failed to set mail ownership"); parent_fetch_error(child, msg); return; } md->decision = m->decision; } data = xmalloc(sizeof *data); data->child = child; data->msgid = msg->id; data->account = dctx->account; data->hook = child_deliver_action_hook; data->actitem = ti; data->dctx = dctx; data->mail = m; data->name = "deliver"; data->uid = uid; data->gid = gid; child = child_start( children, uid, gid, child_deliver, parent_deliver, data, child); log_debug3("parent: deliver " "child %ld started (uid %lu)", (long) child->pid, (u_long) uid); }
/** * @brief Retrieve a user's message, in response to a POP3 RETR command. * @note This function will fail if a deleted message was specified by the user. * @param con the POP3 client connection issuing the command. * @return This function returns no value. */ void pop_retr(connection_t *con) { uint64_t number; meta_message_t *meta; mail_message_t *message; if (con->pop.session_state != 1) { pop_invalid(con); return; } // Which message are we getting. if (!pop_num_parse(con, &number, true)) { con_write_bl(con, "-ERR The retrieve command requires a numeric argument.\r\n", 56); return; } meta_user_rlock(con->pop.user); // Get the message. if (!(meta = pop_get_message(con->pop.user->messages, number))) { meta_user_unlock(con->pop.user); con_write_bl(con, "-ERR Message not found.\r\n", 25); return; } // Check for deletion. if ((meta->status & MAIL_STATUS_HIDDEN) == MAIL_STATUS_HIDDEN) { meta_user_unlock(con->pop.user); con_write_bl(con, "-ERR This message has been marked for deletion.\r\n", 49); return; } // Load the message and spit back the right number of lines. if (!(message = mail_load_message(meta, con->pop.user, con->server, 1))) { meta_user_unlock(con->pop.user); con_write_bl(con, "-ERR The message you requested could not be loaded into memory. It has either been " "deleted by another connection or is corrupted.\r\n", 131); return; } meta_user_unlock(con->pop.user); // Dot stuff the message. st_replace(&(message->text), PLACER("\n.", 2), PLACER("\n..", 3)); // Tell the client to prepare for a message. The size is strictly informational. con_print(con, "+OK %u characters follow.\r\n", st_length_get(message->text)); // We use raw socket IO because it is much faster when writing large amounts of data. con_write_st(con, message->text); // If the message didn't end with a line break, spit two. if (*(st_char_get(message->text) + st_length_get(message->text) - 1) == '\n') { con_write_bl(con, ".\r\n", 3); } else { con_write_bl(con, "\r\n.\r\n", 5); } mail_destroy(message); return; }
/** * Create a new mail message. * * The space pointed to by errstr should be large enough to * hold MAX_MAIL_ERROR bytes. Any less than that and the error * message could be truncated. * * If errlen is 0 then no error message is written to errstr * and errstr can be NULL. * * @param from - who the message is from * @param to - comma delimited list of recipients * @param cc - comma delimited carbon copy list * @param subject - message subject * @param flags - control flags * @param errlen - length of the error message buffer * @param errstr - output: error message * * Control Flags: * * - MAIL_ADD_NEWLINE - Add a newline after every mail message added. * * @return * - pointer to the new Mail message * - NULL if: * - the sendmail program could not be found * - a memory allocation error occurred */ Mail *mail_create( const char *from, const char *to, const char *cc, const char *subject, int flags, size_t errlen, char *errstr) { Mail *mail; int alloc_error; /* Find the sendmail program if it has not already been found */ if (gSendMailPath[0] == '\0') { if (access("/usr/lib/sendmail", X_OK) == 0) { strcpy(gSendMailPath, "/usr/lib/sendmail"); } else if (access("/usr/sbin/sendmail", X_OK) == 0) { strcpy(gSendMailPath, "/usr/sbin/sendmail"); } else { snprintf(errstr, errlen, "Could not create mail message: '%s'\n" " -> sendmail program not found\n", subject); return((Mail *)NULL); } } /* Create the Mail structure */ mail = (Mail *)calloc(1, sizeof(Mail)); if (!mail) { snprintf(errstr, errlen, "Could not create mail message: '%s'\n" " -> memory allocation error\n", subject); return((Mail *)NULL); } alloc_error = 0; if (from) { mail->from = msngr_copy_string(from); if (!mail->from) { alloc_error = 1; } } if (to && !alloc_error) { mail->to = msngr_copy_string(to); if (!mail->to) { alloc_error = 1; } } if (cc && !alloc_error) { mail->cc = msngr_copy_string(cc); if (!mail->cc) { alloc_error = 1; } } if (subject && !alloc_error) { mail->subject = msngr_copy_string(subject); if (!mail->subject) { alloc_error = 1; } } if (!alloc_error) { mail->length = 0; mail->nalloced = MAIL_BODY_GROWTH_SIZE; mail->body = (char *)calloc(mail->nalloced, sizeof(char)); if (!mail->body) { alloc_error = 1; } } if (!alloc_error) { mail->errstr = (char *)calloc(MAX_MAIL_ERROR, sizeof(char)); if (!mail->errstr) { alloc_error = 1; } } if (alloc_error) { mail_destroy(mail); snprintf(errstr, errlen, "Could not create mail message: '%s'\n" " -> memory allocation error\n", subject); return((Mail *)NULL); } mail->flags = flags; return(mail); }
/* 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); }