mirror of https://git.code.sf.net/p/isync/isync
Browse Source
as opposed to earlier threats, BerkDB was not entirely dropped; i suppose the isync 0.7 -> 0.8 change had a reason, so i added an alternative UID storage scheme. note that BDB 4.0 is not sufficient, as the db->open function changed in an incompatible way ... i updated the debian packaging except for a changelog entry. note that i removed the upgrade blurb, as upstream now has a smooth upgrade path down to at least isync 0.4.wip/ssl-fprint
Oswald Buddenhagen
21 years ago
48 changed files with 7938 additions and 4481 deletions
@ -1,39 +1,51 @@
|
||||
change of UIDVALIDITY shouldn't be considered fatal for the imap connection. |
||||
maybe the error handling needs to be cleaned up in general. |
||||
make SSL certificate validation more automatic. |
||||
|
||||
don't require maildir_trash. currently MaxMessages gets into the way of |
||||
simply removing it; that is fixable with some shuffling, though. |
||||
add asynchronous operation to remote mailbox drivers. this is actually |
||||
what prevents us from simply using c-client and thus becoming mailsync. |
||||
|
||||
refactor mailbox support. create proper mailbox drivers; handle imap and |
||||
maildir (and anything else) symmetrically; decouple UID->message mapping |
||||
from sync database - should use the same UID storing schemes as c-client |
||||
(pine, uw-imap) does, at least optionally, i think. |
||||
handle custom flags (keywords). |
||||
|
||||
add asynchrounous operation to remote mailbox drivers. this is actually |
||||
what prevents us from simply using c-client for the previous point and |
||||
thus simply becoming mailsync. |
||||
fix maildir_{open_store,list} to handle partial names (last char not slash). |
||||
|
||||
store message flags in sync database, so _un_setting them will be properly |
||||
synced as well. |
||||
add a way to automatically create and sync subfolders. |
||||
|
||||
handle custom imap flags. currently, isync just fails horribly if it |
||||
encounters some. |
||||
could store TUID even when UIDPLUS is supported. would avoid duplicated |
||||
messages after abort before new UID arrives. |
||||
|
||||
add options for fine-grained control of syncing operations (--new, --delete & |
||||
--flags) and direction (--push & --pull). |
||||
decouple TUID search from append. that's a prerequisite for usable |
||||
MULTIAPPEND, and is generally good for async. should be way faster, too, |
||||
as it saves repeated mailbox rescans with single-file formats. |
||||
|
||||
add support for syncing with other: and shared: via NAMESPACE |
||||
use MULTIAPPEND and FETCH with multiple messages. |
||||
|
||||
isync ignores asynchronous notifications (untagged responses), so mail |
||||
arriving during a fetch will not be fetched in the current run any more. |
||||
create dummies describing MIME structure of messages bigger than MaxSize. |
||||
flagging the dummy would fetch the real message. possibly remove --renew. |
||||
|
||||
add a way to automatically create and sync IMAP subfolders. |
||||
don't SELECT boxes unless really needed; in particular not for appending, |
||||
and in write-only mode not before changes are made. |
||||
|
||||
make the command line take precedence over the config file. |
||||
possibly request message attributes on a per-message basis from the drivers. |
||||
considerations: |
||||
- record non-existing UID ranges in the sync database, so IMAP FETCHes needn't |
||||
to exclude anyway non-existing messages explicitly. |
||||
- when detect unborn pairs and orphaned messages being gone? implied by expunge: |
||||
with trashing, by local driver, or of messages we deleted in this run. the |
||||
remaining cases could be handled by automatic periodical cleanup passes, an |
||||
explicit --cleanup action, or be implied by one of the other actions. |
||||
- the benefit of this is questionable, as fine-grained requests will result |
||||
in sending huge amounts of data, and upstream is often way slower than |
||||
downstream. |
||||
|
||||
possibly timestamp mails with remote arrival date. |
||||
maildir: possibly timestamp mails with remote arrival date. |
||||
|
||||
possibly recover from UIDVALIDITY change by resyncing according to message |
||||
IDs - this is a pretty common condition with uw-imap. |
||||
maybe throw out the ctx->recent stuff - it's used only for one info message. |
||||
|
||||
possibly use ^[[1m to highlight error messages. |
||||
|
||||
consider alternative trash implementation: trash only messages we delete, |
||||
and trash before marking them deleted in the mailbox. downside: all other |
||||
programs have to do the same. and what if the deleted flag is unset? |
||||
|
||||
items out of scope of purely UID based approach: |
||||
- detect message moves between folders |
||||
- recovering from UIDVALIDITY change (uw-imap does this a lot) |
||||
|
@ -1,16 +0,0 @@
|
||||
isync (0.8-1) unstable; urgency=low |
||||
|
||||
IMPORTANT upgrade note: |
||||
|
||||
This version includes a change to the way the UID for each message is |
||||
stored in the local mailbox. You need to remove all the messages in your |
||||
local folder if you were previously using another version of isync or else |
||||
you will end up with duplicate messages on your IMAP server. |
||||
|
||||
A suggested upgrade procedure is to use isync version 0.7 to synchronize |
||||
any local changes in isync-managed mailboxes with your IMAP server, and |
||||
then remove the contents of the local mailboxes, before upgrading to this |
||||
version. Then run isync again to pull down the mail again. You must do |
||||
this manually, the Debian package will not do this for you. |
||||
|
||||
-- Joey Hess <joeyh@debian.org> Tue, 29 Oct 2002 13:50:40 -0500 |
@ -1,22 +0,0 @@
|
||||
A note from isync's web site: |
||||
|
||||
To use this command effectively, you need a mail client that sets the T |
||||
(trashed) flag when it deletes a message from a maildir mailbox, instead of |
||||
just removing it altogether. Currently, only Mutt 1.3.27 supports this. Without |
||||
such a client, isync will refetch the locally deleted messages from the server |
||||
since they will never get expunged. Be sure to put |
||||
|
||||
set maildir_trash |
||||
|
||||
in your ~/.muttrc when using Mutt. |
||||
|
||||
isync can be integrated into Mutt fairly easily with a few hooks: |
||||
|
||||
folder-hook ~A bind index $ <sync-mailbox> |
||||
folder-hook +maildir 'macro index $ "<sync-mailbox>!isync -e maildir\n"' |
||||
|
||||
where maildir is the name of the local mailbox (or its alias). This works well |
||||
so long as you are not modifying the IMAP mailbox outside of Mutt. However, if |
||||
you are using another mail program simultaneously Mutt will have the wrong idea |
||||
of the local mailbox flags and messages will start disappearing from its index |
||||
display (don't worry, they are still on disk). |
@ -1,8 +0,0 @@
|
||||
#!/bin/sh |
||||
set -e |
||||
. /usr/share/debconf/confmodule |
||||
if [ "$1" = "configure" -a ! -z "$2" ] && \ |
||||
dpkg --compare-versions "$2" lt 0.8; then |
||||
db_input critical isync/upgrade_0.8 || true |
||||
db_go || true |
||||
fi |
@ -1,146 +0,0 @@
|
||||
#! /bin/sh -e |
||||
## 20-cleanup.dpatch by Theodore Ts'o <tytso@mit.edu> |
||||
## |
||||
## DP: Make sure the database store and the imap database is closed |
||||
## DP: if isync is aborted. |
||||
|
||||
[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts |
||||
patch_opts="${patch_opts:--f --no-backup-if-mismatch}" |
||||
|
||||
if [ $# -ne 1 ]; then |
||||
echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" |
||||
exit 1 |
||||
fi |
||||
case "$1" in |
||||
-patch) patch $patch_opts -p1 < $0;; |
||||
-unpatch) patch $patch_opts -p1 -R < $0;; |
||||
*) |
||||
echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" |
||||
exit 1;; |
||||
esac |
||||
|
||||
exit 0 |
||||
@DPATCH@ |
||||
|
||||
Problem description: |
||||
|
||||
>> If isync dies in the middle of synchronization, or the network |
||||
>> connection breaks while it is synchronizing a mailbox, new messages |
||||
>> which are downloaded from the IMAP server do not have their UID saved |
||||
>> to the maildir directory. This is REALLY, REALLY BAD, because it |
||||
>> means that on the next isync, the downloaded messages are re-uploaded |
||||
>> to the imap server, resulting in duplicate messages in the IMAP store. |
||||
>> |
||||
>> This takes means the network download takes longer, and if the network |
||||
>> connection is unrealible, it means it's more likely the the IMAP |
||||
>> connection will break, resulting in more duplicate messages being |
||||
>> uploaded to the servers. (The first time, 14 messages were uploaded |
||||
>> to the server. The second time I re-isynced, 65 messages were |
||||
>> uploaded to the server, resulting in some 79 duplicate messages that I |
||||
>> had to manually weed out. Grr, grr, grr, grr.) |
||||
|
||||
Problem solution: |
||||
|
||||
Actually, I managed to figure out the solution a while ago, and got |
||||
hung up trying to figure out the right way to submit the patches back |
||||
to upstream (there's no mailing list that I can find; so do you just |
||||
communicate directly with the developers). Anyway, I got busy and I |
||||
never had a chance to send the patches a while ago. |
||||
|
||||
This patch is not the best, but it does seem to work. Perhaps a |
||||
better approach would be to use the more advanced API's available with |
||||
berkdb, so you can actually force a sync to the db/dbm files after |
||||
the mail message has been downloaded. Fundamentally, that's the |
||||
problem. The id has been added to the db file, but the changes don't |
||||
get forced out to disk, so in the case of an abnormal termination of |
||||
the program, the id's never get written to disk. |
||||
|
||||
The patch enclosed below solves the problem by establishing a signal |
||||
handler, which cleans up in the case of the user typing ^C (after the |
||||
network connection has gone away, say because your GSM phone's GPRS |
||||
connection has gotten flakey, for example). However, it doesn't solve |
||||
the problem in case of an abrupt system crash. In order to address |
||||
that problem, the overall program interfaces would have to be changed |
||||
to use the newer berkdb interfaces directly, but that would mean |
||||
dropping compatibility with the ancient dbm interface. Personally, I |
||||
don't think that to be any great loss, but the changes would be much |
||||
more invasive, and would require agreement with the upstream |
||||
maintainer that this is the right way to go. |
||||
|
||||
Also, for bonus points, perhaps there should be an inactivity timer so |
||||
that isync can automatically figure out when the network connection |
||||
has gone away, and can do a clean shutdown and exit automatically, |
||||
instead of requiring the user to type ^C. |
||||
|
||||
- Ted |
||||
|
||||
|
||||
Patched files: src/main.c |
||||
=================================================================== |
||||
RCS file: isync-0.9.2/src/RCS/main.c,v |
||||
retrieving revision 1.3 |
||||
diff -u -r1.3 isync-0.9.2/src/main.c |
||||
--- isync-0.9.2/src/main.c 2004/01/10 01:13:38 1.3 |
||||
+++ isync-0.9.2/src/main.c 2004/01/10 01:14:34 |
||||
@@ -35,6 +35,7 @@ |
||||
#include <string.h> |
||||
#include <ctype.h> |
||||
#include <dirent.h> |
||||
+#include <signal.h> |
||||
|
||||
int Quiet; |
||||
|
||||
@@ -92,6 +93,22 @@ |
||||
unsigned int Tag = 0; |
||||
char Hostname[256]; |
||||
int Verbose = 0; |
||||
+mailbox_t *CleanupMail = 0; |
||||
+imap_t *CleanupImap = 0; |
||||
+int CleanupValid = 0; |
||||
+ |
||||
+static void signal_exit(int sig) |
||||
+{ |
||||
+ info("Abort received\n"); |
||||
+ if (CleanupValid) { |
||||
+ info("Aborting, cleaning up\n"); |
||||
+ if (CleanupMail) |
||||
+ maildir_close (CleanupMail); |
||||
+ if (CleanupImap) |
||||
+ imap_close (CleanupImap); |
||||
+ } |
||||
+ exit (1); |
||||
+} |
||||
|
||||
static void |
||||
version (void) |
||||
@@ -319,6 +336,10 @@ |
||||
usage (1); |
||||
} |
||||
|
||||
+ signal(SIGTERM, signal_exit); |
||||
+ signal(SIGHUP, signal_exit); |
||||
+ signal(SIGINT, signal_exit); |
||||
+ |
||||
gethostname (Hostname, sizeof (Hostname)); |
||||
|
||||
load_config (config, &o2o); |
||||
@@ -410,6 +431,9 @@ |
||||
ret = 1; |
||||
break; |
||||
} |
||||
+ CleanupValid = 1; |
||||
+ CleanupMail = mail; |
||||
+ CleanupImap = imap; |
||||
|
||||
info ("Synchronizing\n"); |
||||
i = (delete || box->delete) ? SYNC_DELETE : 0; |
||||
@@ -460,6 +484,8 @@ |
||||
|
||||
} while (0); |
||||
|
||||
+ CleanupValid = 0; |
||||
+ |
||||
/* we never sync the same mailbox twice, so close it now */ |
||||
if (mail) |
||||
maildir_close (mail); |
||||
|
@ -1,458 +0,0 @@
|
||||
#!/bin/sh -e |
||||
## 30-aysnc-imap.dpatch by Theodore Y. Ts'o <tytso@mit.edu> |
||||
## |
||||
## DP: Add the beginnings of asynchronous IMAP support. So far, we only |
||||
## DP: support asynchronous flag setting, since that's the easist. |
||||
## DP: Eventually we need to support asynchronous message fetches and |
||||
## DP: uploads. |
||||
|
||||
if [ $# -ne 1 ]; then |
||||
echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" |
||||
exit 1 |
||||
fi |
||||
|
||||
[ -f debian/patches/00patch-opts ] && . debian/patches/00patch-opts |
||||
patch_opts="${patch_opts:--f --no-backup-if-mismatch}" |
||||
|
||||
case "$1" in |
||||
-patch) patch $patch_opts -p1 < $0;; |
||||
-unpatch) patch $patch_opts -p1 -R < $0;; |
||||
*) |
||||
echo >&2 "`basename $0`: script expects -patch|-unpatch as argument" |
||||
exit 1;; |
||||
esac |
||||
|
||||
exit 0 |
||||
|
||||
@DPATCH@ |
||||
diff -urNad /usr/projects/isync/SF-cvs/isync/src/imap.c isync/src/imap.c |
||||
--- /usr/projects/isync/SF-cvs/isync/src/imap.c 2004-01-15 14:24:40.000000000 -0500 |
||||
+++ isync/src/imap.c 2004-01-15 20:36:15.000000000 -0500 |
||||
@@ -3,6 +3,7 @@ |
||||
* isync - IMAP4 to maildir mailbox synchronizer |
||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org> |
||||
* Copyright (C) 2002-2003 Oswald Buddenhagen <ossi@users.sf.net> |
||||
+ * Copyright (C) 2004 Theodore Ts'o <tytso@alum.mit.edu> |
||||
* |
||||
* 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 |
||||
@@ -35,13 +36,33 @@ |
||||
#include <string.h> |
||||
#include <ctype.h> |
||||
#include <sys/socket.h> |
||||
+#include <sys/ioctl.h> |
||||
#include <netinet/in.h> |
||||
+#include <netinet/tcp.h> |
||||
#include <arpa/inet.h> |
||||
#include <netdb.h> |
||||
#if HAVE_LIBSSL |
||||
# include <openssl/err.h> |
||||
#endif |
||||
|
||||
+struct imap_cmd { |
||||
+ unsigned int tag; |
||||
+ char *cmd; |
||||
+ int flags; |
||||
+ int response; |
||||
+ struct imap_cmd *next; |
||||
+ int (*complete_fn) (imap_t *imap, struct imap_cmd * cmd); |
||||
+}; |
||||
+ |
||||
+#define IMAP_FLAG_DONE 0x0001 |
||||
+ |
||||
+static struct imap_cmd *in_progress = NULL; |
||||
+static int num_in_progress = 0; |
||||
+int max_in_progress_high = 50; |
||||
+int max_in_progress_low = 10; |
||||
+ |
||||
+static struct imap_cmd *get_cmd_result(imap_t *imap); |
||||
+ |
||||
const char *Flags[] = { |
||||
"\\Seen", |
||||
"\\Answered", |
||||
@@ -199,6 +220,22 @@ |
||||
return write (sock->fd, buf, len); |
||||
} |
||||
|
||||
+static int |
||||
+socket_pending(Socket_t *sock) |
||||
+{ |
||||
+ int num = -1; |
||||
+ |
||||
+ if (ioctl(sock->fd, FIONREAD, &num) < 0) |
||||
+ return -1; |
||||
+ if (num > 0) |
||||
+ return num; |
||||
+#if HAVE_LIBSSL |
||||
+ if (sock->use_ssl) |
||||
+ return SSL_pending (sock->ssl); |
||||
+#endif |
||||
+ return 0; |
||||
+} |
||||
+ |
||||
static void |
||||
socket_perror (const char *func, Socket_t *sock, int ret) |
||||
{ |
||||
@@ -301,16 +338,20 @@ |
||||
} |
||||
|
||||
static int |
||||
-parse_fetch (imap_t * imap, list_t * list) |
||||
+parse_fetch (imap_t * imap, char *cmd) |
||||
{ |
||||
- list_t *tmp; |
||||
+ list_t *tmp, *list; |
||||
unsigned int uid = 0; |
||||
unsigned int mask = 0; |
||||
unsigned int size = 0; |
||||
message_t *cur; |
||||
|
||||
- if (!is_list (list)) |
||||
+ list = parse_list (cmd, 0); |
||||
+ |
||||
+ if (!is_list (list)) { |
||||
+ free_list(list); |
||||
return -1; |
||||
+ } |
||||
|
||||
for (tmp = list->child; tmp; tmp = tmp->next) |
||||
{ |
||||
@@ -325,6 +366,7 @@ |
||||
if (uid < imap->minuid) |
||||
{ |
||||
/* already saw this message */ |
||||
+ free_list(list); |
||||
return 0; |
||||
} |
||||
else if (uid > imap->maxuid) |
||||
@@ -387,6 +429,7 @@ |
||||
cur->flags = mask; |
||||
cur->size = size; |
||||
|
||||
+ free_list(list); |
||||
return 0; |
||||
} |
||||
|
||||
@@ -415,39 +458,121 @@ |
||||
} |
||||
} |
||||
|
||||
-static int |
||||
-imap_exec (imap_t * imap, const char *fmt, ...) |
||||
+static void print_imap_command(const char *cmd, FILE *f) |
||||
+{ |
||||
+ if (strncmp(cmd, "LOGIN", 5)) |
||||
+ fputs(cmd, f); |
||||
+ else |
||||
+ fputs("LOGIN USERNAME PASSWORD", f); |
||||
+} |
||||
+ |
||||
+static struct imap_cmd *issue_imap_cmd(imap_t *imap, |
||||
+ const char *fmt, ...) |
||||
{ |
||||
va_list ap; |
||||
- char tmp[256]; |
||||
- char buf[256]; |
||||
- char *cmd; |
||||
- char *arg; |
||||
- char *arg1; |
||||
- config_t *box; |
||||
+ char tmp[1024]; |
||||
+ char buf[1024]; |
||||
+ struct imap_cmd *cmd; |
||||
int n; |
||||
|
||||
+ cmd = malloc(sizeof(struct imap_cmd)); |
||||
+ if (!cmd) |
||||
+ return NULL; |
||||
+ |
||||
+ cmd->tag = ++Tag; |
||||
+ cmd->flags = 0; |
||||
+ cmd->response = 0; |
||||
+ cmd->complete_fn = 0; |
||||
+ |
||||
va_start (ap, fmt); |
||||
vsnprintf (tmp, sizeof (tmp), fmt, ap); |
||||
va_end (ap); |
||||
|
||||
- snprintf (buf, sizeof (buf), "%d %s\r\n", ++Tag, tmp); |
||||
+ cmd->cmd = malloc(strlen(tmp)+1); |
||||
+ if (cmd->cmd) |
||||
+ strcpy(cmd->cmd, tmp); |
||||
+ |
||||
+ snprintf (buf, sizeof (buf), "%d %s\r\n", cmd->tag, tmp); |
||||
if (Verbose) { |
||||
- printf (">>> %s", buf); |
||||
+ if (num_in_progress) |
||||
+ printf("(%d in progress) ", num_in_progress); |
||||
+ printf(">>> %d ", cmd->tag); |
||||
+ print_imap_command(tmp, stdout); |
||||
+ fputc('\n', stdout); |
||||
fflush (stdout); |
||||
} |
||||
n = socket_write (imap->sock, buf, strlen (buf)); |
||||
if (n <= 0) |
||||
{ |
||||
socket_perror ("write", imap->sock, n); |
||||
- return -1; |
||||
+ free(cmd); |
||||
+ return NULL; |
||||
} |
||||
+ cmd->next = in_progress; |
||||
+ in_progress = cmd; |
||||
+ num_in_progress++; |
||||
+ if ((num_in_progress > max_in_progress_high) || |
||||
+ socket_pending(imap->sock)) { |
||||
+ while ((num_in_progress > max_in_progress_low) || |
||||
+ socket_pending(imap->sock)) { |
||||
+ if (Verbose && socket_pending(imap->sock)) |
||||
+ printf("(Socket input pending)\n"); |
||||
+ get_cmd_result(imap); |
||||
+ } |
||||
+ } |
||||
+ return cmd; |
||||
+} |
||||
+ |
||||
+static struct imap_cmd *find_imap_cmd(unsigned int tag) |
||||
+{ |
||||
+ struct imap_cmd *cmd, *prev; |
||||
+ |
||||
+ for (prev=NULL, cmd=in_progress; cmd; cmd = cmd->next) { |
||||
+ if (tag == cmd->tag) { |
||||
+ return cmd; |
||||
+ } |
||||
+ prev = cmd; |
||||
+ } |
||||
+ return NULL; |
||||
+} |
||||
+ |
||||
+static void dequeue_imap_cmd(unsigned int tag) |
||||
+{ |
||||
+ struct imap_cmd *cmd, *prev; |
||||
+ |
||||
+ for (prev=NULL, cmd=in_progress; cmd; cmd = cmd->next) { |
||||
+ if (tag != cmd->tag) { |
||||
+ prev = cmd; |
||||
+ continue; |
||||
+ } |
||||
+ if (prev) |
||||
+ prev->next = cmd->next; |
||||
+ else |
||||
+ in_progress = cmd->next; |
||||
+ cmd->next = 0; |
||||
+ if (cmd->cmd) |
||||
+ free(cmd->cmd); |
||||
+ cmd->cmd = 0; |
||||
+ free(cmd); |
||||
+ break; |
||||
+ } |
||||
+} |
||||
+ |
||||
+static struct imap_cmd *get_cmd_result(imap_t *imap) |
||||
+{ |
||||
+ char *cmd; |
||||
+ char *arg; |
||||
+ char *arg1; |
||||
+ config_t *box; |
||||
+ int n; |
||||
+ unsigned int tag; |
||||
+ struct imap_cmd *cmdp; |
||||
|
||||
for (;;) |
||||
{ |
||||
next: |
||||
if (buffer_gets (imap->buf, &cmd)) |
||||
- return -1; |
||||
+ return NULL; |
||||
|
||||
arg = next_arg (&cmd); |
||||
if (*arg == '*') |
||||
@@ -456,7 +581,7 @@ |
||||
if (!arg) |
||||
{ |
||||
fprintf (stderr, "IMAP error: unable to parse untagged response\n"); |
||||
- return -1; |
||||
+ return NULL; |
||||
} |
||||
|
||||
if (!strcmp ("NAMESPACE", arg)) |
||||
@@ -528,23 +653,14 @@ |
||||
imap->recent = atoi (arg); |
||||
else if (!strcmp ("FETCH", arg1)) |
||||
{ |
||||
- list_t *list; |
||||
- |
||||
- list = parse_list (cmd, 0); |
||||
- |
||||
- if (parse_fetch (imap, list)) |
||||
- { |
||||
- free_list (list); |
||||
- return -1; |
||||
- } |
||||
- |
||||
- free_list (list); |
||||
+ if (parse_fetch (imap, cmd)) |
||||
+ return NULL; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
fprintf (stderr, "IMAP error: unable to parse untagged response\n"); |
||||
- return -1; |
||||
+ return NULL; |
||||
} |
||||
} |
||||
#if HAVE_LIBSSL |
||||
@@ -555,7 +671,7 @@ |
||||
if (!imap->cram) |
||||
{ |
||||
fprintf (stderr, "IMAP error, not doing CRAM-MD5 authentication\n"); |
||||
- return -1; |
||||
+ return NULL; |
||||
} |
||||
resp = cram (cmd, imap->box->user, imap->box->pass); |
||||
|
||||
@@ -568,34 +684,94 @@ |
||||
if (n <= 0) |
||||
{ |
||||
socket_perror ("write", imap->sock, n); |
||||
- return -1; |
||||
+ return NULL; |
||||
} |
||||
n = socket_write (imap->sock, "\r\n", 2); |
||||
if (n <= 0) |
||||
{ |
||||
socket_perror ("write", imap->sock, n); |
||||
- return -1; |
||||
+ return NULL; |
||||
} |
||||
imap->cram = 0; |
||||
} |
||||
#endif |
||||
- else if ((size_t) atol (arg) != Tag) |
||||
- { |
||||
- fprintf (stderr, "IMAP error: wrong tag\n"); |
||||
- return -1; |
||||
- } |
||||
- else |
||||
- { |
||||
- arg = next_arg (&cmd); |
||||
- parse_response_code (imap, cmd); |
||||
- if (!strcmp ("OK", arg)) |
||||
- return 0; |
||||
- return -1; |
||||
+ else { |
||||
+ tag = (unsigned int) atol (arg); |
||||
+ cmdp = find_imap_cmd(tag); |
||||
+ if (!cmdp) { |
||||
+ fprintf(stderr, "IMAP error: sent unknown tag: %u\n", |
||||
+ tag); |
||||
+ return NULL; |
||||
+ } |
||||
+ arg = next_arg (&cmd); |
||||
+ if (strncmp("OK", arg, 2)) { |
||||
+ if (cmdp->cmd) { |
||||
+ fputc('\'', stderr); |
||||
+ print_imap_command(cmdp->cmd, stderr); |
||||
+ fputc('\'', stderr); |
||||
+ } else |
||||
+ fprintf(stderr, "tag %u", tag); |
||||
+ fprintf(stderr, " returned an error (%s): %s\n", |
||||
+ arg, cmd ? cmd : ""); |
||||
+ cmdp->response = -1; |
||||
+ } |
||||
+ parse_response_code (imap, cmd); |
||||
+ num_in_progress--; |
||||
+ cmdp->flags |= IMAP_FLAG_DONE; |
||||
+ if (Verbose) |
||||
+ printf("Tag %u completed with response %d\n", |
||||
+ cmdp->tag, cmdp->response); |
||||
+ return cmdp; |
||||
} |
||||
} |
||||
/* not reached */ |
||||
} |
||||
|
||||
+static void flush_imap_cmds(imap_t *imap) |
||||
+{ |
||||
+ struct imap_cmd *cmdp; |
||||
+ |
||||
+ while (num_in_progress) { |
||||
+ if (in_progress && in_progress->flags & IMAP_FLAG_DONE) { |
||||
+ dequeue_imap_cmd(in_progress->tag); |
||||
+ continue; |
||||
+ } |
||||
+ cmdp = get_cmd_result(imap); |
||||
+ if (!cmdp) |
||||
+ printf("Error trying to flush pending imap cmds\n"); |
||||
+ } |
||||
+} |
||||
+ |
||||
+static int |
||||
+imap_exec (imap_t * imap, const char *fmt, ...) |
||||
+{ |
||||
+ va_list ap; |
||||
+ char tmp[1024]; |
||||
+ struct imap_cmd *cmdp, *waitp; |
||||
+ int result; |
||||
+ |
||||
+ va_start (ap, fmt); |
||||
+ vsnprintf (tmp, sizeof (tmp), fmt, ap); |
||||
+ va_end (ap); |
||||
+ |
||||
+ cmdp = issue_imap_cmd(imap, "%s", tmp); |
||||
+ if (!cmdp) |
||||
+ return -1; |
||||
+ |
||||
+ if (cmdp->flags & IMAP_FLAG_DONE) |
||||
+ return cmdp->response; |
||||
+ |
||||
+ do { |
||||
+ waitp = get_cmd_result(imap); |
||||
+ } while (waitp->tag != cmdp->tag); |
||||
+ |
||||
+ result = cmdp->response; |
||||
+ dequeue_imap_cmd(cmdp->tag); |
||||
+ |
||||
+ return cmdp->response; |
||||
+ |
||||
+} |
||||
+ |
||||
#ifdef HAVE_LIBSSL |
||||
static int |
||||
start_tls (imap_t *imap, config_t * cfg) |
||||
@@ -1039,6 +1215,7 @@ |
||||
size_t n; |
||||
char buf[1024]; |
||||
|
||||
+ flush_imap_cmds(imap); |
||||
send_server (imap->sock, "UID FETCH %d BODY.PEEK[]", uid); |
||||
|
||||
for (;;) |
||||
@@ -1160,7 +1337,9 @@ |
||||
(buf[0] != 0) ? " " : "", Flags[i]); |
||||
} |
||||
|
||||
- return imap_exec (imap, "UID STORE %d +FLAGS.SILENT (%s)", uid, buf); |
||||
+ if (issue_imap_cmd(imap, "UID STORE %d +FLAGS.SILENT (%s)", uid, buf)) |
||||
+ return 0; |
||||
+ return -1; |
||||
} |
||||
|
||||
int |
||||
@@ -1249,6 +1428,7 @@ |
||||
strcat (flagstr,") "); |
||||
} |
||||
|
||||
+ flush_imap_cmds(imap); |
||||
send_server (imap->sock, "APPEND %s%s %s{%d}", |
||||
imap->prefix, imap->box->box, flagstr, len + extra); |
||||
|
||||
@@ -1341,6 +1521,7 @@ |
||||
} |
||||
|
||||
/* didn't receive an APPENDUID */ |
||||
+ flush_imap_cmds(imap); |
||||
send_server (imap->sock, |
||||
"UID SEARCH HEADER X-TUID %08lx%05lx%04x", |
||||
tv.tv_sec, tv.tv_usec, pid); |
@ -1 +0,0 @@
|
||||
[type: gettext/rfc822deb] templates |
@ -1,60 +0,0 @@
|
||||
# |
||||
# Translators, if you are not familiar with the PO format, gettext |
||||
# documentation is worth reading, especially sections dedicated to |
||||
# this format, e.g. by running: |
||||
# info -n '(gettext)PO Files' |
||||
# info -n '(gettext)Header Entry' |
||||
# |
||||
# Some information specific to po-debconf are available at |
||||
# /usr/share/doc/po-debconf/README-trans |
||||
# or http://www.debian.org/intl/l10n/po-debconf/README-trans |
||||
# |
||||
# Developers do not need to manually edit POT or PO files. |
||||
# |
||||
#, fuzzy |
||||
msgid "" |
||||
msgstr "" |
||||
"Project-Id-Version: PACKAGE VERSION\n" |
||||
"Report-Msgid-Bugs-To: \n" |
||||
"POT-Creation-Date: 2003-10-14 21:55+0200\n" |
||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" |
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" |
||||
"Language-Team: LANGUAGE <LL@li.org>\n" |
||||
"MIME-Version: 1.0\n" |
||||
"Content-Type: text/plain; charset=CHARSET\n" |
||||
"Content-Transfer-Encoding: 8bit\n" |
||||
|
||||
#. Description |
||||
#: ../templates:4 |
||||
msgid "Abort isync upgrade" |
||||
msgstr "" |
||||
|
||||
#. Description |
||||
#: ../templates:4 |
||||
msgid "" |
||||
"You are upgrading from an older version of isync that stored the UID of each " |
||||
"message in a way that is not compatable with the new version. You need to " |
||||
"remove all the messages in local folders downloaded with the old version of " |
||||
"isync. Otherwise isync will get confused and upload duplicate messages to " |
||||
"the IMAP server." |
||||
msgstr "" |
||||
|
||||
#. Description |
||||
#: ../templates:4 |
||||
msgid "" |
||||
"A suggested upgrade procedure is to use the isync version 0.7 to synchronize " |
||||
"any local changes in isync-managed mailboxes with your IMAP server (if there " |
||||
"are any local changes to synchronise), and then remove the contents of the " |
||||
"local mailboxes, before upgrading to version 0.8 or above. Then run isync " |
||||
"again to pull down the mail again. You must do this manually; the Debian " |
||||
"package will not do this for you." |
||||
msgstr "" |
||||
|
||||
#. Description |
||||
#: ../templates:4 |
||||
msgid "" |
||||
"If you want, the upgrade of isync can be aborted to let you deal with this " |
||||
"issue. Or you can just suspend the upgrade or switch to a different virtual " |
||||
"console to take care of it. Do not continue past this point before manually " |
||||
"resolving this issue!" |
||||
msgstr "" |
@ -1,19 +0,0 @@
|
||||
#!/bin/sh |
||||
set -e |
||||
|
||||
if [ "$1" = "upgrade" ] && dpkg --compare-versions "$2" lt "0.8"; then |
||||
# Do not do debconf stuff if debconf is not there. |
||||
# I don't want to have to pre-depend on debconf. |
||||
if [ -e /usr/share/debconf/confmodule ]; then |
||||
. /usr/share/debconf/confmodule |
||||
db_get isync/upgrade_0.8 |
||||
if [ "$RET" = true ]; then |
||||
echo "Aborting isync upgrade at your request so you can manually resolve upgrade issue." >&2 |
||||
exit 1 |
||||
fi |
||||
else |
||||
echo "WARNING: Read NEWS.Debian file about manual upgrade issues from isync 0.7." >&2 |
||||
fi |
||||
fi |
||||
|
||||
#DEBHELPER# |
@ -1,21 +0,0 @@
|
||||
Template: isync/upgrade_0.8 |
||||
Type: boolean |
||||
Default: false |
||||
_Description: Abort isync upgrade |
||||
You are upgrading from an older version of isync that stored the UID of |
||||
each message in a way that is not compatable with the new version. You |
||||
need to remove all the messages in local folders downloaded with the old |
||||
version of isync. Otherwise isync will get confused and upload duplicate |
||||
messages to the IMAP server. |
||||
. |
||||
A suggested upgrade procedure is to use the isync version 0.7 to |
||||
synchronize any local changes in isync-managed mailboxes with your IMAP |
||||
server (if there are any local changes to synchronise), and then remove |
||||
the contents of the local mailboxes, before upgrading to version 0.8 or |
||||
above. Then run isync again to pull down the mail again. You must do this |
||||
manually; the Debian package will not do this for you. |
||||
. |
||||
If you want, the upgrade of isync can be aborted to let you deal with this |
||||
issue. Or you can just suspend the upgrade or switch to a different |
||||
virtual console to take care of it. Do not continue past this point before |
||||
manually resolving this issue! |
@ -1,4 +1,5 @@
|
||||
.deps |
||||
Makefile |
||||
Makefile.in |
||||
isync |
||||
mbsync |
||||
mdconvert |
||||
|
@ -1,5 +1,16 @@
|
||||
bin_PROGRAMS = isync
|
||||
isync_SOURCES = main.c imap.c sync.c maildir.c list.c cram.c config.c dotlock.c
|
||||
noinst_HEADERS = isync.h dotlock.h
|
||||
INCLUDES=$(RPM_OPT_FLAGS)
|
||||
DISTCLEANFILES = *~
|
||||
if with_compat |
||||
compat_dir = compat
|
||||
endif |
||||
SUBDIRS = $(compat_dir)
|
||||
|
||||
bin_PROGRAMS = mbsync mdconvert
|
||||
|
||||
mbsync_SOURCES = main.c sync.c config.c util.c drv_imap.c drv_maildir.c
|
||||
mbsync_LDADD = -ldb $(SSL_LIBS) $(SOCK_LIBS)
|
||||
noinst_HEADERS = isync.h
|
||||
|
||||
mdconvert_SOURCES = mdconvert.c
|
||||
mdconvert_LDADD = -ldb
|
||||
|
||||
man_MANS = mbsync.1 mdconvert.1
|
||||
EXTRA_DIST = mbsyncrc.sample $(man_MANS)
|
||||
|
@ -0,0 +1,8 @@
|
||||
bin_PROGRAMS = isync
|
||||
|
||||
isync_SOURCES = main.c config.c convert.c util.c
|
||||
isync_LDADD = -ldb
|
||||
noinst_HEADERS = isync.h
|
||||
|
||||
man_MANS = isync.1
|
||||
EXTRA_DIST = isyncrc.sample $(man_MANS)
|
@ -0,0 +1,443 @@
|
||||
/*
|
||||
* isync - mbsync wrapper: IMAP4 to maildir mailbox synchronizer |
||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org> |
||||
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#include "isync.h" |
||||
|
||||
#include <unistd.h> |
||||
#include <limits.h> |
||||
#include <errno.h> |
||||
#include <pwd.h> |
||||
#include <sys/types.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.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) |
||||
perror( "fopen" ); |
||||
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 (!memcmp( "imaps:", val, 6 )) { |
||||
val += 6; |
||||
cfg->use_imaps = 1; |
||||
cfg->port = 993; |
||||
cfg->use_sslv2 = 1; |
||||
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 )) |
||||
cfg->use_sslv2 = is_true( val ); |
||||
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 void |
||||
write_imap_server( FILE *fp, config_t *cfg ) |
||||
{ |
||||
config_t *pbox; |
||||
char *p, *p2; |
||||
int hl, a1, a2, a3, a4; |
||||
char buf[128]; |
||||
static int tunnels; |
||||
|
||||
if (cfg->tunnel) { |
||||
nfasprintf( (char **)&cfg->server_name, "tunnel%d", ++tunnels ); |
||||
fprintf( fp, "IMAPAccount %s\nTunnel \"%s\"\n", |
||||
cfg->server_name, cfg->tunnel ); |
||||
} else { |
||||
if (sscanf( cfg->host, "%d.%d.%d.%d", &a1, &a2, &a3, &a4 ) == 4) |
||||
cfg->server_name = nfstrdup( cfg->host ); |
||||
else { |
||||
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 (!memcmp( pbox->server_name, buf, hl + 1 )) { |
||||
nfasprintf( (char **)&cfg->server_name, "%s-%d", buf, ++pbox->servers ); |
||||
goto gotsrv; |
||||
} |
||||
cfg->server_name = nfstrdup( buf ); |
||||
cfg->servers = 1; |
||||
gotsrv: ; |
||||
} |
||||
fprintf( fp, "IMAPAccount %s\n", cfg->server_name ); |
||||
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", cfg->user ); |
||||
if (cfg->pass) |
||||
fprintf( fp, "Pass \"%s\"\n", cfg->pass ); |
||||
fprintf( fp, "RequireCRAM %s\nRequireSSL %s\n" |
||||
"UseSSLv2 %s\nUseSSLv3 %s\nUseTLSv1 %s\n", |
||||
tb(cfg->require_cram), tb(cfg->require_ssl), |
||||
tb(cfg->use_sslv2), tb(cfg->use_sslv3), tb(cfg->use_tlsv1) ); |
||||
if ((cfg->use_imaps || cfg->use_sslv2 || cfg->use_sslv3 || cfg->use_tlsv1) && |
||||
cfg->cert_file) |
||||
fprintf( fp, "CertificateFile %s\n", 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->server_name, cfg->stores ); |
||||
else |
||||
cfg->store_name = cfg->server_name; |
||||
fprintf( fp, "IMAPStore %s\nAccount %s\n", |
||||
cfg->store_name, cfg->server_name ); |
||||
if (*folder) |
||||
fprintf( fp, "Path \"%s\"\n", folder ); |
||||
else |
||||
fprintf( fp, "UseNamespace %s\n", tb(cfg->use_namespace) ); |
||||
if (inbox) |
||||
fprintf( fp, "MapInbox \"%s\"\n", inbox ); |
||||
if (cfg->copy_deleted_to) |
||||
fprintf( fp, "Trash \"%s\"\n", 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) |
||||
fputs( "Sync New ReNew Flags\n", fp ); |
||||
if (cfg->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; |
||||
config_t *box, *sbox, *pbox; |
||||
|
||||
if (!(fp = fdopen( fd, "w" ))) { |
||||
perror( "fdopen" ); |
||||
return; |
||||
} |
||||
|
||||
fprintf( fp, "SyncState *\n\nMaildirStore local\nPath \"%s/\"\nAltMap %s\n\n", maildir, tb( altmap > 0 ) ); |
||||
if (o2o) { |
||||
write_imap_server( fp, &global ); |
||||
write_imap_store( fp, &global ); |
||||
fprintf( fp, "Channel 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_sslv2 || |
||||
box->use_sslv3 || box->use_tlsv1) && |
||||
mstrcmp( pbox->cert_file, box->cert_file )) /* nonsense */ |
||||
continue; |
||||
if (pbox->use_imaps != box->use_imaps || |
||||
pbox->use_sslv2 != box->use_sslv2 || |
||||
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: |
||||
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 :local:%s\n", |
||||
box->channel_name, box->store_name, box->box, box->path ); |
||||
write_channel_parm( fp, box ); |
||||
} |
||||
|
||||
} |
||||
|
||||
fclose( fp ); |
||||
} |
||||
|
||||
config_t * |
||||
find_box( const char *s ) |
||||
{ |
||||
config_t *p; |
||||
char *t; |
||||
|
||||
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; |
||||
} |
@ -0,0 +1,259 @@
|
||||
/*
|
||||
* isync - mbsync wrapper: IMAP4 to maildir mailbox synchronizer |
||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org> |
||||
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#include "isync.h" |
||||
|
||||
#include <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 <errno.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, bl, 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 )) { |
||||
fprintf( stderr, "ERROR: stat %s: %s (errno %d)\n", buf, |
||||
strerror(errno), errno ); |
||||
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) { |
||||
perror( 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 )) { |
||||
perror( ilname ); |
||||
err2: |
||||
close( fd ); |
||||
goto err1; |
||||
} |
||||
|
||||
if (!(fp = fopen( iuvname, "r" ))) { |
||||
perror( iuvname ); |
||||
goto err2; |
||||
} |
||||
fscanf( fp, "%d", &uidval ); |
||||
fclose( fp ); |
||||
if (!(fp = fopen( imuname, "r" ))) { |
||||
perror( imuname ); |
||||
goto err2; |
||||
} |
||||
fscanf( fp, "%d", &maxuid ); |
||||
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++) { |
||||
bl = nfsnprintf( buf, sizeof(buf), "%s/%s/", mboxdir, subdirs[i] ); |
||||
if (!(d = opendir( buf ))) { |
||||
perror( "opendir" ); |
||||
err4: |
||||
if (msgs) |
||||
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" ))) { |
||||
perror( 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 ); |
||||
rename( iumname, diumname ); |
||||
} else { |
||||
if (!(fp = fopen( uvname, "w" ))) { |
||||
perror( uvname ); |
||||
goto err4; |
||||
} |
||||
fprintf( fp, "%d\n%d\n", uidval, maxuid ); |
||||
fclose( fp ); |
||||
} |
||||
|
||||
unlink( iuvname ); |
||||
unlink( imuname ); |
||||
|
||||
close( fd ); |
||||
unlink( ilname ); |
||||
|
||||
if (msgs) |
||||
free( msgs ); |
||||
free( mboxdir ); |
||||
return; |
||||
} |
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* isync - mbsync wrapper: IMAP4 to maildir mailbox synchronizer |
||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org> |
||||
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#define _GNU_SOURCE |
||||
|
||||
#include <config.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 |
||||
|
||||
typedef struct config { |
||||
struct config *next; |
||||
|
||||
const char *server_name; |
||||
int 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_sslv2:1; |
||||
unsigned int use_sslv3:1; |
||||
unsigned int use_tlsv1:1; |
||||
char *cert_file; |
||||
|
||||
const char *store_name; |
||||
int 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 config_t global, *boxes; |
||||
|
||||
extern const char *maildir, *xmaildir, *folder, *inbox; |
||||
extern int o2o, altmap; |
||||
|
||||
/* 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 ATTR_NORETURN oob( void ); |
@ -0,0 +1,431 @@
|
||||
/*
|
||||
* isync - mbsync wrapper: IMAP4 to maildir mailbox synchronizer |
||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org> |
||||
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#include "isync.h" |
||||
|
||||
#include <sys/types.h> |
||||
#include <sys/stat.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <fcntl.h> |
||||
#include <stdarg.h> |
||||
#include <limits.h> |
||||
#include <pwd.h> |
||||
#include <stdio.h> |
||||
#include <errno.h> |
||||
#include <string.h> |
||||
#include <ctype.h> |
||||
#include <dirent.h> |
||||
|
||||
#if HAVE_GETOPT_LONG |
||||
# define _GNU_SOURCE |
||||
# include <getopt.h> |
||||
struct option Opts[] = { |
||||
{"write", 0, NULL, 'w' }, |
||||
{"writeto", 0, NULL, 'W' }, |
||||
{"all", 0, NULL, 'a' }, |
||||
{"list", 0, NULL, 'l'}, |
||||
{"config", 1, NULL, 'c'}, |
||||
{"create", 0, NULL, 'C'}, |
||||
{"create-local", 0, NULL, 'L'}, |
||||
{"create-remote", 0, NULL, 'R'}, |
||||
{"delete", 0, NULL, 'd'}, |
||||
{"expunge", 0, NULL, 'e'}, |
||||
{"fast", 0, NULL, 'f'}, |
||||
{"help", 0, NULL, 'h'}, |
||||
{"remote", 1, NULL, 'r'}, |
||||
{"folder", 1, NULL, 'F'}, |
||||
{"maildir", 1, NULL, 'M'}, |
||||
{"one-to-one", 0, NULL, '1'}, |
||||
{"inbox", 1, NULL, 'I'}, |
||||
{"host", 1, NULL, 's'}, |
||||
{"port", 1, NULL, 'p'}, |
||||
{"debug", 0, NULL, 'D'}, |
||||
{"quiet", 0, NULL, 'q'}, |
||||
{"user", 1, NULL, 'u'}, |
||||
{"version", 0, NULL, 'v'}, |
||||
{"verbose", 0, NULL, 'V'}, |
||||
{0, 0, 0, 0} |
||||
}; |
||||
#endif |
||||
|
||||
static void |
||||
version( void ) |
||||
{ |
||||
puts( PACKAGE " " VERSION ); |
||||
exit( 0 ); |
||||
} |
||||
|
||||
static void |
||||
usage( int code ) |
||||
{ |
||||
fputs( |
||||
PACKAGE " " VERSION " - mbsync wrapper: IMAP4 to maildir synchronizer\n" |
||||
"Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org>\n" |
||||
"Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net>\n" |
||||
"usage:\n" |
||||
" " PACKAGE " [ flags ] mailbox [mailbox ...]\n" |
||||
" " PACKAGE " [ flags ] -a\n" |
||||
" " PACKAGE " [ flags ] -l\n" |
||||
" -a, --all synchronize all defined mailboxes\n" |
||||
" -l, --list list all defined mailboxes and exit\n" |
||||
" -L, --create-local create local maildir mailbox if nonexistent\n" |
||||
" -R, --create-remote create remote imap mailbox if nonexistent\n" |
||||
" -C, --create create both local and remote mailboxes if nonexistent\n" |
||||
" -d, --delete delete local msgs that don't exist on the server\n" |
||||
" -e, --expunge expunge deleted messages\n" |
||||
" -f, --fast only fetch new messages\n" |
||||
" -r, --remote BOX remote mailbox\n" |
||||
" -F, --folder DIR remote IMAP folder containing mailboxes\n" |
||||
" -M, --maildir DIR local directory containing mailboxes\n" |
||||
" -1, --one-to-one map every IMAP <folder>/box to <maildir>/box\n" |
||||
" -I, --inbox BOX map IMAP INBOX to <maildir>/BOX (exception to -1)\n" |
||||
" -s, --host HOST IMAP server address\n" |
||||
" -p, --port PORT server IMAP port\n" |
||||
" -u, --user USER IMAP user name\n" |
||||
" -c, --config CONFIG read an alternate config file (default: ~/.isyncrc)\n" |
||||
" -D, --debug print debugging messages\n" |
||||
" -V, --verbose verbose mode (display network traffic)\n" |
||||
" -q, --quiet don't display progress info\n" |
||||
" -v, --version display version\n" |
||||
" -h, --help display this help message\n\n" |
||||
"Note that this is a wrapper binary only; the \"real\" isync is named \"mbsync\".\n" |
||||
"Options to permanently transform your old isync configuration:\n" |
||||
" -w, --write write permanent mbsync configuration\n" |
||||
" -W, --writeto FILE write permanent mbsync configuration to FILE\n", |
||||
code ? stderr : stdout ); |
||||
exit( code ); |
||||
} |
||||
|
||||
static const char * |
||||
strrstr( const char *h, const char *n ) |
||||
{ |
||||
char *p = strstr( h, n ); |
||||
if (!p) |
||||
return 0; |
||||
do { |
||||
h = p; |
||||
p = strstr( h + 1, n ); |
||||
} while (p); |
||||
return h;
|
||||
} |
||||
|
||||
static void |
||||
add_arg( char ***args, const char *arg ) |
||||
{ |
||||
int nu = 0; |
||||
if (*args) |
||||
for (; (*args)[nu]; nu++); |
||||
*args = nfrealloc( *args, sizeof(char *) * (nu + 2)); |
||||
(*args)[nu] = nfstrdup( arg ); |
||||
(*args)[nu + 1] = 0; |
||||
} |
||||
|
||||
#define OP_EXPUNGE (1<<0) |
||||
#define OP_DELETE (1<<1) |
||||
#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; |
||||
|
||||
const char *Home; |
||||
|
||||
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; |
||||
} |
||||
|
||||
/* defaults */ |
||||
/* XXX the precedence is borked:
|
||||
it's defaults < cmdline < file instead of defaults < file < cmdline */ |
||||
global.port = 143; |
||||
global.box = "INBOX"; |
||||
global.use_namespace = 1; |
||||
global.require_ssl = 1; |
||||
global.use_tlsv1 = 1; |
||||
folder = ""; |
||||
maildir = "~"; |
||||
xmaildir = Home; |
||||
|
||||
#define FLAGS "wW:alCLRc:defhp:qu:r:F:M:1I:s:vVD" |
||||
|
||||
mod = all = list = ops = writeout = Quiet = Verbose = Debug = 0; |
||||
#if HAVE_GETOPT_LONG |
||||
while ((i = getopt_long( argc, argv, FLAGS, Opts, NULL )) != -1) |
||||
#else |
||||
while ((i = getopt( argc, argv, FLAGS )) != -1) |
||||
#endif |
||||
{ |
||||
switch (i) { |
||||
case 'W': |
||||
outconfig = optarg; |
||||
/* plopp */ |
||||
case 'w': |
||||
writeout = 1; |
||||
break; |
||||
case 'l': |
||||
list = 1; |
||||
/* plopp */ |
||||
case 'a': |
||||
all = 1; |
||||
break; |
||||
case '1': |
||||
o2o = 1; |
||||
mod = 1; |
||||
break; |
||||
case 'C': |
||||
ops |= OP_CREATE_REMOTE|OP_CREATE_LOCAL; |
||||
break; |
||||
case 'L': |
||||
ops |= OP_CREATE_LOCAL; |
||||
break; |
||||
case 'R': |
||||
ops |= OP_CREATE_REMOTE; |
||||
break; |
||||
case 'c': |
||||
config = optarg; |
||||
break; |
||||
case 'd': |
||||
ops |= OP_DELETE; |
||||
break; |
||||
case 'e': |
||||
ops |= OP_EXPUNGE; |
||||
break; |
||||
case 'f': |
||||
ops |= OP_FAST; |
||||
break; |
||||
case 'p': |
||||
global.port = atoi( optarg ); |
||||
mod = 1; |
||||
break; |
||||
case 'r': |
||||
global.box = optarg; |
||||
mod = 1; |
||||
break; |
||||
case 'F': |
||||
folder = optarg; |
||||
mod = 1; |
||||
break; |
||||
case 'M': |
||||
maildir = optarg; |
||||
mod = 1; |
||||
break; |
||||
case 'I': |
||||
inbox = optarg; |
||||
mod = 1; |
||||
break; |
||||
case 's': |
||||
#if HAVE_LIBSSL |
||||
if (!strncasecmp( "imaps:", optarg, 6 )) { |
||||
global.use_imaps = 1; |
||||
global.port = 993; |
||||
global.use_sslv2 = 1; |
||||
global.use_sslv3 = 1; |
||||
optarg += 6; |
||||
} |
||||
#endif |
||||
global.host = optarg; |
||||
mod = 1; |
||||
break; |
||||
case 'u': |
||||
global.user = optarg; |
||||
mod = 1; |
||||
break; |
||||
case 'D': |
||||
Debug = 1; |
||||
break; |
||||
case 'V': |
||||
Verbose = 1; |
||||
break; |
||||
case 'q': |
||||
Quiet++; |
||||
break; |
||||
case 'v': |
||||
version(); |
||||
case 'h': |
||||
usage( 0 ); |
||||
default: |
||||
usage( 1 ); |
||||
} |
||||
} |
||||
|
||||
if (config) { |
||||
if (*config != '/') { |
||||
if (!getcwd( path1, sizeof(path1) )) { |
||||
fprintf( stderr, "Can't obtain working directory\n" ); |
||||
return 1; |
||||
} |
||||
pl = strlen( path1 ); |
||||
nfsnprintf( path1 + pl, sizeof(path1) - pl, "/%s", config ); |
||||
config = path1; |
||||
} |
||||
} else { |
||||
nfsnprintf( path1, sizeof(path1), "%s/.isyncrc", Home ); |
||||
config = path1; |
||||
} |
||||
stor = &boxes; |
||||
load_config( config, &stor ); |
||||
|
||||
if (!all && !o2o) |
||||
for (i = optind; argv[i]; i++) |
||||
if (!(box = find_box( argv[i] ))) { |
||||
box = nfmalloc( sizeof(config_t) ); |
||||
memcpy( box, &global, sizeof(config_t) ); |
||||
box->path = argv[i]; |
||||
*stor = box; |
||||
stor = &box->next; |
||||
mod = 1; |
||||
} |
||||
|
||||
if (writeout) { |
||||
all = 1; |
||||
if (mod) |
||||
fprintf( stderr, |
||||
"Warning: command line switches that influence the resulting config file\n" |
||||
"have been supplied.\n" ); |
||||
} else { |
||||
if (!argv[optind] && !all) { |
||||
fprintf( stderr, "No mailbox specified. Try isync -h\n" ); |
||||
return 1; |
||||
} |
||||
} |
||||
|
||||
if (all) { |
||||
if (o2o) { |
||||
DIR * dir; |
||||
struct dirent *de; |
||||
|
||||
if (!(dir = opendir( xmaildir ))) { |
||||
fprintf( stderr, "%s: %s\n", xmaildir, strerror(errno) ); |
||||
return 1; |
||||
} |
||||
while ((de = readdir( dir ))) { |
||||
if (*de->d_name == '.') |
||||
continue; |
||||
nfsnprintf( path1, sizeof(path1), "%s/%s/cur", xmaildir, de->d_name ); |
||||
if (stat( path1, &st ) || !S_ISDIR( st.st_mode )) |
||||
continue; |
||||
global.path = de->d_name; |
||||
global.box = (inbox && !strcmp( inbox, global.path )) ? |
||||
"INBOX" : global.path; |
||||
convert( &global ); |
||||
} |
||||
closedir( dir ); |
||||
} else |
||||
for (box = boxes; box; box = box->next) |
||||
convert( box ); |
||||
} else { |
||||
for (i = optind; argv[i]; i++) |
||||
if (o2o) { |
||||
global.path = argv[i]; |
||||
global.box = |
||||
(inbox && !strcmp( global.path, inbox )) ? |
||||
"INBOX" : global.path; |
||||
convert( &global ); |
||||
} else |
||||
convert( find_box( argv[i] ) ); |
||||
} |
||||
|
||||
if (writeout) { |
||||
if (!outconfig) { |
||||
const char *p = strrchr( config, '/' ); |
||||
if (!p) |
||||
p = config; |
||||
p = strrstr( p, "isync" ); |
||||
if (!p) |
||||
nfsnprintf( path2, sizeof(path2), "%s.mbsync", config ); |
||||
else |
||||
nfsnprintf( path2, sizeof(path2), "%.*smb%s", p - config, config, p + 1 ); |
||||
outconfig = path2; |
||||
} |
||||
if ((fd = creat( outconfig, 0666 )) < 0) { |
||||
fprintf( stderr, "Error: cannot write new config %s: %s\n", outconfig, strerror(errno) ); |
||||
return 1; |
||||
} |
||||
} else { |
||||
strcpy( path2, "/tmp/mbsyncrcXXXXXX" ); |
||||
if ((fd = mkstemp( path2 )) < 0) { |
||||
fprintf( stderr, "Can't create temp file\n" ); |
||||
return 1; |
||||
} |
||||
} |
||||
write_config( fd ); |
||||
|
||||
if (writeout) |
||||
return 0; |
||||
args = 0; |
||||
add_arg( &args, "mbsync" ); |
||||
if (Verbose) |
||||
add_arg( &args, "-V" ); |
||||
if (Debug) |
||||
add_arg( &args, "-D" ); |
||||
for (; Quiet; Quiet--) |
||||
add_arg( &args, "-q" ); |
||||
add_arg( &args, "-cT" ); |
||||
add_arg( &args, path2 ); |
||||
if (ops & OP_FAST) |
||||
add_arg( &args, "-Ln" ); |
||||
else if (!(ops & OP_DELETE)) |
||||
add_arg( &args, "-nNf" ); |
||||
if (ops & OP_CREATE_REMOTE) |
||||
add_arg( &args, "-Cm" ); |
||||
if (ops & OP_CREATE_LOCAL) |
||||
add_arg( &args, "-Cs" ); |
||||
if (ops & OP_EXPUNGE) |
||||
add_arg( &args, "-X" ); |
||||
if (list) |
||||
add_arg( &args, "-l" ); |
||||
if (o2o) { |
||||
if (all) |
||||
add_arg( &args, "o2o" ); |
||||
else { |
||||
char buf[1024]; |
||||
strcpy( buf, "o2o:" ); |
||||
strcat( buf, argv[optind] ); |
||||
while (argv[++optind]) { |
||||
strcat( buf, "," ); |
||||
strcat( buf, argv[optind] ); |
||||
} |
||||
add_arg( &args, buf ); |
||||
} |
||||
} else { |
||||
if (all) |
||||
add_arg( &args, "-a" ); |
||||
else |
||||
for (; argv[optind]; optind++) |
||||
add_arg( &args, find_box( argv[optind] )->channel_name ); |
||||
} |
||||
execvp( args[0], args ); |
||||
perror( args[0] ); |
||||
return 1; |
||||
} |
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* isync - mbsync wrapper: IMAP4 to maildir mailbox synchronizer |
||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org> |
||||
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#include "isync.h" |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#include <pwd.h> |
||||
#include <ctype.h> |
||||
|
||||
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 = 0; |
||||
else if ((*strp = malloc( len + 1 ))) { |
||||
if (len >= sizeof(tmp)) |
||||
vsprintf( *strp, fmt, ap ); |
||||
else |
||||
memcpy( *strp, tmp, len + 1 ); |
||||
} |
||||
return len; |
||||
} |
||||
#endif |
||||
|
||||
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 (!*str) |
||||
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; |
||||
} |
@ -1,89 +0,0 @@
|
||||
/* $Id$
|
||||
* |
||||
* isync - IMAP4 to maildir mailbox synchronizer |
||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org> |
||||
* |
||||
* 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 |
||||
* |
||||
* As a special exception, isync may be linked with the OpenSSL library, |
||||
* despite that library's more restrictive license. |
||||
*/ |
||||
|
||||
#include <config.h> |
||||
|
||||
#if HAVE_LIBSSL |
||||
|
||||
#include "isync.h" |
||||
|
||||
#include <assert.h> |
||||
#include <string.h> |
||||
#include <openssl/hmac.h> |
||||
|
||||
#define ENCODED_SIZE(n) (4*((n+2)/3)) |
||||
|
||||
static char |
||||
hexchar (unsigned int b) |
||||
{ |
||||
if (b < 10) |
||||
return '0' + b; |
||||
return 'a' + (b - 10); |
||||
} |
||||
|
||||
char * |
||||
cram (const char *challenge, const char *user, const char *pass) |
||||
{ |
||||
HMAC_CTX hmac; |
||||
char hash[16]; |
||||
char hex[33]; |
||||
int i; |
||||
unsigned int hashlen = sizeof (hash); |
||||
char buf[256]; |
||||
int len = strlen (challenge); |
||||
char *response = calloc (1, 1 + len); |
||||
char *final; |
||||
|
||||
/* response will always be smaller than challenge because we are
|
||||
* decoding. |
||||
*/ |
||||
len = EVP_DecodeBlock ((unsigned char *) response, (unsigned char *) challenge, strlen (challenge)); |
||||
|
||||
HMAC_Init (&hmac, (unsigned char *) pass, strlen (pass), EVP_md5 ()); |
||||
HMAC_Update (&hmac, (unsigned char *) response, strlen(response)); |
||||
HMAC_Final (&hmac, (unsigned char *) hash, &hashlen); |
||||
|
||||
assert (hashlen == sizeof (hash)); |
||||
|
||||
free (response); |
||||
|
||||
hex[32] = 0; |
||||
for (i = 0; i < 16; i++) |
||||
{ |
||||
hex[2 * i] = hexchar ((hash[i] >> 4) & 0xf); |
||||
hex[2 * i + 1] = hexchar (hash[i] & 0xf); |
||||
} |
||||
|
||||
snprintf (buf, sizeof (buf), "%s %s", user, hex); |
||||
|
||||
len = strlen (buf); |
||||
len = ENCODED_SIZE (len) + 1; |
||||
final = malloc (len); |
||||
final[len - 1] = 0; |
||||
|
||||
assert (EVP_EncodeBlock ((unsigned char *) final, (unsigned char *) buf, strlen (buf)) == len - 1); |
||||
|
||||
return final; |
||||
} |
||||
|
||||
#endif |
@ -1,102 +0,0 @@
|
||||
/* $Id$
|
||||
* |
||||
* isync - IMAP4 to maildir mailbox synchronizer |
||||
* Copyright (C) 2002 Michael R. Elkins <me@mutt.org> |
||||
* |
||||
* 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 |
||||
* |
||||
* As a special exception, isync may be linked with the OpenSSL library, |
||||
* despite that library's more restrictive license. |
||||
*/ |
||||
|
||||
/*
|
||||
* this file contains routines to establish a mutex using a `dotlock' file |
||||
*/ |
||||
|
||||
#include "dotlock.h" |
||||
|
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#include <fcntl.h> |
||||
#include <sys/stat.h> |
||||
#if TESTING |
||||
#include <stdio.h> |
||||
#endif |
||||
|
||||
int dotlock_lock (const char *path, int *fd) |
||||
{ |
||||
struct flock lck; |
||||
|
||||
*fd = open (path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR); |
||||
if (*fd == -1) |
||||
return -1; |
||||
memset (&lck, 0, sizeof(lck)); |
||||
#if SEEK_SET != 0 |
||||
lck.l_whence = SEEK_SET; |
||||
#endif |
||||
#if F_WRLCK != 0 |
||||
lck.l_type = F_WRLCK; |
||||
#endif |
||||
if (fcntl (*fd, F_SETLK, &lck)) |
||||
{ |
||||
close (*fd); |
||||
*fd = -1; |
||||
return -1; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
int dotlock_unlock (int *fd) |
||||
{ |
||||
int r = 0; |
||||
struct flock lck; |
||||
|
||||
if (*fd != -1) |
||||
{ |
||||
memset (&lck, 0, sizeof(lck)); |
||||
#if SEEK_SET != 0 |
||||
lck.l_whence = SEEK_SET; |
||||
#endif |
||||
#if F_UNLCK != 0 |
||||
lck.l_type = F_UNLCK; |
||||
#endif |
||||
if (fcntl (*fd, F_SETLK, &lck)) |
||||
r = -1; |
||||
close (*fd); |
||||
*fd = -1; |
||||
} |
||||
return r; |
||||
} |
||||
|
||||
#if TESTING |
||||
int main (void) |
||||
{ |
||||
int fd; |
||||
|
||||
if (dotlock_lock ("./lock", &fd)) |
||||
{ |
||||
perror ("dotlock_lock"); |
||||
goto done; |
||||
} |
||||
puts ("sleeping for 5 seconds"); |
||||
sleep(5); |
||||
if (dotlock_unlock (&fd)) |
||||
{ |
||||
perror ("dotlock_unlock"); |
||||
} |
||||
done: |
||||
exit (0); |
||||
} |
||||
#endif |
@ -1,25 +0,0 @@
|
||||
/* $Id$
|
||||
* |
||||
* isync - IMAP4 to maildir mailbox synchronizer |
||||
* Copyright (C) 2002 Michael R. Elkins <me@mutt.org> |
||||
* |
||||
* 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 |
||||
* |
||||
* As a special exception, isync may be linked with the OpenSSL library, |
||||
* despite that library's more restrictive license. |
||||
*/ |
||||
|
||||
int dotlock_lock (const char *, int *); |
||||
int dotlock_unlock (int *); |
@ -1,179 +0,0 @@
|
||||
/* $Id$
|
||||
* |
||||
* isync - IMAP4 to maildir mailbox synchronizer |
||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org> |
||||
* |
||||
* 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 |
||||
* |
||||
* As a special exception, isync may be linked with the OpenSSL library, |
||||
* despite that library's more restrictive license. |
||||
*/ |
||||
|
||||
#include "isync.h" |
||||
|
||||
#include <ctype.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
|
||||
static char * |
||||
skip_string (char *s) |
||||
{ |
||||
while (*s && *s != '"') |
||||
s++; |
||||
return s; |
||||
} |
||||
|
||||
list_t * |
||||
parse_list (char *s, char **end) |
||||
{ |
||||
int level = 1; |
||||
list_t *cur; |
||||
list_t **list; |
||||
char *b; |
||||
|
||||
cur = calloc (1, sizeof (list_t)); |
||||
while (isspace ((unsigned char) *s)) |
||||
s++; |
||||
if (*s == '(') |
||||
{ |
||||
/* start of list. find the end of the list */ |
||||
s++; |
||||
b = s; /* save beginning */ |
||||
cur->val = LIST; |
||||
while (*s) |
||||
{ |
||||
if (*s == '(') |
||||
{ |
||||
level++; |
||||
} |
||||
else if (*s == ')') |
||||
{ |
||||
level--; |
||||
if (level == 0) |
||||
break; |
||||
} |
||||
else if (*s == '"') |
||||
{ |
||||
s = skip_string (s + 1); |
||||
if (!*s) |
||||
{ |
||||
/* parse error */ |
||||
free (cur); |
||||
return NULL; |
||||
} |
||||
} |
||||
s++; |
||||
} |
||||
if (level != 0) |
||||
{ |
||||
free (cur); /* parse error */ |
||||
return NULL; |
||||
} |
||||
*s++ = 0; |
||||
|
||||
list = &cur->child; |
||||
while (*b) |
||||
{ |
||||
*list = parse_list (b, &b); |
||||
if (*list == NULL) |
||||
{ |
||||
/* parse error */ |
||||
free (cur); |
||||
return NULL; |
||||
} |
||||
while (*list) |
||||
list = &(*list)->next; |
||||
} |
||||
} |
||||
else if (*s == '"') |
||||
{ |
||||
/* quoted string */ |
||||
s++; |
||||
cur->val = s; |
||||
s = skip_string (s); |
||||
if (!*s) |
||||
{ |
||||
/* parse error */ |
||||
free (cur); |
||||
return NULL; |
||||
} |
||||
*s++ = 0; |
||||
cur->val = strdup (cur->val); |
||||
} |
||||
else |
||||
{ |
||||
/* atom */ |
||||
cur->val = s; |
||||
while (*s && !isspace ((unsigned char) *s)) |
||||
s++; |
||||
if (*s) |
||||
*s++ = 0; |
||||
if (strcmp ("NIL", cur->val)) |
||||
cur->val = strdup (cur->val); |
||||
else |
||||
cur->val = NIL; |
||||
} |
||||
if (end) |
||||
*end = s; |
||||
return cur; |
||||
} |
||||
|
||||
int |
||||
is_atom (list_t * list) |
||||
{ |
||||
return (list && list->val && list->val != NIL && list->val != LIST); |
||||
} |
||||
|
||||
int |
||||
is_list (list_t * list) |
||||
{ |
||||
return (list && list->val == LIST); |
||||
} |
||||
|
||||
int |
||||
is_nil (list_t * list) |
||||
{ |
||||
return (list && list->val == NIL); |
||||
} |
||||
|
||||
void |
||||
free_list (list_t * list) |
||||
{ |
||||
list_t *tmp; |
||||
|
||||
while (list) |
||||
{ |
||||
tmp = list; |
||||
list = list->next; |
||||
if (is_list (tmp)) |
||||
free_list (tmp->child); |
||||
else if (is_atom (tmp)) |
||||
free (tmp->val); |
||||
free (tmp); |
||||
} |
||||
} |
||||
|
||||
#if TEST |
||||
int |
||||
main (int argc, char **argv) |
||||
{ |
||||
char buf[256]; |
||||
list_t *list; |
||||
|
||||
strcpy (buf, |
||||
"((compound list) atom NIL \"string with a (\" (another list))"); |
||||
list = parse_list (buf, 0); |
||||
} |
||||
#endif |
@ -1,459 +0,0 @@
|
||||
/* $Id$
|
||||
* |
||||
* isync - IMAP4 to maildir mailbox synchronizer |
||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org> |
||||
* Copyright (C) 2002-2003 Oswald Buddenhagen <ossi@users.sf.net> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
* |
||||
* As a special exception, isync may be linked with the OpenSSL library, |
||||
* despite that library's more restrictive license. |
||||
*/ |
||||
|
||||
#include "isync.h" |
||||
#include "dotlock.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 <errno.h> |
||||
#include <time.h> |
||||
|
||||
/* 2,<flags> */ |
||||
static void |
||||
parse_info (message_t * m, char *s) |
||||
{ |
||||
if (*s == '2' && *(s + 1) == ',') |
||||
{ |
||||
s += 2; |
||||
while (*s) |
||||
{ |
||||
if (*s == 'F') |
||||
m->flags |= D_FLAGGED; |
||||
else if (*s == 'R') |
||||
m->flags |= D_ANSWERED; |
||||
else if (*s == 'T') |
||||
m->flags |= D_DELETED; |
||||
else if (*s == 'S') |
||||
m->flags |= D_SEEN; |
||||
s++; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* There are three possible results of this function: |
||||
* >1 uid was already seen |
||||
* 0 uid was not yet seen |
||||
* -1 unable to read uid because of some other error |
||||
*/ |
||||
|
||||
static int |
||||
read_uid (const char *path, const char *file, unsigned int *uid /* out */) |
||||
{ |
||||
char full[_POSIX_PATH_MAX]; |
||||
int fd; |
||||
int ret = -1; |
||||
int len; |
||||
char buf[64], *ptr; |
||||
|
||||
snprintf (full, sizeof (full), "%s/%s", path, file); |
||||
fd = open (full, O_RDONLY); |
||||
if (fd == -1) |
||||
{ |
||||
if (errno != ENOENT) |
||||
{ |
||||
perror (full); |
||||
return -1; |
||||
} |
||||
return 0; /* doesn't exist */ |
||||
} |
||||
len = read (fd, buf, sizeof (buf) - 1); |
||||
if (len == -1) |
||||
perror ("read"); |
||||
else |
||||
{ |
||||
buf[len] = 0; |
||||
errno = 0; |
||||
*uid = strtoul (buf, &ptr, 10); |
||||
if (errno) |
||||
perror ("strtoul"); |
||||
else if (ptr && *ptr == '\n') |
||||
ret = 1; |
||||
/* else invalid value */ |
||||
} |
||||
close (fd); |
||||
return ret; |
||||
} |
||||
|
||||
/*
|
||||
* open a maildir mailbox. |
||||
* if OPEN_FAST is set, we just check to make |
||||
* sure its a valid mailbox and don't actually parse it. any IMAP messages |
||||
* with the \Recent flag set are guaranteed not to be in the mailbox yet, |
||||
* so we can save a lot of time when the user just wants to fetch new messages |
||||
* without syncing the flags. |
||||
* if OPEN_CREATE is set, we create the mailbox if it doesn't already exist. |
||||
*/ |
||||
mailbox_t * |
||||
maildir_open (const char *path, int flags) |
||||
{ |
||||
char buf[_POSIX_PATH_MAX]; |
||||
DIR *d; |
||||
struct dirent *e; |
||||
message_t **cur; |
||||
message_t *p; |
||||
mailbox_t *m; |
||||
char *s; |
||||
int count = 0; |
||||
struct stat sb; |
||||
const char *subdirs[] = { "cur", "new", "tmp" }; |
||||
int i, ret; |
||||
DBT key, value; |
||||
|
||||
m = calloc (1, sizeof (mailbox_t)); |
||||
m->lockfd = -1; |
||||
/* filename expansion happens here, not in the config parser */ |
||||
m->path = expand_strdup (path); |
||||
|
||||
if (stat (m->path, &sb)) |
||||
{ |
||||
if (errno == ENOENT && (flags & OPEN_CREATE)) |
||||
{ |
||||
if (mkdir (m->path, S_IRUSR | S_IWUSR | S_IXUSR)) |
||||
{ |
||||
fprintf (stderr, "ERROR: mkdir %s: %s (errno %d)\n", |
||||
m->path, strerror (errno), errno); |
||||
goto err; |
||||
} |
||||
|
||||
for (i = 0; i < 3; i++) |
||||
{ |
||||
snprintf (buf, sizeof (buf), "%s/%s", m->path, subdirs[i]); |
||||
if (mkdir (buf, S_IRUSR | S_IWUSR | S_IXUSR)) |
||||
{ |
||||
fprintf (stderr, "ERROR: mkdir %s: %s (errno %d)\n", |
||||
buf, strerror (errno), errno); |
||||
goto err; |
||||
} |
||||
} |
||||
|
||||
} |
||||
else |
||||
{ |
||||
fprintf (stderr, "ERROR: stat %s: %s (errno %d)\n", m->path, |
||||
strerror (errno), errno); |
||||
goto err; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
/* check to make sure this looks like a valid maildir box */ |
||||
for (i = 0; i < 3; i++) |
||||
{ |
||||
snprintf (buf, sizeof (buf), "%s/%s", m->path, subdirs[i]); |
||||
if (stat (buf, &sb)) |
||||
{ |
||||
fprintf (stderr, "ERROR: stat %s: %s (errno %d)\n", buf, |
||||
strerror (errno), errno); |
||||
fprintf (stderr, |
||||
"ERROR: %s does not appear to be a valid maildir style mailbox\n", |
||||
m->path); |
||||
goto err; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/*
|
||||
* we need a mutex on the maildir because of the state files that isync |
||||
* uses. |
||||
*/ |
||||
snprintf (buf, sizeof (buf), "%s/isynclock", m->path); |
||||
if (dotlock_lock (buf, &m->lockfd)) |
||||
goto err; |
||||
|
||||
/* check for the uidvalidity value */ |
||||
i = read_uid (m->path, "isyncuidvalidity", &m->uidvalidity); |
||||
if (i == -1) |
||||
goto err; |
||||
else if (i > 0) |
||||
m->uidseen = 1; |
||||
|
||||
/* load the current maxuid */ |
||||
if (read_uid (m->path, "isyncmaxuid", &m->maxuid) == -1) |
||||
goto err; |
||||
|
||||
snprintf (buf, sizeof (buf), "%s/isyncuidmap.db", m->path); |
||||
if (db_create (&m->db, 0, 0)) { |
||||
fputs ("dbcreate failed\n", stderr); |
||||
goto err; |
||||
} |
||||
if ((ret = m->db->set_pagesize (m->db, 4096)) != 0 || |
||||
(ret = m->db->set_h_ffactor (m->db, 40)) != 0 || |
||||
(ret = m->db->set_h_nelem (m->db, 1)) != 0) { |
||||
fputs ("Error configuring database\n", stderr); |
||||
goto err; |
||||
} |
||||
m->db->open (m->db, buf, 0, DB_HASH, DB_CREATE, S_IRUSR | S_IWUSR); |
||||
if (m->db == NULL) |
||||
{ |
||||
fputs ("ERROR: unable to open UID db\n", stderr); |
||||
goto err; |
||||
} |
||||
|
||||
if (flags & OPEN_FAST) |
||||
return m; |
||||
|
||||
cur = &m->msgs; |
||||
for (; count < 2; count++) |
||||
{ |
||||
/* read the msgs from the new subdir */ |
||||
snprintf (buf, sizeof (buf), "%s/%s", m->path, |
||||
(count == 0) ? "new" : "cur"); |
||||
d = opendir (buf); |
||||
if (!d) |
||||
{ |
||||
perror ("opendir"); |
||||
goto err; |
||||
} |
||||
while ((e = readdir (d))) |
||||
{ |
||||
if (*e->d_name == '.') |
||||
continue; /* skip dot-files */ |
||||
*cur = calloc (1, sizeof (message_t)); |
||||
p = *cur; |
||||
p->file = strdup (e->d_name); |
||||
p->uid = -1; |
||||
p->flags = 0; |
||||
p->new = (count == 0); |
||||
|
||||
/* determine the UID for this message. The basename (sans
|
||||
* flags) is used as the key in the db |
||||
*/ |
||||
memset (&key, 0, sizeof(key)); |
||||
memset (&value, 0, sizeof(value)); |
||||
key.data = p->file; |
||||
s = strchr (p->file, ':'); |
||||
key.size = s ? (size_t) (s - p->file) : strlen (p->file); |
||||
ret = m->db->get (m->db, 0, &key, &value, 0); |
||||
if (ret == DB_NOTFOUND) { |
||||
/* Every locally generated message triggers this ... */ |
||||
/*warn ("Warning: no UID for message %.*s\n",
|
||||
key.size, p->file);*/ |
||||
} else if (ret) { |
||||
fprintf (stderr, "Unexpected error (%d) from db_get(%.*s)\n",
|
||||
ret, key.size, p->file); |
||||
} else if (ret == 0) { |
||||
p->uid = *((int *) value.data); |
||||
if (p->uid > m->maxuid) |
||||
m->maxuid = p->uid; |
||||
} |
||||
if (s) |
||||
parse_info (p, s + 1); |
||||
if (p->flags & D_DELETED) |
||||
m->deleted++; |
||||
cur = &p->next; |
||||
} |
||||
closedir (d); |
||||
} |
||||
return m; |
||||
|
||||
err: |
||||
if (m->db) |
||||
m->db->close (m->db, 0); |
||||
dotlock_unlock (&m->lockfd); |
||||
free (m->path); |
||||
free (m); |
||||
return NULL; |
||||
} |
||||
|
||||
/* permanently remove messages from a maildir mailbox. if `dead' is nonzero,
|
||||
* we only remove the messags marked dead. |
||||
*/ |
||||
int |
||||
maildir_expunge (mailbox_t * mbox, int dead) |
||||
{ |
||||
message_t **cur = &mbox->msgs; |
||||
message_t *tmp; |
||||
char *s; |
||||
DBT key; |
||||
char path[_POSIX_PATH_MAX]; |
||||
|
||||
while (*cur) |
||||
{ |
||||
if ((dead == 0 && (*cur)->flags & D_DELETED) || |
||||
(dead && (*cur)->dead)) |
||||
{ |
||||
tmp = *cur; |
||||
snprintf (path, sizeof (path), "%s/%s/%s", |
||||
mbox->path, tmp->new ? "new" : "cur", tmp->file); |
||||
if (unlink (path)) |
||||
perror (path); |
||||
/* remove the message from the UID map */ |
||||
memset (&key, 0, sizeof(key)); |
||||
key.data = tmp->file; |
||||
s = strchr (tmp->file, ':'); |
||||
key.size = s ? (size_t) (s - tmp->file) : strlen (key.data); |
||||
mbox->db->del (mbox->db, 0, &key, 0); |
||||
mbox->db->sync (mbox->db, 0); |
||||
*cur = (*cur)->next; |
||||
free (tmp->file); |
||||
free (tmp); |
||||
} |
||||
else |
||||
cur = &(*cur)->next; |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
maildir_update_maxuid (mailbox_t * mbox) |
||||
{ |
||||
int fd; |
||||
char buf[64]; |
||||
size_t len; |
||||
char path[_POSIX_PATH_MAX]; |
||||
int ret = 0; |
||||
|
||||
snprintf (path, sizeof (path), "%s/isyncmaxuid", mbox->path); |
||||
fd = open (path, O_WRONLY | O_CREAT, 0600); |
||||
if (fd == -1) |
||||
{ |
||||
perror ("open"); |
||||
return -1; |
||||
} |
||||
|
||||
/* write out the file */ |
||||
snprintf (buf, sizeof (buf), "%u\n", mbox->maxuid); |
||||
len = write (fd, buf, strlen (buf)); |
||||
if (len == (size_t) - 1) |
||||
{ |
||||
perror ("write"); |
||||
ret = -1; |
||||
} |
||||
|
||||
if (close (fd)) |
||||
ret = -1; |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
#define _24_HOURS (3600 * 24) |
||||
|
||||
static void |
||||
maildir_clean_tmp (const char *mbox) |
||||
{ |
||||
char path[_POSIX_PATH_MAX]; |
||||
DIR *dirp; |
||||
struct dirent *entry; |
||||
struct stat st; |
||||
time_t now; |
||||
|
||||
snprintf (path, sizeof (path), "%s/tmp", mbox); |
||||
dirp = opendir (path); |
||||
if (dirp == NULL) |
||||
{ |
||||
fprintf (stderr, "maildir_clean_tmp: opendir: %s: %s (errno %d)\n", |
||||
path, strerror (errno), errno); |
||||
return; |
||||
} |
||||
/* assuming this scan will take less than a second, we only need to
|
||||
* check the time once before the following loop. |
||||
*/ |
||||
time (&now); |
||||
while ((entry = readdir (dirp))) |
||||
{ |
||||
snprintf (path, sizeof (path), "%s/tmp/%s", mbox, entry->d_name); |
||||
if (stat (path, &st)) |
||||
fprintf (stderr, "maildir_clean_tmp: stat: %s: %s (errno %d)\n", |
||||
path, strerror (errno), errno); |
||||
else if (S_ISREG (st.st_mode) && now - st.st_ctime >= _24_HOURS) |
||||
{ |
||||
/* this should happen infrequently enough that it won't be
|
||||
* bothersome to the user to display when it occurs. |
||||
*/ |
||||
info ("Notice: removing stale file %s\n", path); |
||||
if (unlink (path)) |
||||
fprintf (stderr, |
||||
"maildir_clean_tmp: unlink: %s: %s (errno %d)\n", |
||||
path, strerror (errno), errno); |
||||
} |
||||
} |
||||
closedir(dirp); |
||||
} |
||||
|
||||
void |
||||
maildir_close (mailbox_t * mbox) |
||||
{ |
||||
if (mbox->db) |
||||
mbox->db->close (mbox->db, 0); |
||||
|
||||
/* release the mutex on the mailbox */ |
||||
dotlock_unlock (&mbox->lockfd); |
||||
|
||||
/* per the maildir(5) specification, delivery agents are supposed to
|
||||
* set a 24-hour timer on items placed in the `tmp' directory. |
||||
*/ |
||||
maildir_clean_tmp (mbox->path); |
||||
|
||||
free (mbox->path); |
||||
free_message (mbox->msgs); |
||||
memset (mbox, 0xff, sizeof (mailbox_t)); |
||||
free (mbox); |
||||
} |
||||
|
||||
int |
||||
maildir_set_uidvalidity (mailbox_t * mbox, unsigned int uidvalidity) |
||||
{ |
||||
char path[_POSIX_PATH_MAX]; |
||||
char buf[16]; |
||||
int fd; |
||||
int ret; |
||||
|
||||
snprintf (path, sizeof (path), "%s/isyncuidvalidity", mbox->path); |
||||
fd = open (path, O_WRONLY | O_CREAT | O_EXCL, 0600); |
||||
if (fd == -1) |
||||
{ |
||||
perror ("open"); |
||||
return -1; |
||||
} |
||||
snprintf (buf, sizeof (buf), "%u\n", uidvalidity); |
||||
|
||||
ret = write (fd, buf, strlen (buf)); |
||||
|
||||
if (ret == -1) |
||||
perror ("write"); |
||||
else if ((size_t) ret != strlen (buf)) |
||||
ret = -1; |
||||
else |
||||
ret = 0; |
||||
|
||||
if (close (fd)) |
||||
{ |
||||
perror ("close"); |
||||
ret = -1; |
||||
} |
||||
|
||||
if (ret) |
||||
if (unlink (path)) |
||||
perror ("unlink"); |
||||
|
||||
return (ret); |
||||
} |
@ -0,0 +1,471 @@
|
||||
.ig |
||||
\" mbsync - mailbox synchronizer |
||||
\" Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org> |
||||
\" Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net> |
||||
\" Copyright (C) 2004 Theodore Y. Ts'o <tytso@mit.edu> |
||||
\" |
||||
\" 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 |
||||
\" |
||||
\" As a special exception, mbsync may be linked with the OpenSSL library, |
||||
\" despite that library's more restrictive license. |
||||
.. |
||||
.TH mbsync 1 "2004 Mar 27" |
||||
.. |
||||
.SH NAME |
||||
mbsync - synchronize IMAP4 and Maildir mailboxes |
||||
.. |
||||
.SH SYNOPSIS |
||||
\fBmbsync\fR [\fIoptions\fR ...] {{\fIchannel\fR[\fB:\fIbox\fR[{\fB,\fR|\fB\\n\fR}...]]|\fIgroup\fR} ...|\fB-a\fR} |
||||
.. |
||||
.SH DESCRIPTION |
||||
\fBmbsync\fR is a command line application which synchronizes mailboxes; |
||||
currently Maildir and IMAP4 mailboxes are supported. |
||||
New messages, message deletions and flag changes can be propagated both ways; |
||||
the operation set can be selected in a fine-grained manner. |
||||
.br |
||||
Synchronization is based on unique message identifiers (UIDs), so no |
||||
identification conflicts can occur (as opposed to some other mail synchronizers). |
||||
OTOH, \fBmbsync\fR is susceptible to UID validity changes (that \fIshould\fR |
||||
never happen, but see "Compatibility" in the README). |
||||
Synchronization state is kept in one local text file per mailbox pair; |
||||
multiple replicas of a mailbox can be maintained. |
||||
.. |
||||
.SH OPTIONS |
||||
.TP |
||||
\fB-c\fR, \fB--config\fR \fIfile\fR |
||||
Read configuration from \fIfile\fR. |
||||
By default, the configuration is read from ~/.mbsyncrc. |
||||
.TP |
||||
\fB-a\fR, \fB--all\fR |
||||
Select all configured channels. Any channel/group specifications on the command |
||||
line are ignored. |
||||
.TP |
||||
\fB-l\fR, \fB--list\fR |
||||
Don't synchronize anything, but list all mailboxes in the selected channels |
||||
and exit. |
||||
.TP |
||||
\fB-C\fR[\fBm\fR][\fBs\fR], \fB--create\fR[\fB-master\fR|\fB-slave\fR] |
||||
Override any \fBCreate\fR options from the config file. See below. |
||||
.TP |
||||
\fB-X\fR[\fBm\fR][\fBs\fR], \fB--expunge\fR[\fB-master\fR|\fB-slave\fR] |
||||
Override any \fBExpunge\fR options from the config file. See below. |
||||
.TP |
||||
{\fB-n\fR|\fB-N\fR|\fB-d\fR|\fB-f\fR|\fB-0\fR|\fB-F\fR},\ |
||||
{\fB--new\fR|\fB--renew\fR|\fB--delete\fR|\fB--flags\fR|\fB--noop\fR|\fB--full\fR} |
||||
.TP |
||||
\r{\fB-L\fR|\fB-H\fR}[\fBn\fR][\fBN\fR][\fBd\fR][\fBf\fR],\ |
||||
{\fB--pull\fR|\fB--push\fR}[\fB-new\fR|\fB-renew\fR|\fB-delete\fR|\fB-flags\fR] |
||||
Override any \fBSync\fR options from the config file. See below. |
||||
.TP |
||||
\fB-h\fR, \fB--help\fR |
||||
Display a summary of command line options. |
||||
.TP |
||||
\fB-v\fR, \fB--version\fR |
||||
Display version information. |
||||
.TP |
||||
\fB-V\fR, \fB--verbose\fR |
||||
Enable \fIverbose\fR mode, which displays the IMAP4 network traffic. |
||||
.TP |
||||
\fB-D\fR, \fB--debug\fR |
||||
Enable printing \fIdebug\fR information. |
||||
.TP |
||||
\fB-q\fR, \fB--quiet\fR |
||||
Suppress informational messages. |
||||
If specified twice, suppress warning messages as well. |
||||
.. |
||||
.SH CONFIGURATION |
||||
The configuration file is mandatory; \fBmbsync\fR will not run without it. |
||||
Lines starting with a hash mark (\fB#\fR) are comments and are ignored entirely. |
||||
Configuration items are keywords followed by one or more arguments; |
||||
arguments containing spaces must be enclosed in double quotes (\fB"\fR). |
||||
All keywords (including those used as arguments) are case-insensitive. |
||||
There are a few global options, the rest applies to particular sections. |
||||
Sections are started by a section keyword and are terminated by an empty line |
||||
or end of file. |
||||
Every section defines an object with a an identifier unique within that |
||||
object class. |
||||
.P |
||||
There are two basic object classes: Stores and Channels. A Store defines |
||||
a collection of mailboxes; basically a folder, either local or remote. |
||||
A Channel connects two Stores, describing the way the two are synchronized. |
||||
.br |
||||
There are two auxiliary object classes: Accounts and Groups. An Account |
||||
describes the connection part of remote Stores, so a server connection can be |
||||
shared between multiple Stores. A Group aggregates multiple Channels to |
||||
save typing on the command line. |
||||
.. |
||||
.SS All Stores |
||||
These options can be used in all supported Store types. |
||||
.br |
||||
In this context, the term "remote" describes the second Store within a Channel, |
||||
and not necessarily a remote server. |
||||
.br |
||||
The special mailbox \fBINBOX\fR exists in every Store; its physical location |
||||
in the file system is Store type specific. |
||||
.. |
||||
.TP |
||||
\fBPath\fR \fIpath\fR |
||||
The location of the Store in the (server's) file system. |
||||
If this is no absolute path, the reference point is Store type specific. |
||||
This string is prepended to the mailbox names addressed in this Store, |
||||
but is not considered part of them; this is important for \fBPatterns\fR |
||||
in the Channels section. |
||||
Note that you \fBmust\fR append a slash if you want to specify an entire |
||||
directory. |
||||
(Default: \fI""\fR) |
||||
.. |
||||
.TP |
||||
\fBMaxSize\fR \fIsize\fR[\fBk\fR|\fBm\fR][\fBb\fR] |
||||
Messages larger than that will not be propagated into this Store. |
||||
This is useful for weeding out messages with large attachments. |
||||
\fBK\fR and \fBM\fR can be appended to the size to specify KiBytes resp. |
||||
MeBytes instead of bytes. \fBB\fR is accepted but superflous. |
||||
If \fIsize\fR is 0, the maximum message size is \fBunlimited\fR. |
||||
(Default: \fI0\fR) |
||||
.. |
||||
.TP |
||||
\fBMapInbox\fR \fImailbox\fR |
||||
Create a virtual mailbox (relative to \fBPath\fR), which is backed by |
||||
the \fBINBOX\fR. Makes sense in conjunction with \fBPatterns\fR in the |
||||
Channels section. |
||||
.. |
||||
.TP |
||||
\fBTrash\fR \fImailbox\fR |
||||
Specifies a mailbox (relative to \fBPath\fR) to copy deleted messages to |
||||
prior to expunging. See \fBINHERENT PROBLEMS\fR below. |
||||
(Default: none) |
||||
.. |
||||
.TP |
||||
\fBTrashNewOnly\fR \fIyes\fR|\fIno\fR |
||||
When trashing, copy only not yet propagated messages. This makes sense if the |
||||
remote Store has a \fBTrash\fR as well (with \fBTrashNewOnly\fR \fIno\fR). |
||||
(Default: \fIno\fR) |
||||
.. |
||||
.TP |
||||
\fBTrashRemoteNew\fR \fIyes\fR|\fIno\fR |
||||
When expunging the remote Store, copy not yet propagated messages to this |
||||
Store's \fBTrash\fR. When using this, the remote Store does not need an own |
||||
\fBTrash\fR at all, yet all messages are archived. |
||||
(Default: \fIno\fR) |
||||
.. |
||||
.SS Maildir Stores |
||||
The reference point for relative \fBPath\fRs is $HOME. |
||||
.P |
||||
As \fBmbsync\fR needs UIDs, but no standardized UID storage scheme exists for |
||||
Maildir, \fBmbsync\fR supports two schemes, each with its pros and cons. |
||||
.br |
||||
The \fBnative\fR scheme is stolen from the latest Maildir patches to \fBc-client\fR |
||||
and is therefore compatible with \fBpine\fR. The UID validity is stored in a |
||||
file named .uidvalidity; the UIDs are encoded in the file names of the messages. |
||||
.br |
||||
The \fBalternative\fR scheme is based on the UID mapping used by \fBisync\fR |
||||
versions 0.8 and 0.9.x. The invariant parts of the file names of the messages |
||||
are used as keys into a Berkeley database named .isyncuidmap.db, which holds |
||||
the UID validity as well. |
||||
.br |
||||
The \fBnative\fR scheme is faster, more space efficient, endianess independent |
||||
and "human readable", but will be disrupted if a message is copied from another |
||||
mailbox without getting a new file name; this would result in duplicated UIDs |
||||
sooner or later, which in turn results in a UID validity change, making |
||||
synchronization fail. |
||||
The \fBalternative\fR scheme would fail if a MUA changed a message's file name |
||||
in a part \fBmbsync\fR considers invariant; this would be interpreted as a |
||||
message deletion and a new message, resulting in unnecessary traffic. |
||||
.br |
||||
\fBMutt\fR is known to work fine with both schemes. |
||||
.br |
||||
Use \fBmdconvert\fR to convert mailboxes from one scheme to the other. |
||||
.. |
||||
.TP |
||||
\fBMaildirStore\fR \fIname\fR |
||||
Define the Maildir Store \fIname\fR, opening a section for its parameters. |
||||
.. |
||||
.TP |
||||
\fBAltMap\fR \fIyes\fR|\fIno\fR |
||||
Use the \fBalternative\fR UID storage scheme for mailboxes in this Store. |
||||
This does not affect mailboxes that do already have a UID storage scheme; |
||||
use \fBmdconvert\fR to change it. |
||||
(Default: \fIno\fR) |
||||
.. |
||||
.TP |
||||
\fBInbox\fR \fIpath\fR |
||||
The location of the \fBINBOX\fR. This is \fInot\fR relative to \fBPath\fR. |
||||
(Default: \fI~/Maildir\fR) |
||||
.. |
||||
.SS IMAP4 Accounts |
||||
.TP |
||||
\fBIMAPAccount\fR \fIname\fR |
||||
Define the IMAP4 Account \fIname\fR, opening a section for its parameters. |
||||
.. |
||||
.TP |
||||
\fBHost\fR [\fBimaps:\fR]\fIhost\fR |
||||
Specify the DNS name or IP address of the IMAP server. If \fIhost\fR is |
||||
prefixed with \fBimaps:\fR the connection is assumed to be an SSL connection |
||||
to port 993. |
||||
Note that modern servers support SSL on the default port 143 via the |
||||
STARTTLS extension, which will be used automatically by default. |
||||
.. |
||||
.TP |
||||
\fBPort\fR \fIport\fR |
||||
Specify the TCP port number of the IMAP server. (Default: 143 for imap, |
||||
993 for imaps) |
||||
.. |
||||
.TP |
||||
\fBUser\fR \fIusername\fR |
||||
Specify the login name on the IMAP server. (Default: current local user) |
||||
.. |
||||
.TP |
||||
\fBPass\fR \fIpassword\fR |
||||
Specify 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, \fBmbsync\fR |
||||
will prompt you for it. |
||||
.. |
||||
.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. This makes most other IMAPAccount options superflous. |
||||
.. |
||||
.TP |
||||
\fBRequireCRAM\fR \fIyes\fR|\fIno\fR |
||||
If set to \fIyes\fR, \fBmbsync\fR will abort the connection if no CRAM-MD5 |
||||
authentication is possible. (Default: \fIno\fR) |
||||
.. |
||||
.TP |
||||
\fBRequireSSL\fR \fIyes\fR|\fIno\fR |
||||
\fBmbsync\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 X.509 CA certificates used to verify server identities. |
||||
This option is \fImandatory\fR if SSL is used. See \fBSSL CERTIFICATES\fR below. |
||||
.. |
||||
.TP |
||||
\fBUseSSLv2\fR \fIyes\fR|\fIno\fR |
||||
Use SSLv2 for communication with the IMAP server over SSL? |
||||
(Default: \fIyes\fR if an imaps \fBHost\fR is used, otherwise \fIno\fR) |
||||
.. |
||||
.TP |
||||
\fBUseSSLv3\fR \fIyes\fR|\fIno\fR |
||||
Use SSLv3 for communication with the IMAP server over SSL? |
||||
(Default: \fIyes\fR if an imaps \fBHost\fR is used, otherwise \fIno\fR) |
||||
.. |
||||
.TP |
||||
\fBUseTLSv1\fR \fIyes\fR|\fIno\fR |
||||
Use TLSv1 for communication with the IMAP server over SSL? |
||||
(Default: \fIyes\fR) |
||||
.. |
||||
.SS IMAP Stores |
||||
The reference point for relative \fBPath\fRs is whatever the server likes it |
||||
to be; probably the user's $HOME or $HOME/Mail on that server. The location |
||||
of \fBINBOX\fR is up to the server as well and is usually irrelevant. |
||||
.TP |
||||
\fBIMAPStore\fR \fIname\fR |
||||
Define the IMAP4 Store \fIname\fR, opening a section for its parameters. |
||||
.. |
||||
.TP |
||||
\fBAccount\fR \fIaccount\fR |
||||
Specify which IMAP4 Account to use. Instead of defining an Account and |
||||
referencing it here, it is also possible to specify all the Account options |
||||
directly in the Store's section - this makes sense if an Account is used for |
||||
one Store only anyway. |
||||
.. |
||||
.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 \fBPath\fR was specified. |
||||
(Default: \fIyes\fR) |
||||
.. |
||||
.SS Channels |
||||
.TP |
||||
\fBChannel\fR \fIname\fR |
||||
Define the Channel \fIname\fR, opening a section for its parameters. |
||||
.. |
||||
.TP |
||||
{\fBMaster\fR|\fBSlave\fR} \fB:\fIstore\fB:\fR[\fImailbox\fR] |
||||
Specify the Master resp. Slave Store to be connected by this Channel. |
||||
If \fImailbox\fR is omitted, \fBINBOX\fR is assumed. |
||||
The \fImailbox\fR specification can be overridden by \fBPatterns\fR, which |
||||
in turn can be overridden by a mailbox list in a Channel reference (a Group |
||||
specification or the command line). |
||||
.. |
||||
.TP |
||||
\fBPattern\fR[\fBs\fR] [\fB!\fR]\fIpattern\fR ... |
||||
Instead of synchronizing only one mailbox pair, synchronize all mailboxes |
||||
that match the \fIpattern\fR(s). The mailbox names are the same on both |
||||
Master and Slave. Patterns are IMAP4 patterns, i.e., \fB*\fR matches anything |
||||
and \fB%\fR matches anything up to the next hierarchy delimiter. Prepending |
||||
\fB!\fR to a pattern makes it an exclusion. Multiple patterns can be specified |
||||
(either by supplying multiple arguments or by using \fBPattern\fR multiple |
||||
times); later matches take precedence. |
||||
Example: "\fBPatterns\fR\ \fI%\ !Trash\fR" |
||||
.. |
||||
.TP |
||||
\fBMaxSize\fR \fIsize\fR[\fBk\fR|\fBm\fR][\fBb\fR] |
||||
Analogous to the homonymous option in the Stores section, but applies equally |
||||
to Master and Slave. Note that this actually modifies the Stores, so take care |
||||
not to provide conflicting settings if you use the Stores in multiple Channels. |
||||
.. |
||||
.TP |
||||
\fBMaxMessages\fR \fIcount\fR |
||||
Sets the maximum number of messages to keep in each Slave 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 recent messages will not |
||||
be automatically deleted. |
||||
If \fIcount\fR is 0, the maximum number of messages is \fBunlimited\fR |
||||
(Default: \fI0\fR). |
||||
.. |
||||
.TP |
||||
\fBSync\fR {\fINone\fR|[\fIPull\fR] [\fIPush\fR] [\fINew\fR] [\fIReNew\fR] [\fIDelete\fR] [\fIFlags\fR]|\fIFull\fR} |
||||
Select the synchronization operation(s) to perform: |
||||
.br |
||||
\fBPull\fR - propagate changes from Master to Slave. |
||||
.br |
||||
\fBPush\fR - propagate changes from Slave to Master. |
||||
.br |
||||
\fBNew\fR - propagate newly appeared messages. |
||||
.br |
||||
\fBReNew\fR - previously refused messages are re-evaluated for propagation. |
||||
Useful after flagging affected messages in the source Store or enlarging |
||||
MaxSize in the destination Store. |
||||
.br |
||||
\fBDelete\fR - propagate message deletions. This applies only to messages that |
||||
are actually gone, i.e., were expunged. The affected messages in the remote |
||||
Store are marked as deleted only, i.e., they won't be really deleted until |
||||
that Store is expunged. |
||||
.br |
||||
\fBFlags\fR - propagate flag changes. Note that Deleted/Trashed is a flag as |
||||
well; this is particularily interesting if you use \fBmutt\fR with the |
||||
maildir_trash option. |
||||
.br |
||||
\fBAll\fR (\fB--full\fR on the command line) - all of the above. |
||||
This is the global default. |
||||
.br |
||||
\fBNone\fR (\fB--noop\fR on the command line) - don't propagate anything. |
||||
Useful if you want to expunge only. |
||||
.IP |
||||
\fBPull\fR and \fBPush\fR are direction flags, while \fBNew\fR, \fBReNew\fR, |
||||
\fBDelete\fR and \fBFlags\fR are type flags. The two flag classes make up a |
||||
two-dimensional matrix (a table). Its cells are the individual actions to |
||||
perform. There are two styles of asserting the cells: |
||||
.br |
||||
In the first style, the flags select entire rows/colums in the matrix. Only |
||||
the cells which are selected both horizontally and vertically are asserted. |
||||
Specifying no flags from a class is like specifying all flags from this class. |
||||
For example, "\fBSync\fR\ \fBPull\fR\ \fBNew\fR\ \fBFlags\fR" will propagate |
||||
new messages and flag changes from the Master to the Slave, |
||||
"\fBSync\fR\ \fBNew\fR\ \fBDelete\fR" will propagate message arrivals and |
||||
deletions both ways, and "\fBSync\fR\ \fBPush\fR" will propagate all changes |
||||
from the Slave to the Master. |
||||
.br |
||||
In the second style, direction flags are concatenated with type flags; every |
||||
compound flag immediately asserts a cell in the matrix. In addition to at least |
||||
one compound flag, the individual flags can be used as well, but as opposed to |
||||
the first style, they immediately assert all cells in their respective |
||||
row/column. For example, |
||||
"\fBSync\fR\ \fBPullNew\fR\ \fBPullDelete\fR\ \fBPush\fR" will propagate |
||||
message arrivals and deletions from the Master to the Slave and any changes |
||||
from the Slave to the Master. |
||||
Note that it is not allowed to assert a cell in two ways, e.g. |
||||
"\fBSync\fR\ \fBPullNew\fR\ \fBPull\fR" and |
||||
"\fBSync\fR\ \fBPullNew\fR\ \fBDelete\fR\ \fBPush\fR" induce error messages. |
||||
.. |
||||
.TP |
||||
\fBCreate\fR {\fINone\fR|\fIMaster\fR|\fISlave\fR|\fIBoth\fR} |
||||
Automatically create missing mailboxes [on the Master/Slave]. |
||||
Otherwise print an error message and skip that mailbox pair if a mailbox |
||||
does not exist. |
||||
(Global default: \fINone\fR) |
||||
.. |
||||
.TP |
||||
\fBExpunge\fR {\fINone\fR|\fIMaster\fR|\fISlave\fR|\fIBoth\fR} |
||||
Permanently remove all messages [on the Master/Slave] marked for deletion. |
||||
(Global default: \fINone\fR) |
||||
.. |
||||
.P |
||||
\fBSync\fR, \fBCreate\fR and \fBExpunge\fR can be used outside any section for |
||||
a global effect. The global settings are overridden by Channel-specific options, |
||||
which in turn are overridden by command line switches. |
||||
.. |
||||
.TP |
||||
\fBSyncState\fR {\fB*\fR|\fIpath\fR} |
||||
Set the location of this Channel's synchronization state files. \fB*\fR means |
||||
that the state should be saved in a file named .mbsyncstate in the |
||||
Slave mailbox itself; this has the advantage that you needn't to care for the |
||||
state file if you delete the mailbox, but it works only with Maildir mailboxes, |
||||
obviously. Otherwise this is interpreted as a string to prepend to the Slave |
||||
mailbox name to make up a complete path. |
||||
.br |
||||
This option can be used outside any section for a global effect. In this case |
||||
the appended string is made up according to the pattern |
||||
\fB:\fImaster\fB:\fImaster-box\fB_:\fIslave\fB:\fIslave-box\fR. |
||||
.br |
||||
(Global default: \fI~/.mbsync/\fR). |
||||
.. |
||||
.SS Groups |
||||
.TP |
||||
\fBGroup\fR \fIname\fR [\fIchannel\fR[\fB:\fIbox\fR[\fB,\fR...]]] ... |
||||
Define the Group \fIname\fR, opening a section for its parameters. |
||||
Note that even though Groups have an own namespace, they will "hide" Channels |
||||
with the same name on the command line. |
||||
.br |
||||
One or more Channels can be specified on the same line. |
||||
.br |
||||
If you supply one or more \fIbox\fRes to a \fIchannel\fR, they will be used |
||||
instead of what is specified in the Channel. The same can be done on the command |
||||
line, except that there newlines can be used as mailbox name separators as well. |
||||
.. |
||||
.TP |
||||
\fBChannel\fR[\fBs\fR] \fIchannel\fR[\fB:\fIbox\fR[\fB,\fR...]] ... |
||||
Add the specified channels to the group. This option can be specified multiple |
||||
times within a Group. |
||||
.. |
||||
.SH SSL CERTIFICATES |
||||
[to be done] |
||||
.. |
||||
.SH INHERENT PROBLEMS |
||||
Changes done after \fBmbsync\fR has retrieved the message list will not be |
||||
synchronised until the next time \fBmbsync\fR is invoked. |
||||
.P |
||||
Using \fBTrash\fR on IMAP Stores bears a race condition: messages will be |
||||
lost if they are marked as deleted after the message list was retrieved but |
||||
before the mailbox is expunged. There is no risk as long as the IMAP mailbox |
||||
is not simultaneously accessed by \fBmbsync\fR and another mail client. |
||||
.. |
||||
.SH FILES |
||||
.TP |
||||
.B ~/.mbsyncrc |
||||
Default configuration file |
||||
.TP |
||||
.B ~/.mbsync/ |
||||
Directory containing synchronization state files |
||||
.. |
||||
.SH SEE ALSO |
||||
mdconvert(1), isync(1), mutt(1), maildir(5) |
||||
.P |
||||
Up to date information on \fBmbsync\fR can be found at http://isync.sf.net/ |
||||
.. |
||||
.SH AUTHOR |
||||
Written by Michael R. Elkins <me@mutt.org>, |
||||
.br |
||||
rewritten and maintained by Oswald Buddenhagen <ossi@users.sf.net>, |
||||
.br |
||||
contributions by Theodore Y. Ts'o <tytso@mit.edu>. |
@ -0,0 +1,82 @@
|
||||
# Global configuration section |
||||
# Values here are used as defaults for any following Channel section that |
||||
# doesn't specify them. |
||||
Expunge None |
||||
Create Both |
||||
|
||||
MaildirStore local |
||||
Path ~/Mail/ |
||||
Trash Trash |
||||
|
||||
|
||||
IMAPStore work |
||||
Host work.host.com |
||||
Pass xxxxxxxx |
||||
CertificateFile /etc/ssl/certs/ca-certificates.crt |
||||
|
||||
Channel work |
||||
Master :work: |
||||
Slave :local:work |
||||
Expunge Slave |
||||
Sync PullNew Push |
||||
|
||||
|
||||
IMAPStore personal |
||||
Host host.play.com |
||||
Port 6789 |
||||
RequireSSL no |
||||
|
||||
Channel personal |
||||
Master :personal: |
||||
Slave :local:personal |
||||
Expunge Both |
||||
MaxMessages 150 |
||||
MaxSize 200k |
||||
|
||||
IMAPStore remote |
||||
Tunnel "ssh -q host.remote.com /usr/sbin/imapd" |
||||
|
||||
Channel remote |
||||
Master :remote: |
||||
Slave :local:remote |
||||
|
||||
|
||||
Group boxes |
||||
Channels work personal remote |
||||
|
||||
|
||||
IMAPStore st1 |
||||
Host st1.domain.com |
||||
RequireCRAM yes |
||||
CertificateFile ~/.st1-certificate.crt |
||||
|
||||
IMAPStore st2 |
||||
Host imap.another-domain.com |
||||
Path non-standard/ |
||||
RequireSSL no |
||||
UseTLSv1 no |
||||
|
||||
Channel rst |
||||
Master :st1:somebox |
||||
Slave :st2: |
||||
|
||||
|
||||
IMAPAccount server |
||||
Host imaps:foo.bar.com |
||||
CertificateFile ~/.server-certificate.crt |
||||
|
||||
IMAPStore server |
||||
Account server |
||||
MapInbox inbox |
||||
Trash ~/trash |
||||
TrashRemoteNew yes |
||||
|
||||
MaildirStore mirror |
||||
Path ~/Maildir/ |
||||
|
||||
Channel o2o |
||||
Master :server: |
||||
Slave :mirror: |
||||
Patterns % |
||||
|
||||
Group partial o2o:inbox,sent-mail,foobar |
@ -0,0 +1,51 @@
|
||||
.ig |
||||
\" mdconvert - Maildir mailbox UID storage scheme converter |
||||
\" Copyright (C) 2004 Oswald Buddenhagen <ossi@users.sf.net> |
||||
\" |
||||
\" This program is free software; you can redistribute it and/or modify |
||||
\" it under the terms of the GNU General Public License as published by |
||||
\" the Free Software Foundation; either version 2 of the License, or |
||||
\" (at your option) any later version. |
||||
\" |
||||
\" This program is distributed in the hope that it will be useful, |
||||
\" but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
\" GNU General Public License for more details. |
||||
\" |
||||
\" You should have received a copy of the GNU General Public License |
||||
\" along with this program; if not, write to the Free Software |
||||
\" Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
.. |
||||
.TH mdconvert 1 "2004 Mar 27" |
||||
.. |
||||
.SH NAME |
||||
mdconvert - Maildir mailbox UID storage scheme converter |
||||
.. |
||||
.SH SYNOPSIS |
||||
\fBmdconvert\fR [\fIoptions\fR ...] \fImailbox\fR ... |
||||
.. |
||||
.SH DESCRIPTION |
||||
\fBmdconvert\fR converts Maildir mailboxes between the two UID storage schemes |
||||
supported by \fBmbsync\fR. See \fBmbsync\fR's manual page for details on these |
||||
schemes. |
||||
.. |
||||
.SH OPTIONS |
||||
.TP |
||||
\fB-a\fR, \fB--alt\fR |
||||
Convert to the \fBalternative\fR (Berkeley DB based) UID storage scheme. |
||||
.TP |
||||
\fB-n\fR, \fB--native\fR |
||||
Convert to the \fBnative\fR (file name based) UID storage scheme. |
||||
This is the default. |
||||
.TP |
||||
\fB-h\fR, \fB--help\fR |
||||
Displays a summary of command line options. |
||||
.TP |
||||
\fB-v\fR, \fB--version\fR |
||||
Displays version information. |
||||
.. |
||||
.SH SEE ALSO |
||||
mbsync(1) |
||||
.. |
||||
.SH AUTHOR |
||||
Written and maintained by Oswald Buddenhagen <ossi@users.sf.net>. |
@ -0,0 +1,256 @@
|
||||
/*
|
||||
* mdconvert - Maildir UID scheme converter |
||||
* Copyright (C) 2004 Oswald Buddenhagen <ossi@users.sf.net> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
*/ |
||||
|
||||
#include <config.h> |
||||
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <fcntl.h> |
||||
#include <sys/stat.h> |
||||
#include <stdarg.h> |
||||
#include <dirent.h> |
||||
#include <limits.h> |
||||
#include <errno.h> |
||||
#include <string.h> |
||||
#include <ctype.h> |
||||
|
||||
#include <db.h> |
||||
|
||||
#define EXE "mdconvert" |
||||
|
||||
static 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) { |
||||
fputs( "Fatal: buffer too small. Please report a bug.\n", stderr ); |
||||
abort(); |
||||
} |
||||
va_end( va ); |
||||
return ret; |
||||
} |
||||
|
||||
static const char *subdirs[] = { "cur", "new" }; |
||||
static struct flock lck; |
||||
static DBT key, value; |
||||
|
||||
static inline int |
||||
convert( const char *box, int altmap ) |
||||
{ |
||||
DB *db; |
||||
DIR *d; |
||||
struct dirent *e; |
||||
const char *u, *ru; |
||||
char *p, *s, *dpath, *spath, *dbpath; |
||||
int i, n, ret, sfd, dfd, bl, ml, uv[2], uid; |
||||
struct stat st; |
||||
char buf[_POSIX_PATH_MAX], buf2[_POSIX_PATH_MAX]; |
||||
char umpath[_POSIX_PATH_MAX], uvpath[_POSIX_PATH_MAX], tdpath[_POSIX_PATH_MAX]; |
||||
|
||||
if (stat( box, &st ) || !S_ISDIR(st.st_mode)) { |
||||
fprintf( stderr, "'%s' is no Maildir mailbox.\n", box ); |
||||
return 1; |
||||
} |
||||
|
||||
nfsnprintf( umpath, sizeof(umpath), "%s/.isyncuidmap.db", box ); |
||||
nfsnprintf( uvpath, sizeof(uvpath), "%s/.uidvalidity", box ); |
||||
if (altmap) |
||||
dpath = umpath, spath = uvpath, dbpath = tdpath; |
||||
else |
||||
spath = umpath, dpath = uvpath, dbpath = umpath; |
||||
nfsnprintf( tdpath, sizeof(tdpath), "%s.tmp", dpath ); |
||||
if ((sfd = open( spath, O_RDWR )) < 0) { |
||||
if (errno != ENOENT) |
||||
perror( spath ); |
||||
return 1; |
||||
} |
||||
if (fcntl( sfd, F_SETLKW, &lck )) { |
||||
perror( spath ); |
||||
goto sbork; |
||||
} |
||||
if ((dfd = open( tdpath, O_RDWR|O_CREAT, 0600 )) < 0) { |
||||
perror( tdpath ); |
||||
goto sbork; |
||||
} |
||||
if (db_create( &db, 0, 0 )) { |
||||
fputs( "Error: db_create() failed\n", stderr ); |
||||
goto tbork; |
||||
} |
||||
if ((ret = db->open( db, 0, dbpath, 0, DB_HASH, DB_CREATE, 0 ))) { |
||||
db->err( db, ret, "Error: db->open(%s)", dbpath ); |
||||
dbork: |
||||
db->close( db, 0 ); |
||||
tbork: |
||||
unlink( tdpath ); |
||||
close( dfd ); |
||||
sbork: |
||||
close( sfd ); |
||||
return 1; |
||||
} |
||||
key.data = (void *)"UIDVALIDITY"; |
||||
key.size = 11; |
||||
if (altmap) { |
||||
if ((n = read( sfd, buf, sizeof(buf) )) <= 0 || |
||||
(buf[n] = 0, sscanf( buf, "%d\n%d", &uv[0], &uv[1] ) != 2)) |
||||
{ |
||||
fprintf( stderr, "Error: cannot read UIDVALIDITY of '%s'.\n", box ); |
||||
goto dbork; |
||||
} |
||||
value.data = uv; |
||||
value.size = sizeof(uv); |
||||
if ((ret = db->put( db, 0, &key, &value, 0 ))) { |
||||
db->err( db, ret, "Error: cannot write UIDVALIDITY for '%s'", box ); |
||||
goto dbork; |
||||
} |
||||
} else { |
||||
if ((ret = db->get( db, 0, &key, &value, 0 ))) { |
||||
db->err( db, ret, "Error: cannot read UIDVALIDITY of '%s'", box ); |
||||
goto dbork; |
||||
} |
||||
n = sprintf( buf, "%d\n%d\n", ((int *)value.data)[0], ((int *)value.data)[1] ); |
||||
if (write( dfd, buf, n ) != n) { |
||||
fprintf( stderr, "Error: cannot write UIDVALIDITY for '%s'.\n", box ); |
||||
goto dbork; |
||||
} |
||||
} |
||||
|
||||
again: |
||||
for (i = 0; i < 2; i++) { |
||||
bl = nfsnprintf( buf, sizeof(buf), "%s/%s/", box, subdirs[i] ); |
||||
if (!(d = opendir( buf ))) { |
||||
perror( "opendir" ); |
||||
goto dbork; |
||||
} |
||||
while ((e = readdir( d ))) { |
||||
if (*e->d_name == '.') |
||||
continue; |
||||
nfsnprintf( buf + bl, sizeof(buf) - bl, "%s", e->d_name ); |
||||
memcpy( buf2, buf, bl ); |
||||
p = strstr( e->d_name, ",U=" ); |
||||
if (p) |
||||
for (u = p, ru = p + 3; isdigit( (unsigned char)*ru ); ru++); |
||||
else |
||||
u = ru = strchr( e->d_name, ':' ); |
||||
if (u) |
||||
ml = u - e->d_name; |
||||
else |
||||
ru = "", ml = INT_MAX; |
||||
if (altmap) { |
||||
if (!p) |
||||
continue; |
||||
key.data = e->d_name; |
||||
key.size = (size_t)(strchr( e->d_name, ',' ) - e->d_name); |
||||
uid = atoi( p + 3 ); |
||||
value.data = &uid; |
||||
value.size = sizeof(uid); |
||||
if ((ret = db->put( db, 0, &key, &value, 0 ))) { |
||||
db->err( db, ret, "Error: cannot write UID for '%s'", box ); |
||||
goto ebork; |
||||
} |
||||
nfsnprintf( buf2 + bl, sizeof(buf2) - bl, "%.*s%s", ml, e->d_name, ru ); |
||||
} else { |
||||
s = strpbrk( e->d_name, ",:" ); |
||||
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, "Error: cannot read UID for '%s'", box ); |
||||
goto ebork; |
||||
} |
||||
continue; |
||||
} |
||||
uid = *(int *)value.data; |
||||
nfsnprintf( buf2 + bl, sizeof(buf2) - bl, "%.*s,U=%d%s", ml, e->d_name, uid, ru ); |
||||
} |
||||
if (rename( buf, buf2 )) { |
||||
if (errno == ENOENT) |
||||
goto again; |
||||
perror( buf ); |
||||
ebork: |
||||
closedir( d ); |
||||
goto dbork; |
||||
} |
||||
|
||||
} |
||||
closedir( d ); |
||||
} |
||||
|
||||
db->close( db, 0 ); |
||||
close( dfd ); |
||||
if (rename( tdpath, dpath )) { |
||||
perror( dpath ); |
||||
return 1; |
||||
} |
||||
if (unlink( spath )) |
||||
perror( spath ); |
||||
close( sfd ); |
||||
return 0; |
||||
} |
||||
|
||||
int |
||||
main( int argc, char **argv ) |
||||
{ |
||||
int oint, ret, altmap = 0; |
||||
|
||||
for (oint = 1; oint < argc; oint++) { |
||||
if (!strcmp( argv[oint], "-h" ) || !strcmp( argv[oint], "--help" )) { |
||||
puts( |
||||
"Usage: " EXE " [-a] mailbox...\n" |
||||
" -a, --alt convert to alternative (DB based) UID scheme\n" |
||||
" -n, --native convert to native (file name based) UID scheme (default)\n" |
||||
" -h, --help show this help message\n" |
||||
" -v, --version display version" |
||||
); |
||||
return 0; |
||||
} else if (!strcmp( argv[oint], "-v" ) || !strcmp( argv[oint], "--version" )) { |
||||
puts( EXE " " VERSION " - Maildir UID scheme converter" ); |
||||
return 0; |
||||
} else if (!strcmp( argv[oint], "-a" ) || !strcmp( argv[oint], "--alt" )) { |
||||
altmap = 1; |
||||
} else if (!strcmp( argv[oint], "-n" ) || !strcmp( argv[oint], "--native" )) { |
||||
altmap = 0; |
||||
} else if (!strcmp( argv[oint], "--" )) { |
||||
oint++; |
||||
break; |
||||
} else if (argv[oint][0] == '-') { |
||||
fprintf( stderr, "Unrecognized option '%s'. Try " EXE " -h\n", argv[oint] ); |
||||
return 1; |
||||
} else |
||||
break; |
||||
} |
||||
if (oint == argc) { |
||||
fprintf( stderr, "Mailbox specification missing. Try " EXE " -h\n" ); |
||||
return 1; |
||||
} |
||||
#if SEEK_SET != 0 |
||||
lck.l_whence = SEEK_SET; |
||||
#endif |
||||
#if F_WRLCK != 0 |
||||
lck.l_type = F_WRLCK; |
||||
#endif |
||||
ret = 0; |
||||
for (; oint < argc; oint++) |
||||
ret |= convert( argv[oint], altmap ); |
||||
return ret; |
||||
} |
||||
|
@ -0,0 +1,389 @@
|
||||
/*
|
||||
* mbsync - mailbox synchronizer |
||||
* Copyright (C) 2000-2002 Michael R. Elkins <me@mutt.org> |
||||
* Copyright (C) 2002-2004 Oswald Buddenhagen <ossi@users.sf.net> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify |
||||
* it under the terms of the GNU General Public License as published by |
||||
* the Free Software Foundation; either version 2 of the License, or |
||||
* (at your option) any later version. |
||||
* |
||||
* This program is distributed in the hope that it will be useful, |
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
* GNU General Public License for more details. |
||||
* |
||||
* You should have received a copy of the GNU General Public License |
||||
* along with this program; if not, write to the Free Software |
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||||
* |
||||
* As a special exception, mbsync may be linked with the OpenSSL library, |
||||
* despite that library's more restrictive license. |
||||
*/ |
||||
|
||||
#include "isync.h" |
||||
|
||||
#include <stdarg.h> |
||||
#include <stdlib.h> |
||||
#include <unistd.h> |
||||
#include <fcntl.h> |
||||
#include <string.h> |
||||
#include <pwd.h> |
||||
#include <ctype.h> |
||||
|
||||
int Verbose, Quiet, Debug; |
||||
|
||||
void |
||||
debug( const char *msg, ... ) |
||||
{ |
||||
va_list va; |
||||
|
||||
if (Debug) { |
||||
va_start( va, msg ); |
||||
vprintf( msg, va ); |
||||
va_end( va ); |
||||
} |
||||
} |
||||
|
||||
void |
||||
info( const char *msg, ... ) |
||||
{ |
||||
va_list va; |
||||
|
||||
if (!Quiet) { |
||||
va_start( va, msg ); |
||||
vprintf( msg, va ); |
||||
va_end( va ); |
||||
fflush( stdout ); |
||||
} |
||||
} |
||||
|
||||
void |
||||
infoc( char c ) |
||||
{ |
||||
if (!Quiet) { |
||||
putchar( c ); |
||||
fflush( stdout ); |
||||
} |
||||
} |
||||
|
||||
void |
||||
warn( const char *msg, ... ) |
||||
{ |
||||
va_list va; |
||||
|
||||
if (Quiet < 2) { |
||||
va_start( va, msg ); |
||||
vfprintf( stderr, msg, va ); |
||||
va_end( va ); |
||||
} |
||||
} |
||||
|
||||
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; |
||||
} |
||||
|
||||
void |
||||
add_string_list( string_list_t **list, const char *str ) |
||||
{ |
||||
string_list_t *elem; |
||||
int len; |
||||
|
||||
len = strlen( str ); |
||||
elem = nfmalloc( sizeof(*elem) + len ); |
||||
elem->next = *list; |
||||
*list = elem; |
||||
memcpy( elem->string, str, len + 1 ); |
||||
} |
||||
|
||||
void |
||||
free_string_list( string_list_t *list ) |
||||
{ |
||||
string_list_t *tlist; |
||||
|
||||
for (; list; list = tlist) { |
||||
tlist = list->next; |
||||
free( list ); |
||||
} |
||||
} |
||||
|
||||
void |
||||
free_generic_messages( message_t *msgs ) |
||||
{ |
||||
message_t *tmsg; |
||||
|
||||
for (; msgs; msgs = tmsg) { |
||||
tmsg = msgs->next; |
||||
free( msgs ); |
||||
} |
||||
} |
||||
|
||||
void |
||||
strip_cr( msg_data_t *msgdata ) |
||||
{ |
||||
int i, o; |
||||
|
||||
if (msgdata->crlf) { |
||||
for (i = o = 0; i < msgdata->len; i++) |
||||
if (msgdata->data[i] != '\r') |
||||
msgdata->data[o++] = msgdata->data[i]; |
||||
msgdata->len = o; |
||||
msgdata->crlf = 0; |
||||
} |
||||
} |
||||
|
||||
#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 = 0; |
||||
else if ((*strp = malloc( len + 1 ))) { |
||||
if (len >= sizeof(tmp)) |
||||
vsprintf( *strp, fmt, ap ); |
||||
else |
||||
memcpy( *strp, tmp, len + 1 ); |
||||
} |
||||
return len; |
||||
} |
||||
#endif |
||||
|
||||
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 * |
||||
nfcalloc( size_t sz ) |
||||
{ |
||||
void *ret; |
||||
|
||||
if (!(ret = calloc( sz, 1 ))) |
||||
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 (!*str) |
||||
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; |
||||
} |
||||
|
||||
/*
|
||||
static struct passwd * |
||||
cur_user( void ) |
||||
{ |
||||
char *p; |
||||
struct passwd *pw; |
||||
uid_t uid; |
||||
|
||||
uid = getuid(); |
||||
if ((!(p = getenv("LOGNAME")) || !(pw = getpwnam( p )) || pw->pw_uid != uid) && |
||||
(!(p = getenv("USER")) || !(pw = getpwnam( p )) || pw->pw_uid != uid) && |
||||
!(pw = getpwuid( uid ))) |
||||
{ |
||||
fputs ("Cannot determinate current user\n", stderr); |
||||
return 0; |
||||
} |
||||
return pw; |
||||
} |
||||
*/ |
||||
|
||||
static char * |
||||
my_strndup( const char *s, size_t nchars ) |
||||
{ |
||||
char *r = nfmalloc( 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; |
||||
q = Home; |
||||
} else { |
||||
if ((p = strchr( s, '/' ))) { |
||||
r = my_strndup( s, (int)(p - s) ); |
||||
pw = getpwnam( r ); |
||||
free( r ); |
||||
} else |
||||
pw = getpwnam( s ); |
||||
if (!pw) |
||||
return 0; |
||||
q = pw->pw_dir; |
||||
} |
||||
nfasprintf( &r, "%s%s", q, p ? p : "" ); |
||||
return r; |
||||
} else |
||||
return nfstrdup( s ); |
||||
} |
||||
|
||||
static int |
||||
compare_ints( const void *l, const void *r ) |
||||
{ |
||||
return *(int *)l - *(int *)r; |
||||
} |
||||
|
||||
void |
||||
sort_ints( int *arr, int len ) |
||||
{ |
||||
qsort( arr, len, sizeof(int), compare_ints ); |
||||
} |
||||
|
||||
|
||||
static struct { |
||||
unsigned char i, j, s[256]; |
||||
} rs; |
||||
|
||||
void |
||||
arc4_init( void ) |
||||
{ |
||||
int i, fd; |
||||
unsigned char j, si, dat[128]; |
||||
|
||||
if ((fd = open( "/dev/urandom", O_RDONLY )) < 0 && (fd = open( "/dev/random", O_RDONLY )) < 0) { |
||||
fprintf( stderr, "Fatal: no random number source available.\n" ); |
||||
exit( 3 ); |
||||
} |
||||
if (read( fd, dat, 128 ) != 128) { |
||||
fprintf( stderr, "Fatal: cannot read random number source.\n" ); |
||||
exit( 3 ); |
||||
} |
||||
close( fd ); |
||||
|
||||
for (i = 0; i < 256; i++) |
||||
rs.s[i] = i; |
||||
for (i = j = 0; i < 256; i++) { |
||||
si = rs.s[i]; |
||||
j += si + dat[i & 127]; |
||||
rs.s[i] = rs.s[j]; |
||||
rs.s[j] = si; |
||||
} |
||||
rs.i = rs.j = 0; |
||||
|
||||
for (i = 0; i < 256; i++) |
||||
arc4_getbyte(); |
||||
} |
||||
|
||||
unsigned char |
||||
arc4_getbyte( void ) |
||||
{ |
||||
unsigned char si, sj; |
||||
|
||||
rs.i++; |
||||
si = rs.s[rs.i]; |
||||
rs.j += si; |
||||
sj = rs.s[rs.j]; |
||||
rs.s[rs.i] = sj; |
||||
rs.s[rs.j] = si; |
||||
return rs.s[(si + sj) & 0xff]; |
||||
} |
Loading…
Reference in new issue