123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- /*
- * isync - mbsync wrapper: IMAP4 to maildir mailbox synchronizer
- * Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
- * Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "isync.h"
- #include <limits.h>
- #include <stdlib.h>
- #include <string.h>
- #include <dirent.h>
- #include <fcntl.h>
- #include <stdio.h>
- #include <unistd.h>
- #include <sys/stat.h>
- #include <time.h>
- #include <db.h>
- static const char *subdirs[] = { "cur", "new", "tmp" };
- static const char Flags[] = { 'D', 'F', 'R', 'S', 'T' };
- static int
- parse_info( const char *s )
- {
- unsigned i;
- int flags;
- flags = 0;
- if (s && *(s + 1) == '2' && *(s + 2) == ',')
- for (s += 3, i = 0; i < as(Flags); i++)
- if (strchr( s, Flags[i] ))
- flags |= (1 << i);
- return flags;
- }
- typedef struct {
- int uid, flags;
- } msg_t;
- static int
- compare_uids( const void *l, const void *r )
- {
- return ((msg_t *)l)->uid - ((msg_t *)r)->uid;
- }
- static DBT key, value;
- static struct flock lck;
- void
- convert( config_t *box )
- {
- DIR *d;
- struct dirent *e;
- char *s, *p, *mboxdir;
- FILE *fp;
- msg_t *msgs;
- DB *db;
- int i, ret, fd, uidval, maxuid, uid, rmsgs, nmsgs, uv[2];
- unsigned u;
- struct stat sb;
- char buf[_POSIX_PATH_MAX], diumname[_POSIX_PATH_MAX],
- uvname[_POSIX_PATH_MAX], sname[_POSIX_PATH_MAX],
- iuvname[_POSIX_PATH_MAX], imuname[_POSIX_PATH_MAX],
- ilname[_POSIX_PATH_MAX], iumname[_POSIX_PATH_MAX];
- mboxdir = expand_strdup( box->path );
- nfsnprintf( iuvname, sizeof(iuvname), "%s/isyncuidvalidity", mboxdir );
- nfsnprintf( diumname, sizeof(iumname), "%s/.isyncuidmap.db", mboxdir );
- nfsnprintf( uvname, sizeof(uvname), "%s/.uidvalidity", mboxdir );
- if (stat( iuvname, &sb )) {
- if (!stat( diumname, &sb ))
- altmap++;
- else if (!stat( uvname, &sb ))
- altmap--;
- err1:
- free( mboxdir );
- return;
- }
- for (i = 0; i < 3; i++) {
- nfsnprintf( buf, sizeof(buf), "%s/%s", mboxdir, subdirs[i] );
- if (stat( buf, &sb )) {
- sys_error( "ERROR: cannot access %s", buf );
- fprintf( stderr,
- "ERROR: '%s' does not appear to be a valid maildir style mailbox\n",
- mboxdir );
- goto err1;
- }
- }
- nfsnprintf( iumname, sizeof(iumname), "%s/isyncuidmap.db", mboxdir );
- nfsnprintf( imuname, sizeof(imuname), "%s/isyncmaxuid", mboxdir );
- nfsnprintf( ilname, sizeof(ilname), "%s/isynclock", mboxdir );
- nfsnprintf( sname, sizeof(sname), "%s/.mbsyncstate", mboxdir );
- if ((fd = open( ilname, O_WRONLY|O_CREAT, 0600 )) < 0) {
- sys_error( "Cannot create %s", ilname );
- goto err1;
- }
- #if SEEK_SET != 0
- lck.l_whence = SEEK_SET;
- #endif
- #if F_WRLCK != 0
- lck.l_type = F_WRLCK;
- #endif
- if (fcntl( fd, F_SETLKW, &lck )) {
- sys_error( "Cannot lock %s", ilname );
- err2:
- close( fd );
- goto err1;
- }
- if (!(fp = fopen( iuvname, "r" ))) {
- sys_error( "Cannot open %s", iuvname );
- goto err2;
- }
- if (fscanf( fp, "%d", &uidval ) != 1) {
- sys_error( "Cannot read %s", iuvname );
- err3:
- fclose( fp );
- goto err2;
- }
- fclose( fp );
- if (!(fp = fopen( imuname, "r" ))) {
- sys_error( "Cannot open %s", imuname );
- goto err2;
- }
- if (fscanf( fp, "%d", &maxuid ) != 1) {
- sys_error( "Cannot read %s", imuname );
- goto err3;
- }
- fclose( fp );
- if (!stat( iumname, &sb )) {
- if (db_create( &db, 0, 0 )) {
- fputs( "dbcreate failed\n", stderr );
- goto err2;
- }
- if ((db->open)( db, 0, iumname, 0, DB_HASH, 0, 0 )) {
- fputs( "cannot open db\n", stderr );
- db->close( db, 0 );
- goto err2;
- }
- altmap++;
- } else {
- db = 0;
- altmap--;
- }
- msgs = 0;
- rmsgs = 0;
- nmsgs = 0;
- for (i = 0; i < 2; i++) {
- nfsnprintf( buf, sizeof(buf), "%s/%s/", mboxdir, subdirs[i] );
- if (!(d = opendir( buf ))) {
- sys_error( "Cannot list %s", buf );
- err4:
- free( msgs );
- if (db)
- db->close( db, 0 );
- goto err2;
- }
- while ((e = readdir( d ))) {
- if (*e->d_name == '.')
- continue;
- s = strchr( e->d_name, ':' );
- if (db) {
- key.data = e->d_name;
- key.size = s ? (size_t)(s - e->d_name) : strlen( e->d_name );
- if ((ret = db->get( db, 0, &key, &value, 0 ))) {
- if (ret != DB_NOTFOUND)
- db->err( db, ret, "Maildir error: db->get()" );
- continue;
- }
- uid = *(int *)value.data;
- } else if ((p = strstr( e->d_name, ",U=" )))
- uid = atoi( p + 3 );
- else
- continue;
- if (nmsgs == rmsgs) {
- rmsgs = rmsgs * 2 + 100;
- msgs = nfrealloc( msgs, rmsgs * sizeof(msg_t) );
- }
- msgs[nmsgs].uid = uid;
- msgs[nmsgs++].flags = parse_info( s );
- }
- closedir( d );
- }
- qsort( msgs, nmsgs, sizeof(msg_t), compare_uids );
- if (!(fp = fopen( sname, "w" ))) {
- sys_error( "Cannot create %s", sname );
- goto err4;
- }
- if (box->max_messages) {
- if (!nmsgs)
- i = maxuid;
- else {
- i = nmsgs - box->max_messages;
- if (i < 0)
- i = 0;
- i = msgs[i].uid - 1;
- }
- } else
- i = 0;
- fprintf( fp, "%d:%d %d:%d:%d\n", uidval, maxuid, uidval, i, maxuid );
- for (i = 0; i < nmsgs; i++) {
- fprintf( fp, "%d %d ", msgs[i].uid, msgs[i].uid );
- for (u = 0; u < as(Flags); u++)
- if (msgs[i].flags & (1 << u))
- fputc( Flags[u], fp );
- fputc( '\n', fp );
- }
- fclose( fp );
- if (db) {
- key.data = (void *)"UIDVALIDITY";
- key.size = 11;
- uv[0] = uidval;
- uv[1] = maxuid;
- value.data = uv;
- value.size = sizeof(uv);
- if ((ret = db->put( db, 0, &key, &value, 0 ))) {
- db->err( db, ret, "Maildir error: db->put()" );
- goto err4;
- }
- db->close( db, 0 );
- if (rename( iumname, diumname )) {
- sys_error( "Cannot rename %s to %s", iumname, diumname );
- goto err4;
- }
- } else {
- if (!(fp = fopen( uvname, "w" ))) {
- sys_error( "Cannot create %s", uvname );
- goto err4;
- }
- fprintf( fp, "%d\n%d\n", uidval, maxuid );
- fclose( fp );
- }
- unlink( iuvname );
- unlink( imuname );
- close( fd );
- unlink( ilname );
- free( msgs );
- free( mboxdir );
- return;
- }
|