2004-03-27 16:07:20 +00:00
|
|
|
/*
|
|
|
|
* mbsync - mailbox synchronizer
|
2002-12-28 15:31:20 +00:00
|
|
|
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>
|
2004-01-27 20:50:49 +00:00
|
|
|
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>
|
2000-12-20 21:41:21 +00:00
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
2002-10-30 02:31:20 +00:00
|
|
|
*
|
2004-03-27 16:07:20 +00:00
|
|
|
* As a special exception, mbsync may be linked with the OpenSSL library,
|
2002-10-30 02:31:20 +00:00
|
|
|
* despite that library's more restrictive license.
|
2000-12-20 21:41:21 +00:00
|
|
|
*/
|
|
|
|
|
2003-05-07 00:06:37 +00:00
|
|
|
#include "isync.h"
|
|
|
|
|
2000-12-20 21:41:21 +00:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
Bunch 'o patches from Oswald Buddenhagen:
i implemented some cool stuff (tm).
first, the long missing "create server-side missing mailboxes". -C now
creates both local and remote boxes; -L and -R create only local/remote.
second, i implemented a 1:1 remote:local folder mapping (-1) with an
optional INBOX exception (inbox/-I). the remote folder is specified with
the folder keyword (or -F switch) and takes precedence over the
namespace setting. the local directory with the mailboxes can now be
specified on the command line, too (-M).
another patch:
- made the -1 switch settable permanently (OneToOne). after all, you
usually define your mailbox layout once forever. removed -A, as it is
semantically -a modified by -1.
- cleaned up message output a bit. still, the quiet variable should be
used throughout the program. at best, create some generic output
function, which obeys a global verbosity level variable.
- optimized + cleaned up configuration parser slightly
- minor cleanups
add an (almost) unique id to every uploaded message and search for it
right after. i thought about using the message-id, but a) it is not
guaranteed to be unique in a mailbox (imagine you edit a mail and store
the dupe in the same box) and b) some mails (e.g., postponed) don't even
have one. a downside of the current implementation is, that this
id-header remains in the mailbox, but given that it wastes only 27 bytes
per mail and removing it would mean several roundtrips more, this seems
acceptable.
i changed the line-counting loop to use a mmapped file instead of
reading it in chunks, as it makes things simpler and is probably even
faster for big mails.
the amount of goto statements in my code may be scary, but c is simply
lacking a multi-level break statement. :)
this is the "shut up" patch. :) it makes the -q option consequent, so to
say.
additionally it adds an -l option which gathers all defined/found
mailboxes and just outputs the list. don't ask what i need it for. ;)
2002-10-30 02:23:05 +00:00
|
|
|
|
2004-03-27 16:07:20 +00:00
|
|
|
int Pid; /* for maildir and imap */
|
|
|
|
char Hostname[256]; /* for maildir */
|
|
|
|
const char *Home; /* for config */
|
2000-12-20 21:41:21 +00:00
|
|
|
|
|
|
|
static void
|
2004-03-27 16:07:20 +00:00
|
|
|
version( void )
|
2000-12-20 21:41:21 +00:00
|
|
|
{
|
2004-03-27 16:07:20 +00:00
|
|
|
puts( PACKAGE " " VERSION );
|
|
|
|
exit( 0 );
|
2000-12-20 21:41:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2004-03-27 16:07:20 +00:00
|
|
|
usage( int code )
|
2000-12-20 21:41:21 +00:00
|
|
|
{
|
2004-03-27 16:07:20 +00:00
|
|
|
fputs(
|
|
|
|
PACKAGE " " VERSION " - mailbox synchronizer\n"
|
2003-05-05 13:24:03 +00:00
|
|
|
"Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>\n"
|
2004-02-01 16:27:28 +00:00
|
|
|
"Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>\n"
|
2004-03-27 16:07:20 +00:00
|
|
|
"Copyright (C) 2004 Theodore Ts'o <tytso@mit.edu>\n"
|
Bunch 'o patches from Oswald Buddenhagen:
i implemented some cool stuff (tm).
first, the long missing "create server-side missing mailboxes". -C now
creates both local and remote boxes; -L and -R create only local/remote.
second, i implemented a 1:1 remote:local folder mapping (-1) with an
optional INBOX exception (inbox/-I). the remote folder is specified with
the folder keyword (or -F switch) and takes precedence over the
namespace setting. the local directory with the mailboxes can now be
specified on the command line, too (-M).
another patch:
- made the -1 switch settable permanently (OneToOne). after all, you
usually define your mailbox layout once forever. removed -A, as it is
semantically -a modified by -1.
- cleaned up message output a bit. still, the quiet variable should be
used throughout the program. at best, create some generic output
function, which obeys a global verbosity level variable.
- optimized + cleaned up configuration parser slightly
- minor cleanups
add an (almost) unique id to every uploaded message and search for it
right after. i thought about using the message-id, but a) it is not
guaranteed to be unique in a mailbox (imagine you edit a mail and store
the dupe in the same box) and b) some mails (e.g., postponed) don't even
have one. a downside of the current implementation is, that this
id-header remains in the mailbox, but given that it wastes only 27 bytes
per mail and removing it would mean several roundtrips more, this seems
acceptable.
i changed the line-counting loop to use a mmapped file instead of
reading it in chunks, as it makes things simpler and is probably even
faster for big mails.
the amount of goto statements in my code may be scary, but c is simply
lacking a multi-level break statement. :)
this is the "shut up" patch. :) it makes the -q option consequent, so to
say.
additionally it adds an -l option which gathers all defined/found
mailboxes and just outputs the list. don't ask what i need it for. ;)
2002-10-30 02:23:05 +00:00
|
|
|
"usage:\n"
|
2004-03-27 16:07:20 +00:00
|
|
|
" " EXE " [flags] {{channel[:box,...]|group} ...|-a}\n"
|
|
|
|
" -a, --all operate on all defined channels\n"
|
|
|
|
" -l, --list list mailboxes instead of syncing them\n"
|
|
|
|
" -n, --new propagate new messages\n"
|
|
|
|
" -d, --delete propagate message deletions\n"
|
|
|
|
" -f, --flags propagate message flag changes\n"
|
|
|
|
" -N, --renew propagate previously not propagated new messages\n"
|
|
|
|
" -L, --pull propagate from master to slave\n"
|
|
|
|
" -H, --push propagate from slave to master\n"
|
|
|
|
" -C, --create create mailboxes if nonexistent\n"
|
|
|
|
" -X, --expunge expunge deleted messages\n"
|
|
|
|
" -c, --config CONFIG read an alternate config file (default: ~/." EXE "rc)\n"
|
|
|
|
" -D, --debug print debugging messages\n"
|
Bunch 'o patches from Oswald Buddenhagen:
i implemented some cool stuff (tm).
first, the long missing "create server-side missing mailboxes". -C now
creates both local and remote boxes; -L and -R create only local/remote.
second, i implemented a 1:1 remote:local folder mapping (-1) with an
optional INBOX exception (inbox/-I). the remote folder is specified with
the folder keyword (or -F switch) and takes precedence over the
namespace setting. the local directory with the mailboxes can now be
specified on the command line, too (-M).
another patch:
- made the -1 switch settable permanently (OneToOne). after all, you
usually define your mailbox layout once forever. removed -A, as it is
semantically -a modified by -1.
- cleaned up message output a bit. still, the quiet variable should be
used throughout the program. at best, create some generic output
function, which obeys a global verbosity level variable.
- optimized + cleaned up configuration parser slightly
- minor cleanups
add an (almost) unique id to every uploaded message and search for it
right after. i thought about using the message-id, but a) it is not
guaranteed to be unique in a mailbox (imagine you edit a mail and store
the dupe in the same box) and b) some mails (e.g., postponed) don't even
have one. a downside of the current implementation is, that this
id-header remains in the mailbox, but given that it wastes only 27 bytes
per mail and removing it would mean several roundtrips more, this seems
acceptable.
i changed the line-counting loop to use a mmapped file instead of
reading it in chunks, as it makes things simpler and is probably even
faster for big mails.
the amount of goto statements in my code may be scary, but c is simply
lacking a multi-level break statement. :)
this is the "shut up" patch. :) it makes the -q option consequent, so to
say.
additionally it adds an -l option which gathers all defined/found
mailboxes and just outputs the list. don't ask what i need it for. ;)
2002-10-30 02:23:05 +00:00
|
|
|
" -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"
|
2004-03-27 16:07:20 +00:00
|
|
|
"\nIf neither --pull nor --push are specified, both are active.\n"
|
|
|
|
"If neither --new, --delete, --flags nor --renew are specified, all are active.\n"
|
|
|
|
"Direction and operation can be concatenated like --pull-new, etc.\n"
|
|
|
|
"--create and --expunge can be suffixed with -master/-slave. Read the man page.\n"
|
|
|
|
"\nSupported mailbox formats are: IMAP4rev1, Maildir\n"
|
|
|
|
"\nCompile time options:\n"
|
2001-10-03 06:15:01 +00:00
|
|
|
#if HAVE_LIBSSL
|
Bunch 'o patches from Oswald Buddenhagen:
i implemented some cool stuff (tm).
first, the long missing "create server-side missing mailboxes". -C now
creates both local and remote boxes; -L and -R create only local/remote.
second, i implemented a 1:1 remote:local folder mapping (-1) with an
optional INBOX exception (inbox/-I). the remote folder is specified with
the folder keyword (or -F switch) and takes precedence over the
namespace setting. the local directory with the mailboxes can now be
specified on the command line, too (-M).
another patch:
- made the -1 switch settable permanently (OneToOne). after all, you
usually define your mailbox layout once forever. removed -A, as it is
semantically -a modified by -1.
- cleaned up message output a bit. still, the quiet variable should be
used throughout the program. at best, create some generic output
function, which obeys a global verbosity level variable.
- optimized + cleaned up configuration parser slightly
- minor cleanups
add an (almost) unique id to every uploaded message and search for it
right after. i thought about using the message-id, but a) it is not
guaranteed to be unique in a mailbox (imagine you edit a mail and store
the dupe in the same box) and b) some mails (e.g., postponed) don't even
have one. a downside of the current implementation is, that this
id-header remains in the mailbox, but given that it wastes only 27 bytes
per mail and removing it would mean several roundtrips more, this seems
acceptable.
i changed the line-counting loop to use a mmapped file instead of
reading it in chunks, as it makes things simpler and is probably even
faster for big mails.
the amount of goto statements in my code may be scary, but c is simply
lacking a multi-level break statement. :)
this is the "shut up" patch. :) it makes the -q option consequent, so to
say.
additionally it adds an -l option which gathers all defined/found
mailboxes and just outputs the list. don't ask what i need it for. ;)
2002-10-30 02:23:05 +00:00
|
|
|
" +HAVE_LIBSSL\n"
|
2001-10-03 06:15:01 +00:00
|
|
|
#else
|
Bunch 'o patches from Oswald Buddenhagen:
i implemented some cool stuff (tm).
first, the long missing "create server-side missing mailboxes". -C now
creates both local and remote boxes; -L and -R create only local/remote.
second, i implemented a 1:1 remote:local folder mapping (-1) with an
optional INBOX exception (inbox/-I). the remote folder is specified with
the folder keyword (or -F switch) and takes precedence over the
namespace setting. the local directory with the mailboxes can now be
specified on the command line, too (-M).
another patch:
- made the -1 switch settable permanently (OneToOne). after all, you
usually define your mailbox layout once forever. removed -A, as it is
semantically -a modified by -1.
- cleaned up message output a bit. still, the quiet variable should be
used throughout the program. at best, create some generic output
function, which obeys a global verbosity level variable.
- optimized + cleaned up configuration parser slightly
- minor cleanups
add an (almost) unique id to every uploaded message and search for it
right after. i thought about using the message-id, but a) it is not
guaranteed to be unique in a mailbox (imagine you edit a mail and store
the dupe in the same box) and b) some mails (e.g., postponed) don't even
have one. a downside of the current implementation is, that this
id-header remains in the mailbox, but given that it wastes only 27 bytes
per mail and removing it would mean several roundtrips more, this seems
acceptable.
i changed the line-counting loop to use a mmapped file instead of
reading it in chunks, as it makes things simpler and is probably even
faster for big mails.
the amount of goto statements in my code may be scary, but c is simply
lacking a multi-level break statement. :)
this is the "shut up" patch. :) it makes the -q option consequent, so to
say.
additionally it adds an -l option which gathers all defined/found
mailboxes and just outputs the list. don't ask what i need it for. ;)
2002-10-30 02:23:05 +00:00
|
|
|
" -HAVE_LIBSSL\n"
|
2001-10-03 06:15:01 +00:00
|
|
|
#endif
|
2004-03-27 16:07:20 +00:00
|
|
|
, code ? stderr : stdout );
|
|
|
|
exit( code );
|
2000-12-20 21:41:21 +00:00
|
|
|
}
|
|
|
|
|
2004-03-27 16:07:20 +00:00
|
|
|
static int
|
|
|
|
matches( const char *t, const char *p )
|
2000-12-20 21:41:21 +00:00
|
|
|
{
|
2004-03-27 16:07:20 +00:00
|
|
|
for (;;) {
|
|
|
|
if (!*p)
|
|
|
|
return !*t;
|
|
|
|
if (*p == '*') {
|
|
|
|
p++;
|
|
|
|
do {
|
|
|
|
if (matches( t, p ))
|
|
|
|
return 1;
|
|
|
|
} while (*t++);
|
|
|
|
return 0;
|
|
|
|
} else if (*p == '%') {
|
|
|
|
p++;
|
|
|
|
do {
|
|
|
|
if (*t == '.' || *t == '/') /* this is "somewhat" hacky ... */
|
|
|
|
return 0;
|
|
|
|
if (matches( t, p ))
|
|
|
|
return 1;
|
|
|
|
} while (*t++);
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
if (*p != *t)
|
|
|
|
return 0;
|
|
|
|
p++, t++;
|
|
|
|
}
|
|
|
|
}
|
2000-12-20 21:41:21 +00:00
|
|
|
}
|
|
|
|
|
2004-03-27 16:07:20 +00:00
|
|
|
static string_list_t *
|
|
|
|
filter_boxes( string_list_t *boxes, string_list_t *patterns )
|
2000-12-20 21:41:21 +00:00
|
|
|
{
|
2004-03-27 16:07:20 +00:00
|
|
|
string_list_t *nboxes = 0, *cpat;
|
|
|
|
const char *ps;
|
|
|
|
int not, fnot;
|
|
|
|
|
|
|
|
for (; boxes; boxes = boxes->next) {
|
|
|
|
fnot = 1;
|
|
|
|
for (cpat = patterns; cpat; cpat = cpat->next) {
|
|
|
|
ps = cpat->string;
|
|
|
|
if (*ps == '!') {
|
|
|
|
ps++;
|
|
|
|
not = 1;
|
|
|
|
} else
|
|
|
|
not = 0;
|
|
|
|
if (matches( boxes->string, ps )) {
|
|
|
|
fnot = not;
|
|
|
|
break;
|
|
|
|
}
|
2001-06-22 23:30:41 +00:00
|
|
|
}
|
2004-03-27 16:07:20 +00:00
|
|
|
if (!fnot)
|
|
|
|
add_string_list( &nboxes, boxes->string );
|
Bunch 'o patches from Oswald Buddenhagen:
i implemented some cool stuff (tm).
first, the long missing "create server-side missing mailboxes". -C now
creates both local and remote boxes; -L and -R create only local/remote.
second, i implemented a 1:1 remote:local folder mapping (-1) with an
optional INBOX exception (inbox/-I). the remote folder is specified with
the folder keyword (or -F switch) and takes precedence over the
namespace setting. the local directory with the mailboxes can now be
specified on the command line, too (-M).
another patch:
- made the -1 switch settable permanently (OneToOne). after all, you
usually define your mailbox layout once forever. removed -A, as it is
semantically -a modified by -1.
- cleaned up message output a bit. still, the quiet variable should be
used throughout the program. at best, create some generic output
function, which obeys a global verbosity level variable.
- optimized + cleaned up configuration parser slightly
- minor cleanups
add an (almost) unique id to every uploaded message and search for it
right after. i thought about using the message-id, but a) it is not
guaranteed to be unique in a mailbox (imagine you edit a mail and store
the dupe in the same box) and b) some mails (e.g., postponed) don't even
have one. a downside of the current implementation is, that this
id-header remains in the mailbox, but given that it wastes only 27 bytes
per mail and removing it would mean several roundtrips more, this seems
acceptable.
i changed the line-counting loop to use a mmapped file instead of
reading it in chunks, as it makes things simpler and is probably even
faster for big mails.
the amount of goto statements in my code may be scary, but c is simply
lacking a multi-level break statement. :)
this is the "shut up" patch. :) it makes the -q option consequent, so to
say.
additionally it adds an -l option which gathers all defined/found
mailboxes and just outputs the list. don't ask what i need it for. ;)
2002-10-30 02:23:05 +00:00
|
|
|
}
|
2004-03-27 16:07:20 +00:00
|
|
|
return nboxes;
|
|
|
|
}
|
Bunch 'o patches from Oswald Buddenhagen:
i implemented some cool stuff (tm).
first, the long missing "create server-side missing mailboxes". -C now
creates both local and remote boxes; -L and -R create only local/remote.
second, i implemented a 1:1 remote:local folder mapping (-1) with an
optional INBOX exception (inbox/-I). the remote folder is specified with
the folder keyword (or -F switch) and takes precedence over the
namespace setting. the local directory with the mailboxes can now be
specified on the command line, too (-M).
another patch:
- made the -1 switch settable permanently (OneToOne). after all, you
usually define your mailbox layout once forever. removed -A, as it is
semantically -a modified by -1.
- cleaned up message output a bit. still, the quiet variable should be
used throughout the program. at best, create some generic output
function, which obeys a global verbosity level variable.
- optimized + cleaned up configuration parser slightly
- minor cleanups
add an (almost) unique id to every uploaded message and search for it
right after. i thought about using the message-id, but a) it is not
guaranteed to be unique in a mailbox (imagine you edit a mail and store
the dupe in the same box) and b) some mails (e.g., postponed) don't even
have one. a downside of the current implementation is, that this
id-header remains in the mailbox, but given that it wastes only 27 bytes
per mail and removing it would mean several roundtrips more, this seems
acceptable.
i changed the line-counting loop to use a mmapped file instead of
reading it in chunks, as it makes things simpler and is probably even
faster for big mails.
the amount of goto statements in my code may be scary, but c is simply
lacking a multi-level break statement. :)
this is the "shut up" patch. :) it makes the -q option consequent, so to
say.
additionally it adds an -l option which gathers all defined/found
mailboxes and just outputs the list. don't ask what i need it for. ;)
2002-10-30 02:23:05 +00:00
|
|
|
|
2004-03-27 16:07:20 +00:00
|
|
|
static void
|
2005-12-28 10:02:22 +00:00
|
|
|
merge_actions( channel_conf_t *chan, int ops[], int have, int mask, int def )
|
2004-03-27 16:07:20 +00:00
|
|
|
{
|
2005-12-28 10:02:22 +00:00
|
|
|
if (ops[M] & have) {
|
|
|
|
chan->ops[M] &= ~mask;
|
|
|
|
chan->ops[M] |= ops[M] & mask;
|
|
|
|
chan->ops[S] &= ~mask;
|
|
|
|
chan->ops[S] |= ops[S] & mask;
|
|
|
|
} else if (!(chan->ops[M] & have)) {
|
|
|
|
if (global_ops[M] & have) {
|
|
|
|
chan->ops[M] |= global_ops[M] & mask;
|
|
|
|
chan->ops[S] |= global_ops[S] & mask;
|
2004-03-27 16:07:20 +00:00
|
|
|
} else {
|
2005-12-28 10:02:22 +00:00
|
|
|
chan->ops[M] |= def;
|
|
|
|
chan->ops[S] |= def;
|
2004-03-27 16:07:20 +00:00
|
|
|
}
|
Bunch 'o patches from Oswald Buddenhagen:
i implemented some cool stuff (tm).
first, the long missing "create server-side missing mailboxes". -C now
creates both local and remote boxes; -L and -R create only local/remote.
second, i implemented a 1:1 remote:local folder mapping (-1) with an
optional INBOX exception (inbox/-I). the remote folder is specified with
the folder keyword (or -F switch) and takes precedence over the
namespace setting. the local directory with the mailboxes can now be
specified on the command line, too (-M).
another patch:
- made the -1 switch settable permanently (OneToOne). after all, you
usually define your mailbox layout once forever. removed -A, as it is
semantically -a modified by -1.
- cleaned up message output a bit. still, the quiet variable should be
used throughout the program. at best, create some generic output
function, which obeys a global verbosity level variable.
- optimized + cleaned up configuration parser slightly
- minor cleanups
add an (almost) unique id to every uploaded message and search for it
right after. i thought about using the message-id, but a) it is not
guaranteed to be unique in a mailbox (imagine you edit a mail and store
the dupe in the same box) and b) some mails (e.g., postponed) don't even
have one. a downside of the current implementation is, that this
id-header remains in the mailbox, but given that it wastes only 27 bytes
per mail and removing it would mean several roundtrips more, this seems
acceptable.
i changed the line-counting loop to use a mmapped file instead of
reading it in chunks, as it makes things simpler and is probably even
faster for big mails.
the amount of goto statements in my code may be scary, but c is simply
lacking a multi-level break statement. :)
this is the "shut up" patch. :) it makes the -q option consequent, so to
say.
additionally it adds an -l option which gathers all defined/found
mailboxes and just outputs the list. don't ask what i need it for. ;)
2002-10-30 02:23:05 +00:00
|
|
|
}
|
2004-03-27 16:07:20 +00:00
|
|
|
}
|
2004-01-09 20:43:36 +00:00
|
|
|
|
2004-03-27 16:07:20 +00:00
|
|
|
int
|
|
|
|
main( int argc, char **argv )
|
|
|
|
{
|
|
|
|
channel_conf_t *chan;
|
2005-12-28 10:02:22 +00:00
|
|
|
store_conf_t *conf[2];
|
2004-03-27 16:07:20 +00:00
|
|
|
group_conf_t *group;
|
2005-12-28 10:02:22 +00:00
|
|
|
driver_t *driver[2];
|
|
|
|
store_t *ctx[2];
|
|
|
|
string_list_t *uboxes[2], *boxes[2], *mbox, *sbox, **mboxp, **sboxp, *cboxes, *chanptr;
|
2004-03-27 16:07:20 +00:00
|
|
|
char *config = 0, *channame, *boxlist, *opt, *ochar;
|
2005-12-28 10:02:22 +00:00
|
|
|
const char *names[2];
|
|
|
|
int all = 0, list = 0, cops = 0, ops[2] = { 0, 0 }, guboxes[2];
|
|
|
|
int oind, ret, op, multiple, pseudo = 0, t;
|
2004-03-27 16:07:20 +00:00
|
|
|
|
|
|
|
gethostname( Hostname, sizeof(Hostname) );
|
|
|
|
if ((ochar = strchr( Hostname, '.' )))
|
|
|
|
*ochar = 0;
|
|
|
|
Pid = getpid();
|
|
|
|
if (!(Home = getenv("HOME"))) {
|
|
|
|
fputs( "Fatal: $HOME not set\n", stderr );
|
|
|
|
return 1;
|
Bunch 'o patches from Oswald Buddenhagen:
i implemented some cool stuff (tm).
first, the long missing "create server-side missing mailboxes". -C now
creates both local and remote boxes; -L and -R create only local/remote.
second, i implemented a 1:1 remote:local folder mapping (-1) with an
optional INBOX exception (inbox/-I). the remote folder is specified with
the folder keyword (or -F switch) and takes precedence over the
namespace setting. the local directory with the mailboxes can now be
specified on the command line, too (-M).
another patch:
- made the -1 switch settable permanently (OneToOne). after all, you
usually define your mailbox layout once forever. removed -A, as it is
semantically -a modified by -1.
- cleaned up message output a bit. still, the quiet variable should be
used throughout the program. at best, create some generic output
function, which obeys a global verbosity level variable.
- optimized + cleaned up configuration parser slightly
- minor cleanups
add an (almost) unique id to every uploaded message and search for it
right after. i thought about using the message-id, but a) it is not
guaranteed to be unique in a mailbox (imagine you edit a mail and store
the dupe in the same box) and b) some mails (e.g., postponed) don't even
have one. a downside of the current implementation is, that this
id-header remains in the mailbox, but given that it wastes only 27 bytes
per mail and removing it would mean several roundtrips more, this seems
acceptable.
i changed the line-counting loop to use a mmapped file instead of
reading it in chunks, as it makes things simpler and is probably even
faster for big mails.
the amount of goto statements in my code may be scary, but c is simply
lacking a multi-level break statement. :)
this is the "shut up" patch. :) it makes the -q option consequent, so to
say.
additionally it adds an -l option which gathers all defined/found
mailboxes and just outputs the list. don't ask what i need it for. ;)
2002-10-30 02:23:05 +00:00
|
|
|
}
|
2004-03-27 16:07:20 +00:00
|
|
|
arc4_init();
|
|
|
|
|
|
|
|
for (oind = 1, ochar = 0; oind < argc; ) {
|
|
|
|
if (!ochar || !*ochar) {
|
|
|
|
if (argv[oind][0] != '-')
|
|
|
|
break;
|
|
|
|
if (argv[oind][1] == '-') {
|
|
|
|
opt = argv[oind++] + 2;
|
|
|
|
if (!*opt)
|
|
|
|
break;
|
|
|
|
if (!strcmp( opt, "config" )) {
|
|
|
|
if (oind >= argc) {
|
|
|
|
fprintf( stderr, "--config requires an argument.\n" );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
config = argv[oind++];
|
|
|
|
} else if (!memcmp( opt, "config=", 7 ))
|
|
|
|
config = opt + 7;
|
|
|
|
else if (!strcmp( opt, "all" ))
|
|
|
|
all = 1;
|
|
|
|
else if (!strcmp( opt, "list" ))
|
|
|
|
list = 1;
|
|
|
|
else if (!strcmp( opt, "help" ))
|
|
|
|
usage( 0 );
|
|
|
|
else if (!strcmp( opt, "version" ))
|
|
|
|
version();
|
2006-01-29 14:46:16 +00:00
|
|
|
else if (!strcmp( opt, "quiet" )) {
|
|
|
|
if (DFlags & QUIET)
|
|
|
|
DFlags |= VERYQUIET;
|
|
|
|
else
|
|
|
|
DFlags |= QUIET;
|
|
|
|
} else if (!strcmp( opt, "verbose" ))
|
|
|
|
DFlags |= VERBOSE | QUIET;
|
|
|
|
else if (!strcmp( opt, "debug" ))
|
|
|
|
DFlags |= DEBUG | QUIET;
|
|
|
|
else if (!strcmp( opt, "pull" ))
|
2005-12-28 10:02:22 +00:00
|
|
|
cops |= XOP_PULL, ops[M] |= XOP_HAVE_TYPE;
|
2004-03-27 16:07:20 +00:00
|
|
|
else if (!strcmp( opt, "push" ))
|
2005-12-28 10:02:22 +00:00
|
|
|
cops |= XOP_PUSH, ops[M] |= XOP_HAVE_TYPE;
|
2004-03-27 16:07:20 +00:00
|
|
|
else if (!memcmp( opt, "create", 6 )) {
|
|
|
|
opt += 6;
|
|
|
|
op = OP_CREATE|XOP_HAVE_CREATE;
|
|
|
|
lcop:
|
|
|
|
if (!*opt)
|
|
|
|
cops |= op;
|
|
|
|
else if (!strcmp( opt, "-master" ))
|
2005-12-28 10:02:22 +00:00
|
|
|
ops[M] |= op, ochar++;
|
2004-03-27 16:07:20 +00:00
|
|
|
else if (!strcmp( opt, "-slave" ))
|
2005-12-28 10:02:22 +00:00
|
|
|
ops[S] |= op, ochar++;
|
2004-03-27 16:07:20 +00:00
|
|
|
else
|
|
|
|
goto badopt;
|
2005-12-28 10:02:22 +00:00
|
|
|
ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
|
2004-03-27 16:07:20 +00:00
|
|
|
} else if (!memcmp( opt, "expunge", 7 )) {
|
|
|
|
opt += 7;
|
|
|
|
op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
|
|
|
|
goto lcop;
|
|
|
|
} else if (!strcmp( opt, "no-expunge" ))
|
2005-12-28 10:02:22 +00:00
|
|
|
ops[M] |= XOP_HAVE_EXPUNGE;
|
2004-03-27 16:07:20 +00:00
|
|
|
else if (!strcmp( opt, "no-create" ))
|
2005-12-28 10:02:22 +00:00
|
|
|
ops[M] |= XOP_HAVE_CREATE;
|
2004-03-27 16:07:20 +00:00
|
|
|
else if (!strcmp( opt, "full" ))
|
2005-12-28 10:02:22 +00:00
|
|
|
ops[M] |= XOP_HAVE_TYPE|XOP_PULL|XOP_PUSH;
|
2004-03-27 16:07:20 +00:00
|
|
|
else if (!strcmp( opt, "noop" ))
|
2005-12-28 10:02:22 +00:00
|
|
|
ops[M] |= XOP_HAVE_TYPE;
|
2004-03-27 16:07:20 +00:00
|
|
|
else if (!memcmp( opt, "pull", 4 )) {
|
|
|
|
op = XOP_PULL;
|
|
|
|
lcac:
|
|
|
|
opt += 4;
|
|
|
|
if (!*opt)
|
|
|
|
cops |= op;
|
|
|
|
else if (*opt == '-') {
|
|
|
|
opt++;
|
|
|
|
goto rlcac;
|
|
|
|
} else
|
|
|
|
goto badopt;
|
|
|
|
} else if (!memcmp( opt, "push", 4 )) {
|
|
|
|
op = XOP_PUSH;
|
|
|
|
goto lcac;
|
|
|
|
} else {
|
|
|
|
op = 0;
|
|
|
|
rlcac:
|
|
|
|
if (!strcmp( opt, "new" ))
|
|
|
|
op |= OP_NEW;
|
|
|
|
else if (!strcmp( opt, "renew" ))
|
|
|
|
op |= OP_RENEW;
|
|
|
|
else if (!strcmp( opt, "delete" ))
|
|
|
|
op |= OP_DELETE;
|
|
|
|
else if (!strcmp( opt, "flags" ))
|
|
|
|
op |= OP_FLAGS;
|
|
|
|
else {
|
|
|
|
badopt:
|
|
|
|
fprintf( stderr, "Unknown option '%s'\n", argv[oind - 1] );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
switch (op & XOP_MASK_DIR) {
|
2005-12-28 10:02:22 +00:00
|
|
|
case XOP_PULL: ops[S] |= op & OP_MASK_TYPE; break;
|
|
|
|
case XOP_PUSH: ops[M] |= op & OP_MASK_TYPE; break;
|
2004-03-27 16:07:20 +00:00
|
|
|
default: cops |= op; break;
|
|
|
|
}
|
2005-12-28 10:02:22 +00:00
|
|
|
ops[M] |= XOP_HAVE_TYPE;
|
2004-03-27 16:07:20 +00:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
ochar = argv[oind++] + 1;
|
|
|
|
if (!*ochar) {
|
|
|
|
fprintf( stderr, "Invalid option '-'\n" );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
switch (*ochar++) {
|
|
|
|
case 'a':
|
|
|
|
all = 1;
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
list = 1;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
if (*ochar == 'T') {
|
|
|
|
ochar++;
|
|
|
|
pseudo = 1;
|
|
|
|
}
|
|
|
|
if (oind >= argc) {
|
|
|
|
fprintf( stderr, "-c requires an argument.\n" );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
config = argv[oind++];
|
|
|
|
break;
|
|
|
|
case 'C':
|
|
|
|
op = OP_CREATE|XOP_HAVE_CREATE;
|
|
|
|
cop:
|
|
|
|
if (*ochar == 'm')
|
2005-12-28 10:02:22 +00:00
|
|
|
ops[M] |= op, ochar++;
|
2004-03-27 16:07:20 +00:00
|
|
|
else if (*ochar == 's')
|
2005-12-28 10:02:22 +00:00
|
|
|
ops[S] |= op, ochar++;
|
2004-03-27 16:07:20 +00:00
|
|
|
else if (*ochar == '-')
|
|
|
|
ochar++;
|
|
|
|
else
|
|
|
|
cops |= op;
|
2005-12-28 10:02:22 +00:00
|
|
|
ops[M] |= op & (XOP_HAVE_CREATE|XOP_HAVE_EXPUNGE);
|
2004-03-27 16:07:20 +00:00
|
|
|
break;
|
|
|
|
case 'X':
|
|
|
|
op = OP_EXPUNGE|XOP_HAVE_EXPUNGE;
|
|
|
|
goto cop;
|
|
|
|
case 'F':
|
|
|
|
cops |= XOP_PULL|XOP_PUSH;
|
|
|
|
case '0':
|
2005-12-28 10:02:22 +00:00
|
|
|
ops[M] |= XOP_HAVE_TYPE;
|
2004-03-27 16:07:20 +00:00
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
case 'd':
|
|
|
|
case 'f':
|
|
|
|
case 'N':
|
|
|
|
--ochar;
|
|
|
|
op = 0;
|
|
|
|
cac:
|
|
|
|
for (;; ochar++) {
|
|
|
|
if (*ochar == 'n')
|
|
|
|
op |= OP_NEW;
|
|
|
|
else if (*ochar == 'd')
|
|
|
|
op |= OP_DELETE;
|
|
|
|
else if (*ochar == 'f')
|
|
|
|
op |= OP_FLAGS;
|
|
|
|
else if (*ochar == 'N')
|
|
|
|
op |= OP_RENEW;
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (op & OP_MASK_TYPE)
|
|
|
|
switch (op & XOP_MASK_DIR) {
|
2005-12-28 10:02:22 +00:00
|
|
|
case XOP_PULL: ops[S] |= op & OP_MASK_TYPE; break;
|
|
|
|
case XOP_PUSH: ops[M] |= op & OP_MASK_TYPE; break;
|
2004-03-27 16:07:20 +00:00
|
|
|
default: cops |= op; break;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
cops |= op;
|
2005-12-28 10:02:22 +00:00
|
|
|
ops[M] |= XOP_HAVE_TYPE;
|
2004-03-27 16:07:20 +00:00
|
|
|
break;
|
|
|
|
case 'L':
|
|
|
|
op = XOP_PULL;
|
|
|
|
goto cac;
|
|
|
|
case 'H':
|
|
|
|
op = XOP_PUSH;
|
|
|
|
goto cac;
|
|
|
|
case 'q':
|
2006-01-29 14:46:16 +00:00
|
|
|
if (DFlags & QUIET)
|
|
|
|
DFlags |= VERYQUIET;
|
|
|
|
else
|
|
|
|
DFlags |= QUIET;
|
2004-03-27 16:07:20 +00:00
|
|
|
break;
|
|
|
|
case 'V':
|
2006-01-29 14:46:16 +00:00
|
|
|
DFlags |= VERBOSE | QUIET;
|
2004-03-27 16:07:20 +00:00
|
|
|
break;
|
|
|
|
case 'D':
|
2006-01-29 14:46:16 +00:00
|
|
|
DFlags |= DEBUG | QUIET;
|
2004-03-27 16:07:20 +00:00
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
version();
|
|
|
|
case 'h':
|
|
|
|
usage( 0 );
|
|
|
|
default:
|
|
|
|
fprintf( stderr, "Unknown option '-%c'\n", *(ochar - 1) );
|
|
|
|
return 1;
|
2001-06-18 17:49:08 +00:00
|
|
|
}
|
2000-12-20 21:41:21 +00:00
|
|
|
}
|
|
|
|
|
2005-12-28 10:02:22 +00:00
|
|
|
if (merge_ops( cops, ops ))
|
2004-03-27 16:07:20 +00:00
|
|
|
return 1;
|
2000-12-20 21:41:21 +00:00
|
|
|
|
2004-03-27 16:07:20 +00:00
|
|
|
if (load_config( config, pseudo ))
|
|
|
|
return 1;
|
2000-12-20 21:41:21 +00:00
|
|
|
|
2004-03-27 16:07:20 +00:00
|
|
|
if (!all && !argv[oind]) {
|
|
|
|
fputs( "No channel specified. Try '" EXE " -h'\n", stderr );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (!channels) {
|
|
|
|
fputs( "No channels defined. Try 'man " EXE "'\n", stderr );
|
|
|
|
return 1;
|
|
|
|
}
|
2000-12-20 21:41:21 +00:00
|
|
|
|
2004-03-27 16:07:20 +00:00
|
|
|
ret = 0;
|
|
|
|
chan = channels;
|
|
|
|
chanptr = 0;
|
2005-12-28 10:02:22 +00:00
|
|
|
ctx[M] = ctx[S] = 0;
|
|
|
|
conf[M] = conf[S] = 0; /* make-gcc-happy */
|
|
|
|
driver[M] = driver[S] = 0; /* make-gcc-happy */
|
|
|
|
guboxes[M] = guboxes[S] = 0;
|
|
|
|
uboxes[M] = uboxes[S] = 0;
|
2004-03-27 16:07:20 +00:00
|
|
|
if (all)
|
|
|
|
multiple = channels->next != 0;
|
|
|
|
else if (argv[oind + 1])
|
|
|
|
multiple = 1;
|
|
|
|
else {
|
|
|
|
multiple = 0;
|
|
|
|
for (group = groups; group; group = group->next)
|
|
|
|
if (!strcmp( group->name, argv[oind] )) {
|
|
|
|
multiple = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (;;) {
|
|
|
|
boxlist = 0;
|
|
|
|
if (!all) {
|
|
|
|
if (chanptr)
|
|
|
|
channame = chanptr->string;
|
|
|
|
else {
|
|
|
|
for (group = groups; group; group = group->next)
|
|
|
|
if (!strcmp( group->name, argv[oind] )) {
|
|
|
|
chanptr = group->channels;
|
|
|
|
channame = chanptr->string;
|
|
|
|
goto gotgrp;
|
|
|
|
}
|
|
|
|
channame = argv[oind];
|
|
|
|
gotgrp: ;
|
|
|
|
}
|
|
|
|
if ((boxlist = strchr( channame, ':' )))
|
|
|
|
*boxlist++ = 0;
|
|
|
|
for (chan = channels; chan; chan = chan->next)
|
|
|
|
if (!strcmp( chan->name, channame ))
|
|
|
|
goto gotchan;
|
|
|
|
fprintf( stderr, "No channel or group named '%s' defined.\n", channame );
|
2003-05-05 13:24:03 +00:00
|
|
|
ret = 1;
|
2004-03-27 16:07:20 +00:00
|
|
|
goto gotnone;
|
|
|
|
gotchan: ;
|
|
|
|
}
|
2005-12-28 10:02:22 +00:00
|
|
|
merge_actions( chan, ops, XOP_HAVE_TYPE, OP_MASK_TYPE, OP_MASK_TYPE );
|
|
|
|
merge_actions( chan, ops, XOP_HAVE_CREATE, OP_CREATE, 0 );
|
|
|
|
merge_actions( chan, ops, XOP_HAVE_EXPUNGE, OP_EXPUNGE, 0 );
|
2005-12-18 13:41:50 +00:00
|
|
|
|
2005-12-28 10:02:22 +00:00
|
|
|
boxes[M] = boxes[S] = cboxes = 0;
|
2004-03-27 16:07:20 +00:00
|
|
|
/* possible todo: handle master <-> slave swaps */
|
2005-12-28 10:02:22 +00:00
|
|
|
for (t = 0; t < 2; t++) {
|
|
|
|
if (ctx[t]) {
|
|
|
|
if (conf[t] == chan->stores[t])
|
|
|
|
continue;
|
|
|
|
free_string_list( uboxes[t] );
|
|
|
|
uboxes[t] = 0;
|
|
|
|
guboxes[t] = 0;
|
|
|
|
if (conf[t]->driver != chan->stores[t]->driver) {
|
|
|
|
driver[t]->close_store( ctx[t] );
|
|
|
|
ctx[t] = 0;
|
|
|
|
}
|
2004-03-27 16:07:20 +00:00
|
|
|
}
|
2005-12-28 10:02:22 +00:00
|
|
|
conf[t] = chan->stores[t];
|
|
|
|
driver[t] = conf[t]->driver;
|
|
|
|
if (!(ctx[t] = driver[t]->open_store( chan->stores[t], ctx[t] ))) {
|
|
|
|
ret = 1;
|
|
|
|
goto next;
|
2004-03-27 16:07:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
info( "Channel %s\n", chan->name );
|
|
|
|
if (list && multiple)
|
|
|
|
printf( "%s:\n", chan->name );
|
|
|
|
if (boxlist) {
|
|
|
|
for (boxlist = strtok( boxlist, ",\n" ); boxlist; boxlist = strtok( 0, ",\n" ))
|
|
|
|
if (list)
|
|
|
|
puts( boxlist );
|
2005-12-28 10:02:22 +00:00
|
|
|
else {
|
|
|
|
names[M] = names[S] = boxlist;
|
|
|
|
switch (sync_boxes( ctx, names, chan )) {
|
|
|
|
case SYNC_BAD(M): t = M; goto screwt;
|
|
|
|
case SYNC_BAD(S): t = S; goto screwt;
|
2004-03-27 16:07:20 +00:00
|
|
|
case SYNC_FAIL: ret = 1;
|
|
|
|
}
|
|
|
|
}
|
2005-12-28 10:02:22 +00:00
|
|
|
} else if (chan->patterns) {
|
|
|
|
for (t = 0; t < 2; t++) {
|
|
|
|
if (!guboxes[t]) {
|
|
|
|
if (driver[t]->list( ctx[t], &uboxes[t] ) != DRV_OK) {
|
|
|
|
screwt:
|
|
|
|
driver[t]->close_store( ctx[t] );
|
|
|
|
free_string_list( uboxes[t] );
|
|
|
|
uboxes[t] = 0;
|
|
|
|
guboxes[t] = 0;
|
|
|
|
ctx[t] = 0;
|
|
|
|
ret = 1;
|
|
|
|
goto next;
|
|
|
|
} else {
|
|
|
|
guboxes[t] = 1;
|
|
|
|
if (ctx[t]->conf->map_inbox)
|
|
|
|
add_string_list( &uboxes[t], ctx[t]->conf->map_inbox );
|
|
|
|
}
|
2004-03-27 16:07:20 +00:00
|
|
|
}
|
2005-12-28 10:02:22 +00:00
|
|
|
boxes[t] = filter_boxes( uboxes[t], chan->patterns );
|
2004-03-27 16:07:20 +00:00
|
|
|
}
|
2005-12-28 10:02:22 +00:00
|
|
|
for (mboxp = &boxes[M]; (mbox = *mboxp); ) {
|
|
|
|
for (sboxp = &boxes[S]; (sbox = *sboxp); sboxp = &sbox->next)
|
2004-03-27 16:07:20 +00:00
|
|
|
if (!strcmp( sbox->string, mbox->string )) {
|
|
|
|
*sboxp = sbox->next;
|
|
|
|
free( sbox );
|
|
|
|
*mboxp = mbox->next;
|
|
|
|
mbox->next = cboxes;
|
|
|
|
cboxes = mbox;
|
|
|
|
goto gotdupe;
|
|
|
|
}
|
|
|
|
mboxp = &mbox->next;
|
|
|
|
gotdupe: ;
|
|
|
|
}
|
|
|
|
for (mbox = cboxes; mbox; mbox = mbox->next)
|
|
|
|
if (list)
|
|
|
|
puts( mbox->string );
|
2005-12-28 10:02:22 +00:00
|
|
|
else {
|
|
|
|
names[M] = names[S] = mbox->string;
|
|
|
|
switch (sync_boxes( ctx, names, chan )) {
|
|
|
|
case SYNC_BAD(M): t = M; goto screwt;
|
|
|
|
case SYNC_BAD(S): t = S; goto screwt;
|
2004-03-27 16:07:20 +00:00
|
|
|
case SYNC_FAIL: ret = 1;
|
|
|
|
}
|
2005-12-28 10:02:22 +00:00
|
|
|
}
|
|
|
|
for (t = 0; t < 2; t++)
|
2005-12-28 11:07:47 +00:00
|
|
|
if ((chan->ops[1-t] & OP_MASK_TYPE) && (chan->ops[1-t] & OP_CREATE)) {
|
2005-12-28 10:02:22 +00:00
|
|
|
for (mbox = boxes[t]; mbox; mbox = mbox->next)
|
|
|
|
if (list)
|
|
|
|
puts( mbox->string );
|
|
|
|
else {
|
|
|
|
names[M] = names[S] = mbox->string;
|
|
|
|
switch (sync_boxes( ctx, names, chan )) {
|
|
|
|
case SYNC_BAD(M): t = M; goto screwt;
|
|
|
|
case SYNC_BAD(S): t = S; goto screwt;
|
|
|
|
case SYNC_FAIL: ret = 1;
|
|
|
|
}
|
2004-03-27 16:07:20 +00:00
|
|
|
}
|
2005-12-28 10:02:22 +00:00
|
|
|
}
|
2004-03-27 16:07:20 +00:00
|
|
|
} else
|
|
|
|
if (list)
|
2005-12-28 10:02:22 +00:00
|
|
|
printf( "%s <=> %s\n", chan->boxes[M], chan->boxes[S] );
|
2004-03-27 16:07:20 +00:00
|
|
|
else
|
2005-12-28 10:02:22 +00:00
|
|
|
switch (sync_boxes( ctx, chan->boxes, chan )) {
|
|
|
|
case SYNC_BAD(M): t = M; goto screwt;
|
|
|
|
case SYNC_BAD(S): t = S; goto screwt;
|
2004-03-27 16:07:20 +00:00
|
|
|
case SYNC_FAIL: ret = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
next:
|
|
|
|
free_string_list( cboxes );
|
2005-12-28 10:02:22 +00:00
|
|
|
free_string_list( boxes[M] );
|
|
|
|
free_string_list( boxes[S] );
|
2004-03-27 16:07:20 +00:00
|
|
|
if (all) {
|
|
|
|
if (!(chan = chan->next))
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (chanptr && (chanptr = chanptr->next))
|
|
|
|
continue;
|
|
|
|
gotnone:
|
|
|
|
if (!argv[++oind])
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-12-28 10:02:22 +00:00
|
|
|
free_string_list( uboxes[S] );
|
|
|
|
if (ctx[S])
|
|
|
|
driver[S]->close_store( ctx[S] );
|
|
|
|
free_string_list( uboxes[M] );
|
|
|
|
if (ctx[M])
|
|
|
|
driver[M]->close_store( ctx[M] );
|
2004-03-27 16:07:20 +00:00
|
|
|
|
|
|
|
return ret;
|
2000-12-20 21:41:21 +00:00
|
|
|
}
|