1
0
mirror of https://github.com/imapsync/imapsync.git synced 2024-11-16 15:52:47 +01:00
This commit is contained in:
Nick Bebout 2012-09-11 20:50:53 -05:00
parent c08a56e486
commit 1e03db551f
58 changed files with 790 additions and 435 deletions

View File

@ -1,17 +1,33 @@
RCS file: RCS/imapsync,v
Working file: imapsync
head: 1.504
head: 1.508
branch:
locks: strict
gilles: 1.504
gilles: 1.508
access list:
symbolic names:
keyword substitution: kv
total revisions: 504; selected revisions: 504
total revisions: 508; selected revisions: 508
description:
----------------------------
revision 1.504 locked by: gilles;
revision 1.508 locked by: gilles;
date: 2012/09/10 21:10:13; author: gilles; state: Exp; lines: +81 -17
Added ETA after each copy. Estimated Time of Arrival.
----------------------------
revision 1.507
date: 2012/09/09 12:57:44; author: gilles; state: Exp; lines: +20 -12
Bugfix. Previous fix about characters *|?:"<> in cache path was not complete.
----------------------------
revision 1.506
date: 2012/09/07 14:51:00; author: gilles; state: Exp; lines: +10 -7
Option. Added --noexpungeaftereach to speedup --delete --expunge from Gmail.
----------------------------
revision 1.505
date: 2012/09/07 10:40:55; author: gilles; state: Exp; lines: +10 -10
Usability. Added Host1 or Host2 before "Nb messages" "Total size" with --foldersiszes
----------------------------
revision 1.504
date: 2012/08/28 13:10:26; author: gilles; state: Exp; lines: +10 -9
Bugfix. sentsince sentbefore in int seconds.
----------------------------

22
FAQ
View File

@ -1,5 +1,5 @@
#!/bin/cat
# $Id: FAQ,v 1.114 2012/07/19 09:42:13 gilles Exp gilles $
# $Id: FAQ,v 1.116 2012/09/11 21:00:06 gilles Exp gilles $
+------------------+
| FAQ for imapsync |
@ -262,13 +262,13 @@ R. - Download latest Mail::IMAPClient 3.xx at
- run imapsync with perl and -I option tailing to use the perl
module Mail-IMAPClient-3.xx. Example:
perl -I./Mail-IMAPClient-3.31/lib ./imapsync ...
perl -I./Mail-IMAPClient-3.32/lib ./imapsync ...
or if imapsync is in directory /path/
perl -I./Mail-IMAPClient-3.31/lib /path/imapsync ...
perl -I./Mail-IMAPClient-3.32/lib /path/imapsync ...
- Look at the script named i3 in the tarball, it can be used to
run imapsync with included Mail-IMAPClient-3.31/ wherever you
run imapsync with included Mail-IMAPClient-3.32/ wherever you
unpacked the imapsync tarball
=======================================================================
@ -1369,16 +1369,17 @@ R. GroupWise 7 seems buggy. Apply GroupWise 7 support pack 1
=======================================================================
Q. Migrating from David Tobit V10
R. Use the following options :
imapsync ... --prefix1 "" --sep1 / --idatefromheader ^
--nofoldersizes --useuid
R. Use the following options:
=======================================================================
imapsync ... --prefix1 "" --sep1 / --idatefromheader ^
--nofoldersizes --useuid --nocheckmessageexists
=======================================================================
Q. Migrating from David Tobit V8
First try above V10 solution since improvments have been made
to support Tobit.
R. Use the following options :
imapsync ... --prefix1 INBOX. --sep1 / --subscribe --subscribed
@ -1386,6 +1387,9 @@ imapsync ... --prefix1 INBOX. --sep1 / --subscribe --subscribed
Q. Migrating from Tobit David Server 6
("DvISE Mail Access Server MA-6.60a (0118)")
First try above V10 solution since improvments have been made
to support Tobit.
R. Look at the discussion:
http://www.linux-france.org/prj/imapsync_list/msg00582.html
http://www.linux-france.org/prj/imapsync_list/threads.html#00582

30
INSTALL
View File

@ -1,4 +1,4 @@
# $Id: INSTALL,v 1.25 2012/07/19 05:57:14 gilles Exp gilles $
# $Id: INSTALL,v 1.26 2012/09/11 21:00:06 gilles Exp gilles $
#
# INSTALL file for imapsync
# imapsync : IMAP sync or copy tool.
@ -76,19 +76,20 @@ Here is some individual module help:
perl -mMail::IMAPClient -e 'print $Mail::IMAPClient::VERSION, "\n"'
New Mail-IMAPClient-3.xx works now very well with imapsync,
better than Mail-IMAPClient-2.2.9 with memory and other things,
at least with Mail-IMAPClient-3.25 (previous may bug).
Don't hesitate to use latest Mail-IMAPClient-3.xx
better than old Mail-IMAPClient-2.2.9, with memory and other things.
Use at least Mail-IMAPClient-3.25 (previous may bug).
Don't hesitate to use latest Mail-IMAPClient-3.xx (3.xx >= 3.32 at the time
of this writing)
Look at the script named i3 in the tarball, it can be used to
run imapsync with included Mail-IMAPClient-3.31/ wherever you
run imapsync with included Mail-IMAPClient-3.32/ wherever you
unpacked the imapsync tarball.
- Perl Digest::MD5 module.
try:
perl -mDigest::MD5
perl -mDigest::MD5 -e ""
http://search.cpan.org/
http://search.cpan.org/~gaas/Digest-MD5-2.52/
@ -97,27 +98,31 @@ Here is some individual module help:
I use 2.39 (Ubuntu package)
- Term::ReadKey
perl -mTerm::ReadKey -e ''
perl -mTerm::ReadKey -e ""
- IO::Socket::SSL
perl -mIO::Socket::SSL -e ''
perl -mIO::Socket::SSL -e ""
- File::Spec
perl -mFile::Spec -e ''
perl -mFile::Spec -e ""
- File::Path
perl -mFile::Path -e ''
perl -mFile::Path -e ""
- Perl Digest::HMAC_MD5 module
Good for non plain text password over network.
perl -mDigest::HMAC_MD5 -e ""
- Perl Authen::NTLM
perl -mAuthen::NTLM -e ''
perl -mAuthen::NTLM -e ""
- Perl Time::HiRes
perl -mTime::HiRes -e ""
Test everything in one command:
perl -mMail::IMAPClient -mDigest::MD5 -mTerm::ReadKey -mIO::Socket::SSL \
-mFile::Spec -mDigest::HMAC_MD5 -mAuthen::NTLM -e ''
-mFile::Spec -mDigest::HMAC_MD5 -mAuthen::NTLM -e -mTime::HiRes ''
You can install easily those Perl modules in latest release via the
following commands (with root permissions)
@ -129,6 +134,7 @@ following commands (with root permissions)
perl -MCPAN -e 'install File::Spec'
perl -MCPAN -e 'install Digest::HMAC_MD5'
perl -MCPAN -e 'install Authen::NTLM'
perl -MCPAN -e 'install Time::HiRes'
You can install them easily too by using the standard install
command on your system if the packages have been made on it

View File

@ -1,5 +1,5 @@
# $Id: Makefile,v 1.103 2012/08/29 10:24:17 gilles Exp gilles $
# $Id: Makefile,v 1.107 2012/09/11 21:00:06 gilles Exp gilles $
.PHONY: help usage all
@ -32,7 +32,7 @@ VERSION_EXE=$(shell cat ./VERSION_EXE)
HELLO=$(shell date;uname -a)
IMAPClient_2xx=./W/Mail-IMAPClient-2.2.9
IMAPClient_3xx=./W/Mail-IMAPClient-3.31/lib
IMAPClient_3xx=./W/Mail-IMAPClient-3.32/lib
IMAPClient=$(IMAPClient_3xx)
hello:
@ -264,20 +264,24 @@ ksa:
rsync -avHz --delete \
. imapsync@ks.lamiral.info:public_html/imapsync/
publish: upload_ks ks
publish: upload_ks ks ml
PUBLIC_FILES = ./ChangeLog ./COPYING ./CREDITS ./FAQ \
./index.shtml ./INSTALL \
./VERSION ./VERSION_EXE \
./README ./TODO
PUBLIC_FILES_W = ./W/style.css \
./TIME \
./VERSION ./VERSION_EXE \
./W/TIME \
./W/paypal.shtml ./W/paypal_return.shtml ./W/paypal_return_support.shtml
PUBLIC_FILES_IMAGES = ./W/images/logo_imapsync.png ./W/images/logo_imapsync_s.png
ml:
m4 -P W/ml_announce.in | mutt -H-
mailq
upload_ks: ci
rsync -lptvHzP $(PUBLIC_FILES) \
@ -303,13 +307,10 @@ upload_lfo:
/home/gilles/public_html/www.linux-france.org/html/prj/imapsync/.htaccess
sh ~/memo/lfo-rsync
upload_index: index.shtml FAQ paypal.shtml
validate --verbose index.shtml paypal.shtml
rcsdiff index.shtml paypal.shtml FAQ COPYING
rsync -avH index.shtml FAQ paypal.shtml COPYING root@ks.lamiral.info:/var/www/imapsync/
rsync -avH index.shtml FAQ paypal.shtml COPYING \
../../public_html/www.linux-france.org/html/prj/imapsync/
sh $(HOME)/memo/lfo-rsync
upload_index: index.shtml FAQ
validate --verbose index.shtml
rcsdiff index.shtml FAQ COPYING
rsync -avH index.shtml FAQ COPYING root@ks.lamiral.info:/var/www/imapsync/
niouze_lfo :
echo "CORRECT ME: . ./memo && lfo_announce"

4
README
View File

@ -3,7 +3,7 @@ NAME
Synchronise mailboxes between two imap servers. Good at IMAP migration.
More than 44 different IMAP server softwares supported with success.
$Revision: 1.504 $
$Revision: 1.508 $
SYNOPSIS
To synchronise imap account "foo" on "imap.truc.org" to imap account
@ -440,5 +440,5 @@ SIMILAR SOFTWARES
Feedback (good or bad) will often be welcome.
$Id: imapsync,v 1.504 2012/08/28 13:10:26 gilles Exp gilles $
$Id: imapsync,v 1.508 2012/09/10 21:10:13 gilles Exp gilles $

54
TODO
View File

@ -1,5 +1,5 @@
#!/bin/cat
# $Id: TODO,v 1.112 2012/07/19 09:41:54 gilles Exp gilles $
# $Id: TODO,v 1.113 2012/09/11 20:58:32 gilles Exp gilles $
TODO file for imapsync
----------------------
@ -31,14 +31,7 @@ Add a FAQ entry about long path over than 260 character on Win32.
Fix long path over than 260 character on Win32.
Think about Digest::SHA or Digest::SHA::PurePerl.
Try to use imapsync with cygwin.
Add an option to solve syncing Sent folder when no good header
are available:
http://www.linux-france.org/prj/imapsync_list/msg01151.html
http://www.linux-france.org/prj/imapsync_list/msg01158.html
Think about a file database like DBM instead.
Find a way to avoid passwords in --debugimap unless needed.
@ -101,19 +94,6 @@ Fix bug "not possible to use space in the imap password"
Add kerberos authentification
Add a --skipheaderinfolder option
Fix this:
> - Erreur avec la traditionnelle différence entre Windows
> et Linux sur les retour-chariots : le calcul de la
> longueur du message ou des entêtes à envoyer au serveur
> cible n'est pas bon sur une machine Windows.
> Ci-dessous la modif :
>
> # No NL Count on Windows my $length = ( -s $file ) + $bare_nl_count;
> my $length = ( -s $file );
I wonder if it is Windows or the imap server used.
Add stdin/stdout filter before transfer:
"Now i asked me, how to modify your perl program to work with
@ -152,9 +132,6 @@ Add --verbose from Kjetil jumbo patch.
Read the IMAP RFC http://www.faqs.org/rfcs/rfc3501.html
Add debian packaging in the Makefile.
Write to the debian maintener about that.
Interface with external software like procmail
Read:
@ -165,6 +142,33 @@ http://asg.web.cmu.edu/cyrus/download/imapd/altnamespace.html
===========================================================================
DONE. Not donse since useless now (--useuid)
Add a --skipheaderinfolder option
DONE. Not fixed since only reported once a long time ago.
Fix this:
> - Erreur avec la traditionnelle différence entre Windows
> et Linux sur les retour-chariots : le calcul de la
> longueur du message ou des entêtes à envoyer au serveur
> cible n'est pas bon sur une machine Windows.
> Ci-dessous la modif :
>
> # No NL Count on Windows my $length = ( -s $file ) + $bare_nl_count;
> my $length = ( -s $file );
I wonder if it is Windows or the imap server used.
DONE. No Debian package anymore.
Add debian packaging in the Makefile.
Write to the debian maintener about that.
DONE with --addheader
Add an option to solve syncing Sent folder when no good header
are available:
http://www.linux-france.org/prj/imapsync_list/msg01151.html
http://www.linux-france.org/prj/imapsync_list/msg01158.html
DONE. Add a note about
"One other thing: You might want to warn idiots like me, that if your
cache resides on a filesystem with a limited number of inodes such as

