123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436 |
- /*
- * 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 <sys/types.h>
- #include <sys/stat.h>
- #include <sys/param.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <limits.h>
- #include <pwd.h>
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <dirent.h>
- #ifdef HAVE_GETOPT_LONG
- # 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'},
- {"pass", 1, NULL, 'P'},
- {"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-2006,2008,2010-2012 Oswald Buddenhagen <ossi@users.sf.net>\n"
- "Copyright (C) 2004 Theodore Ts'o <tytso@mit.edu>\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"
- " -P, --pass PASSWORD IMAP password\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;
- int o2o, altmap, delete, expunge;
- const char *Home;
- int HomeLen;
- 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;
- }
- HomeLen = strlen( Home );
- /* defaults */
- /* XXX the precedence is borked:
- it's defaults < cmdline < file instead of defaults < file < cmdline */
- #ifdef BSD
- global.user = getenv( "USER" );
- #else
- global.user = getenv( "LOGNAME" );
- #endif
- 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:P:r:F:M:1I:s:vVD"
- mod = all = list = ops = writeout = Quiet = Verbose = Debug = 0;
- #ifdef 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':
- delete = 1;
- break;
- case 'e':
- expunge = 1;
- 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':
- #ifdef 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 'P':
- global.pass = optarg;
- mod = 1;
- break;
- case 'D':
- Debug = 1;
- break;
- case 'V':
- Verbose++;
- 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 ))) {
- sys_error( "Cannot list '%s'", xmaildir );
- return 1;
- }
- while ((de = readdir( dir ))) {
- if (*de->d_name == '.')
- continue;
- nfsnprintf( path2, sizeof(path2), "%s/%s/cur", xmaildir, de->d_name );
- if (stat( path2, &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) {
- sys_error( "Error: cannot create config file '%s'", outconfig );
- return 1;
- }
- } else {
- strcpy( path2, "/tmp/mbsyncrcXXXXXX" );
- if ((fd = mkstemp( path2 )) < 0) {
- sys_error( "Error: cannot create temporary config file" );
- return 1;
- }
- }
- write_config( fd );
- if (writeout)
- return 0;
- args = 0;
- add_arg( &args, "mbsync" );
- while (--Verbose >= 0)
- 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)
- add_arg( &args, "-lC" );
- 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 );
- sys_error( "Cannot execute %s", args[0] );
- return 1;
- }
|