mirror of https://git.code.sf.net/p/isync/isync
Browse Source
it was deprecated in 1.2. until 1.4 gets released, enough time will have passed for sure.1.4
Oswald Buddenhagen
7 years ago
16 changed files with 14 additions and 1994 deletions
@ -1,12 +0,0 @@ |
|||||||
bin_PROGRAMS = isync
|
|
||||||
|
|
||||||
isync_SOURCES = main.c config.c convert.c util.c
|
|
||||||
isync_LDADD = $(DB_LIBS)
|
|
||||||
noinst_HEADERS = isync.h
|
|
||||||
|
|
||||||
man_MANS = isync.1
|
|
||||||
|
|
||||||
exampledir = $(docdir)/examples
|
|
||||||
example_DATA = isyncrc.sample
|
|
||||||
|
|
||||||
EXTRA_DIST = $(example_DATA) $(man_MANS)
|
|
@ -1,551 +0,0 @@ |
|||||||
/*
|
|
||||||
* 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 <unistd.h> |
|
||||||
#include <limits.h> |
|
||||||
#include <errno.h> |
|
||||||
#include <pwd.h> |
|
||||||
#include <sys/types.h> |
|
||||||
#include <string.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <stdio.h> |
|
||||||
#include <ctype.h> |
|
||||||
|
|
||||||
static char * |
|
||||||
my_strndup( const char *s, size_t nchars ) |
|
||||||
{ |
|
||||||
char *r = nfmalloc( sizeof(char) * (nchars + 1) ); |
|
||||||
memcpy( r, s, nchars ); |
|
||||||
r[nchars] = 0; |
|
||||||
return r; |
|
||||||
} |
|
||||||
|
|
||||||
char * |
|
||||||
expand_strdup( const char *s ) |
|
||||||
{ |
|
||||||
struct passwd *pw; |
|
||||||
const char *p, *q; |
|
||||||
char *r; |
|
||||||
|
|
||||||
if (*s == '~') { |
|
||||||
s++; |
|
||||||
if (!*s) { |
|
||||||
p = 0; |
|
||||||
q = Home; |
|
||||||
} else if (*s == '/') { |
|
||||||
p = s + 1; |
|
||||||
q = Home; |
|
||||||
} else { |
|
||||||
if ((p = strchr( s, '/' ))) { |
|
||||||
r = my_strndup( s, (int)(p - s) ); |
|
||||||
pw = getpwnam( r ); |
|
||||||
free( r ); |
|
||||||
p++; |
|
||||||
} else |
|
||||||
pw = getpwnam( s ); |
|
||||||
if (!pw) |
|
||||||
return 0; |
|
||||||
q = pw->pw_dir; |
|
||||||
} |
|
||||||
nfasprintf( &r, "%s/%s", q, p ? p : "" ); |
|
||||||
return r; |
|
||||||
} else if (*s != '/' && xmaildir) { |
|
||||||
nfasprintf( &r, "%s/%s", xmaildir, s ); |
|
||||||
return r; |
|
||||||
} else |
|
||||||
return nfstrdup( s ); |
|
||||||
} |
|
||||||
|
|
||||||
static int |
|
||||||
is_true( const char *val ) |
|
||||||
{ |
|
||||||
return |
|
||||||
!strcasecmp( val, "yes" ) || |
|
||||||
!strcasecmp( val, "true" ) || |
|
||||||
!strcasecmp( val, "on" ) || |
|
||||||
!strcmp( val, "1" ); |
|
||||||
} |
|
||||||
|
|
||||||
void |
|
||||||
load_config( const char *path, config_t ***stor ) |
|
||||||
{ |
|
||||||
config_t **sstor, *cfg; |
|
||||||
FILE *fp; |
|
||||||
char *p, *cmd, *val; |
|
||||||
int line = 0; |
|
||||||
char buf[1024]; |
|
||||||
|
|
||||||
if (!(fp = fopen( path, "r" ))) { |
|
||||||
if (errno != ENOENT) |
|
||||||
sys_error( "Cannot read config file '%s'", path ); |
|
||||||
return; |
|
||||||
} |
|
||||||
if (!Quiet && !Debug && !Verbose) |
|
||||||
printf( "Reading configuration file %s\n", path ); |
|
||||||
buf[sizeof(buf) - 1] = 0; |
|
||||||
cfg = &global; |
|
||||||
while (fgets( buf, sizeof(buf) - 1, fp )) { |
|
||||||
p = buf; |
|
||||||
cmd = next_arg( &p ); |
|
||||||
val = next_arg( &p ); |
|
||||||
line++; |
|
||||||
if (!cmd || *cmd == '#') |
|
||||||
continue; |
|
||||||
if (!val) { |
|
||||||
fprintf( stderr, "%s:%d: parameter missing\n", path, line ); |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (!strcasecmp( "Mailbox", cmd )) { |
|
||||||
if (o2o) |
|
||||||
break; |
|
||||||
cfg = **stor = nfmalloc( sizeof(config_t) ); |
|
||||||
*stor = &cfg->next; |
|
||||||
memcpy( cfg, &global, sizeof(config_t) ); |
|
||||||
/* not expanded at this point */ |
|
||||||
cfg->path = nfstrdup( val ); |
|
||||||
} else if (!strcasecmp( "OneToOne", cmd )) { |
|
||||||
if (boxes) { |
|
||||||
forbid: |
|
||||||
fprintf( stderr, |
|
||||||
"%s:%d: keyword '%s' allowed only in global section\n", |
|
||||||
path, line, cmd ); |
|
||||||
continue; |
|
||||||
} |
|
||||||
o2o = is_true( val ); |
|
||||||
} else if (!strcasecmp( "Maildir", cmd )) { |
|
||||||
if (boxes) |
|
||||||
goto forbid; |
|
||||||
maildir = nfstrdup( val ); |
|
||||||
xmaildir = expand_strdup( val ); |
|
||||||
} else if (!strcasecmp( "Folder", cmd )) { |
|
||||||
if (boxes) |
|
||||||
goto forbid; |
|
||||||
folder = nfstrdup( val ); |
|
||||||
} else if (!strcasecmp( "Inbox", cmd )) { |
|
||||||
if (boxes) |
|
||||||
goto forbid; |
|
||||||
inbox = nfstrdup( val ); |
|
||||||
} else if (!strcasecmp( "Host", cmd )) { |
|
||||||
if (starts_with( val, -1, "imaps:", 6 )) { |
|
||||||
val += 6; |
|
||||||
cfg->use_imaps = 1; |
|
||||||
cfg->port = 993; |
|
||||||
cfg->use_sslv3 = 1; |
|
||||||
} |
|
||||||
cfg->host = nfstrdup( val ); |
|
||||||
} else if (!strcasecmp( "User", cmd )) |
|
||||||
cfg->user = nfstrdup( val ); |
|
||||||
else if (!strcasecmp( "Pass", cmd )) |
|
||||||
cfg->pass = nfstrdup( val ); |
|
||||||
else if (!strcasecmp ( "Port", cmd )) |
|
||||||
cfg->port = atoi( val ); |
|
||||||
else if (!strcasecmp ( "Box", cmd )) |
|
||||||
cfg->box = nfstrdup( val ); |
|
||||||
else if (!strcasecmp ( "Alias", cmd )) { |
|
||||||
if (!boxes) { |
|
||||||
fprintf( stderr, |
|
||||||
"%s:%d: keyword 'Alias' allowed only in mailbox specification\n", |
|
||||||
path, line ); |
|
||||||
continue; |
|
||||||
} |
|
||||||
cfg->alias = nfstrdup( val ); |
|
||||||
} else if (!strcasecmp( "MaxSize", cmd )) |
|
||||||
cfg->max_size = atol( val ); |
|
||||||
else if (!strcasecmp ( "MaxMessages", cmd )) |
|
||||||
cfg->max_messages = atol( val ); |
|
||||||
else if (!strcasecmp ( "UseNamespace", cmd )) |
|
||||||
cfg->use_namespace = is_true( val ); |
|
||||||
else if (!strcasecmp ( "CopyDeletedTo", cmd )) |
|
||||||
cfg->copy_deleted_to = nfstrdup( val ); |
|
||||||
else if (!strcasecmp ( "Tunnel", cmd )) |
|
||||||
cfg->tunnel = nfstrdup( val ); |
|
||||||
else if (!strcasecmp ( "Expunge", cmd )) |
|
||||||
cfg->expunge = is_true( val ); |
|
||||||
else if (!strcasecmp( "Delete", cmd )) |
|
||||||
cfg->delete = is_true( val ); |
|
||||||
else if (!strcasecmp( "CertificateFile", cmd )) |
|
||||||
cfg->cert_file = expand_strdup( val ); |
|
||||||
else if (!strcasecmp( "RequireSSL", cmd )) |
|
||||||
cfg->require_ssl = is_true( val ); |
|
||||||
else if (!strcasecmp( "UseSSLv2", cmd )) |
|
||||||
fprintf( stderr, "Warning: UseSSLv2 is no longer supported\n" ); |
|
||||||
else if (!strcasecmp( "UseSSLv3", cmd )) |
|
||||||
cfg->use_sslv3 = is_true( val ); |
|
||||||
else if (!strcasecmp( "UseTLSv1", cmd )) |
|
||||||
cfg->use_tlsv1 = is_true( val ); |
|
||||||
else if (!strcasecmp( "RequireCRAM", cmd )) |
|
||||||
cfg->require_cram = is_true( val ); |
|
||||||
else if (buf[0]) |
|
||||||
fprintf( stderr, "%s:%d: unknown keyword '%s'\n", path, line, cmd ); |
|
||||||
} |
|
||||||
fclose( fp ); |
|
||||||
if (o2o) { |
|
||||||
if (!global.host && !global.tunnel) { |
|
||||||
fprintf( stderr, "Neither Host nor Tunnel given to OneToOne. Aborting.\n" ); |
|
||||||
exit( 1 ); |
|
||||||
} |
|
||||||
} else |
|
||||||
for (sstor = &boxes; (cfg = *sstor); ) { |
|
||||||
if (!cfg->host && !cfg->tunnel) { |
|
||||||
fprintf( stderr, "Mailbox '%s' has neither Host nor Tunnel. Skipping.\n", |
|
||||||
cfg->alias ? cfg->alias : cfg->path ); |
|
||||||
if (&cfg->next == *stor) |
|
||||||
*stor = sstor; |
|
||||||
*sstor = cfg->next; |
|
||||||
continue; |
|
||||||
} |
|
||||||
sstor = &cfg->next; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
static const char * |
|
||||||
tb( int on ) |
|
||||||
{ |
|
||||||
return on ? "yes" : "no"; |
|
||||||
} |
|
||||||
|
|
||||||
static const char * |
|
||||||
quotify( const char *str ) |
|
||||||
{ |
|
||||||
char *ostr; |
|
||||||
int i; |
|
||||||
|
|
||||||
for (i = 0; str[i]; i++) { |
|
||||||
if (isspace( str[i] )) { |
|
||||||
nfasprintf( &ostr, "\"%s\"", str ); |
|
||||||
return ostr; |
|
||||||
} |
|
||||||
} |
|
||||||
return str; |
|
||||||
} |
|
||||||
|
|
||||||
static void |
|
||||||
write_imap_server( FILE *fp, config_t *cfg ) |
|
||||||
{ |
|
||||||
config_t *pbox; |
|
||||||
char *p, *p2; |
|
||||||
int hl, a1, a2, a3, a4; |
|
||||||
char buf[128], ubuf[64]; |
|
||||||
static int tunnels; |
|
||||||
|
|
||||||
/* The old server names determine the derived store names. They are kinda stupid,
|
|
||||||
* but can't be changed, because store names are encoded in state file names. */ |
|
||||||
if (cfg->tunnel) |
|
||||||
nfasprintf( (char **)&cfg->old_server_name, "tunnel%d", ++tunnels ); |
|
||||||
else { |
|
||||||
if (sscanf( cfg->host, "%d.%d.%d.%d", &a1, &a2, &a3, &a4 ) == 4) |
|
||||||
hl = nfsnprintf( buf, sizeof(buf), "%s", cfg->host ); |
|
||||||
else { |
|
||||||
/* XXX this does not avoid clashes. add port? */ |
|
||||||
p = strrchr( cfg->host, '.' ); |
|
||||||
if (!p) |
|
||||||
hl = nfsnprintf( buf, sizeof(buf), "%s", cfg->host ); |
|
||||||
else { |
|
||||||
hl = nfsnprintf( buf, sizeof(buf), "%.*s", p - cfg->host, cfg->host ); |
|
||||||
p2 = strrchr( buf, '.' ); |
|
||||||
if (p2) |
|
||||||
hl = sprintf( buf, "%s", p2 + 1 ); |
|
||||||
} |
|
||||||
} |
|
||||||
if (boxes) /* !o2o */ |
|
||||||
for (pbox = boxes; pbox != cfg; pbox = pbox->next) |
|
||||||
if (equals( pbox->old_server_name, -1, buf, hl )) { |
|
||||||
nfasprintf( (char **)&cfg->old_server_name, "%s-%d", buf, ++pbox->old_servers ); |
|
||||||
goto gotsrv; |
|
||||||
} |
|
||||||
cfg->old_server_name = nfstrdup( buf ); |
|
||||||
cfg->old_servers = 1; |
|
||||||
gotsrv: ; |
|
||||||
} |
|
||||||
|
|
||||||
/* The "new" server names determine the names of the accounts themselves.
|
|
||||||
* They are optimized for descriptiveness, e.g. in password prompts. */ |
|
||||||
if (cfg->user) |
|
||||||
nfsnprintf( ubuf, sizeof(ubuf), "%s@", cfg->user ); |
|
||||||
else |
|
||||||
ubuf[0] = 0; |
|
||||||
if (!cfg->host) |
|
||||||
hl = nfsnprintf( buf, sizeof(buf), "%stunnel", ubuf ); |
|
||||||
else { |
|
||||||
if (cfg->port != (cfg->use_imaps ? 993 : 143)) |
|
||||||
hl = nfsnprintf( buf, sizeof(buf), "%s%s_%d", ubuf, cfg->host, cfg->port ); |
|
||||||
else |
|
||||||
hl = nfsnprintf( buf, sizeof(buf), "%s%s", ubuf, cfg->host ); |
|
||||||
} |
|
||||||
if (boxes) /* !o2o */ |
|
||||||
for (pbox = boxes; pbox != cfg; pbox = pbox->next) |
|
||||||
if (equals( pbox->server_name, -1, buf, hl )) { |
|
||||||
nfasprintf( (char **)&cfg->server_name, "%s-%d", buf, ++pbox->servers ); |
|
||||||
goto ngotsrv; |
|
||||||
} |
|
||||||
cfg->server_name = nfstrdup( buf ); |
|
||||||
cfg->servers = 1; |
|
||||||
ngotsrv: ; |
|
||||||
|
|
||||||
fprintf( fp, "IMAPAccount %s\n", cfg->server_name ); |
|
||||||
if (cfg->tunnel) |
|
||||||
fprintf( fp, "Tunnel \"%s\"\n", cfg->tunnel ); |
|
||||||
else { |
|
||||||
if (cfg->use_imaps) |
|
||||||
fprintf( fp, "Host imaps:%s\n", cfg->host ); |
|
||||||
else |
|
||||||
fprintf( fp, "Host %s\n", cfg->host ); |
|
||||||
fprintf( fp, "Port %d\n", cfg->port ); |
|
||||||
} |
|
||||||
if (cfg->user) |
|
||||||
fprintf( fp, "User %s\n", quotify( cfg->user ) ); |
|
||||||
if (cfg->pass) |
|
||||||
fprintf( fp, "Pass %s\n", quotify( cfg->pass ) ); |
|
||||||
fprintf( fp, "RequireCRAM %s\nRequireSSL %s\n" |
|
||||||
"UseSSLv3 %s\nUseTLSv1 %s\nUseTLSv1.1 %s\nUseTLSv1.2 %s\n", |
|
||||||
tb(cfg->require_cram), tb(cfg->require_ssl), |
|
||||||
tb(cfg->use_sslv3), tb(cfg->use_tlsv1), tb(cfg->use_tlsv1), tb(cfg->use_tlsv1) ); |
|
||||||
if ((cfg->use_imaps || cfg->use_sslv3 || cfg->use_tlsv1) && cfg->cert_file) |
|
||||||
fprintf( fp, "CertificateFile %s\n", quotify( cfg->cert_file ) ); |
|
||||||
fputc( '\n', fp ); |
|
||||||
} |
|
||||||
|
|
||||||
static void |
|
||||||
write_imap_store( FILE *fp, config_t *cfg ) |
|
||||||
{ |
|
||||||
if (cfg->stores > 1) |
|
||||||
nfasprintf( (char **)&cfg->store_name, "%s-%d", cfg->old_server_name, cfg->stores ); |
|
||||||
else |
|
||||||
cfg->store_name = cfg->old_server_name; |
|
||||||
fprintf( fp, "IMAPStore %s\nAccount %s\n", |
|
||||||
cfg->store_name, cfg->server_name ); |
|
||||||
if (*folder) |
|
||||||
fprintf( fp, "Path %s\n", quotify( folder ) ); |
|
||||||
else |
|
||||||
fprintf( fp, "UseNamespace %s\n", tb(cfg->use_namespace) ); |
|
||||||
if (inbox) |
|
||||||
fprintf( fp, "MapInbox %s\n", quotify( inbox ) ); |
|
||||||
if (cfg->copy_deleted_to) |
|
||||||
fprintf( fp, "Trash %s\n", quotify( cfg->copy_deleted_to ) ); |
|
||||||
fputc( '\n', fp ); |
|
||||||
} |
|
||||||
|
|
||||||
static void |
|
||||||
write_channel_parm( FILE *fp, config_t *cfg ) |
|
||||||
{ |
|
||||||
if (cfg->max_size) |
|
||||||
fprintf( fp, "MaxSize %d\n", cfg->max_size ); |
|
||||||
if (cfg->max_messages) |
|
||||||
fprintf( fp, "MaxMessages %d\n", cfg->max_messages ); |
|
||||||
if (cfg->delete && !global.delete && !delete) |
|
||||||
fputs( "Sync All\n", fp ); |
|
||||||
if (cfg->expunge && !global.expunge && !expunge) |
|
||||||
fputs( "Expunge Both\n", fp ); |
|
||||||
fputc( '\n', fp ); |
|
||||||
} |
|
||||||
|
|
||||||
static int |
|
||||||
mstrcmp( const char *s1, const char *s2 ) |
|
||||||
{ |
|
||||||
if (s1 == s2) |
|
||||||
return 0; |
|
||||||
if (!s1 || !s2) |
|
||||||
return 1; |
|
||||||
return strcmp( s1, s2 ); |
|
||||||
} |
|
||||||
|
|
||||||
void |
|
||||||
write_config( int fd ) |
|
||||||
{ |
|
||||||
FILE *fp; |
|
||||||
const char *cn, *scn; |
|
||||||
char *path, *local_box, *local_store; |
|
||||||
config_t *box, *sbox, *pbox; |
|
||||||
int pl; |
|
||||||
|
|
||||||
if (!(fp = fdopen( fd, "w" ))) { |
|
||||||
perror( "fdopen" ); |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
fputs( "SyncState *\n", fp ); |
|
||||||
if (!global.delete && !delete) |
|
||||||
fputs( "Sync New ReNew Flags\n", fp ); |
|
||||||
if (global.expunge || expunge) |
|
||||||
fputs( "Expunge Both\n", fp ); |
|
||||||
fputc( '\n', fp ); |
|
||||||
if (o2o) { |
|
||||||
write_imap_server( fp, &global ); |
|
||||||
write_imap_store( fp, &global ); |
|
||||||
fprintf( fp, "MaildirStore local\nPath %s/\n", quotify( maildir ) ); |
|
||||||
if (!inbox) { /* just in case listing actually produces an INBOX ... */ |
|
||||||
nfasprintf( (char **)&inbox, "%s/INBOX", maildir ); |
|
||||||
fprintf( fp, "Inbox %s\n", quotify( inbox ) ); |
|
||||||
} |
|
||||||
if (altmap > 0) |
|
||||||
fputs( "AltMap yes\n", fp ); |
|
||||||
fprintf( fp, "\nChannel o2o\nMaster :%s:\nSlave :local:\nPattern %%\n", global.store_name ); |
|
||||||
write_channel_parm( fp, &global ); |
|
||||||
} else { |
|
||||||
for (box = boxes; box; box = box->next) { |
|
||||||
for (pbox = boxes; pbox != box; pbox = pbox->next) { |
|
||||||
if (box->tunnel) { |
|
||||||
if (mstrcmp( pbox->tunnel, box->tunnel )) |
|
||||||
continue; |
|
||||||
} else { |
|
||||||
if (mstrcmp( pbox->host, box->host ) || |
|
||||||
pbox->use_imaps != box->use_imaps || |
|
||||||
pbox->port != box->port) |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (mstrcmp( pbox->user, box->user ) || |
|
||||||
mstrcmp( pbox->pass, box->pass )) /* nonsense */ |
|
||||||
continue; |
|
||||||
if ((box->use_imaps || |
|
||||||
box->use_sslv3 || box->use_tlsv1) && |
|
||||||
mstrcmp( pbox->cert_file, box->cert_file )) /* nonsense */ |
|
||||||
continue; |
|
||||||
if (pbox->use_imaps != box->use_imaps || |
|
||||||
pbox->use_sslv3 != box->use_sslv3 || |
|
||||||
pbox->use_tlsv1 != box->use_tlsv1) |
|
||||||
continue; |
|
||||||
box->server_name = pbox->server_name; |
|
||||||
for (sbox = boxes; sbox != box; sbox = sbox->next) { |
|
||||||
if (sbox->server_name != box->server_name || |
|
||||||
mstrcmp( sbox->copy_deleted_to, box->copy_deleted_to ) || |
|
||||||
(!*folder && sbox->use_namespace != box->use_namespace)) |
|
||||||
continue; |
|
||||||
box->store_name = sbox->store_name; |
|
||||||
goto gotall; |
|
||||||
} |
|
||||||
box->stores = ++pbox->stores; |
|
||||||
goto gotsrv; |
|
||||||
} |
|
||||||
write_imap_server( fp, box ); |
|
||||||
box->stores = 1; |
|
||||||
gotsrv: |
|
||||||
write_imap_store( fp, box ); |
|
||||||
gotall: |
|
||||||
|
|
||||||
path = expand_strdup( box->path ); |
|
||||||
if (starts_with( path, -1, Home, HomeLen ) && path[HomeLen] == '/') |
|
||||||
nfasprintf( &path, "~%s", path + HomeLen ); |
|
||||||
local_store = local_box = strrchr( path, '/' ) + 1; |
|
||||||
pl = local_store - path; |
|
||||||
/* try to re-use existing store */ |
|
||||||
for (pbox = boxes; pbox != box; pbox = pbox->next) |
|
||||||
if (pbox->local_store_path && equals( pbox->local_store_path, -1, path, pl )) |
|
||||||
goto gotstor; |
|
||||||
box->local_store_path = my_strndup( path, pl ); |
|
||||||
/* derive a suitable name */ |
|
||||||
if (!strcmp( box->local_store_path, "/var/mail/" ) || !strcmp( box->local_store_path, "/var/spool/mail/" )) { |
|
||||||
local_store = nfstrdup( "spool" ); |
|
||||||
} else if (!strcmp( box->local_store_path, "~/" )) { |
|
||||||
local_store = nfstrdup( "home" ); |
|
||||||
} else { |
|
||||||
local_store = memrchr( box->local_store_path, '/', pl - 1 ); |
|
||||||
if (local_store) { |
|
||||||
local_store = my_strndup( local_store + 1, pl - 2 - (local_store - box->local_store_path) ); |
|
||||||
for (pl = 0; local_store[pl]; pl++) |
|
||||||
local_store[pl] = tolower( local_store[pl] ); |
|
||||||
} else { |
|
||||||
local_store = nfstrdup( "local" ); |
|
||||||
} |
|
||||||
} |
|
||||||
/* avoid name clashes with imap stores */ |
|
||||||
for (pbox = boxes; pbox != box; pbox = pbox->next) |
|
||||||
if (!strcmp( pbox->store_name, local_store )) { |
|
||||||
nfasprintf( &local_store, "local_%s", local_store ); |
|
||||||
goto gotsdup; |
|
||||||
} |
|
||||||
gotsdup: |
|
||||||
/* avoid name clashes with other local stores */ |
|
||||||
for (pbox = boxes; pbox != box; pbox = pbox->next) |
|
||||||
if (pbox->local_store_name && !strcmp( pbox->local_store_name, local_store )) { |
|
||||||
nfasprintf( (char **)&box->local_store_name, "%s-%d", local_store, ++pbox->local_stores ); |
|
||||||
goto gotdup; |
|
||||||
} |
|
||||||
box->local_store_name = local_store; |
|
||||||
box->local_stores = 1; |
|
||||||
gotdup: |
|
||||||
fprintf( fp, "MaildirStore %s\nPath %s\n", box->local_store_name, quotify( box->local_store_path ) ); |
|
||||||
if (altmap > 0) |
|
||||||
fputs( "AltMap yes\n", fp ); |
|
||||||
fputc( '\n', fp ); |
|
||||||
pbox = box; |
|
||||||
gotstor: |
|
||||||
|
|
||||||
if (box->alias) |
|
||||||
cn = box->alias; |
|
||||||
else { |
|
||||||
cn = strrchr( box->path, '/' ); |
|
||||||
if (cn) |
|
||||||
cn++; |
|
||||||
else |
|
||||||
cn = box->path; |
|
||||||
} |
|
||||||
for (sbox = boxes; sbox != box; sbox = sbox->next) { |
|
||||||
if (sbox->alias) |
|
||||||
scn = sbox->alias; |
|
||||||
else { |
|
||||||
scn = strrchr( sbox->path, '/' ); |
|
||||||
if (scn) |
|
||||||
scn++; |
|
||||||
else |
|
||||||
scn = sbox->path; |
|
||||||
} |
|
||||||
if (mstrcmp( cn, scn )) |
|
||||||
continue; |
|
||||||
nfasprintf( (char **)&box->channel_name, "%s-%d", cn, ++sbox->channels ); |
|
||||||
goto gotchan; |
|
||||||
} |
|
||||||
box->channels = 1; |
|
||||||
box->channel_name = cn; |
|
||||||
gotchan: |
|
||||||
|
|
||||||
fprintf( fp, "Channel %s\nMaster :%s:%s\nSlave :%s:%s\n", |
|
||||||
box->channel_name, box->store_name, quotify( box->box ), pbox->local_store_name, quotify( local_box ) ); |
|
||||||
write_channel_parm( fp, box ); |
|
||||||
} |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
fclose( fp ); |
|
||||||
} |
|
||||||
|
|
||||||
config_t * |
|
||||||
find_box( const char *s ) |
|
||||||
{ |
|
||||||
config_t *p; |
|
||||||
char *t; |
|
||||||
|
|
||||||
if (starts_with( s, -1, Home, HomeLen ) && s[HomeLen] == '/') |
|
||||||
s += HomeLen + 1; |
|
||||||
for (p = boxes; p; p = p->next) { |
|
||||||
if (!strcmp( s, p->path ) || (p->alias && !strcmp( s, p->alias ))) |
|
||||||
return p; |
|
||||||
/* check to see if the full pathname was specified on the
|
|
||||||
* command line. |
|
||||||
*/ |
|
||||||
t = expand_strdup( p->path ); |
|
||||||
if (!strcmp( s, t )) { |
|
||||||
free( t ); |
|
||||||
return p; |
|
||||||
} |
|
||||||
free( t ); |
|
||||||
} |
|
||||||
return 0; |
|
||||||
} |
|
@ -1,265 +0,0 @@ |
|||||||
/*
|
|
||||||
* 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; |
|
||||||
} |
|
@ -1,328 +0,0 @@ |
|||||||
.ig |
|
||||||
\" 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/>. |
|
||||||
\" |
|
||||||
.. |
|
||||||
.TH isync 1 "2010 Feb 7" |
|
||||||
.. |
|
||||||
.SH NAME |
|
||||||
isync - synchronize IMAP4 and Maildir mailboxes |
|
||||||
.. |
|
||||||
.SH SYNOPSIS |
|
||||||
\fBisync\fR [\fIoptions\fR ...] {\fImailbox\fR ...|\fI-a\fR|\fI-l\fR} |
|
||||||
.. |
|
||||||
.SH DESCRIPTION |
|
||||||
\fBisync\fR is a command line application which synchronizes local |
|
||||||
Maildir mailboxes with remote IMAP4 mailboxes, suitable for use in |
|
||||||
IMAP-disconnected mode. Multiple copies of the remote IMAP4 mailboxes can |
|
||||||
be maintained, and all flags are synchronized. |
|
||||||
.br |
|
||||||
\fBisync\fR is only a wrapper binary around \fBmbsync\fR to simplify upgrades. |
|
||||||
It will automatically migrate the UID mapping from previous versions of |
|
||||||
\fBisync\fR (even before 0.8) to the new format, and transparently call |
|
||||||
\fBmbsync\fR. If you were using \fBisync\fR version 0.8 or 0.9.x you might |
|
||||||
want to use \fBmdconvert\fR to convert the mailboxes to the more efficient |
|
||||||
\fBnative\fR UID storage scheme after migrating them. |
|
||||||
.br |
|
||||||
\fBisync\fR is deprecated. Please use the \fB-w\fR option to permanently |
|
||||||
migrate the configuration and start using \fBmbsync\fR directly. |
|
||||||
.. |
|
||||||
.SH OPTIONS |
|
||||||
.TP |
|
||||||
\fB-c\fR, \fB--config\fR \fIfile\fR |
|
||||||
Read configuration from \fIfile\fR. |
|
||||||
By default, the configuration is read from ~/.isyncrc if it exists. |
|
||||||
.TP |
|
||||||
\fB-1\fR, \fB--one-to-one\fR |
|
||||||
Instead of using the mailbox specifications in ~/.isyncrc, isync will pick up |
|
||||||
all mailboxes from the local directory and remote folder and map them 1:1 |
|
||||||
onto each other according to their names. |
|
||||||
.TP |
|
||||||
\fB-I\fR, \fB--inbox\fR \fImailbox\fR |
|
||||||
Exception to the 1:1 mapping created by -1: the special IMAP mailbox \fIINBOX\fR |
|
||||||
is mapped to the local \fImailbox\fR (relative to the maildir). |
|
||||||
.TP |
|
||||||
\fB-a\fR, \fB--all\fR |
|
||||||
Synchronize all mailboxes (either specified in ~/.isyncrc or determined by the |
|
||||||
1:1 mapping). |
|
||||||
.TP |
|
||||||
\fB-l\fR, \fB--list\fR |
|
||||||
Don't synchronize anything, but list all mailboxes and exit. |
|
||||||
.TP |
|
||||||
\fB-L\fR, \fB--create-local\fR |
|
||||||
Automatically create the local Maildir mailbox if it doesn't already |
|
||||||
exist. |
|
||||||
.TP |
|
||||||
\fB-R\fR, \fB--create-remote\fR |
|
||||||
Automatically create the remote IMAP mailbox if it doesn't already exist. |
|
||||||
.TP |
|
||||||
\fB-C\fR, \fB--create\fR |
|
||||||
Automatically create any mailboxes if they don't already exist. |
|
||||||
This is simply a combination of -L and -R. |
|
||||||
.TP |
|
||||||
\fB-d\fR, \fB--delete\fR |
|
||||||
Causes \fBisync\fR to propagate message deletions. |
|
||||||
By default, \fIdead\fR messages are \fBnot\fR deleted. |
|
||||||
.TP |
|
||||||
\fB-e\fR, \fB--expunge\fR |
|
||||||
Causes \fBisync\fR to permanently remove all messages marked for deletion. |
|
||||||
By default, \fIdeleted\fR messages are \fBnot\fR expunged. |
|
||||||
.TP |
|
||||||
\fB-f\fR, \fB--fast\fR |
|
||||||
Only fetch new messages existing on the server into the local mailbox. |
|
||||||
Message deletions and flag changes will not be propagated. |
|
||||||
.TP |
|
||||||
\fB-h\fR, \fB--help\fR |
|
||||||
Displays a summary of command line options |
|
||||||
.TP |
|
||||||
\fB-p\fR, \fB--port\fR \fIport\fR |
|
||||||
Specifies the port on the IMAP server to connect to (default: 143 for imap, |
|
||||||
993 for imaps) |
|
||||||
.TP |
|
||||||
\fB-q\fR, \fB--quiet\fR |
|
||||||
Suppress informational messages. |
|
||||||
If specified twice, suppress warning messages as well. |
|
||||||
.TP |
|
||||||
\fB-r\fR, \fB--remote\fR \fIbox\fR |
|
||||||
Specifies the name of the remote IMAP mailbox to synchronize with |
|
||||||
(Default: INBOX) |
|
||||||
.TP |
|
||||||
\fB-s\fR, \fB--host\fR [\fBimaps:\fR]\fIhost\fR |
|
||||||
Specifies the hostname of the IMAP server |
|
||||||
.TP |
|
||||||
\fB-u\fR, \fB--user\fR \fIuser\fR |
|
||||||
Specifies the login name to access the IMAP server (default: $USER) |
|
||||||
.TP |
|
||||||
\fB-P\fR, \fB--pass\fR \fIpassword\fR |
|
||||||
Specifies the password to access the IMAP server (prompted for by default) |
|
||||||
.TP |
|
||||||
\fB-M\fR, \fB--maildir\fR \fIdir\fR |
|
||||||
Specifies the location for your local mailboxes. |
|
||||||
.TP |
|
||||||
\fB-F\fR, \fB--folder\fR \fIfolder\fR/ |
|
||||||
Specifies the location for your remote mailboxes. |
|
||||||
.TP |
|
||||||
\fB-v\fR, \fB--version\fR |
|
||||||
Displays \fBisync\fR version information. |
|
||||||
.TP |
|
||||||
\fB-V\fR, \fB--verbose\fR |
|
||||||
Enables \fIverbose\fR mode, which displays the IMAP4 network traffic. |
|
||||||
.TP |
|
||||||
\fB-D\fR, \fB--debug\fR |
|
||||||
Enable printing of \fIdebug\fR messages. |
|
||||||
.TP |
|
||||||
\fB-w\fR, \fB--write\fR |
|
||||||
Don't run \fBmbsync\fR, but instead write a permanent config file for it. |
|
||||||
The UID mappings of all configured mailboxes will be migrated. |
|
||||||
Note that most command line options that would affect an actual sync operation |
|
||||||
will be incorporated into the new config file as well; exceptions are |
|
||||||
--fast and --create[-remote|-local]. |
|
||||||
The name of the new config file is determined by replacing the last occurrence |
|
||||||
of "isync" with "mbsync", or appending ".mbsync" if "isync" was not found. |
|
||||||
.TP |
|
||||||
\fB-W\fR, \fB--writeto\fR \fIfile\fR |
|
||||||
Like \fB-w\fR, but use the specified name for the new config file. |
|
||||||
.. |
|
||||||
.SH CONFIGURATION |
|
||||||
\fBisync\fR by default reads \fI~/.isyncrc\fR to load configuration data. |
|
||||||
Each non-empty line of the configuration file that does not start with a |
|
||||||
hash mark consists of a command. |
|
||||||
The following commands are understood: |
|
||||||
.TP |
|
||||||
\fBMailbox\fR \fIpath\fR |
|
||||||
Defines a local Maildir mailbox. All configuration commands following this |
|
||||||
line, up until the next \fIMailbox\fR command, apply to this mailbox only. |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBHost\fR [\fBimaps:\fR]\fIname\fR |
|
||||||
Defines the DNS name or IP address of the IMAP server. If the hostname is |
|
||||||
prefixed with \fBimaps:\fR the connection is assumed to be a SSL connection |
|
||||||
to port 993 (though you can change this by placing a \fBPort\fR command |
|
||||||
\fBafter\fR the \fBHost\fR command). |
|
||||||
Note that modern servers support SSL on the default port 143. |
|
||||||
\fBisync\fR will always attempt to use SSL if available. |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBPort\fR \fIport\fR |
|
||||||
Defines the TCP port number of the IMAP server (Default: 143 for imap, |
|
||||||
993 for imaps) |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBBox\fR \fImailbox\fR |
|
||||||
Defines the name of the remote IMAP mailbox associated with the local |
|
||||||
Maildir mailbox (Default: INBOX) |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBUser\fR \fIusername\fR |
|
||||||
Defines the login name on the IMAP server (Default: current user) |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBPass\fR \fIpassword\fR |
|
||||||
Defines the password for \fIusername\fR on the IMAP server. |
|
||||||
Note that this option is \fBNOT\fR required. |
|
||||||
If no password is specified in the configuration file, \fBisync\fR |
|
||||||
will prompt you for it. |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBAlias\fR \fIstring\fR |
|
||||||
Defines an alias for the mailbox which can be used as a shortcut on the |
|
||||||
command line. |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBCopyDeletedTo\fR \fImailbox\fR |
|
||||||
Specifies the remote IMAP mailbox to copy deleted messages to prior to |
|
||||||
expunging (Default: none). |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBDelete\fR \fIyes\fR|\fIno\fR |
|
||||||
Specifies whether message deletions are propagated. (Default: no). |
|
||||||
\fBNOTE:\fR The \fI-d\fR command line option overrides this setting when |
|
||||||
set to \fIno\fR. |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBExpunge\fR \fIyes\fR|\fIno\fR |
|
||||||
Specifies whether deleted messages are expunged. (Default: no). |
|
||||||
\fBNOTE:\fR The \fI-e\fR command line option overrides this setting when |
|
||||||
set to \fIno\fR. |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBMailDir\fR \fIdirectory\fR |
|
||||||
Specifies the location of your local mailboxes if a relative path is |
|
||||||
specified in a \fIMailbox\fR command (Default: \fI~\fR). |
|
||||||
\fBNOTE:\fR This directive is allowed only in the \fIglobal\fR |
|
||||||
section (see below). |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBFolder\fR \fIdirectory\fR/ |
|
||||||
Specifies the location of your IMAP mailboxes |
|
||||||
specified in \fIBox\fR commands (Default: \fI""\fR). |
|
||||||
\fBNOTE:\fR You \fBmust\fR append the hierarchy delimiter (usually |
|
||||||
a slash) to this specification. |
|
||||||
\fBNOTE 2:\fR This directive is allowed only in the \fIglobal\fR |
|
||||||
section (see below). |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBMaxMessages\fR \fIcount\fR |
|
||||||
Sets the number of messages \fBisync\fR should keep in the local copy of a |
|
||||||
mailbox. |
|
||||||
This is useful for mailboxes where you keep a complete archive on the server, |
|
||||||
but want to mirror only the last messages (for instance, for mailing lists). |
|
||||||
The messages that were the first to arrive in the mailbox (independently of the |
|
||||||
actual date of the message) will be deleted first. |
|
||||||
Messages that are flagged (marked as important) and unread messages will not be |
|
||||||
automatically deleted. |
|
||||||
If \fIcount\fR is 0, the maximum number of messages is \fBunlimited\fR. |
|
||||||
(Default: 0) |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBMaxSize\fR \fIbytes\fR |
|
||||||
Messages larger than that many bytes will not be transferred over the wire. |
|
||||||
This is useful for weeding out messages with large attachments. |
|
||||||
If \fIbytes\fR is 0, the maximum file size is \fBunlimited\fR. |
|
||||||
(Default: 0) |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBTunnel\fR \fIcommand\fR |
|
||||||
Specify a command to run to establish a connection rather than opening a TCP |
|
||||||
socket. This allows you to run an IMAP session over an SSH tunnel, for |
|
||||||
example. |
|
||||||
.TP |
|
||||||
\fBUseNamespace\fR \fIyes\fR|\fIno\fR |
|
||||||
Selects whether the server's first "personal" NAMESPACE should be prefixed to |
|
||||||
mailbox names. Disabling this makes sense for some broken IMAP servers. |
|
||||||
This option is meaningless if a \fIFolder\fR was specified. |
|
||||||
(Default: \fIyes\fR) |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBRequireCRAM\fR \fIyes\fR|\fIno\fR |
|
||||||
If set to \fIyes\fR, \fBisync\fR will abort the connection if no CRAM-MD5 |
|
||||||
authentication is possible. (Default: \fIno\fR) |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBRequireSSL\fR \fIyes\fR|\fIno\fR |
|
||||||
\fBisync\fR will abort the connection if a TLS/SSL session cannot be |
|
||||||
established with the IMAP server. (Default: \fIyes\fR) |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBCertificateFile\fR \fIpath\fR |
|
||||||
File containing additional X.509 certificates used to verify server |
|
||||||
identities. Directly matched peer certificates are always trusted, |
|
||||||
regardless of validity. |
|
||||||
.br |
|
||||||
Note that the system's default certificate store is always used |
|
||||||
and should not be specified here. |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBUseSSLv2\fR \fIyes\fR|\fIno\fR |
|
||||||
Should \fBisync\fR use SSLv2 for communication with the IMAP server over SSL? |
|
||||||
(Default: \fIno\fR) |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBUseSSLv3\fR \fIyes\fR|\fIno\fR |
|
||||||
Should \fBisync\fR use SSLv3 for communication with the IMAP server over SSL? |
|
||||||
(Default: \fIyes\fR if the imaps port is used, otherwise \fIno\fR) |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBUseTLSv1\fR \fIyes\fR|\fIno\fR |
|
||||||
Should \fBisync\fR use TLSv1.x for communication with the IMAP server over SSL? |
|
||||||
(Default: \fIyes\fR) |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBOneToOne\fR |
|
||||||
\fBisync\fR will ignore any \fIMailbox\fR specifications and instead pick up |
|
||||||
all mailboxes from the local \fIMailDir\fR and remote \fIFolder\fR and map |
|
||||||
them 1:1 onto each other according to their names. |
|
||||||
\fBNOTE:\fR This directive is allowed only in the \fIglobal\fR |
|
||||||
section (see below). |
|
||||||
.. |
|
||||||
.TP |
|
||||||
\fBInbox\fR \fImailbox\fR |
|
||||||
Exception to the OneToOne mapping: the special IMAP mailbox \fIINBOX\fR |
|
||||||
is mapped to the local \fImailbox\fR (relative to the \fIMailDir\fR). |
|
||||||
\fBNOTE:\fR This directive is only meaningful in the \fIglobal\fR |
|
||||||
section (see below). |
|
||||||
.. |
|
||||||
.P |
|
||||||
Configuration commands that appear prior to the first \fBMailbox\fR |
|
||||||
command are considered to be \fIglobal\fR |
|
||||||
options which are used as defaults when those specific options are not |
|
||||||
specifically set for a defined Mailbox. For example, if you use the same |
|
||||||
login name for several IMAP servers, you can put a \fBUser\fR command before |
|
||||||
the first \fBMailbox\fR command, and then leave out the \fBUser\fR command |
|
||||||
in the sections for each mailbox. |
|
||||||
\fBisync\fR will then use the global value by default. |
|
||||||
.. |
|
||||||
.SH FILES |
|
||||||
.TP |
|
||||||
.B ~/.isyncrc |
|
||||||
Default configuration file |
|
||||||
.. |
|
||||||
.SH BUGS |
|
||||||
The configuration file takes precedence over command line options. |
|
||||||
.br |
|
||||||
Use -c /dev/null to work around. |
|
||||||
.P |
|
||||||
See the \fBINHERENT PROBLEMS\fR section in the \fBmbsync\fR man page, too. |
|
||||||
.. |
|
||||||
.SH SEE ALSO |
|
||||||
mbsync(1), mdconvert(1), mutt(1), maildir(5) |
|
||||||
.P |
|
||||||
Up to date information on \fBisync\fR can be found at http://isync.sf.net/ |
|
||||||
.. |
|
||||||
.SH AUTHORS |
|
||||||
Originally written by Michael R. Elkins, |
|
||||||
currently maintained by Oswald Buddenhagen. |
|
@ -1,116 +0,0 @@ |
|||||||
/*
|
|
||||||
* 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 <autodefs.h> |
|
||||||
|
|
||||||
#include <sys/types.h> |
|
||||||
#include <stdarg.h> |
|
||||||
|
|
||||||
#define as(ar) (sizeof(ar)/sizeof(ar[0])) |
|
||||||
|
|
||||||
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) |
|
||||||
# define ATTR_UNUSED __attribute__((unused)) |
|
||||||
# define ATTR_NORETURN __attribute__((noreturn)) |
|
||||||
# define ATTR_PRINTFLIKE(fmt,var) __attribute__((format(printf,fmt,var))) |
|
||||||
#else |
|
||||||
# define ATTR_UNUSED |
|
||||||
# define ATTR_NORETURN |
|
||||||
# define ATTR_PRINTFLIKE(fmt,var) |
|
||||||
#endif |
|
||||||
|
|
||||||
#if __GNUC__ >= 7 |
|
||||||
# define FALLTHROUGH __attribute__((fallthrough)); |
|
||||||
#else |
|
||||||
# define FALLTHROUGH |
|
||||||
#endif |
|
||||||
|
|
||||||
typedef struct config { |
|
||||||
struct config *next; |
|
||||||
|
|
||||||
const char *server_name; |
|
||||||
const char *old_server_name; |
|
||||||
int servers; |
|
||||||
int old_servers; |
|
||||||
char *host; |
|
||||||
int port; |
|
||||||
char *user; |
|
||||||
char *pass; |
|
||||||
char *tunnel; |
|
||||||
unsigned int require_cram:1; |
|
||||||
unsigned int require_ssl:1; |
|
||||||
unsigned int use_imaps:1; |
|
||||||
unsigned int use_sslv3:1; |
|
||||||
unsigned int use_tlsv1:1; |
|
||||||
char *cert_file; |
|
||||||
|
|
||||||
const char *store_name; |
|
||||||
int stores; |
|
||||||
const char *local_store_name; |
|
||||||
const char *local_store_path; |
|
||||||
int local_stores; |
|
||||||
char *copy_deleted_to; |
|
||||||
unsigned int use_namespace:1; |
|
||||||
|
|
||||||
const char *channel_name; |
|
||||||
int channels; |
|
||||||
const char *alias; |
|
||||||
const char *box; |
|
||||||
const char *path; /* path relative to .maildir, or absolute path */ |
|
||||||
int max_size; |
|
||||||
unsigned int max_messages; |
|
||||||
unsigned int expunge:1; |
|
||||||
unsigned int delete:1; |
|
||||||
} config_t; |
|
||||||
|
|
||||||
extern int Quiet, Verbose, Debug; |
|
||||||
|
|
||||||
extern const char *Home; |
|
||||||
extern int HomeLen; |
|
||||||
|
|
||||||
extern config_t global, *boxes; |
|
||||||
|
|
||||||
extern const char *maildir, *xmaildir, *folder, *inbox; |
|
||||||
extern int o2o, altmap, delete, expunge; |
|
||||||
|
|
||||||
/* config.c */ |
|
||||||
void load_config( const char *, config_t *** ); |
|
||||||
void write_config( int ); |
|
||||||
char *expand_strdup( const char * ); |
|
||||||
config_t *find_box( const char * ); |
|
||||||
|
|
||||||
/* convert.c */ |
|
||||||
void convert( config_t * ); |
|
||||||
|
|
||||||
/* util.c */ |
|
||||||
char *next_arg( char ** ); |
|
||||||
void *nfmalloc( size_t sz ); |
|
||||||
void *nfrealloc( void *mem, size_t sz ); |
|
||||||
char *nfstrdup( const char *str ); |
|
||||||
int nfvasprintf( char **str, const char *fmt, va_list va ); |
|
||||||
int nfasprintf( char **str, const char *fmt, ... ); |
|
||||||
int nfsnprintf( char *buf, int blen, const char *fmt, ... ); |
|
||||||
void sys_error( const char *, ... ); |
|
||||||
void ATTR_NORETURN oob( void ); |
|
||||||
|
|
||||||
#ifndef HAVE_MEMRCHR |
|
||||||
void *memrchr( const void *s, int c, size_t n ); |
|
||||||
#endif |
|
||||||
|
|
||||||
int starts_with( const char *str, int strl, const char *cmp, int cmpl ); |
|
||||||
int equals( const char *str, int strl, const char *cmp, int cmpl ); |
|
@ -1,55 +0,0 @@ |
|||||||
# Global configuration section |
|
||||||
# Values here are used as defaults for any following Mailbox section that |
|
||||||
# doesn't specify it. |
|
||||||
|
|
||||||
# SSL server certificate file |
|
||||||
CertificateFile ~/.isync.certs |
|
||||||
|
|
||||||
# by default, expunge deleted messages (same as -e on command line) |
|
||||||
Expunge yes |
|
||||||
|
|
||||||
# by default delete messages in the local mailbox which no longer exist |
|
||||||
# on the server |
|
||||||
Delete yes |
|
||||||
|
|
||||||
# copy deleted messages to the IMAP "Trash" folder |
|
||||||
CopyDeletedTo "Trash" |
|
||||||
|
|
||||||
# my default username, if different from the local username |
|
||||||
User me |
|
||||||
#Port 143 |
|
||||||
#Box INBOX |
|
||||||
# don't download messages larger than 200K bytes |
|
||||||
MaxSize 200000 |
|
||||||
|
|
||||||
### |
|
||||||
### work mailbox |
|
||||||
### |
|
||||||
|
|
||||||
Mailbox /home/me/Mail/work |
|
||||||
Host work.host.com |
|
||||||
Pass xxxxxxxx |
|
||||||
# define a shortcut so I can just use "isync work" from the command line |
|
||||||
Alias work |
|
||||||
# don't auto expunge messages in this box (overridden by -e on command line) |
|
||||||
Expunge no |
|
||||||
|
|
||||||
### |
|
||||||
### personal mailbox |
|
||||||
### |
|
||||||
|
|
||||||
Mailbox /home/me/Mail/personal |
|
||||||
Host host.play.com |
|
||||||
# use a non-default port for this connection |
|
||||||
Port 6789 |
|
||||||
Alias personal |
|
||||||
|
|
||||||
|
|
||||||
### |
|
||||||
### Remote mailbox over a SSH tunnel |
|
||||||
### |
|
||||||
|
|
||||||
Mailbox /home/me/Mail/remote |
|
||||||
Host host.remote.com |
|
||||||
Tunnel "ssh -q host.remote.com /usr/sbin/imapd" |
|
||||||
Alias remote |
|
@ -1,438 +0,0 @@ |
|||||||
/*
|
|
||||||
* 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 ATTR_NORETURN |
|
||||||
version( void ) |
|
||||||
{ |
|
||||||
puts( PACKAGE " " VERSION ); |
|
||||||
exit( 0 ); |
|
||||||
} |
|
||||||
|
|
||||||
static void ATTR_NORETURN |
|
||||||
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 = ""; /* implicit INBOX in resulting Master/Slave entries */ |
|
||||||
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; |
|
||||||
FALLTHROUGH |
|
||||||
case 'w': |
|
||||||
writeout = 1; |
|
||||||
break; |
|
||||||
case 'l': |
|
||||||
list = 1; |
|
||||||
FALLTHROUGH |
|
||||||
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_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 (!writeout) |
|
||||||
fputs( "Notice: please run 'isync -w' and start using 'mbsync' directly.\n", stderr ); |
|
||||||
|
|
||||||
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 (!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; |
|
||||||
} |
|
@ -1,208 +0,0 @@ |
|||||||
/*
|
|
||||||
* 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 <stdio.h> |
|
||||||
#include <stdlib.h> |
|
||||||
#include <unistd.h> |
|
||||||
#include <string.h> |
|
||||||
#include <pwd.h> |
|
||||||
#include <ctype.h> |
|
||||||
|
|
||||||
void |
|
||||||
sys_error( const char *msg, ... ) |
|
||||||
{ |
|
||||||
va_list va; |
|
||||||
char buf[1024]; |
|
||||||
|
|
||||||
va_start( va, msg ); |
|
||||||
if ((unsigned)vsnprintf( buf, sizeof(buf), msg, va ) >= sizeof(buf)) |
|
||||||
oob(); |
|
||||||
va_end( va ); |
|
||||||
perror( buf ); |
|
||||||
} |
|
||||||
|
|
||||||
char * |
|
||||||
next_arg( char **s ) |
|
||||||
{ |
|
||||||
char *ret; |
|
||||||
|
|
||||||
if (!s || !*s) |
|
||||||
return 0; |
|
||||||
while (isspace( (unsigned char) **s )) |
|
||||||
(*s)++; |
|
||||||
if (!**s) { |
|
||||||
*s = 0; |
|
||||||
return 0; |
|
||||||
} |
|
||||||
if (**s == '"') { |
|
||||||
++*s; |
|
||||||
ret = *s; |
|
||||||
*s = strchr( *s, '"' ); |
|
||||||
} else { |
|
||||||
ret = *s; |
|
||||||
while (**s && !isspace( (unsigned char) **s )) |
|
||||||
(*s)++; |
|
||||||
} |
|
||||||
if (*s) { |
|
||||||
if (**s) |
|
||||||
*(*s)++ = 0; |
|
||||||
if (!**s) |
|
||||||
*s = 0; |
|
||||||
} |
|
||||||
return ret; |
|
||||||
} |
|
||||||
|
|
||||||
#ifndef HAVE_VASPRINTF |
|
||||||
static int |
|
||||||
vasprintf( char **strp, const char *fmt, va_list ap ) |
|
||||||
{ |
|
||||||
int len; |
|
||||||
char tmp[1024]; |
|
||||||
|
|
||||||
if ((len = vsnprintf( tmp, sizeof(tmp), fmt, ap )) < 0 || !(*strp = malloc( len + 1 ))) |
|
||||||
return -1; |
|
||||||
if (len >= (int)sizeof(tmp)) |
|
||||||
vsprintf( *strp, fmt, ap ); |
|
||||||
else |
|
||||||
memcpy( *strp, tmp, len + 1 ); |
|
||||||
return len; |
|
||||||
} |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifndef HAVE_MEMRCHR |
|
||||||
void * |
|
||||||
memrchr( const void *s, int c, size_t n ) |
|
||||||
{ |
|
||||||
u_char *b = (u_char *)s, *e = b + n; |
|
||||||
|
|
||||||
while (--e >= b) |
|
||||||
if (*e == c) |
|
||||||
return (void *)e; |
|
||||||
return 0; |
|
||||||
} |
|
||||||
#endif |
|
||||||
|
|
||||||
#ifndef HAVE_STRNLEN |
|
||||||
int |
|
||||||
strnlen( const char *str, size_t maxlen ) |
|
||||||
{ |
|
||||||
size_t len; |
|
||||||
|
|
||||||
/* It's tempting to use memchr(), but it's allowed to read past the end of the actual string. */ |
|
||||||
for (len = 0; len < maxlen && str[len]; len++) {} |
|
||||||
return len; |
|
||||||
} |
|
||||||
|
|
||||||
#endif |
|
||||||
|
|
||||||
int |
|
||||||
starts_with( const char *str, int strl, const char *cmp, int cmpl ) |
|
||||||
{ |
|
||||||
if (strl < 0) |
|
||||||
strl = strnlen( str, cmpl + 1 ); |
|
||||||
return (strl >= cmpl) && !memcmp( str, cmp, cmpl ); |
|
||||||
} |
|
||||||
|
|
||||||
int |
|
||||||
equals( const char *str, int strl, const char *cmp, int cmpl ) |
|
||||||
{ |
|
||||||
if (strl < 0) |
|
||||||
strl = strnlen( str, cmpl + 1 ); |
|
||||||
return (strl == cmpl) && !memcmp( str, cmp, cmpl ); |
|
||||||
} |
|
||||||
|
|
||||||
void |
|
||||||
oob( void ) |
|
||||||
{ |
|
||||||
fputs( "Fatal: buffer too small. Please report a bug.\n", stderr ); |
|
||||||
abort(); |
|
||||||
} |
|
||||||
|
|
||||||
int |
|
||||||
nfsnprintf( char *buf, int blen, const char *fmt, ... ) |
|
||||||
{ |
|
||||||
int ret; |
|
||||||
va_list va; |
|
||||||
|
|
||||||
va_start( va, fmt ); |
|
||||||
if (blen <= 0 || (unsigned)(ret = vsnprintf( buf, blen, fmt, va )) >= (unsigned)blen) |
|
||||||
oob(); |
|
||||||
va_end( va ); |
|
||||||
return ret; |
|
||||||
} |
|
||||||
|
|
||||||
static void ATTR_NORETURN |
|
||||||
oom( void ) |
|
||||||
{ |
|
||||||
fputs( "Fatal: Out of memory\n", stderr ); |
|
||||||
abort(); |
|
||||||
} |
|
||||||
|
|
||||||
void * |
|
||||||
nfmalloc( size_t sz ) |
|
||||||
{ |
|
||||||
void *ret; |
|
||||||
|
|
||||||
if (!(ret = malloc( sz ))) |
|
||||||
oom(); |
|
||||||
return ret; |
|
||||||
} |
|
||||||
|
|
||||||
void * |
|
||||||
nfrealloc( void *mem, size_t sz ) |
|
||||||
{ |
|
||||||
char *ret; |
|
||||||
|
|
||||||
if (!(ret = realloc( mem, sz )) && sz) |
|
||||||
oom(); |
|
||||||
return ret; |
|
||||||
} |
|
||||||
|
|
||||||
char * |
|
||||||
nfstrdup( const char *str ) |
|
||||||
{ |
|
||||||
char *ret; |
|
||||||
|
|
||||||
if (!(ret = strdup( str ))) |
|
||||||
oom(); |
|
||||||
return ret; |
|
||||||
} |
|
||||||
|
|
||||||
int |
|
||||||
nfvasprintf( char **str, const char *fmt, va_list va ) |
|
||||||
{ |
|
||||||
int ret = vasprintf( str, fmt, va ); |
|
||||||
if (ret < 0) |
|
||||||
oom(); |
|
||||||
return ret; |
|
||||||
} |
|
||||||
|
|
||||||
int |
|
||||||
nfasprintf( char **str, const char *fmt, ... ) |
|
||||||
{ |
|
||||||
int ret; |
|
||||||
va_list va; |
|
||||||
|
|
||||||
va_start( va, fmt ); |
|
||||||
ret = nfvasprintf( str, fmt, va ); |
|
||||||
va_end( va ); |
|
||||||
return ret; |
|
||||||
} |
|
Loading…
Reference in new issue