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

WEB邮件程序

开发平台:

C/C++

  1. /*
  2. ** Copyright 1998 - 2000 Double Precision, Inc.  See COPYING for
  3. ** distribution information.
  4. */
  5. /*
  6. ** $Id: maildir.c,v 1.35 2000/05/02 04:18:51 mrsam Exp $
  7. */
  8. #include <stdio.h>
  9. #include <string.h>
  10. #include <stdlib.h>
  11. #include <ctype.h>
  12. #include <fcntl.h>
  13. #include <errno.h>
  14. #include "config.h"
  15. #include "sqwebmail.h"
  16. #include "maildir.h"
  17. #include "folder.h"
  18. #include "rfc822/rfc822.h"
  19. #include "pref.h"
  20. #include "sqconfig.h"
  21. #include "dbobj.h"
  22. #include "maildir/maildirquota.h"
  23. #include "maildir/maildirrequota.h"
  24. #include "maildir/maildirgetquota.h"
  25. #include "maildir/maildirmisc.h"
  26. #include "maildir/maildircreate.h"
  27. #if HAVE_UNISTD_H
  28. #include <unistd.h>
  29. #endif
  30. #if HAVE_DIRENT_H
  31. #include <dirent.h>
  32. #define NAMLEN(dirent) strlen(dirent->d_name)
  33. #else
  34. #define dirent direct
  35. #define NAMLEN(dirent) ((dirent)->d_namlen)
  36. #if HAVE_SYS_NDIR_H
  37. #include <sys/ndir.h>
  38. #endif
  39. #if HAVE_SYS_DIR_H
  40. #include <sys/dir.h>
  41. #endif
  42. #if HAVE_NDIR_H
  43. #include <ndir.h>
  44. #endif
  45. #endif
  46. #include <sys/types.h>
  47. #include <sys/stat.h>
  48. #if HAVE_UTIME_H
  49. #include <utime.h>
  50. #endif
  51. static time_t current_time;
  52. extern time_t rfc822_parsedt(const char *);
  53. extern const char *dropre(const char *, int *);
  54. static char *folderdatname=0; /* Which folder has been cached */
  55. static struct dbobj folderdat;
  56. static const char *folderdatmode; /* "R" or "W" */
  57. static time_t cachemtime; /* Modification time of the cache file */
  58. static unsigned long new_cnt, all_cnt;
  59. static int isoldestfirst;
  60. static char sortorder;
  61. static void createmdcache(const char *);
  62. static void maildir_getfoldermsgs(const char *);
  63. /* Change timestamp on a file */
  64. static const char *parse_ul(const char *p, unsigned long *ul)
  65. {
  66. int err=1;
  67. while (p && isspace((int)(unsigned char)*p)) ++p;
  68. *ul=0;
  69. while (p && *p >= '0' && *p <= '9')
  70. {
  71. *ul *= 10;
  72. *ul += (*p-'0');
  73. err=0;
  74. ++p;
  75. }
  76. if (err) return (0);
  77. return (p);
  78. }
  79. static void change_timestamp(const char *filename, time_t t)
  80. {
  81. #if HAVE_UTIME
  82. struct utimbuf ut;
  83. ut.actime=ut.modtime=t;
  84. utime(filename, &ut);
  85. #else
  86. #if HAVE_UTIMES
  87. struct timeval tv;
  88. tv.tv_sec=t;
  89. tv.tv_usec=0;
  90. utimes(filename, &tv);
  91. #else
  92. #error You do not have utime or utimes function.  Upgrade your operating system.
  93. #endif
  94. #endif
  95. }
  96. /* Translate folder name into directory name */
  97. static char *xlate_mdir(const char *foldername)
  98. {
  99. char *p;
  100. if (strchr(foldername, ':')) enomem();
  101. p=maildir_folderdir(0, foldername);
  102. if (!p) enomem();
  103. return (p);
  104. }
  105. static char *xlate_shmdir(const char *foldername)
  106. {
  107. if (*foldername == ':')
  108. {
  109. char *p;
  110. p=maildir_shareddir(0, foldername+1);
  111. if (!p) enomem();
  112. return (p);
  113. }
  114. return (xlate_mdir(foldername));
  115. }
  116. /* Display message size in meaningfull form */
  117. static void cat_n(char *buf, unsigned long n)
  118. {
  119. char bb[MAXLONGSIZE+1];
  120. char *p=bb+sizeof(bb)-1;
  121. *p=0;
  122. do
  123. {
  124. *--p = "0123456789"[n % 10];
  125. n=n/10;
  126. } while (n);
  127. strcat(buf, p);
  128. }
  129. const char *showsize(unsigned long n)
  130. {
  131. static char sizebuf[MAXLONGSIZE+10];
  132. /* If size is less than 1K bytes, display it as 0.xK */
  133. if (n < 1024)
  134. {
  135. strcpy(sizebuf, "0.");
  136. cat_n(sizebuf, (int)(10 * n / 1024 ));
  137. strcat(sizebuf, "K");
  138. }
  139. /* If size is less than 1 meg, display is as xK */
  140. else if (n < 1024 * 1024)
  141. {
  142. *sizebuf=0;
  143. cat_n(sizebuf, (unsigned long)(n+512)/1024);
  144. strcat(sizebuf, "K");
  145. }
  146. /* Otherwise, display in megabytes */
  147. else
  148. {
  149. unsigned long nm=(double)n / (1024.0 * 1024.0) * 10;
  150. *sizebuf=0;
  151. cat_n( sizebuf, nm / 10);
  152. strcat(sizebuf, ".");
  153. cat_n( sizebuf, nm % 10);
  154. strcat(sizebuf, "M");
  155. }
  156. return (sizebuf);
  157. }
  158. /* Put together a filename from up to three parts */
  159. char *alloc_filename(const char *dir1, const char *dir2, const char *filename)
  160. {
  161. char *p;
  162. if (!dir1) dir1="";
  163. if (!dir2) dir2="";
  164. p=malloc(strlen(dir1)+strlen(dir2)+strlen(filename)+3);
  165. if (!p) enomem();
  166. strcpy(p, dir1);
  167. if (*dir2)
  168. {
  169. if (*p) strcat(p, "/");
  170. strcat(p, dir2);
  171. }
  172. if (*filename)
  173. {
  174. if (*p) strcat(p, "/");
  175. strcat(p, filename);
  176. }
  177. return (p);
  178. }
  179. /*
  180. ** char *maildir_find(const char *maildir, const char *filename)
  181. ** - find a message in a maildir
  182. **
  183. ** Return the full path to the indicated message.  If the message flags
  184. ** in filename have changed, we search for the given message.
  185. */
  186. char *maildir_find(const char *folder, const char *filename)
  187. {
  188. char *p;
  189. char *d=xlate_shmdir(folder);
  190. int fd;
  191. if (!d) return (0);
  192. p=maildir_filename(d, 0, filename);
  193. free(d);
  194. if (!p) enomem();
  195. if ((fd=open(p, O_RDONLY)) >= 0)
  196. {
  197. close(fd);
  198. return (p);
  199. }
  200. free(p);
  201. return (0);
  202. }
  203. /*
  204. ** char *maildir_basename(const char *filename)
  205. **
  206. ** - return base name of the file (strip off cur or new, strip of trailing :)
  207. */
  208. char *maildir_basename(const char *filename)
  209. {
  210. const char *q=strrchr(filename, '/');
  211. char *p, *r;
  212. if (q) ++q;
  213. else q=filename;
  214. p=alloc_filename("", "", q);
  215. if ((r=strchr(p, ':')) != 0) *r='';
  216. return (p);
  217. }
  218. /* Display message creation time.  If less than one week old (more or less)
  219. ** show day of the week, and time of day, otherwise show day, month, year
  220. */
  221. static const char *displaydate(time_t t)
  222. {
  223. struct tm *tmp=localtime(&t);
  224. static char datebuf[40];
  225. datebuf[0]='';
  226. if (tmp)
  227. {
  228. strftime(datebuf, sizeof(datebuf)-1,
  229. (t < current_time - 6 * 24 * 60 * 60 ||
  230. t > current_time + 12 * 60 * 60
  231. ? "%d %b %Y" : "%a %I:%M %p"), tmp);
  232. datebuf[sizeof(datebuf)-1]=0;
  233. }
  234. return (datebuf);
  235. }
  236. /*
  237. ** Add a flag to a maildir filename
  238. */
  239. static char *maildir_addflagfilename(const char *filename, char flag)
  240. {
  241. char *new_filename=malloc(strlen(filename)+5);
  242. /* We can possibly add as many as four character */
  243. char *p;
  244. char *q;
  245. strcpy(new_filename, filename);
  246. p=strrchr(new_filename, '/');
  247. if (!p) p=new_filename;
  248. if ((q=strchr(p, ':')) == 0)
  249. strcat(new_filename, ":2,");
  250. else if (q[1] != '2' && q[2] != ',')
  251. strcpy(p, ":2,");
  252. p=strchr(p, ':');
  253. if (strchr(p, flag))
  254. {
  255. free(new_filename);
  256. return (0); /* Already set */
  257. }
  258. p += 2;
  259. while (*p && *p < flag) p++;
  260. q=p+strlen(p);
  261. while ((q[1]=*q) != *p)
  262. --q;
  263. *p=flag;
  264. return (new_filename);
  265. }
  266. static void closedb()
  267. {
  268. if (folderdatname)
  269. {
  270. dbobj_close(&folderdat);
  271. free(folderdatname);
  272. folderdatname=0;
  273. }
  274. }
  275. static int opencache(const char *folder, const char *mode)
  276. {
  277. char *maildir=xlate_shmdir(folder);
  278. char *cachename;
  279. size_t l;
  280. char *p;
  281. char *q;
  282. char *r;
  283. unsigned long ul;
  284. if (!maildir) return (-1);
  285. cachename=alloc_filename(maildir, "", MAILDIRCURCACHE "." DBNAME);
  286. if (folderdatname && strcmp(folderdatname, cachename) == 0)
  287. {
  288. if (strcmp(mode, "W") == 0 &&
  289. strcmp(folderdatmode, "W"))
  290. ;
  291. /*
  292. ** We want to open for write, folder is open for
  293. ** read
  294. */
  295. else
  296. {
  297. free(cachename);
  298. return (0);
  299. /* We already have this folder cache open */
  300. }
  301. }
  302. closedb();
  303. folderdatmode=mode;
  304. dbobj_init(&folderdat);
  305. if (dbobj_open(&folderdat, cachename, mode)) return (-1);
  306. folderdatname=cachename;
  307. if ((p=dbobj_fetch(&folderdat, "HEADER", 6, &l, "")) == 0)
  308. return (0);
  309. q=malloc(l+1);
  310. if (!q) enomem();
  311. memcpy(q, p, l);
  312. q[l]=0;
  313. free(p);
  314. cachemtime=0;
  315. new_cnt=0;
  316. all_cnt=0;
  317. isoldestfirst=0;
  318. sortorder=0;
  319. for (p=q; (p=strtok(p, "n")) != 0; p=0)
  320. {
  321. if ((r=strchr(p, '=')) == 0) continue;
  322. *r++=0;
  323. if (strcmp(p, "SAVETIME") == 0 &&
  324. parse_ul(r, &ul))
  325. cachemtime=ul;
  326. else if (strcmp(p, "COUNT") == 0)
  327. parse_ul(r, &all_cnt);
  328. else if (strcmp(p, "NEWCOUNT") == 0)
  329. parse_ul(r, &new_cnt);
  330. else if (strcmp(p, "SORT") == 0)
  331. {
  332. unsigned long ul;
  333. const char *s;
  334. if ((s=parse_ul(r, &ul)) != 0)
  335. {
  336. isoldestfirst=ul;
  337. sortorder= *s;
  338. }
  339. }
  340. }
  341. free(q);
  342. return (0);
  343. }
  344. #if 0
  345. static void maildir_addflag(const char *filename, char flag)
  346. {
  347. char *new_filename;
  348. if ((new_filename=maildir_addflagfilename(filename, flag)) != 0)
  349. {
  350. rename(filename, new_filename);
  351. free(new_filename);
  352. }
  353. }
  354. #endif
  355. /* And, remove a flag */
  356. static void maildir_remflagname(char *filename, char flag)
  357. {
  358. char *p;
  359. p=strrchr(filename, '/');
  360. if (!p) p=filename;
  361. if ((p=strchr(p, ':')) == 0) return;
  362. else if (p[1] != '2' && p[2] != ',')
  363. return;
  364. p=strchr(p, ':');
  365. p += 3;
  366. while (*p && isalpha((int)(unsigned char)*p))
  367. {
  368. if (*p == flag)
  369. {
  370. while ( (*p=p[1]) != 0)
  371. p++;
  372. return;
  373. }
  374. p++;
  375. }
  376. }
  377. static MSGINFO *get_msginfo(unsigned long n)
  378. {
  379. char namebuf[MAXLONGSIZE+40];
  380. char *p;
  381. size_t len;
  382. unsigned long ul;
  383. static char *buf=0;
  384. size_t bufsize=0;
  385. static MSGINFO msginfo_buf;
  386. sprintf(namebuf, "REC%lu", n);
  387. p=dbobj_fetch(&folderdat, namebuf, strlen(namebuf), &len, "");
  388. if (!p) return (0);
  389. if (!buf || len > bufsize)
  390. {
  391. buf= buf ? realloc(buf, len+1):malloc(len+1);
  392. if (!buf) enomem();
  393. bufsize=len;
  394. }
  395. memcpy(buf, p, len);
  396. buf[len]=0;
  397. memset(&msginfo_buf, 0, sizeof(msginfo_buf));
  398. msginfo_buf.filename= msginfo_buf.date_s= msginfo_buf.from_s=
  399. msginfo_buf.subject_s= msginfo_buf.size_s="";
  400. for (p=buf; (p=strtok(p, "n")) != 0; p=0)
  401. {
  402. char *q=strchr(p, '=');
  403. if (!q) continue;
  404. *q++=0;
  405. if (strcmp(p, "FILENAME") == 0)
  406. msginfo_buf.filename=q;
  407. else if (strcmp(p, "DATES") == 0)
  408. msginfo_buf.date_s=q;
  409. else if (strcmp(p, "FROM") == 0)
  410. msginfo_buf.from_s=q;
  411. else if (strcmp(p, "SUBJECT") == 0)
  412. msginfo_buf.subject_s=q;
  413. else if (strcmp(p, "SIZES") == 0)
  414. msginfo_buf.size_s=q;
  415. else if (strcmp(p, "DATE") == 0 &&
  416. parse_ul(q, &ul))
  417. msginfo_buf.date_n=ul;
  418. else if (strcmp(p, "SIZEN") == 0 &&
  419. parse_ul(q, &ul))
  420. msginfo_buf.size_n=ul;
  421. else if (strcmp(p, "TIME") == 0 &&
  422. parse_ul(q, &ul))
  423. msginfo_buf.mi_mtime=ul;
  424. else if (strcmp(p, "INODE") == 0 &&
  425. parse_ul(q, &ul))
  426. msginfo_buf.mi_ino=ul;
  427. }
  428. return (&msginfo_buf);
  429. }
  430. static MSGINFO *get_msginfo_alloc(unsigned long n)
  431. {
  432. MSGINFO *msginfop=get_msginfo(n);
  433. MSGINFO *p;
  434. if (!msginfop) return (0);
  435. if ((p= (MSGINFO *) malloc(sizeof(*p))) == 0)
  436. enomem();
  437. memset(p, 0, sizeof(*p));
  438. if ((p->filename=strdup(msginfop->filename)) == 0 ||
  439. (p->date_s=strdup(msginfop->date_s)) == 0 ||
  440. (p->from_s=strdup(msginfop->from_s)) == 0 ||
  441. (p->subject_s=strdup(msginfop->subject_s)) == 0 ||
  442. (p->size_s=strdup(msginfop->size_s)) == 0)
  443. enomem();
  444. p->date_n=msginfop->date_n;
  445. p->size_n=msginfop->size_n;
  446. p->mi_mtime=msginfop->mi_mtime;
  447. p->mi_ino=msginfop->mi_ino;
  448. return (p);
  449. }
  450. static void put_msginfo(MSGINFO *m, unsigned long n)
  451. {
  452. char namebuf[MAXLONGSIZE+40];
  453. char *rec;
  454. sprintf(namebuf, "REC%lu", n);
  455. rec=malloc(strlen(m->filename)+strlen(m->from_s)+
  456. strlen(m->date_s)+
  457. strlen(m->subject_s)+strlen(m->size_s)+MAXLONGSIZE*4+
  458. sizeof("FILENAME=nDATES=nFROM=nSUBJECT=nSIZES=nDATE=n"
  459. "SIZEN=nTIME=nINODE=n")+100);
  460. if (!rec) enomem();
  461. sprintf(rec, "FILENAME=%snDATES=%snFROM=%snSUBJECT=%snSIZES=%sn"
  462. "DATE=%lun"
  463. "SIZEN=%lun"
  464. "TIME=%lun"
  465. "INODE=%lun",
  466. m->filename,
  467. m->date_s,
  468. m->from_s,
  469. m->subject_s,
  470. m->size_s,
  471. (unsigned long)m->date_n,
  472. (unsigned long)m->size_n,
  473. (unsigned long)m->mi_mtime,
  474. (unsigned long)m->mi_ino);
  475. if (dbobj_store(&folderdat, namebuf, strlen(namebuf),
  476. rec, strlen(rec), "R"))
  477. enomem();
  478. free(rec);
  479. }
  480. static void update_foldermsgs(const char *folder, const char *newname, size_t pos)
  481. {
  482. MSGINFO *p;
  483. char *n;
  484. n=strrchr(newname, '/')+1;
  485. if (opencache(folder, "W") || (p=get_msginfo(pos)) == 0)
  486. {
  487. error("Internal error in update_foldermsgs");
  488. return;
  489. }
  490. p->filename=n;
  491. put_msginfo(p, pos);
  492. }
  493. static void maildir_markflag(const char *folder, size_t pos, char flag)
  494. {
  495. MSGINFO *p;
  496. char *filename;
  497. char *new_filename;
  498. if (opencache(folder, "W") || (p=get_msginfo(pos)) == 0)
  499. {
  500. error("Internal error in maildir_markflag");
  501. return;
  502. }
  503. filename=maildir_find(folder, p->filename);
  504. if (!filename) return;
  505. if ((new_filename=maildir_addflagfilename(filename, flag)) != 0)
  506. {
  507. rename(filename, new_filename);
  508. update_foldermsgs(folder, new_filename, pos);
  509. free(new_filename);
  510. }
  511. free(filename);
  512. }
  513. void maildir_markread(const char *folder, size_t pos)
  514. {
  515. maildir_markflag(folder, pos, 'S');
  516. }
  517. void maildir_markreplied(const char *folder, const char *message)
  518. {
  519. char *filename;
  520. char *new_filename;
  521. filename=maildir_find(folder, message);
  522. if (filename &&
  523. (new_filename=maildir_addflagfilename(filename, 'R')) != 0)
  524. {
  525. rename(filename, new_filename);
  526. free(new_filename);
  527. }
  528. if (filename) free(filename);
  529. }
  530. char *maildir_posfind(const char *folder, size_t *pos)
  531. {
  532. MSGINFO *p;
  533. char *filename;
  534. if (opencache(folder, "R") || (p=get_msginfo( *pos)) == 0)
  535. {
  536. error("Internal error in maildir_posfind");
  537. return (0);
  538. }
  539. filename=maildir_find(folder, p->filename);
  540. return(filename);
  541. }
  542. void maildir_msgpurge(const char *folder, size_t pos)
  543. {
  544. char *filename=maildir_posfind(folder, &pos);
  545. if (filename)
  546. {
  547. unlink(filename);
  548. free(filename);
  549. }
  550. }
  551. void maildir_msgpurgefile(const char *folder, const char *msgid)
  552. {
  553. char *filename=maildir_find(folder, msgid);
  554. if (filename)
  555. {
  556. unlink(filename);
  557. free(filename);
  558. }
  559. }
  560. /*
  561. ** A message is moved to a different folder as follows.
  562. ** The message is linked to the destination folder, then marked with a 'T'
  563. ** flag in the original folder.  Later, all T-marked messages are deleted.
  564. */
  565. static int msgcopy(int fromfd, int tofd)
  566. /* ... Except moving to/from sharable folder actually
  567. ** involves copying.
  568. */
  569. {
  570. char buf[8192];
  571. int i, j;
  572. char *p;
  573. while ((i=read(fromfd, buf, sizeof(buf))) > 0)
  574. {
  575. p=buf;
  576. while (i)
  577. {
  578. j=write(tofd, p, i);
  579. if (j <= 0) return (-1);
  580. p += j;
  581. i -= j;
  582. }
  583. }
  584. return (i);
  585. }
  586. static int do_msgmove(const char *from,
  587. const char *file, const char *dest, size_t pos)
  588. {
  589. char *destdir;
  590. const char *p;
  591. char *basename;
  592. char *newname;
  593. char *tmpname;
  594. struct stat stat_buf;
  595. char *new_filename;
  596. char quotabuf[QUOTABUFSIZE];
  597. int quotafd;
  598. unsigned long filesize=0;
  599. int no_link=0;
  600. quotafd= -1;
  601. if (maildir_getquota(".", quotabuf))
  602. {
  603. if (errno != ENOENT) enomem();
  604. quotabuf[0]=0;
  605. }
  606. if (stat(file, &stat_buf) || stat_buf.st_nlink != 1)
  607. return (0); /* Already moved */
  608. /* Update quota */
  609. if (quotabuf[0] && strcmp(from, dest))
  610. {
  611. if (maildir_parsequota(file, &filesize))
  612. filesize=stat_buf.st_size;
  613. /* Recover from possible corruption */
  614. if (strcmp(dest, TRASH) == 0) /* Moving to trash */
  615. {
  616. int rc;
  617. if (*from != ':')
  618. {
  619. do
  620. {
  621. rc=maildir_checkquota(".", &quotafd,
  622. quotabuf, -filesize, -1);
  623. if (rc && errno != EAGAIN)
  624. {
  625. if (quotafd >= 0)
  626. close(quotafd);
  627. enomem();
  628. }
  629. } while (rc);
  630. maildir_addquota(".", quotafd, quotabuf,
  631. -filesize, -1);
  632. }
  633. if (quotafd >= 0) close(quotafd);
  634. }
  635. else /* Moving FROM trash */
  636. {
  637. int rc;
  638. if (*from != ':')
  639. {
  640. do
  641. {
  642. rc=maildir_checkquota(".", &quotafd,
  643. quotabuf, filesize, 1);
  644. if (rc && errno != EAGAIN)
  645. {
  646. if (quotafd >= 0)
  647. close(quotafd);
  648. enomem();
  649. }
  650. } while (rc);
  651. maildir_addquota(".", quotafd, quotabuf,
  652. filesize, 1);
  653. }
  654. if (quotafd >= 0) close(quotafd);
  655. }
  656. }
  657. destdir=xlate_shmdir(dest);
  658. if (!destdir) enomem();
  659. if (*dest == ':' || *from == ':')
  660. {
  661. int fromfd, tofd;
  662. char *l;
  663. if (*dest == ':') /* Copy to the sharable folder */
  664. {
  665. char *p=malloc(strlen(destdir)+sizeof("/shared"));
  666. if (!p)
  667. {
  668. free(destdir);
  669. enomem();
  670. }
  671. strcat(strcpy(p, destdir), "/shared");
  672. free(destdir);
  673. destdir=p;
  674. }
  675. for (;;)
  676. {
  677. int rc=maildir_try_create(destdir, "copy", 0, &tmpname,
  678. &newname);
  679. if (rc < 0)
  680. {
  681. free(destdir);
  682. error("Can't create new file.");
  683. }
  684. if (rc == 0)
  685. break;
  686. sleep(5);
  687. }
  688. if (*dest == ':')
  689. /* We need to copy it directly into /cur of the dest folder */
  690. {
  691. memcpy(strrchr(newname, '/')-3, "cur", 3);
  692. /* HACK!!!!!!!!!!!! */
  693. }
  694. if ((fromfd=maildir_semisafeopen(file, O_RDONLY, 0)) < 0)
  695. {
  696. free(destdir);
  697. free(tmpname);
  698. free(newname);
  699. enomem();
  700. }
  701. if ( *dest == ':' )
  702. umask (0022);
  703. if ((tofd=maildir_safeopen(tmpname, O_RDWR|O_CREAT|O_EXCL,
  704. 0644)) < 0)
  705. {
  706. umask (0077);
  707. close(fromfd);
  708. free(destdir);
  709. free(tmpname);
  710. free(newname);
  711. return (-1);
  712. }
  713. umask (0077);
  714. if (msgcopy(fromfd, tofd))
  715. {
  716. close(fromfd);
  717. close(tofd);
  718. free(destdir);
  719. free(tmpname);
  720. free(newname);
  721. enomem();
  722. }
  723. close(fromfd);
  724. close(tofd);
  725. /*
  726. ** When we attempt to DELETE a message in the sharable folder,
  727. ** attempt to remove the UNDERLYING message
  728. */
  729. if (*from == ':' && (l=maildir_getlink(file)) != 0)
  730. {
  731. if (unlink(l))
  732. {
  733. /* Not our message */
  734. free(l);
  735. if (strcmp(dest, TRASH) == 0)
  736. {
  737. unlink(tmpname);
  738. free(destdir);
  739. free(tmpname);
  740. free(newname);
  741. return (0);
  742. }
  743. }
  744. free(l);
  745. }
  746. if (rename(tmpname, newname))
  747. {
  748. free(destdir);
  749. free(tmpname);
  750. free(newname);
  751. enomem();
  752. }
  753. no_link=1; /* Don't call link(), below */
  754. free(tmpname);
  755. free(newname);
  756. }
  757. p=strrchr(file, '/');
  758. if (p) ++p;
  759. else p=file;
  760. if ( (basename=strdup(p)) == NULL)
  761. enomem();
  762. maildir_remflagname(basename, 'T'); /* Remove any deleted flag for new name */
  763. newname=alloc_filename(destdir, "cur", basename);
  764. free(destdir);
  765. free(basename);
  766. /* When DELETE is called for a message in TRASH, from and dest will
  767. ** be the same, so we just mark the file as Trashed, to be removed
  768. ** in checknew.
  769. */
  770. if (no_link == 0 && strcmp(from, dest))
  771. link(file, newname);
  772. free(newname);
  773. if ((new_filename=maildir_addflagfilename(file, 'T')) != 0)
  774. {
  775. rename(file, new_filename);
  776. update_foldermsgs(from, new_filename, pos);
  777. free(new_filename);
  778. }
  779. return (0);
  780. }
  781. int maildir_msgmove(const char *folder, size_t pos, const char *dest)
  782. {
  783. char *filename=maildir_posfind(folder, &pos);
  784. int rc;
  785. if (!filename) return (0);
  786. rc=do_msgmove(folder, filename, dest, pos);
  787. free(filename);
  788. return (rc);
  789. }
  790. void maildir_msgdeletefile(const char *folder, const char *file, size_t pos)
  791. {
  792. char *filename=maildir_find(folder, file);
  793. if (filename)
  794. {
  795. (void)do_msgmove(folder, filename, TRASH, pos);
  796. free(filename);
  797. }
  798. }
  799. int maildir_msgmovefile(const char *folder, const char *file, const char *dest,
  800. size_t pos)
  801. {
  802. char *filename=maildir_find(folder, file);
  803. int rc;
  804. if (!filename) return (0);
  805. rc=do_msgmove(folder, filename, dest, pos);
  806. free(filename);
  807. return (rc);
  808. }
  809. /*
  810. ** Grab new messages from new.
  811. */
  812. static void maildir_checknew(const char *dir)
  813. {
  814. char *dirbuf;
  815. struct stat stat_buf;
  816. DIR *dirp;
  817. struct dirent *dire;
  818. time_t cntmtime;
  819. /* Delete old files in tmp */
  820. maildir_purgetmp(dir);
  821. /* Move everything from new to cur */
  822. dirbuf=alloc_filename(dir, "new", "");
  823. for (dirp=opendir(dirbuf); dirp && (dire=readdir(dirp)) != 0; )
  824. {
  825. char *oldname, *newname;
  826. char *p;
  827. if (dire->d_name[0] == '.') continue;
  828. oldname=alloc_filename(dirbuf, dire->d_name, "");
  829. newname=malloc(strlen(oldname)+4);
  830. if (!newname) enomem();
  831. strcat(strcat(strcpy(newname, dir), "/cur/"), dire->d_name);
  832. p=strrchr(newname, '/');
  833. if ((p=strchr(p, ':')) != NULL) *p=0; /* Someone screwed up */
  834. strcat(newname, ":2,");
  835. rename(oldname, newname);
  836. free(oldname);
  837. free(newname);
  838. }
  839. if (dirp) closedir(dirp);
  840. free(dirbuf);
  841. /* Look for any messages mark as deleted.  When we delete a message
  842. ** we link it into the Trash folder, and mark the original with a T,
  843. ** which we delete when we check for new messages.
  844. */
  845. dirbuf=alloc_filename(dir, "cur", "");
  846. if (stat(dirbuf, &stat_buf))
  847. {
  848. free(dirbuf);
  849. return;
  850. }
  851. /* If the count cache file is still current, the directory hasn't
  852. ** changed, so we don't need to scan it for deleted messages.  When
  853. ** a message is deleted, the rename bumps up the timestamp.
  854. **
  855. ** This depends on dodirscan() being called after this function,
  856. ** which updates MAILDIRCOUNTCACHE
  857. */
  858. if (read_sqconfig(dir, MAILDIRCOUNTCACHE, &cntmtime) != 0 &&
  859. cntmtime > stat_buf.st_mtime)
  860. {
  861. free(dirbuf);
  862. return;
  863. }
  864. for (dirp=opendir(dirbuf); dirp && (dire=readdir(dirp)) != 0; )
  865. {
  866. char *p;
  867. if (dire->d_name[0] == '.') continue;
  868. if (maildirfile_type(dire->d_name) == MSGTYPE_DELETED)
  869. {
  870. p=alloc_filename(dirbuf, "", dire->d_name);
  871. maildir_unlinksharedmsg(p);
  872. /* Does The Right Thing if this is a shared
  873. ** folder
  874. */
  875. free(p);
  876. }
  877. }
  878. if (dirp) closedir(dirp);
  879. free(dirbuf);
  880. }
  881. /*
  882. ** Automatically purge deleted messages.
  883. */
  884. void maildir_autopurge()
  885. {
  886. char *dir;
  887. char *dirbuf;
  888. struct stat stat_buf;
  889. DIR *dirp;
  890. struct dirent *dire;
  891. char *filename;
  892. /* This is called when logging in.  Version 0.18 supports maildir
  893. ** quotas, so automatically upgrade all folders.
  894. */
  895. for (dirp=opendir("."); dirp && (dire=readdir(dirp)) != 0; )
  896. {
  897. if (dire->d_name[0] != '.') continue;
  898. if (strcmp(dire->d_name, ".") == 0 ||
  899. strcmp(dire->d_name, "..") == 0) continue;
  900. filename=alloc_filename(dire->d_name, "maildirfolder", "");
  901. if (!filename) enomem();
  902. close(open(filename, O_RDWR|O_CREAT, 0644));
  903. free(filename);
  904. /* Eliminate plain text cache starting with version 0.24 */
  905. filename=alloc_filename(dire->d_name, MAILDIRCURCACHE, "");
  906. if (!filename) enomem();
  907. unlink(filename);
  908. free(filename);
  909. }
  910. /* Version 0.24 top level remove */
  911. unlink(MAILDIRCURCACHE);
  912. if (dirp)
  913. closedir(dirp);
  914. dir=xlate_mdir(TRASH);
  915. /* Delete old files in tmp */
  916. time(&current_time);
  917. dirbuf=alloc_filename(dir, "cur", "");
  918. free(dir);
  919. for (dirp=opendir(dirbuf); dirp && (dire=readdir(dirp)) != 0; )
  920. {
  921. if (dire->d_name[0] == '.') continue;
  922. filename=alloc_filename(dirbuf, dire->d_name, "");
  923. if (stat(filename, &stat_buf) == 0 &&
  924. stat_buf.st_ctime < current_time
  925. - pref_autopurge * 24 * 60 * 60)
  926. {
  927. unlink(filename);
  928. }
  929. free(filename);
  930. }
  931. if (dirp) closedir(dirp);
  932. free(dirbuf);
  933. }
  934. static int subjectcmp(const char *a, const char *b)
  935. {
  936. int aisre;
  937. int bisre;
  938. int n;
  939. a=dropre(a, &aisre);
  940. b=dropre(b, &bisre);
  941. n=strcasecmp(a,b);
  942. if (n == 0) n=aisre - bisre;
  943. return (n);
  944. }
  945. /*
  946. ** Messages supposed to be arranged in the reverse chronological order of
  947. ** arrival.
  948. **
  949. ** Instead of stat()ing every file in the directory, we depend on the
  950. ** naming convention that are specified for the Maildir.  Therefore, we rely
  951. ** on Maildir writers observing the required naming conventions.
  952. */
  953. static int messagecmp(const MSGINFO **pa, const MSGINFO **pb)
  954. {
  955. int gt=1, lt=-1;
  956. int n;
  957. const MSGINFO *a= *pa;
  958. const MSGINFO *b= *pb;
  959. if (pref_flagisoldest1st)
  960. {
  961. gt= -1;
  962. lt= 1;
  963. }
  964. switch (pref_flagsortorder) {
  965. case 'F':
  966. n=strcasecmp(a->from_s, b->from_s);
  967. if (n) return (n);
  968. break;
  969. case 'S':
  970. n=subjectcmp(a->subject_s, b->subject_s);
  971. if (n) return (n);
  972. break;
  973. }
  974. if (a->date_n < b->date_n) return (gt);
  975. if (a->date_n > b->date_n) return (lt);
  976. if (a->mi_ino < b->mi_ino) return (gt);
  977. if (a->mi_ino > b->mi_ino) return (lt);
  978. return (0);
  979. }
  980. /*
  981. ** maildirfile_type(directory, filename) - return one of the following:
  982. **
  983. **   MSGTYPE_NEW - new message
  984. **   MSGTYPE_DELETED - trashed message
  985. **   '' - all other kinds
  986. */
  987. char maildirfile_type(const char *p)
  988. {
  989. const char *q=strrchr(p, '/');
  990. int seen_trash=0, seen_r=0, seen_s=0;
  991. if (q) p=q;
  992. if ( !(p=strchr(p, ':')) || *++p != '2' || *++p != ',')
  993. return (MSGTYPE_NEW); /* No :2,info */
  994. ;
  995. ++p;
  996. while (p && isalpha((int)(unsigned char)*p))
  997. switch (*p++) {
  998. case 'T':
  999. seen_trash=1;
  1000. break;
  1001. case 'R':
  1002. seen_r=1;
  1003. break;
  1004. case 'S':
  1005. seen_s=1;
  1006. break;
  1007. }
  1008. if (seen_trash)
  1009. return (MSGTYPE_DELETED); /* Trashed message */
  1010. if (seen_s)
  1011. {
  1012. if (seen_r) return (MSGTYPE_REPLIED);
  1013. return (0);
  1014. }
  1015. return (MSGTYPE_NEW);
  1016. }
  1017. static int docount(const char *fn, unsigned *new_cnt, unsigned *other_cnt)
  1018. {
  1019. const char *filename=strrchr(fn, '/');
  1020. char c;
  1021. if (filename) ++filename;
  1022. else filename=fn;
  1023. if (*filename == '.') return (0); /* We don't want this one */
  1024. c=maildirfile_type(filename);
  1025. if (c == MSGTYPE_NEW)
  1026. ++ *new_cnt;
  1027. else
  1028. ++ *other_cnt;
  1029. return (1);
  1030. }
  1031. MSGINFO **maildir_read(const char *dirname, unsigned nfiles,
  1032. size_t *starting_pos,
  1033. int *morebefore, int *moreafter)
  1034. {
  1035. MSGINFO **msginfo;
  1036. size_t i;
  1037. if ((msginfo=malloc(sizeof(MSGINFO *)*nfiles)) == 0)
  1038. enomem();
  1039. for (i=0; i<nfiles; i++)
  1040. msginfo[i]=0;
  1041. if (opencache(dirname, "W")) return (msginfo);
  1042. if (nfiles > all_cnt) nfiles=all_cnt;
  1043. if (*starting_pos + nfiles > all_cnt)
  1044. *starting_pos=all_cnt-nfiles;
  1045. *morebefore = *starting_pos > 0;
  1046. for (i=0; i<nfiles; i++)
  1047. {
  1048. if (*starting_pos + i >= all_cnt) break;
  1049. if ((msginfo[i]= get_msginfo_alloc(*starting_pos + i)) == 0)
  1050. break;
  1051. }
  1052. *moreafter= *starting_pos + i < all_cnt;
  1053. return (msginfo);
  1054. }
  1055. static void dodirscan(const char *, unsigned *, unsigned *);
  1056. void maildir_count(const char *folder,
  1057. unsigned *new_ptr,
  1058. unsigned *other_ptr)
  1059. {
  1060. char *dir=xlate_shmdir(folder);
  1061. *new_ptr=0;
  1062. *other_ptr=0;
  1063. if (dir)
  1064. {
  1065. if (*folder == ':')
  1066. {
  1067. maildir_shared_sync(dir);
  1068. }
  1069. maildir_checknew(dir);
  1070. dodirscan(dir, new_ptr, other_ptr);
  1071. }
  1072. free(dir);
  1073. }
  1074. unsigned maildir_countof(const char *folder)
  1075. {
  1076. maildir_getfoldermsgs(folder);
  1077. return (all_cnt);
  1078. }
  1079. static void dodirscan(const char *dir, unsigned *new_cnt,
  1080. unsigned *other_cnt)
  1081. {
  1082. DIR *dirp;
  1083. struct dirent *de;
  1084. char *curname;
  1085. struct stat cur_stat;
  1086. time_t cntmtime;
  1087. const char *p;
  1088. char cntbuf[MAXLONGSIZE*2+4];
  1089. curname=alloc_filename(dir, "cur", "");
  1090. if (stat(curname, &cur_stat))
  1091. {
  1092. free(curname);
  1093. return;
  1094. }
  1095. if ((p=read_sqconfig(dir, MAILDIRCOUNTCACHE, &cntmtime)) != 0 &&
  1096. cntmtime > cur_stat.st_mtime)
  1097. {
  1098. unsigned long n;
  1099. unsigned long o;
  1100. if ((p=parse_ul(p, &n)) && (p=parse_ul(p, &o)))
  1101. {
  1102. *new_cnt=n;
  1103. *other_cnt=o;
  1104. free(curname);
  1105. return; /* Valid cache of count */
  1106. }
  1107. }
  1108. *new_cnt=0;
  1109. *other_cnt=0;
  1110. dirp=opendir(curname);
  1111. while (dirp && (de=readdir(dirp)) != NULL)
  1112. docount(de->d_name, new_cnt, other_cnt);
  1113. if (dirp) closedir(dirp);
  1114. sprintf(cntbuf, "%u %u", *new_cnt, *other_cnt);
  1115. write_sqconfig(dir, MAILDIRCOUNTCACHE, cntbuf);
  1116. if ( read_sqconfig(dir, MAILDIRCOUNTCACHE, &cntmtime) == 0)
  1117. enomem();
  1118. if (cntmtime == cur_stat.st_mtime) /* Potential race condition */
  1119. {
  1120. free(curname);
  1121. curname=alloc_filename(dir, MAILDIRCOUNTCACHE, "");
  1122. change_timestamp(curname, cntmtime-1);
  1123. /* ... So rebuild it next time */
  1124. }
  1125. free(curname);
  1126. }
  1127. void maildir_free(MSGINFO **files, unsigned nfiles)
  1128. {
  1129. unsigned i;
  1130. for (i=0; i<nfiles; i++)
  1131. {
  1132. if ( files[i] )
  1133. maildir_nfreeinfo( files[i] );
  1134. }
  1135. free(files);
  1136. }
  1137. static char *buf=0;
  1138. size_t bufsize=0, buflen=0;
  1139. static void addbuf(int c)
  1140. {
  1141. if (buflen == bufsize)
  1142. {
  1143. char *newbuf= buf ? realloc(buf, bufsize+512):malloc(bufsize+512);
  1144. if (!newbuf) enomem();
  1145. buf=newbuf;
  1146. bufsize += 512;
  1147. }
  1148. buf[buflen++]=c;
  1149. }
  1150. char *maildir_readline(FILE *fp)
  1151. {
  1152. int c;
  1153. buflen=0;
  1154. while ((c=getc(fp)) != 'n' && c >= 0)
  1155. if (buflen < 8192)
  1156. addbuf(c);
  1157. if (c < 0 && buflen == 0) return (NULL);
  1158. addbuf(0);
  1159. return (buf);
  1160. }
  1161. char *maildir_readheader_mimepart(FILE *fp, char **value, int preserve_nl,
  1162. off_t *mimepos, const off_t *endpos)
  1163. {
  1164. int c;
  1165. buflen=0;
  1166. if (mimepos && *mimepos >= *endpos) return (0);
  1167. while (mimepos == 0 || *mimepos < *endpos)
  1168. {
  1169. if ((c=getc(fp)) != 'n' && c >= 0)
  1170. {
  1171. addbuf(c);
  1172. if (mimepos) ++ *mimepos;
  1173. continue;
  1174. }
  1175. if ( c == 'n' && mimepos) ++ *mimepos;
  1176. if (buflen == 0) return (0);
  1177. if (c < 0) break;
  1178. c=getc(fp);
  1179. if (c >= 0) ungetc(c, fp);
  1180. if (c == 'n' || !isspace(c)) break;
  1181. addbuf(preserve_nl ? 'n':' ');
  1182. }
  1183. addbuf(0);
  1184. for ( *value=buf; **value; (*value)++)
  1185. {
  1186. if (**value == ':')
  1187. {
  1188. **value='';
  1189. ++*value;
  1190. break;
  1191. }
  1192. **value=tolower(**value);
  1193. }
  1194. while (**value && isspace((int)(unsigned char)**value)) ++*value;
  1195. return(buf);
  1196. }
  1197. char *maildir_readheader(FILE *fp, char **value, int preserve_nl)
  1198. {
  1199. return (maildir_readheader_mimepart(fp, value, preserve_nl, 0, 0));
  1200. }
  1201. /*****************************************************************************
  1202. The MSGINFO structure contains the summary of the headers found in all
  1203. messages in the cur directory.
  1204. Instead of opening each message every time we need to serve the directory
  1205. contents, the messages are scanned once, and a cache file is built
  1206. containing the contents.
  1207. *****************************************************************************/
  1208. /* Deallocate an individual MSGINFO structure */
  1209. void maildir_nfreeinfo(MSGINFO *mi)
  1210. {
  1211. if (mi->filename) free(mi->filename);
  1212. if (mi->date_s) free(mi->date_s);
  1213. if (mi->from_s) free(mi->from_s);
  1214. if (mi->subject_s) free(mi->subject_s);
  1215. if (mi->size_s) free(mi->size_s);
  1216. free(mi);
  1217. }
  1218. /* Initialize a MSGINFO structure by reading the message headers */
  1219. MSGINFO *maildir_ngetinfo(const char *filename)
  1220. {
  1221. FILE *fp;
  1222. MSGINFO *mi;
  1223. struct stat stat_buf;
  1224. char *hdr, *val;
  1225. const char *p;
  1226. int is_sent_header=0;
  1227. char *fromheader=0;
  1228. int fd;
  1229. /* Hack - see if we're reading a message from the Sent or Drafts
  1230. folder */
  1231. p=strrchr(filename, '/');
  1232. if ((p && p - filename >=
  1233. sizeof(SENT) + 5 && strncmp(p - (sizeof(SENT) + 5),
  1234. "/." SENT "/", sizeof(SENT)+2) == 0)
  1235. || strncmp(filename, "." SENT "/", sizeof(SENT)+1) == 0)
  1236. is_sent_header=1;
  1237. if ((p && p - filename >=
  1238. sizeof(DRAFTS) + 5 && strncmp(p-(sizeof(DRAFTS) + 5),
  1239. "/." DRAFTS "/", sizeof(DRAFTS)+2) == 0)
  1240. || strncmp(filename, "." DRAFTS "/", sizeof(DRAFTS)+1) == 0)
  1241. is_sent_header=1;
  1242. if ((mi=(MSGINFO *)malloc(sizeof(MSGINFO))) == 0)
  1243. enomem();
  1244. memset(mi, '', sizeof(*mi));
  1245. fp=0;
  1246. fd=maildir_semisafeopen(filename, O_RDONLY, 0);
  1247. if (fd >= 0)
  1248. if ((fp=fdopen(fd, "r")) == 0)
  1249. close(fd);
  1250. if (fp == NULL)
  1251. {
  1252. free(mi);
  1253. return (NULL);
  1254. }
  1255. /* mi->filename shall be the base filename, normalized as :2, */
  1256. if ((p=strrchr(filename, '/')) != NULL)
  1257. p++;
  1258. else p=filename;
  1259. if (!(mi->filename=strdup(p)))
  1260. enomem();
  1261. if (fstat(fileno(fp), &stat_buf) == 0)
  1262. {
  1263. mi->mi_mtime=stat_buf.st_mtime;
  1264. mi->mi_ino=stat_buf.st_ino;
  1265. mi->size_n=stat_buf.st_size;
  1266. mi->size_s=strdup( showsize(stat_buf.st_size));
  1267. mi->date_n=mi->mi_mtime; /* Default if no Date: */
  1268. if (!mi->size_s) enomem();
  1269. }
  1270. else
  1271. {
  1272. free(mi->filename);
  1273. fclose(fp);
  1274. free(mi);
  1275. return (0);
  1276. }
  1277. while ((hdr=maildir_readheader(fp, &val, 0)) != 0)
  1278. {
  1279. if (strcmp(hdr, "subject") == 0)
  1280. {
  1281. if (mi->subject_s) free(mi->subject_s);
  1282. mi->subject_s=strdup(val);
  1283. if (!mi->subject_s) enomem();
  1284. }
  1285. if (strcmp(hdr, "date") == 0 && mi->date_s == 0)
  1286. {
  1287. time_t t=rfc822_parsedt(val);
  1288. if (t)
  1289. {
  1290. mi->date_n=t;
  1291. mi->date_s=strdup(displaydate(mi->date_n));
  1292. if (!mi->date_s) enomem();
  1293. }
  1294. }
  1295. if ((is_sent_header ?
  1296. strcmp(hdr, "to") == 0 || strcmp(hdr, "cc") == 0:
  1297. strcmp(hdr, "from") == 0) && fromheader == 0)
  1298. {
  1299. struct rfc822t *from_addr;
  1300. struct rfc822a *from_addra;
  1301. char *p;
  1302. int dotflag=0;
  1303. from_addr=rfc822t_alloc(val, NULL);
  1304. if (!from_addr) enomem();
  1305. from_addra=rfc822a_alloc(from_addr);
  1306. if (!from_addra) enomem();
  1307. if (from_addra->naddrs > 1)
  1308. dotflag=1;
  1309. if (from_addra->naddrs > 0)
  1310. p=rfc822_getname(from_addra, 0);
  1311. else
  1312. p=val;
  1313. if (fromheader) free(fromheader);
  1314. if ((fromheader=malloc(strlen(p)+7)) == 0)
  1315. enomem();
  1316. strcpy(fromheader, p);
  1317. if (dotflag)
  1318. strcat(fromheader, "...");
  1319. rfc822a_free(from_addra);
  1320. rfc822t_free(from_addr);
  1321. }
  1322. if (mi->date_s && fromheader && mi->subject_s)
  1323. break;
  1324. }
  1325. fclose(fp);
  1326. mi->from_s=fromheader;
  1327. if (!mi->date_s)
  1328. mi->date_s=strdup(displaydate(mi->date_n));
  1329. if (!mi->date_s) enomem();
  1330. if (!mi->from_s && !(mi->from_s=strdup(""))) enomem();
  1331. if (!mi->subject_s && !(mi->subject_s=strdup(""))) enomem();
  1332. return (mi);
  1333. }
  1334. /************************************************************************/
  1335. /* Save cache file */
  1336. static unsigned long save_cnt, savenew_cnt;
  1337. static time_t save_time;
  1338. static char *save_dbname;
  1339. static char *save_tmpdbname;
  1340. struct dbobj tmpdb;
  1341. static void maildir_save_start(const char *maildir, time_t t)
  1342. {
  1343. char *tptr, *nptr;
  1344. save_dbname=alloc_filename(maildir, "", MAILDIRCURCACHE "." DBNAME);
  1345. save_time=t;
  1346. for (;;)
  1347. {
  1348. int rc=maildir_try_create(maildir, "db", 0, &tptr, &nptr);
  1349. if (rc < 0)
  1350. error("Can't create cache file.");
  1351. if (rc == 0)
  1352. {
  1353. save_tmpdbname=tptr;
  1354. free(nptr);
  1355. break;
  1356. }
  1357. sleep(5);
  1358. }
  1359. dbobj_init(&tmpdb);
  1360. if (dbobj_open(&tmpdb, save_tmpdbname, "N"))
  1361. error("Can't create cache file.");
  1362. save_cnt=0;
  1363. savenew_cnt=0;
  1364. }
  1365. static void maildir_saveinfo(MSGINFO *m)
  1366. {
  1367. char *rec;
  1368. char recnamebuf[MAXLONGSIZE+40];
  1369. rec=malloc(strlen(m->filename)+strlen(m->from_s)+
  1370. strlen(m->date_s)+
  1371. strlen(m->subject_s)+strlen(m->size_s)+MAXLONGSIZE*4+
  1372. sizeof("FILENAME=nDATES=nFROM=nSUBJECT=nSIZES=nDATE=n"
  1373. "SIZEN=nTIME=nINODE=n")+100);
  1374. if (!rec) enomem();
  1375. sprintf(rec, "FILENAME=%snDATES=%snFROM=%snSUBJECT=%snSIZES=%sn"
  1376. "DATE=%lun"
  1377. "SIZEN=%lun"
  1378. "TIME=%lun"
  1379. "INODE=%lun",
  1380. m->filename,
  1381. m->date_s,
  1382. m->from_s,
  1383. m->subject_s,
  1384. m->size_s,
  1385. (unsigned long)m->date_n,
  1386. (unsigned long)m->size_n,
  1387. (unsigned long)m->mi_mtime,
  1388. (unsigned long)m->mi_ino);
  1389. sprintf(recnamebuf, "REC%lu", (unsigned long)save_cnt);
  1390. if (dbobj_store(&tmpdb, recnamebuf, strlen(recnamebuf),
  1391. rec, strlen(rec), "R"))
  1392. enomem();
  1393. free(rec);
  1394. save_cnt++;
  1395. if (maildirfile_type(m->filename) == MSGTYPE_NEW)
  1396. savenew_cnt++;
  1397. }
  1398. static void maildir_save_end(const char *maildir)
  1399. {
  1400. char *curname;
  1401. char *rec;
  1402. curname=alloc_filename(maildir, "", "cur");
  1403. rec=malloc(MAXLONGSIZE*4+sizeof(
  1404. "SAVETIME=n"
  1405. "COUNT=n"
  1406. "NEWCOUNT=n"
  1407. "SORT=n")+100);
  1408. if (!rec) enomem();
  1409. sprintf(rec,
  1410. "SAVETIME=%lunCOUNT=%lunNEWCOUNT=%lunSORT=%d%cn",
  1411. (unsigned long)save_time,
  1412. (unsigned long)save_cnt,
  1413. (unsigned long)savenew_cnt,
  1414. pref_flagisoldest1st,
  1415. pref_flagsortorder);
  1416. if (dbobj_store(&tmpdb, "HEADER", 6, rec, strlen(rec), "R"))
  1417. enomem();
  1418. dbobj_close(&tmpdb);
  1419. free(rec);
  1420. rename(save_tmpdbname, save_dbname);
  1421. unlink(save_tmpdbname);
  1422. #if 0
  1423. What the fuck was I thinking?
  1424. struct stat new_stat_buf;
  1425. struct stat dir_stat_buf;
  1426. if (!replace && (stat(save_cachename, &new_stat_buf)
  1427. || stat(curname, &dir_stat_buf)
  1428. )
  1429. )
  1430. {
  1431. unlink(save_cachename);
  1432. free(save_cachename);
  1433. free(save_tmpcachename);
  1434. free(curname);
  1435. return;
  1436. }
  1437. #endif
  1438. free(curname);
  1439. free(save_dbname);
  1440. free(save_tmpdbname);
  1441. }
  1442. void maildir_savefoldermsgs(const char *folder)
  1443. {
  1444. }
  1445. /************************************************************************/
  1446. struct MSGINFO_LIST {
  1447. struct MSGINFO_LIST *next;
  1448. MSGINFO *minfo;
  1449. } ;
  1450. static void createmdcache(const char *maildir)
  1451. {
  1452. char *curname;
  1453. DIR *dirp;
  1454. struct dirent *de;
  1455. struct MSGINFO_LIST *milist, *newmi;
  1456. MSGINFO *mi;
  1457. unsigned long cnt=0;
  1458. curname=alloc_filename(maildir, "", "cur");
  1459. time(&current_time);
  1460. maildir_save_start(maildir, current_time);
  1461. milist=0;
  1462. dirp=opendir(curname);
  1463. while (dirp && (de=readdir(dirp)) != NULL)
  1464. {
  1465. char *filename;
  1466. if (de->d_name[0] == '.')
  1467. continue;
  1468. filename=alloc_filename(curname, "", de->d_name);
  1469. mi=maildir_ngetinfo(filename);
  1470. free(filename);
  1471. if (!mi) continue;
  1472. if (!(newmi=malloc(sizeof(struct MSGINFO_LIST)))) enomem();
  1473. newmi->next= milist;
  1474. milist=newmi;
  1475. newmi->minfo=mi;
  1476. ++cnt;
  1477. }
  1478. if (dirp) closedir(dirp);
  1479. free(curname);
  1480. if (milist)
  1481. {
  1482. MSGINFO **miarray=malloc(sizeof(MSGINFO *) * cnt);
  1483. unsigned long i;
  1484. if (!miarray) enomem();
  1485. i=0;
  1486. while (milist)
  1487. {
  1488. miarray[i++]=milist->minfo;
  1489. newmi=milist;
  1490. milist=newmi->next;
  1491. free(newmi);
  1492. }
  1493. qsort(miarray, cnt, sizeof(*miarray),
  1494. ( int (*)(const void *, const void *)) messagecmp);
  1495. for (i=0; i<cnt; i++)
  1496. {
  1497. maildir_saveinfo(miarray[i]);
  1498. maildir_nfreeinfo(miarray[i]);
  1499. }
  1500. free(miarray);
  1501. }
  1502. maildir_save_end(maildir);
  1503. }
  1504. static int chkcache(const char *folder)
  1505. {
  1506. if (opencache(folder, "W")) return (-1);
  1507. if (isoldestfirst != pref_flagisoldest1st) return (-1);
  1508. if (sortorder != pref_flagsortorder) return (-1);
  1509. return (0);
  1510. }
  1511. static void maildir_getfoldermsgs(const char *folder)
  1512. {
  1513. char *dir=xlate_shmdir(folder);
  1514. if (!dir) return;
  1515. while ( chkcache(folder) )
  1516. {
  1517. closedb();
  1518. createmdcache(dir);
  1519. }
  1520. free(dir);
  1521. }
  1522. void maildir_remcache(const char *folder)
  1523. {
  1524. char *dir=xlate_shmdir(folder);
  1525. char *cachename=alloc_filename(dir, "", MAILDIRCURCACHE "." DBNAME);
  1526. unlink(cachename);
  1527. if (folderdatname && strcmp(folderdatname, cachename) == 0)
  1528. closedb();
  1529. free(cachename);
  1530. free(dir);
  1531. }
  1532. void maildir_reload(const char *folder)
  1533. {
  1534. char *dir=xlate_shmdir(folder);
  1535. char *curname;
  1536. struct stat stat_buf;
  1537. if (!dir) return;
  1538. curname=alloc_filename(dir, "cur", ".");
  1539. /* Remove old cache file when: */
  1540. if (opencache(folder, "W") == 0)
  1541. {
  1542. if ( stat(curname, &stat_buf) != 0 ||
  1543. stat_buf.st_mtime >= cachemtime)
  1544. {
  1545. closedb();
  1546. createmdcache(dir);
  1547. }
  1548. }
  1549. free(dir);
  1550. maildir_getfoldermsgs(folder);
  1551. free(curname);
  1552. }
  1553. /*
  1554. maildir_readfolders(char ***) - read all the folders in the mailbox.
  1555. maildir_freefolders(char ***) - deallocate memory
  1556. */
  1557. static void addfolder(const char *name, char ***buf, size_t *size, size_t *cnt)
  1558. {
  1559. if (*cnt >= *size)
  1560. {
  1561. char **newbuf= *buf ? realloc(*buf, (*size + 10) * sizeof(char *))
  1562. : malloc( (*size+10) * sizeof(char *));
  1563. if (!newbuf) enomem();
  1564. *buf=newbuf;
  1565. *size += 10;
  1566. }
  1567. (*buf)[*cnt]=0;
  1568. if ( name && ((*buf)[*cnt]=strdup(name)) == 0) enomem();
  1569. ++*cnt;
  1570. }
  1571. /*
  1572. **  Return a sorted list of folders.
  1573. **
  1574. **  Shared folders:
  1575. **
  1576. **  Shared folders are returned as ":maildirname.foldername".
  1577. **
  1578. **  : characters are not valid in regular folder names, so we use that
  1579. **  to mark shared folders, and they will be manually sorted after
  1580. **  regular folders.
  1581. **
  1582. **  HACK:
  1583. **
  1584. **  Subscribed folders will be listed as ":maildirname.last.0foldername".
  1585. **  Unsubscribed folders will be listed as ":mailfirname.last.1foldername".
  1586. **  So the unsubscribed folders will be sorted after the subscribed ones.
  1587. **
  1588. **  Then, after sorting, remove the 0 or 1 extra character.
  1589. */
  1590. static int mdcomparefunc( char **a, char **b)
  1591. {
  1592. char *ca= *a, *cb= *b;
  1593. if (*ca == ':' && *cb != ':') return (1);
  1594. if (*ca != ':' && *cb == ':') return (-1);
  1595. return (strcasecmp(ca, cb));
  1596. }
  1597. struct add_shared_info {
  1598. char ***p;
  1599. size_t *s;
  1600. size_t *c;
  1601. } ;
  1602. static char *append_suffix(const char *n)
  1603. {
  1604. char *name;
  1605. const char *q=strrchr(n, '.');
  1606. if (!q) return (0); /* ??? */
  1607. ++q;
  1608. name=malloc(strlen(n)+sizeof(":0"));
  1609. if (!name) return (0);
  1610. *name=':';
  1611. memcpy(name+1, n, q-n);
  1612. strcpy( &name[q-n+1], "0");
  1613. strcat(name, q);
  1614. return (name);
  1615. }
  1616. static void add_shared(const char *n, void *p)
  1617. {
  1618. struct add_shared_info *i= (struct add_shared_info *)p;
  1619. char *s;
  1620. if (strchr(n, ':')) return;
  1621. s=append_suffix(n);
  1622. if (!s) return;
  1623. addfolder(s, i->p, i->s, i->c);
  1624. free(s);
  1625. }
  1626. static void add_sharable(const char *n, void *p)
  1627. {
  1628. struct add_shared_info *i= (struct add_shared_info *)p;
  1629. char *s;
  1630. char **c;
  1631. size_t j;
  1632. if (strchr(n, ':')) return;
  1633. /* Only add folders that haven't been subscribed to yet */
  1634. s=append_suffix(n);
  1635. if (!s) return;
  1636. c= *i->p;
  1637. for (j=0; j < *i->c; j++)
  1638. if (strcmp( (*i->p)[j], s) == 0)
  1639. {
  1640. free(s);
  1641. return;
  1642. }
  1643. strrchr(s, '.')[1] = '1';
  1644. addfolder(s, i->p, i->s, i->c);
  1645. free(s);
  1646. }
  1647. void maildir_readfolders(char ***fp)
  1648. {
  1649. size_t fbsize=0;
  1650. size_t fbcnt=0;
  1651. DIR *dirp;
  1652. struct dirent *dire;
  1653. struct stat stat_buf;
  1654. char *temp_buf;
  1655. size_t i;
  1656. *fp=0;
  1657. addfolder(INBOX, fp, &fbsize, &fbcnt);
  1658. dirp=opendir(".");
  1659. while ( dirp && (dire=readdir(dirp)) != 0)
  1660. {
  1661. if (dire->d_name[0] != '.' ||
  1662. strcmp(dire->d_name, ".") == 0 ||
  1663. strcmp(dire->d_name, "..") == 0 ||
  1664. strchr(dire->d_name, ':'))
  1665. continue;
  1666. if ((temp_buf=malloc(strlen(dire->d_name)+5)) == 0)
  1667. enomem();
  1668. if ( stat(
  1669. strcat(strcpy(temp_buf, dire->d_name), "/tmp"),
  1670. &stat_buf) != 0 ||
  1671. !S_ISDIR(stat_buf.st_mode) ||
  1672.      stat(
  1673. strcat(strcpy(temp_buf, dire->d_name), "/new"),
  1674. &stat_buf) != 0 ||
  1675. !S_ISDIR(stat_buf.st_mode) ||
  1676.      stat(
  1677. strcat(strcpy(temp_buf, dire->d_name), "/cur"),
  1678. &stat_buf) != 0 ||
  1679. !S_ISDIR(stat_buf.st_mode) )
  1680. {
  1681. free(temp_buf);
  1682. continue;
  1683. }
  1684. free(temp_buf);
  1685. addfolder(dire->d_name+1, fp, &fbsize, &fbcnt);
  1686. }
  1687. if (dirp) closedir(dirp);
  1688. {
  1689. struct add_shared_info info;
  1690. info.p=fp;
  1691. info.s= &fbsize;
  1692. info.c= &fbcnt;
  1693. maildir_list_shared(".", &add_shared, &info);
  1694. maildir_list_sharable(".", &add_sharable, &info);
  1695. }
  1696. qsort( (*fp)+1, fbcnt-1, sizeof(**fp),
  1697. (int (*)(const void *, const void *))mdcomparefunc);
  1698. for (i=0; i < fbcnt; i++)
  1699. {
  1700. char *c=(*fp)[i];
  1701. if (*c != ':') continue;
  1702. c=strrchr(c, '.');
  1703. ++c;
  1704. while (*c)
  1705. {
  1706. *c=c[1];
  1707. ++c;
  1708. }
  1709. }
  1710. addfolder(NULL, fp, &fbsize, &fbcnt);
  1711. }
  1712. void maildir_freefolders(char ***fp)
  1713. {
  1714. size_t cnt;
  1715. for (cnt=0; (*fp)[cnt]; cnt++)
  1716. free( (*fp)[cnt] );
  1717. free(*fp);
  1718. }
  1719. int maildir_create(const char *foldername)
  1720. {
  1721. char *dir=xlate_mdir(foldername);
  1722. int rc= -1;
  1723. if (mkdir(dir, 0700) == 0)
  1724. {
  1725. char *tmp=alloc_filename(dir, "tmp", "");
  1726. if (mkdir(tmp, 0700) == 0)
  1727. {
  1728. char *tmp2=alloc_filename(dir, "new", "");
  1729. if (mkdir(tmp2, 0700) == 0)
  1730. {
  1731. char *tmp3=alloc_filename(dir, "cur", "");
  1732. if (mkdir(tmp3, 0700) == 0)
  1733. {
  1734. char *tmp4=alloc_filename(dir, "maildirfolder",
  1735. "");
  1736. close(open(tmp4, O_RDWR|O_CREAT, 0600));
  1737. rc=0;
  1738. free(tmp4);
  1739. }
  1740. free(tmp3);
  1741. }
  1742. if (rc) rmdir(tmp2);
  1743. free (tmp2);
  1744. }
  1745. if (rc) rmdir(tmp);
  1746. free(tmp);
  1747. }
  1748. if (rc) rmdir(dir);
  1749. free(dir);
  1750. return (rc);
  1751. }
  1752. static void rmdirtmp(const char *tmpdir)
  1753. {
  1754. DIR *dirp;
  1755. struct dirent *de;
  1756. dirp=opendir(tmpdir);
  1757. while (dirp && (de=readdir(dirp)) != NULL)
  1758. {
  1759. if (strcmp(de->d_name, ".") && strcmp(de->d_name, ".."))
  1760. {
  1761. char *q=alloc_filename(tmpdir, "", de->d_name);
  1762. if (q) { unlink(q); free(q); }
  1763. }
  1764. }
  1765. if (dirp) closedir(dirp);
  1766. }
  1767. static void rmdirmain(const char *maindir)
  1768. {
  1769. DIR *dirp;
  1770. struct dirent *de;
  1771. dirp=opendir(maindir);
  1772. while (dirp && (de=readdir(dirp)) != NULL)
  1773. {
  1774. if (strcmp(de->d_name, ".") && strcmp(de->d_name, ".."))
  1775. {
  1776. char *q=alloc_filename(maindir, "", de->d_name);
  1777. if (q) { unlink(q); free(q); }
  1778. }
  1779. }
  1780. if (dirp) closedir(dirp);
  1781. }
  1782. int maildir_delete(const char *foldername)
  1783. {
  1784. char *dir, *tmp, *new, *cur;
  1785. int rc=0;
  1786. if (strcmp(foldername, INBOX) == 0 ||
  1787. strcmp(foldername, SENT) == 0 ||
  1788. strcmp(foldername, TRASH) == 0 ||
  1789. strcmp(foldername, DRAFTS) == 0) return (-1);
  1790. dir=xlate_mdir(foldername);
  1791. tmp=alloc_filename(dir, "tmp", "");
  1792. cur=alloc_filename(dir, "cur", "");
  1793. new=alloc_filename(dir, "new", "");
  1794. if ( rmdir(new) || rmdir(cur)
  1795. || ( rmdirtmp(tmp), rmdir(tmp))
  1796. || (rmdirmain(dir), rmdir(dir)) )
  1797. {
  1798. rc= -1;
  1799. mkdir(tmp, 0700);
  1800. mkdir(new, 0700);
  1801. mkdir(cur, 0700);
  1802. }
  1803. free(tmp);
  1804. free(new);
  1805. free(cur);
  1806. free(dir);
  1807. return (rc);
  1808. }
  1809. int maildir_rename(const char *from, const char *to)
  1810. {
  1811. char *fromdir, *todir;
  1812. int rc;
  1813. if (strcmp(from, INBOX) == 0 ||
  1814. strcmp(from, SENT) == 0 ||
  1815. strcmp(from, TRASH) == 0 ||
  1816. strcmp(from, DRAFTS) == 0 ||
  1817. strcmp(to, INBOX) == 0) return (-1);
  1818. fromdir=xlate_mdir(from);
  1819. todir=xlate_mdir(to);
  1820. rc=rename(fromdir, todir);
  1821. free(fromdir);
  1822. free(todir);
  1823. return (rc);
  1824. }
  1825. /* ------------------------------------------------------------------- */
  1826. /* Here's where we create a new message in a maildir.  First maildir_createmsg
  1827. ** is called.  Then, the message contents are defined via maildir_writemsg,
  1828. ** then maildir_closemsg is called. */
  1829. static char writebuf[BUFSIZ];
  1830. static char *writebufptr;
  1831. static int writebufcnt, writebufleft;
  1832. static int writeerr;
  1833. off_t writebufpos;
  1834. int writebuf8bit;
  1835. int maildir_createmsg(const char *foldername, const char *seq,
  1836. char **retname)
  1837. {
  1838. char *p;
  1839. char *dir=xlate_mdir(foldername);
  1840. char *filename;
  1841. int n;
  1842. /* Create a new file in the tmp directory. */
  1843. for (;;)
  1844. {
  1845. int rc;
  1846. char *nptr;
  1847. rc=maildir_try_create(dir, seq, 0, &filename, &nptr);
  1848. if (rc < 0)
  1849. error("maildir_createmsg: cannot create temp file.");
  1850. if (rc == 0)
  1851. {
  1852. free(nptr);
  1853. break;
  1854. }
  1855. sleep(5);
  1856. }
  1857. n=maildir_safeopen(filename, O_CREAT|O_RDWR|O_TRUNC, 0644);
  1858. if (n < 0)
  1859. {
  1860. free(filename);
  1861. error("maildir_createmsg: cannot create temp file.");
  1862. }
  1863. p=strrchr(filename, '/');
  1864. *retname=strdup(p+1);
  1865. if (*retname == 0)
  1866. {
  1867. close(n);
  1868. free(filename);
  1869. enomem();
  1870. }
  1871. free(filename);
  1872. /* Buffer writes */
  1873. writebufcnt=0;
  1874. writebufpos=0;
  1875. writebuf8bit=0;
  1876. writebufleft=0;
  1877. writeerr=0;
  1878. return (n);
  1879. }
  1880. /* Like createmsg, except we're rewriting the contents of this message here,
  1881. ** so we might as well use the same name. */
  1882. int maildir_recreatemsg(const char *folder, const char *name, char **baseptr)
  1883. {
  1884. char *dir=xlate_mdir(folder);
  1885. char *base;
  1886. char *p;
  1887. int n;
  1888. base=maildir_basename(name);
  1889. p=alloc_filename(dir, "tmp", base);
  1890. free(dir);
  1891. *baseptr=base;
  1892. n=maildir_safeopen(p, O_CREAT|O_RDWR|O_TRUNC, 0644);
  1893. if (n < 0) free(base);
  1894. free(p);
  1895. writebufcnt=0;
  1896. writebufleft=0;
  1897. writeerr=0;
  1898. writebufpos=0;
  1899. writebuf8bit=0;
  1900. return (n);
  1901. }
  1902. /* Flush write buffer */
  1903. static void writeflush(int n)
  1904. {
  1905. const char *q=writebuf;
  1906. int c;
  1907. /* Keep calling write() until there's an error, or we're all done */
  1908. while (!writeerr && writebufcnt)
  1909. {
  1910. c=write(n, q, writebufcnt);
  1911. if ( c <= 0)
  1912. writeerr=1;
  1913. else
  1914. {
  1915. q += c;
  1916. writebufcnt -= c;
  1917. }
  1918. }
  1919. /* We have an empty buffer now */
  1920. writebufcnt=0;
  1921. writebufleft=sizeof(writebuf);
  1922. writebufptr=writebuf;
  1923. }
  1924. /* Add whatever we have to the buffer */
  1925. /* Write to the message file.  The writes are buffered, and we will set a
  1926. ** flag if there's error writing to the message file.
  1927. */
  1928. void maildir_writemsgstr(int n, const char *p)
  1929. {
  1930. maildir_writemsg(n, p, strlen(p));
  1931. }
  1932. void maildir_writemsg(int n, const char *p, size_t cnt)
  1933. {
  1934. int c;
  1935. size_t i;
  1936. writebufpos += cnt; /* I'm optimistic */
  1937. for (i=0; i<cnt; i++)
  1938. if (p[i] & 0x80) writebuf8bit=1;
  1939. while (cnt)
  1940. {
  1941. /* Flush buffer if it's full.  No need to flush if we've
  1942. ** already had an error before. */
  1943. if (writebufleft == 0) writeflush(n);
  1944. c=writebufleft;
  1945. if (c > cnt) c=cnt;
  1946. memcpy(writebufptr, p, c);
  1947. writebufptr += c;
  1948. p += c;
  1949. cnt -= c;
  1950. writebufcnt += c;
  1951. writebufleft -= c;
  1952. }
  1953. }
  1954. /* The new message has been written out.  Move the new file from the tmp
  1955. ** directory to either the new directory (if 'new' is set), or to the
  1956. ** cur directory.
  1957. **
  1958. ** The caller might have encountered an error condition.  If 'isok' is zero,
  1959. ** we just delete the file.  If we had a write error, we delete the file
  1960. ** as well.  We return -1 in both cases, or 0 if the new file has been
  1961. ** succesfully moved into its final resting place.
  1962. */
  1963. int maildir_writemsg_flush(int n )
  1964. {
  1965. writeflush(n);
  1966. return (writeerr);
  1967. }
  1968. int maildir_closemsg(int n, /* File descriptor */
  1969. const char *folder, /* Folder */
  1970. const char *retname, /* Filename in folder */
  1971. int isok, /* 0 - discard it (I changed my mind),
  1972.    1 - keep it
  1973.   -1 - keep it even if we'll exceed the quota
  1974. */
  1975. unsigned long prevsize /* Prev size of this msg, used in quota calc */
  1976. )
  1977. {
  1978. char *dir=xlate_mdir(folder);
  1979. char *oldname=alloc_filename(dir, "tmp", retname);
  1980. char *newname;
  1981. struct stat stat_buf;
  1982. char quotabuf[QUOTABUFSIZE];
  1983. int quotafd;
  1984. writeflush(n); /* If there's still anything in the buffer */
  1985. if (fstat(n, &stat_buf))
  1986. {
  1987. close(n);
  1988. unlink(oldname);
  1989. enomem();
  1990. }
  1991. newname=maildir_find(folder, retname);
  1992. /* If we called recreatemsg before */
  1993. if (!newname)
  1994. {
  1995. newname=alloc_filename(dir, "cur:2,S", retname);
  1996. /* Hack of the century          ^^^^ */
  1997. strcat(strcat(strcat(strcpy(newname, dir), "/cur/"),
  1998. retname), ":2,S");
  1999. }
  2000. if (writeerr)
  2001. {
  2002. close(n);
  2003. unlink(oldname);
  2004. enomem();
  2005. }
  2006. close(n);
  2007. if (maildir_getquota(dir, quotabuf))
  2008. {
  2009. if (errno != ENOENT) enomem();
  2010. quotabuf[0]=0;
  2011. }
  2012. quotafd= -1;
  2013. if (quotabuf[0])
  2014. {
  2015. /* *ALWAYS* call checkquota */
  2016. if (maildir_checkquota(dir, &quotafd, quotabuf,
  2017. stat_buf.st_size - prevsize,
  2018. (prevsize == 0 ? 1:0)) && errno != EAGAIN)
  2019. {
  2020. if (prevsize < stat_buf.st_size
  2021. /* But report an error only when quota
  2022. ** gets larger.
  2023. */
  2024. )
  2025. {
  2026. if (isok == -1)
  2027. {
  2028. isok= -2;
  2029. }
  2030. else
  2031. {
  2032. isok=0;
  2033. if (quotafd >= 0)
  2034. close(quotafd);
  2035. }
  2036. }
  2037. }
  2038. }
  2039. if (isok)
  2040. rename(oldname, newname);
  2041. unlink(oldname);
  2042. if (isok)
  2043. {
  2044. char *realnewname=maildir_requota(newname, stat_buf.st_size);
  2045. if (strcmp(newname, realnewname))
  2046. rename(newname, realnewname);
  2047. free(realnewname);
  2048. if (quotabuf[0])
  2049. {
  2050. maildir_addquota(dir, quotafd, quotabuf,
  2051. stat_buf.st_size - prevsize,
  2052. (prevsize == 0 ? 1:0));
  2053. }
  2054. }
  2055. free(dir);
  2056. free(oldname);
  2057. free(newname);
  2058. return (isok && isok != -2? 0:-1);
  2059. }
  2060. void maildir_deletenewmsg(int n, const char *folder, const char *retname)
  2061. {
  2062. char *dir=xlate_mdir(folder);
  2063. char *oldname=alloc_filename(dir, "tmp", retname);
  2064. close(n);
  2065. unlink(oldname);
  2066. free(oldname);
  2067. free(dir);
  2068. }
  2069. void maildir_cleanup()
  2070. {
  2071. closedb();
  2072. }