convert.c 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  1. /*
  2. * isync - mbsync wrapper: IMAP4 to maildir mailbox synchronizer
  3. * Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
  4. * Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
  5. *
  6. * This program is free software; you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation; either version 2 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, write to the Free Software
  18. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  19. */
  20. #include "isync.h"
  21. #include <limits.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <dirent.h>
  25. #include <fcntl.h>
  26. #include <stdio.h>
  27. #include <unistd.h>
  28. #include <sys/stat.h>
  29. #include <errno.h>
  30. #include <time.h>
  31. #include <db.h>
  32. static const char *subdirs[] = { "cur", "new", "tmp" };
  33. static const char Flags[] = { 'D', 'F', 'R', 'S', 'T' };
  34. static int
  35. parse_info( const char *s )
  36. {
  37. unsigned i;
  38. int flags;
  39. flags = 0;
  40. if (s && *(s + 1) == '2' && *(s + 2) == ',')
  41. for (s += 3, i = 0; i < as(Flags); i++)
  42. if (strchr( s, Flags[i] ))
  43. flags |= (1 << i);
  44. return flags;
  45. }
  46. typedef struct {
  47. int uid, flags;
  48. } msg_t;
  49. static int
  50. compare_uids( const void *l, const void *r )
  51. {
  52. return ((msg_t *)l)->uid - ((msg_t *)r)->uid;
  53. }
  54. static DBT key, value;
  55. static struct flock lck;
  56. void
  57. convert( config_t *box )
  58. {
  59. DIR *d;
  60. struct dirent *e;
  61. char *s, *p, *mboxdir;
  62. FILE *fp;
  63. msg_t *msgs;
  64. DB *db;
  65. int i, ret, fd, uidval, maxuid, bl, uid, rmsgs, nmsgs, uv[2];
  66. unsigned u;
  67. struct stat sb;
  68. char buf[_POSIX_PATH_MAX], diumname[_POSIX_PATH_MAX],
  69. uvname[_POSIX_PATH_MAX], sname[_POSIX_PATH_MAX],
  70. iuvname[_POSIX_PATH_MAX], imuname[_POSIX_PATH_MAX],
  71. ilname[_POSIX_PATH_MAX], iumname[_POSIX_PATH_MAX];
  72. mboxdir = expand_strdup( box->path );
  73. nfsnprintf( iuvname, sizeof(iuvname), "%s/isyncuidvalidity", mboxdir );
  74. nfsnprintf( diumname, sizeof(iumname), "%s/.isyncuidmap.db", mboxdir );
  75. nfsnprintf( uvname, sizeof(uvname), "%s/.uidvalidity", mboxdir );
  76. if (stat( iuvname, &sb )) {
  77. if (!stat( diumname, &sb ))
  78. altmap++;
  79. else if (!stat( uvname, &sb ))
  80. altmap--;
  81. err1:
  82. free( mboxdir );
  83. return;
  84. }
  85. for (i = 0; i < 3; i++) {
  86. nfsnprintf( buf, sizeof(buf), "%s/%s", mboxdir, subdirs[i] );
  87. if (stat( buf, &sb )) {
  88. fprintf( stderr, "ERROR: stat %s: %s (errno %d)\n", buf,
  89. strerror(errno), errno );
  90. fprintf( stderr,
  91. "ERROR: %s does not appear to be a valid maildir style mailbox\n",
  92. mboxdir );
  93. goto err1;
  94. }
  95. }
  96. nfsnprintf( iumname, sizeof(iumname), "%s/isyncuidmap.db", mboxdir );
  97. nfsnprintf( imuname, sizeof(imuname), "%s/isyncmaxuid", mboxdir );
  98. nfsnprintf( ilname, sizeof(ilname), "%s/isynclock", mboxdir );
  99. nfsnprintf( sname, sizeof(sname), "%s/.mbsyncstate", mboxdir );
  100. if ((fd = open( ilname, O_WRONLY|O_CREAT, 0600 )) < 0) {
  101. perror( ilname );
  102. goto err1;
  103. }
  104. #if SEEK_SET != 0
  105. lck.l_whence = SEEK_SET;
  106. #endif
  107. #if F_WRLCK != 0
  108. lck.l_type = F_WRLCK;
  109. #endif
  110. if (fcntl( fd, F_SETLKW, &lck )) {
  111. perror( ilname );
  112. err2:
  113. close( fd );
  114. goto err1;
  115. }
  116. if (!(fp = fopen( iuvname, "r" ))) {
  117. perror( iuvname );
  118. goto err2;
  119. }
  120. fscanf( fp, "%d", &uidval );
  121. fclose( fp );
  122. if (!(fp = fopen( imuname, "r" ))) {
  123. perror( imuname );
  124. goto err2;
  125. }
  126. fscanf( fp, "%d", &maxuid );
  127. fclose( fp );
  128. if (!stat( iumname, &sb )) {
  129. if (db_create( &db, 0, 0 )) {
  130. fputs( "dbcreate failed\n", stderr );
  131. goto err2;
  132. }
  133. if (db->open( db, 0, iumname, 0, DB_HASH, 0, 0 )) {
  134. fputs( "cannot open db\n", stderr );
  135. db->close( db, 0 );
  136. goto err2;
  137. }
  138. altmap++;
  139. } else {
  140. db = 0;
  141. altmap--;
  142. }
  143. msgs = 0;
  144. rmsgs = 0;
  145. nmsgs = 0;
  146. for (i = 0; i < 2; i++) {
  147. bl = nfsnprintf( buf, sizeof(buf), "%s/%s/", mboxdir, subdirs[i] );
  148. if (!(d = opendir( buf ))) {
  149. perror( "opendir" );
  150. err4:
  151. if (msgs)
  152. free( msgs );
  153. if (db)
  154. db->close( db, 0 );
  155. goto err2;
  156. }
  157. while ((e = readdir( d ))) {
  158. if (*e->d_name == '.')
  159. continue;
  160. s = strchr( e->d_name, ':' );
  161. if (db) {
  162. key.data = e->d_name;
  163. key.size = s ? (size_t)(s - e->d_name) : strlen( e->d_name );
  164. if ((ret = db->get( db, 0, &key, &value, 0 ))) {
  165. if (ret != DB_NOTFOUND)
  166. db->err( db, ret, "Maildir error: db->get()" );
  167. continue;
  168. }
  169. uid = *(int *)value.data;
  170. } else if ((p = strstr( e->d_name, ",U=" )))
  171. uid = atoi( p + 3 );
  172. else
  173. continue;
  174. if (nmsgs == rmsgs) {
  175. rmsgs = rmsgs * 2 + 100;
  176. msgs = nfrealloc( msgs, rmsgs * sizeof(msg_t) );
  177. }
  178. msgs[nmsgs].uid = uid;
  179. msgs[nmsgs++].flags = parse_info( s );
  180. }
  181. closedir( d );
  182. }
  183. qsort( msgs, nmsgs, sizeof(msg_t), compare_uids );
  184. if (!(fp = fopen( sname, "w" ))) {
  185. perror( sname );
  186. goto err4;
  187. }
  188. if (box->max_messages) {
  189. if (!nmsgs)
  190. i = maxuid;
  191. else {
  192. i = nmsgs - box->max_messages;
  193. if (i < 0)
  194. i = 0;
  195. i = msgs[i].uid - 1;
  196. }
  197. } else
  198. i = 0;
  199. fprintf( fp, "%d:%d %d:%d:%d\n", uidval, maxuid, uidval, i, maxuid );
  200. for (i = 0; i < nmsgs; i++) {
  201. fprintf( fp, "%d %d ", msgs[i].uid, msgs[i].uid );
  202. for (u = 0; u < as(Flags); u++)
  203. if (msgs[i].flags & (1 << u))
  204. fputc( Flags[u], fp );
  205. fputc( '\n', fp );
  206. }
  207. fclose( fp );
  208. if (db) {
  209. key.data = (void *)"UIDVALIDITY";
  210. key.size = 11;
  211. uv[0] = uidval;
  212. uv[1] = maxuid;
  213. value.data = uv;
  214. value.size = sizeof(uv);
  215. if ((ret = db->put( db, 0, &key, &value, 0 ))) {
  216. db->err( db, ret, "Maildir error: db->put()" );
  217. goto err4;
  218. }
  219. db->close( db, 0 );
  220. rename( iumname, diumname );
  221. } else {
  222. if (!(fp = fopen( uvname, "w" ))) {
  223. perror( uvname );
  224. goto err4;
  225. }
  226. fprintf( fp, "%d\n%d\n", uidval, maxuid );
  227. fclose( fp );
  228. }
  229. unlink( iuvname );
  230. unlink( imuname );
  231. close( fd );
  232. unlink( ilname );
  233. if (msgs)
  234. free( msgs );
  235. free( mboxdir );
  236. return;
  237. }