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