2004-03-27 16:07:20 +00:00
|
|
|
/*
|
|
|
|
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "isync.h"
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <pwd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
|
|
|
|
#if HAVE_GETOPT_LONG
|
|
|
|
# define _GNU_SOURCE
|
|
|
|
# include <getopt.h>
|
|
|
|
struct option Opts[] = {
|
|
|
|
{"write", 0, NULL, 'w' },
|
|
|
|
{"writeto", 0, NULL, 'W' },
|
|
|
|
{"all", 0, NULL, 'a' },
|
|
|
|
{"list", 0, NULL, 'l'},
|
|
|
|
{"config", 1, NULL, 'c'},
|
|
|
|
{"create", 0, NULL, 'C'},
|
|
|
|
{"create-local", 0, NULL, 'L'},
|
|
|
|
{"create-remote", 0, NULL, 'R'},
|
|
|
|
{"delete", 0, NULL, 'd'},
|
|
|
|
{"expunge", 0, NULL, 'e'},
|
|
|
|
{"fast", 0, NULL, 'f'},
|
|
|
|
{"help", 0, NULL, 'h'},
|
|
|
|
{"remote", 1, NULL, 'r'},
|
|
|
|
{"folder", 1, NULL, 'F'},
|
|
|
|
{"maildir", 1, NULL, 'M'},
|
|
|
|
{"one-to-one", 0, NULL, '1'},
|
|
|
|
{"inbox", 1, NULL, 'I'},
|
|
|
|
{"host", 1, NULL, 's'},
|
|
|
|
{"port", 1, NULL, 'p'},
|
|
|
|
{"debug", 0, NULL, 'D'},
|
|
|
|
{"quiet", 0, NULL, 'q'},
|
|
|
|
{"user", 1, NULL, 'u'},
|
|
|
|
{"version", 0, NULL, 'v'},
|
|
|
|
{"verbose", 0, NULL, 'V'},
|
|
|
|
{0, 0, 0, 0}
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static void
|
|
|
|
version( void )
|
|
|
|
{
|
|
|
|
puts( PACKAGE " " VERSION );
|
|
|
|
exit( 0 );
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
usage( int code )
|
|
|
|
{
|
|
|
|
fputs(
|
|
|
|
PACKAGE " " VERSION " - mbsync wrapper: IMAP4 to maildir synchronizer\n"
|
|
|
|
"Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>\n"
|
|
|
|
"Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>\n"
|
|
|
|
"usage:\n"
|
|
|
|
" " PACKAGE " [ flags ] mailbox [mailbox ...]\n"
|
|
|
|
" " PACKAGE " [ flags ] -a\n"
|
|
|
|
" " PACKAGE " [ flags ] -l\n"
|
|
|
|
" -a, --all synchronize all defined mailboxes\n"
|
|
|
|
" -l, --list list all defined mailboxes and exit\n"
|
|
|
|
" -L, --create-local create local maildir mailbox if nonexistent\n"
|
|
|
|
" -R, --create-remote create remote imap mailbox if nonexistent\n"
|
|
|
|
" -C, --create create both local and remote mailboxes if nonexistent\n"
|
|
|
|
" -d, --delete delete local msgs that don't exist on the server\n"
|
|
|
|
" -e, --expunge expunge deleted messages\n"
|
|
|
|
" -f, --fast only fetch new messages\n"
|
|
|
|
" -r, --remote BOX remote mailbox\n"
|
|
|
|
" -F, --folder DIR remote IMAP folder containing mailboxes\n"
|
|
|
|
" -M, --maildir DIR local directory containing mailboxes\n"
|
|
|
|
" -1, --one-to-one map every IMAP <folder>/box to <maildir>/box\n"
|
|
|
|
" -I, --inbox BOX map IMAP INBOX to <maildir>/BOX (exception to -1)\n"
|
|
|
|
" -s, --host HOST IMAP server address\n"
|
|
|
|
" -p, --port PORT server IMAP port\n"
|
|
|
|
" -u, --user USER IMAP user name\n"
|
|
|
|
" -c, --config CONFIG read an alternate config file (default: ~/.isyncrc)\n"
|
|
|
|
" -D, --debug print debugging messages\n"
|
|
|
|
" -V, --verbose verbose mode (display network traffic)\n"
|
|
|
|
" -q, --quiet don't display progress info\n"
|
|
|
|
" -v, --version display version\n"
|
|
|
|
" -h, --help display this help message\n\n"
|
|
|
|
"Note that this is a wrapper binary only; the \"real\" isync is named \"mbsync\".\n"
|
|
|
|
"Options to permanently transform your old isync configuration:\n"
|
|
|
|
" -w, --write write permanent mbsync configuration\n"
|
|
|
|
" -W, --writeto FILE write permanent mbsync configuration to FILE\n",
|
|
|
|
code ? stderr : stdout );
|
|
|
|
exit( code );
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
strrstr( const char *h, const char *n )
|
|
|
|
{
|
|
|
|
char *p = strstr( h, n );
|
|
|
|
if (!p)
|
|
|
|
return 0;
|
|
|
|
do {
|
|
|
|
h = p;
|
|
|
|
p = strstr( h + 1, n );
|
|
|
|
} while (p);
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
add_arg( char ***args, const char *arg )
|
|
|
|
{
|
|
|
|
int nu = 0;
|
|
|
|
if (*args)
|
|
|
|
for (; (*args)[nu]; nu++);
|
|
|
|
*args = nfrealloc( *args, sizeof(char *) * (nu + 2));
|
|
|
|
(*args)[nu] = nfstrdup( arg );
|
|
|
|
(*args)[nu + 1] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define OP_FAST (1<<2)
|
|
|
|
#define OP_CREATE_REMOTE (1<<3)
|
|
|
|
#define OP_CREATE_LOCAL (1<<4)
|
|
|
|
|
|
|
|
int Quiet, Verbose, Debug;
|
|
|
|
config_t global, *boxes;
|
|
|
|
const char *maildir, *xmaildir, *folder, *inbox;
|
2004-03-29 06:52:50 +00:00
|
|
|
int o2o, altmap, delete, expunge;
|
2004-03-27 16:07:20 +00:00
|
|
|
|
|
|
|
const char *Home;
|
2004-04-26 14:48:48 +00:00
|
|
|
int HomeLen;
|
2004-03-27 16:07:20 +00:00
|
|
|
|
|
|
|
int
|
|
|
|
main( int argc, char **argv )
|
|
|
|
{
|
|
|
|
config_t *box, **stor;
|
|
|
|
char *config = 0, *outconfig = 0, **args;
|
|
|
|
int i, pl, fd, mod, all, list, ops, writeout;
|
|
|
|
struct stat st;
|
|
|
|
char path1[_POSIX_PATH_MAX], path2[_POSIX_PATH_MAX];
|
|
|
|
|
|
|
|
if (!(Home = getenv("HOME"))) {
|
|
|
|
fputs( "Fatal: $HOME not set\n", stderr );
|
|
|
|
return 1;
|
|
|
|
}
|
2004-04-26 14:48:48 +00:00
|
|
|
HomeLen = strlen( Home );
|
2004-03-27 16:07:20 +00:00
|
|
|
|
|
|
|
/* defaults */
|
|
|
|
/* XXX the precedence is borked:
|
|
|
|
it's defaults < cmdline < file instead of defaults < file < cmdline */
|
|
|
|
global.port = 143;
|
|
|
|
global.box = "INBOX";
|
|
|
|
global.use_namespace = 1;
|
|
|
|
global.require_ssl = 1;
|
|
|
|
global.use_tlsv1 = 1;
|
|
|
|
folder = "";
|
|
|
|
maildir = "~";
|
|
|
|
xmaildir = Home;
|
|
|
|
|
|
|
|
#define FLAGS "wW:alCLRc:defhp:qu:r:F:M:1I:s:vVD"
|
|
|
|
|
|
|
|
mod = all = list = ops = writeout = Quiet = Verbose = Debug = 0;
|
|
|
|
#if HAVE_GETOPT_LONG
|
|
|
|
while ((i = getopt_long( argc, argv, FLAGS, Opts, NULL )) != -1)
|
|
|
|
#else
|
|
|
|
while ((i = getopt( argc, argv, FLAGS )) != -1)
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
switch (i) {
|
|
|
|
case 'W':
|
|
|
|
outconfig = optarg;
|
|
|
|
/* plopp */
|
|
|
|
case 'w':
|
|
|
|
writeout = 1;
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
list = 1;
|
|
|
|
/* plopp */
|
|
|
|
case 'a':
|
|
|
|
all = 1;
|
|
|
|
break;
|
|
|
|
case '1':
|
|
|
|
o2o = 1;
|
|
|
|
mod = 1;
|
|
|
|
break;
|
|
|
|
case 'C':
|
|
|
|
ops |= OP_CREATE_REMOTE|OP_CREATE_LOCAL;
|
|
|
|
break;
|
|
|
|
case 'L':
|
|
|
|
ops |= OP_CREATE_LOCAL;
|
|
|
|
break;
|
|
|
|
case 'R':
|
|
|
|
ops |= OP_CREATE_REMOTE;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
config = optarg;
|
|
|
|
break;
|
|
|
|
case 'd':
|
2004-03-29 06:52:50 +00:00
|
|
|
delete = 1;
|
2004-03-27 16:07:20 +00:00
|
|
|
break;
|
|
|
|
case 'e':
|
2004-03-29 06:52:50 +00:00
|
|
|
expunge = 1;
|
2004-03-27 16:07:20 +00:00
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
ops |= OP_FAST;
|
|
|
|
break;
|
|
|
|
case 'p':
|
|
|
|
global.port = atoi( optarg );
|
|
|
|
mod = 1;
|
|
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
global.box = optarg;
|
|
|
|
mod = 1;
|
|
|
|
break;
|
|
|
|
case 'F':
|
|
|
|
folder = optarg;
|
|
|
|
mod = 1;
|
|
|
|
break;
|
|
|
|
case 'M':
|
|
|
|
maildir = optarg;
|
|
|
|
mod = 1;
|
|
|
|
break;
|
|
|
|
case 'I':
|
|
|
|
inbox = optarg;
|
|
|
|
mod = 1;
|
|
|
|
break;
|
|
|
|
case 's':
|
|
|
|
#if HAVE_LIBSSL
|
|
|
|
if (!strncasecmp( "imaps:", optarg, 6 )) {
|
|
|
|
global.use_imaps = 1;
|
|
|
|
global.port = 993;
|
|
|
|
global.use_sslv2 = 1;
|
|
|
|
global.use_sslv3 = 1;
|
|
|
|
optarg += 6;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
global.host = optarg;
|
|
|
|
mod = 1;
|
|
|
|
break;
|
|
|
|
case 'u':
|
|
|
|
global.user = optarg;
|
|
|
|
mod = 1;
|
|
|
|
break;
|
|
|
|
case 'D':
|
|
|
|
Debug = 1;
|
|
|
|
break;
|
|
|
|
case 'V':
|
|
|
|
Verbose = 1;
|
|
|
|
break;
|
|
|
|
case 'q':
|
|
|
|
Quiet++;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
version();
|
|
|
|
case 'h':
|
|
|
|
usage( 0 );
|
|
|
|
default:
|
|
|
|
usage( 1 );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (config) {
|
|
|
|
if (*config != '/') {
|
|
|
|
if (!getcwd( path1, sizeof(path1) )) {
|
|
|
|
fprintf( stderr, "Can't obtain working directory\n" );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
pl = strlen( path1 );
|
|
|
|
nfsnprintf( path1 + pl, sizeof(path1) - pl, "/%s", config );
|
|
|
|
config = path1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
nfsnprintf( path1, sizeof(path1), "%s/.isyncrc", Home );
|
|
|
|
config = path1;
|
|
|
|
}
|
|
|
|
stor = &boxes;
|
|
|
|
load_config( config, &stor );
|
|
|
|
|
|
|
|
if (!all && !o2o)
|
|
|
|
for (i = optind; argv[i]; i++)
|
|
|
|
if (!(box = find_box( argv[i] ))) {
|
|
|
|
box = nfmalloc( sizeof(config_t) );
|
|
|
|
memcpy( box, &global, sizeof(config_t) );
|
|
|
|
box->path = argv[i];
|
|
|
|
*stor = box;
|
|
|
|
stor = &box->next;
|
|
|
|
mod = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (writeout) {
|
|
|
|
all = 1;
|
|
|
|
if (mod)
|
|
|
|
fprintf( stderr,
|
|
|
|
"Warning: command line switches that influence the resulting config file\n"
|
|
|
|
"have been supplied.\n" );
|
|
|
|
} else {
|
|
|
|
if (!argv[optind] && !all) {
|
|
|
|
fprintf( stderr, "No mailbox specified. Try isync -h\n" );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (all) {
|
|
|
|
if (o2o) {
|
|
|
|
DIR * dir;
|
|
|
|
struct dirent *de;
|
|
|
|
|
|
|
|
if (!(dir = opendir( xmaildir ))) {
|
|
|
|
fprintf( stderr, "%s: %s\n", xmaildir, strerror(errno) );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
while ((de = readdir( dir ))) {
|
|
|
|
if (*de->d_name == '.')
|
|
|
|
continue;
|
|
|
|
nfsnprintf( path1, sizeof(path1), "%s/%s/cur", xmaildir, de->d_name );
|
|
|
|
if (stat( path1, &st ) || !S_ISDIR( st.st_mode ))
|
|
|
|
continue;
|
|
|
|
global.path = de->d_name;
|
|
|
|
global.box = (inbox && !strcmp( inbox, global.path )) ?
|
|
|
|
"INBOX" : global.path;
|
|
|
|
convert( &global );
|
|
|
|
}
|
|
|
|
closedir( dir );
|
|
|
|
} else
|
|
|
|
for (box = boxes; box; box = box->next)
|
|
|
|
convert( box );
|
|
|
|
} else {
|
|
|
|
for (i = optind; argv[i]; i++)
|
|
|
|
if (o2o) {
|
|
|
|
global.path = argv[i];
|
|
|
|
global.box =
|
|
|
|
(inbox && !strcmp( global.path, inbox )) ?
|
|
|
|
"INBOX" : global.path;
|
|
|
|
convert( &global );
|
|
|
|
} else
|
|
|
|
convert( find_box( argv[i] ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (writeout) {
|
|
|
|
if (!outconfig) {
|
|
|
|
const char *p = strrchr( config, '/' );
|
|
|
|
if (!p)
|
|
|
|
p = config;
|
|
|
|
p = strrstr( p, "isync" );
|
|
|
|
if (!p)
|
|
|
|
nfsnprintf( path2, sizeof(path2), "%s.mbsync", config );
|
|
|
|
else
|
|
|
|
nfsnprintf( path2, sizeof(path2), "%.*smb%s", p - config, config, p + 1 );
|
|
|
|
outconfig = path2;
|
|
|
|
}
|
|
|
|
if ((fd = creat( outconfig, 0666 )) < 0) {
|
|
|
|
fprintf( stderr, "Error: cannot write new config %s: %s\n", outconfig, strerror(errno) );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
strcpy( path2, "/tmp/mbsyncrcXXXXXX" );
|
|
|
|
if ((fd = mkstemp( path2 )) < 0) {
|
|
|
|
fprintf( stderr, "Can't create temp file\n" );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
write_config( fd );
|
|
|
|
|
|
|
|
if (writeout)
|
|
|
|
return 0;
|
|
|
|
args = 0;
|
|
|
|
add_arg( &args, "mbsync" );
|
|
|
|
if (Verbose)
|
|
|
|
add_arg( &args, "-V" );
|
|
|
|
if (Debug)
|
|
|
|
add_arg( &args, "-D" );
|
|
|
|
for (; Quiet; Quiet--)
|
|
|
|
add_arg( &args, "-q" );
|
|
|
|
add_arg( &args, "-cT" );
|
|
|
|
add_arg( &args, path2 );
|
|
|
|
if (ops & OP_FAST)
|
|
|
|
add_arg( &args, "-Ln" );
|
|
|
|
if (ops & OP_CREATE_REMOTE)
|
|
|
|
add_arg( &args, "-Cm" );
|
|
|
|
if (ops & OP_CREATE_LOCAL)
|
|
|
|
add_arg( &args, "-Cs" );
|
|
|
|
if (list)
|
2004-04-27 20:23:22 +00:00
|
|
|
add_arg( &args, "-lC" );
|
2004-03-27 16:07:20 +00:00
|
|
|
if (o2o) {
|
|
|
|
if (all)
|
|
|
|
add_arg( &args, "o2o" );
|
|
|
|
else {
|
|
|
|
char buf[1024];
|
|
|
|
strcpy( buf, "o2o:" );
|
|
|
|
strcat( buf, argv[optind] );
|
|
|
|
while (argv[++optind]) {
|
|
|
|
strcat( buf, "," );
|
|
|
|
strcat( buf, argv[optind] );
|
|
|
|
}
|
|
|
|
add_arg( &args, buf );
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (all)
|
|
|
|
add_arg( &args, "-a" );
|
|
|
|
else
|
|
|
|
for (; argv[optind]; optind++)
|
|
|
|
add_arg( &args, find_box( argv[optind] )->channel_name );
|
|
|
|
}
|
|
|
|
execvp( args[0], args );
|
|
|
|
perror( args[0] );
|
|
|
|
return 1;
|
|
|
|
}
|