convert.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  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 Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, 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 <time.h>
  30. #include <db.h>
  31. static const char *subdirs[] = { "cur", "new", "tmp" };
  32. static const char Flags[] = { 'D', 'F', 'R', 'S', 'T' };
  33. static int
  34. parse_info( const char *s )
  35. {
  36. unsigned i;
  37. int flags;
  38. flags = 0;
  39. if (s && *(s + 1) == '2' && *(s + 2) == ',')
  40. for (s += 3, i = 0; i < as(Flags); i++)
  41. if (strchr( s, Flags[i] ))
  42. flags |= (1 << i);
  43. return flags;
  44. }
  45. typedef struct {
  46. int uid, flags;
  47. } msg_t;
  48. static int
  49. compare_uids( const void *l, const void *r )
  50. {
  51. return ((msg_t *)l)->uid - ((msg_t *)r)->uid;
  52. }
  53. static DBT key, value;
  54. static struct flock lck;
  55. void
  56. convert( config_t *box )
  57. {
  58. DIR *d;
  59. struct dirent *e;
  60. char *s, *p, *mboxdir;
  61. FILE *fp;
  62. msg_t *msgs;
  63. DB *db;
  64. int i, ret, fd, uidval, maxuid, uid, rmsgs, nmsgs, uv[2];
  65. unsigned u;
  66. struct stat sb;
  67. char buf[_POSIX_PATH_MAX], diumname[_POSIX_PATH_MAX],
  68. uvname[_POSIX_PATH_MAX], sname[_POSIX_PATH_MAX],
  69. iuvname[_POSIX_PATH_MAX], imuname[_POSIX_PATH_MAX],
  70. ilname[_POSIX_PATH_MAX], iumname[_POSIX_PATH_MAX];
  71. mboxdir = expand_strdup( box->path );
  72. nfsnprintf( iuvname, sizeof(iuvname), "%s/isyncuidvalidity", mboxdir );
  73. nfsnprintf( diumname, sizeof(iumname), "%s/.isyncuidmap.db", mboxdir );
  74. nfsnprintf( uvname, sizeof(uvname), "%s/.uidvalidity", mboxdir );
  75. if (stat( iuvname, &sb )) {
  76. if (!stat( diumname, &sb ))
  77. altmap++;
  78. else if (!stat( uvname, &sb ))
  79. altmap--;
  80. err1:
  81. free( mboxdir );
  82. return;
  83. }
  84. for (i = 0; i < 3; i++) {
  85. nfsnprintf( buf, sizeof(buf), "%s/%s", mboxdir, subdirs[i] );
  86. if (stat( buf, &sb )) {
  87. sys_error( "ERROR: cannot access %s", buf );
  88. fprintf( stderr,
  89. "ERROR: '%s' does not appear to be a valid maildir style mailbox\n",
  90. mboxdir );
  91. goto err1;
  92. }
  93. }
  94. nfsnprintf( iumname, sizeof(iumname), "%s/isyncuidmap.db", mboxdir );
  95. nfsnprintf( imuname, sizeof(imuname), "%s/isyncmaxuid", mboxdir );
  96. nfsnprintf( ilname, sizeof(ilname), "%s/isynclock", mboxdir );
  97. nfsnprintf( sname, sizeof(sname), "%s/.mbsyncstate", mboxdir );
  98. if ((fd = open( ilname, O_WRONLY|O_CREAT, 0600 )) < 0) {
  99. sys_error( "Cannot create %s", ilname );
  100. goto err1;
  101. }
  102. #if SEEK_SET != 0
  103. lck.l_whence = SEEK_SET;
  104. #endif
  105. #if F_WRLCK != 0
  106. lck.l_type = F_WRLCK;
  107. #endif
  108. if (fcntl( fd, F_SETLKW, &lck )) {
  109. sys_error( "Cannot lock %s", ilname );
  110. err2:
  111. close( fd );
  112. goto err1;
  113. }
  114. if (!(fp = fopen( iuvname, "r" ))) {
  115. sys_error( "Cannot open %s", iuvname );
  116. goto err2;
  117. }
  118. fscanf( fp, "%d", &uidval );
  119. fclose( fp );
  120. if (!(fp = fopen( imuname, "r" ))) {
  121. sys_error( "Cannot open %s", imuname );
  122. goto err2;
  123. }
  124. fscanf( fp, "%d", &maxuid );
  125. fclose( fp );
  126. if (!stat( iumname, &sb )) {
  127. if (db_create( &db, 0, 0 )) {
  128. fputs( "dbcreate failed\n", stderr );
  129. goto err2;
  130. }
  131. if ((db->open)( db, 0, iumname, 0, DB_HASH, 0, 0 )) {
  132. fputs( "cannot open db\n", stderr );
  133. db->close( db, 0 );
  134. goto err2;
  135. }
  136. altmap++;
  137. } else {
  138. db = 0;
  139. altmap--;
  140. }
  141. msgs = 0;
  142. rmsgs = 0;
  143. nmsgs = 0;
  144. for (i = 0; i < 2; i++) {
  145. nfsnprintf( buf, sizeof(buf), "%s/%s/", mboxdir, subdirs[i] );
  146. if (!(d = opendir( buf ))) {
  147. sys_error( "Cannot list %s", buf );
  148. err4:
  149. free( msgs );
  150. if (db)
  151. db->close( db, 0 );
  152. goto err2;
  153. }
  154. while ((e = readdir( d ))) {
  155. if (*e->d_name == '.')
  156. continue;
  157. s = strchr( e->d_name, ':' );
  158. if (db) {
  159. key.data = e->d_name;
  160. key.size = s ? (size_t)(s - e->d_name) : strlen( e->d_name );
  161. if ((ret = db->get( db, 0, &key, &value, 0 ))) {
  162. if (ret != DB_NOTFOUND)
  163. db->err( db, ret, "Maildir error: db->get()" );
  164. continue;
  165. }
  166. uid = *(int *)value.data;
  167. } else if ((p = strstr( e->d_name, ",U=" )))
  168. uid = atoi( p + 3 );
  169. else
  170. continue;
  171. if (nmsgs == rmsgs) {
  172. rmsgs = rmsgs * 2 + 100;
  173. msgs = nfrealloc( msgs, rmsgs * sizeof(msg_t) );
  174. }
  175. msgs[nmsgs].uid = uid;
  176. msgs[nmsgs++].flags = parse_info( s );
  177. }
  178. closedir( d );
  179. }
  180. qsort( msgs, nmsgs, sizeof(msg_t), compare_uids );
  181. if (!(fp = fopen( sname, "w" ))) {
  182. sys_error( "Cannot create %s", sname );
  183. goto err4;
  184. }
  185. if (box->max_messages) {
  186. if (!nmsgs)
  187. i = maxuid;
  188. else {
  189. i = nmsgs - box->max_messages;
  190. if (i < 0)
  191. i = 0;
  192. i = msgs[i].uid - 1;
  193. }
  194. } else
  195. i = 0;
  196. fprintf( fp, "%d:%d %d:%d:%d\n", uidval, maxuid, uidval, i, maxuid );
  197. for (i = 0; i < nmsgs; i++) {
  198. fprintf( fp, "%d %d ", msgs[i].uid, msgs[i].uid );
  199. for (u = 0; u < as(Flags); u++)
  200. if (msgs[i].flags & (1 << u))
  201. fputc( Flags[u], fp );
  202. fputc( '\n', fp );
  203. }
  204. fclose( fp );
  205. if (db) {
  206. key.data = (void *)"UIDVALIDITY";
  207. key.size = 11;
  208. uv[0] = uidval;
  209. uv[1] = maxuid;
  210. value.data = uv;
  211. value.size = sizeof(uv);
  212. if ((ret = db->put( db, 0, &key, &value, 0 ))) {
  213. db->err( db, ret, "Maildir error: db->put()" );
  214. goto err4;
  215. }
  216. db->close( db, 0 );
  217. rename( iumname, diumname );
  218. } else {
  219. if (!(fp = fopen( uvname, "w" ))) {
  220. sys_error( "Cannot create %s", uvname );
  221. goto err4;
  222. }
  223. fprintf( fp, "%d\n%d\n", uidval, maxuid );
  224. fclose( fp );
  225. }
  226. unlink( iuvname );
  227. unlink( imuname );
  228. close( fd );
  229. unlink( ilname );
  230. free( msgs );
  231. free( mboxdir );
  232. return;
  233. }