mirror of https://git.code.sf.net/p/isync/isync
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
257 lines
6.0 KiB
257 lines
6.0 KiB
/* |
|
* 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, write to the Free Software Foundation, |
|
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA |
|
*/ |
|
|
|
#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 <errno.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 )) { |
|
fprintf( stderr, "ERROR: stat %s: %s (errno %d)\n", buf, |
|
strerror(errno), errno ); |
|
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) { |
|
perror( 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 )) { |
|
perror( ilname ); |
|
err2: |
|
close( fd ); |
|
goto err1; |
|
} |
|
|
|
if (!(fp = fopen( iuvname, "r" ))) { |
|
perror( iuvname ); |
|
goto err2; |
|
} |
|
fscanf( fp, "%d", &uidval ); |
|
fclose( fp ); |
|
if (!(fp = fopen( imuname, "r" ))) { |
|
perror( imuname ); |
|
goto err2; |
|
} |
|
fscanf( fp, "%d", &maxuid ); |
|
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 ))) { |
|
perror( "opendir" ); |
|
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" ))) { |
|
perror( 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 ); |
|
rename( iumname, diumname ); |
|
} else { |
|
if (!(fp = fopen( uvname, "w" ))) { |
|
perror( 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; |
|
}
|
|
|