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