This commit is contained in:
Nick Bebout 2011-03-12 02:44:54 +00:00
parent 1afcfe91ff
commit dd1d8ce6e9
10 changed files with 256 additions and 89 deletions

View file

@ -1,5 +1,5 @@
#!/bin/cat #!/bin/cat
# $Id: CREDITS,v 1.139 2010/06/21 00:16:01 gilles Exp gilles $ # $Id: CREDITS,v 1.140 2010/07/12 00:19:09 gilles Exp gilles $
If you want to make a donation to the author, Gilles LAMIRAL: If you want to make a donation to the author, Gilles LAMIRAL:
@ -23,6 +23,9 @@ I thank very much all of these people.
Bertrand STERN Bertrand STERN
Contributed by giving money 100 USD Contributed by giving money 100 USD
George Hazlewood
Contributed by giving money 40 USD
Miguel Jacq Miguel Jacq
Contributed by giving money 100 AUD Contributed by giving money 100 AUD

View file

@ -1,17 +1,43 @@
RCS file: RCS/imapsync,v RCS file: RCS/imapsync,v
Working file: imapsync Working file: imapsync
head: 1.321 head: 1.327
branch: branch:
locks: strict locks: strict
gilles: 1.321 gilles: 1.327
access list: access list:
symbolic names: symbolic names:
keyword substitution: kv keyword substitution: kv
total revisions: 321; selected revisions: 321 total revisions: 327; selected revisions: 327
description: description:
---------------------------- ----------------------------
revision 1.321 locked by: gilles; revision 1.327 locked by: gilles;
date: 2010/07/12 00:23:02; author: gilles; state: Exp; lines: +7 -5
Good exit at the end.
----------------------------
revision 1.326
date: 2010/07/12 00:16:03; author: gilles; state: Exp; lines: +9 -7
Default value when no reconnect.
----------------------------
revision 1.325
date: 2010/07/11 23:26:04; author: gilles; state: Exp; lines: +72 -38
Added --pidfile option.
Added die_clean() exit_clean() functions to remove pid file before quitting.
----------------------------
revision 1.324
date: 2010/07/11 21:28:23; author: gilles; state: Exp; lines: +24 -18
Added --debugimap1 --debugimap2 to permit imap outpout with only one host.
----------------------------
revision 1.323
date: 2010/07/11 21:10:17; author: gilles; state: Exp; lines: +28 -10
Added Reconnect_counter()
Added reconnect statistics
----------------------------
revision 1.322
date: 2010/07/10 22:30:18; author: gilles; state: Exp; lines: +46 -9
Added regression tests to remove first "From " header line. tests_regexmess()
----------------------------
revision 1.321
date: 2010/07/09 03:27:31; author: gilles; state: Exp; lines: +6 -6 date: 2010/07/09 03:27:31; author: gilles; state: Exp; lines: +6 -6
Added Smarter Mail 5.0 success. Added Smarter Mail 5.0 success.
---------------------------- ----------------------------

21
FAQ
View file

@ -1,5 +1,5 @@
#!/bin/cat #!/bin/cat
# $Id: FAQ,v 1.69 2010/07/07 22:47:39 gilles Exp gilles $ # $Id: FAQ,v 1.70 2010/07/12 00:18:33 gilles Exp gilles $
+------------------+ +------------------+
| FAQ for imapsync | | FAQ for imapsync |
@ -641,17 +641,28 @@ Any Maildir/ configured imap server may refuse this message since its
header is invalid. The first "From " line is not valid. It lacks a header is invalid. The first "From " line is not valid. It lacks a
colon character ":". To solve this problem you have several solutions colon character ":". To solve this problem you have several solutions
a) Remove these first "From " line manually for each message before a) Remove manually this first "From " line for each message before
using imapsync. Don't think to add a colon to this line since you using imapsync.
will end with two "From:" lines (just look at the other lines)
b) Run imapsync with the following options : b) Replace manually the whitespace by a colon in string "From " but you
might end with two "From:" lines (just have a look at the other header lines)
c) Run imapsync with the following option :
--regexmess 's/\AFrom /From:/' --regexmess 's/\AFrom /From:/'
or may be better (no other "From:" collision): or may be better (no other "From:" collision):
d) Run imapsync with the following option :
--regexmess 's/\AFrom /X-om:/' --regexmess 's/\AFrom /X-om:/'
e) Run imapsync with the following option :
--regexmess 's{\AFrom\ [^\n]*(\n)?}{}gxms'
Solution e) is solution a) made by imapsync itself.
Solutions c) and d) keep "From " lines information
(normally it's useless to keep them)
Best solutions are e) or d).
======================================================================= =======================================================================
Q. The contact folder isn't well copied. Q. The contact folder isn't well copied.

8
README
View file

