maildirquota.c
上传用户:s81996212
上传日期:2007-01-04
资源大小:722k
文件大小:12k
源码类别:

WEB邮件程序

开发平台:

C/C++

  1. /*
  2. ** Copyright 1998 - 2000 Double Precision, Inc.
  3. ** See COPYING for distribution information.
  4. */
  5. #if HAVE_CONFIG_H
  6. #include "config.h"
  7. #endif
  8. #include <sys/types.h>
  9. #if HAVE_DIRENT_H
  10. #include <dirent.h>
  11. #define NAMLEN(dirent) strlen((dirent)->d_name)
  12. #else
  13. #define dirent direct
  14. #define NAMLEN(dirent) (dirent)->d_namlen
  15. #if HAVE_SYS_NDIR_H
  16. #include <sys/ndir.h>
  17. #endif
  18. #if HAVE_SYS_DIR_H
  19. #include <sys/dir.h>
  20. #endif
  21. #if HAVE_NDIR_H
  22. #include <ndir.h>
  23. #endif
  24. #endif
  25. #include <sys/types.h>
  26. #if HAVE_SYS_STAT_H
  27. #include <sys/stat.h>
  28. #endif
  29. #include <sys/uio.h>
  30. #include "maildirquota.h"
  31. #include "maildirmisc.h"
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <string.h>
  35. #include <errno.h>
  36. #if HAVE_FCNTL_H
  37. #include <fcntl.h>
  38. #endif
  39. #if HAVE_UNISTD_H
  40. #include <unistd.h>
  41. #endif
  42. #include <time.h>
  43. #include <numlib/numlib.h>
  44. static const char rcsid[]="$Id: maildirquota.c,v 1.3 2000/05/24 03:42:00 mrsam Exp $";
  45. /* Read the maildirsize file */
  46. static int maildirsize_read(const char *filename, /* The filename */
  47. int *fdptr, /* Keep the file descriptor open */
  48. off_t *sizeptr, /* Grand total of maildir size */
  49. unsigned *cntptr, /* Grand total of message count */
  50. unsigned *nlines, /* # of lines in maildirsize */
  51. struct stat *statptr) /* The stats on maildirsize */
  52. {
  53. char buf[5120];
  54. int f;
  55. char *p;
  56. unsigned l;
  57. int n;
  58. int first;
  59. if ((f=maildir_safeopen(filename, O_RDWR|O_APPEND, 0)) < 0)
  60. return (-1);
  61. p=buf;
  62. l=sizeof(buf);
  63. while (l)
  64. {
  65. n=read(f, p, l);
  66. if (n < 0)
  67. {
  68. close(f);
  69. return (-1);
  70. }
  71. if (n == 0) break;
  72. p += n;
  73. l -= n;
  74. }
  75. if (l == 0 || fstat(f, statptr)) /* maildir too big */
  76. {
  77. close(f);
  78. return (-1);
  79. }
  80. *sizeptr=0;
  81. *cntptr=0;
  82. *nlines=0;
  83. *p=0;
  84. p=buf;
  85. first=1;
  86. while (*p)
  87. {
  88. long n=0;
  89. int c=0;
  90. char *q=p;
  91. while (*p)
  92. if (*p++ == 'n')
  93. {
  94. p[-1]=0;
  95. break;
  96. }
  97. if (first)
  98. {
  99. first=0;
  100. continue;
  101. }
  102. sscanf(q, "%ld %d", &n, &c);
  103. *sizeptr += n;
  104. *cntptr += c;
  105. ++ *nlines;
  106. }
  107. *fdptr=f;
  108. return (0);
  109. }
  110. static char *makenewmaildirsizename(const char *, int *);
  111. static int countcurnew(const char *, time_t *, off_t *, unsigned *);
  112. static int countsubdir(const char *, const char *,
  113. time_t *, off_t *, unsigned *);
  114. static int statcurnew(const char *, time_t *);
  115. static int statsubdir(const char *, const char *, time_t *);
  116. #define MDQUOTA_SIZE 'S' /* Total size of all messages in maildir */
  117. #define MDQUOTA_BLOCKS 'B' /* Total # of blocks for all messages in
  118. maildir -- NOT IMPLEMENTED */
  119. #define MDQUOTA_COUNT 'C' /* Total number of messages in maildir */
  120. static int qcalc(off_t s, unsigned n, const char *quota)
  121. {
  122. unsigned long i;
  123. errno=ENOSPC;
  124. while (quota && *quota)
  125. {
  126. if (*quota < '0' || *quota > '9')
  127. {
  128. ++quota;
  129. continue;
  130. }
  131. i=0;
  132. while (*quota >= '0' && *quota <= '9')
  133. i=i*10 + (*quota++ - '0');
  134. switch (*quota) {
  135. default:
  136. if (i < s) return (-1);
  137. break;
  138. case 'C':
  139. if (i < n) return (-1);
  140. break;
  141. }
  142. }
  143. return (0);
  144. }
  145. static int doaddquota(const char *, int, const char *, long, int, int);
  146. int maildir_checkquota(const char *dir,
  147. int *maildirsize_fdptr,
  148. const char *quota_type,
  149. long xtra_size,
  150. int xtra_cnt)
  151. {
  152. char *checkfolder=(char *)malloc(strlen(dir)+sizeof("/maildirfolder"));
  153. char *newmaildirsizename;
  154. struct stat stat_buf;
  155. int maildirsize_fd;
  156. off_t maildirsize_size;
  157. unsigned maildirsize_cnt;
  158. unsigned maildirsize_nlines;
  159. int n;
  160. time_t tm;
  161. time_t maxtime;
  162. DIR *dirp;
  163. struct dirent *de;
  164. if (checkfolder == 0) return (-1);
  165. *maildirsize_fdptr= -1;
  166. strcat(strcpy(checkfolder, dir), "/maildirfolder");
  167. if (stat(checkfolder, &stat_buf) == 0) /* Go to parent */
  168. {
  169. strcat(strcpy(checkfolder, dir), "/..");
  170. n=maildir_checkquota(checkfolder, maildirsize_fdptr,
  171. quota_type, xtra_size, xtra_cnt);
  172. free(checkfolder);
  173. return (n);
  174. }
  175. if (!quota_type || !*quota_type) return (0);
  176. strcat(strcpy(checkfolder, dir), "/maildirsize");
  177. time(&tm);
  178. if (maildirsize_read(checkfolder, &maildirsize_fd,
  179. &maildirsize_size, &maildirsize_cnt,
  180. &maildirsize_nlines, &stat_buf) == 0)
  181. {
  182. n=qcalc(maildirsize_size+xtra_size, maildirsize_cnt+xtra_cnt,
  183. quota_type);
  184. if (n == 0)
  185. {
  186. free(checkfolder);
  187. *maildirsize_fdptr=maildirsize_fd;
  188. return (0);
  189. }
  190. close(maildirsize_fd);
  191. if (maildirsize_nlines == 1 && tm < stat_buf.st_mtime + 15*60)
  192. return (n);
  193. }
  194. maxtime=0;
  195. maildirsize_size=0;
  196. maildirsize_cnt=0;
  197. if (countcurnew(dir, &maxtime, &maildirsize_size, &maildirsize_cnt))
  198. {
  199. free(checkfolder);
  200. return (-1);
  201. }
  202. dirp=opendir(dir);
  203. while (dirp && (de=readdir(dirp)) != 0)
  204. {
  205. if (countsubdir(dir, de->d_name, &maxtime, &maildirsize_size,
  206. &maildirsize_cnt))
  207. {
  208. free(checkfolder);
  209. closedir(dirp);
  210. return (-1);
  211. }
  212. }
  213. if (dirp)
  214. {
  215. #if CLOSEDIR_VOID
  216. closedir(dirp);
  217. #else
  218. if (closedir(dirp))
  219. {
  220. free(checkfolder);
  221. return (-1);
  222. }
  223. #endif
  224. }
  225. newmaildirsizename=makenewmaildirsizename(dir, &maildirsize_fd);
  226. if (!newmaildirsizename)
  227. {
  228. free(checkfolder);
  229. return (-1);
  230. }
  231. *maildirsize_fdptr=maildirsize_fd;
  232. if (doaddquota(dir, maildirsize_fd, quota_type, maildirsize_size,
  233. maildirsize_cnt, 1))
  234. {
  235. free(newmaildirsizename);
  236. unlink(newmaildirsizename);
  237. close(maildirsize_fd);
  238. *maildirsize_fdptr= -1;
  239. free(checkfolder);
  240. return (-1);
  241. }
  242. strcat(strcpy(checkfolder, dir), "/maildirsize");
  243. if (rename(newmaildirsizename, checkfolder))
  244. {
  245. free(checkfolder);
  246. unlink(newmaildirsizename);
  247. close(maildirsize_fd);
  248. *maildirsize_fdptr= -1;
  249. }
  250. free(checkfolder);
  251. free(newmaildirsizename);
  252. tm=0;
  253. if (statcurnew(dir, &tm))
  254. {
  255. close(maildirsize_fd);
  256. *maildirsize_fdptr= -1;
  257. return (-1);
  258. }
  259. dirp=opendir(dir);
  260. while (dirp && (de=readdir(dirp)) != 0)
  261. {
  262. if (statsubdir(dir, de->d_name, &tm))
  263. {
  264. close(maildirsize_fd);
  265. *maildirsize_fdptr= -1;
  266. closedir(dirp);
  267. return (-1);
  268. }
  269. }
  270. if (dirp)
  271. {
  272. #if CLOSEDIR_VOID
  273. closedir(dirp);
  274. #else
  275. if (closedir(dirp))
  276. {
  277. close(maildirsize_fd);
  278. *maildirsize_fdptr= -1;
  279. return (-1);
  280. }
  281. #endif
  282. }
  283. if (tm != maxtime) /* Race condition, someone changed something */
  284. {
  285. errno=EAGAIN;
  286. return (-1);
  287. }
  288. return (qcalc(maildirsize_size+xtra_size, maildirsize_cnt+xtra_cnt,
  289. quota_type));
  290. }
  291. int maildir_addquota(const char *dir, int maildirsize_fd,
  292. const char *quota_type, long maildirsize_size, int maildirsize_cnt)
  293. {
  294. if (!quota_type || !*quota_type) return (0);
  295. return (doaddquota(dir, maildirsize_fd, quota_type, maildirsize_size,
  296. maildirsize_cnt, 0));
  297. }
  298. static int doaddquota(const char *dir, int maildirsize_fd,
  299. const char *quota_type, long maildirsize_size, int maildirsize_cnt,
  300. int isnew)
  301. {
  302. union {
  303. char buf[100];
  304. struct stat stat_buf;
  305. } u; /* Scrooge */
  306. char *newname2=0;
  307. char *newmaildirsizename=0;
  308. struct iovec iov[3];
  309. int niov;
  310. struct iovec *p;
  311. int n;
  312. niov=0;
  313. if ( maildirsize_fd < 0)
  314. {
  315. newname2=(char *)malloc(strlen(dir)+sizeof("/maildirfolder"));
  316. if (!newname2) return (-1);
  317. strcat(strcpy(newname2, dir), "/maildirfolder");
  318. if (stat(newname2, &u.stat_buf) == 0)
  319. {
  320. strcat(strcpy(newname2, dir), "/..");
  321. n=doaddquota(newname2, maildirsize_fd, quota_type,
  322. maildirsize_size, maildirsize_cnt,
  323. isnew);
  324. free(newname2);
  325. return (n);
  326. }
  327. strcat(strcpy(newname2, dir), "/maildirsize");
  328. if ((maildirsize_fd=maildir_safeopen(newname2,
  329. O_RDWR|O_APPEND, 0644)) < 0)
  330. {
  331. newmaildirsizename=makenewmaildirsizename(dir, &maildirsize_fd);
  332. if (!newmaildirsizename)
  333. {
  334. free(newname2);
  335. return (-1);
  336. }
  337. maildirsize_fd=maildir_safeopen(newmaildirsizename,
  338. O_CREAT|O_RDWR|O_APPEND, 0644);
  339. if (maildirsize_fd < 0)
  340. {
  341. free(newname2);
  342. return (-1);
  343. }
  344. isnew=1;
  345. }
  346. }
  347. if (isnew)
  348. {
  349. iov[0].iov_base=(caddr_t)quota_type;
  350. iov[0].iov_len=strlen(quota_type);
  351. iov[1].iov_base=(caddr_t)"n";
  352. iov[1].iov_len=1;
  353. niov=2;
  354. }
  355. sprintf(u.buf, "%ld %dn", maildirsize_size, maildirsize_cnt);
  356. iov[niov].iov_base=(caddr_t)u.buf;
  357. iov[niov].iov_len=strlen(u.buf);
  358. p=iov;
  359. ++niov;
  360. n=0;
  361. while (niov)
  362. {
  363. if (n)
  364. {
  365. if (n < p->iov_len)
  366. {
  367. p->iov_base=
  368. (caddr_t)((char *)p->iov_base + n);
  369. p->iov_len -= n;
  370. }
  371. else
  372. {
  373. n -= p->iov_len;
  374. ++p;
  375. --niov;
  376. continue;
  377. }
  378. }
  379. n=writev( maildirsize_fd, p, niov);
  380. if (n <= 0)
  381. {
  382. if (newname2)
  383. {
  384. close(maildirsize_fd);
  385. free(newname2);
  386. }
  387. return (-1);
  388. }
  389. }
  390. if (newname2)
  391. {
  392. close(maildirsize_fd);
  393. if (newmaildirsizename)
  394. {
  395. rename(newmaildirsizename, newname2);
  396. free(newmaildirsizename);
  397. }
  398. free(newname2);
  399. }
  400. return (0);
  401. }
  402. /* New maildirsize is built in the tmp subdirectory */
  403. static char *makenewmaildirsizename(const char *dir, int *fd)
  404. {
  405. char hostname[256];
  406. struct stat stat_buf;
  407. time_t t;
  408. char *p;
  409. hostname[0]=0;
  410. hostname[sizeof(hostname)-1]=0;
  411. gethostname(hostname, sizeof(hostname)-1);
  412. p=(char *)malloc(strlen(dir)+strlen(hostname)+130);
  413. if (!p) return (0);
  414. for (;;)
  415. {
  416. char tbuf[NUMBUFSIZE];
  417. char pbuf[NUMBUFSIZE];
  418. time(&t);
  419. strcat(strcpy(p, dir), "/tmp/");
  420. sprintf(p+strlen(p), "%s.%s_NeWmAiLdIrSiZe.%s",
  421. str_time_t(t, tbuf),
  422. str_pid_t(getpid(), pbuf), hostname);
  423. if (stat( (const char *)p, &stat_buf) < 0 &&
  424. (*fd=maildir_safeopen(p,
  425. O_CREAT|O_RDWR|O_APPEND, 0644)) >= 0)
  426. break;
  427. sleep(3);
  428. }
  429. return (p);
  430. }
  431. static int statcurnew(const char *dir, time_t *maxtimestamp)
  432. {
  433. char *p=(char *)malloc(strlen(dir)+5);
  434. struct stat stat_buf;
  435. if (!p) return (-1);
  436. strcat(strcpy(p, dir), "/cur");
  437. if ( stat(p, &stat_buf) == 0 && stat_buf.st_mtime > *maxtimestamp)
  438. *maxtimestamp=stat_buf.st_mtime;
  439. strcat(strcpy(p, dir), "/new");
  440. if ( stat(p, &stat_buf) == 0 && stat_buf.st_mtime > *maxtimestamp)
  441. *maxtimestamp=stat_buf.st_mtime;
  442. free(p);
  443. return (0);
  444. }
  445. static int statsubdir(const char *dir, const char *subdir, time_t *maxtime)
  446. {
  447. char *p;
  448. int n;
  449. if ( *subdir != '.' || strcmp(subdir, ".") == 0 ||
  450. strcmp(subdir, "..") == 0 || strcmp(subdir, ".Trash") == 0)
  451. return (0);
  452. p=(char *)malloc(strlen(dir)+strlen(subdir)+2);
  453. if (!p) return (-1);
  454. strcat(strcat(strcpy(p, dir), "/"), subdir);
  455. n=statcurnew(p, maxtime);
  456. free(p);
  457. return (n);
  458. }
  459. static int docount(const char *, time_t *, off_t *, unsigned *);
  460. static int countcurnew(const char *dir, time_t *maxtime,
  461. off_t *sizep, unsigned *cntp)
  462. {
  463. char *p=(char *)malloc(strlen(dir)+5);
  464. int n;
  465. if (!p) return (-1);
  466. strcat(strcpy(p, dir), "/new");
  467. n=docount(p, maxtime, sizep, cntp);
  468. if (n == 0)
  469. {
  470. strcat(strcpy(p, dir), "/cur");
  471. n=docount(p, maxtime, sizep, cntp);
  472. }
  473. free(p);
  474. return (n);
  475. }
  476. static int countsubdir(const char *dir, const char *subdir, time_t *maxtime,
  477. off_t *sizep, unsigned *cntp)
  478. {
  479. char *p;
  480. int n;
  481. if ( *subdir != '.' || strcmp(subdir, ".") == 0 ||
  482. strcmp(subdir, "..") == 0 || strcmp(subdir, ".Trash") == 0)
  483. return (0);
  484. p=(char *)malloc(strlen(dir)+strlen(subdir)+2);
  485. if (!p) return (2);
  486. strcat(strcat(strcpy(p, dir), "/"), subdir);
  487. n=countcurnew(p, maxtime, sizep, cntp);
  488. free(p);
  489. return (n);
  490. }
  491. static int docount(const char *dir, time_t *dirstamp,
  492. off_t *sizep, unsigned *cntp)
  493. {
  494. struct stat stat_buf;
  495. char *p;
  496. DIR *dirp;
  497. struct dirent *de;
  498. unsigned long s;
  499. if (stat(dir, &stat_buf)) return (0); /* Ignore */
  500. if (stat_buf.st_mtime > *dirstamp) *dirstamp=stat_buf.st_mtime;
  501. if ((dirp=opendir(dir)) == 0) return (0);
  502. while ((de=readdir(dirp)) != 0)
  503. {
  504. const char *n=de->d_name;
  505. if (*n == '.') continue;
  506. /* PATCH - do not count msgs marked as deleted */
  507. for ( ; *n; n++)
  508. {
  509. if (n[0] != ':' || n[1] != '2' ||
  510. n[2] != ',') continue;
  511. n += 3;
  512. while (*n >= 'A' && *n <= 'Z')
  513. {
  514. if (*n == 'T') break;
  515. ++n;
  516. }
  517. break;
  518. }
  519. if (*n == 'T') continue;
  520. n=de->d_name;
  521. if (maildir_parsequota(n, &s) == 0)
  522. stat_buf.st_size=s;
  523. else
  524. {
  525. p=(char *)malloc(strlen(dir)+strlen(n)+2);
  526. if (!p)
  527. {
  528. closedir(dirp);
  529. return (-1);
  530. }
  531. strcat(strcat(strcpy(p, dir), "/"), n);
  532. if (stat(p, &stat_buf))
  533. {
  534. free(p);
  535. continue;
  536. }
  537. free(p);
  538. }
  539. *sizep += stat_buf.st_size;
  540. ++*cntp;
  541. }
  542. #if CLOSEDIR_VOID
  543. closedir(dirp);
  544. #else
  545. if (closedir(dirp))
  546. return (-1);
  547. #endif
  548. return (0);
  549. }