#include <sys_defs.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <msg.h>
#include <vstring.h>
#include <vstream.h>
#include <mymalloc.h>
#include <stringops.h>
#include <set_eugid.h>
#include <mail_copy.h>
#include <mbox_open.h>
#include <defer.h>
#include <sent.h>
#include <mail_params.h>
#include <virtual8_maps.h>
#ifndef EDQUOT
#define EDQUOT EFBIG
#endif
#include "virtual.h"
#define YES 1
#define NO 0
static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
{
char *myname = "deliver_mailbox_file";
VSTRING *why;
MBOX *mp;
int mail_copy_status;
int deliver_status;
int copy_flags;
long end;
struct stat st;
state.level++;
if (msg_verbose)
MSG_LOG_STATE(myname, state);
if (vstream_fseek(state.msg_attr.fp, state.msg_attr.offset, SEEK_SET) < 0)
msg_fatal("seek message file %s: %m", VSTREAM_PATH(state.msg_attr.fp));
state.msg_attr.delivered = state.msg_attr.recipient;
mail_copy_status = MAIL_COPY_STAT_WRITE;
why = vstring_alloc(100);
copy_flags = MAIL_COPY_MBOX;
set_eugid(usr_attr.uid, usr_attr.gid);
mp = mbox_open(usr_attr.mailbox, O_APPEND | O_WRONLY | O_CREAT,
S_IRUSR | S_IWUSR, &st, -1, -1,
virtual_mbox_lock_mask, why);
if (mp != 0) {
if (S_ISREG(st.st_mode) == 0) {
vstream_fclose(mp->fp);
vstring_sprintf(why, "destination is not a regular file");
errno = 0;
} else {
end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END);
mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
copy_flags, "\n", why);
}
mbox_release(mp);
}
set_eugid(var_owner_uid, var_owner_gid);
if (mail_copy_status & MAIL_COPY_STAT_CORRUPT) {
deliver_status = DEL_STAT_DEFER;
} else if (mail_copy_status != 0) {
deliver_status = (errno == EDQUOT || errno == EFBIG ?
bounce_append : defer_append)
(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"mailbox %s: %s", usr_attr.mailbox, vstring_str(why));
} else {
deliver_status = sent(SENT_ATTR(state.msg_attr), "mailbox");
}
vstring_free(why);
return (deliver_status);
}
int deliver_mailbox(LOCAL_STATE state, USER_ATTR usr_attr, int *statusp)
{
char *myname = "deliver_mailbox";
const char *mailbox_res;
const char *uid_res;
const char *gid_res;
long n;
state.level++;
if (msg_verbose)
MSG_LOG_STATE(myname, state);
if (*var_virt_mailbox_base != '/')
msg_fatal("do not specify relative pathname: %s = %s",
VAR_VIRT_MAILBOX_BASE, var_virt_mailbox_base);
mailbox_res = virtual8_maps_find(virtual_mailbox_maps, state.msg_attr.user);
if (mailbox_res == 0) {
if (dict_errno == 0)
return (NO);
*statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"%s: lookup %s: %m",
virtual_mailbox_maps->title, state.msg_attr.user);
return (YES);
}
usr_attr.mailbox = concatenate(var_virt_mailbox_base, "/",
mailbox_res, (char *) 0);
#define RETURN(res) { myfree(usr_attr.mailbox); return (res); }
uid_res = virtual8_maps_find(virtual_uid_maps, state.msg_attr.user);
if (uid_res == 0) {
*statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"recipient %s: uid not found in %s",
state.msg_attr.user, virtual_uid_maps->title);
RETURN(YES);
}
if ((n = atol(uid_res)) < var_virt_minimum_uid) {
*statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"recipient %s: bad uid %s in %s",
state.msg_attr.user, uid_res, virtual_uid_maps->title);
RETURN(YES);
}
usr_attr.uid = (uid_t) n;
gid_res = virtual8_maps_find(virtual_gid_maps, state.msg_attr.user);
if (gid_res == 0) {
*statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"recipient %s: gid not found in %s",
state.msg_attr.user, virtual_gid_maps->title);
RETURN(YES);
}
if ((n = atol(gid_res)) <= 0) {
*statusp = defer_append(BOUNCE_FLAG_KEEP, BOUNCE_ATTR(state.msg_attr),
"recipient %s: bad gid %s in %s",
state.msg_attr.user, gid_res, virtual_gid_maps->title);
RETURN(YES);
}
usr_attr.gid = (gid_t) n;
if (msg_verbose)
msg_info("%s[%d]: set user_attr: %s, uid = %u, gid = %u",
myname, state.level, usr_attr.mailbox,
(unsigned) usr_attr.uid, (unsigned) usr_attr.gid);
#define LAST_CHAR(s) (s[strlen(s) - 1])
if (LAST_CHAR(usr_attr.mailbox) == '/')
*statusp = deliver_maildir(state, usr_attr);
else
*statusp = deliver_mailbox_file(state, usr_attr);
RETURN(YES);
}