@ -3,7 +3,7 @@ NAME
Synchronise mailboxes between two imap servers. Good at IMAP migration. Synchronise mailboxes between two imap servers. Good at IMAP migration.
More than 32 different IMAP server softwares supported with success. More than 32 different IMAP server softwares supported with success.
$Revision: 1.321 $ $Revision: 1.327 $
INSTALL INSTALL
imapsync works fine under any Unix OS with perl. imapsync works fine under any Unix OS with perl.
@ -69,10 +69,12 @@ SYNOPSIS
[--subscribed] [--subscribe] [--subscribe_all] [--subscribed] [--subscribe] [--subscribe_all]
[--nofoldersizes] [--nofoldersizes]
[--dry] [--dry]
[--debug] [--debugimap] [--debug] [--debugimap][--debugimap1][--debugimap2]
[--timeout <int>] [--fast] [--timeout <int>] [--fast]
[--split1] [--split2] [--split1] [--split2]
[--reconnectretry1 <int>] [--reconnectretry2 <int>] [--reconnectretry1 <int>] [--reconnectretry2 <int>]
[--pidfile <filepath>]
[--tmpdir <dirpath>]
[--version] [--help] [--version] [--help]
DESCRIPTION DESCRIPTION
@ -375,5 +377,5 @@ SIMILAR SOFTWARES
Feedback (good or bad) will always be welcome. Feedback (good or bad) will always be welcome.
$Id: imapsync,v 1.321 2010/07/09 03:27:31 gilles Exp gilles $ $Id: imapsync,v 1.327 2010/07/12 00:23:02 gilles Exp gilles $

4
TIME
View file

@ -1,4 +1,6 @@
120 --pidfile option. die_clean() exit_clean()
120 reconnect counter, --debugimap1 --debugimap2
50 FAQ tested "From " removing solution.
600 split maxcommandlenght, email, reconnect better. 600 split maxcommandlenght, email, reconnect better.
25 reconnect AUTOLOADING bug? 25 reconnect AUTOLOADING bug?
80 --subscribe_all. 1.318 80 --subscribe_all. 1.318

21
TODO
View file

@ -1,5 +1,5 @@
#!/bin/cat #!/bin/cat
# $Id: TODO,v 1.76 2010/07/07 23:49:12 gilles Exp gilles $ # $Id: TODO,v 1.77 2010/07/12 00:13:15 gilles Exp gilles $
TODO file for imapsync TODO file for imapsync
---------------------- ----------------------
@ -69,20 +69,16 @@ issues so far". Sounds good!
Add an option to implement the faq entry about copying a contact folder. Add an option to implement the faq entry about copying a contact folder.
imapsync doesn't report well. It should says "I had imapsync doesn't report well. It should says "I had
to sync 123 messages but I could transfer only 99 messages" to sync 123 messages but I could transfer only 99 messages"
Maybe count messages not transfered because they're dupplicate.
Fix bug "not possible to use space in the imap password" Fix bug "not possible to use space in the imap password"
Add kerberos authentification Add kerberos authentification
Add NOOP commands to avoid timeouts.
Add a --pidfile option.
Write a clean_exit() replacing each die() or exit() call.
Add a --skipheaderinfolder option Add a --skipheaderinfolder option
See the code patches/imapsync_Cvitkovich_pidfile_tmpfile
Fix this: Fix this:
> - Erreur avec la traditionnelle différence entre Windows > - Erreur avec la traditionnelle différence entre Windows
@ -145,6 +141,17 @@ http://asg.web.cmu.edu/cyrus/download/imapd/altnamespace.html
Explain expunge behavior. Explain expunge behavior.
DONE. Write a clean_exit() replacing each die() or exit() call.
Wrote exit_clean() and die_clean() to remove pid file.
DONE. Add a --pidfile option.
DONE. Add NOOP commands to avoid timeouts.
Useless since reconnect mode permits timeouts.
DONE. Add --subscribeall option. DONE. Add --subscribeall option.
Is it possible to have a option that subscribes all folders regardless of Is it possible to have a option that subscribes all folders regardless of
subscription on the source server? Perhaps --subscribeall? subscription on the source server? Perhaps --subscribeall?

View file

@ -1 +1 @@
1.321 1.327

211
imapsync
View file

