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. |
make SSL certificate validation more automatic. |
||||||
maybe the error handling needs to be cleaned up in general. |
|
||||||
|
|
||||||
don't require maildir_trash. currently MaxMessages gets into the way of |
add asynchronous operation to remote mailbox drivers. this is actually |
||||||
simply removing it; that is fixable with some shuffling, though. |
what prevents us from simply using c-client and thus becoming mailsync. |
||||||
|
|
||||||
refactor mailbox support. create proper mailbox drivers; handle imap and |
handle custom flags (keywords). |
||||||
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. |
|
||||||
|
|
||||||
add asynchrounous operation to remote mailbox drivers. this is actually |
fix maildir_{open_store,list} to handle partial names (last char not slash). |
||||||
what prevents us from simply using c-client for the previous point and |
|
||||||
thus simply becoming mailsync. |
|
||||||
|
|
||||||
store message flags in sync database, so _un_setting them will be properly |
add a way to automatically create and sync subfolders. |
||||||
synced as well. |
|
||||||
|
|
||||||
handle custom imap flags. currently, isync just fails horribly if it |
could store TUID even when UIDPLUS is supported. would avoid duplicated |
||||||
encounters some. |
messages after abort before new UID arrives. |
||||||
|
|
||||||
add options for fine-grained control of syncing operations (--new, --delete & |
decouple TUID search from append. that's a prerequisite for usable |
||||||
--flags) and direction (--push & --pull). |
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 |
create dummies describing MIME structure of messages bigger than MaxSize. |
||||||
arriving during a fetch will not be fetched in the current run any more. |
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 |
maybe throw out the ctx->recent stuff - it's used only for one info message. |
||||||
IDs - this is a pretty common condition with uw-imap. |
|
||||||
|
|
||||||
possibly use ^[[1m to highlight error messages. |
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 |
.deps |
||||||
Makefile |
Makefile |
||||||
Makefile.in |
Makefile.in |
||||||
isync |
mbsync |
||||||
|
mdconvert |
||||||
|
@ -1,5 +1,16 @@ |
|||||||
bin_PROGRAMS = isync
|
if with_compat |
||||||
isync_SOURCES = main.c imap.c sync.c maildir.c list.c cram.c config.c dotlock.c
|
compat_dir = compat
|
||||||
noinst_HEADERS = isync.h dotlock.h
|
endif |
||||||
INCLUDES=$(RPM_OPT_FLAGS)
|
SUBDIRS = $(compat_dir)
|
||||||
DISTCLEANFILES = *~
|
|
||||||
|
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