1 /*
2 ** Copyright 1998 - 2009 Double Precision, Inc.
3 ** See COPYING for distribution information.
4 */
5 
6 #include	"config.h"
7 #include	"maildirquota.h"
8 #include	"maildircreate.h"
9 #include	"maildirmisc.h"
10 #include	"quotawarnmsg.h"
11 #include	<stdio.h>
12 #include	<string.h>
13 #include	<stdlib.h>
14 #include	<sys/types.h>
15 #include	<errno.h>
16 #if HAVE_SYS_STAT_H
17 #include	<sys/stat.h>
18 #endif
19 #if HAVE_UNISTD_H
20 #include	<unistd.h>
21 #endif
22 #if	HAVE_FCNTL_H
23 #include	<fcntl.h>
24 #endif
25 #include	<time.h>
26 #if	HAVE_SYSEXITS_H
27 #include	<sysexits.h>
28 #endif
29 #include	"rfc822/rfc822.h"
30 #ifndef	BUFSIZE
31 #define	BUFSIZE	8192
32 #endif
33 
34 #ifndef	EX_OSERR
35 #define	EX_OSERR	71
36 #endif
37 
38 #ifndef	EX_IOERR
39 #define	EX_IOERR	74
40 #endif
41 
42 #ifndef	EX_TEMPFAIL
43 #define EX_TEMPFAIL	75
44 #endif
45 
46 #ifndef	EX_NOPERM
47 #define	EX_NOPERM	77
48 #endif
49 
50 
deliver(int fdin,const char * dir,long s,int auto_create,int quota_warn_percent,const char * pfix,const char * newquota,const char * quota_warn_msg)51 static long deliver(int fdin, const char *dir, long s,
52 		    int auto_create, int quota_warn_percent, const char *pfix,
53 		    const char *newquota,
54 		    const char *quota_warn_msg)
55 {
56 	struct maildir_tmpcreate_info createInfo;
57 	char	buf[BUFSIZ];
58 	int	n;
59 	long	ss=0;
60 	int	fd;
61 
62 	maildir_tmpcreate_init(&createInfo);
63 	createInfo.openmode=0666;
64 	createInfo.maildir=dir;
65 	createInfo.uniq=pfix;
66 	createInfo.msgsize=s;
67 	createInfo.doordie=1;
68 
69 	while ((fd=maildir_tmpcreate_fd(&createInfo)) < 0)
70 	{
71 		if (errno == ENOENT && auto_create && maildir_mkdir(dir) == 0)
72 		{
73 			auto_create=0;
74 			continue;
75 		}
76 
77 		perror(dir);
78 		exit(EX_TEMPFAIL);
79 	}
80 
81 	while ((n=read(fdin, buf, sizeof(buf))) > 0)
82 	{
83 	char	*p=buf;
84 
85 		ss += n;
86 		while (n)
87 		{
88 		int	l;
89 
90 			if ((l=write(fd, p, n)) < 0)
91 			{
92 				close(fd);
93 				unlink(createInfo.tmpname);
94 				perror(createInfo.tmpname);
95 				exit(EX_IOERR);
96 			}
97 			p += l;
98 			n -= l;
99 		}
100 	}
101 	close(fd);
102 	if (n < 0)
103 	{
104 		unlink(createInfo.tmpname);
105 		perror(createInfo.tmpname);
106 		exit(EX_IOERR);
107 	}
108 
109 	if (s != ss)
110 	{
111 		char	*qq;
112 		struct maildirsize info;
113 
114 		if (s)	*strrchr(createInfo.newname, ',')=0;
115 		/* Zap incorrect size */
116 		qq=malloc(strlen(createInfo.newname)+100);
117 		if (!qq)
118 		{
119 			unlink(createInfo.tmpname);
120 			perror(createInfo.tmpname);
121 			exit(EX_OSERR);
122 		}
123 		sprintf(qq, "%s,S=%ld", createInfo.newname, ss-s);
124 		free(createInfo.newname);
125 		createInfo.newname=qq;
126 
127 		if (maildirquota_countfolder(dir))
128 		{
129 			if (maildir_quota_add_start(dir, &info, ss-s, 1,
130 						    newquota))
131 			{
132 				unlink(createInfo.tmpname);
133 				printf("Mail quota exceeded.\n");
134 #if HAVE_COURIER
135 				exit(EX_TEMPFAIL);
136 #else
137 				exit(EX_NOPERM);
138 #endif
139 			}
140 			maildir_quota_add_end(&info, ss-s, 1);
141 		}
142 	}
143 
144 	if (maildir_movetmpnew(createInfo.tmpname, createInfo.newname))
145 	{
146 		unlink(createInfo.tmpname);
147 		perror(createInfo.tmpname);
148 		exit(EX_IOERR);
149 	}
150 	maildir_tmpcreate_free(&createInfo);
151 
152 	if (quota_warn_percent >= 0)
153 		maildir_deliver_quota_warning(dir, quota_warn_percent,
154 					      quota_warn_msg);
155 
156 	return (ss);
157 }
158 
main(int argc,char ** argv)159 int main(int argc, char **argv)
160 {
161 	const char *dir;
162 	struct	stat	stat_buf;
163 	int	auto_create = 0;
164 	int	quota_warn_percent = -1;
165 	int i;
166 	const char *quota=NULL;
167 	const   char *quota_warn_msg=0;
168 
169 	for (i=1; i<argc; i++)
170 	{
171 		if (strcmp(argv[i], "-c") == 0)
172 		{
173 			auto_create = 1;
174 			continue;
175 		}
176 
177 		if (strcmp(argv[i], "-w") == 0 && argc - i > 1)
178 		{
179 			quota_warn_percent = atoi(argv[i+1]);
180 			++i;
181 			continue;
182 		}
183 
184 		if (strcmp(argv[i], "-W") == 0 && argc - i > 1)
185 		{
186 			quota_warn_msg = argv[i+1];
187 			++i;
188 			continue;
189 		}
190 
191 		break;
192 	}
193 	if (i >= argc || quota_warn_percent < -1 || quota_warn_percent > 100)
194 	{
195 		fprintf(stderr, "Usage: %s [-c] [-w percent] maildir\n",
196 			argv[0]);
197 		exit(73);
198 	}
199 
200 	dir=argv[i];
201 
202 	++i;
203 	if (i < argc)
204 		quota=argv[i];
205 
206 	if (fstat(0, &stat_buf) == 0 && S_ISREG(stat_buf.st_mode) &&
207 		stat_buf.st_size > 0)
208 	{
209 		struct maildirsize info;
210 		int doquota=maildirquota_countfolder(dir);
211 
212 		if (doquota &&
213 		    maildir_quota_add_start(dir, &info, stat_buf.st_size, 1,
214 					    quota))
215 		{
216 			if (quota_warn_percent >= 0)
217 				maildir_deliver_quota_warning(dir, quota_warn_percent,
218 							      quota_warn_msg);
219 			printf("Mail quota exceeded.\n");
220 			exit(77);
221 		}
222 		deliver(0, dir, stat_buf.st_size,
223 			auto_create, quota_warn_percent, NULL, quota,
224 			quota_warn_msg);
225 
226 		if (doquota)
227 			maildir_quota_add_end(&info, stat_buf.st_size, 1);
228 		exit(0);
229 	}
230 	deliver(0, dir, 0, auto_create, quota_warn_percent, NULL, quota,
231 		quota_warn_msg);
232 	exit(0);
233 }
234