mirror of
https://github.com/imapsync/imapsync.git
synced 2024-11-16 15:52:47 +01:00
1.508
This commit is contained in:
parent
c08a56e486
commit
1e03db551f
24
ChangeLog
24
ChangeLog
@ -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
22
FAQ
@ -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
30
INSTALL
@ -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
|
||||
|
25
Makefile
25
Makefile
@ -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
4
README
@ -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
54
TODO
@ -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
|
||||
|
@ -1 +1 @@
|
||||
1.504
|
||||
1.508
|
||||
|
@ -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)
|
||||
|
@ -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]
|
@ -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
|
@ -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>',
|
@ -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
|
@ -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 {
|
@ -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
|
@ -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
|
@ -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
30
W/learn/data_utf7
Normal 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
13
W/learn/imap_utf7
Executable 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
41
W/ml_announce.in
Normal 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
|
@ -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 \
|
||||
|
@ -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 \
|
||||
|
@ -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
4
i3
@ -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
129
imapsync
@ -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( ) ;
|
||||
}
|
||||
}
|
||||
|
||||
|
127
index.shtml
127
index.shtml
@ -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>*|?:"<></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>
|
||||
|
28
tests.sh
28
tests.sh
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user