@ -9,7 +9,7 @@ tool. Synchronise mailboxes between two imap servers. Good
at IMAP migration. More than 32 different IMAP server softwares at IMAP migration. More than 32 different IMAP server softwares
supported with success. supported with success.
$Revision: 1.321 $ $Revision: 1.327 $
=head1 INSTALL =head1 INSTALL
@ -77,10 +77,12 @@ The option list:
[--subscribed] [--subscribe] [--subscribe_all] [--subscribed] [--subscribe] [--subscribe_all]
[--nofoldersizes] [--nofoldersizes]
[--dry] [--dry]
[--debug] [--debugimap] [--debug] [--debugimap][--debugimap1][--debugimap2]
[--timeout <int>] [--fast] [--timeout <int>] [--fast]
[--split1] [--split2] [--split1] [--split2]
[--reconnectretry1 <int>] [--reconnectretry2 <int>] [--reconnectretry1 <int>] [--reconnectretry2 <int>]
[--pidfile <filepath>]
[--tmpdir <dirpath>]
[--version] [--help] [--version] [--help]
=cut =cut
@ -433,7 +435,7 @@ Entries for imapsync:
Feedback (good or bad) will always be welcome. Feedback (good or bad) will always be welcome.
$Id: imapsync,v 1.321 2010/07/09 03:27:31 gilles Exp gilles $ $Id: imapsync,v 1.327 2010/07/12 00:23:02 gilles Exp gilles $
=cut =cut
@ -463,7 +465,8 @@ eval { require 'usr/include/sysexits.ph' };
my( my(
$rcs, $debug, $debugimap, $error, $rcs, $pidfile,
$debug, $debugimap, $debugimap1, $debugimap2, $error,
$host1, $host2, $port1, $port2, $host1, $host2, $port1, $port2,
$user1, $user2, $password1, $password2, $passfile1, $passfile2, $user1, $user2, $password1, $password2, $passfile1, $passfile2,
@folder, @include, @exclude, @folderrec, @folder, @include, @exclude, @folderrec,
@ -507,7 +510,7 @@ my(
use vars qw ($opt_G); # missing code for this will be option. use vars qw ($opt_G); # missing code for this will be option.
$rcs = '$Id: imapsync,v 1.321 2010/07/09 03:27:31 gilles Exp gilles $ '; $rcs = '$Id: imapsync,v 1.327 2010/07/12 00:23:02 gilles Exp gilles $ ';
$rcs =~ m/,v (\d+\.\d+)/; $rcs =~ m/,v (\d+\.\d+)/;
$VERSION = ($1) ? $1: "UNKNOWN"; $VERSION = ($1) ? $1: "UNKNOWN";
@ -570,13 +573,11 @@ while (@argv_copy) {
} }
} }
my $banner = join("", my $banner_imapsync = join("",
'$RCSfile: imapsync,v $ ', '$RCSfile: imapsync,v $ ',
'$Revision: 1.321 $ ', '$Revision: 1.327 $ ',
'$Date: 2010/07/09 03:27:31 $ ', '$Date: 2010/07/12 00:23:02 $ ',
"\n",localhost_info(), "\n",localhost_info(), "\n",
" and the module Mail::IMAPClient version used here is ",
$VERSION_IMAPClient,"\n",
"Command line used:\n", "Command line used:\n",
"$0 @argv_nopassord\n", "$0 @argv_nopassord\n",
); );
@ -588,8 +589,27 @@ unless(defined(&_SYSEXITS_H)) {
get_options(); get_options();
sub write_pidfile {
my $pidfile = shift;
print "PID file is $pidfile\n";
if (-e $pidfile) {
warn "$pidfile already exists, overwriting it\n";
}
open(PIDFILE, ">$pidfile") or do {
warn "Could not open $pidfile for writing";
return undef;
};
print PIDFILE $PROCESS_ID;
close PIDFILE;
return($PROCESS_ID);
}
$tmpdir ||= File::Spec->tmpdir(); $tmpdir ||= File::Spec->tmpdir();
$pidfile ||= $tmpdir . '/imapsync.pid';
sub check_dir { sub check_dir {
my $dir = shift; my $dir = shift;
@ -607,20 +627,34 @@ sub check_dir {
$allow3xx = defined($allow3xx) ? $allow3xx : 1; $allow3xx = defined($allow3xx) ? $allow3xx : 1;
check_lib_version() or check_lib_version() or
die "imapsync needs perl lib Mail::IMAPClient release 2.2.9, or 3.0.19 or superior \n"; die "imapsync needs perl lib Mail::IMAPClient release 2.2.9, or 3.0.25 or superior \n";
print $banner; print $banner_imapsync;
print "Temp directory is $tmpdir\n"; print "Temp directory is $tmpdir\n";
check_dir($tmpdir); check_dir($tmpdir);
write_pidfile($pidfile) if ($pidfile);
exit(0) if ($justbanner); exit_clean(0) if ($justbanner);
sub exit_clean {
my $status = shift;
unlink($pidfile);
exit($status);
}
sub die_clean {
unlink($pidfile);
die @_;
}
sub missing_option { sub missing_option {
my ($option) = @_; my ($option) = @_;
die "$option option must be used, run $0 --help for help\n"; die_clean "$option option must be used, run $0 --help for help\n";
} }
# By default, 1000 at a time, not more. # By default, 1000 at a time, not more.
@ -633,6 +667,7 @@ $port1 ||= (defined $ssl1 and !defined $tls1) ? 993 : 143;
$host2 || missing_option("--host2") ; $host2 || missing_option("--host2") ;
$port2 ||= (defined $ssl2 && !defined $tls2) ? 993 : 143; $port2 ||= (defined $ssl2 && !defined $tls2) ? 993 : 143;
$debugimap1 = $debugimap2 = 1 if ($debugimap);
sub connect_imap { sub connect_imap {
my($host, $port, $debugimap, $ssl, $tls) = @_; my($host, $port, $debugimap, $ssl, $tls) = @_;
@ -644,7 +679,7 @@ sub connect_imap {
$imap->Tls($tls) if ($tls); $imap->Tls($tls) if ($tls);
#$imap->connect() #$imap->connect()
myconnect($imap) myconnect($imap)
or die "Can not open imap connection on [$host]: $@\n"; or die_clean("Can not open imap connection on [$host]: $@\n");
} }
sub localhost_info { sub localhost_info {
@ -655,8 +690,8 @@ sub localhost_info {
uname(), uname(),
), ),
")\n", ")\n",
"with perl ", "With perl ",
sprintf("%vd", $PERL_VERSION),"\n", sprintf("%vd", $PERL_VERSION),
" Mail::IMAPClient $Mail::IMAPClient::VERSION", " Mail::IMAPClient $Mail::IMAPClient::VERSION",
); );
return($infos); return($infos);
@ -667,15 +702,15 @@ if ($justconnect) {
my $imap1 = (); my $imap1 = ();
my $imap2 = (); my $imap2 = ();
$imap1 = connect_imap($host1, $port1, $debugimap, $ssl1, $tls1); $imap1 = connect_imap($host1, $port1, $debugimap1, $ssl1, $tls1);
print "Host1 software: ", server_banner($imap1); print "Host1 software: ", server_banner($imap1);
print "Host1 capability: ", join(" ", $imap1->capability()), "\n"; print "Host1 capability: ", join(" ", $imap1->capability()), "\n";
$imap2 = connect_imap($host2, $port2, $debugimap, $ssl2, $tls2); $imap2 = connect_imap($host2, $port2, $debugimap2, $ssl2, $tls2);
print "Host2 software: ", server_banner($imap2); print "Host2 software: ", server_banner($imap2);
print "Host2 capability: ", join(" ", $imap2->capability()), "\n"; print "Host2 capability: ", join(" ", $imap2->capability()), "\n";
$imap1->logout(); $imap1->logout();
$imap2->logout(); $imap2->logout();
exit(0); exit_clean(0);
} }
$user1 || missing_option("--user1"); $user1 || missing_option("--user1");
@ -774,14 +809,14 @@ my $imap2 = ();
$timestart = time(); $timestart = time();
$timebefore = $timestart; $timebefore = $timestart;
$debugimap and print "Host1 connection\n"; $debugimap1 and print "Host1 connection\n";
$imap1 = login_imap($host1, $port1, $user1, $password1, $imap1 = login_imap($host1, $port1, $user1, $password1,
$debugimap, $timeout, $fastio1, $ssl1, $tls1, $debugimap1, $timeout, $fastio1, $ssl1, $tls1,
$authmech1, $authuser1, $reconnectretry1); $authmech1, $authuser1, $reconnectretry1);
$debugimap and print "Host2 connection\n"; $debugimap2 and print "Host2 connection\n";
$imap2 = login_imap($host2, $port2, $user2, $password2, $imap2 = login_imap($host2, $port2, $user2, $password2,
$debugimap, $timeout, $fastio2, $ssl2, $tls2, $debugimap2, $timeout, $fastio2, $ssl2, $tls2,
$authmech2, $authuser2, $reconnectretry2); $authmech2, $authuser2, $reconnectretry2);
# history # history
@ -814,7 +849,7 @@ sub login_imap {
#$imap->connect() #$imap->connect()
myconnect($imap) myconnect($imap)
or die "Can not open imap connection on [$host] with user [$user]: $@\n"; or die_clean("Can not open imap connection on [$host] with user [$user]: $@\n");
print "Banner: ", server_banner($imap); print "Banner: ", server_banner($imap);
@ -846,11 +881,11 @@ sub login_imap {
chomp($einfo); chomp($einfo);
my $error = "$info [$authmech]: $einfo\n"; my $error = "$info [$authmech]: $einfo\n";
print $error; # note: duplicating error on stdout/stderr print $error; # note: duplicating error on stdout/stderr
die $error if ($authmech eq 'LOGIN' or $imap->IsUnconnected() or $authuser); die_clean($error) if ($authmech eq 'LOGIN' or $imap->IsUnconnected() or $authuser);
print "Trying LOGIN Auth mechanism on [$host] with user [$user]\n"; print "Trying LOGIN Auth mechanism on [$host] with user [$user]\n";
$imap->Authmechanism(""); $imap->Authmechanism("");
$imap->login() or $imap->login() or
die "$info [LOGIN]: ", $imap->LastError, "\n"; die_clean("$info [LOGIN]: ", $imap->LastError, "\n");
} }
print "Success login on [$host] with user [$user] auth [$authmech]\n"; print "Success login on [$host] with user [$user] auth [$authmech]\n";
return($imap); return($imap);
@ -877,12 +912,12 @@ sub server_banner {
$debug and print "Host1 capability: ", join(" ", $imap1->capability()), "\n"; $debug and print "Host1 capability: ", join(" ", $imap1->capability()), "\n";
$debug and print "Host2 capability: ", join(" ", $imap2->capability()), "\n"; $debug and print "Host2 capability: ", join(" ", $imap2->capability()), "\n";
die unless $imap1->IsAuthenticated(); die_clean() unless $imap1->IsAuthenticated();
print "host1: state Authenticated\n"; print "host1: state Authenticated\n";
die unless $imap2->IsAuthenticated(); die_clean() unless $imap2->IsAuthenticated();
print "host2: state Authenticated\n"; print "host2: state Authenticated\n";
exit(0) if ($justlogin); exit_clean(0) if ($justlogin);
$split1 and $imap1->Split($split1); $split1 and $imap1->Split($split1);
$split2 and $imap2->Split($split2); $split2 and $imap2->Split($split2);
@ -891,7 +926,8 @@ $split2 and $imap2->Split($split2);
# Folder stuff # Folder stuff
# #
my (@h1_folders, %requested_folder, @h2_folders, @h2_folders_list, %h2_folders_list, %subscribed_folder, %h2_folders); my (@h1_folders, %requested_folder,
@h2_folders, @h2_folders_list, %h2_folders_list, %subscribed_folder, %h2_folders);
sub tests_folder_routines { sub tests_folder_routines {
ok( !give_requested_folders() ,"no requested folders" ); ok( !give_requested_folders() ,"no requested folders" );
@ -1139,7 +1175,7 @@ sub get_prefix {
"No NAMESPACE capability in imap server ", "No NAMESPACE capability in imap server ",
$imap->Server(),"\n", $imap->Server(),"\n",
"Give the prefix namespace with the $prefix_opt option\n"; "Give the prefix namespace with the $prefix_opt option\n";
exit(1); exit_clean(1);
} }
} }
@ -1161,14 +1197,14 @@ sub get_separator {
warn warn
"NAMESPACE request failed for ", "NAMESPACE request failed for ",
$imap->Server(), ": ", $imap->LastError, "\n"; $imap->Server(), ": ", $imap->LastError, "\n";
exit(1); exit_clean(1);
} }
else{ else{
warn warn
"No NAMESPACE capability in imap server ", "No NAMESPACE capability in imap server ",
$imap->Server(),"\n", $imap->Server(),"\n",
"Give the separator character with the $sep_opt option\n"; "Give the separator character with the $sep_opt option\n";
exit(1); exit_clean(1);
} }
} }
@ -1214,7 +1250,7 @@ sub foldersizes {
$smess = $imap->message_count(); $smess = $imap->message_count();
unless ($smess == 0) { unless ($smess == 0) {
#$imap->Ranges(1); #$imap->Ranges(1);
$imap->fetch_hash("RFC822.SIZE",$hashref) or die "$@"; $imap->fetch_hash("RFC822.SIZE",$hashref) or die_clean("$@");
#$imap->Ranges(0); #$imap->Ranges(0);
#print map {$hashref->{$_}->{"RFC822.SIZE"}, " "} keys %$hashref; #print map {$hashref->{$_}->{"RFC822.SIZE"}, " "} keys %$hashref;
map {$stot += $hashref->{$_}->{"RFC822.SIZE"}} keys %$hashref; map {$stot += $hashref->{$_}->{"RFC822.SIZE"}} keys %$hashref;
@ -1256,7 +1292,7 @@ sub timenext {
return($timerel); return($timerel);
} }
exit if ($justfoldersizes); exit_clean(0) if ($justfoldersizes);
# needed for setting flags # needed for setting flags
my $imap2hasuidplus = $imap2->has_capability("UIDPLUS"); my $imap2hasuidplus = $imap2->has_capability("UIDPLUS");
@ -1344,7 +1380,7 @@ sub imap2_folder_name {
my $h2_fold_before = $h2_fold; my $h2_fold_before = $h2_fold;
eval("\$h2_fold =~ $regextrans2"); eval("\$h2_fold =~ $regextrans2");
$debug and print "[$h2_fold_before] -> [$h2_fold] using re [$regextrans2]\n"; $debug and print "[$h2_fold_before] -> [$h2_fold] using re [$regextrans2]\n";
die("error: eval regextrans2 '$regextrans2': $@\n") if $@; die_clean("error: eval regextrans2 '$regextrans2': $@\n") if $@;
} }
return($h2_fold); return($h2_fold);
} }
@ -1457,7 +1493,7 @@ sub flags_regex {
my $h1_flags_orig = $h1_flags; my $h1_flags_orig = $h1_flags;
$debug and print "eval \$h1_flags =~ $regexflag\n"; $debug and print "eval \$h1_flags =~ $regexflag\n";
eval("\$h1_flags =~ $regexflag"); eval("\$h1_flags =~ $regexflag");
die("error: eval regexflag '$regexflag': $@\n") if $@; die_clean("error: eval regexflag '$regexflag': $@\n") if $@;
$debug and print "regexflag $regexflag [$h1_flags_orig] -> [$h1_flags]\n"; $debug and print "regexflag $regexflag [$h1_flags_orig] -> [$h1_flags]\n";
} }
return($h1_flags); return($h1_flags);
@ -1544,14 +1580,17 @@ sub flags_filter {
print "++++ Looping on each folder ++++\n"; print "++++ Looping on each folder ++++\n";
#sleep 10;
FOLDER: foreach my $h1_fold (@h1_folders) { FOLDER: foreach my $h1_fold (@h1_folders) {
last FOLDER if $imap1->IsUnconnected();
last FOLDER if $imap2->IsUnconnected();
my $h2_fold; my $h2_fold;
print "Host1 Folder [$h1_fold]\n"; print "Host1 Folder [$h1_fold]\n";
$h2_fold = imap2_folder_name($h1_fold); $h2_fold = imap2_folder_name($h1_fold);
print "Host2 Folder [$h2_fold]\n"; print "Host2 Folder [$h2_fold]\n";
last FOLDER if $imap1->IsUnconnected();
last FOLDER if $imap2->IsUnconnected();
unless ($imap1->select($h1_fold)) { unless ($imap1->select($h1_fold)) {
warn warn
@ -1786,19 +1825,56 @@ FOLDER: foreach my $h1_fold (@h1_folders) {
@regexmess = 's{\AFrom\ }{From:}gxms'; @regexmess = 's{\AFrom\ }{From:}gxms';
ok( '' ok( ''
eq regexmess(''), eq regexmess(''),
'From mbox 1 blank'); 'From mbox 1 add colon blank');
ok( 'From:<tartanpion@machin.truc>' ok( 'From:<tartanpion@machin.truc>'
eq regexmess('From <tartanpion@machin.truc>'), eq regexmess('From <tartanpion@machin.truc>'),
'From mbox 2'); 'From mbox 2 add colo');
ok( "\n" . 'From <tartanpion@machin.truc>' ok( "\n" . 'From <tartanpion@machin.truc>'
eq regexmess("\n" . 'From <tartanpion@machin.truc>'), eq regexmess("\n" . 'From <tartanpion@machin.truc>'),
'From mbox 3'); 'From mbox 3 add colo');
ok( "From: zzz\n" . 'From <tartanpion@machin.truc>' ok( "From: zzz\n" . 'From <tartanpion@machin.truc>'
eq regexmess("From zzz\n" . 'From <tartanpion@machin.truc>'), eq regexmess("From zzz\n" . 'From <tartanpion@machin.truc>'),
'From mbox 4'); 'From mbox 4 add colo');
@regexmess = 's{\AFrom\ [^\n]*(\n)?}{}gxms';
ok( ''
eq regexmess(''),
'From mbox 1 remove, blank');
ok( ''
eq regexmess('From <tartanpion@machin.truc>'),
'From mbox 2 remove');
ok( "\n" . 'From <tartanpion@machin.truc>'
eq regexmess("\n" . 'From <tartanpion@machin.truc>'),
'From mbox 3 remove');
#print "[", regexmess("From zzz\n" . 'From <tartanpion@machin.truc>'), "]";
ok( "" . 'From <tartanpion@machin.truc>'
eq regexmess("From zzz\n" . 'From <tartanpion@machin.truc>'),
'From mbox 4 remove');
ok(
'Date: Sat, 10 Jul 2010 05:34:45 -0700
From:<tartanpion@machin.truc>
Hello,
Bye.'
eq regexmess(
'From zzz
Date: Sat, 10 Jul 2010 05:34:45 -0700
From:<tartanpion@machin.truc>
Hello,
Bye.'
),
'From mbox 5 remove');
} }
sub regexmess { sub regexmess {
@ -1806,7 +1882,7 @@ FOLDER: foreach my $h1_fold (@h1_folders) {
foreach my $regexmess (@regexmess) { foreach my $regexmess (@regexmess) {
$debug and print "eval \$string =~ $regexmess\n"; $debug and print "eval \$string =~ $regexmess\n";
eval("\$string =~ $regexmess"); eval("\$string =~ $regexmess");
die("error: eval regexmess '$regexmess': $@\n") if $@; die_clean("error: eval regexmess '$regexmess': $@\n") if $@;
} }
return($string); return($string);
} }
@ -2040,13 +2116,18 @@ sub lost_connection {
$imap1->logout(); $imap1->logout();
$imap2->logout(); $imap2->logout();
my $host1_reconnect_count = $imap1->Reconnect_counter() || 0;
my $host2_reconnect_count = $imap2->Reconnect_counter() || 0;
$timeend = time(); $timeend = time();
$timediff = $timeend - $timestart; $timediff = $timeend - $timestart;
stats(); stats();
exit(1) if($error); exit_clean(1) if($error);
exit_clean(0);
sub select_msgs { sub select_msgs {
my ($imap) = @_; my ($imap) = @_;
@ -2092,6 +2173,8 @@ sub stats {
print "Total bytes error : $mess_size_total_error\n"; print "Total bytes error : $mess_size_total_error\n";
$timediff ||= 1; # No division per 0 $timediff ||= 1; # No division per 0
printf ("Average bandwidth rate : %.1f KiB/s\n", $mess_size_total_trans / 1024 / $timediff); printf ("Average bandwidth rate : %.1f KiB/s\n", $mess_size_total_trans / 1024 / $timediff);
print "Reconnections to host1 : $host1_reconnect_count\n";
print "Reconnections to host2 : $host2_reconnect_count\n";
print "Detected $error errors\n\n"; print "Detected $error errors\n\n";
print thank_author(); print thank_author();
} }
@ -2119,6 +2202,8 @@ sub get_options {
my $opt_ret = GetOptions( my $opt_ret = GetOptions(
"debug!" => \$debug, "debug!" => \$debug,
"debugimap!" => \$debugimap, "debugimap!" => \$debugimap,
"debugimap1!" => \$debugimap1,
"debugimap2!" => \$debugimap2,
"host1=s" => \$host1, "host1=s" => \$host1,
"host2=s" => \$host2, "host2=s" => \$host2,
"port1=i" => \$port1, "port1=i" => \$port1,
@ -2190,6 +2275,8 @@ sub get_options {
"allow3xx!" => \$allow3xx, "allow3xx!" => \$allow3xx,
"justlogin!" => \$justlogin, "justlogin!" => \$justlogin,
"tmpdir=s" => \$tmpdir, "tmpdir=s" => \$tmpdir,
"pidfile=s" => \$pidfile,
); );
$debug and print "get options: [$opt_ret]\n"; $debug and print "get options: [$opt_ret]\n";
@ -2306,7 +2393,7 @@ sub firstline {
my($file) = @_; my($file) = @_;
my $line = ""; my $line = "";
open FILE, $file or die("error [$file]: $! "); open FILE, $file or die_clean("error [$file]: $! ");
chomp($line = <FILE>); chomp($line = <FILE>);
close FILE; close FILE;
$line = ($line) ? $line: "error !EMPTY! [$file]"; $line = ($line) ? $line: "error !EMPTY! [$file]";
@ -2317,7 +2404,7 @@ sub firstline {
sub file_to_string { sub file_to_string {
my($file) = @_; my($file) = @_;
my @string; my @string;
open FILE, $file or die("error [$file]: $! "); open FILE, $file or die_clean("error [$file]: $! ");
@string = <FILE>; @string = <FILE>;
close FILE; close FILE;
return join("", @string); return join("", @string);
@ -2326,7 +2413,7 @@ sub file_to_string {
sub string_to_file { sub string_to_file {
my($string, $file) = @_; my($string, $file) = @_;
sysopen(FILE, $file,O_WRONLY|O_TRUNC|O_CREAT, 0600) or die("$! $file"); sysopen(FILE, $file,O_WRONLY|O_TRUNC|O_CREAT, 0600) or die_clean("$! $file");
print FILE $string; print FILE $string;
close FILE; close FILE;
} }
@ -2378,6 +2465,7 @@ Several options are mandatory.
--tmpdir <string> : where to store temporary files and subdirectories. --tmpdir <string> : where to store temporary files and subdirectories.
Will be created if it doesn't exist. Will be created if it doesn't exist.
Default is system specific and should be ok. Default is system specific and should be ok.
--pidfile <string> : the file where imapsync pid is written.
--prefix1 <string> : remove prefix to all destination folders --prefix1 <string> : remove prefix to all destination folders
(usually INBOX. for cyrus imap servers) (usually INBOX. for cyrus imap servers)
you can use --prefix1 if your source imap server you can use --prefix1 if your source imap server
@ -2457,7 +2545,9 @@ Several options are mandatory.
--syncacls : Synchronises acls (Access Control Lists). --syncacls : Synchronises acls (Access Control Lists).
--nosyncacls : Does not synchronise acls. This is the default. --nosyncacls : Does not synchronise acls. This is the default.
--debug : debug mode. --debug : debug mode.
--debugimap : imap debug mode. Very verbose. --debugimap1 : imap debug mode for host1. imap debug is very verbose.
--debugimap2 : imap debug mode for host2.
--debugimap : imap debug mode for host1 and host2.
--version : print software version. --version : print software version.
--justconnect : just connect to both servers and print useful --justconnect : just connect to both servers and print useful
information. Need only --host1 and --host2 options. information. Need only --host1 and --host2 options.
@ -3144,7 +3234,7 @@ no warnings 'once';
#print "call @_\n"; #print "call @_\n";
$rc = $self->_imap_command_do(@_); $rc = $self->_imap_command_do(@_);
push( @err, $self->LastError ) if $self->LastError; push( @err, $self->LastError ) if $self->LastError;
#print "call @_ done [$rc] [$retry][" . $self->IsUnconnected . "]\n"; #print "call @_ done [", $rc || '', "] [$tries/$retry][" . $self->IsUnconnected . "]\n";
} }
if ( !defined($rc) and $retry and $self->IsUnconnected if ( !defined($rc) and $retry and $self->IsUnconnected
@ -3152,6 +3242,7 @@ no warnings 'once';
print "\nWarning: disconnected. "; print "\nWarning: disconnected. ";
if ( $self->reconnect ) { if ( $self->reconnect ) {
print "Reconnect successful on try #$tries\n"; print "Reconnect successful on try #$tries\n";
$self->Reconnect_counter($self->Reconnect_counter() + 1);
} }
else { else {
print "Reconnect failed on try #$tries\n"; print "Reconnect failed on try #$tries\n";
@ -3585,14 +3676,14 @@ sub starttls {
my $banner = $self->Banner(); my $banner = $self->Banner();
$debug and print $banner; $debug and print $banner;
unless ($banner =~ /^\* OK \[CAPABILITY.*STARTTLS.*\]/) { unless ($banner =~ /^\* OK \[CAPABILITY.*STARTTLS.*\]/) {
die "No STARTTLS capability: $banner"; die_clean( "No STARTTLS capability: $banner" );
} }
print $socket, "\n"; print $socket, "\n";
print $socket "z00 STARTTLS\015\012"; print $socket "z00 STARTTLS\015\012";
my $txt = $socket->getline(); my $txt = $socket->getline();
$debug and print "Read: $txt"; $debug and print "Read: $txt";
unless($txt =~ /^z00 OK/){ unless($txt =~ /^z00 OK/){
die "Invalid response for STARTTLS: $txt\n"; die_clean( "Invalid response for STARTTLS: $txt\n" );
} }
$debug and print "Calling start_SSL\n"; $debug and print "Calling start_SSL\n";
unless(IO::Socket::SSL->start_SSL($socket, unless(IO::Socket::SSL->start_SSL($socket,
@ -3602,10 +3693,10 @@ sub starttls {
SSL_verify_depth => 1, SSL_verify_depth => 1,
})) }))
{ {
die "Couldn't start TLS: ".IO::Socket::SSL::errstr()."\n"; die_clean( "Couldn't start TLS: ".IO::Socket::SSL::errstr()."\n");
} }
if (ref($socket) ne "IO::Socket::SSL") { if (ref($socket) ne "IO::Socket::SSL") {
die "Socket has NOT been converted to SSL"; die_clean( "Socket has NOT been converted to SSL");
}else{ }else{
$debug and print "Socket successfuly converted to SSL\n"; $debug and print "Socket successfuly converted to SSL\n";
} }
@ -3633,6 +3724,14 @@ sub Tls {
return $self->{TLS}; return $self->{TLS};
} }
sub Reconnect_counter {
my $self = shift;
if (@_) { $self->{Reconnect_counter} = shift }
return $self->{Reconnect_counter};
}
sub Banner { sub Banner {
my $self = shift; my $self = shift;

View file

@ -5,7 +5,7 @@
<title>imapsync</title> <title>imapsync</title>
<meta name="generator" content="Bluefish 1.0.7"/> <meta name="generator" content="Bluefish 1.0.7"/>
<meta name="author" content="Gilles LAMIRAL"/> <meta name="author" content="Gilles LAMIRAL"/>
<meta name="date" content="2010-06-22T18:26:45+0200"/> <meta name="date" content="2010-07-11T21:37:45+0200"/>
<meta name="copyright" content="None"/> <meta name="copyright" content="None"/>
<meta name="keywords" content="imap, transfert, migration"/> <meta name="keywords" content="imap, transfert, migration"/>
<meta name="description" content="imap migration tool"/> <meta name="description" content="imap migration tool"/>
@ -55,7 +55,7 @@ Or offer him a book on his
(<!--#flastmod file="imapsync" -->) (<!--#flastmod file="imapsync" -->)
</a></h2> </a></h2>
<h2><a href="dist/?C=M;O=D">imapsync download</a></h2> <h2><a href="dist/?M=D">imapsync download</a></h2>
<h2><a href="INSTALL">imapsync installation</a></h2> <h2><a href="INSTALL">imapsync installation</a></h2>

View file

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# $Id: tests.sh,v 1.104 2010/07/09 03:06:44 gilles Exp gilles $ # $Id: tests.sh,v 1.105 2010/07/12 00:14:00 gilles Exp gilles $
# Example: # Example:
# CMD_PERL='perl -I./Mail-IMAPClient-3.14/lib' sh -x tests.sh # CMD_PERL='perl -I./Mail-IMAPClient-3.14/lib' sh -x tests.sh
@ -157,6 +157,14 @@ locallocal() {
--allow3xx --allow3xx
} }
ll_pidfile() {
$CMD_PERL ./imapsync \
--justbanner \
--pidfile /var/tmp/imapsync.pid
! test -f /var/tmp/imapsync.pid
}
ll_ask_password() { ll_ask_password() {
@ -168,14 +176,15 @@ ll_ask_password() {
--justlogin --justlogin
} }
ll_timeout() { ll_timeout() {
$CMD_PERL ./imapsync \ $CMD_PERL ./imapsync \
--host1 $HOST1 --user1 tata \ --host1 $HOST1 --user1 tata \
--passfile1 ../../var/pass/secret.tata \ --passfile1 ../../var/pass/secret.tata \
--host2 $HOST2 --user2 titi \ --host2 $HOST2 --user2 titi \
--passfile2 ../../var/pass/secret.titi \ --passfile2 ../../var/pass/secret.titi \
--folder INBOX --timeout 1 \ --folder INBOX --timeout 1
--allow3xx
} }
@ -368,8 +377,15 @@ ll_dev_reconnect()
{ {
# in another terminal: # in another terminal:
# #
# while :; do killall -u vmail imapd; sleepenh 3; done : <<'EOF'
# while :; do
killall -u vmail imapd;
RAND_WAIT=`numrandom .1..5i.1`
echo sleeping $RAND_WAIT
sleepenh $RAND_WAIT
done
EOF
$CMD_PERL ./imapsync \ $CMD_PERL ./imapsync \
--host1 $HOST1 --user1 tata \ --host1 $HOST1 --user1 tata \
--passfile1 ../../var/pass/secret.tata \ --passfile1 ../../var/pass/secret.tata \
@ -1288,6 +1304,7 @@ test $# -eq 0 && run_tests \
first_sync_dry \ first_sync_dry \
first_sync \ first_sync \
locallocal \ locallocal \
ll_pidfile \
ll_ask_password \ ll_ask_password \
ll_bug_folder_name_with_blank \ ll_bug_folder_name_with_blank \
ll_timeout \ ll_timeout \