Beispiel #1
0
static int update_link(const char *curdir,
	const char *linkname, const char *linkvalue,
	const char *shareddir,
	const char *msgfilename,
	size_t msgfilenamelen)
{
	char	*p=malloc(strlen(shareddir)+sizeof("/cur/")+msgfilenamelen);
	char	*q;
	int	fd;
	struct maildir_tmpcreate_info createInfo;

	if (!p)
	{
		perror("malloc");
		return (-1);
	}

	strcat(strcpy(p, shareddir), "/cur/");
	q=p+strlen(p);
	memcpy(q, msgfilename, msgfilenamelen);
	q[msgfilenamelen]=0;

	if (linkvalue && strcmp(p, linkvalue) == 0)
	{
		/* the link is good */

		free(p);
		return (0);
	}

	/* Ok, we want this to be an atomic operation. */

	maildir_tmpcreate_init(&createInfo);
	createInfo.maildir=curdir;
	createInfo.uniq="relink";
	createInfo.doordie=1;

	if ((fd=maildir_tmpcreate_fd(&createInfo)) < 0)
		return -1;

	close(fd);
	unlink(createInfo.tmpname);

	if (symlink(p, createInfo.tmpname) < 0 ||
	    rename(createInfo.tmpname, linkname) < 0)
	{
		perror(createInfo.tmpname);
		maildir_tmpcreate_free(&createInfo);
		return (-1);
	}

	maildir_tmpcreate_free(&createInfo);
	return (0);
}
Beispiel #2
0
static int savepop3dlist(struct msglist **a, size_t cnt,
			  unsigned long uid)
{
	FILE *fp;
	size_t i;

	struct maildir_tmpcreate_info createInfo;

	maildir_tmpcreate_init(&createInfo);

	createInfo.uniq="pop3";
	createInfo.doordie=1;

	if ((fp=maildir_tmpcreate_fp(&createInfo)) == NULL)
	{
		maildir_tmpcreate_free(&createInfo);
		return -1;
	}

	fprintf(fp, "/2 %lu %lu\n", uid, uidv);

	for (i=0; i<cnt; i++)
	{
		char *p=a[i]->filename;
		char *q;

		if ((q=strrchr(p, '/')) != NULL)
			p=q+1;

		fprintf(fp, "%s %lu %lu:%lu\n", p, (unsigned long)a[i]->size,
			a[i]->uid.n, a[i]->uid.uidv);
	}

	if (fflush(fp) || ferror(fp))
	{
		fclose(fp);
		unlink(createInfo.tmpname);
		maildir_tmpcreate_free(&createInfo);
		return -1;
	}

	if (fclose(fp) ||
	    rename(createInfo.tmpname, POP3DLIST) < 0)
	{
		unlink(createInfo.tmpname);
		maildir_tmpcreate_free(&createInfo);
		return -1;
	}

	maildir_tmpcreate_free(&createInfo);
	return 0;
}
Beispiel #3
0
static int create_db(struct dbobj *obj,
	const char *dir,
	char **dbname)
{
	struct maildir_tmpcreate_info createInfo;

	maildir_tmpcreate_init(&createInfo);

	createInfo.maildir=dir;
	createInfo.uniq="sync";
	createInfo.doordie=1;

	{
		int	fd;

		fd=maildir_tmpcreate_fd(&createInfo);

		if (fd < 0)
		{
			perror(dir);
			return -1;
		}
		close(fd);

		dbobj_init(obj);
		if (dbobj_open(obj, createInfo.tmpname, "N") < 0)
		{
			perror(createInfo.tmpname);
			unlink(createInfo.tmpname);
			maildir_tmpcreate_free(&createInfo);
			return (-1);
		}
	}

	*dbname=createInfo.tmpname;
	createInfo.tmpname=NULL;
	maildir_tmpcreate_free(&createInfo);
	return (0);
}
Beispiel #4
0
int maildir_filter_savemaildirfilter(struct maildirfilter *mf, const char *maildir,
			 const char *from)
{
	// by lfan, to support .qmail-user forward file
	char *p, *p2, *user;
	char *maildirpath;
	//const char *maildirpath=maildir_filter_config(maildir, "MAILDIR");
	struct maildir_tmpcreate_info createInfo;
	int fd, rc;

	p=login_returnaddr();
	p2=strdup(p);
	user=strtok(p2, "@");
	p = malloc(strlen(user) + 12);
	sprintf( p, "./%s/Maildir", user );
	free(p2);
	maildirpath=p;
	
	
	if (!maildirpath || !*maildirpath)
	{
		errno=EINVAL;
		return (-1);
	}

	maildir_tmpcreate_init(&createInfo);
	createInfo.maildir=maildir;
	createInfo.uniq="maildirfilter-tmp";
	createInfo.doordie=1;

	if ((fd=maildir_tmpcreate_fd(&createInfo)) < 0)
		return -1;

	close(fd);
	unlink(createInfo.tmpname);

	strcat(strcpy(createInfo.newname, maildir), "/maildirfilter.tmp");

	rc=maildir_filter_saverules(mf, createInfo.tmpname,
				    maildir, maildirpath, from);
	if (rc == 0 && rename(createInfo.tmpname, createInfo.newname))
		rc= -1;
	maildir_tmpcreate_free(&createInfo);
	free(p);
	return (rc);
}
Beispiel #5
0
void write_sqconfig(const char *dir, const char *configfile, const char *val)
{
	char *p=malloc(strlen(dir) + strlen(configfile) + 2);

	struct maildir_tmpcreate_info createInfo;
	FILE *fp;

	if (!p)	enomem();

	strcat(strcat(strcpy(p, dir), "/"), configfile);
	if (!val)
	{
		unlink(p);
		free(p);
		return;
	}

	maildir_tmpcreate_init(&createInfo);

	createInfo.maildir=dir;
	createInfo.uniq="config";
	createInfo.doordie=1;

	fp=maildir_tmpcreate_fp(&createInfo);

	if (!fp)
		enomem();


	free(createInfo.newname);
	createInfo.newname=p;

	fprintf(fp, "%s\n", val);
	fflush(fp);
	if (ferror(fp))	eio("Error after write:",p);
	fclose(fp);

	/* Note - umask should already turn off the 077 bits, but
	** just in case someone screwed up previously, I'll fix it
	** myself */

	chmod(createInfo.tmpname, 0600);
	rename(createInfo.tmpname, createInfo.newname);
	maildir_tmpcreate_free(&createInfo);
}
static int maildir_tmpcreate_fd_do(struct maildir_tmpcreate_info *info)
{
	const char *maildir=info->maildir;
	const char *uniq=info->uniq;
	const char *hostname=info->hostname;

	char hostname_buf[256];
	char time_buf[NUMBUFSIZE];
	char usec_buf[NUMBUFSIZE];
	char pid_buf[NUMBUFSIZE];
	char len_buf[NUMBUFSIZE+3];
	char dev_buf[NUMBUFSIZE];
	char ino_buf[NUMBUFSIZE];
	struct timeval tv;

	struct stat stat_buf;
	int fd;

	if (!maildir)
		maildir=".";
	if (!uniq)
		uniq="";

	if (!hostname || !*hostname)
	{
		hostname_buf[sizeof(hostname_buf)-1]=0;
		if (gethostname(hostname_buf, sizeof(hostname_buf)-1) < 0)
			strcpy(hostname_buf, "localhost");
		hostname=hostname_buf;
	}

	gettimeofday(&tv, NULL);

	libmail_str_time_t(tv.tv_sec, time_buf);
	libmail_str_time_t(tv.tv_usec, usec_buf);
	libmail_str_pid_t(getpid(), pid_buf);
	len_buf[0]=0;
	if (info->msgsize > 0)
	{
		strcpy(len_buf, ",S=");
		libmail_str_size_t(info->msgsize, len_buf+3);
	}

	if (info->tmpname)
		free(info->tmpname);

	info->tmpname=malloc(strlen(maildir)+strlen(uniq)+
			     strlen(hostname)+strlen(time_buf)+
			     strlen(usec_buf)+
			     strlen(pid_buf)+strlen(len_buf)+100);

	if (!info->tmpname)
	{
		maildir_tmpcreate_free(info);
		return -1;
	}

	strcpy(info->tmpname, maildir);
	strcat(info->tmpname, "/tmp/");
	strcat(info->tmpname, time_buf);
	strcat(info->tmpname, ".M");
	strcat(info->tmpname, usec_buf);
	strcat(info->tmpname, "P");
	strcat(info->tmpname, pid_buf);

	if (*uniq)
		strcat(strcat(info->tmpname, "_"), uniq);
	strcat(info->tmpname, ".");
	strcat(info->tmpname, hostname);
	strcat(info->tmpname, len_buf);

	if (stat( info->tmpname, &stat_buf) == 0)
	{
		maildir_tmpcreate_free(info);
		errno=EAGAIN;
		return -1;
	}

	if (errno != ENOENT)
	{
		maildir_tmpcreate_free(info);
		if (errno == EAGAIN)
			errno=EIO;
		return -1;
	}

	if ((fd=maildir_safeopen_stat(info->tmpname, O_CREAT|O_RDWR|O_TRUNC,
				      info->openmode, &stat_buf)) < 0)
	{
		maildir_tmpcreate_free(info);
		return -1;
	}

	libmail_strh_dev_t(stat_buf.st_dev, dev_buf);
	libmail_strh_ino_t(stat_buf.st_ino, ino_buf);

	if (info->newname)
		free(info->newname);
	info->newname=NULL;

	if (info->curname)
		free(info->curname);
	info->curname=NULL;

	info->newname=malloc(strlen(info->tmpname)+strlen(ino_buf)+
			     strlen(dev_buf)+3);

	if (info->newname)
	{
		info->curname=malloc(strlen(info->tmpname)+strlen(ino_buf)+
				     strlen(dev_buf)+3);
		if (!info->curname)
		{
			free(info->newname);
			info->newname=NULL;
		}
	}

	if (!info->newname)
	{
		maildir_tmpcreate_free(info);
		unlink(info->tmpname);
		close(fd);
		if (errno == EAGAIN)
			errno=EIO;
		return -1;
	}

	strcpy(info->newname, maildir);
	strcat(info->newname, "/new/");
	strcat(info->newname, time_buf);
	strcat(info->newname, ".M");
	strcat(info->newname, usec_buf);
	strcat(info->newname, "P");
	strcat(info->newname, pid_buf);
	strcat(info->newname, "V");
	strcat(info->newname, dev_buf);
	strcat(info->newname, "I");
	strcat(info->newname, ino_buf);
	if (*uniq)
		strcat(strcat(info->newname, "_"), uniq);
	strcat(info->newname, ".");
	strcat(info->newname, hostname);
	strcat(info->newname, len_buf);

	strcpy(info->curname, info->newname);
	memcpy(info->curname + strlen(maildir)+1, "cur", 3);

	return fd;
}
Beispiel #7
0
static int savemessage(const char *extension, const char *sender,
		const char *receipient,
		FILE *f, const char *name,
		const char *ufromline,
		const char *dtline,
		const char *rpline,
		const char *quota)
{
FILE	*delivf;
char	buf[BUFSIZ];
int	c;
static unsigned counter=0;
struct	stat stat_buf;
struct maildirsize quotainfo;
struct maildir_tmpcreate_info createInfo;

	umask(077);

	if ((delivf=fopen(name, "a")) != 0)
	{
		/* Ok, perhaps this is a mailbox */

		struct ll_mail *ll=ll_mail_alloc(name);

		fclose(delivf);

		if (!ll)
		{
			delivery_error(name);	/* I Give up */
		}

		while ((mbox_fd=ll_mail_open(ll)) < 0)
		{
			switch (errno) {
			case EEXIST:
			case EAGAIN:
				sleep(5);
				continue;
				break;
			}

			delivery_error(name);
		}

		delivf=fdopen(mbox_fd, "w");

		if (delivf == NULL || fseek(delivf, 0L, SEEK_END) < 0
		    || (mbox_size=ftell(delivf)) == (off_t)-1)
		{
			if (delivf)
				fclose(delivf);
			close(mbox_fd);
			ll_mail_free(ll);
			delivery_error(name);	/* I Give up */
		}

		signal(SIGHUP, truncmbox);
		signal(SIGINT, truncmbox);
		signal(SIGQUIT, truncmbox);
		signal(SIGTERM, truncmbox);

		fprintf(delivf, "%s\n%s\n%s\n",
			ufromline,
			dtline,
			rpline);

		while (fgets(buf, sizeof(buf), f) != 0)
		{
		char	*q=buf;

			while (*q == '>')	q++;
			if (strncmp(q, "From ", 5) == 0)
				putc('>', delivf);
			fprintf(delivf, "%s", buf);
			if (strchr(buf, '\n') == 0)
			{
				while ((c=getc(f)) >= 0)
				{
					putc(c, delivf);
					if (c == '\n')	break;
				}
			}
		}

		if ( ferror(f) || fflush(delivf) || ferror(delivf)
#if	EXPLICITSYNC
			|| fsync(fileno(delivf))
#endif
			||
				(signal(SIGHUP, SIG_DFL),
				signal(SIGINT, SIG_DFL),
				signal(SIGQUIT, SIG_DFL),
				signal(SIGTERM, SIG_DFL),
				fclose(delivf))
			)
		{
#if	HAVE_FTRUNCATE
			if (ftruncate(mbox_fd, mbox_size) < 0)
				; /* ignore */
#endif
			close(mbox_fd);
			ll_mail_free(ll);
			delivery_error("mailbox.close");
		}
		close(mbox_fd);
		ll_mail_free(ll);
		return (0);
	}

	if (fstat(fileno(f), &stat_buf))
	{
		delivery_error("stat");
		return (-1);
	}

	stat_buf.st_size += strlen(dtline) + strlen(rpline) + 2;

	if (maildir_quota_add_start(name, &quotainfo, stat_buf.st_size, 1,
				    quota && *quota != 0 ? quota:NULL))
	{
		errno=ENOSPC;
		delivery_error("out of memory.");
	}

	maildir_closequotafile(&quotainfo);	/* For now. */

	sprintf(buf, "%u", ++counter);

	maildir_tmpcreate_init(&createInfo);
	createInfo.maildir=name;
	createInfo.uniq=buf;
	createInfo.msgsize=stat_buf.st_size;
	createInfo.doordie=1;

	if ((delivf=maildir_tmpcreate_fp(&createInfo)) == NULL)
	{
		snprintf(buf, BUFSIZ-1,
			 "maildir.open: %s: %s", name,
			 strerror(errno));
		buf[BUFSIZ-1] = 0;
		delivery_error(buf);
		return (-1);
	}

	fprintf(delivf, "%s\n%s\n", dtline, rpline);

	{
		char buffer[BUFSIZ];
		int n;

		while ((n=fread(buffer, 1, sizeof(buffer), f)) > 0)
			if (fwrite(buffer, 1, n, delivf)  != n)
				break;
	}

	if ( ferror(f) || fflush(delivf) || ferror(delivf)
#if	EXPLICITSYNC
			|| fsync(fileno(delivf))
#endif
			|| fclose(delivf)
			|| (delivf=0, maildir_movetmpnew(createInfo.tmpname,
							 createInfo.newname)))
	{
		snprintf(buf, BUFSIZ-1,
			 "maildir.close: %s: %s", name,
			 strerror(errno));
		buf[BUFSIZ-1] = 0;

		if (delivf)	fclose(delivf);
		unlink(createInfo.newname);
		delivery_error(buf);
		return (-1);
	}

#if EXPLICITDIRSYNC

	{
		int fd;

		strcpy(strrchr(createInfo.newname, '/')+1, ".");

		fd=open(createInfo.newname, O_RDONLY);

		if (fd >= 0)
		{
			fsync(fd);
			close(fd);
		}
	}
#endif

	maildir_tmpcreate_free(&createInfo);

	maildir_quota_deleted(name, stat_buf.st_size, 1);
	return (0);
}
Beispiel #8
0
int maildir_filter_importmaildirfilter(const char *maildir)
{
	const char *p=maildir_filter_config(maildir, "MAILDIRFILTER");
	char *maildirfilter;
	FILE *i, *o;
	struct maildir_tmpcreate_info createInfo;

	if (!p)	return (-1);

	if (!*p)
	{
		errno=ENOENT;
		return (-1);
	}

	maildirfilter=maildir_filter_config_maildirfilter(maildir);
	if (!maildirfilter)	return (-1);

	maildir_tmpcreate_init(&createInfo);

	createInfo.maildir=maildir;
	createInfo.uniq="maildirfilter-tmp";
	createInfo.doordie=1;

	if ((o=maildir_tmpcreate_fp(&createInfo)) == NULL)
	{
		free(maildirfilter);
		return (-1);
	}

	strcat(strcpy(createInfo.newname, maildir),
	       "/maildirfilter.tmp"); /* We enough we have enough mem: .uniq */

	if ((i=fopen(maildirfilter, "r")) == 0)
	{
	struct	maildirfilter mf;

		if (errno != ENOENT)
		{
			fclose(o);
			unlink(createInfo.tmpname);
			maildir_tmpcreate_free(&createInfo);
			free(maildirfilter);
			return (-1);
		}

		memset(&mf, 0, sizeof(mf));
		fclose(o);
		unlink(createInfo.tmpname);
		unlink(createInfo.newname);
		maildir_filter_savemaildirfilter(&mf, maildir, "");
		/* write out a blank one */
	}
	else
	{
		char	buf[BUFSIZ];
		int	n;

		while ((n=fread(buf, 1, sizeof(buf), i)) > 0)
			if (fwrite(buf, 1, n, o) != n)
			{
				fclose(o);
				fclose(i);
				unlink(createInfo.tmpname);
				maildir_tmpcreate_free(&createInfo);
				free(maildirfilter);
				return (-1);
			}
		if (fflush(o))
		{
			fclose(o);
			fclose(i);
			unlink(createInfo.tmpname);
			maildir_tmpcreate_free(&createInfo);
			free(maildirfilter);
			return (-1);
		}
		fclose(o);
		fclose(i);
		if (chmod(createInfo.tmpname, 0600)
		    || rename(createInfo.tmpname, createInfo.newname))
		{
			unlink(createInfo.tmpname);
			maildir_tmpcreate_free(&createInfo);
			free(maildirfilter);
			return (-1);
		}
	}

	maildir_tmpcreate_free(&createInfo);
	free(maildirfilter);
	return (0);
}
Beispiel #9
0
int	Maildir::MaildirOpen(const char *dir, Mio &file, off_t s)
{
	Buffer	buf;
	struct maildirsize quotainfo;

	const char *quotap;

	Buffer quotabuf;

	quotabuf="MAILDIRQUOTA";	/* Reuse a convenient buffer */
	quotabuf= *GetVar(quotabuf);
	quotabuf += '\0';

	quotap=quotabuf;

	if (!*quotap)
		quotap=NULL;

	MaildirAbort();

AlarmTimer	abort_timer;
static long	counter=0;

	buf.set(counter++);
	buf += '\0';

	struct maildir_tmpcreate_info createInfo;

	maildir_tmpcreate_init(&createInfo);

	createInfo.maildir=dir;
	createInfo.uniq=(const char *)buf;
	createInfo.msgsize=s;
	createInfo.openmode=0666;

	abort_timer.Set( 24 * 60 * 60 );
	while (!abort_timer.Expired())
	{
		Buffer name_buf;

		name_buf="UMASK";
		const char *um=GetVarStr(name_buf);
		unsigned int umask_val=077;

		sscanf(um, "%o", &umask_val);

		umask_val=umask(umask_val);

		int f=maildir_tmpcreate_fd(&createInfo);
		umask(umask_val);

		if (f >= 0)
		{
			Buffer b;

			b="FLAGS";

			const char *flags=GetVarStr(b);

			tmpname=createInfo.tmpname;
			tmpname += '\0';

			if (flags)
			{
				const char *p=flags;

				while (*p)
				{
					if (strchr("DRSF", *p) == NULL)
					{
						f=0;
						break;
					}
					++p;
				}
			}

			if (flags && *flags)
			{
				newname=createInfo.curname;
				newname += ':';
				newname += '2';
				newname += ',';
				newname += flags;
			}
			else
			{
				newname=createInfo.newname;
			}

			newname += '\0';
			maildir_tmpcreate_free(&createInfo);

			file.fd(f);
			is_open=1;
			maildirRoot=dir;
			maildirRoot += '\0';

			if (maildir_quota_add_start(dir, &quotainfo, s,
						    1, quotap))
			{
				file.fd(-1);
				unlink( (const char *)tmpname );
				is_open=0;
				maildir_deliver_quota_warning(dir,
							      quota_warn_percent,
							      quota_warn_message);
				merr << "maildrop: maildir over quota.\n";
				return (-1);
			}

			maildir_quota_add_end(&quotainfo, s, 1);
			return (0);
		}

		if (errno != EAGAIN)
		{
			merr << "maildrop: " << dir << ": " << strerror(errno)
			     << "\n";
			return -1;
		}

		AlarmSleep	try_again(2);
	}

	merr << "maildrop: time out on maildir directory.\n";
	return (-1);
}
Beispiel #10
0
static int newmsgs(const char *cur, const char *shared, struct dbobj *obj)
{
	char	*key, *val;
	size_t	keylen, vallen;
	int fd;
	struct maildir_tmpcreate_info createInfo;

	maildir_tmpcreate_init(&createInfo);
	createInfo.maildir=cur;
	createInfo.uniq="newlink";
	createInfo.doordie=1;

	if ((fd=maildir_tmpcreate_fd(&createInfo)) < 0)
		return -1;
	close(fd);

	unlink(createInfo.tmpname);

	for (key=dbobj_firstkey(obj, &keylen, &val, &vallen); key;
		key=dbobj_nextkey(obj, &keylen, &val, &vallen))
	{
	char	*slink=malloc(strlen(shared)+sizeof("/cur/")+vallen);
	char	*q;

		if (!slink)
		{
			free(val);
			maildir_tmpcreate_free(&createInfo);
			return (-1);
		}

		strcat(strcpy(slink, shared), "/cur/");
		q=slink+strlen(slink);
		memcpy(q, val, vallen);
		q[vallen]=0;
		free(val);

		if (symlink(slink, createInfo.tmpname))
		{
			perror(createInfo.tmpname);

			free(slink);
			maildir_tmpcreate_free(&createInfo);
			return (-1);
		}

		free(slink);
		slink=malloc(strlen(cur)+sizeof("/new/" MDIRSEP "2,")+keylen);
		if (!slink)
		{
			perror("malloc");
			maildir_tmpcreate_free(&createInfo);
			return (-1);
		}

		strcat(strcpy(slink, cur), "/new/");
		q=slink+strlen(slink);
		memcpy(q, key, keylen);
		strcpy(q+keylen, MDIRSEP "2,");

		if (rename(createInfo.tmpname, slink))
		{
			free(slink);
			maildir_tmpcreate_free(&createInfo);
			return (-1);
		}
		free(slink);
	}
	maildir_tmpcreate_free(&createInfo);
	return (0);
}
Beispiel #11
0
static long deliver(int fdin, const char *dir, long s,
		    int auto_create, int quota_warn_percent, const char *pfix,
		    const char *newquota)
{
	struct maildir_tmpcreate_info createInfo;
	char	buf[BUFSIZ];
	int	n;
	long	ss=0;
	int	fd;

	maildir_tmpcreate_init(&createInfo);

	createInfo.maildir=dir;
	createInfo.uniq=pfix;
	createInfo.msgsize=s;
	createInfo.doordie=1;

	while ((fd=maildir_tmpcreate_fd(&createInfo)) < 0)
	{
		if (errno == ENOENT && auto_create && maildir_mkdir(dir) == 0)
		{
			auto_create=0;
			continue;
		}

		perror(dir);
		exit(EX_TEMPFAIL);
	}

	while ((n=read(fdin, buf, sizeof(buf))) > 0)
	{
	char	*p=buf;

		ss += n;
		while (n)
		{
		int	l;

			if ((l=write(fd, p, n)) < 0)
			{
				close(fd);
				unlink(createInfo.tmpname);
				perror(createInfo.tmpname);
				exit(EX_IOERR);
			}
			p += l;
			n -= l;
		}
	}
	close(fd);
	if (n < 0)
	{
		unlink(createInfo.tmpname);
		perror(createInfo.tmpname);
		exit(EX_IOERR);
	}

	if (s != ss)
	{
		char	*qq;
		struct maildirsize info;

		if (s)	*strrchr(createInfo.newname, ',')=0;
		/* Zap incorrect size */
		qq=malloc(strlen(createInfo.newname)+100);
		if (!qq)
		{
			unlink(createInfo.tmpname);
			perror(createInfo.tmpname);
			exit(EX_OSERR);
		}
		sprintf(qq, "%s,S=%ld", createInfo.newname, ss-s);
		free(createInfo.newname);
		createInfo.newname=qq;

		if (maildirquota_countfolder(dir))
		{
			if (maildir_quota_add_start(dir, &info, ss-s, 1,
						    newquota))
			{
				unlink(createInfo.tmpname);
				printf("Mail quota exceeded.\n");
				exit(EX_NOPERM);
			}
			maildir_quota_add_end(&info, ss-s, 1);
		}
	}

	if (maildir_movetmpnew(createInfo.tmpname, createInfo.newname))
	{
		unlink(createInfo.tmpname);
		perror(createInfo.tmpname);
		exit(EX_IOERR);
	}
	maildir_tmpcreate_free(&createInfo);

	if (quota_warn_percent >= 0)
		maildir_deliver_quota_warning(dir, quota_warn_percent);

	return (ss);
}