View File

@ -1 +1 @@
1.504
1.508

View File

@ -1 +1 @@
1.504
1.508

View File

@ -152,3 +152,7 @@
1346160945 END 1.504 : mardi 28 août 2012, 15:35:45 (UTC+0200)
1346241775 BEGIN 1.504 : mercredi 29 août 2012, 14:02:55 (UTC+0200)
1346242932 END 1.504 : mercredi 29 août 2012, 14:22:12 (UTC+0200)
1347195553 BEGIN 1.507 : dimanche 9 septembre 2012, 14:59:13 (UTC+0200)
1347196697 END 1.507 : dimanche 9 septembre 2012, 15:18:17 (UTC+0200)
1347392501 BEGIN 1.508 : mardi 11 septembre 2012, 21:41:41 (UTC+0200)
1347393591 END 1.508 : mardi 11 septembre 2012, 21:59:51 (UTC+0200)

View File

@ -5,6 +5,27 @@ Changes from 2.99_01 to 3.16 made by Mark Overmeer
Changes from 0.09 to 2.99_01 made by David Kernen
- Potential compatibility issues from 3.17+ highlighted with '*'
version 3.32: Fri, Aug 10, 2012 4:43:24 PM
- document RFC2087 quota related calls
[Mathias Reitinger] documentation request
- rt.cpan.org#78474: idle/idle_data documentation error
[Dima Kogan]
- Quote()/Massage() now uses literals for non ascii data
[Mathias Reitinger] reported issues with utf8 data in password
- use Quote()/Massage() consistently now in:
login() proxyauth() deleteacl() setacl() listrights() rename()
- documented deleteacl() and other minor pod cleanup
- ran Mail::IMAPClient::BodyStructure through perltidy
- update year in README/pod to 2012
- rt.cpan.org#74733: Fails with Parse::RecDescent >= 1.966_002
rt.cpan.org#74593: Recent changes break Module::ExtractUse and ...
[ANDK, TEAM, SREZIC, NBEBOUT at CPAN and nine from detonation]
- Makefile.PL avoid buggy Parse::RecDescent 1.966_002 until 1.967_009
- rt.cpan.org#76989: Mail::IMAPClient::BodyStructure usage/docs
[Pierluigi Frullani]
- fix incorrect documentation on new()
- lots of doc verbiage updates
version 3.31: Mon, Mar 19, 2012 11:11:11 AM
- rt.cpan.org#74799: Support for partial data responses in fetch_hash
[Philip Garrett]

View File

@ -1,6 +1,6 @@
--- #YAML:1.0
name: Mail-IMAPClient
version: 3.31
version: 3.32
abstract: IMAP4 client library
author:
- Phil Pearl (Lobbes) <phil@zimbra.com>
@ -28,7 +28,7 @@ no_index:
directory:
- t
- inc
generated_by: ExtUtils::MakeMaker version 6.55_02
generated_by: ExtUtils::MakeMaker version 6.57_05
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: 1.4

View File

@ -37,6 +37,22 @@ MSG
sleep 3;
}
# HACK: die on broken Parse::RecDescent 1.966002 through 1.967009
# - rt.cpan.org#74593: Recent changes break Module::ExtractUse and ...
# - rt.cpan.org#74733: Fails with Parse::RecDescent >= 1.966_002
do {
eval { require version; require Parse::RecDescent; };
unless ($@) {
my $found = version->parse( Parse::RecDescent->VERSION() );
my $broke = version->parse("1.966002");
my $fixed = version->parse("1.967009");
if ( $found < $fixed and $found >= $broke ) {
die("Found broken Parse::RecDescent $found in your environment.\n",
"Please upgrade to version $fixed or greater.\n");
}
}
};
WriteMakefile(
NAME => 'Mail::IMAPClient',
AUTHOR => 'Phil Pearl (Lobbes) <phil@zimbra.com>',

View File

@ -64,7 +64,7 @@ COPYRIGHT AND LICENSE
=====================
Copyright (C) 1999-2003 The Kernen Group, Inc.
Copyright (C) 2007-2009 Mark Overmeer
Copyright (C) 2010-2011 Phil Pearl (Lobbes)
Copyright (C) 2010-2012 Phil Pearl (Lobbes)
All rights reserved.
This library is free software; you can redistribute it and/or modify

View File

@ -7,7 +7,7 @@ use strict;
use warnings;
package Mail::IMAPClient;
our $VERSION = '3.31';
our $VERSION = '3.32';
use Mail::IMAPClient::MessageSet;
@ -546,20 +546,15 @@ sub login {
or return undef;
}
else {
my $user = $self->User;
my $passwd = $self->Password;
my $id = $self->User;
return undef unless ( defined($passwd) and defined($id) );
return undef unless ( defined($passwd) and defined($user) );
# BUG: should use Quote() with $passwd and $id
if ( $passwd eq "" or $passwd =~ m/\W/ ) {
$passwd =~ s/(["\\])/\\$1/g;
$passwd = qq("$passwd");
}
$user = ( $user eq "" ) ? qq("") : $self->Quote($user);
$passwd = ( $passwd eq "" ) ? qq("") : $self->Quote($passwd);
$id = qq("$id") if $id !~ /^".*"$/;
$self->_imap_command("LOGIN $id $passwd")
$self->_imap_command("LOGIN $user $passwd")
or return undef;
}
@ -577,6 +572,7 @@ sub noop {
sub proxyauth {
my ( $self, $user ) = @_;
$user = ( $user eq "" ) ? qq("") : $self->Quote($user);
$self->_imap_command("PROXYAUTH $user") ? $self->Results : undef;
}
@ -741,33 +737,27 @@ sub subscribed {
return wantarray ? @folders : \@folders;
}
# BUG? cleanup escaping/quoting
sub deleteacl {
my ( $self, $target, $user ) = @_;
$target = $self->Massage($target);
$user =~ s/^"(.*)"$/$1/;
$user =~ s/"/\\"/g;
$user = ( $user eq "" ) ? qq("") : $self->Quote($user);
$self->_imap_command(qq(DELETEACL $target "$user"))
$self->_imap_command(qq(DELETEACL $target $user))
or return undef;
return wantarray ? $self->History : $self->Results;
}
# BUG? cleanup escaping/quoting
sub setacl {
my ( $self, $target, $user, $acl ) = @_;
$target ||= $self->Folder;
$target = $self->Massage($target);
$user ||= $self->User;
$user =~ s/^"(.*)"$/$1/;
$user =~ s/"/\\"/g;
$user = ( $user eq "" ) ? qq("") : $self->Quote($user);
$acl = ( $acl eq "" ) ? qq("") : $self->Quote($acl);
$acl =~ s/^"(.*)"$/$1/;
$acl =~ s/"/\\"/g;
$self->_imap_command(qq(SETACL $target "$user" "$acl"))
$self->_imap_command(qq(SETACL $target $user $acl))
or return undef;
return wantarray ? $self->History : $self->Results;
@ -809,10 +799,9 @@ sub listrights {
$target = $self->Massage($target);
$user ||= $self->User;
$user =~ s/^"(.*)"$/$1/;
$user =~ s/"/\\"/g;
$user = ( $user eq "" ) ? qq("") : $self->Quote($user);
$self->_imap_command(qq(LISTRIGHTS $target "$user"))
$self->_imap_command(qq(LISTRIGHTS $target $user))
or return undef;
my $resp = first { /^\* LISTRIGHTS/ } $self->History;
@ -2352,21 +2341,13 @@ sub uidexpunge {
return wantarray ? $self->History : $self->Results;
}
# BUG? cleanup escaping/quoting
sub rename {
my ( $self, $from, $to ) = @_;
if ( $from =~ /^"(.*)"$/ ) {
$from = $1 unless $self->exists($from);
$from =~ s/"/\\"/g;
}
$from = ( $from eq "" ) ? qq("") : $self->Massage($from);
$to = ( $to eq "" ) ? qq("") : $self->Massage($to);
if ( $to =~ /^"(.*)"$/ ) {
$to = $1 unless $self->exists($from) && $from =~ /^".*"$/;
$to =~ s/"/\\"/g;
}
$self->_imap_command(qq(RENAME "$from" "$to")) ? $self : undef;
$self->_imap_command(qq(RENAME $from $to)) ? $self : undef;
}
sub status {
@ -3352,37 +3333,38 @@ sub getquotaroot {
return $self->_imap_command("GETQUOTAROOT $who") ? $self->Results : undef;
}
# BUG? using user/$User here and INBOX in quota/quota_usage
sub getquota {
my ( $self, $what ) = @_;
my $who = $what ? $self->Massage($what) : "user/$self->{User}";
my $who = $what ? $self->Massage($what) : "user/" . $self->User;
return $self->_imap_command("GETQUOTA $who") ? $self->Results : undef;
}
# usage: $self->setquota($folder, storage => 512)
# usage: $self->setquota($quotaroot, storage => 512, ...)
sub setquota(@) {
my ( $self, $what ) = ( shift, shift );
my $who = $what ? $self->Massage($what) : "user/$self->{User}";
my $who = $what ? $self->Massage($what) : "user/" . $self->User;
my @limits;
while (@_) {
my $key = uc shift @_;
push @limits, $key => shift @_;
my ( $k, $v ) = ( $self->Quote( uc( shift @_ ) ), shift @_ );
push( @limits, "($k $v)" );
}
local $" = ' ';
$self->_imap_command("SETQUOTA $who (@limits)") ? $self->Results : undef;
my $limits = join( ' ', @limits );
$self->_imap_command("SETQUOTA $who $limits") ? $self->Results : undef;
}
sub quota {
my $self = shift;
my $what = shift || "INBOX";
$self->_imap_command("GETQUOTA $what") or $self->getquotaroot($what);
( map { /.*STORAGE\s+\d+\s+(\d+).*\n$/ ? $1 : () } $self->Results )[0];
my ( $self, $what ) = ( shift, shift || "INBOX" );
my $tref = $self->getquota($what) or return undef;
shift @$tref; # pop off command
return ( map { /.*STORAGE\s+\d+\s+(\d+).*\n$/ ? $1 : () } @$tref )[0];
}
sub quota_usage {
my $self = shift;
my $what = shift || "INBOX";
$self->_imap_command("GETQUOTA $what") || $self->getquotaroot($what);
( map { /.*STORAGE\s+(\d+)\s+\d+.*\n$/ ? $1 : () } $self->Results )[0];
my ( $self, $what ) = ( shift, shift || "INBOX" );
my $tref = $self->getquota($what) or return undef;
shift @$tref; # pop off command
return ( map { /.*STORAGE\s+(\d+)\s+\d+.*\n$/ ? $1 : () } @$tref )[0];
}
sub Quote($) { $_[0]->Massage( $_[1], NonFolderArg ) }
@ -3395,15 +3377,16 @@ sub Quote($) { $_[0]->Massage( $_[1], NonFolderArg ) }
# resp-specials = "]"
# rfc2060:
# CTL ::= <any ASCII control character and DEL, 0x00 - 0x1f, 0x7f>
# Additionally, we encode strings with } and [, be less than minimal
# Paranoia/safety:
# encode strings with "}" / "[" / "]" / non-ascii chars
sub Massage($;$) {
my ( $self, $name, $notFolder ) = @_;
$name =~ s/^\"(.*)\"$/$1/ unless $notFolder;
$name =~ s/^\"(.*)\"$/$1/s unless $notFolder;
if ( $name =~ /["\\]/ ) {
if ( $name =~ /["\\[:^ascii:][:cntrl:]]/s ) {
return "{" . length($name) . "}" . $CRLF . $name;
}
elsif ( $name =~ /[(){}\s[:cntrl:]%*\[\]]/ ) {
elsif ( $name =~ /[(){}\s%*\[\]]/s ) {
return qq("$name");
}
else {

View File

@ -1,11 +1,11 @@
=head1 NAME
=head1 NAME
Mail::IMAPClient - An IMAP Client API
=head1 SYNOPSIS
use Mail::IMAPClient;
my $imap = Mail::IMAPClient->new(
Server => 'localhost',
User => 'username',
@ -230,7 +230,7 @@ Example:
The B<Quote> method accepts a value as an argument and returns its
argument as a correctly quoted string or a literal string. Since
version 3.17 Mail::IMAPClient automatically quotes search arguments we
use a SCALARREF so search will not modify or re-quite the valaue
use a SCALARREF so search will not modify or re-quote the value
returned by B<Quote>.
Note this method should not be used on folder names for
@ -783,6 +783,18 @@ The B<delete> method accepts a single argument, the name of a folder
to delete. It returns a true value on success and C<undef> on
failure.
=head2 deleteacl
Example:
$imap->deleteacl( $folder, $userid )
or die "Could not delete acl: $@\n";
The B<deleteacl> method accepts two input arguments, a folder name, a
user id (or authentication identifier, to use the terminology of
RFC2086). See RFC2086 for more information. (This is somewhat
experimental and its implementation may change.)
=head2 delete_message
Example:
@ -795,7 +807,7 @@ The above could also be rewritten like this:
# scalar context returns array ref
my $msgs = scalar($imap->seen);
scalar(@$msgs) and $imap->delete_message($msgs)
or die "Could not delete_message: $@\n";
@ -945,7 +957,7 @@ server will likely respond with an error like I<* BAD Invalid tag>.
On failure <undef> is returned and L</LastError> is set.
See also L</idle>, L</imap_data> and L</Results>.
See also L</idle>, L</idle_data> and L</Results>.
=head2 examine
@ -1277,10 +1289,15 @@ has been terminated by calling L</done>. Failure to do so will result
in an error and the idle command will typically be terminated by the
server.
See also L</imap_data> and L</done>.
See also L</idle_data> and L</done>.
=head2 idle_data
Usage:
# an optional timeout in seconds may be specified
$imap->idle_data( [$timeout] )
Example:
my $tag = $imap->idle or warn "idle failed: $@\n";
@ -1292,12 +1309,12 @@ Example:
The B<idle_data> method can be used to accept any unsolicited mailbox
update messages that have been sent by the server during an L</idle>
command. This method does not send any commands to the server, it
simply waits for data from the server and returns that data to the
caller.
simply looks for and optionally waits for data from the server and
returns that data to the caller.
The B<idle> method accepts an optional $timeout argument and returns
an array (or an array reference if called in scalar context) with the
messages from the server.
The B<idle_data> method accepts an optional $timeout argument and
returns an array (or an array reference if called in scalar context)
with the messages from the server.
By default a timeout of 0 seconds is used (do not block). Internally
the timeout is passed to L<perlfunc/select>. The timeout controls how
@ -1399,6 +1416,87 @@ The B<get_header> method is a short-cut for:
my $messageId = $imap->parse_headers($msg,"Subject")->{"Subject"}[0];
=head2 getquotaroot
Example:
my $results = $imap->getquotaroot($mailboxname)
or die "Could not getquotaroot for $mailboxname: $@\n";
The B<getquotaroot> method implements the RFC2087 GETQUOTAROOT
command. The "$mailboxname" defaults to "INBOX" if no argument is
provided.
On error C<undef> is returned, otherwise L</Results> are returned.
The results should have the untagged QUOTAROOT response from the
server along with the QUOTAROOT's resource usage and limits in an
untagged QUOTA response.
See also B<RFC2087>, L</getquota>, L</setquota>, L</quota> and L</quota_usage>.
=head2 getquota
Example:
my $results = $imap->getquota($quotaroot)
or die "Could not getquota for $quotaroot: $@\n";
The B<getquota> method implements the RFC2087 GETQUOTA command. The
"$quotaroot" defaults to "user/I<User>" if no argument is provided.
On error C<undef> is returned, otherwise L</Results> are returned.
The results from the server should have the untagged QUOTA response
from the server.
See also B<RFC2087>, L</getquotaroot>, L</quota> and L</quota_usage>.
=head2 quota
Example:
my $limit = $imap->quota($quotaroot)
or die "Could not get quota limit for $quotaroot: $@\n";
The B<quota> method takes the L</Results> from L<getquota> and parses
out the "STORAGE" limit returned by the server. The "$quotaroot"
defaults to "INBOX" if no argument is provided.
On error C<undef> is returned, otherwise the integer "STORAGE" limit
provided by the server is returned.
See also B<RFC2087>, L</getquotaroot>, L</getquota> and L</quota_usage>.
=head2 quota_usage
Example:
my $usage = $imap->quota_usage($quotaroot)
or die "Could not get quota usage for $quotaroot: $@\n";
The B<quota_usage> method takes the L</Results> from L<getquota> and
parses out the "STORAGE" usage returned by the server. The
"$quotaroot" defaults to "INBOX" if no argument is provided.
On error C<undef> is returned, otherwise the integer "STORAGE" usage
provided by the server is returned.
See also B<RFC2087>, L</getquotaroot>, L</getquota> and L</quota>.
=head2 setquota
Example:
my $results = $imap->setquota( $quotaroot, $resource, $limit )
or die "Could not setquota for $quotaroot: $@\n";
The B<setquota> method implements the RFC2087 SETQUOTA command. It
accepts multiple pairs of $resource and $limit arguments. The
"$quotaroot" defaults to "user/I<User>" if not defined.
On error C<undef> is returned, otherwise L</Results> are returned.
See also B<RFC2087>, L</getquotaroot> and L</getquota>.
=head2 is_parent
Example:
@ -1477,7 +1575,8 @@ and $@ is set. The methods L</new>, L</connect>, and L</Socket> may
automatically invoke B<login> see the documentation of each method for
details.
If the L</Compress> parameter is set, the L</compress> method will automatically be called after successful authentication.
If the L</Compress> parameter is set, the L</compress> method will
automatically be called after successful authentication.
See also L</proxyauth> and L</Proxy> for additional information
regarding ways of authenticating with a server via SASL and/or
@ -2275,7 +2374,7 @@ contain both subfolders and mail messages; other servers allow this.)
Example:
$imap->set_flag("Seen",@msgs)
$imap->set_flag( "Seen", @msgs )
or die "Could not set flag: $@\n";
The B<set_flag> method accepts the name of a flag as its first
@ -2298,7 +2397,7 @@ which is why you don't have to worry about it overly much.)
Example:
$imap->setacl($folder,$userid,$authstring)
$imap->setacl( $folder, $userid, $aclstring )
or die "Could not set acl: $@\n";
The B<setacl> method accepts three input arguments, a folder name, a
@ -2429,7 +2528,7 @@ Version note: method added in Mail::IMAPClient 3.22
Example:
my @rawdata = $imap->status($folder,qw/(Messages)/)
my @rawdata = $imap->status( $folder, qw/(Messages)/ )
or die "Error obtaining status: $@\n";
The B<status> method accepts one argument, the name of a folder (or
@ -2646,7 +2745,7 @@ messages in the currently selected Folder.
Example:
$imap->unset_flag("\Seen",@msgs)
$imap->unset_flag( "\Seen", @msgs )
or die "Could not unset_flag: $@\n";
The B<unset_flag> method accepts the name of a flag as its first
@ -2723,9 +2822,9 @@ obtain the current value of the parameter as follows:
my $imap = Mail::IMAPClient->new;
$imap->parameter( "value");
$imap->parameter2("value");
... # A whole bunch of awesome Perl code, omitted for brevity
my $forgot = $imap->parameter;
my $forgot2 = $imap->parameter2;
@ -3740,7 +3839,7 @@ exchange. After the L</authenticate> method sends "<tag> AUTHENTICATE
challenge. The L</authenticate> method then invokes the code whose
reference is stored in the B<Authcallback> parameter as follows:
$Authcallback->($challenge, $imap)
$Authcallback->( $challenge, $imap )
where C<$Authcallback> is the code reference stored in the
B<Authcallback> parameter, C<$challenge> is the challenge received
@ -3771,7 +3870,7 @@ http://rt.cpan.org/Public/Dist/Display.html?Name=Mail-IMAPClient
Copyright (C) 1999-2003 The Kernen Group, Inc.
Copyright (C) 2007-2009 Mark Overmeer
Copyright (C) 2010-2011 Phil Pearl (Lobbes)
Copyright (C) 2010-2012 Phil Pearl (Lobbes)
All rights reserved.
This library is free software; you can redistribute it and/or modify

View File

@ -9,94 +9,98 @@ my $HEAD = "HEAD";
# my has file scope, not limited to package!
my $parser = Mail::IMAPClient::BodyStructure::Parse->new
or die "Cannot parse rules: $@\n"
. "Try remaking Mail::IMAPClient::BodyStructure::Parse.\n";
or die "Cannot parse rules: $@\n"
. "Try remaking Mail::IMAPClient::BodyStructure::Parse.\n";
sub new
{ my $class = shift;
sub new {
my $class = shift;
my $bodystructure = shift;
my $self = $parser->start($bodystructure)
or return undef;
my $self = $parser->start($bodystructure)
or return undef;
$self->{_prefix} = "";
$self->{_id} = exists $self->{bodystructure} ? $HEAD : 1;
$self->{_top} = 1;
bless $self, ref($class)||$class;
bless $self, ref($class) || $class;
}
sub _get_thingy
{ my $thingy = shift;
my $object = shift || (ref $thingy ? $thingy : undef);
sub _get_thingy {
my $thingy = shift;
my $object = shift || ( ref $thingy ? $thingy : undef );
unless ($object && ref $object)
{ warn $@ = "No argument passed to $thingy method.";
unless ( $object && ref $object ) {
warn $@ = "No argument passed to $thingy method.";
return undef;
}
unless(UNIVERSAL::isa($object, 'HASH') && exists $object->{$thingy})
{ my $a = $thingy =~ /^[aeiou]/i ? 'an' : 'a';
my $has = ref $object eq 'HASH' ? join(", ",keys %$object) : '';
warn $@ = ref($object)." $object does not have $a $thingy. "
. ($has ? "It has $has" : '');
unless ( UNIVERSAL::isa( $object, 'HASH' ) && exists $object->{$thingy} ) {
my $a = $thingy =~ /^[aeiou]/i ? 'an' : 'a';
my $has = ref $object eq 'HASH' ? join( ", ", keys %$object ) : '';
warn $@ =
ref($object)
. " $object does not have $a $thingy. "
. ( $has ? "It has $has" : '' );
return undef;
}
my $value = $object->{$thingy};
$value =~ s/\\ ( [\\\(\)"\x0d\x0a] )/$1/gx;
$value =~ s/^"(.*)"$/$1/;
$value =~ s/\\ ( [\\\(\)"\x0d\x0a] )/$1/gx;
$value =~ s/^"(.*)"$/$1/;
$value;
}
BEGIN
{ no strict 'refs';
BEGIN {
no strict 'refs';
foreach my $datum (
qw/ bodytype bodysubtype bodyparms bodydisp bodyid bodydesc bodyenc
bodysize bodylang envelopestruct textlines / )
{ *$datum = sub { _get_thingy($datum, @_) };
qw/ bodytype bodysubtype bodyparms bodydisp bodyid bodydesc bodyenc
bodysize bodylang envelopestruct textlines /
)
{
*$datum = sub { _get_thingy( $datum, @_ ) };
}
}
sub parts
{ my $self = shift;
return wantarray ? @{$self->{PartsList}} : $self->{PartsList}
if exists $self->{PartsList};
sub parts {
my $self = shift;
return wantarray ? @{ $self->{PartsList} } : $self->{PartsList}
if exists $self->{PartsList};
my @parts;
$self->{PartsList} = \@parts;
# BUG?: should this default to ($HEAD, TEXT)
unless(exists $self->{bodystructure})
{ $self->{PartsIndex}{1} = $self;
@parts = ($HEAD, 1);
unless ( exists $self->{bodystructure} ) {
$self->{PartsIndex}{1} = $self;
@parts = ( $HEAD, 1 );
return wantarray ? @parts : \@parts;
}
foreach my $p ($self->bodystructure)
{ my $id = $p->id;
foreach my $p ( $self->bodystructure ) {
my $id = $p->id;
push @parts, $id;
$self->{PartsIndex}{$id} = $p ;
$self->{PartsIndex}{$id} = $p;
my $type = uc $p->bodytype || '';
push @parts, "$id.$HEAD"
if $type eq 'MESSAGE';
if $type eq 'MESSAGE';
}
wantarray ? @parts : \@parts;
}
sub bodystructure
{ my $self = shift;
sub bodystructure {
my $self = shift;
my $partno = 0;
my @parts;
if($self->{_top})
{ $self->{_id} ||= $HEAD;
if ( $self->{_top} ) {
$self->{_id} ||= $HEAD;
$self->{_prefix} ||= $HEAD;
$partno = 0;
foreach my $b ( @{$self->{bodystructure}} )
{ $b->{_id} = ++$partno;
foreach my $b ( @{ $self->{bodystructure} } ) {
$b->{_id} = ++$partno;
$b->{_prefix} = $partno;
push @parts, $b, $b->bodystructure;
}
@ -104,10 +108,10 @@ sub bodystructure
}
my $prefix = $self->{_prefix} || "";
$prefix =~ s/\.?$/./;
$prefix =~ s/\.?$/./;
foreach my $p ( @{$self->{bodystructure}} )
{ $partno++;
foreach my $p ( @{ $self->{bodystructure} } ) {
$partno++;
# BUG?: old code didn't add .TEXT sections, should we skip these?
# - This code needs to be generalised (maybe it belongs in parts()?)
@ -119,14 +123,14 @@ sub bodystructure
my $ptype = $p->{bodytype} || "";
# a message and the multipart inside of it "collapse together"
if ($partno == 1 and $stype eq 'MESSAGE' and $ptype eq 'MULTIPART') {
if ( $partno == 1 and $stype eq 'MESSAGE' and $ptype eq 'MULTIPART' ) {
$pno = "TEXT";
$p->{_prefix} = "$prefix";
}
else {
$p->{_prefix} = "$prefix$partno";
}
$p->{_id} ||= "$prefix$pno";
$p->{_id} ||= "$prefix$pno";
push @parts, $p, $p->{bodystructure} ? $p->bodystructure : ();
}
@ -134,22 +138,22 @@ sub bodystructure
wantarray ? @parts : \@parts;
}
sub id
{ my $self = shift;
sub id {
my $self = shift;
return $self->{_id}
if exists $self->{_id};
if exists $self->{_id};
return $HEAD
if $self->{_top};
if $self->{_top};
# BUG?: can this be removed? ... seems wrong
if ($self->{bodytype} eq 'MULTIPART')
{ my $p = $self->{_id} || $self->{_prefix};
if ( $self->{bodytype} eq 'MULTIPART' ) {
my $p = $self->{_id} || $self->{_prefix};
$p =~ s/\.$//;
return $p;
}
else
{ return $self->{_id} ||= 1;
else {
return $self->{_id} ||= 1;
}
}
@ -159,55 +163,57 @@ our @ISA = qw/Mail::IMAPClient::BodyStructure/;
package Mail::IMAPClient::BodyStructure::Envelope;
our @ISA = qw/Mail::IMAPClient::BodyStructure/;
sub new
{ my ($class, $envelope) = @_;
sub new {
my ( $class, $envelope ) = @_;
$parser->envelope($envelope);
}
sub parse_string
{ my ($class, $envelope) = @_;
sub parse_string {
my ( $class, $envelope ) = @_;
$envelope = "(" . $envelope . ")" unless ( $envelope =~ /^\(/ );
$parser->envelopestruct($envelope);
}
sub from_addresses { shift->_addresses(from => 1) }
sub sender_addresses { shift->_addresses(sender => 1) }
sub replyto_addresses { shift->_addresses(replyto => 1) }
sub to_addresses { shift->_addresses(to => 0) }
sub cc_addresses { shift->_addresses(cc => 0) }
sub bcc_addresses { shift->_addresses(bcc => 0) }
sub from_addresses { shift->_addresses( from => 1 ) }
sub sender_addresses { shift->_addresses( sender => 1 ) }
sub replyto_addresses { shift->_addresses( replyto => 1 ) }
sub to_addresses { shift->_addresses( to => 0 ) }
sub cc_addresses { shift->_addresses( cc => 0 ) }
sub bcc_addresses { shift->_addresses( bcc => 0 ) }
sub _addresses($$$)
{ my ($self, $name, $isSender) = @_;
sub _addresses($$$) {
my ( $self, $name, $isSender ) = @_;
ref $self->{$name} eq 'ARRAY'
or return ();
or return ();
my @list;
foreach ( @{$self->{$name}} )
{ my $pn = $_->personalname;
foreach ( @{ $self->{$name} } ) {
my $pn = $_->personalname;
my $name = $pn && $pn ne 'NIL' ? "$pn " : '';
push @list, $name . '<' . $_->mailboxname . '@' . $_->hostname . '>';
}
wantarray ? @list
: $isSender ? $list[0]
: \@list;
wantarray ? @list
: $isSender ? $list[0]
: \@list;
}
BEGIN
{ no strict 'refs';
for my $datum ( qw(subject inreplyto from messageid bcc date
replyto to sender cc))
{ *$datum = sub { @_ > 1 ? $_[0]->{$datum} = $_[1] : $_[0]->{$datum} }
BEGIN {
no strict 'refs';
for my $datum (
qw(subject inreplyto from messageid bcc date
replyto to sender cc)
)
{
*$datum = sub { @_ > 1 ? $_[0]->{$datum} = $_[1] : $_[0]->{$datum} }
}
}
package Mail::IMAPClient::BodyStructure::Address;
our @ISA = qw/Mail::IMAPClient::BodyStructure/;
for my $datum ( qw(personalname mailboxname hostname sourcename) )
{ no strict 'refs';
for my $datum (qw(personalname mailboxname hostname sourcename)) {
no strict 'refs';
*$datum = sub { shift->{$datum}; };
}
@ -221,38 +227,32 @@ Mail::IMAPClient::BodyStructure - parse fetched results
=head1 SYNOPSIS
use Mail::IMAPClient::BodyStructure;
use Mail::IMAPClient;
use Mail::IMAPClient::BodyStructure;
my $imap = Mail::IMAPClient->new(Server=>$serv,User=>$usr,Password=>$pwd);
$imap->select("INBOX") or die "cannot select the inbox for $usr: $@\n";
my $imap = Mail::IMAPClient->new(
Server => $server, User => $login, Password => $pass
);
my @recent = $imap->search("recent");
$imap->select("INBOX") or die "Could not select INBOX: $@\n";
foreach my $id (@recent)
{ my $fetched = $imap->fetch($id, "bodystructure");
my $struct = Mail::IMAPClient::BodyStructure->new($fetched);
my @recent = $imap->search("recent") or die "No recent msgs in INBOX\n";
my $mime = $struct->bodytype."/".$struct->bodysubtype;
my $parts =join "\n\t", $struct->parts;
print "Msg $id (Content-type: $mime) contains these parts:\n\t$parts\n";
foreach my $id (@recent) {
my $bsdat = $imap->fetch( $id, "bodystructure" );
my $bso = Mail::IMAPClient::BodyStructure->new($bsdat);
my $mime = $bso->bodytype . "/" . $bso->bodysubtype;
my $parts = map( "\n\t" . $_, $bso->parts );
print "Msg $id (Content-type: $mime) contains these parts:$parts\n";
}
=head1 DESCRIPTION
This extension will parse the result of an IMAP FETCH BODYSTRUCTURE
command into a perl data structure. It also provides helper methods that
will help you pull information out of the data structure.
command into a perl data structure. It also provides helper methods
to help pull information out of the data structure.
Use of this extension requires Parse::RecDescent. If you don't have
Parse::RecDescent then you must either get it or refrain from using
this module.
=head2 EXPORT
Nothing is exported by default. C<$parser> is exported upon
request. C<$parser> is the BodyStucture object's Parse::RecDescent object,
which you'll probably only need for debugging purposes.
This module requires Parse::RecDescent.
=head1 Class Methods
@ -261,21 +261,13 @@ The following class method is available:
=head2 new
This class method is the constructor method for instantiating new
Mail::IMAPClient::BodyStructure objects. The B<new> method accepts one
argument, a string containing a server response to a FETCH BODYSTRUCTURE
directive. Only one message's body structure should be described in this
string, although that message may contain an arbitrary number of parts.
Mail::IMAPClient::BodyStructure objects. The B<new> method accepts
one argument, a string containing a server response to a FETCH
BODYSTRUCTURE directive.
If you know the messages sequence number or unique ID (UID)
but haven't got its body structure, and you want to get the body
structure and parse it into a B<Mail::IMAPClient::BodyStructure>
object, then you might as well save yourself some work and use
B<Mail::IMAPClient>'s B<get_bodystructure> method, which accepts
a message sequence number (or UID if I<Uid> is true) and returns a
B<Mail::IMAPClient::BodyStructure> object. It's functionally equivalent
to issuing the FETCH BODYSTRUCTURE IMAP client command and then passing
the results to B<Mail::IMAPClient::BodyStructure>'s B<new> method but
it does those things in one simple method call.
The module B<Mail::IMAPClient> provides the B<get_bodystructure>
conveniece method to simplify use of this module when starting with
just a messages sequence number or unique ID (UID).
=head1 Object Methods
@ -344,10 +336,8 @@ calling B<Mail::IMAPClient::Bodystructure> object.
=head2 envelopestruct
The B<envelopestruct> object method requires no arguments. It returns
the envelopestruct for the message whose structure is described by the
calling B<Mail::IMAPClient::Bodystructure> object. This envelope structure
is blessed into the B<Mail::IMAPClient::BodyStructure::Envelope> subclass,
which is explained more fully below.
a B<Mail::IMAPClient::BodyStructure::Envelope> object for the message
from the calling B<Mail::IMAPClient::Bodystructure> object.
=head2 textlines
@ -355,37 +345,38 @@ The B<textlines> object method requires no arguments. It returns the
textlines for the message whose structure is described by the calling
B<Mail::IMAPClient::Bodystructure> object.
=head1 Envelopes and the Mail::IMAPClient::BodyStructure::Envelope Subclass
=head1 Mail::IMAPClient::BodyStructure::Envelope
The IMAP standard specifies that output from the IMAP B<FETCH
ENVELOPE> command will be an RFC2060 envelope structure. It further
ENVELOPE> command will be an RFC2060 envelope structure. It further
specifies that output from the B<FETCH BODYSTRUCTURE> command may also
contain embedded envelope structures (if, for example, a message's
subparts contain one or more included messages). Objects belonging to
subparts contain one or more included messages). Objects belonging to
B<Mail::IMAPClient::BodyStructure::Envelope> are Perl representations
of these envelope structures, which is to say the nested parenthetical
lists of RFC2060 translated into a Perl datastructure.
Note that all of the fields relate to the specific part to which they
belong. In other words, output from a FETCH nnnn ENVELOPE command (or,
in B<Mail::IMAPClient>, C<$imap->fetch($msgid,"ENVELOPE")> or C<my $env =
$imap->get_envelope($msgid)>) are for the message, but fields from within
a bodystructure relate to the message subpart and not the parent message.
belong. In other words, output from a FETCH nnnn ENVELOPE command
(or, in B<Mail::IMAPClient>, C<$imap->fetch($msgid,"ENVELOPE")> or
C<my $env = $imap->get_envelope($msgid)>) are for the message, but
fields from within a bodystructure relate to the message subpart and
not the parent message.
An envelope structure's B<Mail::IMAPClient::BodyStructure::Envelope>
representation is a hash of thingies that looks like this:
{
subject => "subject",
inreplyto => "reference_message_id",
from => [ addressStruct1 ],
messageid => "message_id",
bcc => [ addressStruct1, addressStruct2 ],
date => "Tue, 09 Jul 2002 14:15:53 -0400",
replyto => [ adressStruct1, addressStruct2 ],
to => [ adressStruct1, addressStruct2 ],
sender => [ adressStruct1 ],
cc => [ adressStruct1, addressStruct2 ],
subject => "subject",
inreplyto => "reference_message_id",
from => [ addressStruct1 ],
messageid => "message_id",
bcc => [ addressStruct1, addressStruct2 ],
date => "Tue, 09 Jul 2002 14:15:53 -0400",
replyto => [ adressStruct1, addressStruct2 ],
to => [ adressStruct1, addressStruct2 ],
sender => [ adressStruct1 ],
cc => [ adressStruct1, addressStruct2 ],
}
The B<...::Envelope> object also has methods for accessing data in the
@ -411,17 +402,17 @@ Returns the message id of the message.
=back
You can also use the following methods to get addressing
information. Each of these methods returns an array of
You can also use the following methods to get addressing information.
Each of these methods returns an array of
B<Mail::IMAPClient::BodyStructure::Address> objects, which are perl
data structures representing RFC2060 address structures. Some of these
arrays would naturally contain one element (such as B<from>, which
normally contains a single "From:" address); others will often contain
more than one address. However, because RFC2060 defines all of these as
"lists of address structures", they are all translated into arrays of
B<...::Address> objects.
data structures representing RFC2060 address structures. Some of
these arrays would naturally contain one element (such as B<from>,
which normally contains a single "From:" address); others will often
contain more than one address. However, because RFC2060 defines all
of these as "lists of address structures", they are all translated
into arrays of B<...::Address> objects.
See the section on B<Mail::IMAPClient::BodyStructure::Address>", below,
See the section on B<Mail::IMAPClient::BodyStructure::Address>, below,
for alternate (and preferred) ways of accessing these data.
The methods available are:
@ -430,9 +421,9 @@ The methods available are:
=item bcc
Returns an array of blind cc'ed recipients' address structures. (Don't
expect much in here unless the message was sent from the mailbox you're
poking around in, by the way.)
Returns an array of blind cc'ed recipients' address structures.
(Don't expect much in here unless the message was sent from the
mailbox you're poking around in, by the way.)
=item cc
@ -444,8 +435,8 @@ Returns an array of "From:" address structures--usually just one.
=item replyto
Returns an array of "Reply-to:" address structures. Once again there is
usually just one address in the list.
Returns an array of "Reply-to:" address structures. Once again there
is usually just one address in the list.
=item sender
@ -459,12 +450,12 @@ Returns an array of recipients' address structures.
=back
Each of the methods that returns a list of address structures (i.e. a
list of B<Mail::IMAPClient::BodyStructure::Address> arrays) also has an
analagous method that will return a list of E-Mail addresses instead. The
addresses are in the format C<personalname E<lt>mailboxname@hostnameE<gt>>
(see the section on B<Mail::IMAPClient::BodyStructure::Address>,
below) However, if the personal name is 'NIL' then it is omitted from
the address.
list of B<Mail::IMAPClient::BodyStructure::Address> arrays) also has
an analagous method that will return a list of E-Mail addresses
instead. The addresses are in the format C<personalname
E<lt>mailboxname@hostnameE<gt>> (see the section on
B<Mail::IMAPClient::BodyStructure::Address>, below) However, if the
personal name is 'NIL' then it is omitted from the address.
These methods are:
@ -472,65 +463,66 @@ These methods are:
=item bcc_addresses
Returns a list (or an array reference if called in scalar context)
of blind cc'ed recipients' email addresses. (Don't expect much in here
Returns a list (or an array reference if called in scalar context) of
blind cc'ed recipients' email addresses. (Don't expect much in here
unless the message was sent from the mailbox you're poking around in,
by the way.)
=item cc_addresses
Returns a list of cc'ed recipients' email addresses. If called in a scalar
context it returns a reference to an array of email addresses.
Returns a list of cc'ed recipients' email addresses. If called in a
scalar context it returns a reference to an array of email addresses.
=item from_addresses
Returns a list of "From:" email addresses. If called in a scalar context
it returns the first email address in the list. (It's usually a list of just
one anyway.)
Returns a list of "From:" email addresses. If called in a scalar
context it returns the first email address in the list. (It's usually
a list of just one anyway.)
=item replyto_addresses
Returns a list of "Reply-to:" email addresses. If called in a scalar context
it returns the first email address in the list.
Returns a list of "Reply-to:" email addresses. If called in a scalar
context it returns the first email address in the list.
=item sender_addresses
Returns a list of senders' email addresses. If called in a scalar context
it returns the first email address in the list.
Returns a list of senders' email addresses. If called in a scalar
context it returns the first email address in the list.
=item to_addresses
Returns a list of recipients' email addresses. If called in a scalar context
it returns a reference to an array of email addresses.
Returns a list of recipients' email addresses. If called in a scalar
context it returns a reference to an array of email addresses.
=back
Note that context affects the behavior of all of the above methods.
Those fields that will commonly contain multiple entries (i.e. they are
recipients) will return an array reference when called in scalar context.
You can use this behavior to optimize performance.
Those fields that will commonly contain multiple entries (i.e. they
are recipients) will return an array reference when called in scalar
context. You can use this behavior to optimize performance.
Those fields that will commonly contain just one address (the sender's) will
return the first (and usually only) address. You can use this behavior to
optimize your development time.
Those fields that will commonly contain just one address (the
sender's) will return the first (and usually only) address. You can
use this behavior to optimize your development time.
=head1 Addresses and the Mail::IMAPClient::BodyStructure::Address
Several components of an envelope structure are address
structures. They are each parsed into their own object,
Several components of an envelope structure are address structures.
They are each parsed into their own object,
B<Mail::IMAPClient::BodyStructure::Address>, which looks like this:
{ mailboxname => 'somebody.special'
, hostname => 'somplace.weird.com'
, personalname => 'Somebody Special
, sourceroute => 'NIL'
{
mailboxname => 'somebody.special',
hostname => 'somplace.weird.com'
personalname => 'Somebody Special
sourceroute => 'NIL'
}
RFC2060 specifies that each address component of a bodystructure is a
list of address structures, so B<Mail::IMAPClient::BodyStructure> parses
each of these into an array of B<Mail::IMAPClient::BodyStructure::Address>
objects.
list of address structures, so B<Mail::IMAPClient::BodyStructure>
parses each of these into an array of
B<Mail::IMAPClient::BodyStructure::Address> objects.
Each of these objects has the following methods available to it:
@ -543,13 +535,13 @@ the left of the '@' sign.
=item hostname
Returns the "hostname" portion of the address, which is the part to the
right of the '@' sign.
Returns the "hostname" portion of the address, which is the part to
the right of the '@' sign.
=item personalname
Returns the "personalname" portion of the address, which is the part of
the address that's treated like a comment.
Returns the "personalname" portion of the address, which is the part
of the address that's treated like a comment.
=item sourceroute
@ -557,30 +549,28 @@ Returns the "sourceroute" portion of the address, which is typically "NIL".
=back
Taken together, the parts of an address structure form an address that will
look something like this:
Taken together, the parts of an address structure form an address that
will look something like this:
C<personalname E<lt>mailboxname@hostnameE<gt>>
Note that because the B<Mail::IMAPClient::BodyStructure::Address>
objects come in arrays, it's generally easier to use the methods
available to B<Mail::IMAPClient::BodyStructure::Envelope> to obtain
all of the addresses in a particular array in one operation. These
methods are provided, however, in case you'd rather do things
the hard way. (And also because the aforementioned methods from
all of the addresses in a particular array in one operation. These
methods are provided, however, in case you'd rather do things the hard
way. (And also because the aforementioned methods from
B<Mail::IMAPClient::BodyStructure::Envelope> need them anyway.)
=cut
=head1 AUTHOR
David J. Kernen
Reworked and maintained by Mark Overmeer.
Original author: David J. Kernen; Reworked by: Mark Overmeer;
Maintained by Phil Pearl.
=head1 SEE ALSO
perl(1), Mail::IMAPClient, and RFC2060. See also Parse::RecDescent if you
want to understand the internals of this module.
perl(1), Mail::IMAPClient, Parse::RecDescent, and RFC2060.
=cut

View File

@ -413,11 +413,14 @@ ok( $imap->reconnect, "reconnect" );
ok_relaxed_logout($imap);
# Test STARTTLS - an optional feature so tests always succeed
{
$imap->connect( Starttls => 1 );
# STARTTLS - an optional feature
if ( $imap->_load_module("SSL") ) {
$imap->connect( Ssl => 0, Starttls => 1 );
ok( 1, "OPTIONAL connect(Starttls=>1)" . ( $@ ? ": (error) $@ " : "" ) );
}
else {
ok( 1, "skipping optional STARTTLS test" );
}
# LOGOUT
# - on successful LOGOUT $code is OK (not BYE!) see RFC 3501 sect 7.1.5

30
W/learn/data_utf7 Normal file
View File

@ -0,0 +1,30 @@
[&ZTZO9nux-]
[&ZTZO9nux-/263&cO1+vw-]
[&ZTZO9nux-/&kK57sZXumJg-]
[&ZTZO9nux-/&fwFb+G3u-]
[&ZTZO9nux-/11111]
[&XfJT0ZAB-]
[&XfJT0ZAB-/321]
[&XfJSIJZk-]
[&XfJSIJZk-/&fwFb+G3u-]
[&g0l6Pw-]
[&Tg1mDpCuTvZZOQ-]
[&XfJfUmhj-]
[&XfJfUmhj-/&VGhfi14I-]
[&XfJfUmhj-/&Ti1W,U4Hf1E-]
[&XfJfUmhj-/&f1F62Q-]
[&XfJfUmhj-/&UWh0Aw-]
[&XfJfUmhj-/&UWh0Aw-/11]
[&XfJfUmhj-/&fwFb+G3u-]
[&XfJfUmhj-/&X66Pbw-eip]
[&XfJfUmhj-/China Tax Service]
[&XfJfUmhj-/IT&ZXR0Bg-]
[&XfJfUmhj-/&cGuPZnlo-]
[&XfJfUmhj-/&UWhl9g-]
[&XfJfUmhj-/&dTWL3U8ai64-]
[&XfJfUmhj-/&V,mLrQ-]
[&XfJfUmhj-/&cO1wuU,hYG+QH5AS-]
[Sent Messages]
[Deleted Messages]
[&V4NXPpCuTvY-]
[&XfJSIJZkkK5O9g-]

13
W/learn/imap_utf7 Executable file
View File

@ -0,0 +1,13 @@
#!/usr/bin/perl
use Unicode::IMAPUtf7;
my $t = Unicode::IMAPUtf7->new();
while (<>) {
chomp ;
push( @result, sprintf( "%33s %s\n", $_, $t->decode($_) ) ) ;
}
print @result ;

41
W/ml_announce.in Normal file
View File

@ -0,0 +1,41 @@
m4_dnl $Id: ml_announce.in,v 1.3 2012/09/11 21:01:53 gilles Exp gilles $
m4_dnl
m4_define(`M4_imapsync_VERSION',m4_esyscmd(cat VERSION|tr -d '\n'))m4_dnl
m4_define(`M4_SECRET_PATH',m4_esyscmd(cat dist/path_last.txt|tr -d '\n'))m4_dnl
m4_dnl
From: Gilles LAMIRAL <gilles.lamiral@laposte.net>
Bcc: gilles@lamiral.info
Subject: [imapsync update] new imapsync release M4_imapsync_VERSION available
To: imapsync_update@lists.lamiral.info
Hello imapsync user,
You're subscribed to the newsletter announcing imapsync new releases
(very few traffic) and the way to get them. Send me a note if you
don't want to receive those announces anymore.
You will find the latest imapsync.exe binary (release M4_imapsync_VERSION)
and the latest imapsync source code (release M4_imapsync_VERSION) at the following link:
http://imapsync.lamiral.info/dist/M4_SECRET_PATH/
Three files are there:
- imapsync is directly the perl script (also found in the tarball) for a fast upgrade.
- imapsync-M4_imapsync_VERSION.tgz is the tarball containing everything of the project (maybe too much)
- imapsync.exe is the win32 standalone binary.
What's new in this M4_imapsync_VERSION release can be found at
http://imapsync.lamiral.info/#latest
I thank you again for buying and using imapsync,
I wish you successful imap transfers!
Feedback is welcome!
Web site: http://imapsync.lamiral.info/
--
Au revoir.
Gilles Lamiral, La Billais, 35580 Baulon, France
tel +33 951 84 42 42
mob +33 620 79 76 06

View File

@ -1,13 +1,13 @@
#!/bin/sh
# $Id: paypal_run_dev,v 1.5 2011/05/20 10:50:05 gilles Exp gilles $
# $Id: paypal_run_dev,v 1.7 2012/09/10 11:53:37 gilles Exp gilles $
set -e
#set -x
# Add path to commands at home
PATH=$PATH:/g/public_html/imapsync/W/paypal_reply
PERL5LIB=/g/public_html/imapsync/Mail-IMAPClient-3.30/lib
PERL5LIB=/g/public_html/imapsync/Mail-IMAPClient-3.32/lib
export PERL5LIB
test -f /g/public_html/imapsync/W/paypal_reply/paypal_functions \

View File

@ -1,6 +1,6 @@
#!/bin/sh
# $Id: paypal_run_laposte,v 1.5 2012/08/24 14:18:02 gilles Exp gilles $
# $Id: paypal_run_laposte,v 1.6 2012/09/10 11:54:33 gilles Exp gilles $
set -e
#set -x
@ -8,7 +8,7 @@ set -e
# Add path to commands at home
PATH=$PATH:/g/public_html/imapsync/W/paypal_reply
PERL5LIB=/g/public_html/imapsync/Mail-IMAPClient-3.30/lib
PERL5LIB=/g/public_html/imapsync/Mail-IMAPClient-3.32/lib
export PERL5LIB
test -f /g/public_html/imapsync/W/paypal_reply/paypal_functions \

View File

@ -1,2 +1,6 @@
imapsync \ --host1 p --user1 toto --passfile1 secret.toto \ --host2 p --user2 titi --passfile2 secret.titi
imapsync \ --host1 p --user1 tata --passfile1 secret.tata \ --host2 p --user2 titi --passfile2 secret.titi
REM
cd C:\msys\1.0\home\Admin\imapsync
REM imapsync.exe \ --host1 p --user1 toto --passfile1 secret.toto \ --host2 p --user2 titi --passfile2 secret.titi
.\imapsync.exe \ --host1 p --user1 tata --passfile1 secret.tata \ --host2 p --user2 titi --passfile2 secret.titi

4
i3
View File

@ -1,7 +1,7 @@
#!/bin/sh
# $Id: i3,v 1.10 2012/08/12 23:15:15 gilles Exp gilles $
# $Id: i3,v 1.11 2012/09/11 21:00:06 gilles Exp gilles $
BASE=`dirname $0`
perl -I${BASE}/W/Mail-IMAPClient-3.31/lib ${BASE}/imapsync "$@"
perl -I${BASE}/W/Mail-IMAPClient-3.32/lib ${BASE}/imapsync "$@"

129
imapsync
View File

@ -20,7 +20,7 @@ Synchronise mailboxes between two imap servers.
Good at IMAP migration. More than 44 different IMAP server softwares
supported with success.
$Revision: 1.504 $
$Revision: 1.508 $
=head1 SYNOPSIS
@ -515,7 +515,7 @@ Entries for imapsync:
Feedback (good or bad) will often be welcome.
$Id: imapsync,v 1.504 2012/08/28 13:10:26 gilles Exp gilles $
$Id: imapsync,v 1.508 2012/09/10 21:10:13 gilles Exp gilles $
=cut
@ -589,6 +589,7 @@ my(
$version, $help,
$justconnect, $justfolders, $justbanner,
$fast,
$total_bytes_transferred,
$total_bytes_skipped,
$total_bytes_error,
@ -603,6 +604,12 @@ my(
$h2_total_bytes_duplicate,
$h1_nb_msg_deleted,
$h2_nb_msg_deleted,
$h1_bytes_processed,
$h1_nb_msg_processed,
$h1_nb_msg_start, $h1_bytes_start,
$h2_nb_msg_start, $h2_bytes_start,
$timeout,
$timestart, $timestart_int, $timeend, $timediff,
$timesize, $timebefore,
@ -627,13 +634,14 @@ my(
$addheader,
%h1, %h2,
$checkselectable, $checkmessageexists,
$expungeaftereach,
);
# main program
# global variables initialisation
$rcs = '$Id: imapsync,v 1.504 2012/08/28 13:10:26 gilles Exp gilles $ ';
$rcs = '$Id: imapsync,v 1.508 2012/09/10 21:10:13 gilles Exp gilles $ ';
$total_bytes_transferred = 0;
$total_bytes_skipped = 0;
@ -645,6 +653,11 @@ $h1_nb_msg_duplicate = $h2_nb_msg_duplicate = 0;
$h1_nb_msg_noheader = $h2_nb_msg_noheader = 0;
$h1_total_bytes_duplicate = $h2_total_bytes_duplicate = 0;
$h1_nb_msg_start = $h1_bytes_start = 0 ;
$h2_nb_msg_start = $h2_bytes_start = 0 ;
$h1_nb_msg_processed = $h1_bytes_processed = 0 ;
$nb_errors = 0;
$max_msg_size_in_bytes = 0;
@ -715,6 +728,7 @@ $cacheaftercopy = 1 if ( $usecache and ( ! defined( $cacheaftercopy ) ) ) ;
$checkselectable = defined( $checkselectable ) ? $checkselectable : 1 ;
$checkmessageexists = defined( $checkmessageexists ) ? $checkmessageexists : 1 ;
$expungeaftereach = defined( $expungeaftereach ) ? $expungeaftereach : 1 ;
print banner_imapsync(@argv_copy);
@ -1043,9 +1057,9 @@ foreach my $h1_fold (@h1_folders_all) {
#@h2_folders_from_1_all = sort keys(%h2_folders_from_1_all);
if ($foldersizes) {
foldersizes( "Host1", $imap1, @h1_folders_wanted ) ;
foldersizes( "Host2", $imap2, @h2_folders_from_1_wanted ) ;
if ( $foldersizes ) {
( $h1_nb_msg_start, $h1_bytes_start ) = foldersizes( "Host1", $imap1, @h1_folders_wanted ) ;
( $h2_nb_msg_start, $h2_bytes_start ) = foldersizes( "Host2", $imap2, @h2_folders_from_1_wanted ) ;
sleep( 2 ) ;
}
@ -1221,6 +1235,7 @@ FOLDER: foreach my $h1_fold (@h1_folders_wanted) {
$total_bytes_skipped += $h1_size;
$nb_msg_skipped += 1;
$h1_nb_msg_noheader +=1;
$h1_nb_msg_processed +=1 ;
} elsif(0 == $rc) {
# duplicate
push(@h1_msgs_duplicate, $m);
@ -1229,6 +1244,7 @@ FOLDER: foreach my $h1_fold (@h1_folders_wanted) {
$nb_msg_skipped += 1;
$h1_total_bytes_duplicate += $h1_size;
$h1_nb_msg_duplicate += 1;
$h1_nb_msg_processed +=1 ;
}
}
my $h1_msgs_duplicate_nb = scalar( @h1_msgs_duplicate ) ;
@ -1281,6 +1297,7 @@ FOLDER: foreach my $h1_fold (@h1_folders_wanted) {
= sort {$h2_hash{$a}{'m'} <=> $h2_hash{$b}{'m'}} keys(%h2_hash);
if ( 0 ) {
# What the hell was this code written for?
# hashes, keys are uid, values are the internaldates in epoch (best format to compare dates)
my %h1_epoch ;
my %h2_epoch ;
@ -1341,7 +1358,7 @@ FOLDER: foreach my $h1_fold (@h1_folders_wanted) {
$debug and print "Host2 uidnext: $h2_uidnext\n" ;
$h2_uidguess = $h2_uidnext ;
MESS: foreach my $m_id (@h1_hash_keys_sorted_by_uid) {
#print "h1_nb_msg_processed: $h1_nb_msg_processed\n" ;
my $h1_size = $h1_hash{$m_id}{'s'};
my $h1_msg = $h1_hash{$m_id}{'m'};
my $h1_idate = $h1_hash{$m_id}{'D'};
@ -1360,6 +1377,8 @@ FOLDER: foreach my $h1_fold (@h1_folders_wanted) {
$debug and print "Host1 found msg $h1_fold/$h1_msg equals Host2 $h2_fold/$h2_msg\n" ;
$total_bytes_skipped += $h1_size ;
$nb_msg_skipped += 1 ;
$h1_nb_msg_processed +=1 ;
if ( $usecache ) {
$debugcache and print "touch $cache_dir/${h1_msg}_$h2_msg\n" ;
touch( "$cache_dir/${h1_msg}_$h2_msg" )
@ -1378,12 +1397,12 @@ FOLDER: foreach my $h1_fold (@h1_folders_wanted) {
"Host1 size msg $h1_fold/$h1_msg = $h1_size <> $h2_size = Host2 $h2_fold/$h2_msg\n";
if( $delete ) {
my $expunge_message = '' ;
$expunge_message = "and expunged" if ( $expunge or $expunge1 ) ;
$expunge_message = "and expunged" if ( $expungeaftereach and ( $expunge or $expunge1 ) ) ;
print "Host1 msg $h1_fold/$h1_msg marked deleted $expunge_message $dry_message\n" ;
unless( $dry ) {
$imap1->delete_message( $h1_msg ) ;
$h1_nb_msg_deleted += 1 ;
$imap1->expunge() if ( $expunge or $expunge1 ) ;
$imap1->expunge() if ( $expungeaftereach and ( $expunge or $expunge1 ) ) ;
}
}
@ -1398,6 +1417,7 @@ FOLDER: foreach my $h1_fold (@h1_folders_wanted) {
my $h1_size = $h1_fir_ref->{ $h1_msg }->{ 'RFC822.SIZE' } || 0 ;
$total_bytes_skipped += $h1_size;
$nb_msg_skipped += 1;
$h1_nb_msg_processed +=1 ;
}
#print "Messages by uid: ", map { "$_ " } keys %h1_msgs_copy_by_uid, "\n" ;
@ -1903,8 +1923,8 @@ sub banner_imapsync {
my @argv_copy = @_;
my $banner_imapsync = join("",
'$RCSfile: imapsync,v $ ',
'$Revision: 1.504 $ ',
'$Date: 2012/08/28 13:10:26 $ ',
'$Revision: 1.508 $ ',
'$Date: 2012/09/10 21:10:13 $ ',
"\n",localhost_info(), "\n",
"Command line used:\n",
"$0 ", command_line_nopassword(@argv_copy), "\n",
@ -2352,10 +2372,11 @@ sub foldersizes {
$total_size += $stot ;
$total_nb += $nb_msgs ;
}
printf ( "Nb messages: %11s messages\n", $total_nb ) ;
printf ( "Total size: %11s bytes (%s)\n", $total_size, bytes_display_string( $total_size ) ) ;
printf ( "Biggest message: %11s bytes (%s)\n", $biggest, bytes_display_string( $biggest ) ) ;
printf ( "Time spent: %11.1f seconds\n", timenext( ) ) ;
printf ( "%s Nb messages: %11s messages\n", $side, $total_nb ) ;
printf ( "%s Total size: %11s bytes (%s)\n", $side, $total_size, bytes_display_string( $total_size ) ) ;
printf ( "%s Biggest message: %11s bytes (%s)\n", $side, $biggest, bytes_display_string( $biggest ) ) ;
printf ( "%s Time spent: %11.1f seconds\n", $side, timenext( ) ) ;
return( $total_nb, $total_size ) ;
}
sub timenext {
@ -2735,13 +2756,22 @@ sub copy_message {
my $h1_flags = $h1_fir_ref->{$h1_msg}->{"FLAGS"} || '' ;
my $h1_idate = $h1_fir_ref->{$h1_msg}->{"INTERNALDATE"} || '' ;
return() if size_filtered( $h1_size, $h1_msg, $h1_fold, $h2_fold ) ;
if (size_filtered( $h1_size, $h1_msg, $h1_fold, $h2_fold ) ) {
$h1_nb_msg_processed +=1 ;
return( ) ;
}
my $string;
do { print "SLEEP 5\n" and sleep 5 ; } if ( $debugsleep ) ;
print "- msg $h1_fold/$h1_msg S[$h1_size] F[$h1_flags] I[$h1_idate] has RFC822.SIZE null!\n" if ( ! $h1_size ) ;
return( ) if ( $checkmessageexists and not message_exists( $imap1, $h1_msg ) ) ;
if ( $checkmessageexists and not message_exists( $imap1, $h1_msg ) ) {
$h1_nb_msg_processed +=1 ;
return( ) ;
}
$string = $imap1->message_string($h1_msg);
@ -2754,6 +2784,7 @@ sub copy_message {
$nb_errors++ ;
$total_bytes_error += $h1_size if ( $h1_size ) ;
#relogin1( ) if ( $relogin1 ) ;
$h1_nb_msg_processed +=1 ;
return( ) ;
}
@ -2807,6 +2838,7 @@ sub copy_message {
$imap2->LastError, "\n";
$nb_errors++;
$total_bytes_error += $h1_size;
$h1_nb_msg_processed +=1 ;
return( ) ;
}
else{
@ -2819,12 +2851,15 @@ sub copy_message {
$h2_uidguess += 1 ;
$total_bytes_transferred += $h1_size ;
$nb_msg_transferred += 1 ;
$h1_nb_msg_processed +=1 ;
my $time_spent = timesince( $begin_transfer_time ) ;
my $rate = bytes_display_string( $total_bytes_transferred / $time_spent ) ;
my $eta = eta( $time_spent, $h1_nb_msg_processed, $h1_nb_msg_start, $nb_msg_transferred ) ;
#my $eta = eta( $time_spent, $nb_msg_transferred, $h1_nb_msg_start ) ;
printf( "msg %s/%-19s copied to %s/%-10s %.2f msgs/s %s/s\n",
$h1_fold, "$h1_msg {$string_len}", $h2_fold, $new_id, $nb_msg_transferred/$time_spent, $rate );
printf( "msg %s/%-19s copied to %s/%-10s %.2f msgs/s %s/s %s\n",
$h1_fold, "$h1_msg {$string_len}", $h2_fold, $new_id, $nb_msg_transferred/$time_spent, $rate, $eta );
if ( $usecache and $cacheaftercopy and $new_id =~ m{^\d+$} ) {
$debugcache and print "touch $cache_dir/${h1_msg}_$new_id\n" ;
@ -2844,8 +2879,39 @@ sub copy_message {
}
else{
$nb_msg_skipped_dry_mode += 1;
$h1_nb_msg_processed +=1 ;
}
return( );
}
sub eta {
return( '' ) if not $foldersizes ;
my( $time_spent, $h1_nb_msg_processed, $h1_nb_msg_start, $nb_msg_transferred ) = @_ ;
my $time_remaining = time_remaining( @_ ) ;
my $nb_msg_remaining = $h1_nb_msg_start - $h1_nb_msg_processed ;
my $eta_date = localtime( time + $time_remaining ) ;
return( sprintf( "ETA: %s %1.0f s %s msgs left", $eta_date, $time_remaining, $nb_msg_remaining ) ) ;
}
sub time_remaining {
my( $time_spent, $h1_nb_msg_processed, $h1_nb_msg_start, $nb_msg_transferred ) = @_ ;
my $time_remaining = ( $time_spent / $nb_msg_transferred ) * ( $h1_nb_msg_start - $h1_nb_msg_processed ) ;
return( $time_remaining ) ;
}
sub tests_time_remaining {
ok( 1 == time_remaining( 1, 1, 2, 1 ), "time_remaining: 1, 1, 2, 1 -> 1") ;
ok( 1 == time_remaining( 9, 9, 10, 9 ), "time_remaining: 9, 9, 10, 9 -> 1") ;
ok( 9 == time_remaining( 1, 1, 10, 1 ), "time_remaining: 1, 1, 10, 1 -> 1") ;
}
@ -3274,20 +3340,27 @@ sub touch {
return( ! $failures );
}
sub tests_cache_folder {
ok( '/path/fold1/fold2' eq cache_folder( '/path', 'fold1', 'fold2'), 'cache_folder: /path, fold1, fold2 -> /path/fold1/fold2' ) ;
ok( '/pa_th/fold1/fold2' eq cache_folder( '/pa*th', 'fold1', 'fold2'), 'cache_folder: /pa*th, fold1, fold2 -> /path/fold1/fold2' ) ;
ok( '/_p_a__th/fol_d1/fold2' eq cache_folder( '/>p<a|*th', 'fol*d1', 'fold2'), 'cache_folder: />p<a|*th, fol*d1, fold2 -> /path/fol_d1/fold2' ) ;
}
sub cache_folder {
my( $cache_dir, $h1_fold, $h2_fold ) = @_ ;
#print "sep1 $h1_sep sep2 $h2_sep\n";
my $sep1 = $h1_sep || '/';
my $sep2 = $h2_sep || '/';
#print "$cache_dir h1_fold $h1_fold sep1 $sep1 h2_fold $h2_fold sep2 $sep2\n";
$h1_fold = convert_sep_to_slash( $h1_fold, $sep1 ) ;
$h2_fold = convert_sep_to_slash( $h2_fold, $sep2 ) ;
$h1_fold = filter_forbidden_characters( $h1_fold ) ;
$h2_fold = filter_forbidden_characters( $h2_fold ) ;
return( "$cache_dir/$h1_fold/$h2_fold" ) ;
my $cache_folder = "$cache_dir/$h1_fold/$h2_fold" ;
$cache_folder = filter_forbidden_characters( $cache_folder ) ;
#print "cache_folder [$cache_folder]\n" ;
return( $cache_folder ) ;
}
sub filter_forbidden_characters {
@ -3606,6 +3679,7 @@ sub get_options {
"exitwhenover=i" => \$exitwhenover,
"checkselectable!" => \$checkselectable,
"checkmessageexists!" => \$checkmessageexists,
"expungeaftereach!" => \$expungeaftereach,
);
$debug and print "get options: [$opt_ret]\n";
@ -3795,7 +3869,7 @@ sub check_last_release {
}
sub imapsync_version {
my $rcs = '$Id: imapsync,v 1.504 2012/08/28 13:10:26 gilles Exp gilles $ ';
my $rcs = '$Id: imapsync,v 1.508 2012/09/10 21:10:13 gilles Exp gilles $ ';
$rcs =~ m/,v (\d+\.\d+)/;
my $VERSION = ($1) ? $1: "UNKNOWN";
return($VERSION);
@ -4594,7 +4668,7 @@ sub tests_debug {
SKIP: {
skip "No test in normal run" if ( not $tests_debug );
tests_cache_dir_fix( ) ;
tests_time_remaining( ) ;
}
}
@ -4633,6 +4707,7 @@ sub tests {
tests_add_header( ) ;
tests_cache_dir_fix( ) ;
tests_filter_forbidden_characters( ) ;
tests_cache_folder( ) ;
}
}

View File

@ -5,7 +5,7 @@
<title>Imapsync: an IMAP migration tool ( release <!--#exec cmd="cat ./VERSION"--> )</title>
<meta name="generator" content="Bluefish 1.0.7"/>
<meta name="author" content="Gilles LAMIRAL"/>
<meta name="date" content="2012-08-29T12:23:32+0200"/>
<meta name="date" content="2012-09-12T00:06:47+0200"/>
<meta name="copyright" content="None"/>
<meta name="keywords" content="imap, transfert, migration"/>
<meta name="description" content="imap migration tool"/>
@ -95,7 +95,7 @@ total is 93 millions for 2011</li>
<p>New features or bugfixes since previous releases:</p>
<!-- <ul>
<li><b>1.504</b></li>
<li><b>1.508</b></li>
<li><b>Enhancement</b>: </li>
<li><b>Enhancement</b>: </li>
<li><b>Enhancement</b>: </li>
@ -110,10 +110,19 @@ total is 93 millions for 2011</li>
<li><b>Bug fix</b>: </li>
</ul>
-->
<ul>
<li><b>1.508</b></li>
<li><b>Usability</b>: imapsync guesses and <b>prints when it'll finish</b> the transfer; added <b>ETA</b> after each copy (Estimated Time of Arrival)</li>
<li><b>Enhancement</b>: Added <b>--noexpungeaftereach</b> to speedup --delete --expunge from Gmail.</li>
<li><b>Usability</b>: Added Host1 or Host2 before "Nb messages" "Total size" with --foldersiszes (to facilitate parsing)</li>
<li><b>Bug fix</b>: Previous fix about characters *|?:"<> in cache path was not complete.</li>
</ul>
<ul>
<li><b>1.504</b></li>
<li><b>Enhancement</b>: Added option <b>--nocheckmessageexists</b> to <b>speed up</b> with <b>Tobbit imap server</b> as host1.</li>
<li><b>Enhancement</b>: Added option <b>--nocheckmessageexists</b> to <b>speed up</b> with <b>Tobit imap server</b> as host1.</li>
<li><b>Usability</b>: Added <b>transfer rate</b> and number of messages rate <b>after each copy</b>.</li>
<li><b>Usability</b>: Use Time::HiRes time to get time with better precesion than the second.</li>
<li><b>Bug fix</b>: Convert characters <kbd>*|?:"&lt;&gt;</kbd> to <kbd>_</kbd> in cache paths because they are forbidden on Windows paths.</li>
@ -422,71 +431,85 @@ Don't hesitate to have a try, I will help you and make efforts to switch them to
[host1] means "source server" and [host2] means "destination server":
</p>
<!--
(<a href=""></a>)
-->
<ul>
<li>1und1 H mimap1 84498 [host1]</li>
<li>a1.net imap.a1.net IMAP4 Ready [host1]</li>
<li>1und1 H mimap1 84498 [host1] (<a href="http://www.1und1.de/">http://www.1und1.de/</a>)</li>
<li>a1.net imap.a1.net IMAP4 Ready [host1] </li>
<li>Archiveopteryx 2.03, 2.04, 2.09, 2.10 [host2], 3.0.0 [host2]
(OSL 3.0) http://www.archiveopteryx.org/</li>
<li>Axigen Mail Server Version 8.0.0</li>
<li>BincImap 1.2.3 (GPL) (http://www.bincimap.org/)</li>
<li>CommuniGatePro server (Redhat 8.0) (Solaris), CommuniGate Pro 5.2.17[host2] (CentOS 5.4)</li>
(OSL 3.0) (<a href="http://www.archiveopteryx.org/">http://www.archiveopteryx.org/</a>)</li>
<li>Axigen Mail Server Version 8.0.0 (<a href="http://www.axigen.com/">http://www.axigen.com/</a>)</li>
<li>BincImap 1.2.3 (GPL) (<a href="http://www.bincimap.org/">http://www.bincimap.org/</a>)</li>
<li>CommuniGatePro server (Redhat 8.0) (Solaris), CommuniGate Pro 5.2.17[host2] (CentOS 5.4)
(<a href="http://www.communigate.com/">http://www.communigate.com/</a>) </li>
<li>Courier IMAP 1.5.1, 2.2.0, 2.1.1, 2.2.1, 3.0.8, 3.0.3, 4.1.1 (GPL)
(http://www.courier-mta.org/)</li>
<li>Critical Path (7.0.020)</li>
(<a href="http://www.courier-mta.org/imap/">http://www.courier-mta.org/imap/</a>) </li>
<li>Critical Path (7.0.020) (<a href=""></a>) </li>
<li>Cyrus IMAP 1.5, 1.6,
2.1, 2.1.15, 2.1.16, 2.1.18
2.2.1, 2.2.2-BETA, 2.2.3, 2.2.6, 2.2.10, 2.2.12, 2.2.13,
2.3-alpha (OSI Approved), 2.3.1, 2.3.7, 2.3.16
(http://asg.web.cmu.edu/cyrus/)
(<a href="http://cyrusimap.web.cmu.edu/">http://cyrusimap.web.cmu.edu/</a>)
</li>
<li>David Tobit V8.</li>
<li>DBMail 1.2.1, 2.0.4, 2.0.9, 2.2rc1 (GPL) (http://www.dbmail.org/).
2.0.7 seems buggy.</li>
<li>Deerfield VisNetic MailServer 5.8.6 [host1]</li>
<li>dkimap4 [host1]</li>
<li>Domino (Notes) 4.61[host1], 6.5, 5.0.6, 5.0.7, 7.0.2, 6.0.2CF1, 7.0.1[host1], 8.0.1[host1]</li>
<li>David Tobit V8. (<a href="http://www.tobit.com/">http://www.tobit.com/</a>) </li>
<li>DBMail 1.2.1, 2.0.4, 2.0.9, 2.2rc1 (GPL).
2.0.7 seems buggy. (<a href="http://www.dbmail.org/">http://www.dbmail.org/</a>) </li>
<li>Deerfield VisNetic MailServer 5.8.6 [host1]
(<a href="http://www.deerfield.net/products/visnetic-mailserver/">http://www.deerfield.net/products/visnetic-mailserver/</a>) </li>
<li>dkimap4 [host1] (<a href=""></a>) </li>
<li>Domino (Notes) 4.61[host1], 6.5, 5.0.6, 5.0.7, 7.0.2, 6.0.2CF1, 7.0.1[host1], 8.0.1[host1]
(<a href="http://www-01.ibm.com/software/lotus/products/notes/">http://www-01.ibm.com/software/lotus/products/notes/</a>) </li>
<li><b>Dovecot</b> 0.99.10.4, 0.99.14, 0.99.14-8.fc4, 1.0-0.beta2.7,
1.0.0 [dest/source] (LGPL) (http://www.dovecot.org/)</li>
<li>Eudora WorldMail v2</li>
<li><b>Gimap</b> (<b>Gmail</b> imap) [host1] [host2]</li>
<li>GMX IMAP4 StreamProxy.</li>
<li>Godaddy IMAP (since Godaddy runs Courier)</li>
<li>Groupwise IMAP (Novell) 6.x and 7.0. Buggy so see the FAQ.</li>
<li>hMailServer 5.3.3 [host2], 4.4.1 [host1], HMAILSERVER 5.3.2-B1769 on windows 2003 [hsot2]</li>
<li>iPlanet Messaging server 4.15, 5.1, 5.2</li>
<li>IMail 7.15 (Ipswitch/Win2003), 8.12, 11.03 [host1]</li>
<li>Kerio 7.2.0P1 [host1]</li>
<li><b>MailEnable</b> 4.23 [host1][host2], 4.26 [host1][host2], 5 [host1]</li>
<li>MDaemon 7.0.1, 8.0.2, 8.1, 9.5.4 (Windows server 2003 R2 platform), 12 [host2], 12.0.3 [host1], 12.5.5 [host1]</li>
<li>Mercury 4.1 (Windows server 2000 platform)</li>
1.0.0 [dest/source] (LGPL) (http://www.dovecot.org/) (<a href="http://www.dovecot.org/">http://www.dovecot.org/</a>) </li>
<li>Eudora WorldMail v2 (<a href="http://www.eudora.com/worldmail/">http://www.eudora.com/worldmail/</a>) </li>
<li><b>Gimap</b> (<b>Gmail</b> imap) [host1] [host2] (<a href="http://mail.google.com/">http://mail.google.com/</a>) </li>
<li>GMX IMAP4 StreamProxy. (<a href="http://www.gmx.com/">http://www.gmx.com/</a>) </li>
<li>Godaddy IMAP (since Godaddy runs Courier) (<a href="http://www.godaddy.com/">http://www.godaddy.com/</a>) </li>
<li>Groupwise IMAP (Novell) 6.x and 7.0. Buggy so see the FAQ.
(<a href="http://www.novell.com/products/groupwise/">http://www.novell.com/products/groupwise/</a>) </li>
<li>hMailServer 5.3.3 [host2], 4.4.1 [host1], HMAILSERVER 5.3.2-B1769 on windows 2003 [hsot2]
(<a href="http://www.hmailserver.com/">http://www.hmailserver.com/</a>) </li>
<li>iPlanet Messaging server 4.15, 5.1, 5.2
(<a href="http://en.wikipedia.org/wiki/Oracle_Communications_Messaging_Server">http://en.wikipedia.org/wiki/Oracle_Communications_Messaging_Server</a>) </li>
<li>IMail 7.15 (Ipswitch/Win2003), 8.12, 11.03 [host1] (<a href="http://www.imailserver.com/">http://www.imailserver.com/</a>) </li>
<li>Kerio 7.2.0P1 [host1] (<a href="http://www.kerio.com/">http://www.kerio.com/</a>) </li>
<li><b>MailEnable</b> 4.23 [host1][host2], 4.26 [host1][host2], 5 [host1]
(<a href="http://www.mailenable.com/">http://www.mailenable.com/</a>) </li>
<li>MDaemon 7.0.1, 8.0.2, 8.1, 9.5.4 (Windows server 2003 R2 platform), 12 [host2], 12.0.3 [host1], 12.5.5 [host1]
(<a href="http://www.altn.com/">http://www.altn.com/</a>) </li>
<li>Mercury 4.1 (Windows server 2000 platform) (<a href="http://www.pmail.com/">http://www.pmail.com/</a>) </li>
<li><b>Microsoft Exchange Server</b> 5.5, 6.0.6249.0[host1], 6.0.6487.0[host1],
6.5.7638.1 [host2], 6.5 [host1], Exchange 2007 SP1 (with Update Rollup 2),
Exchange2007-EP-SP2,
Exchange 2010 RTM (Release to Manufacturing) [host2],
Exchange 2010 SP1 RU2 [host2]
Exchange 2010 SP1 RU2 [host2]
(<a href="http://www.microsoft.com/exchange/">http://www.microsoft.com/exchange/</a>)
</li>
<li>Mirapoint server 4.1.9-GA [host1]</li>
<li>Netscape Mail Server 3.6 (Wintel)</li>
<li>Netscape Messaging Server 4.15 Patch 7</li>
<li>OpenMail IMAP server B.07.00.k0</li>
<li>OpenWave</li>
<li>Oracle Beehive [host1]</li>
<li>Qualcomm Worldmail (NT)</li>
<li>Rockliffe Mailsite 5.3.11, 4.5.6</li>
<li>Samsung Contact IMAP server 8.5.0</li>
<li>Scalix v10.1, 10.0.1.3, 11.0.0.431</li>
<li>SmarterMail, Smarter Mail 5.0 Enterprise, Smarter Mail 5.5 [host1].</li>
<li>SunONE Messaging server 5.2, 6.0 (SUN JES - Java Enterprise System)</li>
<li>Sun Java(tm) System Messaging Server 6.2-2.05, 6.2-7.05, 6.3</li>
<li>Surgemail 3.6f5-5</li>
<li>Mirapoint server 4.1.9-GA [host1] (<a href="http://www.mirapoint.com/">http://www.mirapoint.com/</a>) </li>
<li>Netscape Mail Server 3.6 (Wintel) </li>
<li>Netscape Messaging Server 4.15 Patch 7 </li>
<li>OpenMail IMAP server B.07.00.k0 </li>
<li>OpenWave (<a href="http://www.openwave.com/">http://www.openwave.com/</a>) </li>
<li>Oracle Beehive [host1]
(<a href="http://www.oracle.com/technetwork/middleware/beehive/">http://www.oracle.com/technetwork/middleware/beehive/</a>) </li>
<li>Qualcomm Worldmail (NT) (<a href="http://www.eudora.com/worldmail/">http://www.eudora.com/worldmail/</a>) </li>
<li>Rockliffe Mailsite 5.3.11, 4.5.6 (<a href="http://www.mailsite.com/">http://www.mailsite.com/</a>) </li>
<li>Samsung Contact IMAP server 8.5.0 </li>
<li>Scalix v10.1, 10.0.1.3, 11.0.0.431 (<a href="http://www.scalix.com/">http://www.scalix.com/</a>) </li>
<li>SmarterMail, Smarter Mail 5.0 Enterprise, Smarter Mail 5.5 [host1]. (<a href="http://www.smartertools.com/">http://www.smartertools.com/</a>) </li>
<li>SunONE Messaging server 5.2, 6.0 (SUN JES - Java Enterprise System) (<a href="http://www.oracle.com/">http://www.oracle.com/</a>) </li>
<li>Sun Java(tm) System Messaging Server 6.2-2.05, 6.2-7.05, 6.3 (<a href="http://www.oracle.com/">http://www.oracle.com/</a>) </li>
<li>Surgemail 3.6f5-5 (<a href="http://netwinsite.com/surgemail/">http://netwinsite.com/surgemail/</a>) </li>
<li>UW-imap servers (imap-2000b) rijkkramer IMAP4rev1 2000.287
(RedHat uses UW like 2003.338rh), v12.264 Solaris 5.7 (OSI Approved)
(http://www.washington.edu/imap/)</li>
<li>UW - QMail v2.1</li>
<li>VMS, Imap part of TCP/IP suite of VMS 7.3.2</li>
<li><b>Yahoo</b> [host1]</li>
(<a href="http://www.washington.edu/imap/">http://www.washington.edu/imap/</a>) </li>
<li>VMS, Imap part of TCP/IP suite of VMS 7.3.2 (<a href="http://h71000.www7.hp.com/openvms/">http://h71000.www7.hp.com/openvms/</a>) </li>
<li><b>Yahoo</b> [host1] (<a href="http://www.yahoo.com/">http://www.yahoo.com/</a>) </li>
<li><b>Zimbra-IMAP</b> 3.0.1 GA 160, 3.1.0 Build 279, 4.0.5, 4.5.2, 4.5.6,
Zimbra 5.0.24_GA_3356.RHEL4 [host1], 5.5, 6.x</li>
Zimbra 5.0.24_GA_3356.RHEL4 [host1], 5.5, 6.x
(<a href="http://www.zimbra.com/">http://www.zimbra.com/</a>) </li>
</ul>
<h2><a id="similar"></a>Similar softwares</h2>
@ -553,7 +576,7 @@ alt="Viewable With Any Browser" />
<!--#config timefmt="%D" -->
<!--#config timefmt="%A %B %d, %Y" -->
<b>This document last modified on <!--#echo var="LAST_MODIFIED" --></b>
($Id: index.shtml,v 1.129 2012/08/29 10:25:29 gilles Exp gilles $)
($Id: index.shtml,v 1.131 2012/09/11 22:07:18 gilles Exp gilles $)
</p>
</body>

View File

@ -1,9 +1,9 @@
#!/bin/sh
# $Id: tests.sh,v 1.200 2012/08/28 13:11:30 gilles Exp gilles $
# $Id: tests.sh,v 1.201 2012/09/10 21:12:35 gilles Exp gilles $
# Example 1:
# CMD_PERL='perl -I./Mail-IMAPClient-3.31/lib' sh -x tests.sh
# CMD_PERL='perl -I./Mail-IMAPClient-3.32/lib' sh -x tests.sh
# Example 2:
# To select which Mail-IMAPClient within arguments:
@ -23,7 +23,7 @@ echo HOST2=$HOST2
# few debugging tests use:
CMD_PERL_2xx='perl -I./W/Mail-IMAPClient-2.2.9'
CMD_PERL_3xx='perl -I./W/Mail-IMAPClient-3.31/lib'
CMD_PERL_3xx='perl -I./W/Mail-IMAPClient-3.32/lib'
CMD_PERL=${CMD_PERL:-$CMD_PERL_3xx}
@ -1588,9 +1588,31 @@ ll_delete2() {
--host2 $HOST2 --user2 titi \
--passfile2 ../../var/pass/secret.titi \
--folder INBOX \
--delete2 --expunge2
}
ll_delete2_reverse() {
$CMD_PERL ./imapsync \
--host1 $HOST1 --user1 titi \
--passfile1 ../../var/pass/secret.titi \
--host2 $HOST2 --user2 tata \
--passfile2 ../../var/pass/secret.tata \
--folder INBOX \
--delete2 --expunge2
}
ll_delete_reverse() {
$CMD_PERL ./imapsync \
--host1 $HOST1 --user1 titi \
--passfile1 ../../var/pass/secret.titi \
--host2 $HOST2 --user2 tata \
--passfile2 ../../var/pass/secret.tata \
--folder INBOX \
--delete --minage 100 --maxage 300 --noexpungeaftereach
}
ll_delete2_minage() {
can_send && sendtestmessage titi
$CMD_PERL ./imapsync \