This commit is contained in:
Nick Bebout 2015-12-03 11:16:32 -06:00
parent f1987d5e52
commit b7c835d670
134 changed files with 44448 additions and 2810 deletions

10
CREDITS
View file

@ -1,5 +1,5 @@
#!/bin/cat
# $Id: CREDITS,v 1.182 2015/05/26 10:16:16 gilles Exp gilles $
# $Id: CREDITS,v 1.184 2015/11/05 20:57:21 gilles Exp gilles $
If you want to make a donation to me, imapsync author, Gilles LAMIRAL,
use any of the following ways:
@ -24,6 +24,14 @@ I thank very much all of these people.
I thank also very much all people who bought imapsync from the homepage
but I don't cite them here.
Mike Salonia
Contributed by using and validating the multi-archive Gmail
destination account. See FAQ.d/FAQ.Gmail.txt
Sebastian Lemke
Contributed by moving hosts from sync_loop_unix.sh to the
credentials file "file.txt".
Ingo Wichmann
Contributed by giving the book
14.95 USD "Rambles Through My Library"

127
ChangeLog
View file

@ -1,17 +1,136 @@
RCS file: RCS/imapsync,v
Working file: imapsync
head: 1.644
head: 1.670
branch:
locks: strict
gilles: 1.644
gilles: 1.670
access list:
symbolic names:
keyword substitution: kv
total revisions: 644; selected revisions: 644
total revisions: 670; selected revisions: 670
description:
----------------------------
revision 1.644 locked by: gilles;
revision 1.670 locked by: gilles;
date: 2015/12/03 02:36:41; author: gilles; state: Exp; lines: +11 -12
Bugfix. logfile missed user2.
----------------------------
revision 1.669
date: 2015/12/03 02:03:53; author: gilles; state: Exp; lines: +138 -83
--logdir --logfile now compatible with old --logfile alone. tests cases.
----------------------------
revision 1.668
date: 2015/12/02 13:23:22; author: gilles; state: Exp; lines: +94 -86
Fixed some perlcritics.
----------------------------
revision 1.667
date: 2015/11/30 02:44:12; author: gilles; state: Exp; lines: +156 -60
--automap implemented.
Added --justautomap to see what will happen with --automap and --f1f2 options.
----------------------------
revision 1.666
date: 2015/11/23 14:56:56; author: gilles; state: Exp; lines: +50 -19
Doc fix. --logfile path inline and in usage().
Added require JSON::WebToken::Crypt::RSA and Crypt::OpenSSL::RSA to a good build on Win32.
Tested OAUTH2 on windows. Works.
Bug fix. Changed "Host1: checking all wanted folders exist" not efficient algorythm
to allow a 2.4 million folders account. Yes, some people have this...
----------------------------
revision 1.665
date: 2015/11/06 00:45:35; author: gilles; state: Exp; lines: +29 -9
Made quota wrnings, quota human usable.
----------------------------
revision 1.664
date: 2015/11/04 18:09:22; author: gilles; state: Exp; lines: +362 -323
Back to require IO::Socket::SSL;
instead of use.
Reformated the usage output.
Added --f1f2 str1=str2 : Force folder str1 to be synced to str2.
--f1f2 overrides any automap mapping and any regextrans2
----------------------------
revision 1.663
date: 2015/10/03 23:59:27; author: gilles; state: Exp; lines: +12 -9
Bugfix. Return with previous Debug when no quota available.
----------------------------
revision 1.662
date: 2015/10/03 22:14:37; author: gilles; state: Exp; lines: +84 -24
Added quota_extract_storage_limit_in_bytes()
Added quota_extract_storage_current_in_bytes()
----------------------------
revision 1.661
date: 2015/09/28 15:36:41; author: gilles; state: Exp; lines: +18 -19
Better prints.
----------------------------
revision 1.660
date: 2015/09/28 14:18:10; author: gilles; state: Exp; lines: +21 -15
IMAP output as an early stage of quota and ID.
----------------------------
revision 1.659
date: 2015/09/21 22:47:50; author: gilles; state: Exp; lines: +107 -29
Better ID format sent. Order terms like in thr RFC.
Added imapsync_id_github, in case.
----------------------------
revision 1.658
date: 2015/09/19 08:56:07; author: gilles; state: Exp; lines: +8 -8
RCS date in id.
----------------------------
revision 1.657
date: 2015/09/19 08:26:04; author: gilles; state: Exp; lines: +206 -77
Started to use global $sync-> in order to reduce number of parameters in routines.
----------------------------
revision 1.656
date: 2015/09/13 16:11:07; author: gilles; state: Exp; lines: +46 -24
Some perlcritic fixes.
----------------------------
revision 1.655
date: 2015/09/11 01:57:51; author: gilles; state: Exp; lines: +15 -12
Bugfix testing automap.
----------------------------
revision 1.654
date: 2015/09/11 01:23:42; author: gilles; state: Exp; lines: +121 -76
Added --automap to implement rfc6154. Turned on by default.
Use --noautomap to avoid it.
----------------------------
revision 1.653
date: 2015/09/05 21:35:56; author: gilles; state: Exp; lines: +27 -25
IO::Socket::SSL mandatory to run.
SSL_VERIFY_NONE in --ssl and --tls
----------------------------
revision 1.652
date: 2015/08/28 14:59:59; author: gilles; state: Exp; lines: +8 -8
"Initial difference" -> "Start difference"
----------------------------
revision 1.651
date: 2015/08/18 22:35:05; author: gilles; state: Exp; lines: +8 -8
fixed xoauth2 calls.
----------------------------
revision 1.650
date: 2015/08/16 00:42:58; author: gilles; state: Exp; lines: +28 -28
Changed some output, added Host1: or Host2 at the begining of line.
----------------------------
revision 1.649
date: 2015/08/10 03:10:15; author: gilles; state: Exp; lines: +7 -7
576 tests.
----------------------------
revision 1.648
date: 2015/08/10 02:58:21; author: gilles; state: Exp; lines: +99 -39
Added guess_prefix() and guess_separator()
Guess prefixes and separators instead of forcing the user to find them.
----------------------------
revision 1.647
date: 2015/08/07 04:35:15; author: gilles; state: Exp; lines: +33 -20
Added folders counting outputs.
----------------------------
revision 1.646
date: 2015/08/07 00:07:39; author: gilles; state: Exp; lines: +16 -6
Added sub imap_utf7_encode( ). Not used.
----------------------------
revision 1.645
date: 2015/07/31 14:48:11; author: gilles; state: Exp; lines: +11 -11
Better outpout in login_imap()
----------------------------
revision 1.644
date: 2015/07/17 01:22:52; author: gilles; state: Exp; lines: +9 -7
Added NOOP in --dry mode during fake APPEND.
----------------------------

421
FAQ
View file

@ -1,5 +1,5 @@
#!/bin/cat
# $Id: FAQ,v 1.209 2015/05/09 20:53:23 gilles Exp gilles $
# $Id: FAQ,v 1.216 2015/11/13 23:58:12 gilles Exp gilles $
+-------------------+
| FAQs for imapsync |
@ -65,20 +65,29 @@ R. Use md5sum to check integrity of the file.
=======================================================================
Q. How to install imapsync?
R. Read the INSTALL file in the tarball also available at
R. Read the INSTALL files in the tarball also available at
http://imapsync.lamiral.info/INSTALL
http://imapsync.lamiral.info/INSTALL.d/
=======================================================================
Q. How to configure and run imapsync?
R. Read the README and FAQ files in the tarball also available at
R. Read the README, OPTIONS and FAQ files in the tarball also
available at:
http://imapsync.lamiral.info/README
http://imapsync.lamiral.info/OPTIONS
http://imapsync.lamiral.info/FAQ
=======================================================================
Q. Can you give some configuration examples?
R. The FAQ file contains many examples for several scenarios
R1. Basic usage is described there:
http://imapsync.lamiral.info/#DOC_BASIC
imapsync --host1 test1.lamiral.info --user1 test1 --password1 secret1 \
--host2 test2.lamiral.info --user2 test2 --password2 secret2
R2. The FAQ files contains many examples for several scenarios
http://imapsync.lamiral.info/FAQ
=======================================================================
@ -277,17 +286,24 @@ option --justfoldersizes (no transfer will be done)
=======================================================================
Q. I see warning messages like
"Host1 Sent/15 size 1428 ignored (no header so we ignore this message)"
Q. I see warning messages like the following:
"Host1 Sent/15 size 1428 ignored (no header so we ignore this message.
To solve this: use --addheader)".
What can I do to transfer those messages?
R1. Use --addheader option, it will add a header like
"Message-Id: <15@imapsync>" and transfer the message on host2.
Duplicates won't happen in next runs.
R1. Like suggested inline, use --addheader option.
Option --addheader will add an header line like
Message-Id: <15@imapsync>
where 15 is the message UID number on host1.
Then imapsync will transfer the changed message on host2.
Duplicates won't happen on next runs.
imapsync ... --addheader
R2. Use --useuid then imapsync will avoid dealing with headers.
R2. Other solution.
Use --useuid then imapsync will avoid dealing with headers.
imapsync ... --useuid
@ -343,7 +359,7 @@ Q. How can I try imapsync with latest Mail::IMAPClient 3.xx perl module?
Three solutions at least.
R1 - Look at the script named "i3" in the tarball, it can be used to
run imapsync with the included Mail-IMAPClient-3.35/ wherever you
run imapsync with the included Mail-IMAPClient-3.37/ wherever you
unpacked the imapsync tarball
R2 Run:
@ -367,10 +383,10 @@ R3 If you want to install the Perl module locally in a directory
- run imapsync with perl and -I option tailing to use the perl
module Mail-IMAPClient-3.xx. Example:
perl -I./Mail-IMAPClient-3.35/lib ./imapsync ...
perl -I./Mail-IMAPClient-3.37/lib ./imapsync ...
or if imapsync is in directory /path/
perl -I./Mail-IMAPClient-3.35/lib /path/imapsync ...
perl -I./Mail-IMAPClient-3.37/lib /path/imapsync ...
=======================================================================
@ -573,6 +589,11 @@ The file imapsync.pid contains the PID of the imapsync process.
This file is removed at the end of a normal run.
You can safely ignore the warning if you don't use imapsync.pid file.
=======================================================================
Q. Quantifier in {,} bigger than 32766 in regex; marked by <-- HERE in
m/(.{ <-- HERE 1,49947})(?:,|$)/ at Mail/IMAPClient.pm line 2121.
R. Do not use a bigger value than 3276 with --split1 or --split2
=======================================================================
Q. Couldn't create [INBOX.Ops/foo/bar]: NO Invalid mailbox name:
@ -628,63 +649,6 @@ R1. Use it with --subscribed
R2. There is also the --subscribe_all option that subscribe
to all folders on host2.
=======================================================================
Q. Is there a way we can specify a date range to sync emails?
If yes, can you please share an example?
R. Yes, with the --search option.
imapsync ... --search "SENTSINCE 1-Jan-2010 SENTBEFORE 31-Dec-2010"
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec
=======================================================================
Q. Is there a way we can specify an age to sync emails?
If yes, can you please share some examples?
R. Yes, with the --maxage or the --minage option.
E.1 Sync only messages less than 2 days old:
imapsync ... --maxage 2
E.2 Sync only messages more than 2 days old:
imapsync ... --minage 2
E.3 Sync only messages more than 30 days old and less than 365 days old:
imapsync ... --minage 30 --maxage 365
E.4 Sync only messages less than 30 days old or more than 365 days old:
imapsync ... --maxage 30 --minage 365
Full explanation:
--maxage <int> : Skip messages older than <int> days.
final stats (skipped) don't count older messages
see also --minage
--minage <int> : Skip messages newer than <int> days.
final stats (skipped) don't count newer messages
You can do (+ are the messages selected):
past|----maxage+++++++++++++++>now
past|+++++++++++++++minage---->now
past|----maxage+++++minage---->now (intersection)
past|++++minage-----maxage++++>now (union)
=======================================================================
Q. On Unix, some passwords contain * and " characters. Login fails.
R. Use a backslash to escape the characters:
@ -1056,12 +1020,12 @@ b) Replace manually the whitespace by a colon in string "From " but you
header lines of the message)
c) Run imapsync with the following option (this replaces "From "by "From:"):
--regexmess 's/\AFrom /From:/'
--regexmess 's/\AFrom /From: /'
or may be better (no other "From:" collision):
d) Run imapsync with the following option (this replaces "From "by "X-om:"):
--regexmess 's/\AFrom /X-om:/'
--regexmess 's/\AFrom /X-From: /'
e) Run imapsync with the following option (this removes the whole "From " line):
--regexmess 's{\AFrom\ [^\n]*(\n)?}{}gxms'
@ -1087,319 +1051,6 @@ using the same server, we can use $from->copy Therefore we seem to not
download and upload the message and therefore we do not have any
format issues. And now it works fine. (Thanks to Hansjoerg.Maurer)
=======================================================================
Server specific issues and solutions
=======================================================================
=======================================================================
Q. From Zimbra to XXX
imapsync ... \
--exclude "Conversation Action Settings" \
--exclude "Quick Step Settings" \
--exclude "News Feed"
=======================================================================
Q. From or to HMailServer version 4.4.1.
R. You have to add prefix and separator manually because 4.4.1 doesn't
honor the NAMESPACE imap command.
Example for host1:
imapsync ... \
--prefix1 "" --sep1 .
No specific option for HMailServer 5.3.3 since NAMESPACE is supported.
Maybe --subscribe_all will help you to see all migrated folders.
=======================================================================
Q. Synchronizing from Kerio Connect to XXX
R. No special options required.
See also:
http://www.linux-france.org/prj/imapsync_list/msg01756.html
http://www.safetynet-it.com/it-support/mac-kerio-server-to-microsoft-exchange-2010-migration-1/
http://www.safetynet-it.com/it-support/mac-kerio-server-to-microsoft-exchange-2010-migration-2/
=======================================================================
Q. Synchronizing from SmarterMail to XXX
imapsync --host1 imap.d1.org --user1 joe --password1 secret1 --sep1 "/" \
--host2 imap.d2.org --user2 joe --password2 secret2 \
--prefix1 "" \
--regextrans2 "s#Sent Items$#Sent#" \
--dry --justfolders
Maybe add other --regextrans2 to change folder names and see the result.
When satisfied, run without --dry --justfolders
=======================================================================
Q. Synchronizing from Yahoo to XXX
R. Use --host1 imap.mail.yahoo.com --sep1 '/'
./imapsync \
--host1 imap.mail.yahoo.com \
--user1 billy \
--password1 secret \
--host2 XXX \
--user2 billy \
--password2 secret \
--sep1 '/'
Can also add --ssl1 to gain encrypted transfer from yahoo.
SSL seems to be mandatory for yahoo (since november 2011)
=======================================================================
Q. from Microsoft's Exchange 2007 to Google Apps for your Domain
(GAFYD)
R. Take a look at:
http://mark.ossdl.de/2009/02/migrating-from-exchange-2007-to-google-apps-mail/
=======================================================================
Q. Syncing from Google Apps domain to Googlemail account
A known bug encountered with this output (Alexander is a folder name):
++++ Verifying [Alexander] -> [Alexander] ++++
+ NO msg #16 [A96Dh4AwlLVphOAW5MS/eQ:779824] in Alexander
+ Copying msg #16:779824 to folder Alexander
flags from : [\Seen]["04-Jul-2007 14:32:22 +0100"]
Couldn't append msg #16 (Subject:[Rieter-Event (please accept with
comments)]) to folder Alexander: 46 NO Invalid folder: Sent (Failure)
In fact folder "Sent" is just the last folder listed previously
as a:
...
To Folder [Sent] does not exist yet
To Folder [Sonja] Size: 1024546 Messages: 96
...
R. Just run imapsync a time like this :
imapsync ... --folder Alexander
=======================================================================
Q. Migrating from or to Parallels Plex Server
R. It depends on the OS
Parallells Plesk Panel for Windows requires --sep2 / --prefix2 ""
Parallells Plesk Panel for Linux works with default parameters.
=======================================================================
Q. I'm migrating from WU to Cyrus, and the mail folders are under
/home/user/mail but the tool copies everything in /home/user, how
can i avoid that?
Two solutions:
R. Use
imapsync ... --include '^mail'
R. or (better)
imapsync ... --subscribed --subscribe
=======================================================================
Q. I'm migrating from WU to Cyrus, and the mail folders are under
/home/user/mail directory. When imapsync creates the folders in
the new cyrus imap server, it makes a folder "mail" and below that
folder puts all the mail folders the user have in /home/user/mail,
i would like to have all those folders directly under INBOX.
R. Use
imapsync ... --regextrans2 's/^mail/INBOX/' --dry
look at the simulation and if all transformations seem
good then remove the --dry option.
=======================================================================
Q. Migrating from Groupwise to Cyrus
R. By Jamie Neil:
I eventually managed to get the mail to migrate without errors using the
following options:
--sep1 /
- doesn't report separator so has to be set explicitly.
--nosyncacls
- doesn't support ACLs.
--skipheader '^Content-Type'
- MIME separator IDs seem to change every time a mail is accessed so
this is required to stop duplicates.
--maxage 3650
- some messages just don't seem to want to transfer and produce the
perl errors I mentioned before. This prevents the errors, but the
bad messages don't transfer.
Even though the mail migrated OK, there are a couple of gotchas with
Groupwise IMAP:
1) Some of the GW folders are not real folders and are not available
to IMAP, the main problem one being "Sent Items". I could find no way
of coping the contents of these folders. The nearest I got was to
create a "real" folder and copy/move the sent items into it, but
imapsync still didn't see the messages (I think because there is
something funny about the reported dates/sizes).
It think this problem has been rectified in GW6.5.
2) The "skipheader '^Content-Type'" directive is required to stop
duplicate messages being created. GW seems to generate this field on
the fly for messages that have MIME separators and so it's different
every time.
3) Version 6.0.1 of the Groupwise Internet Connector sucks. I was
getting server aborts when I pushed it a bit hard! I eventually had to
upgrade to 6.0.4 which seems to be a lot more stable.
=======================================================================
Q. Migrating from iPlanet Messaging Server
5.2 Patch 2 (built Jul 14 2004)) to Groupwise 7.0
I encounter many errors like this:
"Error trying to append string: 17847 BAD APPEND"
R. GroupWise 7 seems buggy. Apply GroupWise 7 support pack 1
=======================================================================
Q. Migrating from David Tobit V10 (DvISE Mail Access Server MA-...)
R. Use the following options:
imapsync ... --prefix1 "" --sep1 / --idatefromheader ^
--nofoldersizes --useuid --nocheckmessageexists
=======================================================================
Q. Migrating from David Tobit V8
("* OK IMAP4rev1 DvISE Mail Access Server MA-8.10a (0126)")
First try above V10 solution since improvments have been made
to support Tobit.
R. Use the following options :
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
patch saved in ./patches/imapsync-1.337_tobit_V6.patch
=======================================================================
Q. I need to migrate 1250 mailboxes, passwords are in a MySQL Database.
Can you tell me if your script suits my needs?
R. Mailboxes must exist before running imapsync.
You have to extract users logins and passwords in a csv file.
See the "HUGE MIGRATION" section in the README file.
======================================================================
Q: From MailEnable 1.75
R: --sep1 "/" --prefix1 ""
Q: From MailEnable 2.2
R: --sep1 "." --prefix1 ""
Q: To MailEnable
R: --sep2 / --prefix2 "" --addheader --messageidnodomain --syncflagsaftercopy
======================================================================
Q. From GMX IMAP4 StreamProxy
R. Use:
--prefix1 INBOX and --sep1 .
======================================================================
Q. From Courier to Archiveopteryx
R. You can read http://www.archiveopteryx.org/migration/imapsync
Default values might be fine now with latest imapsync.
======================================================================
Q. To Sun Java(tm) System Messaging Server 6.2-7.05
Q. To Communigate Pro - Solaris version
R. See and run patches/imapsync_1.267_jari
======================================================================
Q. From Softalk Workgroup Mail 7.6.4
R. Old Softalk releases don't support the IMAP SEARCH command.
Here are the options to get it working.
imapsync ... --sep1 '.' --prefix1 '' \
--noabletosearch --nocheckmessageexists --addheader
(Thanks to Andrew Tucker)
======================================================================
Q. From or to QQMail IMAP4Server
R. imapsync ... --noabletosearch
======================================================================
Q. From FirstClass to XXX
http://www.firstclass.com/
R. Migrating from FirstClass is not easy because FirstClass, strangely,
does not show all messages via IMAP. To make it show all messages,
a trick, painful to follow by hand, is moving emails
out and back in, for each folder. May be it can be done by a script.
FirstClass releases prior to release 12 do not shows the "Sent"
folder in IMAP but FirstClass release 12 shows it.
I advice you to upgrade to FirstClass release 12 before leaving it
with imapsync or another imap tool.
Here is a command line used to migrate from FirtClass release 12:
imapsync ... \
--tmpdir /var/tmp --usecache \
--useheader Message-ID \
--idatefromheader \
--addheader \
--regextrans2 "s,(/|^) +,\$1,g" --regextrans2 "s, +(/|$),\$1,g" \
--regextrans2 "s/[\^]/_/g" \
--regextrans2 "s/['\"\\\\]/_/g" \
--regextrans2 "s,&AC8-,-,g" \
--regextrans2 "s,&APg-,oe,g"
On Windows, in the previous example containing \$1 you have to
replace the two \$1 by $1 (remove the \ before $).
Special thanks to Kristian Wind and Joey Alexander for helping me
writing this FAQ item.
See also this worth reading discussion in a Zimbra forum:
http://www.zimbra.com/forums/migration/20349-help-needed-migrating-firstclass.html
======================================================================
Q. From XXX to FTGate
R. Do NOT use --usecache since new UIDs are not given by FTGate and also
badly guessed by imapsync. UIDEXPUNGE does not work so use also
--expunge2 when using --delete2
imapsync ... \
--sep2 / --prefix2 "" \
--useheader Message-Id \
======================================================================
Q: How can I write an .rpm with imapsync

View file

@ -1,38 +1,50 @@
#!/bin/cat
$Id: FAQ.Domino.txt,v 1.2 2015/03/26 04:24:17 gilles Exp gilles $
# $Id: FAQ.Domino.txt,v 1.4 2015/09/19 08:58:34 gilles Exp gilles $
======================================================================
Domino specific issues and solutions
Imapsync. Domino specific issues and solutions
======================================================================
======================================================================
Q. From Domino Notes to xxx
On Windows use:
imapsync.exe ... --sep2 "\\" --prefix2 ""
imapsync.exe ... --sep1 "\\" --prefix1 ""
On Unix use:
imapsync ... --sep2 '\\' --prefix2 ''
imapsync ... --sep1 '\' --prefix1 ''
======================================================================
Q. From xxx to Domino Notes
For Domino anywhere with imapsync.exe on Windows use:
Domino doesn't accept INBOX subfolders.
On Windows:
imapsync.exe ... ^
--sep2 "\\" --prefix2 "" ^
--regextrans2 "s,^INBOX\\(.*),$1,"
--regextrans2 "s,^Inbox\\(.*),$1,i"
Explanation: Domino doesn't accept INBOX subfolders.
On Unix:
imapsync ... \
--sep2 '\' --prefix2 '' \
--regextrans2 's,^Inbox\\(.*),$1,i'
If you want to sync the complete host1 mailbox in a subfolder called OLDBOX use:
On Windows:
imapsync.exe ... ^
--sep2 "\\" --prefix2 "" ^
--regextrans2 "s,(.*),OLDBOX\\$1," --justfolders --dry
--subfolder2 "OLDBOX" --justfolders --dry
On Unix:
imapsync ... \
--sep2 '\' --prefix2 '' \
--subfolder2 'OLDBOX' --justfolders --dry
If the output is correct for you then remove --dry and have a run.
Verify the folder hierarchy is good on host2 then remove --justfolders to

View file

@ -1,8 +1,8 @@
#!/bin/cat
$Id: FAQ.Dovecot.txt,v 1.1 2015/03/23 00:16:43 gilles Exp gilles $
$Id: FAQ.Dovecot.txt,v 1.2 2015/07/18 22:35:27 gilles Exp gilles $
=======================================================================
Dovecot specific issues and solutions
Imapsync. Dovecot specific issues and solutions
=======================================================================

View file

@ -1,8 +1,8 @@
#!/bin/cat
$Id: FAQ.Duplicates.txt,v 1.3 2015/04/02 23:40:08 gilles Exp gilles $
$Id: FAQ.Duplicates.txt,v 1.5 2015/09/19 08:59:14 gilles Exp gilles $
======================================================================
Imapsync and message duplicates issues
Imapsync and duplicated messages issues.
======================================================================
=======================================================================
@ -62,6 +62,11 @@ and Received lines? Often standalone Message-Id works:
imapsync ... --useheader "Message-Id"
Once imapsync does not generate duplicates, the previous duplicates
can be deleted with option --delete2duplicates
imapsync ... --useheader "Message-Id" --delete2duplicates
Another good way toward a solution is to isolate two or three messages
in a BUG folder and send me the --debug output by email at
gilles.lamiral@laposte.net
@ -69,7 +74,7 @@ gilles.lamiral@laposte.net
imapsync ... --debug --folder BUG
I will take a close look at the log and modify imapsync to fix
this faulty duplicate behaviour.
this faulty duplicate behavior.
Remark. (Trick found by Tomasz Kaczmarski)

View file

@ -1,13 +1,60 @@
#!/bin/cat
$Id: FAQ.Exchange.txt,v 1.4 2015/06/03 15:33:48 gilles Exp gilles $
$Id: FAQ.Exchange.txt,v 1.14 2015/11/30 16:12:18 gilles Exp gilles $
=======================================================================
Exchange 20xx and Office365 specific issues and solutions
Imapsync. Exchange 20xx and Office365 specific issues and solutions
=======================================================================
Questions anwswered in this FAQ are:
Q. Can I use imapsync to transfer from or to Exchange or Office365 accounts?
Q. How to sync from XXX to Exchange 2010/2013 or Office365
Q. For Office365 I have double and triple checked the username and
password spelling but I still get a "LOGIN failed". Any clue?
Q. Exchange fails with "User is authenticated but not connected".
Q. From XXX to Exchange 2013 or Office365, read receipts are all
resent again after a sync. Even for old messages. How can I fix that?
Q. From XXX to Exchange 2010/2013 or Office365 I get this error message
sometimes: "BAD Command Argument Error 11". What does it mean?
Q. From XXX to Exchange 2010 or 2013 or Office365 the flag Flagged does
not seem to be well synced. What can I do?
Q. Exchange and Office365 have throttle mechanisms to limit any huge
usage. Sometimes imapsync transfers are too stressful for servers.
How to deal with that?
Q. How to migrate from or to Exchange 2007/2010 with an
admin/authuser account?
Q. How to migrate from or to Office 365 with an admin/authuser account?
Q. How to migrate from or to Exchange 2003 with an admin/authuser
account?
Q. Couldn't create folder [trash] "Mailbox already exists".
Q. Migrating to Exchange 201O, messages get date of the transfer,
this is bad for sorting and listing. What can I do?
Q. How to sync from any to Exchange2007?
Q. How to sync from Microsoft Exchange 2000 IMAP4rev1 server?
=======================================================================
Q. From XXX to Exchange 2010/2013 or Office365
Q. Can I use imapsync to transfer from or to Exchange or Office365 accounts?
R. Yes. But IMAP access to a Exchange or Office365 account is not always
allowed by default so it has to be allowed in the server configuration
part:
=======================================================================
Q. How to sync from XXX to Exchange 2010/2013 or Office365
R. Here is a command line resume that solves most encountered issues when
migrating to Exchange or Office365. To understand or change the
@ -19,9 +66,13 @@ On Windows:
imapsync.exe ... ^
--maxsize 10000000 ^
--maxlinelength 9900 ^
--maxmessagespersecond 4 ^
--regexflag "s/\\Flagged//g" ^
--disarmreadreceipts ^
--maxlinelength 9000
--regexmess "s,(.{9900}),$1\r\n,g"
On Unix
imapsync ... --regexmess 's,(.{9900}),$1\r\n,g'
On Unix:
@ -29,17 +80,49 @@ On Unix:
imapsync ... \
--maxsize 10000000 \
--maxlinelength 9900 \
--regexflag "s/\\Flagged//g" \
--maxmessagespersecond 4 \
--regexflag 's/\\Flagged//g' \
--disarmreadreceipts \
--maxlinelengthcmd 'reformime -r7'
To get the "reformime" command on Linux install the "maildrop" package
No "reformime" on Windows so for now messages with too long line length
can't be synced to Exchange or Office365.
On Linux, to get the "reformime" command, install the "maildrop" package.
In case you don't have it you can use
--regexmess 's,(.{9900}),$1\r\n,g'
instead of --maxlinelengthcmd 'reformime -r7'
On Windows, no "reformime" is available so messages with too long line length
can be synced to Exchange or Office365 by inserting a CRLF every 9900
characters on long lines, using --regexmess "s,(.{9900}),$1\r\n,g"
=======================================================================
Q. From XXX to Exchange 2013 or Office365 read receipts are all
Q. For Office365 I have double and triple checked the username and
password spelling but I still get a "LOGIN failed". Any clue?
R1. Triple check the hostname then. Try all of these:
* imap-mail.outlook.com
* imap.outlook.com
* outlook.office365.com
R2. Also triple check a license is assigned to that account
in Office365.
R3. Try with a classic email client like Thunderbird and the same
parameters.
=======================================================================
Q. Exchange fails with "User is authenticated but not connected".
R. "The message “User is authenticated but not connected” is due to a
bug in the Exchange server's IMAP implementation. If the client
presents a valid user name but an invalid password, the server
accepts the login, but subsequent commands fail with the
aforementioned error message." Source:
http://unix.stackexchange.com/questions/164823/user-is-authenticated-but-not-connected-after-changing-my-exchange-password
Thanks to James Abbottsmith for this link and explanation at
https://github.com/imapsync/imapsync/issues/32#issuecomment-153561647
=======================================================================
Q. From XXX to Exchange 2013 or Office365, read receipts are all
resent again after a sync. Even for old messages. How can I fix that?
R. imapsync can remove the header containing this read receipt request.
@ -74,7 +157,7 @@ Thanks to David Karnowski for pointing and solving this issue.
=======================================================================
Q. From XXX to Exchange 2010/2013 or Office365 I get this error message
sometimes: "BAD Command Argument Error 11"
sometimes: "BAD Command Argument Error 11". What does it mean?
R. This error message comes from Exchange IMAP server when it
encounters any problem. Most of the time it is one of the following:
@ -101,6 +184,15 @@ R. This error message comes from Exchange IMAP server when it
imapsync ... --maxlinelength 9900
In case you prefer fixing messages with long lines the hard way,
instead of skipping them with --maxlinelength 9900, just use:
On Windows
imapsync ... --regexmess "s,(.{9900}),$1\r\n,g"
On Unix
imapsync ... --regexmess 's,(.{9900}),$1\r\n,g'
Have also in mind that Exchange closes the connection after 10 errors
encountered so you might also see "BYE Connection closed" errors from
Exchange, which means Exchange leaves the session and say goodbye,
@ -108,7 +200,7 @@ come back later. Rerun a sync then.
=======================================================================
Q. From XXX to Exchange 2010 or 2013 or Office365 the flag Flagged does
not seem to be well synced.
not seem to be well synced. What can I do?
R. Use the following trick. Run imapsync twice, one with --regexflag
and one without, like this:
@ -128,7 +220,15 @@ With STORE it sets and gets the "\Flagged" flag everywhere.
Thanks to Dave Murray and Simon Savva for reporting and solving
this issue.
======================================================================
Q. Exchange and Office365 have throttle mechanisms to limit any huge
usage. Sometimes imapsync transfers are too stressful for servers.
How to deal with that?
R. It looks like limiting 4 messages per second is enough to never
reach any throttle limit.
imapsync ... --maxmessagespersecond 4
======================================================================
Q. How to migrate from or to Exchange 2007/2010 with an
@ -245,8 +345,7 @@ In case you are not aware:
=======================================================================
Q. Couldn't create folder [trash] from [INBOX.trash]:
588 NO Mailbox already exists.
Q. Couldn't create folder [trash] "Mailbox already exists".
R. Some servers take care about character case in folder names,
some servers do not, like Exchange. Since non-respecting case
@ -275,10 +374,13 @@ R. Some servers take care about character case in folder names,
mandatory, otherwise imapsync will sync messages from the
first Trash and then delete them when syncing trash.
In order to avoid merging folders that are considered different
on host1 but the same on destination host2 because of case
sensitivities and insensitivities, use --nomixfolders
======================================================================
Q. Migrating to Exchange 201O, messages get date of the transfer,
this is bad for sorting and listing.
this is bad for sorting and listing. What can I do?
R1. Be sure to have at least Exchange 2010 SP2 Rollup 5
http://www.tribalchicken.com.au/15-technical/29-imapsync-exchange2010
@ -291,7 +393,7 @@ It's often shorter to change one server than thousands clients
so R1 might be easier to do.
======================================================================
Q. From any to Exchange2007
Q. How to sync from any to Exchange2007?
Several problems:
- Big messages: increase the "send- and receive-connector"
@ -310,10 +412,9 @@ Two users succeeded by using "MS Transporter Suite" (which is closed
expensive non-free software).
======================================================================
Q. From Microsoft Exchange 2000 IMAP4rev1 server version 6.0.6487.0.
Q. How to sync from Microsoft Exchange 2000 IMAP4rev1 server?
R. imapsync ... \
--prefix1 INBOX.
R. imapsync ... --prefix1 "INBOX."
=======================================================================

View file

@ -1,5 +1,5 @@
#!/bin/cat
$Id: FAQ.Flags.txt,v 1.3 2015/04/03 21:05:11 gilles Exp gilles $
$Id: FAQ.Flags.txt,v 1.4 2015/07/18 22:35:27 gilles Exp gilles $
======================================================================
Imapsync and flags

View file

@ -1,9 +1,9 @@
#!/bin/cat
$Id: FAQ.Folders_Mapping.txt,v 1.5 2015/05/11 10:36:33 gilles Exp gilles $
$Id: FAQ.Folders_Mapping.txt,v 1.8 2015/12/03 02:37:45 gilles Exp gilles $
===========================================
Imapsync changing folders names
===========================================
======================================================================
Imapsync. Changing folders names
======================================================================
Things to know and understand before playing with --regextrans2
@ -61,18 +61,23 @@ Q. Give examples about --regextrans2
Examples:
1) To remove INBOX. in the name of destination folders:
1) To remove INBOX. in the name of destination folders
--regextrans2 's/^INBOX\.(.+)/$1/'
imapsync ... --regextrans2 's/^INBOX\.(.+)/$1/'
2a) To sync all folders to INBOX:
2) To change only INBOX to Inbox_Migrated
imapsync ... --regextrans2 's{^INBOX$}{Inbox_Migrated}'
2a) To sync all folders to INBOX
imapsync ... --regextrans2 "s/.*/INBOX/"
2b) To sync a complete account in a subfolder called FOO:
2b) To sync a complete account in a subfolder called FOO
Since imapsync release 1.641 simply use:
Since imapsync release 1.641 simply use
imapsync ... --subfolder2 FOO
@ -130,6 +135,21 @@ On Windows:
--regextrans2 s,\^",_,g
3c) to substitute all characters *%. by underscores _
You can increase the *%. list by any unwanted character.
On Linux/Unix:
--regextrans2 'tr,*%.#,_,'
On Windows:
--regextrans2 "tr,*%.#,_,"
3d) It is a bad idea to substitute & characters since &
is a character to encode non-ascii characters in IMAP folder names.
4) to change folder names like this:
[mail/Sent Items] -> [Sent]

199
FAQ.d/FAQ.Gmail.txt Executable file → Normal file
View file

@ -1,13 +1,78 @@
#!/bin/cat
$Id: FAQ.Gmail.txt,v 1.2 2015/05/11 01:11:40 gilles Exp gilles $
$Id: FAQ.Gmail.txt,v 1.13 2015/11/05 21:01:12 gilles Exp gilles $
======================================================================
Imapsync with Gmail
======================================================================
Questions anwswered in this FAQ are:
Q. Can I use imapsync to transfer from or to Gmail accounts?
Q. How to synchronize from Gmail to Gmail?
Q. How to synchronize from XXX to Gmail?
Q. How to synchronize from Gmail to XXX?
Q. How to avoid the [IMAP] prefix on Gmail side?
Q. I can't authenticate with Gmail via IMAP
and Gmail says "Please log in via your web browser"
Q. Can not open imap connection on [imap.gmail.com]
Q. Gmail does not really delete messages in folder [Gmail]/All Mail
Q. Does imapsync have the capability to do 2 stage authentication?
Q. How to use XOAUTH2 to globally authenticate gmail users?
Q. How to use XOAUTH to globally authenticate gmail users?
Q. How to use a Gmail account to backup several different imap accounts?
Q. How to migrate email from gmail to google apps?
=======================================================================
Q. Synchronizing from XXX to Gmail
Q. Can I use imapsync to transfer from or to Gmail accounts?
R. Yes. But IMAP access to a Gmail account is not allowed by default so
it has to be allowed in the Gmail configuration part:
-> Settings
-> Forwarding and POP/IMAP
-> IMAP Access
-> Enable IMAP
=======================================================================
Q. How to synchronize from Gmail to Gmail?
R. Use the following example:
./imapsync \
--host1 imap.gmail.com \
--ssl1 \
--user1 account1@gmail.com \
--password1 gmailsecret1 \
--host2 imap.gmail.com \
--ssl2 \
--user2 account2@gmail.com \
--password2 gmailsecret2 \
--exitwhenover 500000000 \
--exclude "\[Gmail\]$"
Explanations:
--ssl1 --ssl2 are mandatory since Gmail only supports
imap ssl connections.
--exitwhenover 500000000 ( ~500 MB ) option is here to avoid
locking or errors when transfers exceed maximum limit.
See http://support.google.com/a/bin/answer.py?hl=en&answer=1071518
--exitwhenover is not mandatory in the sense you may be able to
use an upper value than 500 MB without disconnections; I don't
know the hard value, it seems to vary, so just have some tries
and report me what you discover in case you detect something
reliable.
--exclude "\[Gmail\]$" is just there to avoid a warning error
when selecting this not used folder.
=======================================================================
=======================================================================
Q. How to synchronize from XXX to Gmail?
R. There are some details to get the special [Gmail] sub-folders
right. Here's an example of migrating an old "Sent" folder to
@ -102,31 +167,23 @@ unselect some "System labels", depending on your needs.
The "All Mail" archive pseudo-folder should be updated automatically.
=======================================================================
Q. Some of the folders are getting created with [IMAP] prefix on Google
side. How to stop creating folder with this prefix?
Any switch we can use? e.g. [IMAP]/Archive
Q. How to synchronize from Gmail to XXX?
R. No switch in imapsync since [IMAP]/ prefix is done by Gmail,
it might be configurable with Gmail parameters.
=======================================================================
Q. Synchronizing from Gmail to XXX
R. Gmail needs SSL
R. Use this example:
./imapsync \
--host1 imap.gmail.com \
--user1 gilles.lamiral@gmail.com \
--password1 gmailsecret \
--host2 localhost
--host2 localhost \
--user2 tata \
--password2 tatasecret \
--ssl1 \
--exitwhenover 2500000000 \
--useheader="X-Gmail-Received" \
--useheader "Message-Id" \
--regextrans2 "s,\[Gmail\].,," \
--skipcrossduplicates \
--folderfirst "Work" \
--folderfirst "Friends" \
@ -138,8 +195,9 @@ Explanations:
--ssl1 is mandatory since Gmail only supports imap ssl connections.
--exitwhenover 2500000000 option is here to avoid locking when
transfers exceed maximum limit.
--exitwhenover 2500000000 (2.5 GB) option is here to avoid
locking when transfers exceed maximum limit.
See http://support.google.com/a/bin/answer.py?hl=en&answer=1071518
--exitwhenover is not mandatory in the sense you may be able to
use an upper value than 2.5 GB without disconnections; I don't
@ -154,9 +212,9 @@ by imapsync can not fail using this header. "Message-Id" is there
for safety about this Gmail rule.
If your destination imap server doesn't like "[Gmail]" name, just add
option:
--regextrans2 's/\[Gmail\]/Gmail/'
--regextrans2 "s,\[Gmail\].,,"
If your destination imap server doesn't like "[Gmail]" name,
get rid of this "[Gmail]" part with that.
You can select folders exported to imap within the gmail preferences,
for example you may unselect all "System labels".
@ -186,9 +244,17 @@ label CanWait and only it.
--skipcrossduplicates, will only put in "[Gmail]/All Mail"
the messages that are not labeled at all.
=======================================================================
Q. How to avoid the [IMAP] prefix on Gmail side?
How to stop creating folder with this prefix?
Any switch we can use? e.g. [IMAP]/Archive
R. No switch in imapsync since [IMAP]/ prefix is done by Gmail,
it might be configurable within Gmail parameters configuration.
=======================================================================
Q. I can't authenticate with Gmail via IMAP
Gmail says "Please log in via your web browser"
and Gmail says "Please log in via your web browser"
R1. See Coert Grobbelaar solution:
https://security.stackexchange.com/questions/86404/how-do-i-interact-with-google-to-import-email-via-imapsync
@ -200,6 +266,38 @@ so I logged for this account via a web browser,
it asked me to receive a code via a mobile, I said yes,
I entered the code and everything went ok.
R3. Use https://www.google.com/settings/security/lesssecureapps
(thanks to Flavio Zarur)
See https://support.google.com/accounts/answer/6010255?hl=en
=======================================================================
Q. Can not open imap connection on [imap.gmail.com]:
Unable to connect to imap.gmail.com
R0. It looks like this issue is related to ipv6. Both ipv4 and ipv6
protocols should work with gmail and imapsync, I test that regurlarly,
imapsync works fine for both ipv4 and ipv6.
If you disable ipv6 then disable also ipv6 resolution or at least
make ipv4 answers be taken before ipv6 since default resolution
order is to take ipv6 resolution if any.
R1. A first simple solution is to use directly gmail ipv4 ip address:
imapsync ... --host1 74.125.133.108
In case it changes, get with any command showing the imap.gmail.com resolution
nslookup imap.gmail.com
host imap.gmail.com
ping imap.gmail.com
Or go to http://ping.eu/nslookup/ to get the resolution.
R2. Fix imapsync with the line:
use IO::Socket::SSL 'inet4' ;
Thanks to Chris Nolan to report, understand and fix this issue!
=======================================================================
Q. Gmail does not really delete messages in folder [Gmail]/All Mail
What happens? What can I do?
@ -212,61 +310,42 @@ be moved to the "Trash" folder and be deleted from "Trash".
=======================================================================
Q. Does imapsync have the capability to do 2 stage authentication for google.
Q. Does imapsync have the capability to do 2 stage authentication?
R. No, imapsync doesn't support 2 stage authentication.
Reading https://support.google.com/mail/answer/1173270?hl=en
it looks like it can't because imapsync uses imap protocol.
So you have to follow the Google recommendation and generate an
application-specific password or normal authentication or XOAUTH.
application-specific password or normal authentication
or use XOAUTH or XOAUTH2.
=======================================================================
Q. Is XOAUTH2 authentication available with imapsync?
Q. How to use XOAUTH2 to globally authenticate gmail users?
R. Yes but only on Unix systems and not really well documented. See
* http://www.linux-france.org/prj/imapsync_list/msg02129.html
* https://github.com/imapsync/imapsync/pull/25/files
R. Yes, but really tested on Unix systems, not sure on Windows. See:
http://imapsync.lamiral.info/FAQ.d/FAQ.XOAUTH2.txt
=======================================================================
Q. How to use XOAUTH to globally authenticate gmail users?
The XOAUTH code and this FAQ item come from Eduardo Bortoluzzi
Thanks Eduardo!
R. The goal of OAUTH is to migrate all users from/to Google Apps
Premier Edition without knowing their passwords.
The global password is available at the Google Apps control panel,
at Advanced Tools -> Manage OAuth domain key.
./imapsync \
--host1 imap.gmail.com --ssl1 \
--user1 foo@lab3.dedal.br \
--password1 secret1 \
--authmech1 XOAUTH \
--host2 imap.gmail.com --ssl2 \
--user2 bar@lab3.dedal.br \
--password2 secret2 \
--authmech2 XOAUTH
Google Apps is a paid service, but you can try it for 30 days without any cost.
Some notes about configuring the Google Apps XOAUTH:
On "Advanced Tools > Manage OAuth domain key > Two-legged OAuth access control"
the "Allow access to all APIs" must be checked
(https://support.google.com/a/bin/answer.py?answer=162105)
OR
On "Advanced Tools > Manage third party OAuth client access",
the configured costumer key must have the scope
"https://mail.google.com/" configured
(https://support.google.com/a/bin/answer.py?answer=162106).
R0. XOAUTH is considered obsolete and superseded by XOAUTH2
See http://imapsync.lamiral.info/FAQ.d/FAQ.XOAUTH2.txt
=======================================================================
Q. migrate email from gmail to google apps
Q. How to use a Gmail account to backup several different imap accounts?
R. For each account named xxx use:
imapsync ... --subfolder2 xxx/xxx
It syncs the account xxx under a sub-subfolder xxx/xxx. This way there
is no supplementary label created on the multi-archive Gmail
destination account. No labels all over the place and all original
xxx sub-folders show up nested within xxx/xxx.
=======================================================================
Q. How to migrate email from gmail to google apps?
R. Take a look at:
http://www.linux-france.org/prj/imapsync_list/msg00639.html

72
FAQ.d/FAQ.ISP.txt Normal file
View file

@ -0,0 +1,72 @@
#!/bin/cat
$Id: FAQ.ISP.txt,v 1.2 2015/10/21 15:23:07 gilles Exp gilles $
=================================================
Imapsync. ISP specific issues and solutions
=================================================
* IMAP Sync - usage scenario with ISP - by Flávio Zarur Lucarelli.
I thought Id write a quick step by step on my attempts to learn the
imapsync features that matter the most, so it works as we expected in
the cenario in which we use it, which is to migrate customers from
their old ISP to our ISP/email hosting. Thanks to the master Gilles
Lamiral for all his help and hard work.
First of all, remember to use --dry to test things first always and
check the log file to see what would actually happen.
My first goal is to have an exact sync of an account from
current/source host to the new/destination host and be able to sync
several times. The --useuid parameter is very important for that
purpose. This is what I use:
imapsync --host1 imap.gmail.com --user1 user@domain.com --password1 pwd --ssl1 --host2 imap.myisp.com --user2 user@domain.com --password2 pwd --ssl2 --useuid --delete2 --delete2folders
This makes it so imap.myisp.com (destination) is an exact copy of the
account at imap.gmail.com (source). This is not a problem, since the
user is not using the new host yet. ]You can check Imapsync log files
and surely you will see the final difference should be 0. Check also
for any possible errors in the log (search for "error").
The second goal is to lower the TTL (ex: 5 min) for the host
associated with the MX record, in the domain's DNS server. Let's say
customer has a host mail which his MX points to, with a high TTL
(usually 1 hour). Lower it to 5 min so that, when you change the MX,
it propagates faster.
When comes time to switch over to the new host, do a final sync with
above syntax, before changing the MX. Then, change the MX and tell
your users to start using exclusively the new host.
A few hours after the MX change, we will run Imapsync again. We have
to start preserving emails users move or flag in the new host, which
they started using, so we can't do an exact sync anymore.
The best solution for me was to Sync any new emails (maxage:1) from
source (that could arrive in source even after MX change, due to
cache) and delete such emails from source server. This way, customer's
mailbox is still intact on the source server, except new emails, which
get synced to new server and deleted from source.
imapsync --host1 imap.gmail.com --user1 user@domain.com --password1 pwd --ssl2 --folder INBOX --useuid --noexpungeaftereach --skipemptyfolders --maxage 1 --delete1
I personally prefer to keep a copy of users box intact in source, but
if that's not an issue for you, you can remove --folder INBOX and even
--maxage, but then, all emails in source will be deleted. You can use
--maxage 1 with --delete1, however, for all folder (without specifying
--folder INBOX), so only any new email that arrives at source is
copied to destination and deleted from source.
My next goal was to automate the process, so I followed this advice:
http://imapsync.lamiral.info/examples/sync_loop_unix.sh
I also ended up requiring a regex to translate folder names. On the
old server (Gmail), Sent items were in a folder called [Gmail]/E-mails
enviados and on the new server, its simply called SENT. Same with
lixeira (trash) and rascunhos (drafts).
So this was added:
--regextrans2 "s,\[Gmail\].,," --regextrans2 "s,E-mails enviados,Sent," --regextrans2 "s,/Lixeira,Trash," --regextrans2 "s,/Rascunhos,Drafts,"

87
FAQ.d/FAQ.Massive.txt Executable file → Normal file
View file

@ -1,5 +1,5 @@
#!/bin/cat
$Id: FAQ.Massive.txt,v 1.1 2015/03/26 05:06:27 gilles Exp gilles $
$Id: FAQ.Massive.txt,v 1.5 2015/11/05 14:46:20 gilles Exp gilles $
======================================================================
Imapsync for massive migrations
@ -10,49 +10,55 @@ Questions answered here are:
Q. I need to migrate hundred accounts, how can I do?
Q. I have to migrate 500k users using 400 TB of disk space.
How do I proceed?
Q. How to determine what is the bottleneck in my current imapsync process?
=======================================================================
Q. I need to migrate hundred accounts, how can I do?
R. If you have many mailboxes to migrate think about a little
shell program. Write a file called file.txt (for example)
containing users and passwords.
script program. Write a file called file.txt (for example)
containing hosts users and passwords on both sides.
The separator used in this example is ";"
The file.txt file contains:
The file.txt file contains for example:
user001_1;password001_1;user001_2;password001_2
user002_1;password002_1;user002_2;password002_2
user003_1;password003_1;user003_2;password003_2
user004_1;password004_1;user004_2;password004_2
user005_1;password005_1;user005_2;password005_2
...
host001_1;user001_1;password001_1;host001_2;user001_2;password001_2;
host002_1;user002_1;password002_1;host002_2;user002_2;password002_2;
host003_1;user003_1;password003_1;host003_2;user003_2;password003_2;
host004_1;user004_1;password004_1;host004_2;user004_2;password004_2;
etc.
On Unix the shell program can be:
On Unix the shell script can be:
{ while IFS=';' read u1 p1 u2 p2; do
imapsync --host1 imap.side1.org --user1 "$u1" --password1 "$p1" \
--host2 imap.side2.org --user2 "$u2" --password2 "$p2" ...
done ; } < file.txt
#!/bin/sh
{ while IFS=';' read h1 u1 p1 h2 u2 p2 fake
do
imapsync --host1 "$h1" --user1 "$u1" --password1 "$p1" \
--host2 "$h2" --user2 "$u2" --password2 "$p2"
done
} < file.txt
Here is a complete Unix example nearly ready to use:
Here is a complete Unix example ready to use:
http://imapsync.lamiral.info/examples/sync_loop_unix.sh
On Windows the batch program can be:
On Windows the batch script can be:
FOR /F "tokens=1,2,3,4 delims=; eol=#" %%G IN (file.txt) DO imapsync ^
--host1 imap.side1.org --user1 %%G --password1 %%H ^
--host2 imap.side2.org --user2 %%I --password2 %%J ...
CD /D %~dp0
SET csvfile=file.txt
FOR /F "tokens=1,2,3,4,5,6 delims=; eol=#" %%G IN (%csvfile%) DO (
imapsync ^
--host1 %%G --user1 %%H --password1 %%I ^
--host2 %%J --user2 %%K --password2 %%L ...
)
The ... can be replaced by nothing or any supplementary imapsync option.
The final ... can be replaced by nothing or any supplementary imapsync option.
Here is a complete Windows example nearly ready to use:
http://imapsync.lamiral.info/examples/sync_loop_windows.bat
=======================================================================
Q. I have to migrate 500k users using 400 TB of disk space.
How do I proceed?
@ -63,13 +69,15 @@ they can be processed independently.
500k on 400TB is 800 MB per account on average.
No one knows in advance what is the first bottleneck. The first
bottleneck has to be determined, by measurements, not by guesses.
Once this first bottleneck is known and overcome then the next
bottleneck has to be determined and overcome too, if needed. Repeat
the process of looking for the next bottleneck and its resolution
until you estimate the transfer rates, money costs and final dates are
good enough to proceed the whole 500k/400TB migration.
On any process involving several mechanisms there is always a
bottleneck among all elements taking part on the process. No one knows
in advance what is the first bottleneck. The first bottleneck has to
be determined, by measurements, not by guesses. Once this first
bottleneck is known and overcome then the next bottleneck has to be
determined and overcome too, if needed. Repeat the process of looking
for the next bottleneck and its resolution until you estimate the
transfer rates, money costs and final dates are good enough to proceed
the whole 500k/400TB migration.
Possible bottlenecks:
@ -96,3 +104,22 @@ Possible bottlenecks:
- Bad luck.
- ...
=======================================================================
Q. How to determine what is the bottleneck in my current imapsync process?
R. Divide and conquer.
In order to detect whether host1/link1 is the bottleneck or
host2/link2, we have several tests to explore:
1) run a sync from host1 to host1, with a host1 test account as destination.
This way, only host1+link1 are tested. host2 is not concerned.
If performances increase a lot then host2/link2 is the bottleneck.
2) run a sync from host2 to host2, with a host2 test account as destination.
This way, only host2+link2 are tested. host1 is not concerned.
If performances increase a lot then host1/link1 is the bottleneck.
If performances increase on both tests 1) and 2), I have no clue to explain that.
Same thing if they both decrease!

View file

@ -0,0 +1,93 @@
#!/bin/cat
$Id: FAQ.Messages_selection.txt,v 1.2 2015/10/21 15:39:57 gilles Exp gilles $
====================================
Imapsync. How to select messages
====================================
=======================================================================
Q. Is there a way we can specify a date range to sync emails?
If yes, can you please share an example?
R. Yes, with the --search option.
imapsync ... --search "SENTSINCE 1-Jan-2010 SENTBEFORE 31-Dec-2010"
Jan
Feb
Mar
Apr
May
Jun
Jul
Aug
Sep
Oct
Nov
Dec
=======================================================================
Q. Is there a way we can specify an age to sync emails?
If yes, can you please share some examples?
R. Yes, with the --maxage or the --minage option.
E.1 Sync only messages less than 2 days old:
imapsync ... --maxage 2
E.2 Sync only messages more than 2 days old:
imapsync ... --minage 2
E.3 Sync only messages more than 30 days old and less than 365 days old:
imapsync ... --minage 30 --maxage 365
E.4 Sync only messages less than 30 days old or more than 365 days old:
imapsync ... --maxage 30 --minage 365
Full explanation:
--maxage <int> : Skip messages older than <int> days.
final stats (skipped) don't count older messages
see also --minage
--minage <int> : Skip messages newer than <int> days.
final stats (skipped) don't count newer messages
You can do (+ are the messages selected):
past|----maxage+++++++++++++++>now
past|+++++++++++++++minage---->now
past|----maxage+++++minage---->now (intersection)
past|++++minage-----maxage++++>now (union)
=======================================================================
Q. I want to sync messages based on their UID.
R. First have in mind that UIDs are uniq only per folder, so work this
way only with one folder at a time, with --folder option.
To show UIDs, there is the --debugLIST parameter.
imapsync ... --debugLIST
To sync only a part of all messages, selected by UIDs
from 10000 to 11000:
imapsync ... --search1 "UID 10000:11000"
To sync from INBOX only 3 messages UIDs 20000 20002 20004:
imapsync ... --search1 'OR OR UID 20000 UID 20002 UID 20004' --folder INBOX
To sync all messages from INBOX except 3 messages
UIDs 20000 20002 20004:
imapsync ... --search1 'NOT OR OR UID 20000 UID 20002 UID 20004' --folder INBOX
If you search n UIDs then you have to put n-1 OR in the search line.
That's IMAP.

15
FAQ.d/FAQ.Oracle-UCS.txt Normal file
View file

@ -0,0 +1,15 @@
#!/bin/cat
$Id: FAQ.Oracle-UCS.txt,v 1.1 2015/07/20 04:34:32 gilles Exp gilles $
=======================================================================
Imapsync. Oracle-UCS specific issues and solutions
=======================================================================
Oracle-UCS was previously Sun JES, IPlanet, etc.
"NO Message contains NUL characters"
--skipmess 'm/(\x00)+\Z/'
"Message contains invalid header"
--skipmess 'm/[\x80-\xff]/'

21
FAQ.d/FAQ.Security.txt Normal file
View file

@ -0,0 +1,21 @@
#!/bin/cat
# $Id: FAQ.Security.txt,v 1.1 2015/10/21 14:18:27 gilles Exp gilles $
======================================================================
Imapsync. Security issues and solutions
======================================================================
======================================================================
Q. Imapsync used to use SSL_VERIFY_PEER now it uses SSL_VERIFY_NONE.
How can I change this back to the more secure SSL_VERIFY_PEER?
R1. In function "sub set_ssl", replace
IO::Socket::SSL::SSL_VERIFY_NONE()
by
IO::Socket::SSL::SSL_VERIFY_PEER()
C1. Don't do this in function "sub set_tls" since it won't work by principle,
tls is done AFTER the application level connexion is established

46
FAQ.d/FAQ.SmarterMail.txt Executable file
View file

@ -0,0 +1,46 @@
#!/bin/cat
$Id: FAQ.SmarterMail.txt,v 1.6 2015/11/30 02:58:25 gilles Exp gilles $
=======================================================================
Imapsync. SmarterMail specific issues and solutions
=======================================================================
=======================================================================
Q. Synchronizing from SmarterMail to XXX
On Unix:
imapsync --host1 imap.d1.org --user1 joe --password1 secret1 \
--host2 imap.d2.org --user2 joe --password2 secret2 \
--sep1 "/" --prefix1 "" --useheader Message-Id \
--regextrans2 "s,Deleted Items,Trash," \
--regextrans2 "s,Junk E-Mail,Junk," \
--regextrans2 "s,Sent Items,Sent,"
On Windows:
imapsync.exe --host1 imap.d1.org --user1 joe --password1 secret1 ^
--host2 imap.d2.org --user2 joe --password2 secret2 ^
--sep1 "/" --prefix1 "" --useheader Message-Id ^
--regextrans2 "s,Deleted Items,Trash," ^
--regextrans2 "s,Junk E-Mail,Junk," ^
--regextrans2 "s,Sent Items,Sent,"
Maybe add other --regextrans2 to change folder names, for this
see also http://imapsync.lamiral.info/FAQ.d/FAQ.Folders_Mapping.txt
=======================================================================
Q. Synchronizing from XXX to SmarterMail
On Unix:
imapsync --host1 imap.d1.org --user1 joe --password1 secret1 \
--host2 imap.d2.org --user2 joe --password2 secret2 \
--sep2 "/" --prefix2 "" --useheader Message-Id
On Windows:
imapsync.exe --host1 imap.d1.org --user1 joe --password1 secret1 ^
--host2 imap.d2.org --user2 joe --password2 secret2 ^
--sep2 "/" --prefix2 "" --useheader Message-Id
=======================================================================

View file

@ -0,0 +1,283 @@
#!/bin/cat
$Id: FAQ.Various_Server_Softwares.txt,v 1.2 2015/10/21 15:41:41 gilles Exp gilles $
=======================================================================
Imapsync. Server software specific issues and solutions
=======================================================================
=======================================================================
Q. From Zimbra to XXX
imapsync ... \
--exclude "Conversation Action Settings" \
--exclude "Quick Step Settings" \
--exclude "News Feed"
=======================================================================
Q. From or to HMailServer version 4.4.1.
R. You have to add prefix and separator manually because 4.4.1 doesn't
honor the NAMESPACE imap command.
Example for host1:
imapsync ... \
--prefix1 "" --sep1 .
No specific option for HMailServer 5.3.3 since NAMESPACE is supported.
Maybe --subscribe_all will help you to see all migrated folders.
=======================================================================
Q. Synchronizing from Kerio Connect to XXX
R. No special options required.
See also:
http://www.linux-france.org/prj/imapsync_list/msg01756.html
http://www.safetynet-it.com/it-support/mac-kerio-server-to-microsoft-exchange-2010-migration-1/
http://www.safetynet-it.com/it-support/mac-kerio-server-to-microsoft-exchange-2010-migration-2/
=======================================================================
Q. Synchronizing from Yahoo to XXX
R. Use --host1 imap.mail.yahoo.com --ssl1
./imapsync \
--host1 imap.mail.yahoo.com \
--user1 billy \
--password1 secret \
--ssl1 \
--host2 XXX \
--user2 billy \
--password2 secret
SSL is mandatory for yahoo since november 2011.
=======================================================================
Q. from Microsoft's Exchange 2007 to Google Apps for your Domain
(GAFYD)
R. Take a look at:
http://mark.ossdl.de/2009/02/migrating-from-exchange-2007-to-google-apps-mail/
=======================================================================
Q. Migrating from or to Parallels Plex Server
R. It depends on the OS
Parallells Plesk Panel for Windows requires --sep2 / --prefix2 ""
Parallells Plesk Panel for Linux works with default parameters.
=======================================================================
Q. I'm migrating from WU to Cyrus, and the mail folders are under
/home/user/mail but the tool copies everything in /home/user, how
can i avoid that?
Two solutions:
R. Use
imapsync ... --include '^mail'
R. or (better)
imapsync ... --subscribed --subscribe
=======================================================================
Q. I'm migrating from WU to Cyrus, and the mail folders are under
/home/user/mail directory. When imapsync creates the folders in
the new cyrus imap server, it makes a folder "mail" and below that
folder puts all the mail folders the user have in /home/user/mail,
i would like to have all those folders directly under INBOX.
R. Use
imapsync ... --regextrans2 's/^mail/INBOX/' --dry
look at the simulation and if all transformations seem
good then remove the --dry option.
=======================================================================
Q. Migrating from Groupwise to Cyrus
R. By Jamie Neil:
I eventually managed to get the mail to migrate without errors using the
following options:
--sep1 /
- doesn't report separator so has to be set explicitly.
--nosyncacls
- doesn't support ACLs.
--skipheader '^Content-Type'
- MIME separator IDs seem to change every time a mail is accessed so
this is required to stop duplicates.
--maxage 3650
- some messages just don't seem to want to transfer and produce the
perl errors I mentioned before. This prevents the errors, but the
bad messages don't transfer.
Even though the mail migrated OK, there are a couple of gotchas with
Groupwise IMAP:
1) Some of the GW folders are not real folders and are not available
to IMAP, the main problem one being "Sent Items". I could find no way
of coping the contents of these folders. The nearest I got was to
create a "real" folder and copy/move the sent items into it, but
imapsync still didn't see the messages (I think because there is
something funny about the reported dates/sizes).
It think this problem has been rectified in GW6.5.
2) The "skipheader '^Content-Type'" directive is required to stop
duplicate messages being created. GW seems to generate this field on
the fly for messages that have MIME separators and so it's different
every time.
3) Version 6.0.1 of the Groupwise Internet Connector sucks. I was
getting server aborts when I pushed it a bit hard! I eventually had to
upgrade to 6.0.4 which seems to be a lot more stable.
=======================================================================
Q. Migrating from iPlanet Messaging Server
5.2 Patch 2 (built Jul 14 2004)) to Groupwise 7.0
I encounter many errors like this:
"Error trying to append string: 17847 BAD APPEND"
R. GroupWise 7 seems buggy. Apply GroupWise 7 support pack 1
=======================================================================
Q. Migrating from David Tobit V10 (DvISE Mail Access Server MA-...)
R. Use the following options:
imapsync ... --prefix1 "" --sep1 / --idatefromheader ^
--nofoldersizes --useuid --nocheckmessageexists
=======================================================================
Q. Migrating from David Tobit V8
("* OK IMAP4rev1 DvISE Mail Access Server MA-8.10a (0126)")
First try above V10 solution since improvments have been made
to support Tobit.
R. Use the following options :
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
patch saved in ./patches/imapsync-1.337_tobit_V6.patch
=======================================================================
Q. I need to migrate 1250 mailboxes, passwords are in a MySQL Database.
Can you tell me if your script suits my needs?
R. Mailboxes must exist before running imapsync.
You have to extract users logins and passwords in a csv file.
See the "HUGE MIGRATION" section in the README file.
======================================================================
Q: From MailEnable 1.75
R: --sep1 "/" --prefix1 ""
Q: From MailEnable 2.2
R: --sep1 "." --prefix1 ""
Q: To MailEnable
R: --sep2 / --prefix2 "" --addheader --messageidnodomain --syncflagsaftercopy
======================================================================
Q. From GMX IMAP4 StreamProxy
R. Use:
--prefix1 INBOX and --sep1 .
======================================================================
Q. From Courier to Archiveopteryx
R. You can read http://www.archiveopteryx.org/migration/imapsync
Default values might be fine now with latest imapsync.
======================================================================
Q. To Sun Java(tm) System Messaging Server 6.2-7.05
Q. To Communigate Pro - Solaris version
R. See and run patches/imapsync_1.267_jari
======================================================================
Q. From Softalk Workgroup Mail 7.6.4
R. Old Softalk releases don't support the IMAP SEARCH command.
Here are the options to get it working.
imapsync ... --sep1 '.' --prefix1 '' \
--noabletosearch --nocheckmessageexists --addheader
(Thanks to Andrew Tucker)
======================================================================
Q. From or to QQMail IMAP4Server
R. imapsync ... --noabletosearch
======================================================================
Q. From FirstClass to XXX
http://www.firstclass.com/
R. Migrating from FirstClass is not easy because FirstClass, strangely,
does not show all messages via IMAP. To make it show all messages,
a trick, painful to follow by hand, is moving emails
out and back in, for each folder. May be it can be done by a script.
FirstClass releases prior to release 12 do not shows the "Sent"
folder in IMAP but FirstClass release 12 shows it.
I advice you to upgrade to FirstClass release 12 before leaving it
with imapsync or another imap tool.
Here is a command line used to migrate from FirtClass release 12:
imapsync ... \
--tmpdir /var/tmp --usecache \
--useheader Message-ID \
--idatefromheader \
--addheader \
--regextrans2 "s,(/|^) +,\$1,g" --regextrans2 "s, +(/|$),\$1,g" \
--regextrans2 "s/[\^]/_/g" \
--regextrans2 "s/['\"\\\\]/_/g" \
--regextrans2 "s,&AC8-,-,g" \
--regextrans2 "s,&APg-,oe,g"
On Windows, in the previous example containing \$1 you have to
replace the two \$1 by $1 (remove the \ before $).
Special thanks to Kristian Wind and Joey Alexander for helping me
writing this FAQ item.
See also this worth reading discussion in a Zimbra forum:
http://www.zimbra.com/forums/migration/20349-help-needed-migrating-firstclass.html
======================================================================
Q. From XXX to FTGate
R. Do NOT use --usecache since new UIDs are not given by FTGate and also
badly guessed by imapsync. UIDEXPUNGE does not work so use also
--expunge2 when using --delete2
imapsync ... \
--sep2 / --prefix2 "" \
--useheader Message-Id \

110
FAQ.d/FAQ.XOAUTH2.txt Normal file
View file

@ -0,0 +1,110 @@
#!/bin/cat
$Id: FAQ.XOAUTH2.txt,v 1.6 2015/11/30 23:40:10 gilles Exp gilles $
=======================================================================
Imapsync. Using XOAUTH2 and XOAUTH authentication (Gmail)
=======================================================================
=======================================================================
Q. Is XOAUTH2 authentication available with imapsync?
R. Yes, but XOAUTH2 has been really tested on Unix systems,
less profund on Windows but it should work.
First, consider the XOAUTH2 feature at a prototype level.
Perl modules needed for xoauth2 are:
Crypt::OpenSSL::RSA
JSON
JSON::WebToken
LWP
HTML::Entities
A easy way to install or upgrade Perl modules is to use cpanm command,
also called cpanminus.
sudo cpanm JSON::WebToken JSON Crypt::OpenSSL::RSA LWP HTML::Entities
The code and first explanation comes from Joaquin Lopez at
https://github.com/imapsync/imapsync/pull/25
http://www.linux-france.org/prj/imapsync_list/msg02129.html
Also, the binary command "openssl" is needed since it is used to
convert the pk12 file.
On Windows I've tried xoauth2 with openssl from
https://slproweb.com/download/Win32OpenSSL-1_0_2d.exe at
https://slproweb.com/products/Win32OpenSSL.html
Here is a complete example for Gmail. It is a little stupid
since it is the same account as source and destination.
All xoauth2 is given via the --password1 parameter.
It has the form:
--password1 "A;B;C"
where A = 108687549524-gj68fg5ho5icoicv3v79dq2rcuf5c85e@developer.gserviceaccount.com
is the name of the Google Developer API service account.
where B = /g/var/pass/imapsync-xoauth2-15f8456ad5b7_notasecret.p12
is the location of the keyfile associated with it.
where C = notasecret
is the password to access the keyfile.
imapsync \
--host1 imap.gmail.com --ssl1 --user1 gilles.lamiral@gmail.com \
--password1 "108687549524-gj68fg5ho5icoicv3v79dq2rcuf5c85e@developer.gserviceaccount.com;/g/var/pass/imapsync-xoauth2-15f8456ad5b7_notasecret.p12;notasecret" \
--host2 imap.gmail.com --ssl2 --user2 gilles.lamiral@gmail.com \
--password2 "108687549524-gj68fg5ho5icoicv3v79dq2rcuf5c85e@developer.gserviceaccount.com;/g/var/pass/imapsync-xoauth2-15f8456ad5b7_notasecret.p12" \
--justfoldersizes --nofoldersizes \
--authmech1 XOAUTH2 --authmech2 XOAUTH2 --debug
Use your own xoauth2 values.
=======================================================================
Q. How to use XOAUTH to globally authenticate gmail users?
R0. XOAUTH is considered obsolete and superseded by XOAUTH2
Anyway the manage part might be the same (I don't know).
R1. The XOAUTH code and this FAQ item come from Eduardo Bortoluzzi
Thanks Eduardo!
R2. In case you still have to use XOAUTH, here is the method:
The goal of OAUTH is to migrate all users from/to Google Apps
Premier Edition without knowing their passwords.
The global password is available at the Google Apps control panel,
at Advanced Tools -> Manage OAuth domain key.
./imapsync \
--host1 imap.gmail.com --ssl1 \
--user1 foo@lab3.dedal.br \
--password1 secret1 \
--authmech1 XOAUTH \
--host2 imap.gmail.com --ssl2 \
--user2 bar@lab3.dedal.br \
--password2 secret2 \
--authmech2 XOAUTH
Google Apps is a paid service, but you can try it for 30 days without any cost.
Some notes about configuring the Google Apps XOAUTH:
On "Advanced Tools > Manage OAuth domain key > Two-legged OAuth access control"
the "Allow access to all APIs" must be checked
(https://support.google.com/a/bin/answer.py?answer=162105)
OR
On "Advanced Tools > Manage third party OAuth client access",
the configured costumer key must have the scope
"https://mail.google.com/" configured
(https://support.google.com/a/bin/answer.py?answer=162106).

15
INSTALL
View file

@ -1,4 +1,4 @@
# $Id: INSTALL,v 1.47 2015/03/16 16:36:10 gilles Exp gilles $
# $Id: INSTALL,v 1.48 2015/07/18 20:25:03 gilles Exp gilles $
#
# This is the main INSTALL file for imapsync.
# imapsync : IMAP sync and migrate tool.
@ -110,15 +110,18 @@ http://imapsync.lamiral.info/INSTALL.d/INSTALL.Mandriva.txt
Purchase imapsync at
http://imapsync.lamiral.info/
You'll have access to a compressed tarball called imapsync-x.xxx.tgz
where x.xxx is the version number. Untar the tarball where
or get it anywhere.
You have access to a compressed tarball called imapsync-1.xxx.tgz
where 1.xxx is the version number. Untar the tarball where
you want:
tar xzvf imapsync-x.xxx.tgz
cd
tar xzvf imapsync-1.xxx.tgz
Go into the directory imapsync-x.xxx
Go into the directory imapsync-1.xxx
cd imapsync-x.xxx
cd imapsync-1.xxx
You can easily detect any missing Perl modules via the
script prerequisites_imapsync located in the INSTALL.d directory:

View file

@ -1,3 +1,6 @@
#!/bin/cat
# $Id: INSTALL.CPanel.txt,v 1.4 2015/09/19 08:55:25 gilles Exp gilles $
=================================
= Installing imapsync on CPanel =
=================================

View file

@ -1,3 +1,5 @@
#!/bin/cat
# $Id: INSTALL.Centos.txt,v 1.4 2015/09/19 08:55:25 gilles Exp gilles $
=================================
= Installing imapsync on CentOS =
@ -22,14 +24,19 @@ A good test that shows also the basic example:
imapsync
A live test:
imapsync --testslive
Unit tests:
imapsync --tests
==============
== Centos 6 ==
==============
This section has not been tested with latest imapsync releases (2014 and after)
so it can fail. In case it happens, just write me at gilles.lamiral@laposte.net
and we will fix it together.
This section has been tested with imapsync release 1.644
First, install access to the Epel repository
@ -39,13 +46,22 @@ First, install access to the Epel repository
Then install all other packages via yum:
yum install \
perl-Mail-IMAPClient \
"perl(Term::ReadKey)" \
"perl(Authen::NTLM)" \
perl-Data-Uniqid \
perl-File-Copy-Recursive \
perl-IO-Tee \
perl-Unicode-String
perl-Digest-HMAC \
perl-NTLM \
perl-Compress-Zlib \
perl-Data-Uniqid \
perl-Digest-HMAC \
perl-File-Copy-Recursive \
perl-IO-Socket-SSL \
perl-IO-Socket-INET6 \
perl-IO-Tee \
perl-Mail-IMAPClient \
perl-Parse-RecDescent \
perl-TermReadKey \
perl-Test-Simple \
perl-Test-Pod \
perl-Unicode-String \
perl-URI

View file

@ -1,76 +1,73 @@
#!/bin/cat
# $Id: INSTALL.Darwin.txt,v 1.10 2015/09/19 08:55:25 gilles Exp gilles $
# $Id: INSTALL.Darwin.txt,v 1.6 2015/03/16 16:29:27 gilles Exp gilles $
===================================================
= Installing imapsync binary on Darwin / Mac OS X =
===================================================
============================================
= Installing imapsync on Darwin / Mac OS X =
============================================
First let's configure the cpan command in order it modify only a
very local installation, local to a user, the user you're logged in.
There is a standalone imapsync binary for Mac OS X called imapsync_bin_Darwin,
available in the compressed tarball called imapsync-1.xxx.tgz
where 1.xxx is the version number. I suppose this tarball is put
under your $HOME directory, let say /Users/gilles/, but you can
put it anywhere.
Open a terminal: /Applications/Utilities/Terminal double-click on Terminal.
In order to do a local install, we have to take a fresh start.
In this terminal, type the following (or better copy-paste this line and press RETURN):
rm -f .cpan/CPAN/MyConfig.pm
cpan
Untar the tarball where you want:
cpan should ask for an automatic configuration, say yes.
Example of output:
cd
tar xzvf /Users/gilles/imapsync-1.xxx.tgz
------------------------------------------------------------------------------
Would you like to configure as much as possible automatically? [yes]
...
What approach do you want? (Choose 'local::lib', 'sudo' or 'manual')
[local::lib]
------------------------------------------------------------------------------
Go into the directory imapsync-1.xxx
cd imapsync-1.xxx
At the end of the run, cpan might propose to add some lines in your .bashrc file.
Say yes. The output on the screen is something like the following:
First let's have a simple run to see if imapsync_bin_Darwin works.
You should see some help about options and an example at the end
of this run:
------------------------------------------------------------------------------
...
local::lib is installed. You must now add the following environment variables
to your shell configuration files (or registry, if you are on Windows) and
then restart your command line shell and CPAN before installing modules:
./imapsync_bin_Darwin
PERL_MB_OPT="--install_base \"/Users/gilles/perl5\""; export PERL_MB_OPT;
PERL_MM_OPT="INSTALL_BASE=/Users/gilles/perl5"; export PERL_MM_OPT;
To go further, perform a complete test with two
real IMAP server accounts:
Would you like me to append that to /home/Users/.bashrc now? [yes]
commit: wrote '/Users/gilles/.cpan/CPAN/MyConfig.pm'
...
------------------------------------------------------------------------------
./imapsync_bin_Darwin --testslive
You have to source (the command to source is "." ) your .bashrc and run the "cpan -i" command:
If this sync works fine then imapsync_bin_Darwin is ready for any
imap account synchronization.
. .bashrc
The next time you use cpan command, it will install Perl modules locally,
where you have permission to create files and directories, something like
the path /Users/gilles/perl5/ (where gilles is replaced by your login name).
===================================================
= Installing imapsync script on Darwin / Mac OS X =
===================================================
Next, let's get a script that will check your Perl installation.
Open a terminal: /Applications/Utilities/Terminal double-click on Terminal.
In this terminal, type the following (or better copy-paste this line and press RETURN):
curl -L http://imapsync.lamiral.info/INSTALL.d/prerequisites_imapsync > prerequisites_imapsync
wget --no-check-certificate -O- http://cpanmin.us | perl - -l ~/perl5 App::cpanminus local::lib
eval `perl -I ~/perl5/lib/perl5 -Mlocal::lib`
perl -I ~/perl5/lib/perl5 -Mlocal::lib
Now you should have a script named "prerequisites_imapsync" in the current directory.
Let's execute it with a shell, type:
echo 'eval `perl -I ~/perl5/lib/perl5 -Mlocal::lib`' >> ~/.profile
echo 'export MANPATH=$HOME/perl5/man:$MANPATH' >> ~/.profile
cat ~/.profile
cpanm CPAN
sh prerequisites_imapsync
curl -L http://imapsync.lamiral.info/INSTALL.d/prerequisites_imapsync > prerequisites_imapsync
sh prerequisites_imapsync
When "sh prerequisites_imapsync" command is ended it will propose you
to execute a "cpan -i ..." command to install the missing Perl modules.
The "..." in "cpan -i ..." have to be replaced by the list proposed
in the last output line of a "sh prerequisites_imapsync" run.
For example it can be:
cpanm Authen::NTLM
cpanm File::Copy::Recursive IO::Tee
cpanm Mail::IMAPClient
cpanm Unicode::String
cpan -i Authen::NTLM Data::Uniqid File::Copy::Recursive IO::Tee Mail::IMAPClient Unicode::String
wget -c http://imapsync.lamiral.info/imapsync
./imapsync
perl ./imapsync
perl ./imapsync --modules
cpanm Data::Uniqid
cpanm JSON::WebToken
Once you've run the "cpan -i" command, you can rerun "sh prerequisites_imapsync"
You can rerun "sh prerequisites_imapsync"
to verify everything is ok:
sh prerequisites_imapsync
@ -80,6 +77,20 @@ When everything is ok the script execution ends with this sentence
Now imapsync should work on your system.
=================================================
= Building imapsync binary on Darwin / Mac OS X =
=================================================
cpanm Module::ScanDeps
cpanm Module::ScanDeps
cpanm PAR::Packer
pp -o imapsync.bin imapsync
./imapsync.bin
./imapsync.bin --testslive
./imapsync.bin --tests
./imapsync.bin --module

View file

@ -1,3 +1,5 @@
#!/bin/cat
# $Id: INSTALL.Debian.txt,v 1.5 2015/09/19 08:55:25 gilles Exp gilles $
========================================
= Installing imapsync on Debian 6 or 7 =
@ -71,6 +73,10 @@ liburi-perl
perl -MCPAN -e "install Data::Uniqid"
perl -MCPAN -e "install Authen::NTLM"
perl -MCPAN -e "install Mail::IMAPClient"
Latest command is because the Perl module Mail::IMAPClient
is too old on Debian 6 (it's release "buggy" 3.25).
Now a good dependencies test that shows also the basic example:

View file

@ -1,7 +1,9 @@
#!/bin/cat
# $Id: INSTALL.FreeBSD.txt,v 1.6 2015/09/19 08:55:25 gilles Exp gilles $
==================================
= Installing imapsync on FreeBSD =
==================================
$Id: INSTALL.FreeBSD.txt,v 1.3 2015/03/16 16:32:06 gilles Exp gilles $
Thanks to Kurt Jaeger pi@FreeBSD.org a imapsync package is available in FreeBSD
http://portsmon.freebsd.org/portoverview.py?category=mail&portname=imapsync

View file

@ -1,3 +1,5 @@
#!/bin/cat
# $Id: INSTALL.Mandriva.txt,v 1.4 2015/09/19 08:55:25 gilles Exp gilles $
=====================================
== Installing imapsync on Mandriva ==

View file

@ -1,3 +1,5 @@
#!/bin/cat
# $Id: INSTALL.Ubuntu.txt,v 1.4 2015/09/19 08:55:25 gilles Exp gilles $
=================================
= Installing imapsync on Ubuntu =

View file

@ -1,5 +1,5 @@
NO LIMIT PUBLIC LICENSE
Version 0, June 2012
Version 0/0, June 2012
Gilles LAMIRAL
La Billais
@ -10,6 +10,6 @@ France
Terms and conditions for copying, distribution, modification
or anything else.
0 No limit to do anything with this work and this license.
0 No limits to do anything with this work and this license.
1 GOTO 0

105
Makefile
View file

@ -1,5 +1,5 @@
# $Id: Makefile,v 1.189 2015/07/17 17:36:56 gilles Exp gilles $
# $Id: Makefile,v 1.209 2015/12/03 03:25:22 gilles Exp gilles $
.PHONY: help usage all
@ -21,10 +21,14 @@ usage:
@echo "make W/test3.bat # run W/test3.bat on win32"
@echo "make W/test_reg.bat # run W/test_reg.bat on win32"
@echo "make W/test_exe_2.bat # run W/test_exe_2.bat on win32"
@echo "make prereq_win32 # run W/install_modules.bat on win32"
@echo "make examples/sync_loop_windows.bat # run examples/sync_loop_windows.bat on win32"
@echo "make win32_prereq # run W/install_modules.bat on win32"
@echo "make win32_update_ssl # run W/install_module_ssl.bat on win32"
@echo "make all "
@echo "make upload_tests # upload tests.sh"
@echo "make upload_index"
@echo "make upload_FAQ # upload FAQs and documentation"
@echo "make valid_index # check index.shtml for good syntax"
@echo "make upload_ks"
@echo "make imapsync.exe"
@ -45,7 +49,7 @@ VERSION=$(shell perl -I$(IMAPClient) ./imapsync --version 2>/dev/null || cat VER
VERSION_EXE=$(shell cat ./VERSION_EXE)
HELLO=$(shell date;uname -a)
IMAPClient_3xx=./W/Mail-IMAPClient-3.35/lib
IMAPClient_3xx=./W/Mail-IMAPClient-3.37/lib
IMAPClient=$(IMAPClient_3xx)
HOSTNAME = $(shell hostname -s)
@ -62,7 +66,7 @@ hello:
@echo "$(BIN_NAME)"
all: ChangeLog README VERSION OPTIONS W/imapsync.1 prereq perlcritic bin mac imapsync.exe VERSION_EXE
all: ChangeLog README VERSION OPTIONS W/imapsync.1 biz prereq allcritic bin mac imapsync.exe VERSION_EXE
testp :
sh INSTALL.d/prerequisites_imapsync
@ -136,15 +140,17 @@ ci: cidone
cidone:
rcsdiff RCS/*
cd W && rcsdiff RCS/*
cd S && rcsdiff RCS/*
cd examples && rcsdiff RCS/*
rcsdiff W/*.bat W/*.out W/*.txt W/*.htaccess W/*.shtml W/*.t2t
rcsdiff S/*.txt S/*.shtml
rcsdiff INSTALL.d/*.txt INSTALL.d/prerequisites_imapsync
rcsdiff FAQ.d/*txt
rcsdiff examples/*.sh examples/*.bat examples/*.txt
###############
# Local goals
###############
.PHONY: prereq test tests testp testf test3xx testv3 perlcritic
.PHONY: prereq test tests testp testf test3xx testv3 perlcritic allcritic
prereq: W/prereq.scandeps
@ -156,14 +162,24 @@ W/prereq.scandeps: INSTALL.d/prerequisites_imapsync imapsync
perlcritic: W/perlcritic_3.out W/perlcritic_2.out
allcritic: W/perlcritic_4.out W/perlcritic_3.out W/perlcritic_2.out W/perlcritic_1.out
W/perlcritic_1.out: imapsync
perlcritic -1 imapsync > W/perlcritic_1.out || :
echo | ci -l W/perlcritic_1.out
W/perlcritic_2.out: imapsync
perlcritic -2 imapsync > W/perlcritic_2.out || :
echo | ci -l W/perlcritic_2.out
W/perlcritic_3.out: imapsync
perlcritic -3 imapsync > W/perlcritic_3.out || :
echo | ci -l W/perlcritic_3.out
W/perlcritic_4.out: imapsync
perlcritic -4 imapsync > W/perlcritic_4.out || :
echo | ci -l W/perlcritic_4.out
test_quick : test_quick_3xx
@ -208,13 +224,18 @@ W/test_tests.bat:
scp imapsync W/test_tests.bat Admin@c:'C:/msys/1.0/home/Admin/imapsync/'
ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/test_tests.bat'
.PHONY: W/*.bat
.PHONY: W/*.bat examples/*
examples/sync_loop_windows.bat:
unix2dos examples/sync_loop_windows.bat
scp imapsync examples/file.txt examples/sync_loop_windows.bat Admin@c:'C:/msys/1.0/home/Admin/imapsync/'
ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/sync_loop_windows.bat --nodry --dry --nodry'
# ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/sync_loop_windows.bat '
W/test2.bat:
unix2dos W/test2.bat
scp imapsync examples/file.txt W/test2.bat Admin@c:'C:/msys/1.0/home/Admin/imapsync/'
scp imapsync W/test2.bat Admin@c:'C:/msys/1.0/home/Admin/imapsync/'
ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/test2.bat'
W/test3.bat:
@ -240,23 +261,32 @@ W/test3_gmail.bat:
test_imapsync_exe:
unix2dos W/test_exe.bat
scp W/test_exe.bat Admin@c:'C:/msys/1.0/home/Admin/imapsync/'
time ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/test_exe.bat'
ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/test_exe.bat'
prereq_win32:
win32_prereq:
unix2dos W/install_modules.bat
scp W/install_modules.bat Admin@c:'C:/msys/1.0/home/Admin/imapsync/'
ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/install_modules.bat'
win32_update_ssl:
scp W/install_module_ssl.bat Admin@c:'C:/msys/1.0/home/Admin/imapsync/'
ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/install_module_ssl.bat'
W/install_module_one.bat:
unix2dos W/install_module_one.bat
scp W/install_module_one.bat Admin@c:'C:/msys/1.0/home/Admin/imapsync/'
ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/install_module_one.bat'
imapsync.exe: imapsync
rcsdiff imapsync
ssh Admin@c 'perl -V'
(date "+%s"| tr "\n" " "; echo -n "BEGIN " $(VERSION) ": "; date) >> W/.BUILD_EXE_TIME
unix2dos W/*.bat examples/*.bat
unix2dos W/build_exe.bat W/test_exe.bat W/install_modules.bat
scp W/install_modules.bat Admin@c:'C:/msys/1.0/home/Admin/imapsync/'
# ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/install_modules.bat'
scp imapsync W/build_exe.bat W/test_exe.bat Admin@c:'C:/msys/1.0/home/Admin/imapsync/'
ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/build_exe.bat'
ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/test_exe.bat'
rm -f imapsync.exe
scp Admin@c:'C:/msys/1.0/home/Admin/imapsync/imapsync.exe' .
(date "+%s"| tr "\n" " "; echo -n "END " $(VERSION) ": "; date) >> W/.BUILD_EXE_TIME
@ -265,6 +295,7 @@ exe: imapsync W/build_exe.bat dosify_bat
scp imapsync W/build_exe.bat Admin@c:'C:/msys/1.0/home/Admin/imapsync/'
ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/build_exe.bat'
ssh Admin@c 'C:/msys/1.0/home/Admin/imapsync/imapsync.exe --modules_version'
rm -f imapsync.exe
scp Admin@c:'C:/msys/1.0/home/Admin/imapsync/imapsync.exe' .
(date "+%s"| tr "\n" " "; echo -n "END " $(VERSION) ": "; date) >> W/.BUILD_EXE_TIME
@ -370,7 +401,13 @@ README_dist.txt: dist_dir
sh W/tools/gen_README_dist > $(DIST_PATH)/README_dist.txt
unix2dos $(DIST_PATH)/README_dist.txt
.PHONY: publish upload_ks ks valid_index
.PHONY: publish upload_ks ks valid_index biz
biz: S/imapsync_sold_by_country.txt
S/imapsync_sold_by_country.txt: imapsync
cd S/ && /g/bin/imapsync_by_country && echo | ci -l imapsync_sold_by_country.txt
ks:
rsync -avHz --delete --exclude imapsync.exe \
@ -387,16 +424,6 @@ upload_tests: tests.sh
gilles@ks.lamiral.info:public_html/imapsync/
#upload_ks: ci tarball
upload_ks: ci tarball
rsync -aHv $(PUBLIC) ../imapsync_website/
rsync -aHv $(PUBLIC_W) ../imapsync_website/W/
rsync -aHv --delete ./W/images/ ../imapsync_website/W/images/
rsync -aHv --delete ./W/ks.htaccess ../imapsync_website/.htaccess
rsync -aHv --delete ./dist/ ../imapsync_website/dist/
rsync -aHv --delete ./examples/ ../imapsync_website/examples/
rsync -aHv --delete ./INSTALL.d/ ../imapsync_website/INSTALL.d/
rsync -aHvz --delete ../imapsync_website/ root@ks.lamiral.info:/var/www/imapsync/
publish: dist upload_ks ksa
@ -408,7 +435,7 @@ PUBLIC = ./ChangeLog ./NOLIMIT ./LICENSE ./CREDITS ./FAQ \
./README ./OPTIONS ./TODO ./TUTORIAL.html ./GOOD_PRACTICES.html
PUBLIC_W = ./W/style.css ./W/tw-hash.html \
./W/TIME \
./W/TIME.txt \
./W/paypal.shtml ./W/paypal_return.shtml
@ -445,11 +472,11 @@ checklinkext: S/news.shtml S/external.shtml S/imapservers.shtml S/template.shtm
validate --verbose index.shtml S/*.shtml
touch .valid.index.shtml
.PHONY: upload_index
.PHONY: upload_index upload_FAQ
upload_index: .valid.index.shtml
rcsdiff index.shtml S/*.shtml FAQ FAQ.d/*.txt INSTALL LICENSE CREDITS TODO W/*.bat examples/*.bat index.shtml INSTALL.d/prerequisites_imapsync imapsync
rsync -avH index.shtml FAQ INSTALL OPTIONS NOLIMIT LICENSE CREDITS TODO TUTORIAL.html GOOD_PRACTICES.html imapsync imapsync.exe $(BIN_NAME) imapsync_Darwin_$(VERSION) ../imapsync_website/
rcsdiff index.shtml S/*.shtml FAQ FAQ.d/*.txt INSTALL LICENSE CREDITS TODO W/*.bat examples/*.bat index.shtml INSTALL.d/*.txt imapsync
rsync -avH index.shtml FAQ INSTALL OPTIONS NOLIMIT LICENSE CREDITS TODO TUTORIAL.html GOOD_PRACTICES.html imapsync imapsync.exe $(BIN_NAME) imapsync_bin_Darwin ../imapsync_website/
rsync -avH $(PUBLIC_W) ../imapsync_website/W/
rsync -avH S/ ../imapsync_website/S/
rsync -avH W/images/ ../imapsync_website/W/images/
@ -458,3 +485,23 @@ upload_index: .valid.index.shtml
rsync -aHv --delete ./FAQ.d/ ../imapsync_website/FAQ.d/
rsync -aHvz --delete ../imapsync_website/ root@ks.lamiral.info:/var/www/imapsync/
upload_FAQ:
rcsdiff FAQ FAQ.d/*.txt INSTALL LICENSE CREDITS TODO INSTALL.d/*.txt
rsync -avH FAQ INSTALL OPTIONS CREDITS TODO TUTORIAL.html GOOD_PRACTICES.html ../imapsync_website/
rsync -aHv --delete ./INSTALL.d/ ../imapsync_website/INSTALL.d/
rsync -aHv --delete ./FAQ.d/ ../imapsync_website/FAQ.d/
rsync -aHvz --delete ../imapsync_website/ root@ks.lamiral.info:/var/www/imapsync/
upload_ks: ci tarball
rsync -aHv $(PUBLIC) ../imapsync_website/
rsync -aHv $(PUBLIC_W) ../imapsync_website/W/
rsync -aHv --delete ./W/images/ ../imapsync_website/W/images/
rsync -aHv --delete ./W/ks.htaccess ../imapsync_website/.htaccess
rsync -avH ./S/ ../imapsync_website/S/
rsync -aHv --delete ./dist/ ../imapsync_website/dist/
rsync -aHv --delete ./examples/ ../imapsync_website/examples/
rsync -aHv --delete ./INSTALL.d/ ../imapsync_website/INSTALL.d/
rsync -aHv --delete ./FAQ.d/ ../imapsync_website/FAQ.d/
rsync -aHvz --delete ../imapsync_website/ root@ks.lamiral.info:/var/www/imapsync/

View file

@ -1,5 +1,5 @@
NO LIMIT PUBLIC LICENSE
Version 0, June 2012
Version 0/0, June 2012
Gilles LAMIRAL
La Billais
@ -10,6 +10,6 @@ France
Terms and conditions for copying, distribution, modification
or anything else.
0 No limit to do anything with this work and this license.
0 No limits to do anything with this work and this license.
1 GOTO 0

154
OPTIONS
View file

@ -2,40 +2,44 @@
usage: ./imapsync [options]
Several options are mandatory.
str means string
int means integer
reg means regular expression
cmd means command
--dry : Makes imapsync doing nothing, just print what would
be done without --dry.
--host1 <string> : Source or "from" imap server. Mandatory.
--port1 <int> : Port to connect on host1. Default is 143, 993 if --ssl1
--user1 <string> : User to login on host1. Mandatory.
--host1 str : Source or "from" imap server. Mandatory.
--port1 int : Port to connect on host1. Default is 143, 993 if --ssl1
--user1 str : User to login on host1. Mandatory.
--showpasswords : Shows passwords on output instead of "MASKED".
Useful to restart a complete run by just reading the log.
--password1 <string> : Password for the user1.
--host2 <string> : "destination" imap server. Mandatory.
--port2 <int> : Port to connect on host2. Default is 143, 993 if --ssl2
--user2 <string> : User to login on host2. Mandatory.
--password2 <string> : Password for the user2.
--password1 str : Password for the user1.
--host2 str : "destination" imap server. Mandatory.
--port2 int : Port to connect on host2. Default is 143, 993 if --ssl2
--user2 str : User to login on host2. Mandatory.
--password2 str : Password for the user2.
--passfile1 <string> : Password file for the user1. It must contain the
--passfile1 str : Password file for the user1. It must contain the
password on the first line. This option avoids to show
the password on the command line like --password1 does.
--passfile2 <string> : Password file for the user2. Contains the password.
--passfile2 str : Password file for the user2. Contains the password.
--ssl1 : Use a SSL connection on host1.
--ssl2 : Use a SSL connection on host2.
--tls1 : Use a TLS connection on host1.
--tls2 : Use a TLS connection on host2.
--timeout <int> : Connections timeout in seconds. Default is 120.
--timeout int : Connections timeout in seconds. Default is 120.
0 means no timeout.
--authmech1 <string> : Auth mechanism to use with host1:
--authmech1 str : Auth mechanism to use with host1:
PLAIN, LOGIN, CRAM-MD5 etc. Use UPPERCASE.
--authmech2 <string> : Auth mechanism to use with host2. See --authmech1
--authmech2 str : Auth mechanism to use with host2. See --authmech1
--authuser1 <string> : User to auth with on host1 (admin user).
--authuser1 str : User to auth with on host1 (admin user).
Avoid using --authmech1 SOMETHING with --authuser1.
--authuser2 <string> : User to auth with on host2 (admin user).
--authuser2 str : User to auth with on host2 (admin user).
--proxyauth1 : Use proxyauth on host1. Requires --authuser1.
Required by Sun/iPlanet/Netscape IMAP servers to
be able to use an administrative user.
@ -43,19 +47,19 @@ Several options are mandatory.
--authmd51 : Use MD5 authentification for host1.
--authmd52 : Use MD5 authentification for host2.
--domain1 <string> : Domain on host1 (NTLM authentication).
--domain2 <string> : Domain on host2 (NTLM authentication).
--domain1 str : Domain on host1 (NTLM authentication).
--domain2 str : Domain on host2 (NTLM authentication).
--folder <string> : Sync this folder.
--folder <string> : and this one, etc.
--folderrec <string> : Sync this folder recursively.
--folderrec <string> : and this one, etc.
--folder str : Sync this folder.
--folder str : and this one, etc.
--folderrec str : Sync this folder recursively.
--folderrec str : and this one, etc.
--folderfirst <string> : Sync this folder first. --folderfirst "Work"
--folderfirst <string> : then this one, etc.
--folderlast <string> : Sync this folder last. --folderlast "[Gmail]/All Mail"
--folderlast <string> : then this one, etc.
--folderfirst str : Sync this folder first. --folderfirst "Work"
--folderfirst str : then this one, etc.
--folderlast str : Sync this folder last. --folderlast "[Gmail]/All Mail"
--folderlast str : then this one, etc.
--nomixfolders : Do not merge folders when host1 is case sensitive
while host2 is not (like Exchange). Only the first
@ -63,67 +67,69 @@ Several options are mandatory.
--skipemptyfolders : Empty host1 folders are not created on host2.
--include <regex> : Sync folders matching this regular expression
--include <regex> : or this one, etc.
--f1f2 str1=str2 : Force folder str1 to be synced to str2.
--include reg : Sync folders matching this regular expression
--include reg : or this one, etc.
in case both --include --exclude options are
use, include is done before.
--exclude <regex> : Skips folders matching this regular expression
--exclude reg : Skips folders matching this regular expression
Several folders to avoid:
--exclude 'fold1|fold2|f3' skips fold1, fold2 and f3.
--exclude <regex> : or this one, etc.
--exclude reg : or this one, etc.
--subfolder2 <string> : Move whole host1 folders hierarchy under this
host2 folder <string>.
--subfolder2 str : Move whole host1 folders hierarchy under this
host2 folder str .
It does it by adding two --regextrans2 options before
all others. Add --debug to see what's really going on.
--regextrans2 <regex> : Apply the whole regex to each destination folders.
--regextrans2 <regex> : and this one. etc.
--regextrans2 reg : Apply the whole regex to each destination folders.
--regextrans2 reg : and this one. etc.
When you play with the --regextrans2 option, first
add also the safe options --dry --justfolders
Then, when happy, remove --dry, remove --justfolders.
Have in mind that --regextrans2 is applied after prefix
and separator inversion.
--tmpdir <string> : Where to store temporary files and subdirectories.
--tmpdir str : Where to store temporary files and subdirectories.
Will be created if it doesn't exist.
Default is system specific, Unix is /tmp but
it's often small and deleted at reboot.
--tmpdir /var/tmp should be better.
--pidfile <string> : The file where imapsync pid is written.
--pidfile str : The file where imapsync pid is written.
--pidfilelocking : Abort if pidfile already exists. Usefull to avoid
concurrent transfers on the same mailbox.
--nolog : Turn off logging on file
--logfile <string> : Change the default logfile pathname and filename.
--logfile str : Change the default log filename (can be dirname/filename).
--logdir str : Change the default log directory. Default is LOG_imapsync
--prefix1 <string> : Remove prefix to all destination folders
--prefix1 str : Remove prefix to all destination folders
(usually INBOX. or INBOX/ or an empty string "")
you have to use --prefix1 if host1 imap server
does not have NAMESPACE capability, so imapsync
suggests to use it. All other cases are bad.
--prefix2 <string> : Add prefix to all host2 folders. See --prefix1
--sep1 <string> : Host1 separator in case NAMESPACE is not supported.
--sep2 <string> : Host2 separator in case NAMESPACE is not supported.
--prefix2 str : Add prefix to all host2 folders. See --prefix1
--sep1 str : Host1 separator in case NAMESPACE is not supported.
--sep2 str : Host2 separator in case NAMESPACE is not supported.
--skipmess <regex> : Skips messages maching the regex.
--skipmess reg : Skips messages maching the regex.
Example: 'm/[\x80-ff]/' # to avoid 8bits messages.
--skipmess is applied before --regexmess
--skipmess <regex> : or this one, etc.
--skipmess reg : or this one, etc.
--pipemess <command> : Apply this command to each message content before
the copy.
--pipemess <command> : and this one, etc.
--pipemess cmd : Apply this cmd command to each message content
before the copy.
--pipemess cmd : and this one, etc.
--disarmreadreceipts : Disarms read receipts (host2 Exchange issue)
--regexmess <regex> : Apply the whole regex to each message before transfer.
--regexmess reg : Apply the whole regex to each message before transfer.
Example: 's/\000/ /g' # to replace null by space.
--regexmess <regex> : and this one, etc.
--regexmess reg : and this one, etc.
--regexflag <regex> : Apply the whole regex to each flags list.
--regexflag reg : Apply the whole regex to each flags list.
Example: 's/"Junk"//g' # to remove "Junk" flag.
--regexflag <regex> : and this one, etc.
--regexflag reg : and this one, etc.
--delete : Deletes messages on host1 server after a successful
transfer. Option --delete has the following behavior:
@ -140,9 +146,9 @@ Several options are mandatory.
--delete2folders : Delete folders in host2 that are not in host1 server.
For safety, first try it like this (it is safe):
--delete2folders --dry --justfolders --nofoldersizes
--delete2foldersonly <regex>: Deleted only folders matching regex.
--delete2foldersonly reg : Deleted only folders matching regex.
Example: --delete2foldersonly "/^Junk$|^INBOX.Junk$/"
--delete2foldersbutnot <regex>: Do not delete folders matching regex.
--delete2foldersbutnot reg : Do not delete folders matching regex.
Example: --delete2foldersbutnot "/Tasks$|Contacts$|Foo$/"
--noexpunge : Do not expunge messages on host1.
Expunge really deletes messages marked deleted.
@ -164,12 +170,12 @@ Several options are mandatory.
--idatefromheader : Sets the internal dates on host2 same as the
"Date:" headers.
--maxsize <int> : Skip messages larger (or equal) than <int> bytes
--minsize <int> : Skip messages smaller (or equal) than <int> bytes
--maxage <int> : Skip messages older than <int> days.
--maxsize int : Skip messages larger (or equal) than int bytes
--minsize int : Skip messages smaller (or equal) than int bytes
--maxage int : Skip messages older than int days.
final stats (skipped) don't count older messages
see also --minage
--minage <int> : Skip messages newer than <int> days.
--minage int : Skip messages newer than int days.
final stats (skipped) don't count newer messages
You can do (+ are the messages selected):
past|----maxage+++++++++++++++>now
@ -177,21 +183,23 @@ Several options are mandatory.
past|----maxage+++++minage---->now (intersection)
past|++++minage-----maxage++++>now (union)
--search <string> : Selects only messages returned by this IMAP SEARCH
--search str : Selects only messages returned by this IMAP SEARCH
command. Applied on both sides.
--search1 <string> : Same as --search for selecting host1 messages only.
--search2 <string> : Same as --search for selecting host2 messages only.
--search1 str : Same as --search for selecting host1 messages only.
--search2 str : Same as --search for selecting host2 messages only.
--search CRIT equals --search1 CRIT --search2 CRIT
--exitwhenover <int> : Stop syncing when total bytes transferred reached.
Gmail per day allows 2500000000 down 500000000 upload.
--exitwhenover int : Stop syncing when total bytes transferred reached.
Gmail per day allows
2500000000 = 2.5 GB downloaded from Gmail as host2
500000000 = 500 MB uploaded to Gmail as host1.
--maxlinelength <int> : skip messages with a line length longer than <int> bytes.
--maxlinelength int : skip messages with a line length longer than int bytes.
RFC 2822 says it must be no more than 1000 bytes.
--useheader <string> : Use this header to compare messages on both sides.
--useheader str : Use this header to compare messages on both sides.
Ex: Message-ID or Subject or Date.
--useheader <string> and this one, etc.
--useheader str and this one, etc.
--subscribed : Transfers subscribed folders.
--subscribe : Subscribe to the folders transferred on the
@ -201,7 +209,7 @@ Several options are mandatory.
--nofoldersizes : Do not calculate the size of each folder in bytes
and message counts. Default is to calculate them.
--nofoldersizesatend : Do not calculate the size of each folder in bytes
--nofoldersizesatend: Do not calculate the size of each folder in bytes
and message counts at the end. Default is on.
--justfoldersizes : Exit after having printed the folder sizes.
@ -217,10 +225,11 @@ Several options are mandatory.
--nousecache is used.
--debug : Debug mode.
--debugcontent : Debug content of the messages transfered.
--debugflags : Debug flags.
--debugimap1 : IMAP debug mode for host1. imap debug is very verbose.
--debugimap2 : IMAP debug mode for host2.
--debugfolders : Debug mode for the folders part only.
--debugcontent : Debug content of the messages transfered. Huge ouput.
--debugflags : Debug mode for flags.
--debugimap1 : IMAP debug mode for host1. Very verbose.
--debugimap2 : IMAP debug mode for host2. Very verbose.
--debugimap : IMAP debug mode for host1 and host2.
--debugmemory : Debug mode showing memory consumption after each copy.
@ -228,9 +237,10 @@ Several options are mandatory.
--testslive : Run a live test with test1.lamiral.info imap server.
Useful to check the basics. Needs internet connexion.
--version : Print software version.
--version : Print only software version.
--noreleasecheck : Do not check for new imapsync release (a http request).
--releasecheck : Check for new imapsync release (a http request).
--noid : Do not send/receive ID command to imap servers.
--justconnect : Just connect to both servers and print useful
information. Need only --host1 and --host2 options.
--justlogin : Just login to both host1 and host2 with users
@ -248,9 +258,9 @@ Example: to synchronize imap account "test1" on "test1.lamiral.info"
--host1 test1.lamiral.info --user1 test1 --password1 secret1 \
--host2 test2.lamiral.info --user2 test2 --password2 secret2
Here is a [linux] system (Linux petite 3.2.0-84-generic #121-Ubuntu SMP Tue May 5 18:55:46 UTC 2015 i686)
With perl 5.14.2 Mail::IMAPClient 3.35
$Id: imapsync,v 1.644 2015/07/17 01:22:52 gilles Exp gilles $
Here is a [linux] system (Linux petite 3.2.0-91-generic #129-Ubuntu SMP Wed Sep 9 10:56:56 UTC 2015 i686)
With perl 5.14.2 Mail::IMAPClient 3.37
$Id: imapsync,v 1.670 2015/12/03 02:36:41 gilles Exp gilles $
This current imapsync is up to date
Homepage: http://imapsync.lamiral.info/

44
README
View file

@ -1,10 +1,10 @@
NAME
imapsync - IMAP synchronisation, sync, copy or migration tool.
Synchronises mailboxes between two imap servers. Good at IMAP migration.
More than 52 different IMAP server softwares supported with success, few
More than 66 different IMAP server softwares supported with success, few
failures.
$Revision: 1.644 $
$Revision: 1.670 $
SYNOPSIS
To synchronize imap account "foo" on "imap.truc.org" to imap account
@ -60,36 +60,36 @@ USAGE
The option list:
imapsync [--host1 server1] [--port1 <num>]
[--user1 <string>] [--passfile1 <string>]
[--user1 str ] [--passfile1 str ]
[--host2 server2] [--port2 <num>]
[--user2 <string>] [--passfile2 <string>]
[--user2 str ] [--passfile2 str ]
[--ssl1] [--ssl2]
[--tls1] [--tls2]
[--authmech1 <string>] [--authmech2 <string>]
[--authmech1 str ] [--authmech2 str ]
[--proxyauth1] [--proxyauth2]
[--domain1] [--domain2]
[--authmd51] [--authmd52]
[--folder <string> --folder <string> ...]
[--folderrec <string> --folderrec <string> ...]
[--include <regex>] [--exclude <regex>]
[--prefix2 <string>] [--prefix1 <string>]
[--regextrans2 <regex> --regextrans2 <regex> ...]
[--folder str --folder str ...]
[--folderrec str --folderrec str ...]
[--include reg ] [--exclude reg ]
[--prefix2 str ] [--prefix1 str ]
[--regextrans2 reg --regextrans2 reg ...]
[--sep1 <char>]
[--sep2 <char>]
[--justfolders] [--justfoldersizes] [--justconnect] [--justbanner]
[--syncinternaldates]
[--idatefromheader]
[--syncacls]
[--regexmess <regex>] [--regexmess <regex>]
[--skipmess <regex>] [--skipmess <regex>]
[--maxsize <int>]
[--minsize <int>]
[--maxage <int>]
[--minage <int>]
[--search <string>]
[--search1 <string>]
[--search2 <string>]
[--useheader <string>] [--useheader <string>]
[--regexmess reg ] [--regexmess reg ]
[--skipmess reg ] [--skipmess reg ]
[--maxsize int ]
[--minsize int ]
[--maxage int ]
[--minage int ]
[--search str ]
[--search1 str ]
[--search2 str ]
[--useheader str ] [--useheader str ]
[--nouid1] [--nouid2]
[--usecache]
[--noskipsize]
@ -101,7 +101,7 @@ USAGE
[--nofoldersizes] [--nofoldersizesatend]
[--dry]
[--debug] [--debugimap][--debugimap1][--debugimap2] [--debugcontent]
[--timeout <int>]
[--timeout int ]
[--noreleasecheck]
[--releasecheck]
[--pidfile <filepath>] [--pidfilelocking]
@ -387,5 +387,5 @@ SIMILAR SOFTWARES
Feedback (good or bad) will often be welcome.
$Id: imapsync,v 1.644 2015/07/17 01:22:52 gilles Exp gilles $
$Id: imapsync,v 1.670 2015/12/03 02:36:41 gilles Exp gilles $

View file

@ -5,9 +5,9 @@
<head>
<title>Imapsync similar softwares and external services</title>
<meta name="generator" content="Bluefish 1.0.7"/>
<meta name="author" content="Gilles LAMIRAL"/>
<meta name="date" content="2015-01-30T17:30:18+0100"/>
<meta name="generator" content="Bluefish 2.2.2" />
<meta name="author" content="Gilles LAMIRAL" />
<meta name="date" content="2015-10-08T03:03:44+0200" />
<meta name="copyright" content="None"/>
<meta name="keywords" content="imap, transfer, migration"/>
<meta name="description" content="imap migration tool"/>
@ -63,7 +63,7 @@ Prices are given par mailbox and may be outdated (December 2011).</p>
<li> French Ovh imapcopy <b>0 EUR</b>: <a href="https://ssl0.ovh.net/fr/imapcopy/">https://ssl0.ovh.net/fr/imapcopy/</a></li>
<li> Turkish imapcopy.net <b>0 TRY</b>: <a href="http://imapcopy.net/">http://imapcopy.net/</a></li>
<li> Movemymail free for the first and 5 USD thereafter: <a href="https://movemymail.net">https://movemymail.net</a> .</li>
<li> Migrationwiz 10 USD: <a href="https://www.bittitan.com/products/#migrationwiz"></a>https://www.bittitan.com/products/#migrationwiz</li>
<li> Migrationwiz 10 USD: <a href="https://www.bittitan.com/products/migrationwiz/">https://www.bittitan.com/products/migrationwiz/</a></li>
<li> Rackspace migration 5 USD: <a href="http://www.rackspace.com/email-hosting/migrations">http://www.rackspace.com/email-hosting/migrations</a></li>
<li> Audriga Gmbh 9.99 EUR: <a href="https://www.email-umzug.de/en.html">https://www.email-umzug.de/</a></li>
<li> Yippiemove 15 USD: <a href="http://www.yippiemove.com">http://www.yippiemove.com/</a></li>
@ -98,7 +98,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: external.shtml,v 1.4 2015/04/01 00:00:50 gilles Exp gilles $)<br/>
($Id: external.shtml,v 1.5 2015/10/08 01:05:25 gilles Exp gilles $)<br/>
<a href="#TOP">Top of the page</a>
</p>

View file

@ -29,7 +29,7 @@
<p>Let's start with the long reported <b>success stories</b> list: <b>
63 different imap server softwares supported!</b><br/>
66 different imap server softwares supported!</b><br/>
[host1] means "source server" and [host2] means "destination server":
</p>
@ -54,7 +54,7 @@ Examples:</p>
<p>And now the success imap server software list:</p>
<ul>
<ol>
<li>1und1 H mimap1 84498 [host1], H mibap4 95231 [host1](<a href="http://www.1und1.de/">http://www.1und1.de/</a>)</li>
<li>a1.net imap.a1.net IMAP4 Ready [host1] </li>
<li><b>Apple Server</b> 10.6 Snow Leopard [host1] </li>
@ -104,7 +104,7 @@ Examples:</p>
<li>hMailServer 5.40-B1950 [host12], 5.3.3 [host2], 4.4.1 [host1], 5.3.2-B1769 [host2], 5.6 [host2]
(<a href="https://www.hmailserver.com/">https://www.hmailserver.com/</a>) </li>
<li><b>Hotmail</b> hotmail.com is outlook.com and live.com now.</li>
<li>IceWarp Server 10.4.5 [host1] (<a href="https://www.icewarp.com/">https://www.icewarp.com/</a>)</li>
<li>IceWarp 10.4.5 [host1] 11.2.1.1 [host2] (<a href="https://www.icewarp.com/">https://www.icewarp.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>
@ -155,7 +155,7 @@ Examples:</p>
(<a href="http://www.zimbra.com/">http://www.zimbra.com/</a>) </li>
<li>Zentyal (Zinc) [host1] (<a href="http://www.zentyal.org/">http://www.zentyal.org/</a>) </li>
</ul>
</ol>
<p>Let's finish with reported <b>failure stories</b> over the past.<br/>
Maybe <b>new imapsync releases can run successfully with them</b>.<br/>
@ -202,7 +202,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: imapservers.shtml,v 1.6 2015/06/23 10:45:34 gilles Exp gilles $)<br/>
($Id: imapservers.shtml,v 1.8 2015/11/04 18:21:08 gilles Exp gilles $)<br/>
<a href="#TOP">Top of the page</a>
</p>

View file

@ -0,0 +1,82 @@
1124 Etats-Unis_d'Amerique___ 26.05 % 26.05 % 1
784 Allemagne_______________ 18.17 % 44.23 % 2
409 Royaume-Uni_____________ 9.48 % 53.71 % 3
204 Italie__________________ 4.73 % 58.44 % 4
204 France__________________ 4.73 % 63.17 % 5
190 Canada__________________ 4.40 % 67.57 % 6
175 Suisse__________________ 4.06 % 71.63 % 7
149 Pays-Bas________________ 3.45 % 75.08 % 8
146 Australie_______________ 3.38 % 78.47 % 9
89 Autriche________________ 2.06 % 80.53 % 10
78 Belgique________________ 1.81 % 82.34 % 11
75 Espagne_________________ 1.74 % 84.08 % 12
64 Suede___________________ 1.48 % 85.56 % 13
50 Danemark________________ 1.16 % 86.72 % 14
48 Bresil__________________ 1.11 % 87.83 % 15
40 Norvege_________________ 0.93 % 88.76 % 16
31 Finlande________________ 0.72 % 89.48 % 17
25 Republique_tcheque______ 0.58 % 90.06 % 18
25 Pologne_________________ 0.58 % 90.64 % 19
25 Japon___________________ 0.58 % 91.21 % 20
25 ________________________ 0.58 % 91.79 % 21
22 Russie__________________ 0.51 % 92.30 % 22
21 Irlande_________________ 0.49 % 92.79 % 23
20 Nouvelle-Zelande________ 0.46 % 93.25 % 24
18 Hongrie_________________ 0.42 % 93.67 % 25
15 Afrique_du_Sud__________ 0.35 % 94.02 % 26
14 Portugal________________ 0.32 % 94.34 % 27
14 Hong-Kong_______________ 0.32 % 94.67 % 28
13 Malaisie________________ 0.30 % 94.97 % 29
12 Slovaquie_______________ 0.28 % 95.25 % 30
12 Luxembourg______________ 0.28 % 95.53 % 31
12 Inde____________________ 0.28 % 95.80 % 32
12 Grece___________________ 0.28 % 96.08 % 33
12 Argentine_______________ 0.28 % 96.36 % 34
11 Singapour_______________ 0.25 % 96.62 % 35
11 Chine___________________ 0.25 % 96.87 % 36
11 Chili___________________ 0.25 % 97.13 % 37
10 Mexique_________________ 0.23 % 97.36 % 38
10 Israel__________________ 0.23 % 97.59 % 39
8 Slovenie________________ 0.19 % 97.77 % 40
8 Roumanie________________ 0.19 % 97.96 % 41
8 Emirats_Arabes_Unis_____ 0.19 % 98.15 % 42
7 Lettonie________________ 0.16 % 98.31 % 43
5 Thailande_______________ 0.12 % 98.42 % 44
5 Malte___________________ 0.12 % 98.54 % 45
5 Islande_________________ 0.12 % 98.66 % 46
4 Indonesie_______________ 0.09 % 98.75 % 47
4 Egypte__________________ 0.09 % 98.84 % 48
3 Venezuela_______________ 0.07 % 98.91 % 49
3 Turquie_________________ 0.07 % 98.98 % 50
3 Philippines_____________ 0.07 % 99.05 % 51
3 Estonie_________________ 0.07 % 99.12 % 52
3 Croatie_________________ 0.07 % 99.19 % 53
3 Bulgarie________________ 0.07 % 99.26 % 54
2 Vietnam_________________ 0.05 % 99.30 % 55
2 Uruguay_________________ 0.05 % 99.35 % 56
2 Lituanie________________ 0.05 % 99.40 % 57
2 Costa_Rica______________ 0.05 % 99.44 % 58
2 Chypre__________________ 0.05 % 99.49 % 59
1 Ukraine_________________ 0.02 % 99.51 % 60
1 Trinite-et-Tobago_______ 0.02 % 99.54 % 61
1 Tanzanie________________ 0.02 % 99.56 % 62
1 Taiwan__________________ 0.02 % 99.58 % 63
1 Serbie__________________ 0.02 % 99.61 % 64
1 Senegal_________________ 0.02 % 99.63 % 65
1 Saint_Christophe-Nevis-Anguilla__ 0.02 % 99.65 % 66
1 Qatar___________________ 0.02 % 99.68 % 67
1 Perou___________________ 0.02 % 99.70 % 68
1 Panama__________________ 0.02 % 99.72 % 69
1 Nouvelle-Caledonie______ 0.02 % 99.75 % 70
1 Nigeria_________________ 0.02 % 99.77 % 71
1 Namibie_________________ 0.02 % 99.79 % 72
1 Mongolie________________ 0.02 % 99.81 % 73
1 Moldavie________________ 0.02 % 99.84 % 74
1 Maldives________________ 0.02 % 99.86 % 75
1 Îles_Vierges_britanniques__ 0.02 % 99.88 % 76
1 Koweit__________________ 0.02 % 99.91 % 77
1 Jordanie________________ 0.02 % 99.93 % 78
1 Colombie________________ 0.02 % 99.95 % 79
1 Bahrein_________________ 0.02 % 99.98 % 80
1 Antilles_neerlandaises__ 0.02 % 100.00 % 81
TOTAL = 4314 sales over 81 countries on Thu Dec 3 03:56:13 CET 2015

View file

@ -7,18 +7,17 @@
<title>Imapsync News</title>
<meta name="generator" content="Bluefish 2.2.2" />
<meta name="author" content="Gilles LAMIRAL" />
<meta name="date" content="2015-03-29T15:09:06+0200" />
<meta name="date" content="2015-12-03T03:55:04+0100" />
<meta name="copyright" content="None"/>
<meta name="keywords" content="imap, transfer, migration"/>
<meta name="keywords" content="imap, transfer, migration, synchronization"/>
<meta name="description" content="imap migration tool"/>
<meta http-equiv="content-type" content="text/html; charset=UTF-8"/>
<meta http-equiv="content-type" content="application/xhtml+xml; charset=UTF-8"/>
<meta http-equiv="content-style-type" content="text/css"/>
<meta http-equiv="expires" content="0"/>
<meta http-equiv="expires" content="0"/>
<link rel="icon" type="image/png" href="../W/images/logo_imapsync_s.png" />
<link href="../W/style.css" rel="stylesheet" type="text/css"/>
</head>
<body>
@ -41,7 +40,7 @@
<!--
<ul>
<li><b>1.636</b></li>
<li><b>1.667</b></li>
<li><b>Enhancement</b>: </li>
<li><b>Enhancement</b>: </li>
<li><b>Enhancement</b>: </li>
@ -61,29 +60,104 @@
-->
<ul>
<li><b>1.670</b> Folders mapping made easy with --automap</li>
<li><b>Enhancement</b>: Added option <b><tt>--automap</tt></b> that guesses folders mapping,
for folders like "Sent", "Junk", "Drafts", "All", "Archive", "Flagged".
<ul>
<li>IMAP Special-Use folders described in <a href="https://tools.ietf.org/html/rfc6154">rfc6154</a>
are supported and also well known names for Exchange and common clients. </li>
<li>Automap is turned off by default,
to try it a safe method is to use <tt>--automap --justautomap</tt>, it will exit early</li>
</ul>
</li>
<li><b>Enhancement</b>: Added <tt>--f1f2 str1=str2</tt> : Force folder str1 to be synced to str2.
<ul>
<li>Option --f1f2 overrides any automap mapping and any regextrans2. </li>
<li>Example <tt>--f1f2 Spam=Junk</tt> to map Spam folder to Junk.</li>
</ul>
</li>
<li><b>Enhancement</b>: Added --justautomap to exit after seeing what will happen with --automap and --f1f2 options.</li>
<li><b>Enhancement</b>: Added IMAP4 QUOTA values when they're available and a warning when it's time to find space.
See RFC 2087 <a href="https://tools.ietf.org/html/rfc2087">IMAP4 QUOTA extension</a>
</li>
<li><b>Enhancement</b>: Added <a href="http://tools.ietf.org/html/rfc2971.html">IMAP4 ID extension</a>.
<ul>
<li>ID feature is on by default if supported by the IMAP servers,
use <tt>--noid</tt> to turn it off.</li>
<li>ID Infos returned by the imap servers are shown.</li>
<li>Infos sent to the servers are name=imapsync, version=`imapsync --version`, os=$OSNAME`,
vendor='Gilles LAMIRAL' and date=`rcs date of release`.</li>
<li>For github or other distributors you can hack this part
by searching <tt>$imapsync_id_github</tt></li>
</ul>
</li>
<li><b>Enhancement</b>: Added <tt>--logdir path</tt> to change the default log directory.
Default is <tt>LOG_imapsync/</tt>
</li>
<li><b>Usability</b>: Added folders counting in outputs.</li>
<li><b>Usability</b>: Better output in the login part</li>
<li><b>Usability</b>: Guess prefixes and separators instead of forcing the user to find them.</li>
<li><b>Usability</b>: Output, added <tt>Host1:</tt> or <tt>Host2</tt> at the beginning of lines.</li>
<li><b>Bug fix</b>: SSL_VERIFY_NONE in --ssl and --tls modes</li>
<li><b>Bug fix</b>: Fixed xoauth2 calls. Now XOAUTH2 Works on Windows <tt>--authmech1 XOAUTH2</tt>
with openssl installed.
See <a href="http://imapsync.lamiral.info/FAQ.d/FAQ.XOAUTH2.txt">FAQ.d/FAQ.XOAUTH2.txt</a>.</li>
<li><b>Bug fix</b>: Fixed IO::Socket::SSL constants issue with latest releases</li>
<li><b>Bug fix</b>: Changed "Host1: checking all wanted folders exist" not efficient algorithm in order
to allow efficiently a 2.4 million folders account. Yes, some accounts have this.</li>
<li><b>Refactoring</b>: Started to use global $sync-> in order to reduce number of parameters in routines.</li>
<li><b>Refactoring</b>: Some perlcritic fixes.</li>
</ul>
<ul>
<li><b>1.644</b> Mac OS X standalone binary provided!</li>
<li><b>Enhancement</b>: Mac OS X standalone binary called <tt>imapsync_bin_Darwin</tt></li>
<li><b>Enhancement</b>: Added option <tt>--subfolder2 SUB</tt> Move whole host1 folders hierarchy under folder SUB.</li>
<li><b>Enhancement</b>: Added <tt>--fetch_hash_set "1:*"</tt> to permit Mail2World success.
Need a patched Mail::IMAPClient 3.35 in <tt>sub fetch_hash()</tt></li>
<li><b>Usability</b>: No folders sizes if --justfolders, unless really wanted.</li>
<li><b>Usability</b>: No warning about messages when <tt>--dry --justfolders</tt> are used together.</li>
<li><b>Bug fix</b>: Added NOOP in --dry mode during fake APPEND in order to avoid timeouts</li>
</ul>
<ul>
<li><b>1.636</b></li>
<li><b>Enhancement</b>: Added errors dump listing at the end, before last folder sizes or the statistics. Turned on by default. Use --noerrorsdump to avoid it.</li>
<li><b>Enhancement</b>: Added --maxlinelengthcmd that will be called upon when a line over --maxlinelength is detected. </li>
<li><b>Enhancement</b>: Exchange maxlinelength issue fixed with --maxlinelengthcmd 'reformime -r7' on Linux. Install maildrop package to get reformime command</li>
<li><b>Enhancement</b>: Added --testslive. "imapsync --testslive" performs a live test on real accounts (I own).</li>
<li><b>Enhancement</b>: Added --pipemess in order to pass all message to an external filter tool like "reformime -r7".</li>
<li><b>Enhancement</b>: Added errors dump listing at the end, before last folder sizes or the statistics. Turned on by default. Use <tt>--noerrorsdump</tt> to avoid it.</li>
<li><b>Enhancement</b>: Added <tt>--maxlinelengthcmd</tt> that will be called upon when a line over <tt>--maxlinelength</tt> value is detected. </li>
<li><b>Enhancement</b>: Exchange maxlinelength issue fixed with <tt>--maxlinelengthcmd 'reformime -r7'</tt> on Linux.
Install maildrop package to get reformime command</li>
<li><b>Enhancement</b>: Added <tt>--testslive</tt>. Running <tt>imapsync --testslive</tt> performs a live test on real accounts (I own).</li>
<li><b>Enhancement</b>: Added <tt>--pipemess</tt> in order to pass all message to an external filter tool like <tt>reformime -r7</tt>.</li>
<li><b>Enhancement</b>: Added xoauth2 support, available on Unix with underlying openssl. Thanks to Joaquin Lopez.</li>
<li><b>Enhancement</b>: Added --skipmess to skip messages matching a regex.
Example --skipmess 'm/[\x80-ff]/' to slip messages with non-7bit characters ( ie a byte somewhere begins with 1 )</li>
<li><b>Enhancement</b>: Added <tt>--skipmess regex</tt> to skip messages matching a regex.
Example <tt>--skipmess 'm/[\x80-ff]/'</tt> to slip messages with non-7bit characters ( ie a byte somewhere begins with 1 )</li>
<li><b>Usability</b>: Better output of folders excluded by --exclude and folders included by --include</li>
<li><b>Usability</b>: Added inline help in many places. What you can do with switches to change imapsync behaviour, contextually. Learn imapsync the easy way.</li>
<li><b>Bug fix</b>: imapsync --tests should work under any circumstance now, any Unix, Windows, exe or bin or script. 561 non-regression tests</li>
<li><b>Bug fix</b>: --folderfirst and --folderlast generated an error when their value folder does not exist. Existence is checked.</li>
<li><b>Bug fix</b>: --disarmreadreceipts used to change Disposition-Notification-To in the body when not available in the header. Now never changes the body in all cases.</li>
<li><b>Bug fix</b>: Change default useheader values. Now it is really like --useheader "Message-Id" --useheader "Received".
HMailServer replies two lines with --useheader "Message-Id" --useheader "Message-ID" in older releases.
<li><b>Bug fix</b>: <tt>imapsync --tests</tt> should work under any circumstance now, any Unix, Windows, exe or bin or script. 561 non-regression tests</li>
<li><b>Bug fix</b>: Options <tt>--folderfirst</tt> and <tt>--folderlast</tt> generated an error when their value folder does not exist. Existence is checked.</li>
<li><b>Bug fix</b>: Option <tt>--disarmreadreceipts</tt> used to change Disposition-Notification-To in the body when not available in the header.
Now never changes the body in all cases.</li>
<li><b>Bug fix</b>: Change default useheader values. Now it is really like <tt>--useheader "Message-Id" --useheader "Received"</tt>.
HMailServer replies two lines with <tt>--useheader "Message-Id" --useheader "Message-ID"</tt> in older imapsync releases.
</li>
<li><b>Bug fix</b>: in imap_utf7_decode() + must not be escaped. Was a bug with Cyrillic characters</li>
<li><b>Bug fix</b>: in <tt>imap_utf7_decode()</tt> + character must not be escaped. Was a bug with Cyrillic characters</li>
<li><b>Refactoring</b>: Started to split the <a href="../FAQ">FAQ</a> file in several parts in <a href="../FAQ.d/">FAQ.d/*</a></li>
<li><b>Refactoring</b>: Split the <a href="../INSTALL">INSTALL</a> file in several parts in <a href="../INSTALL.d/">INSTALL.d/*</a></li>
@ -296,7 +370,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: news.shtml,v 1.2 2015/03/31 23:59:58 gilles Exp gilles $)<br/>
($Id: news.shtml,v 1.7 2015/12/03 02:55:37 gilles Exp gilles $)<br/>
<a href="#TOP">Top of the page</a>
</p>

View file

@ -59,7 +59,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: template.shtml,v 1.2 2015/03/29 17:24:47 gilles Exp gilles $)<br/>
($Id: template.shtml,v 1.3 2015/11/05 17:38:18 gilles Exp gilles $)<br/>
<a href="#TOP">Top of the page</a>
</p>

28
TODO
View file

@ -1,5 +1,5 @@
#!/bin/cat
# $Id: TODO,v 1.140 2015/07/17 17:36:22 gilles Exp gilles $
# $Id: TODO,v 1.144 2015/12/03 02:03:06 gilles Exp gilles $
TODO file for imapsync
----------------------
@ -19,11 +19,19 @@ MB
GB
TB
2015_11_24 Jens Herrmann
Add --logdir to allow imapsync choosing the filename while allowing
user to choose the dirname part.
2015_06_02 Karen F Bath.
Add skipped messages in the final dump.
I would like to request if you could add additional errors to the bottom, as we find that things like “MaxLineLength” and “maxsize limit” are classed as skipped messages and in my opinion are errors; as the email message is not transferred but this is not logged at the bottom.
We have our own scan script which we run on all log files at the end and copy the users logs into subfolders that have issues. Ive attached a list of things we search for.
I would like to request if you could add additional errors to the bottom,
as we find that things like MaxLineLength and maxsize limit are classed
as skipped messages and in my opinion are errors; as the email message
is not transferred but this is not logged at the bottom.
We have our own scan script which we run on all log files at the end
and copy the users logs into subfolders that have issues.
I've attached a list of things we search for.
"Error", "Output"
NO Mailbox already exists, "Folder"
@ -97,8 +105,6 @@ when login fails with a "* BYE Temp error" from server.
Consider /var/tmp/ instead of /tmp (/tmp is destoyed
on some Unix at reboot)
Add a FAQ entry about long path over than 260 character on Win32.
Fix long path over than 260 character on Win32 with --usecache
Fix inode crunching with --usecache
Think about Digest::SHA or Digest::SHA::PurePerl.
@ -201,6 +207,16 @@ http://asg.web.cmu.edu/cyrus/download/imapd/altnamespace.html
Now the TODO done! (or not)
===========================================================================
DONE. 2015_08_10.
Guess separators and prefixes when NAMESPACE is not available,
instead of forcing the user to guess and set them.
DONE 2015_08_03. WANTED 2015_07_21
Fix W/learn/imap_utf7_encode
--regextrans2 "s,El&AOk-ments,&AMk-l&AOk-ments,"
DONE. Add a FAQ entry about long path over than 260 character on Win32.
DONE. Build and distribute a standalone Darwin Mac OS X binary.
It's called imapsync_bin_Darwin
@ -607,7 +623,7 @@ To sync a complete account in a subfolder called FOO:
DONE. Make the --justconnect a real "just connect" connection,
not a auth connection like it is now.
DONE. Add --prefix1 option. Don't know what is the need exactly.
DONE. Add --prefix1 option.
The need is to remove this prefix when building target folder names.
DONE. Read the IMAP RFC http://www.rfc-editor.org/rfc/rfc2342.txt

View file

@ -1 +1 @@
1.644
1.670

View file

@ -1 +1 @@
1.644
1.670

View file

@ -326,3 +326,37 @@
1435280203 END 1.643 : vendredi 26 juin 2015, 02:56:43 (UTC+0200)
1437158716 BEGIN 1.644 : vendredi 17 juillet 2015, 20:45:16 (UTC+0200)
1437160124 END 1.644 : vendredi 17 juillet 2015, 21:08:44 (UTC+0200)
1439777074 BEGIN 1.650 : lundi 17 août 2015, 04:04:34 (UTC+0200)
1439778213 END 1.650 : lundi 17 août 2015, 04:23:33 (UTC+0200)
1440289827 BEGIN 1.651 : dimanche 23 août 2015, 02:30:27 (UTC+0200)
1440291228 END 1.651 : dimanche 23 août 2015, 02:53:48 (UTC+0200)
1441934795 BEGIN 1.654 : vendredi 11 septembre 2015, 03:26:35 (UTC+0200)
1441940822 BEGIN 1.655 : vendredi 11 septembre 2015, 05:07:02 (UTC+0200)
1441941869 END 1.655 : vendredi 11 septembre 2015, 05:24:29 (UTC+0200)
1447192716 BEGIN 1.665 : mardi 10 novembre 2015, 22:58:36 (UTC+0100)
1447193035 END 1.665 : mardi 10 novembre 2015, 23:03:55 (UTC+0100)
1447201375 BEGIN 1.665 : mercredi 11 novembre 2015, 01:22:55 (UTC+0100)
1447201490 END 1.665 : mercredi 11 novembre 2015, 01:24:50 (UTC+0100)
1447201666 BEGIN 1.665 : mercredi 11 novembre 2015, 01:27:46 (UTC+0100)
1447202045 BEGIN 1.665 : mercredi 11 novembre 2015, 01:34:05 (UTC+0100)
1447202227 END 1.665 : mercredi 11 novembre 2015, 01:37:07 (UTC+0100)
1447205467 BEGIN 1.665 : mercredi 11 novembre 2015, 02:31:07 (UTC+0100)
1447205527 END 1.665 : mercredi 11 novembre 2015, 02:32:07 (UTC+0100)
1447205754 BEGIN 1.665 : mercredi 11 novembre 2015, 02:35:54 (UTC+0100)
1447205813 END 1.665 : mercredi 11 novembre 2015, 02:36:53 (UTC+0100)
1447205877 BEGIN 1.665 : mercredi 11 novembre 2015, 02:37:57 (UTC+0100)
1447206591 BEGIN 1.665 : mercredi 11 novembre 2015, 02:49:51 (UTC+0100)
1447206779 END 1.665 : mercredi 11 novembre 2015, 02:52:59 (UTC+0100)
1447206877 BEGIN 1.665 : mercredi 11 novembre 2015, 02:54:37 (UTC+0100)
1447207318 BEGIN 1.665 : mercredi 11 novembre 2015, 03:01:58 (UTC+0100)
1447207507 END 1.665 : mercredi 11 novembre 2015, 03:05:07 (UTC+0100)
1447208020 BEGIN 1.665 : mercredi 11 novembre 2015, 03:13:40 (UTC+0100)
1447208213 END 1.665 : mercredi 11 novembre 2015, 03:16:53 (UTC+0100)
1447209722 BEGIN 1.665 : mercredi 11 novembre 2015, 03:42:03 (UTC+0100)
1447209976 END 1.665 : mercredi 11 novembre 2015, 03:46:16 (UTC+0100)
1448298296 BEGIN 1.666 : lundi 23 novembre 2015, 18:04:56 (UTC+0100)
1448298474 END 1.666 : lundi 23 novembre 2015, 18:07:54 (UTC+0100)
1448851660 BEGIN 1.667 : lundi 30 novembre 2015, 03:47:40 (UTC+0100)
1448852283 END 1.667 : lundi 30 novembre 2015, 03:58:03 (UTC+0100)
1449111689 BEGIN 1.670 : jeudi 3 décembre 2015, 04:01:29 (UTC+0100)
1449112253 END 1.670 : jeudi 3 décembre 2015, 04:10:53 (UTC+0100)

View file

@ -0,0 +1,33 @@
Transfer started at Thu Oct 22 15:58:28 2015
PID is 4432
Log file is LOG_imapsync/2015_10_22_15_58_28.txt ( to change it, use --logfile filepath ; or use --nolog to turn off logging )
$RCSfile: imapsync,v $ $Revision: 1.663 $ $Date: 2015/10/03 23:59:27 $
Here is a [linux] system (Linux petite 3.2.0-90-generic #128-Ubuntu SMP Fri Aug 14 21:44:10 UTC 2015 i686)
With perl 5.14.2 Mail::IMAPClient 3.37
Command line used:
../imapsync --modu
Temp directory is /tmp ( to change it use --tmpdir dirpath )
PID file is /tmp/imapsync.pid ( to change it use --pidfile filepath ; to avoid it use --pidfile "" )
Modules version list:
Mail::IMAPClient 3.37
IO::Socket 1.32
IO::Socket::IP ?
IO::Socket::INET 1.31
IO::Socket::SSL 1.53
Net::SSLeay 1.42
Compress::Zlib 2.048
Digest::MD5 2.51
Digest::HMAC_MD5 1.01
Digest::HMAC_SHA1 1.03
Term::ReadKey 2.30
File::Spec 3.33
Time::HiRes 1.972101
Unicode::String 2.09
IO::Tee 0.64
File::Copy::Recursive 0.38
Authen::NTLM 1.09
URI::Escape 3.31
Data::Uniqid 0.12
JSON::WebToken 0.10
( use --no-modules_version to turn off printing this Perl modules list )
--host1 option is mandatory, for help run ../imapsync --help

Binary file not shown.

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,40 @@
Changes
MANIFEST
Makefile.PL
README
examples/build_dist.pl
examples/build_ldif.pl
examples/cleanTest.pl
examples/copy_folder.pl
examples/cyrus_expire.pl
examples/cyrus_expunge.pl
examples/find_dup_msgs.pl
examples/idle.pl
examples/imap_to_mbox.pl
examples/imtestExample.pl
examples/migrate_mail2.pl
examples/migrate_mbox.pl
examples/populate_mailbox.pl
examples/sharedFolder.pl
lib/Mail/IMAPClient.pm
lib/Mail/IMAPClient.pod
lib/Mail/IMAPClient/BodyStructure.pm
lib/Mail/IMAPClient/BodyStructure/Parse.grammar
lib/Mail/IMAPClient/BodyStructure/Parse.pm
lib/Mail/IMAPClient/BodyStructure/Parse.pod
lib/Mail/IMAPClient/MessageSet.pm
lib/Mail/IMAPClient/Thread.grammar
lib/Mail/IMAPClient/Thread.pm
lib/Mail/IMAPClient/Thread.pod
prepare_dist
t/basic.t
t/body_string.t
t/bodystructure.t
t/fetch_hash.t
t/messageset.t
t/pod.t
t/simple.t
t/thread.t
test_template.txt
META.yml Module meta-data (added by MakeMaker)
META.json Module JSON meta-data (added by MakeMaker)

View file

@ -0,0 +1,56 @@
{
"abstract" : "IMAP4 client library",
"author" : [
"Phil Pearl (Lobbes) <phil@zimbra.com>"
],
"dynamic_config" : 1,
"generated_by" : "ExtUtils::MakeMaker version 6.66, CPAN::Meta::Converter version 2.120921",
"license" : [
"perl_5"
],
"meta-spec" : {
"url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
"version" : "2"
},
"name" : "Mail-IMAPClient",
"no_index" : {
"directory" : [
"t",
"inc"
]
},
"prereqs" : {
"build" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"configure" : {
"requires" : {
"ExtUtils::MakeMaker" : "0"
}
},
"runtime" : {
"requires" : {
"Carp" : "0",
"Errno" : "0",
"Fcntl" : "0",
"File::Temp" : "0",
"IO::File" : "0",
"IO::Select" : "0",
"IO::Socket" : "0",
"IO::Socket::INET" : "1.26",
"List::Util" : "0",
"MIME::Base64" : "0",
"Parse::RecDescent" : "1.94",
"Test::More" : "0",
"perl" : "5.008"
}
}
},
"release_status" : "stable",
"resources" : {
"homepage" : "http://sourceforge.net/projects/mail-imapclient/"
},
"version" : "3.37"
}

View file

@ -0,0 +1,36 @@
---
abstract: 'IMAP4 client library'
author:
- 'Phil Pearl (Lobbes) <phil@zimbra.com>'
build_requires:
ExtUtils::MakeMaker: 0
configure_requires:
ExtUtils::MakeMaker: 0
dynamic_config: 1
generated_by: 'ExtUtils::MakeMaker version 6.66, CPAN::Meta::Converter version 2.120921'
license: perl
meta-spec:
url: http://module-build.sourceforge.net/META-spec-v1.4.html
version: 1.4
name: Mail-IMAPClient
no_index:
directory:
- t
- inc
requires:
Carp: 0
Errno: 0
Fcntl: 0
File::Temp: 0
IO::File: 0
IO::Select: 0
IO::Socket: 0
IO::Socket::INET: 1.26
List::Util: 0
MIME::Base64: 0
Parse::RecDescent: 1.94
Test::More: 0
perl: 5.008
resources:
homepage: http://sourceforge.net/projects/mail-imapclient/
version: 3.37

View file

@ -0,0 +1,138 @@
use ExtUtils::MakeMaker;
use warnings;
use strict;
use 5.008_001;
my @missing;
my %optional = (
"Authen::NTLM" => { for => "Authmechanism 'NTLM'" },
"Authen::SASL" => { for => "Authmechanism 'DIGEST-MD5'" },
"Compress::Zlib" => { for => "COMPRESS DEFLATE support" },
"Digest::HMAC_MD5" => { for => "Authmechanism 'CRAM-MD5'" },
"Digest::MD5" => { for => "Authmechanism 'DIGEST-MD5'" },
"IO::Socket::SSL" => { for => "SSL enabled connections (Ssl => 1)" },
"Test::Pod" => { for => "Pod tests", ver => "1.00" },
);
foreach my $mod ( sort keys %optional ) {
my $for = $optional{$mod}->{"for"} || "";
my $ver = $optional{$mod}->{"ver"} || "";
eval "use $mod $ver ();";
push @missing, $mod . ( $for ? " for $for" : "" ) if $@;
}
# similar message to one used in DBI:
if (@missing) {
print( "The following optional modules were not found:",
map( "\n\t" . $_, @missing ), "\n" );
print <<'MSG';
Optional modules are available from any CPAN mirror, reference:
http://search.cpan.org/
http://www.perl.com/CPAN/modules/by-module
http://www.perl.org/CPAN/modules/by-module
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>',
ABSTRACT => 'IMAP4 client library',
VERSION_FROM => 'lib/Mail/IMAPClient.pm',
LICENSE => 'perl',
META_MERGE => {
resources => {
bugtracker => {
web =>
'http://rt.cpan.org/Public/Dist/Display.html?Name=Mail-IMAPClient',
mailto => 'bug-Mail-IMAPClient@rt.cpan.org',
},
homepage => 'http://sourceforge.net/projects/mail-imapclient/',
repository => {
url => 'git://git.code.sf.net/p/mail-imapclient/git',
web => 'http://sourceforge.net/p/mail-imapclient/git/',
type => 'git',
},
},
},
MIN_PERL_VERSION => '5.008',
PREREQ_PM => {
'Carp' => 0,
'Errno' => 0,
'Fcntl' => 0,
'IO::File' => 0,
'IO::Select' => 0,
'IO::Socket' => 0,
'IO::Socket::INET' => 1.26,
'List::Util' => 0,
'MIME::Base64' => 0,
'Parse::RecDescent' => 1.94,
'Test::More' => 0,
'File::Temp' => 0,
},
clean => { FILES => 'test.txt' },
);
set_test_data();
exit 0;
###
### HELPERS
###
sub set_test_data {
unless ( -f "lib/Mail/IMAPClient.pm" ) {
warn("ERROR: not in installation directory\n");
return;
}
if ( -s "./test.txt" ) {
print("The file test.txt will be used for extended tests.\n");
return;
}
print <<EOF;
(OPTIONAL) For extended tests during 'make test', create a file
'test.txt' in the top level directory of this distribution (the same
directory as the Makefile.PL, etc.). This file must contain an IMAP
server name or IP (server=...), a user account (user=...), and a
password (passed=...). A port (port=....) and an authentication
mechanism to be used (authmechanism=...) can also be specified.
Example:
--- BEGIN: test.txt ---
server=localhost
user=mytestuser
passed=mypassword
port=143
--- END: test.txt ---
NOTE: When testing is completed, be sure to remove test.txt (either by
hand or by 'make clean').
EOF
}

View file

@ -0,0 +1,97 @@
Mail::IMAPClient
================
Mail::IMAPClient is a Perl module that provides an interface for
communicating with an IMAP server as an IMAP client.
DEPENDENCIES
============
The following are the minimum requirements for using Mail::IMAPClient:
- Perl 5.8
http://www.perl.org/
- Perl modules from CPAN:
http://search.cpan.org/
Required:
List::Util
MIME::Base64
Parse::RecDescent
Optional:
Authen::NTLM
Authen::SASL
Compress::Zlib
Digest::HMAC_MD5
Digest::MD5
IO::Socket::SSL
- RFC 3501 (IMAP4REV1) compatible IMAP server
http://www.faqs.org/rfcs/rfc3501.html
- Mail::IMAPClient (this package)
INSTALLATION
============
1. Download Mail::IMAPClient module
http://search.cpan.org/dist/Mail-IMAPClient/
2. Read this README
3. This module has a number of dependencies on other Perl modules
available from CPAN. If any modules are missing, appropriate
warnings will be generated in the following step.
4. Prepare to build this module and install any prerequisite modules:
perl Makefile.PL
5. (OPTIONAL) For extended tests during 'make test', create a file
'test.txt' in the top level directory of this distribution (the
same directory as the Makefile.PL, etc.). This file must contain
an IMAP server name or IP (server=...), a user account (user=...),
and password a (passed=...). A port (port=....) and an
authentication mechanism to be used (authmechanism=...) can also be
specified.
Example:
--- BEGIN: test.txt ---
server=localhost
user=mytestuser
passed=mypassword
port=143
--- END: test.txt ---
NOTE: When testing is completed, be sure to remove test.txt (either
by hand or by 'make clean').
6. Build, test and install this module:
make
make test
(sudo) make install
7. Read the documentation to become familiar with this module.
Project Links
=============
- Bugs/tickets:
http://rt.cpan.org/Public/Dist/Display.html?Name=Mail-IMAPClient
- Source code repository (git):
http://sourceforge.net/p/mail-imapclient/git/
- CPAN releases:
http://search.cpan.org/dist/Mail-IMAPClient/
- Project website
http://sourceforge.net/projects/mail-imapclient/
COPYRIGHT AND LICENSE
=====================
Copyright (C) 1999-2003 The Kernen Group, Inc.
Copyright (C) 2007-2009 Mark Overmeer
Copyright (C) 2010-2015 Phil Pearl (Lobbes)
All rights reserved.
This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.0 or,
at your option, any later version of Perl 5 you may have available.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the
GNU General Public License or the Artistic License for more details.

View file

@ -0,0 +1,172 @@
#!/usr/local/bin/perl
#$Id$
use Mail::IMAPClient;
=head1 DESCRIPTION
B<build_dist.pl> accepts the name of a target folder as an argument. It
then opens that folder and rummages through all the mail files in it, looking
for "Reply-to:" headers (or "From:" headers, where there is no "Reply-to:").
It then appends a message into the folder containing all of the addresses in
thus found as a list of recipients. This message can be used to conveniently
drag and drop names into an address book, distribution list, or e-mail message,
using the GUI client of choice.
The email appended to the folder specified in the I<-f> option will have the
subject "buid_dist.pl I<folder> Output".
=head1 SYNTAX
b<build_dist.pl> I<-h>
b<build_dist.pl> I<-s servername -u username -p password -f folder [ -d ]>
=over 4
=item -f The folder name to process.
=item -s The servername of the IMAP server
=item -u The user to log in as
=item -p The password for the user specified in the I<-u> option
=item -d Tells the IMAP client to turn on debugging info
=item -h Prints out this document
=back
B<NOTE:> You can supply defaults for the above options by updating the script.
=cut
use Getopt::Std;
getopts('s:u:p:f:d');
# Update the following to supply defaults:
$opt_f ||= "default folder";
$opt_s ||= "default server";
$opt_u ||= "default user";
$opt_p ||= "default password"; # security risk: use with caution!
# Let the compiler know we're serious about these two variables:
$opt_h = $opt_h or $opt_d = $opt_d ;
exec "perldoc $0" if $opt_h;
my $imap = Mail::IMAPClient->new(
Server => $opt_s ,
User => $opt_u ,
Password=> $opt_p ,
Debug => $opt_d||0 ,
) or die "can't connect to server\n";
$imap->select($opt_f);
my @msgs = $imap->search("NOT SUBJECT",qq("buid_dist.pl $opt_f Output"));
my %list;
foreach my $m (@msgs) {
my $ref = $imap->parse_headers($m,"Reply-to","From");
warn "Couldn't get recipient address from msg#$m\n"
unless scalar(@{$ref->{'Reply-to'}}) ||
scalar(@{$ref->{'From'}}) ;
my $from = scalar(@{$ref->{'Reply-to'}}) ?
$ref->{'Reply-to'}[0] :
$ref->{'From'}[0] ;
my $addr = $from;
$addr =~ s/.*<//;
$addr =~ s/[\<\>]//g;
$list{$addr} = $from unless exists $list{$addr};
}
$append = <<"EOMSG";
To: ${\(join(",",values %list))}
From: $opt_u\@$opt_s
Date: ${\($imap->Rfc822_date(time))}
Subject: build_dist.pl $opt_f Output
The above note was never actually sent to the following people:
${\(join("\n",keys %list))}
Interesting, eh?
Love,
$opt_u
EOMSG
$imap->append($opt_f,$append) or warn "Couldn't append the message.";
$imap->logout;
=head1 AUTHOR
David J. Kernen
The Kernen Group, Inc.
imap@kernengroup.com
=head1 COPYRIGHT
This example and Mail::IMAPClient are Copyright (c) 2003
by The Kernen Group, Inc. All rights reserved.
This example is distributed with Mail::IMAPClient and
subject to the same licensing requirements as Mail::IMAPClient.
imtest is a utility distributed with Cyrus IMAP server,
Copyright (c) 1994-2000 Carnegie Mellon University.
All rights reserved.
=cut
# $Id$
# $Log: build_dist.pl,v $
# Revision 19991216.7 2003/06/12 21:38:29 dkernen
#
# Preparing 2.2.8
# Added Files: COPYRIGHT
# Modified Files: Parse.grammar
# Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#
# Revision 19991216.6 2000/12/11 21:58:50 dkernen
#
# Modified Files:
# build_dist.pl build_ldif.pl copy_folder.pl find_dup_msgs.pl
# imap_to_mbox.pl populate_mailbox.pl
# to add CVS data
#
# Revision 19991216.5 1999/12/16 17:19:09 dkernen
# Bring up to same level
#
# Revision 19991124.3 1999/12/16 17:14:22 dkernen
# Incorporate changes for exists method performance enhancement
#
# Revision 19991124.02 1999/11/24 17:46:16 dkernen
# More fixes to t/basic.t
#
# Revision 19991124.01 1999/11/24 16:51:46 dkernen
# Changed t/basic.t to test for UIDPLUS before trying UID cmds
#
# Revision 1.8 1999/11/23 17:51:05 dkernen
# Committing version 1.06 distribution copy
#

View file

@ -0,0 +1,235 @@
#!/usr/local/bin/perl
#$Id$
use Mail::IMAPClient;
use MIME::Lite;
use Data::Dumper;
=head1 DESCRIPTION
B<build_ldif.pl> accepts the name of a target folder as an argument. It
then opens that folder and rummages through all the mail files in it, looking
for "Reply-to:" headers (or "From:" headers, where there is no "Reply-to:").
It then prints to STDOUT a file in ldif format containing entries for all of
the addresses that it finds. It also appends a message into the specified folder containing
all of the addresses in both the B<To:> field of the message header and in an
LDIF-format attachment.
B<build_ldif.pl> requires B<MIME::Lite>.
=head1 SYNTAX
B<build_ldif.pl> I<-h>
B<build_ldif.pl> I<-s servername -u username -p password -f folder [ -d ]>
=over 4
=item -f The folder name to process.
=item -s The servername of the IMAP server
=item -t Include "To" and "Cc" fields as well as "From"
=item -u The user to log in as
=item -p The password for the user specified in the I<-u> option
=item -d Tells the IMAP client to turn on debugging info
=item -n Suppress delivering message to folder
=item -h Prints out this document
=back
B<NOTE:> You can supply defaults for the above options by updating the script.
=cut
use Getopt::Std;
getopts('hs:u:p:f:dtn');
# Update the following to supply defaults:
$opt_f ||= "default folder";
$opt_s ||= "default server";
$opt_u ||= "default user";
$opt_p ||= "default password"; # security risk: use with caution!
# Let the compiler know we're serious about these variables:
$opt_0 = ( $opt_h or $opt_d or $opt_t or $opt_n or $opt_0);
exec "perldoc $0" if $opt_h;
my $imap = Mail::IMAPClient->new(
Server => $opt_s ,
User => $opt_u ,
Password=> $opt_p ,
Debug => $opt_d||0 ,
) or die "can't connect to server\n";
$imap->select($opt_f); $imap->expunge;
my @msgs = $imap->search("NOT SUBJECT",qq("buid_ldif.pl $opt_f Output"));
my %list;
foreach my $m (@msgs) {
my $ref = $imap->parse_headers($m,"Reply-to","From");
warn "Couldn't get recipient address from msg#$m\n"
unless scalar(@{$ref->{'Reply-to'}}) ||
scalar(@{$ref->{'From'}}) ;
my $from = scalar(@{$ref->{'Reply-to'}}) ?
$ref->{'Reply-to'}[0] :
$ref->{'From'}[0] ;
my $name = $from ;
$name =~ s/<.*// ;
if ($name =~ /\@/) {
$name = $from ;
$name =~ s/\@.*//; ;
}
$name =~ s/\"//g ;
$name =~ s/^\s+|\s+$//g ;
my $addr = $from ;
$addr =~ s/.*<// ;
$addr =~ s/[\<\>]//g ;
$list{lc($addr)} = [ $addr, $name ]
unless exists $list{lc($addr)} ;
if ($opt_t) { # Do "To" and "Cc", too
my $ref = $imap->parse_headers($m,"To","Cc") ;
my @array = ( @{$ref->{To}} , @{$ref->{Cc}} ) ;
my @members = () ;
foreach my $text (@array) {
while ( $text =~ / "([^"\\]*(\\.[^"\\]*)*"[^,]*),? |
([^",]+),? |
,
/gx
) {
push @members, defined($1)?$1:$3 ;
}
}
foreach my $to (@members) {
my $name = $to ;
$name =~ s/<.*// ;
if ($name =~ /\@/) {
$name = $to ;
$name =~ s/\@.*//; ;
}
$name =~ s/\"//g ;
$name =~ s/^\s+|\s+$//g ;
my $addr = $to ;
$addr =~ s/.*<// ;
$addr =~ s/[\<\>]//g ;
$list{lc($addr)} = [ $addr, $name ]
unless exists $list{lc($addr)} ;
}
}
}
my $text = join "",map {
qq{dn: cn="} . $list{$_}[1] .
qq{", mail=$list{$_}[0]\n} .
qq{cn: } . $list{$_}[1] . qq{\n} .
qq{mail: $list{$_}[0]\n} .
qq{objectclass: top\nobjectclass: person\n\n};
} keys %list ;
# Create a new multipart message:
my $msg = MIME::Lite->new(
From => $opt_u,
map({ ("To" => $list{$_}[0]) } keys %list),
Subject => "LDIF file from $opt_f",
Type =>'TEXT',
Data =>"Attached is the LDIF file of addresses from folder $opt_f."
);
$msg->attach( Type =>'text/ldif',
Filename => "$opt_f.ldif",
Data => $text ,
);
print $text;
$imap->append($opt_f, $msg->as_string) unless $opt_n;
print Dumper($imap) if $opt_d;
$imap->logout;
=head1 AUTHOR
David J. Kernen
The Kernen Group, Inc.
imap@kernengroup.com
=head1 COPYRIGHT
This example and Mail::IMAPClient are Copyright (c) 1999,2003
by The Kernen Group, Inc. All rights reserved.
This example is distributed with Mail::IMAPClient and
subject to the same licensing requirements as Mail::IMAPClient.
imtest is a utility distributed with Cyrus IMAP server,
Copyright (c) 1994-2000 Carnegie Mellon University.
All rights reserved.
=cut
# $Id$
# $Log: build_ldif.pl,v $
# Revision 19991216.11 2003/06/12 21:38:30 dkernen
#
# Preparing 2.2.8
# Added Files: COPYRIGHT
# Modified Files: Parse.grammar
# Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#
# Revision 19991216.10 2002/05/24 15:47:18 dkernen
# Misc fixes
#
# Revision 19991216.9 2000/12/11 21:58:51 dkernen
#
# Modified Files:
# build_dist.pl build_ldif.pl copy_folder.pl find_dup_msgs.pl
# imap_to_mbox.pl populate_mailbox.pl
# to add CVS data
#
# Revision 19991216.8 2000/03/02 19:57:13 dkernen
#
# Modified Files: build_ldif.pl -- to support new option to all "To:" and "Cc:" to be included in ldif file
#
# Revision 19991216.7 2000/02/21 16:16:10 dkernen
#
# Modified Files: build_ldif.pl -- to allow for "To:" and "Cc:" header handling and
# to handle quoted names in headers
#
# Revision 19991216.6 1999/12/28 13:56:59 dkernen
# Fixed -h option (help).
#
# Revision 19991216.5 1999/12/16 17:19:10 dkernen
# Bring up to same level
#
# Revision 19991124.3 1999/12/16 17:14:24 dkernen
# Incorporate changes for exists method performance enhancement
#
# Revision 19991124.02 1999/11/24 17:46:18 dkernen
# More fixes to t/basic.t
#
# Revision 19991124.01 1999/11/24 16:51:48 dkernen
# Changed t/basic.t to test for UIDPLUS before trying UID cmds
#
# Revision 1.8 1999/11/23 17:51:05 dkernen
# Committing version 1.06 distribution copy
#

View file

@ -0,0 +1,64 @@
#!/usr/local/bin/perl
use Mail::IMAPClient;
use IO::File;
#
# Example that will also clean out your test account if interrupted 'make test'
# runs have left junk folders there. Run from installation dir, installation/examples
# subdir, or supply full path to the test.txt file (created during 'perl Makefile.PL'
# and left in the installation dir until 'make clean').
# If you 've already run 'make clean' or said no to extended tests,
# then you don't have the file anyway; re-run 'perl Makefile.PL', reply 'y' to the
# extended tests prompt, then supply the test account's credentials as prompted.
# Then try this again.
#
if ( -f "./test.txt" ) {
$configFile = "./test.txt"
} elsif ( -f "../test.txt" ) {
$configFile = "../test.txt"
} elsif ( $ARGV[0] and -f "$ARGV[0]" ) {
$configFile = $ARGV[0];
} else {
print STDERR "Can't find test.txt. Please run this from the installation directory ",
"or supply the full path to test.txt as an argument on the command line.\n";
}
my $fh = IO::File->new("./test.txt") or die "./test.txt: $!\n";
while (my $input = <$fh>) {
chomp $input;
my($k,$v) = split(/=/,$input,2);
$conf{$k}=$v;
}
my $imap = Mail::IMAPClient->new(Server=>$conf{server},User=>$conf{user},
Password=>$conf{passed}) or die "Connecting to $conf{server}: $! $@\n";
for my $f ( grep(/^IMAPClient_/,$imap->folders) ) {
print "Deleting $f\n";
$imap->select($f);
$imap->delete_messages(@{$imap->messages}) ;
$imap->close($f);
$imap->delete($f);
}
=head1 AUTHOR
David J. Kernen
The Kernen Group, Inc.
imap@kernengroup.com
=head1 COPYRIGHT
This example and Mail::IMAPClient are Copyright (c) 2003
by The Kernen Group, Inc. All rights reserved.
This example is distributed with Mail::IMAPClient and
subject to the same licensing requirements as Mail::IMAPClient.
imtest is a utility distributed with Cyrus IMAP server,
Copyright (c) 1994-2000 Carnegie Mellon University.
All rights reserved.
=cut

View file

@ -0,0 +1,147 @@
#!/usr/local/bin/perl
#$Id$
++$|;
use Getopt::Std;
use Mail::IMAPClient;
use vars qw/$opt_r $opt_h $opt_t $opt_f/;
getopts("t:f:F:N:rh");
if ( $opt_h ) {
print &usage;
exit;
}
my($to_id,$to_pass,$thost) = $opt_t =~ m{
([^/]+) # everything up to / is the id
/ # then a slash
([^@]+) # then everything up to @ is pswd
@ # then an @-sign
(.*) # then everything else is the host
}x ;
my($from_id,$from_pass,$fhost) =
$opt_f =~ m{
([^/]+) # everything up to / is the id
/ # then a slash
([^@]+) # then everything up to @ is pswd
@ # then an @-sign
(.*) # then everything else is the host
}x ;
$to_id and $from_id and $to_pass and $from_pass and $thost and $fhost
or die "Error: Must specify -t and -f (to and from)\n" . &usage;
$opt_F or
die "Error: Must specify '-F folder' or how will I know what folder to copy?\n" .
&usage ;
$opt_N ||= $opt_F;
print "Copying folder $opt_F from $from_id\@$fhost to ${to_id}'s $opt_N folder on $thost.\n";
my ($from) = Mail::IMAPClient->new( Server => $fhost,
User => $from_id,
Password=> $from_pass,
Fast_IO => 1,
Uid => 1,
Debug => 0,
);
my ($to) = Mail::IMAPClient->new( Server => $thost,
User => $to_id,
Password=> $to_pass,
Fast_IO => 1,
Uid => 1,
Debug => 0,
);
my @folders = $opt_r ? @{$from->folders($opt_F)} : ( $opt_F ) ;
foreach my $fold (@folders) {
print "Processing folder $fold\n";
$from->select($fold);
if ($opt_F ne $opt_N) {
$fold =~s/^$opt_F/$opt_N/o;
}
unless ($to->exists($fold)) {
$to->create($fold) or warn "Couldn't create $fold\n" and next;
}
$to->select($fold);
my @msgs = $from->search("ALL");
# my %flaghash = $from->flags(\@msgs);
foreach $msg (@msgs) {
print "Processing message $msg in folder $fold.\n";
my $string = $from->message_string($msg);
# print "String = $string\n";
my $new_id = $to->append($fold,$string)
or warn "Couldn't append msg #$msg to target folder $fold.\n";
$to->store($new_id,"+FLAGS (" . join(" ",@{$from->flags($msg)}) . ")");
}
}
sub usage {
return "Syntax:\n\t$0 -t to_id/to_pass\@to.host -f from_id/from_pass\@from.host \\\n" .
"\t\t-F folder [-N New_Folder] [-r]\n".
"\tor\n\t$0 -h\n\n".
"\twhere:\n\t\t".
"to_id\t\tis the id to recieve the folder\n\t\t".
"to_pass\t\tis the password for to_id\n\t\t".
"from\t\tis the uid who currently has the folder\n\t\t".
"from_pass\tis the password for from_id\n\t\t".
"to.host\t\tis the optional host where the 'to' uid has a mailbox\n\t\t".
"from.host\tis the optional host where the 'from' uid has a mailbox\n\t\t".
"folder\t\tis the folder to copy from\n\t\t".
"New_Folder\tis the folder to copy to (defaults to 'folder')\n\t\t".
"-h\t\tprints this help message\n\t\t".
"-r\t\tspecifies a recursive copy (only works on systems that support the idea " .
"\n\t\t\t\tof recursive folders)\n\t\t".
"\n"
;
}
=head1 AUTHOR
David J. Kernen
The Kernen Group, Inc.
imap@kernengroup.com
=head1 COPYRIGHT
This example and Mail::IMAPClient are Copyright (c) 1999,2000,2003
by The Kernen Group, Inc. All rights reserved.
This example is distributed with Mail::IMAPClient and
subject to the same licensing requirements as Mail::IMAPClient.
imtest is a utility distributed with Cyrus IMAP server,
Copyright (c) 1994-2000 Carnegie Mellon University.
All rights reserved.
=cut
# History:
# $Log: copy_folder.pl,v $
# Revision 19991216.3 2003/06/12 21:38:30 dkernen
#
# Preparing 2.2.8
# Added Files: COPYRIGHT
# Modified Files: Parse.grammar
# Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#
# Revision 19991216.2 2000/12/11 21:58:51 dkernen
#
# Modified Files:
# build_dist.pl build_ldif.pl copy_folder.pl find_dup_msgs.pl
# imap_to_mbox.pl populate_mailbox.pl
# to add CVS data
#

View file

@ -0,0 +1,111 @@
#!/usr/local/bin/perl
#$Id
use Mail::IMAPClient; # available from http://search.cpan.org/search?mode=module&query=IMAPClient
use IO::File;
use Getopt::Std;
use vars qw/ $opt_d $opt_s $opt_p $opt_u $opt_P $opt_h /;
&getopts('d:s:u:p:P:h'); # -d days_to_keep -u cyrys_user -p cyrus_pswd -s cyrus_server -P port
my $days_to_keep = $opt_d||365; # Delete msgs older than -d arg or 365 days
my $cutoff = time - ( $days_to_keep * 24 * 60 * 60 ) ; # time - arg * 24 * 60 * 60 = cutoff date in seconds
# Change the following line (or replace it with something better):
$opt_h and die help()."\n";
my $h = $opt_s || "localhost" ;
my $u = $opt_u || "cyrys" ;
my $p = $opt_p or die "Unable to continue. No password provided.\n" . help();
my $imap = Mail::IMAPClient->new(
Server => "$h",
User => "$u", # $u,
Password=> "$p", # $p,
Uid => 1, # True value
Port => $opt_P||143, # imapd
Debug => 0, # Make true to debug
Buffer => 4096*10, # True value; decrease on machines w/little memory
Fast_io => 1, # True value
Timeout => 30, # True value
# Debug_fh=> IO::File->new(">out.db"), # fhandle
)
or die "$@";
my $mcnt = my $fcnt = 0;
print "Deleting messages older than ",$imap->Rfc2060_date($cutoff),"\n";
for my $f ( $imap->folders ) {
print "Expiring $f\n";
unless ($imap->select($f) ) {
$imap->setacl($f,$u,"lrswipcda") or warn "Cannot setacl for $f: $@\n" and next;
$imap->select($f) or warn "Cannot select $f: $@" and next;
}
my @expired = $imap->search("SENTBEFORE",$imap->Rfc2060_date($cutoff));
next unless @expired;
$mcnt += scalar(@expired); $fcnt ++;
print "Deleting ",scalar(@expired)," messages from $f\n";
$imap->delete_message(@expired);
$imap->expunge;
$imap->close;
}
$imap->logout;
print "Deleted a total of $mcnt messages in $fcnt folders.\n";
exit;
sub help {
return <<"EOHELP";
Usage:
$0 [ -d days_to_keep ] [ -s mail_server ] [ -u cyrus_admin_id ] -p cyrus_password
$0 -h
-h -- prints this here help message
-d days_to_keep -- $0 will delete messages older than "days_to_keep". (Default is 365)
-s mail_server -- hostname or IP Address of IMAP mail server (defaults to "localhost")
-u cyrus_admin_id -- user name of Unix account that owns Cyrus server (defaults to "cyrus")
-p cyrus_password -- password for the "cyrus_admin_id" user account (no default)
-P cyrus_port -- port where the cyrus imapd daemon is listening (defaults to value from
/etc/services or '143')
EOHELP
}
=head1 AUTHOR
David J. Kernen
The Kernen Group, Inc.
imap@kernengroup.com
=head1 COPYRIGHT
This example and Mail::IMAPClient are Copyright (c) 2003
by The Kernen Group, Inc. All rights reserved.
This example is distributed with Mail::IMAPClient and
subject to the same licensing requirements as Mail::IMAPClient.
imtest is a utility distributed with Cyrus IMAP server,
Copyright (c) 1994-2000 Carnegie Mellon University.
All rights reserved.
=cut
#$Log: cyrus_expire.pl,v $
#Revision 19991216.2 2003/06/12 21:38:31 dkernen
#
#Preparing 2.2.8
#Added Files: COPYRIGHT
#Modified Files: Parse.grammar
#Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#

View file

@ -0,0 +1,85 @@
#!/usr/local/bin/perl
#$Id$
use Mail::IMAPClient;
use IO::File;
# Change the following line (or replace it with something better):
my($h,$u,$p) = ('cyrus_host','cyrus_admin_id','cyrus_admin_pswd');
my $imap = Mail::IMAPClient->new( Server => "$h", # imap host
User => "$u", # $u,
Password=> "$p", # $p,
Uid => 1, # True value
Port => 143, # Cyrus
Debug => 0, # True value
Buffer => 4096*10, # True value
Fast_io => 1, # True value
Timeout => 30, # True value
# Debug_fh=> IO::File->new(">out.db"), # fhandle
)
or die "$@";
for my $f ( $imap->folders ) {
print "Expunging $f\n";
unless ($imap->select($f) ) {
$imap->setacl($f,$u,"lrswipcda") or warn "Cannot setacl for $f: $@\n" and next;
$imap->select($f) or warn "Cannot select $f: $@" and next;
}
$imap->expunge;
}
=head1 AUTHOR
David J. Kernen
The Kernen Group, Inc.
imap@kernengroup.com
=head1 COPYRIGHT
This example and Mail::IMAPClient are Copyright (c) 2003
by The Kernen Group, Inc. All rights reserved.
This example is distributed with Mail::IMAPClient and
subject to the same licensing requirements as Mail::IMAPClient.
imtest is a utility distributed with Cyrus IMAP server,
Copyright (c) 1994-2000 Carnegie Mellon University.
All rights reserved.
=cut
#
#$Log: cyrus_expunge.pl,v $
#Revision 19991216.3 2003/06/12 21:38:31 dkernen
#
#Preparing 2.2.8
#Added Files: COPYRIGHT
#Modified Files: Parse.grammar
#Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#
#Revision 1.1 2003/06/12 21:38:14 dkernen
#
#Preparing 2.2.8
#Added Files: COPYRIGHT
#Modified Files: Parse.grammar
#Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#
#

View file

@ -0,0 +1,217 @@
#!/usr/local/bin/perl
# $Id$
use Mail::IMAPClient;
use Mozilla::LDAP::Conn;
use Getopt::Std;
use vars qw/$rootdn $opt_a/;
use Data::Dumper;
# It then connects to a user's mailhost and rummages around,
# looking for duplicate messages.
# It will optionally delete messages that are duplicates (based on
# msg-id header and number of bytes).
# For help, enter:
# find_dup_msgs.pl -h
#
getopts('ahdtvf:F:u:s:p:P:');
if ( $opt_h ) {
print STDERR &usage;
exit;
}
my $uid = $opt_u or die &usage;
$opt_s||='localhost';
$opt_p or die &usage;
$opt_P||=143;
$opt_t and
$opt_d and
die "ERROR: Don't specify -d and -t together.\n" . &usage;
my($pu,$pp) = get_admin();
print "Connecting to $host:$opt_P\n" if $opt_v;
my $imap = Imap->new( Server => $opt_s,
User => $opt_u,
Password=> $opt_p,
Port => $opt_P,
Fast_io => 1,
) or die "couldn't connect to $host port $opt_P: $!\n";
my %folders; my %counts;
FOLDER: foreach my $f ( $opt_F ? $opt_F : $imap->folders ) {
next if $opt_t and $f eq 'Trash';
$folders{$f} = 0;
$counts{$f} = $imap->message_count($f);
print "Processing folder $f\n" if $opt_v;
unless ( $imap->select($f)) {
warn "Error selecting $f: " . $imap->LastError . "\n";
next FOLDER;
}
my @msgs = $imap->search("ALL");
my %hash = ();
MESSAGE: foreach my $m (@msgs) {
my $mid;
if ($opt_a) {
my $h = $imap->parse_headers(
$m,"Date","Subject","From","Message-ID"
) or next MESSAGE;
$mid = "$h->{'Date'}[0]$;$h->{'Subject'}[0]$;".
"$h->{'From'}[0]$;$h->{'Message-ID'}[0]";
} else {
$mid = $imap->parse_headers(
$m,
"Message-ID"
)->{'Message-ID'}[0]
or next MESSAGE;
}
my $size = $imap->size($m);
if ( exists $hash{$mid} and $hash{$mid} == $size ) {
if ($opt_f) {
open F,">>$opt_f" or
die "can't open $opt_f: $!\n";
print F $imap->message_string($m),
"___END OF SAVED MESSAGE___","\n";
close F;
}
$imap->move("Trash",$m) if $opt_t;
$imap->delete_message($m) if $opt_d;
$folders{$f}++;
print "Found a duplicate in ${f}; key = $mid\n" if $opt_v;
} else {
$hash{$mid} = $size;
}
}
print "$f hash:\n",Data::Dumper::Dumper(\%hash) if $opt_v;
$imap->expunge if ($opt_t or $opt_d);
}
my $total; my $totms;
map { $total += $_} values %folders;
map { $totms += $_ } values %counts;
print "Found $total duplicate messages in ${uid}'s mailbox. ",
"The breakdown is:\n",
"\tFolder\tNumber of Duplicates\tNumber of Msgs in Folder\n",
"\t------\t--------------------\t------------------------\n",
map { "\t$_\t$folders{$_}\t$counts{$_}\n" } keys %folders,
"\tTOTAL\t$total\t$totms\n"
;
sub usage {
return "Usage:\n" .
"\t$0 [-d|-t] [-v] [-f filename] [-a] [-P port] \\\n".
"\t\t-s server -u user -p password\n\n" .
"\t-a\t\tdo an especially aggressive search for duplicates\n".
"\t-d\t\tdelete duplicates (default is to just report them)\n".
"\t-f file\t\tsave deleted messages in file named 'file'\n" .
"\t-F fldr\t\tOnly check the folder named 'fldr' (default is to check all folders)\n" .
"\t-h\t\tprint this help message (all other options are ignored)\n" .
"\t-p password\tspecify the target user's password\n" .
"\t-P port\t\tspecify the port to connect to (default is 143)\n" .
"\t-s server\tspecify the target mail server\n" .
"\t-u uid\t\tspecify the target user\n" .
"\t-t\t\tmove deleted messages to trash folder\n" .
"\t-v\t\tprint verbose status messages while processing\n".
"\n" ;
}
=head1 AUTHOR
David J. Kernen
The Kernen Group, Inc.
imap@kernengroup.com
=head1 COPYRIGHT
This example and Mail::IMAPClient are Copyright (c) 2003
by The Kernen Group, Inc. All rights reserved.
This example is distributed with Mail::IMAPClient and
subject to the same licensing requirements as Mail::IMAPClient.
imtest is a utility distributed with Cyrus IMAP server,
Copyright (c) 1994-2000 Carnegie Mellon University.
All rights reserved.
=cut
# History:
# $Log: find_dup_msgs.pl,v $
# Revision 19991216.5 2003/06/12 21:38:32 dkernen
#
# Preparing 2.2.8
# Added Files: COPYRIGHT
# Modified Files: Parse.grammar
# Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#
# Revision 1.1 2003/06/12 21:38:14 dkernen
#
# Preparing 2.2.8
# Added Files: COPYRIGHT
# Modified Files: Parse.grammar
# Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#
# Revision 19991216.4 2002/08/23 14:34:51 dkernen
#
# Modified Files: Changes IMAPClient.pm Makefile Makefile.PL test.txt for version 2.2.0
# Added Files: Makefile Makefile.PL Parse.grammar Parse.pm Parse.pod version 2.2.0
# Added Files: parse.t for version 2.2.0
# Added Files: bodystructure.t for 2.2.0
# Modified Files: find_dup_msgs.pl for v2.2.0
#
# Revision 1.6 2001/03/08 19:00:35 dkernen
#
# ----------------------------------------------------------------------
# Modified Files:
# copy_folder.pl delete_mailbox.pl find_dup_msgs.pl
# mbox_check.pl process_orphans.pl rename_id.pl
# scratch_indexes.pl
# to get ready for nsusmsg02 upgrade
# ----------------------------------------------------------------------
#
# Revision 1.5 2000/11/01 15:51:58 dkernen
#
# Modified Files: copy_folder.pl find_dup_msgs.pl restore_mbox.pl
#
# Revision 1.4 2000/04/13 21:17:18 dkernen
#
# Modified Files: find_dup_msgs.pl - to add -a switch (for aggressive dup search)
# Added Files: copy_folder.pl - a utility for copying a folder from one user's
# mailbox to another's
#
# Revision 1.3 2000/03/14 16:40:21 dkernen
#
# Modified Files: find_dup_msgs.pl -- to skip msgs with no message-id
#
# Revision 1.2 2000/03/13 19:05:50 dkernen
#
# Modified Files:
# delete_mailbox.pl find_dup_msgs.pl restore_mbox.pl -- to add cvs comments
# find_dup_msgs.pl -- to fix bug that occurred when -t (move-to-trash) switch is used
#

View file

@ -0,0 +1,231 @@
#!/usr/bin/perl
=head1 NAME
idle.pl - example using IMAP idle
=head1 SYNOPSIS
idle.pl [options]
Options: [*] == Required, [+] == Multiple vals OK, (val) == Default
--o Server=<server> *IMAP server name/IP
--o User=<user> *User account to login to
--o Password=<passwd> *Password to use for the User account
(see security note below)
--o Port=<port> port on Server to connect to
--o Ssl=<bool> use SSL on this connection
--o Starttls=<bool> call STARTTLS on this connection
--o Debug=<int> enable debugging in Mail::IMAPClient
--o ImapclientKey=Val any other Mail::IMAPClient attribute/value pair
--folder <folder> folder (mailbox) to IMAP SELECT (INBOX)
--maxidle <sec> maximum time to idle without receiving data (300)
--help display a brief help message
--man display the entire man page
--debug enable script debugging
=head1 NOTES
=head2 --o Password=<password>
A password specified as a command-line option may be visible
to other users via the system process table. It may alternately be
given in the PASSWORD environment variable.
=head2 --maxidle <sec>
RFC 2177 states, "The server MAY consider a client inactive if it has
an IDLE command running, and if such a server has an inactivity
timeout it MAY log the client off implicitly at the end of its timeout
period. Because of that, clients using IDLE are advised to terminate
the IDLE and re-issue it at least every 29 minutes to avoid being
logged off."
The default of --maxidle 300 is used to allow the client to notice
when a connection has silently been closed upstream due to network or
firewall issue or configuration without missing too many idle events.
=cut
use strict;
use warnings;
use File::Basename qw(basename);
use Getopt::Long qw(GetOptions);
use Mail::IMAPClient qw();
use Pod::Usage qw(pod2usage);
use POSIX qw();
use constant {
FOLDER => "INBOX",
MAXIDLE => 300,
};
$| = 1; # set autoflush
my $DEBUG = 0; # GLOBAL set by process_options()
my $QUIT = 0;
my $VERSION = "1.00";
my $Prog = basename($0);
###
# main program
main();
sub main {
my %Opt = process_options();
pout("started $Prog\n");
my $imap = Mail::IMAPClient->new( %{ $Opt{opt} } )
or die("$Prog: error: Mail::IMAPClient->new: $@\n");
my ( $folder, $chkseen, $tag ) = ( $Opt{folder}, 1, undef );
$imap->select($folder)
or die("$Prog: error: select '$folder': $@\n");
$SIG{'INT'} = \&sigint_handler;
until ($QUIT) {
unless ( $imap->IsConnected ) {
warn("$Prog: reconnecting due to error: $@\n") if $imap->LastError;
$imap->connect or last;
$imap->select($folder) or last;
$tag = undef;
}
my $ret;
if ($chkseen) {
$chkseen = 0;
# end idle if necessary
if ($tag) {
$tag = undef;
$ret = $imap->done or last;
}
my $unseen = $imap->unseen_count;
last if $@;
pout("$unseen unseen/new message(s) in '$folder'\n") if $unseen;
}
# idle for X seconds unless data was returned by done
unless ($ret) {
$tag ||= $imap->idle
or die("$Prog: error: idle: $@\n");
warn( "$Prog: DEBUG: ", _ts(), " do idle_data($Opt{maxidle})\n" )
if $DEBUG;
$ret = $imap->idle_data( $Opt{maxidle} ) or last;
# connection can go stale so we exit/re-enter of idle state
# - RFC 2177 mentions 29m but firewalls may be more strict
unless (@$ret) {
warn( "$Prog: DEBUG: ", _ts(), " force exit of idle\n" )
if $DEBUG;
$tag = undef;
# restarted lost connections on next iteration
$ret = $imap->done or next;
}
}
local ( $1, $2, $3 );
foreach my $resp (@$ret) {
$resp =~ s/\015?\012$//;
warn("$Prog: DEBUG: server response: $resp\n") if $DEBUG;
# ignore:
# - DONE command
# - <tag> OK IDLE...
next if ( $resp eq "DONE" );
next if ( $resp =~ /^\w+\s+OK\s+IDLE\b/ );
if ( $resp =~ /^\*\s+(\d+)\s+(EXISTS)\b/ ) {
my ( $num, $what ) = ( $1, $2 );
pout("$what: $num message(s) in '$folder'\n");
$chkseen++;
}
elsif ( $resp =~ /^\*\s+(\d+)\s+(EXPUNGE)\b/ ) {
my ( $num, $what ) = ( $1, $2 );
pout("$what: message $num from '$folder'\n");
}
# * 83 FETCH (FLAGS (\Seen))
elsif ( $resp =~ /^\*\s+(\d+)\s+(FETCH)\s+(.*)/ ) {
my ( $num, $what, $info ) = ( $1, $2, $3 );
$chkseen++ if ( $info =~ /[\(|\s]\\Seen[\)|\s]/ );
pout("$what: message $num from '$folder': $info\n");
}
else {
pout("server response: $resp\n");
}
}
}
my $rc = 0;
if ($@) {
if ($QUIT) {
warn("$Prog: caught signal\n");
}
else {
$rc = 1;
}
warn("$Prog: imap error: $@\n") if ( !$QUIT || $DEBUG );
}
exit($rc);
}
###
# supporting routines
sub pout {
print( _ts(), " ", @_ );
}
sub process_options {
my ( %Opt, @err );
GetOptions( \%Opt, "opt=s%", "debug:1", "help", "man", "folder=s",
"maxidle:i" )
or pod2usage( -verbose => 0 );
pod2usage( -message => "$Prog: version $VERSION\n", -verbose => 1 )
if ( $Opt{help} );
pod2usage( -verbose => 2 ) if ( $Opt{man} );
# set global DEBUG
$DEBUG = $Opt{debug} || 0;
# folder (mailbox) to watch
$Opt{folder} = FOLDER unless ( exists $Opt{folder} );
# restart idle when no idle_data seen for this long
$Opt{maxidle} = MAXIDLE unless ( exists $Opt{maxidle} );
$Opt{opt}->{Password} = $ENV{PASSWORD}
if ( !exists $Opt{opt}->{Password} && defined $ENV{PASSWORD} );
foreach my $arg (qw(Server User Password)) {
push( @err, "-o $arg=<val> is required" ) if !exists $Opt{opt}->{$arg};
}
pod2usage(
-verbose => 1,
-message => join( "", map( "$Prog: $_\n", @err ) )
) if (@err);
return %Opt;
}
# example: 2005-10-02 07:50:32
sub _ts {
my %opt = @_;
my $fmt = $opt{fmt} || "%Y-%m-%d %T";
return POSIX::strftime( $fmt, localtime(time) );
}
sub sigint_handler {
$QUIT = 1;
}

View file

@ -0,0 +1,266 @@
#!/usr/local/bin/perl
# (c) 1999 Thomas Stromberg, Research Triangle Commerce, Inc.
# This software is protected by the BSD License. No rights reserved anyhow.
# <tstromberg@rtci.com>
# DESC: Reads a users IMAP folders, and converts them to mbox
# Good for an interim switch-over from say, Exchange to Cyrus IMAP.
# $Header$
# History:
# --------
# 2008/08/07 - Added SSL support, fixed From header printing, and CR
# elimination (sobek)
# TODO:
# -----
# lsub instead of list option
use warnings;
use strict;
use Mail::IMAPClient; # a nice set of perl libs for imap
use IO::Socket::SSL; # for SSL support
use vars qw($opt_h $opt_u $opt_p $opt_P $opt_s $opt_i $opt_f $opt_m $opt_b
$opt_c $opt_r $opt_w $opt_W $opt_S $opt_D $opt_U $opt_d $opt_I
$opt_n);
use Getopt::Std; # for the command-line overrides. good for user
use File::Path; # create full file paths. (yummy!)
use File::Basename; # find a nice basename for a folder.
use Date::Manip; # to create From header date
$| = 1;
sub connect_imap();
sub find_folders();
sub write_folder($$$$);
sub help();
# Config for the imap migration kit.
getopts('u:p:P:s:i:f:m:b:c:r:w:W:SDUdhIn:') or
$opt_h = 1;
my $SSL = $opt_S || 0;
my $SERVER = $opt_s || 'machine';
my $USER = $opt_u || 'userid';
my $PASSWORD = $opt_p || 'password';
my $PORT = $opt_P || '143';
my $INBOX_PATH = $opt_i || "/var/mail/$USER";
my $DOINBOX = $opt_I ? 0 : 1 || 1;
my $FOLDERS_PATH = $opt_f || "./folders/$USER";
my $DONT_MOVE = $opt_m || '.mailboxlist|Trash|INBOXIIMAP|mlbxl';
my $READ_DELIMITER = $opt_r || '/';
my $WRITE_DELIMITER = $opt_w || '/';
my $WRITE_MODE = $opt_W || '>';
my $BANNED_CHARS = $opt_b || '.|^|%';
my $CR = $opt_c || "\r";
my $NUMBER = $opt_n || "";
my $DELETE = $opt_D || 0;
my $DEBUG = $opt_d || "0";
my $UNSEEN = $opt_U || 0;
my $FAIL = 0;
my $imap; # definition for IMAP structure
if ($opt_h) {
# print help here
help();
}
sub help() {
print "imap_to_mbox.pl - with the following optional arguments\:
-S Use an SSL connection (default $SSL)
-s <s> Server specification (default $SERVER)
-u <u> User login (default $USER)
-p <p> User password
-P <p> Server Port (default $PORT)
-i <i> INBOX save path (default $INBOX_PATH)
-I skip INBOX (default $DOINBOX)
-f <f> Save path for other folders (default $FOLDERS_PATH)
-m <r> Regexp for IMAP folders not to be saved:
$DONT_MOVE
-r <r> Read delimiter (default \"$READ_DELIMITER\")
-w <w> Write Delimiter (default \"$WRITE_DELIMITER\")
-b <b> Banned chars (default \"$BANNED_CHARS\")
-c <c> Strip CRs from saved files [for Unix] (default \"$CR\")
-n <n> Receive only <n> messages (Default ".($NUMBER ? "$NUMBER" : "all").")
-U Unseen messages Only
-D Delete downloaded files on server
-d Debug mode (default $DEBUG)\n";
exit 1;
}
## do our magic tricks ######################################
connect_imap();
find_folders();
sub connect_imap()
{
# Open an SSL session to the IMAP server
# Handles the SSL setup, and gives us back a socket
my $ssl;
if ($opt_S) {
$ssl=IO::Socket::SSL->new(
PeerHost => "$SERVER:imaps"
# , SSL_version => 'SSLv2' # for older versions of openssl
);
defined $ssl
or die "Error connecting to $SERVER:imaps - $@";
$ssl->autoflush(1);
}
$imap = Mail::IMAPClient->new(
Socket => ($opt_S ? $ssl : 0),
Server => $SERVER,
User => $USER,
Password => $PASSWORD,
Port => $PORT,
Debug => $DEBUG,
Uid => 0,
Clear => 1,
)
or die ("Could not connect to $SERVER:$PORT with $USER: $! $?\n");
}
sub find_folders()
{
my @folders = $imap->folders;
# push(@folders, "INBOX");
foreach my $folder (@folders) {
my $message_count;
if ($folder eq "INBOX" and $DOINBOX == 0) {
print "* $folder is unwanted, skipping.\n";
next;
}
if (!$UNSEEN) {
$message_count = $imap->message_count($folder);
} else {
$message_count = $imap->unseen_count($folder) || 0;
}
if(! $message_count) {
print "* $folder is empty, skipping.\n";
next;
}
if($folder =~ /$DONT_MOVE/) {
warn "! $folder matches DONT_MOVE ruleset, skipping\n";
next;
}
my $new_folder = $folder;
$new_folder =~ s/\./_/g;
$new_folder =~ s/\Q$READ_DELIMITER/$WRITE_DELIMITER/g;
my $path
= $new_folder eq "INBOX" ? "$INBOX_PATH"
: "$FOLDERS_PATH/$new_folder";
if ($NUMBER && $NUMBER < $message_count) {
printf "x %4i %-45.45s => %s", $NUMBER, $folder, $path;
write_folder $folder, $path, 1, $NUMBER;
} else {
printf "x %4i %-45.45s => %s", $message_count, $folder, $path;
write_folder $folder, $path, 1, $message_count;
}
}
}
sub write_folder($$$$)
{ my($folder, $newpath, $first_message, $last_message) = @_;
$imap->select($folder)
or warn "Could not examine $folder: $!";
my $new_dir = dirname $newpath;
my $new_file = basename $newpath;
-d $new_dir
or mkpath($new_dir, 0700)
or die "Cannot create $new_dir:$!\n";
open my $mbox, $WRITE_MODE, $newpath
or die "Cannot create file $newpath: $!\n";
my @msgs = $imap->unseen if $UNSEEN;
for (my $i=$first_message; $i<$last_message+1; ++$i)
{ my $m = ($UNSEEN ? shift @msgs : $i);
my $date = UnixDate(ParseDate($imap->internaldate($m)),
"%a %b %e %T %Y");
my $user = $imap->get_envelope($m)->from_addresses;
$user =~ s/^.*<([^>]*)>/$1/;
$user = '-' unless $user;
print '.' if $m%25 == 0;
my $msg_header = $imap->fetch($m, "FAST")
or warn "Could not fetch header $m from $folder\n";
my $msg_rfc822 = $imap->fetch($m, "RFC822");
unless($msg_rfc822)
{ warn "Could not fetch RFC822 $m from $folder\n";
$FAIL=1
}
undef my $start;
foreach (@$msg_rfc822)
{ my $message;
if($_ =~ /\: / && !$message)
{ ++$message;
print $mbox "From $user $date\n";
}
if(/^\)\r/)
{ undef $message;
print $mbox "\n\n";
}
next unless $message;
$_ =~ s/\r$//;
$_ = $imap->Strip_cr($_) if $CR;
print $mbox "$_";
}
if($DELETE && ! $FAIL)
{ $imap->delete_message($m)
or warn "Could not delete_message: $@\n";
$FAIL = 0;
}
}
close $mbox
or die "Write errors to $newpath: $!\n";
if($DELETE)
{ $imap->expunge($folder)
or warn "Could not expunge: $@\n";
}
print "\n";
}
# 2008/08/07 - Added SSL support, fixed From header printing, and CR
# elimination (sobek)
#
# Revision 19991216.7 2002/08/23 13:29:48 dkernen
#
# Revision 19991216.6 2000/12/11 21:58:52 dkernen
#
# Revision 19991216.5 1999/12/16 17:19:12 dkernen
# Bring up to same level
#
# Revision 19991124.3 1999/12/16 17:14:25 dkernen
# Incorporate changes for exists method performance enhancement
#
# Revision 19991124.02 1999/11/24 17:46:19 dkernen
# More fixes to t/basic.t
#
# Revision 19991124.01 1999/11/24 16:51:49 dkernen
# Changed t/basic.t to test for UIDPLUS before trying UID cmds
#
# Revision 1.3 1999/11/23 17:51:06 dkernen
# Committing version 1.06 distribution copy

View file

@ -0,0 +1,226 @@
#!/usr/local/bin/perl
use Sys::Hostname;
use Mail::IMAPClient;
use IPC::Open3;
use IO::Socket::UNIX;
use IO::Socket;
use Socket;
use Getopt::Std;
&getopts('ha:df:i:o:p:r:m:u:x:w:p:s:');
if ($opt_h) {
print <<" HELP";
$0 -- uses imtest to connect and authenticate to imap server
Options:
-h print this help message
-a auth authenticate as user 'auth'. This value is passed as the '-a' value
to imtest and defaults to whatever you supplied for -u.
-d turn on Mail::IMAPClient debugging
-f file write Mail::IMAPClient debugging info to file 'file'
-m mech use authentication mechanism "mech"; default is to not supply -m to
imtest
-i path path to imtest executable; default is to let your shell find it via the
PATH environmental variable.
-p port port on mail server to connect to (default is 143)
-r rlm Use realm 'rlm' (default is name of mail server)
-s srvr Name of IMAP mail server (default is the localhost's hostname)
-u usr Use 'usr' as the user id (required)
-w pswd Use 'pswd' as the password for 'usr' (required)
-x path Path to Unix socket (fifo). Default is '/tmp/$0.sock'.
-o 'ops' Pass the string 'ops' directy to imtest as additional options.
This is how you get "other" imtest options passed to imtest. (I only
included switches for options that are either really common or useful
to the IMAPClient object as well as to imtest.)
Many of these switches have the same function here as with imtest. I added a
few extras though!
Example:
$0 -o '-k 128 -l 128' -s imapmail -u test -w testpswd \
-i /usr/local/src/cyrus/cyrus-imapd-2.1.11/imtest/ \
-m DIGEST-MD5
It's a good idea to test your options by running imtest from the command line
(but without the -x switch) first. Once you have it working by hand you should
be able to get it to work from this script (or one remarkably like it) without
too much bloodshed.
HELP
exit;
}
$opt_u and $opt_w or die "No userid/password credentials supplied. I hate that.\n";
$opt_a ||= $opt_u;
if ($opt_i ) {
$opt_i =~ m#^[/\.]# or $opt_i = "./$opt_i";
$opt_i =~ m#imtest$# or ( -x $opt_i and -f $opt_i )
or $opt_i .= ( $opt_i =~ m#/$# ? "imtest" : "/imtest") ;
-x $opt_i and -f $opt_i or die "Cannot find executable $opt_i\n";
}
$opt_p ||= 143;
$opt_s ||= hostname;
$opt_r ||= $opt_s;
$opt_x ||= "/tmp/$0.sock";
my($rfh,$wfh,$efh) ;
my($imt) = ($opt_i ? "$opt_i " : "imtest ") .
($opt_m ? "-m $opt_m ":"" ) .
qq(-r $opt_r -a $opt_a -u $opt_u ).
qq(-x $opt_x -w $opt_w -p $opt_p $opt_s);
open3($wfh,$rfh,$efh,$imt);
my $line;
until ($line =~ /^Security strength factor:/i ) {
$line = <$rfh> or die "EOF\n";
print STDERR "Prolog: $line" if $opt_d;
}
sleep 5;
my $sock = IO::Socket::UNIX->new("$opt_x")
or warn "No socket: $!\n" and exit;
print STDERR "<<<END OF PROLOG>>>\n" if $opt_d;
my $imap = Mail::IMAPClient->new;
$imap->Prewritemethod(\&Mail::IMAPClient::Strip_cr);
$imap->User("$opt_u");
$imap->Server("$opt_s");
$imap->Port("$opt_p");
$imap->Debug($opt_d);
$imap->Debug_fh($opt_f||\*STDERR);
$imap->State($imap->Connected);
$imap->Socket($sock);
# Your code goes here:
$imap->Select("INBOX");
for my $m (@{$imap->search("TEXT SUBJECT")} ) {
print "Message $m:\t",$imap->subject($m),"\n";
}
# You should have finished your code by about here
$imap->logout;
print STDERR "<<<END>>>\n" if $opt_d;
exit;
=head1 NAME
imtestExample.pl -- uses imtest to connect and authenticate to imap server
=head1 DESCRIPTION
=head2 Options
=over 4
=item -h
print this help message
=item -a auth
authenticate as user 'auth'. This value is passed as the '-a' value
to imtest and defaults to whatever you supplied for -u.
=item -d
turn on Mail::IMAPClient debugging
=item -f file
write Mail::IMAPClient debugging info to file 'file'
=item -m mech
use authentication mechanism "mech"; default is to not supply -m to
imtest
=item -i path
path to imtest executable; default is to let your shell find it via the
PATH environmental variable.
=item -p port
port on mail server to connect to (default is 143)
=item -r rlm
Use realm 'rlm' (default is name of mail server)
=item -s srvr
Name of IMAP mail server (default is the localhost's hostname)
=item -u usr
Use 'usr' as the user id (required)
=item -w pswd
Use 'pswd' as the password for 'usr' (required)
=item -x path
Path to Unix socket (fifo). Default is '/tmp/$0.sock'.
=item -o 'ops'
Pass the string 'ops' directy to imtest as additional options.
This is how you get "other" imtest options passed to imtest. (I only
included switches for options that are either really common or useful
to the IMAPClient object as well as to imtest.)
Many of these switches have the same function here as with imtest. I added a
few extras though!
=back
Example:
imtestExample.pl -o '-k 128 -l 128' -s imapmail -u test -w testpswd \
-i /usr/local/src/cyrus/cyrus-imapd-2.1.11/imtest/ \
-m DIGEST-MD5
It's a good idea to test your options by running imtest from the command line
(but without the -x switch) first. Once you have it working by hand you should
be able to get it to work from this script (or one remarkably like it) without
too much bloodshed.
=head1 AUTHOR
David J. Kernen
The Kernen Group, Inc.
imap@kernengroup.com
Based on a suggestion by Tara L. Andrews.
=head1 COPYRIGHT
This example and Mail::IMAPClient are Copyright (c) 2003
by The Kernen Group, Inc. All rights reserved.
This example is distributed with Mail::IMAPClient and
subject to the same licensing requirements as Mail::IMAPClient.
imtest is a utility distributed with Cyrus IMAP server,
Copyright (c) 1994-2000 Carnegie Mellon University.
All rights reserved.
=cut

View file

@ -0,0 +1,326 @@
#!/usr/local/bin/perl
#$Id$
#
# An example of how to migrate from a Netscape server
# (which uses a slash as a separator and which does
# not allow subfolders under the INBOX, only next to it)
# to a Cyrus server (which uses a dot (.) as a separator
# and which requires subfolders to be under "INBOX").
# There are also some allowed-character differences taken
# into account but this is by no means complete AFAIK.
#
# This is an example. If you are doing mail migrations
# then this may in fact be a very helpful example but
# it is unlikely to work 100% correctly as-is.
# A good place to start is by testing a rather large-volume
# transfer of actual mail from the source server with the
# -v option turned on and redirect output to a file for
# perusal. Examine the output carefully for unexpected
# results, such as a number of messages being skipped because
# they're already in the target folder when you know darn
# well this is the first time you ran the script. This
# would indicate an incompatibility with the logic for
# detecting duplicates, unless for some reason the source
# mailbox contains a lot of duplicate messages to begin with.
# (The latter case is an example of why you should use an
# actual mailbox stuffed with actual mail for test; if you
# generate test messages and then test migrating those you
# will only prove that your test messages are migratable.
#
# Also, you may need to play with the rules
# for translating folder names based on what kind of
# names your target server and source server support.
#
# You may also need to play with the logic that determines
# whether or not a message has already been migrated,
# especially if your source server has messages that
# did not come from an SMTP gateway or something like that.
#
# Some servers allow folders to contain mail and subfolders,
# some allow folders to only contain either mail or subfolders.
# If you are migrating from a "mixed use" type to a "single use"
# type server then you'll have to figure out how to deal
# with this. (This script deals with this by creating folders like
# "/blah_mail", "/blah/blah_mail", and "/blah/blah/blah_mail"
# to hold mail if the source folder contains mail and subfolders
# and the target server supports only single-use folders.
# You may not choose a different strategy.)
#
# Finally, it's possible that in some server-to-server
# copies, the source server supports messages that the
# target server considers unacceptable. For example, some
# but not all IMAP servers flat out refuse to accept
# messages with "base newlines", which is to say messages
# whose lines are match the pattern /[^\r]\n$/. There is
# no logic in this script that deals with the situation;
# you will have to identify it if it exists and figure
# out how you want to handle it.
#
# This is probably not an exhaustive list of issues you'll
# face in a migration, but it's a start.
#
# If you're just migrating from an old version to a newer
# version of the same server then you'll probably have
# a much easier time of it.
#
#
use Mail::IMAPClient;
use Data::Dumper;
use IO::File;
use File::Basename ;
use Getopt::Std;
use strict;
use vars qw/ $opt_B $opt_D $opt_T $opt_U
$opt_W $opt_b $opt_d $opt_h
$opt_t $opt_u $opt_w $opt_v
$opt_s $opt_S $opt_W $opt_p
$opt_P $opt_f $opt_F $opt_m
$opt_M
/;
getopts('vs:S:u:U:dDb:B:f:F:w:W:p:P:t:T:hm:M:');
if ( $opt_h ) {
print STDERR <<"HELP";
$0 - an example script demonstrating the use of the Mail::IMAPClient's
migrate method.
Syntax:
$0 -s source_server -u source_user -w source_password -p source_port \
-d debug_source -f source_debugging_file -b source_buffsize \
-t source_timeout -m source_auth_mechanism \
-S target_server -U target_user -W target_password -P target_port \
-D debug_target -F target_debugging_file -B target_buffsize \
-T target_timeout -M target_auth_mechanism \
-v
where "source" refers to the "copied from" mailbox, target is the
"copied to" mailbox, and -v turns on verbose output.
Authentication mechanisms default to "PLAIN".
HELP
exit;
}
$opt_v and ++$|;
print "$0: Started at ",scalar(localtime),"\n" if $opt_v;
$opt_p||=143;
$opt_P||=143;
# Make a connection to the source mailbox:
my $imap = Mail::IMAPClient->new(
Server => $opt_s,
User => $opt_u,
Password=> $opt_w,
Uid => 1,
Port => $opt_p,
Debug => $opt_d||0,
Buffer => $opt_b||4096,
Fast_io => 1,
( $opt_m ? ( Authmechanism => $opt_m) : () ),
Timeout => $opt_t,
($opt_f ? ( Debug_fh=>IO::File->new(">$opt_f" )) : ()),
) or die "$@";
# Make a connection to the target mailbox:
my $imap2 = Mail::IMAPClient->new(
Server => $opt_S,
User => $opt_U,
Password=> $opt_W,
Port => $opt_P,
Uid => 1,
Debug => $opt_D||0,
( $opt_M ? ( Authmechanism => $opt_M) : () ),
($opt_F ? ( Debug_fh=>IO::File->new(">$opt_F")) : ()),
Buffer => $opt_B||4096,
Fast_io => 1,
Timeout => $opt_T, # True value
) or die "$@";
# Turn off buffering on debug files:
$imap->Debug_fh->autoflush;
$imap2->Debug_fh->autoflush;
# Get folder hierarchy separator characters from source and target:
my $sep1 = $imap->separator;
my $sep2 = $imap2->separator;
# Find out if source and target support subfolders inside INBOX:
my $inferiorFlag1 = $imap->is_parent("INBOX");
my $inferiorFlag2 = $imap2->is_parent("INBOX");
# Set up a test folders to see if the source and target support mixed-use
# folders (i.e. folders with both subfolders and mail messages):
my $testFolder1 = "Migrate_Test_$$" ; # Ex: Migrate_Test_1234
$testFolder1 = $inferiorFlag2 ?
"INBOX" . $sep2 . $testFolder1 :
$testFolder1 ;
# The following folder will be a subfolder of $testFolder1:
my $testFolder2 = "Migrate_Test_$$" . $sep2 . "Migrate_test_subfolder_$$" ;
$testFolder2 = $inferiorFlag2 ? "INBOX" . $sep2 . $testFolder2 : $testFolder2 ;
$imap2->create($testFolder2) ; # Create the subfolder first; RFC2060 dictates that
# the parent folder should be created at the same time
# The following line inspired the selectable method. It was also made obsolete by it,
# but I'm leaving it as is to demonstrate use of lower-level method calls:
my $mixedUse2 = grep(/NoSelect/i,$imap2->list("",$testFolder1))? 0 : 1;
# Repeat the above with the source mailbox:
$testFolder2 = "Migrate_Test_$$" . $sep1 . "Migrate_test_subfolder_$$" ;
$testFolder2 = $inferiorFlag1 ? "INBOX" . $sep1 . $testFolder1 : $testFolder1 ;
$imap->create($testFolder2) ;
my $mixedUse1 = grep(/NoSelect/i,$imap->list("",$testFolder1))? 0 : 1;
print "Imap host $opt_s:$opt_p uses a '$sep1' as a separator and ",
( defined($inferiorFlag1) ? "allows " : "does not allow "),
"children in the INBOX. It supports ",
($mixedUse1?"mixed use ":"single use "), "folders.\n" if $opt_v;
print "Imap host $opt_S:$opt_P uses a '$sep2' as a separator and ",
( defined($inferiorFlag2) ? "allows " : "does not allow "),
"children in the INBOX. It supports ",
($mixedUse2?"mixed use ":"single use "), "folders.\n" if $opt_v;
for ($testFolder1,$testFolder2) {$imap->delete($_); $imap2->delete($_);}
my($totalMsgs, $totalBytes) = (0,0);
# Now we will migrate the folder. Here we are doing one message at a time
# so that we can do more granular status reporting and error checking.
# A lazier way would be to do all the messages in one migrate method call
# (specifying "ALL" as the message number) but then we wouldn't be able
# to print out which message we were migrating and it would be a little
# bit tougher to control checking for duplicates and stuff like that.
# We could also check the size of the message on the target right after
# the migrate as an extra safety check if we wanted to but I didn't bother
# here. (I saved as an exercise for the reader. Yeah! That's it! An exercise!)
# Iterate over all the folders in the source mailbox:
for my $f ($imap->folders) {
# Select the folder on the source side:
$imap->select($f) ;
# Massage the foldername into an acceptable target-side foldername:
my $targF = "";
my $srcF = $f;
$srcF =~ s/^INBOX$sep1//i;
if ( $inferiorFlag2 ) {
$targF = $srcF eq "INBOX" ? "INBOX" : "INBOX.$f" ;
} else {
$targF = $srcF ;
}
$targF =~ s/$sep1/$sep2/go unless $sep1 eq $sep2;
$targF =~ tr/#\$\& '"/\@\@+_/;
if ( $imap->is_parent($f) and !$mixedUse2 ) {
$targF .= "_mail" ;
}
print "Migrating folder $f to $targF\n" if $opt_v;
# Create the (massaged) folder on the target side:
unless ( $imap2->exists($targF) ) {
$imap2->create($imap2->Massage($targF))
or warn "Cannot create $targF on " . $imap2->Server . ": $@\n" and next;
}
# ... and select it
$imap2->select($imap2->Massage($targF))
or warn "Cannot select $targF on " . $imap2->Server . ": $@\n" and next;
# now that we know the target folder is selectable, we can close it again:
$imap2->close;
my $count = 0;
my $expectedTotal = $imap->message_count($f) ;
# Now start iterating over all the messages on the source side...
for my $msg ($imap->messages) {
++$count;
my $h = "";
# Get some basic info about the message:
eval { $h = ($imap->parse_headers($msg,"Message-id")||{})->{'Message-id'}[0]};
my $tsize = $imap->size($msg);
my $ret = 0 ; my $h2 = [];
# Make sure we didn't already migrate the message in a previous pass:
$imap2->select($targF);
if ( $tsize and $h and $h2 = $imap2->search(
HEADER => 'Message-id' => $imap2->Quote($h),
NOT => SMALLER => $tsize,
NOT => LARGER => $tsize
)
) {
print
"Skipping $f/$msg to $targF. ",
"One or more messages (" ,join(", ",@$h2),
") with the same size and message id ($h) ",
"is already on the server. ",
"\n"
if $opt_v;
$imap2->close;
} else {
print
"Migrating $f/$msg to $targF. ",
"Message #$count of $expectedTotal has ",
$tsize , " bytes.",
"\n" if $opt_v;
$imap2->close;
# Migrate the message:
my $ret = $imap->migrate($imap2,$msg,"$targF") ;
$ret and ( $totalMsgs++ , $totalBytes += $tsize);
$ret or warn "Cannot migrate $f/$msg to $targF on " . $imap2->Server . ": $@\n" ;
}
}
}
print "$0: Finished migrating $totalMsgs messages and $totalBytes bytes at ",scalar(localtime),"\n"
if $opt_v;
exit;
=head1 AUTHOR
David J. Kernen
The Kernen Group, Inc.
imap@kernengroup.com
=head1 COPYRIGHT
This example and Mail::IMAPClient are Copyright (c) 2003
by The Kernen Group, Inc. All rights reserved.
This example is distributed with Mail::IMAPClient and
subject to the same licensing requirements as Mail::IMAPClient.
imtest is a utility distributed with Cyrus IMAP server,
Copyright (c) 1994-2000 Carnegie Mellon University.
All rights reserved.
=cut
#$Log: migrate_mail2.pl,v $
#Revision 19991216.4 2003/06/12 21:38:33 dkernen
#
#Preparing 2.2.8
#Added Files: COPYRIGHT
#Modified Files: Parse.grammar
#Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#

View file

@ -0,0 +1,131 @@
#!/usr/local/bin/perl
#
# This is an example demonstrating the use of the migrate method.
# Note that the migrate method is considered experimental and should
# be used with caution.
#
#$Id$
#
use Mail::IMAPClient;
use IO::File;
use File::Basename ;
use Getopt::Std;
use warnings;
use vars qw/$opt_h $opt_H
$opt_s $opt_u $opt_p $opt_d $opt_b $opt_o
$opt_S $opt_U $opt_P $opt_D $opt_B $opt_O
/;
getopts('Hhs:S:u:U:p:P:d:D:b:B:o:O:');
if ($opt_h or $opt_H ) {
print << "HELP";
Usage:
$0 -[h|H] -- prints this message
Lower-case options are for source server; upper-case options are for the target server.
$0 -s server -S server -u uid -U uid -p passwd -P passwd \
-b buffersize -B buffersize -o debugFile -O debugFile > error_file
All uppercase options except -O default to the lowercase option that was specified.
If you don't specify any uppercase options at all then God help you, I don't know
what will happen.
Always capture STDERR so that you'll be able to resolve any problems that come up.
HELP
exit;
}
my $imap = Mail::IMAPClient->new(
Server => $opt_s,
User => $opt_u,
Password=> $opt_p,
Uid => 1,
Debug => $opt_d,
Buffer => $opt_b||4096,
Fast_io => 1,
Timeout => 160, # True value
Debug_fh=> (
$opt_o ? IO::File->new(">$opt_o")||die "can't open $opt_o: $!\n" : undef )
) or die "Error opening source connection: $@\n";
my $imap2 = Mail::IMAPClient->new(
Server => $opt_S||$opt_s,
User => $opt_U||$opt_u,
Password=> $opt_P||$opt_p,
Uid => 1,
Debug => $opt_D||$opt_d,
Buffer => $opt_B||$opt_b||4096,
Fast_io => 1,
Timeout => 160,
Debug_fh=> (
$opt_O ? IO::File->new(">$opt_O")||die "can't open $opt_O: $!\n" : undef )
) or die "Error opening target connection: $@\n";
$imap->Debug_fh->autoflush;
$imap2->Debug_fh->autoflush;
for my $f ($imap->folders) { $imap->select($f) ; $imap->migrate($imap2,"ALL") ;}
=head1 AUTHOR
David J. Kernen
The Kernen Group, Inc.
imap@kernengroup.com
=head1 COPYRIGHT
This example and Mail::IMAPClient are Copyright (c) 2003
by The Kernen Group, Inc. All rights reserved.
This example is distributed with Mail::IMAPClient and
subject to the same licensing requirements as Mail::IMAPClient.
imtest is a utility distributed with Cyrus IMAP server,
Copyright (c) 1994-2000 Carnegie Mellon University.
All rights reserved.
=cut
#
#$Log: migrate_mbox.pl,v $
#Revision 19991216.2 2003/06/12 21:38:33 dkernen
#
#Preparing 2.2.8
#Added Files: COPYRIGHT
#Modified Files: Parse.grammar
#Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#
#Revision 1.1 2003/06/12 21:38:15 dkernen
#
#Preparing 2.2.8
#Added Files: COPYRIGHT
#Modified Files: Parse.grammar
#Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#
#

View file

@ -0,0 +1,319 @@
#!/usr/local/bin/perl
#$Id$ #
use Time::Local ;
use FileHandle ;
use File::Copy ;
use Mail::IMAPClient;
use Sys::Hostname ;
#
my $default_user = 'default' ;
my $default_pswd = 'default' ;
#
#########################################################################
# ARGS: DATE = YYYYMMDDHHMM (defaults to current system date) #
# UID = IMAP account id (defaults to $default_user) #
# PSWD = uid's password (defaults to $default_pswd) #
# HOST = Target host (defaults to localhost) #
# CLEAN = 1 (defaults to 0; used to clean out mailbox 1st) #
# CLEANONLY= 1 (defaults to 0; if 1 then only CLEAN is done) #
# DOMAIN = x.com (no default) the mail domain for UID's address #
# #
# EG: populate_mailbox.pl DATE=200001010100 UID=testuser #
# #
#########################################################################
#
(my($x)= join(" ",@ARGV)) ;
$x=~s~=~ ~g ;
chomp($x) ;
#
my %hash = split(/\s+/, $x) if $x ;
#
while (my ($k,$v) = each %hash ) {
$hash{uc $k} = $v ;
}
while (my ($k,$v) = each %hash ) {
delete $hash{$k} if $k =~ tr/[a-z]// ;
}
;
$hash{UID} ||= "$default_user" ;
$hash{PSWD} ||= "$default_pswd" ;
$hash{HOST} ||= hostname ;
#
while (my ($k,$v) = each %hash ) {
print "Running with $k set to $v\n" ;
}
#
my $domain = $hash{DOMAIN} or die "No mail domain provided.\n" ;
my $now = seconds($hash{DATE}) || time ;
#
my $six = $now - ( 6 * 24 * 60 * 60 ) ;
my $seven = $now - ( 7 * 24 * 60 * 60 ) ;
my $notthirty = $now - ( 29 * 24 * 60 * 60 ) ;
my $thirty = $now - ( 30 * 24 * 60 * 60 ) ;
my $notsixty = $now - ( 59 * 24 * 60 * 60 ) ;
my $sixty = $now - ( 60 * 24 * 60 * 60 ) ;
my $notd365 = $now - ( 364 * 24 * 60 * 60 ) ;
my $d365 = $now - ( 365 * 24 * 60 * 60 ) ;
#
$hash{SUBJECTS} = [ "Sixty days old", "Less than sixty days old" ,
"365 days old", "Less than 365 days old" ,
"Trash/Incinerator -- 7 days old" ,
"Sent -- 29 days old" ,
"Sent -- 30 days old" ,
"Trash -- 6 days old" ,
] ;
$hash{FOLDERS} = [ "Sent", "INBOX", "Trash" ,
"365_folder", "Trash/Incinerator" ,
"not_365_folder" ,
] ;
#
&clean_mailbox if $hash{CLEANONLY} || $hash{CLEAN} ;
exit if $hash{CLEANONLY} ;
#
#send to: date: subject: #
#-------- --- ----- --------- #
sendmail( $hash{UID}, $sixty, "Sixty days old" ) ;
sendmail( $hash{UID}, $notsixty, "Less than sixty days old") ;
sendmail( $hash{UID}, $d365, "365 days old" ) ;
sendmail( $hash{UID}, $notd365, "Less than 365 days old" ) ;
#
populate_trash("Trash/Incinerator",$hash{UID}, $seven, 7 ) ;
populate_trash( "Trash" , $hash{UID}, $six, 6 ) ;
populate_trash( "Sent" , $hash{UID}, $thirty, 30 ) ;
populate_trash( "Sent" , $hash{UID}, $notthirty, 29 ) ;
#
movemail( "365 days old" ,
"365_folder" ) ;
#
movemail( "Less than 365 days old" ,
"not_365_folder" ) ;
#
exit ;
#
#
sub seconds {
my $d = shift or return undef ;
my($yy,$moy,$dom,$hr,$min) =
#
$d =~ m! ^ # anchor at start #
(\d\d\d\d) # year #
(\d\d) # month #
(\d\d) # day #
(\d\d) # hour #
(\d\d) # minute #
!x ;
#
return timegm(0,$min,$hr,$dom,$moy-1,($yy>99?$yy-1900:$yy)) ;
}
#
sub sendmail {
#
my($to,$date,$subject) = @_ ;
my $text = <<EOTEXT ;
To: $to\@$hash{DOMAIN}
Date: @{[&rfc822_date($date)]}
Subject: $subject
Dear mail tester,
This is a test message to test mail for messages \l$subject.
I hope you like it!
Love,
The E-Mail Engineering Team
EOTEXT
#
for (my $x = 0; $x < 10 ; $x ++ ) {
my $imap = Mail::IMAPClient->new (
Server => $hash{HOST} ,
User => $hash{UID} ,
Password=> $hash{PSWD} )
or die "can't connect: $!\n" ;
#
$imap->append("INBOX",$text) ;
$imap->logout ;
}
}
#
sub populate_trash {
my $where = shift ;
my $to = shift ;
my $date = shift ;
my $d = shift ;
#
my($ss,$min,$hr,$day,$mon,$year)=gmtime($date) ;
$mon++ ;
$year += 1900 ;
my $fn =sprintf("%4.4d%2.2d%2.2d%2.2d%2.2d%2.2d" ,
$year,$mon,$day,$hr,$min,$ss ) ;
my $x = 0 ;
my $subject = "$where -- $d days old" ;
while ($x++ < 10) {
my $fh ;
$fh .= "Date: @{[&rfc822_date($date)]}\n" ;
$fh .= <<EOTRAH ;
Subject: $subject
This note was put in the $where folder $d days ago. (My how time flies!)
I hope you enjoyed testing with it!
EOTRAH
my $imap = Mail::IMAPClient->new (
Server => $hash{HOST} ,
User => $hash{UID} ,
Password=> $hash{PSWD} )
or die "can't connect: $!\n" ;
$imap->append($where, $fh) ;
#
}
#
}
#
sub movemail {
#
my ($subj,$fold) = @_ ;
my $fh = Mail::IMAPClient->new (
Debug => 0 ,
Server => $hash{HOST} ,
User => $hash{UID} ,
Password => $hash{PSWD} ,
)
;
#
$fh->select("inbox") or die "cannot open inbox: $!\n" ;
#
foreach my $f ($fh->search(qq(SUBJECT "$subj")) ) {
#
$fh->move($fold,$f) ;
#
}
#
}
#
sub clean_mailbox {
#
my $fh =Mail::IMAPClient->new (
Debug => 0 ,
Server => $hash{HOST} ,
User => $hash{UID} ,
Password => $hash{PSWD} ,
)
;
for my $x (@{$hash{FOLDERS}}) {
my @msgs ;
$fh->create($x) unless $fh->exists($x) ;
$fh->select($x) ;
for my $s (@{$hash{SUBJECTS}}) {
push @msgs, $fh->search(qq(SUBJECT "$s")) ;
}
$fh->delete_message(@msgs) if scalar(@msgs) ;
$fh->expunge ;
}
}
#
sub rfc822_date {
#Date: Fri, 09 Jul 1999 13:10:55 -0400 #
my $date = shift ;
my @date = localtime($date) ;
my @dow = qw{ Sun Mon Tue Wed Thu Fri Sat } ;
my @mnt = qw{ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec} ;
#
return sprintf (
"%s, %2.2d %s %4.4s %2.2d:%2.2d:%2.2d -0400" ,
$dow[$date[6]] ,
$date[3] ,
$mnt[$date[4]] ,
$date[5]+=1900 ,
$date[2] ,
$date[1] ,
$date[0] )
;
}
=head1 AUTHOR
David J. Kernen
The Kernen Group, Inc.
imap@kernengroup.com
=head1 COPYRIGHT
This example and Mail::IMAPClient are Copyright (c) 2003
by The Kernen Group, Inc. All rights reserved.
This example is distributed with Mail::IMAPClient and
subject to the same licensing requirements as Mail::IMAPClient.
imtest is a utility distributed with Cyrus IMAP server,
Copyright (c) 1994-2000 Carnegie Mellon University.
All rights reserved.
=cut
# $Id$
# $Log: populate_mailbox.pl,v $
# Revision 19991216.8 2003/06/12 21:38:34 dkernen
#
# Preparing 2.2.8
# Added Files: COPYRIGHT
# Modified Files: Parse.grammar
# Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#
# Revision 1.1 2003/06/12 21:38:16 dkernen
#
# Preparing 2.2.8
# Added Files: COPYRIGHT
# Modified Files: Parse.grammar
# Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#
# Revision 19991216.7 2002/08/23 13:29:49 dkernen
#
# Modified Files: Changes IMAPClient.pm INSTALL MANIFEST Makefile Makefile.PL README Todo test.txt
# Made changes to create version 2.1.6.
# Modified Files:
# imap_to_mbox.pl populate_mailbox.pl
# Added Files:
# cleanTest.pl migrate_mbox.pl
#
# Revision 19991216.6 2000/12/11 21:58:53 dkernen
#
# Modified Files:
# build_dist.pl build_ldif.pl copy_folder.pl find_dup_msgs.pl
# imap_to_mbox.pl populate_mailbox.pl
# to add CVS data
#
# Revision 19991216.5 1999/12/16 17:19:15 dkernen
# Bring up to same level
#
# Revision 19991124.3 1999/12/16 17:14:26 dkernen
# Incorporate changes for exists method performance enhancement
#
# Revision 19991124.02 1999/11/24 17:46:21 dkernen
# More fixes to t/basic.t
#
# Revision 19991124.01 1999/11/24 16:51:51 dkernen
# Changed t/basic.t to test for UIDPLUS before trying UID cmds
#
# Revision 1.4 1999/11/23 17:51:06 dkernen
# Committing version 1.06 distribution copy
#

View file

@ -0,0 +1,88 @@
#!/usr/local/bin/perl
#$Id$
use Mail::IMAPClient;
use Getopt::Std;
use File::Basename;
getopts('s:u:p:f:dh');
if ($opt_h) {
print STDERR "$0 -- example of how to select shared folder\n",
"\n\nUsage:\n",
"\t-s server -- specify name or ip address of mail server\n",
"\t-u userid -- specify login name of authenticating user\n",
"\t-p passwd -- specify login password of authenticating user\n",
"\t-f folder -- specify shared folder to access (i.e. '-f frank/INBOX')\n",
"\t-h display this help message\n\n";
"\t-d turn on debugging output\n\n";
exit;
}
my $server = $opt_s or die "No server name specified\n";
my $user = $opt_u or die "No user name specified\n";
my $pass = $opt_p or die "No password specified\n";
my $folder = $opt_f or die "No shared folder specified\n";
chomp $pass;
my $imap = Mail::IMAPClient->new(Server=>$server,User=>$user,Password=>$pass,Debug=>$opt_d)
or die "Can't connect to $user\@$server: $@ $!\n";
my($prefix,$prefSep) = @{$imap->namespace->[1][0]}
or die "Can't get shared folder namespace or separator: $@\n";
my $target = $prefix .
( $prefix =~ /\Q$prefSep\E$/ || $opt_f =~ /^\Q$prefSep/ ? "" : $prefSep ) .
$opt_f ;
print "Selecting $target\n";
$imap->select($target)
or die "Cannot select $target: $@\n";
print "Ok: $target has ", $imap->message_count($target)," messages.\n";
$imap->logout;
exit;
=head1 AUTHOR
David J. Kernen
The Kernen Group, Inc.
imap@kernengroup.com
=head1 COPYRIGHT
This example and Mail::IMAPClient are Copyright (c) 2003
by The Kernen Group, Inc. All rights reserved.
This example is distributed with Mail::IMAPClient and
subject to the same licensing requirements as Mail::IMAPClient.
imtest is a utility distributed with Cyrus IMAP server,
Copyright (c) 1994-2000 Carnegie Mellon University.
All rights reserved.
=cut
#
#$Log: sharedFolder.pl,v $
#Revision 19991216.1 2003/06/12 21:38:35 dkernen
#
#Preparing 2.2.8
#Added Files: COPYRIGHT
#Modified Files: Parse.grammar
#Added Files: Makefile.old
# Makefile.PL Todo sample.perldb
# BodyStructure.pm
# Parse.grammar Parse.pod
# range.t
# Thread.grammar
# draft-crispin-imapv-17.txt rfc1731.txt rfc2060.txt rfc2062.txt
# rfc2221.txt rfc2359.txt rfc2683.txt
#
#

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,576 @@
use warnings;
use strict;
package Mail::IMAPClient::BodyStructure;
use Mail::IMAPClient::BodyStructure::Parse;
# BUG?: old code used name "HEAD" instead of "HEADER", change?
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";
sub new {
my $class = shift;
my $bodystructure = shift;
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;
}
sub _get_thingy {
my $thingy = shift;
my $object = shift || ( ref $thingy ? $thingy : undef );
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" : '' );
return undef;
}
my $value = $object->{$thingy};
$value =~ s/\\ ( [\\\(\)"\x0d\x0a] )/$1/gx;
$value =~ s/^"(.*)"$/$1/;
$value;
}
BEGIN {
no strict 'refs';
foreach my $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};
my @parts;
$self->{PartsList} = \@parts;
# BUG?: should this default to ($HEAD, TEXT)
unless ( exists $self->{bodystructure} ) {
$self->{PartsIndex}{1} = $self;
@parts = ( $HEAD, 1 );
return wantarray ? @parts : \@parts;
}
foreach my $p ( $self->bodystructure ) {
my $id = $p->id;
push @parts, $id;
$self->{PartsIndex}{$id} = $p;
my $type = uc $p->bodytype || '';
push @parts, "$id.$HEAD"
if $type eq 'MESSAGE';
}
wantarray ? @parts : \@parts;
}
sub bodystructure {
my $self = shift;
my $partno = 0;
my @parts;
if ( $self->{_top} ) {
$self->{_id} ||= $HEAD;
$self->{_prefix} ||= $HEAD;
$partno = 0;
foreach my $b ( @{ $self->{bodystructure} } ) {
$b->{_id} = ++$partno;
$b->{_prefix} = $partno;
push @parts, $b, $b->bodystructure;
}
return wantarray ? @parts : \@parts;
}
my $prefix = $self->{_prefix} || "";
$prefix =~ s/\.?$/./;
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()?)
# - Should every message should have HEAD (actually MIME) and TEXT?
# at least dovecot and iplanet appear to allow this even for
# non-multipart sections
my $pno = $partno;
my $stype = $self->{bodytype} || "";
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' ) {
$pno = "TEXT";
$p->{_prefix} = "$prefix";
}
else {
$p->{_prefix} = "$prefix$partno";
}
$p->{_id} ||= "$prefix$pno";
push @parts, $p, $p->{bodystructure} ? $p->bodystructure : ();
}
wantarray ? @parts : \@parts;
}
sub id {
my $self = shift;
return $self->{_id}
if exists $self->{_id};
return $HEAD
if $self->{_top};
# BUG?: can this be removed? ... seems wrong
if ( $self->{bodytype} eq 'MULTIPART' ) {
my $p = $self->{_id} || $self->{_prefix};
$p =~ s/\.$//;
return $p;
}
else {
return $self->{_id} ||= 1;
}
}
package Mail::IMAPClient::BodyStructure::Part;
our @ISA = qw/Mail::IMAPClient::BodyStructure/;
package Mail::IMAPClient::BodyStructure::Envelope;
our @ISA = qw/Mail::IMAPClient::BodyStructure/;
sub new {
my ( $class, $envelope ) = @_;
$parser->envelope($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 _addresses($$$) {
my ( $self, $name, $isSender ) = @_;
ref $self->{$name} eq 'ARRAY'
or return ();
my @list;
foreach ( @{ $self->{$name} } ) {
my $pn = $_->personalname;
my $name = $pn && $pn ne 'NIL' ? "$pn " : '';
push @list, $name . '<' . $_->mailboxname . '@' . $_->hostname . '>';
}
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} }
}
}
package Mail::IMAPClient::BodyStructure::Address;
our @ISA = qw/Mail::IMAPClient::BodyStructure/;
for my $datum (qw(personalname mailboxname hostname sourcename)) {
no strict 'refs';
*$datum = sub { shift->{$datum}; };
}
1;
__END__
=head1 NAME
Mail::IMAPClient::BodyStructure - parse fetched results
=head1 SYNOPSIS
use Mail::IMAPClient;
use Mail::IMAPClient::BodyStructure;
my $imap = Mail::IMAPClient->new(
Server => $server, User => $login, Password => $pass
);
$imap->select("INBOX") or die "Could not select INBOX: $@\n";
my @recent = $imap->search("recent") or die "No recent msgs in INBOX\n";
foreach my $id (@recent) {
my $bsdat = $imap->fetch( $id, "bodystructure" );
my $bso = Mail::IMAPClient::BodyStructure->new( join("", $imap->History) );
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
to help pull information out of the data structure.
This module requires Parse::RecDescent.
=head1 Class Methods
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.
The module B<Mail::IMAPClient> provides the B<get_bodystructure>
convenience method to simplify use of this module when starting with
just a messages sequence number or unique ID (UID).
=head1 Object Methods
The following object methods are available:
=head2 bodytype
The B<bodytype> object method requires no arguments. It returns the
bodytype for the message whose structure is described by the calling
B<Mail::IMAPClient::Bodystructure> object.
=head2 bodysubtype
The B<bodysubtype> object method requires no arguments. It returns the
bodysubtype for the message whose structure is described by the calling
B<Mail::IMAPClient::Bodystructure> object.
=head2 bodyparms
The B<bodyparms> object method requires no arguments. It returns the
bodyparms for the message whose structure is described by the calling
B<Mail::IMAPClient::Bodystructure> object.
=head2 bodydisp
The B<bodydisp> object method requires no arguments. It returns the
bodydisp for the message whose structure is described by the calling
B<Mail::IMAPClient::Bodystructure> object.
=head2 bodyid
The B<bodyid> object method requires no arguments. It returns the
bodyid for the message whose structure is described by the calling
B<Mail::IMAPClient::Bodystructure> object.
=head2 bodydesc
The B<bodydesc> object method requires no arguments. It returns the
bodydesc for the message whose structure is described by the calling
B<Mail::IMAPClient::Bodystructure> object.
=head2 bodyenc
The B<bodyenc> object method requires no arguments. It returns the
bodyenc for the message whose structure is described by the calling
B<Mail::IMAPClient::Bodystructure> object.
=head2 bodysize
The B<bodysize> object method requires no arguments. It returns the
bodysize for the message whose structure is described by the calling
B<Mail::IMAPClient::Bodystructure> object.
=head2 bodylang
The B<bodylang> object method requires no arguments. It returns the
bodylang for the message whose structure is described by the calling
B<Mail::IMAPClient::Bodystructure> object.
=head2 bodystructure
The B<bodystructure> object method requires no arguments. It returns
the bodystructure for the message whose structure is described by the
calling B<Mail::IMAPClient::Bodystructure> object.
=head2 envelopestruct
The B<envelopestruct> object method requires no arguments. It returns
a B<Mail::IMAPClient::BodyStructure::Envelope> object for the message
from the calling B<Mail::IMAPClient::Bodystructure> object.
=head2 textlines
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 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
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
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.
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 ],
}
The B<...::Envelope> object also has methods for accessing data in the
structure. They are:
=over 4
=item date
Returns the date of the message.
=item inreplyto
Returns the message id of the message to which this message is a reply.
=item subject
Returns the subject of the message.
=item messageid
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
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.
See the section on B<Mail::IMAPClient::BodyStructure::Address>, below,
for alternate (and preferred) ways of accessing these data.
The methods available are:
=over 4
=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.)
=item cc
Returns an array of cc'ed recipients' address structures.
=item from
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.
=item sender
Returns an array of senders' address structures--usually just one and
usually the same as B<from>.
=item to
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 analogous 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:
=over 4
=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
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.
=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.)
=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.
=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.
=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.
=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 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,
B<Mail::IMAPClient::BodyStructure::Address>, which looks like this:
{
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.
Each of these objects has the following methods available to it:
=over 4
=item mailboxname
Returns the "mailboxname" portion of the address, which is the part to
the left of the '@' sign.
=item hostname
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.
=item sourceroute
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:
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
B<Mail::IMAPClient::BodyStructure::Envelope> need them anyway.)
=cut
=head1 AUTHOR
Original author: David J. Kernen; Reworked by: Mark Overmeer;
Maintained by Phil Pearl.
=head1 SEE ALSO
perl(1), Mail::IMAPClient, Parse::RecDescent, and RFC2060.
=cut

View file

@ -0,0 +1,189 @@
# Directives
# ( none)
# Start-up Actions
{
my $mibs = "Mail::IMAPClient::BodyStructure";
my $subpartCount = 0;
my $partCount = 0;
sub take_optional_items($$@)
{ my ($r, $items) = (shift, shift);
foreach (@_)
{ my $opt = $_ .'(?)';
exists $items->{$opt} or next;
$r->{$_} = UNIVERSAL::isa($items->{$opt}, 'ARRAY')
? $items->{$opt}[0] : $items->{$opt};
}
}
sub merge_hash($$)
{ my $to = shift;
my $from = shift or return;
while( my($k,$v) = each %$from) { $to->{$k} = $v }
}
}
# Atoms
TEXT: /^"TEXT"|^TEXT/i { $return = "TEXT" }
PLAIN: /^"PLAIN"|^PLAIN/i { $return = "PLAIN" }
HTML: /"HTML"|HTML/i { $return = "HTML" }
MESSAGE: /^"MESSAGE"|^MESSAGE/i { $return = "MESSAGE"}
RFC822: /^"RFC822"|^RFC822/i { $return = "RFC822" }
NIL: /^NIL/i { $return = "NIL" }
RFCNONCOMPLY: /^\(\)/i { $return = "NIL" }
NUMBER: /^(\d+)/ { $return = $item[1] }
# Strings:
SINGLE_QUOTED_STRING: "'" /(?:\\['\\]|[^'])*/ "'" { $return = $item{__PATTERN1__} }
DOUBLE_QUOTED_STRING: '"' /(?:\\["\\]|[^"])*/ '"' { $return = $item{__PATTERN1__} }
BARESTRING: ...!/^[)('"]/ /^(?!\(|\))(?:\\ |\S)+/
{ $return = $item{__PATTERN1__} }
STRING: DOUBLE_QUOTED_STRING | SINGLE_QUOTED_STRING | BARESTRING
STRINGS: "(" STRING(s) ")" { $return = $item{'STRING(s)'} }
textlines: NIL | NUMBER
rfc822message: MESSAGE RFC822 { $return = "MESSAGE RFC822" }
bodysubtype: PLAIN | HTML | NIL | STRING
key: STRING
value: NIL | NUMBER | STRING | KVPAIRS
kvpair: ...!")" key value
{ $return = { $item{key} => $item{value} } }
KVPAIRS: "(" kvpair(s) ")"
{ $return = { map { (%$_) } @{$item{'kvpair(s)'}} } }
bodytype: STRING
bodyparms: NIL | KVPAIRS
bodydisp: NIL | KVPAIRS
bodyid: ...!/[()]/ NIL | STRING
bodydesc: ...!/[()]/ NIL | STRING
bodysize: ...!/[()]/ NIL | NUMBER
bodyenc: NIL | STRING | KVPAIRS
bodyMD5: NIL | STRING
bodylang: NIL | STRING | STRINGS
bodyextra: NIL | STRING | STRINGS
bodyloc: NIL | STRING
personalname: NIL | STRING
sourceroute: NIL | STRING
mailboxname: NIL | STRING
hostname: NIL | STRING
addressstruct: "(" personalname sourceroute mailboxname hostname ")"
{ bless { personalname => $item{personalname}
, sourceroute => $item{sourceroute}
, mailboxname => $item{mailboxname}
, hostname => $item{hostname}
}, 'Mail::IMAPClient::BodyStructure::Address';
}
subject: NIL | STRING
inreplyto: NIL | STRING
messageid: NIL | STRING
date: NIL | STRING
ADDRESSES: NIL | RFCNONCOMPLY
| "(" addressstruct(s) ")" { $return = $item{'addressstruct(s)'} }
cc: ADDRESSES
bcc: ADDRESSES
from: ADDRESSES
replyto: ADDRESSES
sender: ADDRESSES
to: ADDRESSES
envelopestruct: "(" date subject from sender replyto to cc
bcc inreplyto messageid ")"
{ $return = bless {}, "Mail::IMAPClient::BodyStructure::Envelope";
$return->{$_} = $item{$_}
for qw/date subject from sender replyto to cc/
, qw/bcc inreplyto messageid/;
1;
}
basicfields: bodysubtype bodyparms(?) bodyid(?)
bodydesc(?) bodyenc(?) bodysize(?)
{ $return = { bodysubtype => $item{bodysubtype} };
take_optional_items($return, \%item,
qw/bodyparms bodyid bodydesc bodyenc bodysize/);
1;
}
textmessage: TEXT <commit> basicfields textlines(?) bodyMD5(?)
bodydisp(?) bodylang(?) bodyextra(?)
{
$return = $item{basicfields} || {};
$return->{bodytype} = 'TEXT';
take_optional_items($return, \%item
, qw/textlines bodyMD5 bodydisp bodylang bodyextra/);
1;
}
othertypemessage: bodytype basicfields bodyMD5(?) bodydisp(?)
bodylang(?) bodyextra(?)
{ $return = { bodytype => $item{bodytype} };
take_optional_items($return, \%item
, qw/bodyMD5 bodydisp bodylang bodyextra/ );
merge_hash($return, $item{basicfields});
1;
}
nestedmessage: rfc822message <commit> bodyparms bodyid bodydesc bodyenc
# bodysize envelopestruct bodystructure textlines
bodysize envelopestruct(?) bodystructure(?) textlines(?)
bodyMD5(?) bodydisp(?) bodylang(?) bodyextra(?)
{
$return = {};
$return->{$_} = $item{$_}
for qw/bodyparms bodyid bodydesc bodyenc bodysize/;
# envelopestruct bodystructure textlines/;
take_optional_items($return, \%item
, qw/envelopestruct bodystructure textlines/
, qw/bodyMD5 bodydisp bodylang bodyextra/);
merge_hash($return, $item{bodystructure}[0]);
merge_hash($return, $item{basicfields});
$return->{bodytype} = "MESSAGE" ;
$return->{bodysubtype} = "RFC822" ;
1;
}
multipart: subpart(s) <commit> bodysubtype
bodyparms(?) bodydisp(?) bodylang(?) bodyloc(?) bodyextra(?)
<defer: $subpartCount = 0>
{ $return =
{ bodysubtype => $item{bodysubtype}
, bodytype => 'MULTIPART'
, bodystructure => $item{'subpart(s)'}
};
take_optional_items($return, \%item
, qw/bodyparms bodydisp bodylang bodyloc bodyextra/);
1;
}
subpart: "(" part ")" {$return = $item{part}} <defer: ++$subpartCount;>
part: multipart { $return = bless $item{multipart}, $mibs }
| textmessage { $return = bless $item{textmessage}, $mibs }
| nestedmessage { $return = bless $item{nestedmessage}, $mibs }
| othertypemessage { $return = bless $item{othertypemessage}, $mibs }
bodystructure: "(" part(s) ")"
{ $return = $item{'part(s)'} }
start: /.*?\(.*?BODYSTRUCTURE \(/i part(1) /\).*\)\r?\n?/
{ $return = $item{'part(1)'}[0] }
envelope: /.*?\(.*?ENVELOPE/ envelopestruct /.*\)/
{ $return = $item{envelopestruct} }

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,15 @@
=head1 NAME
Mail::IMAPClient::BodyStructure::Parse - used internally by Mail::IMAPClient::BodyStructure
=head1 DESCRIPTION
This module is used internally by L<Mail::IMAPClient::BodyStructure>
and is generated using L<Parse::RecDescent>. It is not meant to be used
directly by other scripts nor is there much point in debugging it.
=head1 SYNOPSIS
This module is used internally by L<Mail::IMAPClient::BodyStructure>
and is not meant to be used or called directly from applications. So
don't do that.

View file

@ -0,0 +1,280 @@
use warnings;
use strict;
package Mail::IMAPClient::MessageSet;
=head1 NAME
Mail::IMAPClient::MessageSet - ranges of message sequence numbers
=cut
use overload
'""' => "str"
, '.=' => sub {$_[0]->cat($_[1])}
, '+=' => sub {$_[0]->cat($_[1])}
, '-=' => sub {$_[0]->rem($_[1])}
, '@{}' => "unfold"
, fallback => 1;
sub new
{ my $class = shift;
my $range = $class->range(@_);
bless \$range, $class;
}
sub str { overload::StrVal( ${$_[0]} ) }
sub _unfold_range($)
# { my $x = shift; return if $x =~ m/[^0-9,:]$/; $x =~ s/\:/../g; eval $x; }
{ map { /(\d+)\s*\:\s*(\d+)/ ? ($1..$2) : $_ }
split /\,/, shift;
}
sub rem
{ my $self = shift;
my %delete = map { ($_ => 1) } map { _unfold_range $_ } @_;
$$self = $self->range(grep {not $delete{$_}} $self->unfold);
$self;
}
sub cat
{ my $self = shift;
$$self = $self->range($$self, @_);
$self;
}
sub range
{ my $self = shift;
my @msgs;
foreach my $m (@_)
{ defined $m && length $m
or next;
foreach my $mm (ref $m eq 'ARRAY' ? @$m : $m)
{ push @msgs, _unfold_range $mm;
}
}
@msgs
or return undef;
@msgs = sort {$a <=> $b} @msgs;
my $low = my $high = shift @msgs;
my @ranges;
foreach my $m (@msgs)
{ next if $m == $high; # double
if($m == $high + 1) { $high = $m }
else
{ push @ranges, $low == $high ? $low : "$low:$high";
$low = $high = $m;
}
}
push @ranges, $low == $high ? $low : "$low:$high" ;
join ",", @ranges;
}
sub unfold
{ my $self = shift;
wantarray ? ( _unfold_range $$self ) : [ _unfold_range $$self ];
}
=head1 SYNOPSIS
my @msgs = $imap->search("SUBJECT","Virus"); # returns 1,3,4,5,6,9,10
my $msgset = Mail::IMAPClient::MessageSet->new(@msgs);
print $msgset; # prints "1,3:6,9:10"
# add message 14 to the set:
$msgset += 14;
print $msgset; # prints "1,3:6,9:10,14"
# add messages 16,17,18,19, and 20 to the set:
$msgset .= "16,17,18:20";
print $msgset; # prints "1,3:6,9:10,14,16:20"
# Hey, I didn't really want message 17 in there; let's take it out:
$msgset -= 17;
print $msgset; # prints "1,3:6,9:10,14,16,18:20"
# Now let's iterate over each message:
for my $msg (@$msgset)
{ print "$msg\n"; # Prints: "1\n3\n4\n5\n6..16\n18\n19\n20\n"
}
print join("\n", @$msgset)."\n"; # same simpler
local $" = "\n"; print "@$msgset\n"; # even more simple
=head1 DESCRIPTION
The B<Mail::IMAPClient::MessageSet> module is designed to make life easier
for programmers who need to manipulate potentially large sets of IMAP
message UID's or sequence numbers.
This module presents an object-oriented interface into handling your
message sets. The object reference returned by the L<new> method is an
overloaded reference to a scalar variable that contains the message set's
compact RFC2060 representation. The object is overloaded so that using
it like a string returns this compact message set representation. You
can also add messages to the set (using either a '.=' operator or a '+='
operator) or remove messages (with the '-=' operator). And if you use
it as an array reference, it will humor you and act like one by calling
L<unfold> for you.
RFC2060 specifies that multiple messages can be provided to certain IMAP
commands by separating them with commas. For example, "1,2,3,4,5" would
specify messages 1, 2, 3, 4, and (you guessed it!) 5. However, if you are
performing an operation on lots of messages, this string can get quite long.
So long that it may slow down your transaction, and perhaps even cause the
server to reject it. So RFC2060 also permits you to specify a range of
messages, so that messages 1, 2, 3, 4 and 5 can also be specified as
"1:5".
This is where B<Mail::IMAPClient::MessageSet> comes in. It will convert
your message set into the shortest correct syntax. This could potentially
save you tons of network I/O, as in the case where you want to fetch the
flags for all messages in a 10000 message folder, where the messages
are all numbered sequentially. Delimited as commas, and making the
best-case assumption that the first message is message "1", it would take
48893 bytes to specify the whole message set using the comma-delimited
method. To specify it as a range, it takes just seven bytes (1:10000).
Note that the L<Mail::IMAPClient> B<Range> method can be used as
a short-cut to specifying C<Mail::IMAPClient::MessageSet-E<gt>new(@etc)>.)
=head1 CLASS METHODS
The only class method you need to worry about is B<new>. And if you create
your B<Mail::IMAPClient::MessageSet> objects via L<Mail::IMAPClient>'s
B<Range> method then you don't even need to worry about B<new>.
=head2 new
Example:
my $msgset = Mail::IMAPClient::MessageSet->new(@msgs);
The B<new> method requires at least one argument. That argument can be
either a message, a comma-separated list of messages, a colon-separated
range of messages, or a combination of comma-separated messages and
colon-separated ranges. It can also be a reference to an array of messages,
comma-separated message lists, and colon separated ranges.
If more then one argument is supplied to B<new>, then those arguments should
be more message numbers, lists, and ranges (or references to arrays of them)
just as in the first argument.
The message numbers passed to B<new> can really be any kind of number at
all but to be useful in a L<Mail::IMAPClient> session they should be either
message UID's (if your I<Uid> parameter is true) or message sequence numbers.
The B<new> method will return a reference to a B<Mail::IMAPClient::MessageSet>
object. That object, when double quoted, will act just like a string whose
value is the message set expressed in the shortest possible way, with the
message numbers sorted in ascending order and with duplicates removed.
=head1 OBJECT METHODS
The only object method currently available to a B<Mail::IMAPClient::MessageSet>
object is the L<unfold> method.
=head2 unfold
Example:
my $msgset = $imap->Range( $imap->messages ) ;
my @all_messages = $msgset->unfold;
The B<unfold> method returns an array of messages that belong to the
message set. If called in a scalar context it returns a reference to the
array instead.
=head1 OVERRIDDEN OPERATIONS
B<Mail::IMAPClient::MessageSet> overrides a number of operators in order
to make manipulating your message sets easier. The overridden operations are:
=head2 stringify
Attempts to stringify a B<Mail::IMAPClient::MessageSet> object will result in
the compact message specification being returned, which is almost certainly
what you will want.
=head2 Auto-increment
Attempts to autoincrement a B<Mail::IMAPClient::MessageSet> object will
result in a message (or messages) being added to the object's message set.
Example:
$msgset += 34;
# Message #34 is now in the message set
=head2 Concatenate
Attempts to concatenate to a B<Mail::IMAPClient::MessageSet> object will
result in a message (or messages) being added to the object's message set.
Example:
$msgset .= "34,35,36,40:45";
# Messages 34,35,36,40,41,42,43,44,and 45 are now in the message set
The C<.=> operator and the C<+=> operator can be used interchangeably, but
as you can see by looking at the examples there are times when use of one
has an aesthetic advantage over use of the other.
=head2 Autodecrement
Attempts to autodecrement a B<Mail::IMAPClient::MessageSet> object will
result in a message being removed from the object's message set.
Examples:
$msgset -= 34;
# Message #34 is no longer in the message set
$msgset -= "1:10";
# Messages 1 through 10 are no longer in the message set
If you attempt to remove a message that was not in the original message set
then your resulting message set will be the same as the original, only more
expensive. However, if you attempt to remove several messages from the message
set and some of those messages were in the message set and some were not,
the additional overhead of checking for the messages that were not there
is negligible. In either case you get back the message set you want regardless
of whether it was already like that or not.
=head1 AUTHOR
David J. Kernen
The Kernen Consulting Group, Inc
=head1 COPYRIGHT
Copyright 1999, 2000, 2001, 2002 The Kernen Group, Inc.
All rights reserved.
This program is free software; you can redistribute it and/or modify it
under the terms of either:
=over 4
=item a) the "Artistic License" which comes with this Kit, or
=item b) the GNU General Public License as published by the Free Software
Foundation; either version 1, or (at your option) any later version.
=back
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU
General Public License or the Artistic License for more details. All your
base are belong to us.
=cut
1;

View file

@ -0,0 +1,18 @@
# Atoms:
NUMBER: /\d+/
# Rules:
threadmember: NUMBER { $return = $item{NUMBER} ; } |
thread { $return = $item{thread} ; }
thread: "(" threadmember(s) ")"
{
$return = $item{'threadmember(s)'}||undef;
}
# Start:
start: /^\* THREAD /i thread(s?) {
$return=$item{'thread(s?)'}||undef;
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,14 @@
=head1 NAME
Mail::IMAPClient::Thread - used internally by Mail::IMAPClient->thread
=head1 DESCRIPTION
This module is used internally by L<Mail::IMAPClient> and is
generated using L<Parse::RecDescent>. It is not meant to be used directly by
other scripts nor is there much point in debugging it.
=head1 SYNOPSIS
This module is used internally by L<Mail::IMAPClient> and is not meant to
be used or called directly from applications. So don't do that.

View file

@ -0,0 +1,43 @@
#!/usr/bin/perl
use strict;
use warnings;
use File::Copy qw/move/;
use Parse::RecDescent 1.94;
sub read_file {
my $file = shift;
local ( $/, *FH );
open( FH, $file ) or return undef;
return <FH>;
}
build_parser(
'lib/Mail/IMAPClient/BodyStructure/Parse.grammar',
'Mail::IMAPClient::BodyStructure::Parse'
);
build_parser( 'lib/Mail/IMAPClient/Thread.grammar',
'Mail::IMAPClient::Thread' );
sub build_parser {
my ( $grammarfn, $package ) = @_;
print("* building $package\n");
my $grammar = read_file($grammarfn)
or die("cannot read grammar from $grammarfn: $!\n");
Parse::RecDescent->Precompile( $grammar, $package );
# clumpsy output by Parse::RecDescent
my $outfn = $package . '.pm';
$outfn =~ s/.*\:\://;
my $realfn = $grammarfn;
$realfn =~ s/\.\w+$/.pm/;
move( $outfn, $realfn )
or die("cannot move $outfn to $realfn: $!\n");
}

View file

@ -0,0 +1,487 @@
#!/usr/bin/perl
use strict;
use warnings;
use IO::File qw();
use Test::More;
use File::Temp qw(tempfile);
my $debug = $ARGV[0];
my %parms;
my $range = 0;
my $uidplus = 0;
my $fast = 1;
BEGIN {
open TST, 'test.txt'
or plan skip_all => 'test parameters not provided in test.txt';
while ( my $l = <TST> ) {
chomp $l;
my ( $p, $v ) = split /\=/, $l, 2;
s/^\s+//, s/\s+$// for $p, $v;
$parms{$p} = $v if $v;
}
close TST;
my @missing;
foreach my $p (qw/server user passed/) {
push( @missing, $p ) unless defined $parms{$p};
}
@missing
? plan skip_all => "missing value for: @missing"
: plan tests => 104;
}
BEGIN { use_ok('Mail::IMAPClient') or exit; }
my %new_args = (
Server => delete $parms{server},
Port => delete $parms{port},
User => delete $parms{user},
Password => delete $parms{passed},
Authmechanism => delete $parms{authmech},
Clear => 0,
Fast_IO => $fast,
Uid => $uidplus,
Debug => $debug,
);
# allow other options to be placed in test.txt
%new_args = ( %new_args, %parms );
my $imap = Mail::IMAPClient->new(
%new_args,
Range => $range,
Debug_fh => ( $debug ? IO::File->new( 'imap1.debug', 'w' ) : undef ),
);
ok( defined $imap, 'created client' );
$imap
or die "Cannot log into $new_args{Server} as $new_args{User}.\n"
. "Are server/user/password correct?\n";
isa_ok( $imap, 'Mail::IMAPClient' );
$imap->Debug_fh->autoflush() if $imap->Debug_fh;
my $testmsg = <<__TEST_MSG;
Date: @{[$imap->Rfc822_date(time)]}
To: <$new_args{User}\@$new_args{Server}>
From: Perl <$new_args{User}\@$new_args{Server}>
Subject: Testing from pid $$
This is a test message generated by $0 during a 'make test' as part of
the installation of the Mail::IMAPClient module from CPAN.
__TEST_MSG
ok( $imap->noop, "noop" );
ok( $imap->tag_and_run("NOOP\r\n"), "tag_and_run" );
my $sep = $imap->separator;
ok( defined $sep, "separator is '$sep'" );
{
my $list = $imap->list();
is( ref($list), "ARRAY", "list" );
my $lsub = $imap->lsub();
is( ref($lsub), "ARRAY", "lsub" );
}
my ( $target, $target2 );
{
my $ispar = $imap->is_parent('INBOX');
my $pre = $ispar ? "INBOX${sep}" : "";
( $target, $target2 ) = ( "${pre}IMAPClient_$$", "${pre}IMAPClient_2_$$" );
ok( defined $ispar, "INBOX is_parent '$ispar' (note: target '$target')" );
}
ok( $imap->select('inbox'), "select inbox" );
# folders
{
my @f = $imap->folders();
ok( @f, "folders" . ( $debug ? ":@f" : "" ) );
my @fh = $imap->folders_hash();
my @fh_keys = qw(attrs delim name);
ok( @fh, "folders_hash keys: @fh_keys" );
is_deeply(
[ sort keys %{ $fh[0] } ],
[ sort @fh_keys ],
"folders eq folders_hash"
)
}
# test append_file
my $append_file_size;
{
my ( $afh, $afn ) = tempfile UNLINK => 1;
# write message to autoflushed file handle since we keep $afh around
my $oldfh = select($afh);
$| = 1;
select($oldfh);
print( $afh $testmsg ) or die("print testmsg failed");
cmp_ok( -s $afn, '>', 0, "tempfile has size" );
ok( $imap->create($target), "create target" );
my $uid = $imap->append_file( $target, $afn );
ok( defined $uid, "append_file test message to $target" );
ok( $imap->select($target), "select $target" );
my $msg = ( $uidplus and $uid ) ? $uid : ( $imap->messages )[0];
my $size = $imap->size($msg);
cmp_ok( $size, '>', 0, "has size $size" );
my $string = $imap->message_string($msg);
ok( defined $string, "returned string" );
cmp_ok( length($string), '==', $size, "string matches server size" );
# dovecot may disconnect client if deleting selected folder
ok( $imap->select("INBOX"), "select INBOX" );
ok( $imap->delete($target), "delete folder $target" );
$append_file_size = $size;
}
# rt.cpan.org#91912: selectable test for /NoSelect
{
my $targetno = $target . "_noselect";
my $targetsubf = $targetno . "${sep}subfolder";
ok( $imap->create($targetsubf), "create target subfolder" );
ok( !$imap->selectable($targetno),
"not selectable (non-mailbox w/inferior)" );
ok( $imap->delete($targetsubf), "delete target subfolder" );
ok( $imap->delete($targetno), "delete parent folder" );
}
ok( $imap->create($target), "create target" );
ok( $imap->select($target), "select $target" );
# Test append / append_string if we also have UID capability
SKIP: {
skip "UIDPLUS not supported", 3 unless $imap->has_capability("UIDPLUS");
my $ouid = $imap->Uid();
$imap->Uid(1);
# test with date that has a leading space
my $d = " 1-Jan-2011 01:02:03 -0500";
my $uid = $imap->append_string( $target, $testmsg, undef, $d );
ok( defined $uid, "append test message to $target with date (uid=$uid)" );
# hash results do not have UID unless requested
my $h1 = $imap->fetch_hash( $uid, "RFC822.SIZE" );
is( ref($h1), "HASH", "fetch_hash($uid,RFC822.SIZE)" );
is( scalar keys %$h1, 1, "fetch_hash: fetched one msg (as requested)" );
is( !exists $h1->{$uid}->{UID}, 1, "fetch_hash: no UID (not requested)" );
$h1 = $imap->fetch_hash( $uid, "UID RFC822.SIZE" );
is( exists $h1->{$uid}->{UID}, 1, "fetch_hash: has UID (as requested)" );
ok( $imap->delete_message($uid), "delete_message $uid" );
ok( $imap->uidexpunge($uid), "uidexpunge $uid" );
# multiple args joined internally in append()
$uid = $imap->append( $target, $testmsg, "Some extra text too" );
ok( defined $uid, "append test message to $target with date (uid=$uid)" );
ok( $imap->delete_message($uid), "delete_message $uid" );
ok( $imap->uidexpunge($uid), "uidexpunge $uid" );
$imap->Uid($ouid);
}
# test append
{
my $uid = $imap->append( $target, $testmsg );
ok( defined $uid, "append test message to $target" );
my $msg = ( $uidplus and $uid ) ? $uid : ( $imap->messages )[0];
my $size = $imap->size($msg);
cmp_ok( $size, '>', 0, "has size $size" );
my $string = $imap->message_string($msg);
ok( defined $string, "returned string" );
cmp_ok( length($string), '==', $size, "string == server size" );
{
my $var;
ok( $imap->message_to_file( \$var, $msg ), "to SCALAR ref" );
cmp_ok( length($var), '==', $size, "correct size" );
my ( $fh, $fn ) = tempfile UNLINK => 1;
ok( $imap->message_to_file( $fn, $msg ), "to file $fn" );
cmp_ok( -s $fn, '==', $size, "correct size" );
}
cmp_ok( $size, '==', $append_file_size, "size matches string/file" );
# save first message/folder for use below...
#OFF ok( $imap->delete($target), "delete folder $target" );
}
#OFF ok( $imap->create($target), "create target" );
ok( $imap->exists($target), "exists $target" );
ok( $imap->create($target2), "create $target2" );
ok( $imap->exists($target2), "exists $target2" );
is( defined $imap->is_parent($sep), 1, "is_parent($sep)" );
is( !$imap->is_parent($target2), 1, "is_parent($target2)" );
{
ok( $imap->subscribe($target), "subscribe $target" );
my $sub1 = $imap->subscribed();
is( ( grep( /^\Q$target\E$/, @$sub1 ) )[0], "$target", "subscribed" );
ok( $imap->unsubscribe($target), "unsubscribe target" );
my $sub2 = $imap->subscribed();
is( ( grep( /^\Q$target\E$/, @$sub2 ) )[0], undef, "unsubscribed" );
}
my $fwquotes = qq($target has "quotes");
if ( $imap->create($fwquotes) ) {
ok( 1, "create '$fwquotes'" );
ok( $imap->select($fwquotes), "select '$fwquotes'" );
ok( $imap->close, "close '$fwquotes'" );
$imap->select('inbox');
ok( $imap->delete($fwquotes), "delete '$fwquotes'" );
}
else {
my $err = $imap->LastError || "(no error)";
ok( 1, "failed creation with quotes, assume not supported: $err" );
ok( 1, "skipping 1/3 tests" );
ok( 1, "skipping 2/3 tests" );
ok( 1, "skipping 3/3 tests" );
}
ok( $imap->select($target), "select $target" );
my $fields = $imap->search( "HEADER", "Message-id", "NOT_A_MESSAGE_ID" );
is( scalar @$fields, 0, 'bogus message id does not exist' );
my @seen = $imap->seen;
cmp_ok( scalar @seen, '==', 1, 'have seen 1' );
ok( $imap->deny_seeing( \@seen ), 'deny seeing' );
my @unseen = $imap->unseen;
cmp_ok( scalar @unseen, '==', 1, 'have unseen 1' );
ok( $imap->see( \@seen ), "let's see one" );
cmp_ok( scalar @seen, '==', 1, 'have seen 1' );
$imap->deny_seeing(@seen); # reset
$imap->Peek(1);
my $subject = $imap->parse_headers( $seen[0], "Subject" )->{Subject}[0];
unlike( join( "", $imap->flags( $seen[0] ) ), qr/\\Seen/i, 'Peek==1' );
$imap->deny_seeing(@seen);
$imap->Peek(0);
$subject = $imap->parse_headers( $seen[0], "Subject" )->{Subject}[0];
like( join( "", $imap->flags( $seen[0] ) ), qr/\\Seen/i, 'Peek==0' );
$imap->deny_seeing(@seen);
$imap->Peek(undef);
$subject = $imap->parse_headers( $seen[0], "Subject" )->{Subject}[0];
unlike( join( "", $imap->flags( $seen[0] ) ), qr/\\Seen/i, 'Peek==undef' );
my $uid2 = $imap->copy( $target2, 1 );
ok( $uid2, "copy $target2" );
my @res = $imap->fetch( 1, "RFC822.TEXT" );
ok( scalar @res, "fetch rfc822" );
{
my $h1 = $imap->fetch_hash("RFC822.SIZE");
is( ref($h1), "HASH", "fetch_hash(RFC822.SIZE)" );
my $id = ( sort { $a <=> $b } keys %$h1 )[0];
my $h2 = $imap->fetch_hash( $id, "RFC822.SIZE" );
is( ref($h2), "HASH", "fetch_hash($id,RFC822.SIZE)" );
is( scalar keys %$h2, 1, "fetch_hash($id,RFC822.SIZE) => fetched one msg" );
}
{
my $seq = "1:*";
my @dat = (qw(RFC822.SIZE INTERNALDATE));
my $h1 = $imap->fetch_hash( $seq, @dat );
is( ref($h1), "HASH", "fetch_hash($seq, " . join( ", ", @dat ) . ")" );
# verify legacy and less desirable use case still works
my $h2 = $imap->fetch_hash("$seq @dat");
is( ref($h2), "HASH", "fetch_hash('$seq @dat')" );
is_deeply( $h1, $h2, "fetch_hash same result with array or string args" );
}
my $h = $imap->parse_headers( 1, "Subject" );
ok( $h, "got subject" );
like( $h->{Subject}[0], qr/^Testing from pid/, "subject matched" );
ok( $imap->select($target), "select $target" );
my @hits = $imap->search( SUBJECT => 'Testing' );
cmp_ok( scalar @hits, '==', 1, 'hit subject Testing' );
ok( defined $hits[0], "subject is defined" );
ok( $imap->delete_message(@hits), 'delete hits' );
my $flaghash = $imap->flags( \@hits );
my $flagflag = 0;
foreach my $v ( values %$flaghash ) {
$flagflag += grep /\\Deleted/, @$v;
}
cmp_ok( $flagflag, '==', scalar @hits, "delete verified" );
my @nohits = $imap->search( \qq(SUBJECT "Productioning") );
cmp_ok( scalar @nohits, '==', 0, 'no hits expected' );
ok( $imap->restore_message(@hits), 'restore messages' );
$flaghash = $imap->flags( \@hits );
foreach my $v ( values %$flaghash ) {
$flagflag-- unless grep /\\Deleted/, @$v;
}
cmp_ok( $flagflag, '==', 0, "restore verified" );
$imap->select($target2);
ok(
$imap->delete_message( scalar( $imap->search("ALL") ) )
&& $imap->close
&& $imap->delete($target2),
"delete $target2"
);
$imap->select("INBOX");
$@ = undef;
@hits =
$imap->search( BEFORE => Mail::IMAPClient::Rfc2060_date(time), "UNDELETED" );
ok( !$@, "search undeleted" ) or diag( '$@:' . $@ );
#
# Test migrate method
#
my $im2 = Mail::IMAPClient->new(
%new_args,
Timeout => 30,
Debug_fh => ( $debug ? IO::File->new(">./imap2.debug") : undef ),
);
ok( defined $im2, 'started second imap client' );
my $source = $target;
$imap->select($source)
or die "cannot select source $source: $@";
$imap->append( $source, $testmsg ) for 1 .. 5;
$imap->close;
$imap->select($source);
my $migtarget = $target . '_mirror';
$im2->create($migtarget)
or die "can't create $migtarget: $@";
$im2->select($migtarget)
or die "can't select $migtarget: $@";
$imap->migrate( $im2, scalar( $imap->search("ALL") ), $migtarget )
or die "couldn't migrate: $@";
$im2->close;
$im2->select($migtarget)
or die "can't select $migtarget: $@";
ok( !$@, "LastError not set" ) or diag( '$@:' . $@ );
#
my $total_bytes1 = 0;
for ( $imap->search("ALL") ) {
my $s = $imap->size($_);
$total_bytes1 += $s;
print "Size of msg $_ is $s\n" if $debug;
}
my $total_bytes2 = 0;
for ( $im2->search("ALL") ) {
my $s = $im2->size($_);
$total_bytes2 += $s;
print "Size of msg $_ is $s\n" if $debug;
}
ok( !$@, "LastError not set" ) or diag( '$@:' . $@ );
cmp_ok( $total_bytes1, '==', $total_bytes2, 'size source==target' );
# cleanup
$im2->select($migtarget);
$im2->delete_message( @{ $im2->messages } )
if $im2->message_count;
ok( $im2->close, "close" );
$im2->delete($migtarget);
ok_relaxed_logout($im2);
# Test IDLE
SKIP: {
skip "IDLE not supported", 4 unless $imap->has_capability("IDLE");
ok( my $idle = $imap->idle, "idle" );
sleep 1;
ok( $imap->idle_data, "idle_data" );
ok( $imap->done($idle), "done" );
ok( !$@, "LastError not set" ) or diag( '$@:' . $@ );
}
$imap->select('inbox');
if ( $imap->rename( $target, "${target}NEW" ) ) {
ok( 1, 'rename' );
$imap->close;
$imap->select("${target}NEW");
$imap->delete_message( @{ $imap->messages } ) if $imap->message_count;
$imap->close;
$imap->delete("${target}NEW");
}
else {
ok( 0, 'rename failed' );
$imap->delete_message( @{ $imap->messages } )
if $imap->message_count;
$imap->close;
$imap->delete($target);
}
$imap->_disconnect;
ok( $imap->reconnect, "reconnect" );
ok_relaxed_logout($imap);
# 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
# however some servers return BYE instead so we let that pass here...
sub ok_relaxed_logout {
my $imap = shift;
local ($@);
my $rc = $imap->logout;
my $err = $imap->LastError || "";
ok( ( $rc or $err =~ /^\* BYE/ ), "logout" . ( $err ? ": $err" : "" ) );
}

View file

@ -0,0 +1,76 @@
#!/usr/bin/perl
#
# tests for body_string()
#
# body_string() calls fetch() internally. rather than refactor
# body_string() just for testing, we subclass M::IC and use the
# overidden fetch() to feed it test data.
use strict;
use warnings;
use IO::Socket qw(:crlf);
use Test::More tests => 3;
BEGIN { use_ok('Mail::IMAPClient') or exit; }
my @tests = (
[
"simple fetch",
[
'12 FETCH 1 BODY[TEXT]',
'* 1 FETCH (FLAGS (\\Seen \\Recent) BODY[TEXT]',
"This is a test message$CRLF" . "Line Z (last line)$CRLF",
")$CRLF",
"12 OK Fetch completed.$CRLF",
],
[ 1 ],
"This is a test message$CRLF" . "Line Z (last line)$CRLF",
],
# 2010-05-27: test for bug reported by Heiko Schlittermann
[
"uwimap IMAP4rev1 2007b.404 fetch unseen",
[
'4 FETCH 1 BODY[TEXT]',
'* 1 FETCH (BODY[TEXT]',
"This is a test message$CRLF" . "Line Z (last line)$CRLF",
")$CRLF",
"* 1 FETCH (FLAGS (\\Recent \\Seen)$CRLF",
"4 OK Fetch completed$CRLF",
],
[ 1 ],
"This is a test message$CRLF" . "Line Z (last line)$CRLF",
],
);
package Test::Mail::IMAPClient;
use base qw(Mail::IMAPClient);
sub new {
my ( $class, %args ) = @_;
my %me = %args;
return bless \%me, $class;
}
sub fetch {
my ( $self, @args ) = @_;
return $self->{_next_fetch_response} || [];
}
package main;
sub run_tests {
my ( $imap, $tests ) = @_;
for my $test (@$tests) {
my ( $comment, $fetch, $request, $response ) = @$test;
$imap->{_next_fetch_response} = $fetch;
my $r = $imap->body_string(@$request);
is_deeply( $r, $response, $comment );
}
}
my $imap = Test::Mail::IMAPClient->new( Uid => 0, Debug => 0 );
run_tests( $imap, \@tests );

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,317 @@
#!/usr/bin/perl
#
# tests for fetch_hash()
#
# fetch_hash() calls fetch() internally. rather than refactor
# fetch_hash() just for testing, we instead subclass M::IC and use the
# overidden fetch() to feed it test data.
use strict;
use warnings;
use Test::More tests => 27;
BEGIN { use_ok('Mail::IMAPClient') or exit; }
my @tests = (
[
"unquoted value",
[ q{* 1 FETCH (UNQUOTED foobar)}, ],
[ [1], qw(UNQUOTED) ],
{ "1" => { "UNQUOTED" => q{foobar}, } },
],
[
"quoted value",
[ q{* 1 FETCH (QUOTED "foo bar baz")}, ],
[ [1], qw(QUOTED) ],
{ "1" => { "QUOTED" => q{foo bar baz}, }, },
],
[
"escaped-backslash before end-quote",
[ q{* 1 FETCH (QUOTED "foo bar baz\\\\")}, ],
[ [1], qw(QUOTED) ],
{ "1" => { "QUOTED" => q{foo bar baz\\\\}, }, },
],
[
"parenthesized value",
[ q{* 1 FETCH (PARENS (foo bar))}, ],
[ [1], qw(PARENS) ],
{ "1" => { "PARENS" => q{foo bar}, }, },
],
[
"parenthesized value with quotes",
[ q{* 1 FETCH (PARENS (foo "bar" baz))}, ],
[ [1], qw(PARENS) ],
{ "1" => { "PARENS" => q{foo "bar" baz}, }, },
],
[
"parenthesized value with parens at start",
[ q{* 1 FETCH (PARENS ((foo) bar baz))}, ],
[ [1], qw(PARENS) ],
{ "1" => { "PARENS" => q{(foo) bar baz}, }, },
],
[
"parenthesized value with parens in middle",
[ q{* 1 FETCH (PARENS (foo (bar) baz))}, ],
[ [1], qw(PARENS) ],
{ "1" => { "PARENS" => q{foo (bar) baz}, }, },
],
[
"parenthesized value with parens at end",
[ q{* 1 FETCH (PARENS (foo bar (baz)))}, ],
[ [1], qw(PARENS) ],
{ "1" => { "PARENS" => q{foo bar (baz)}, }, },
],
[
"parenthesized value with quoted parentheses",
[ q{* 1 FETCH (PARENS (foo "(bar)" baz))}, ],
[ [1], qw(PARENS) ],
{ "1" => { "PARENS" => q{foo "(bar)" baz}, }, },
],
[
"parenthesized value with quoted unclosed parentheses",
[ q{* 1 FETCH (PARENS (foo "(bar" baz))}, ],
[ [1], qw(PARENS) ],
{ "1" => { "PARENS" => q{foo "(bar" baz}, }, },
],
[
"parenthesized value with quoted unopened parentheses",
[ q{* 1 FETCH (PARENS (foo "bar)" baz))}, ],
[ [1], qw(PARENS) ],
{ "1" => { "PARENS" => q{foo "bar)" baz}, }, },
],
[
"complex parens",
[ q{* 1 FETCH (PARENS ((((foo) "bar") baz (quux))))}, ],
[ [1], qw(PARENS) ],
{ "1" => { "PARENS" => q{(((foo) "bar") baz (quux))}, }, },
],
[
"basic literal value",
[ q{* 1 FETCH (LITERAL}, q{foo}, q{)}, ],
[ [1], qw(LITERAL) ],
{ "1" => { "LITERAL" => q{foo}, }, },
],
[
"multiline literal value",
[ q{* 1 FETCH (LITERAL}, q{foo\r\nbar\r\nbaz\r\n}, q{)}, ],
[ [1], qw(LITERAL) ],
{ "1" => { "LITERAL" => q{foo\r\nbar\r\nbaz\r\n}, }, },
],
[
"multiple attributes",
[ q{* 1 FETCH (FOO foo BAR bar BAZ baz)}, ],
[ [1], qw(FOO BAR BAZ) ],
{
"1" => {
"FOO" => q{foo},
"BAR" => q{bar},
"BAZ" => q{baz},
},
},
],
[
"dotted attribute",
[ q{* 1 FETCH (FOO.BAR foobar)}, ],
[ [1], qw(FOO.BAR) ],
{ "1" => { "FOO.BAR" => q{foobar}, }, },
],
[
"complex attribute",
[ q{* 1 FETCH (FOO.BAR[BAZ (QUUX)] quuz)}, ],
[ [1], q{FOO.BAR[BAZ (QUUX)]} ],
{ "1" => { q{FOO.BAR[BAZ (QUUX)]} => q{quuz}, }, },
],
[
"BODY.PEEK[] requests match BODY[] responses",
[q{* 1 FETCH (BODY[] foo)}],
[ [1], qw(BODY.PEEK[]) ],
{ "1" => { "BODY[]" => q{foo}, }, },
],
[
"BODY.PEEK[] requests match BODY.PEEK[] responses also",
[q{* 1 FETCH (BODY.PEEK[] foo)}],
[ [1], qw(BODY.PEEK[]) ],
{ "1" => { "BODY.PEEK[]" => q{foo}, }, },
],
[
"BODY[]<0.1024> requests match BODY[]<0> responses",
[ q{* 1 FETCH (BODY[]<0>}, q{foo}, ")\r\n" ],
[ [1], qw(BODY[]<0.1024>) ],
{ "1" => { "BODY[]<0>" => q{foo}, }, },
],
[
"BODY.PEEK[]<0.1024> requests match BODY[]<0> responses",
[ q{* 1 FETCH (BODY[]<0>}, q{foo}, ")\r\n" ],
[ [1], qw(BODY.PEEK[]<0.1024>) ],
{ "1" => { "BODY[]<0>" => q{foo}, }, },
],
[
"non-escaped BODY[HEADER.FIELDS (...)]",
[
q{* 1 FETCH (FLAGS () BODY[HEADER.FIELDS (TO FROM SUBJECT DATE)]},
'From: Phil Pearl (Lobbes) <phil+from@perkpartners.com>
To: phil+to@perkpartners.com
Subject: foo "bar\" (baz\)
Date: Sat, 22 Jan 2011 20:43:58 -0500
'
],
[ [1], ( qw(FLAGS), 'BODY[HEADER.FIELDS (TO FROM SUBJECT DATE)]' ) ],
{
'1' => {
'BODY[HEADER.FIELDS (TO FROM SUBJECT DATE)]' =>
'From: Phil Pearl (Lobbes) <phil+from@perkpartners.com>
To: phil+to@perkpartners.com
Subject: foo "bar\" (baz\)
Date: Sat, 22 Jan 2011 20:43:58 -0500
',
'FLAGS' => '',
},
},
],
);
my @uid_tests = (
[
"uid enabled",
[ q{* 1 FETCH (UID 123 UNQUOTED foobar)}, ],
[ [123], qw(UNQUOTED) ],
{ "123" => { "UNQUOTED" => q{foobar}, } },
],
[
"ENVELOPE with escaped-backslash before end-quote",
[ q{* 1 FETCH (UID 1 FLAGS (\Seen) ENVELOPE ("Fri, 28 Jan 2011 00:03:30 -0500" "Subject" (("Ken N" NIL "ken" "dom.loc")) (("Ken N" NIL "ken" "dom.loc")) (("Ken N" NIL "ken" "dom.loc")) (("Ken Backslash\\\\" NIL "ken.bl" "dom.loc")) NIL NIL NIL "<msgid>")) } ],
[ [1], qw(UID FLAGS ENVELOPE) ],
{
"1" => {
'UID' => '1',
'FLAGS' => '\\Seen',
'ENVELOPE' =>
q{"Fri, 28 Jan 2011 00:03:30 -0500" "Subject" (("Ken N" NIL "ken" "dom.loc")) (("Ken N" NIL "ken" "dom.loc")) (("Ken N" NIL "ken" "dom.loc")) (("Ken Backslash\\\\" NIL "ken.bl" "dom.loc")) NIL NIL NIL "<msgid>"}
},
},
],
[
"escaped ENVELOPE subject",
[
q{* 1 FETCH (UID 1 X-SAVEDATE "28-Jan-2011 16:52:31 -0500" FLAGS (\Seen) ENVELOPE ("Fri, 28 Jan 2011 00:03:30 -0500"},
q{foo "bar\\" (baz\\)},
q{ (("Phil Pearl" NIL "phil" "dom.loc")) (("Phil Pearl" NIL "phil" "dom.loc")) (("Phil Pearl" NIL "phil" "dom.loc")) ((NIL NIL "phil" "dom.loc")) NIL NIL NIL "<msgid>")) }
],
[ [1], qw(UID X-SAVEDATE FLAGS ENVELOPE) ],
{
"1" => {
'X-SAVEDATE' => '28-Jan-2011 16:52:31 -0500',
'UID' => '1',
'FLAGS' => '\\Seen',
'ENVELOPE' =>
q{"Fri, 28 Jan 2011 00:03:30 -0500" "foo \\"bar\\\\\\" (baz\\\\)" (("Phil Pearl" NIL "phil" "dom.loc")) (("Phil Pearl" NIL "phil" "dom.loc")) (("Phil Pearl" NIL "phil" "dom.loc")) ((NIL NIL "phil" "dom.loc")) NIL NIL NIL "<msgid>"}
},
},
],
[
"real life example",
[
'* 1 FETCH (UID 541 FLAGS (\\Seen) INTERNALDATE "15-Sep-2009 20:05:45 +1000" RFC822.SIZE 771 BODY[HEADER.FIELDS (TO FROM DATE SUBJECT)]',
'Date: Tue, 15 Sep 2009 20:05:45 +1000
To: rob@pyro
From: rob@pyro
Subject: test Tue, 15 Sep 2009 20:05:45 +1000
',
' BODY[]',
'Return-Path: <rob@pyro>
Delivered-To: rob@pyro
Received: from pyro (pyro [127.0.0.1])
by pyro.home (Postfix) with ESMTP id A5C8115A066
for <rob@pyro>; Tue, 15 Sep 2009 20:05:45 +1000 (EST)
Date: Tue, 15 Sep 2009 20:05:45 +1000
To: rob@pyro
From: rob@pyro
Subject: test Tue, 15 Sep 2009 20:05:45 +1000
X-Mailer: swaks v20061116.0 jetmore.org/john/code/#swaks
Message-Id: <20090915100545.A5C8115A066@pyro.home>
Lines: 1
This is a test mailing
',
')
',
],
[
[1],
q{BODY.PEEK[HEADER.FIELDS (To From Date Subject)]},
qw(FLAGS INTERNALDATE RFC822.SIZE BODY[])
],
{
"541" => {
'BODY[]' => 'Return-Path: <rob@pyro>
Delivered-To: rob@pyro
Received: from pyro (pyro [127.0.0.1])
by pyro.home (Postfix) with ESMTP id A5C8115A066
for <rob@pyro>; Tue, 15 Sep 2009 20:05:45 +1000 (EST)
Date: Tue, 15 Sep 2009 20:05:45 +1000
To: rob@pyro
From: rob@pyro
Subject: test Tue, 15 Sep 2009 20:05:45 +1000
X-Mailer: swaks v20061116.0 jetmore.org/john/code/#swaks
Message-Id: <20090915100545.A5C8115A066@pyro.home>
Lines: 1
This is a test mailing
',
'INTERNALDATE' => '15-Sep-2009 20:05:45 +1000',
'FLAGS' => '\\Seen',
'BODY[HEADER.FIELDS (TO FROM DATE SUBJECT)]' =>
'Date: Tue, 15 Sep 2009 20:05:45 +1000
To: rob@pyro
From: rob@pyro
Subject: test Tue, 15 Sep 2009 20:05:45 +1000
',
'RFC822.SIZE' => '771',
},
},
],
);
package Test::Mail::IMAPClient;
use vars qw(@ISA);
@ISA = qw(Mail::IMAPClient);
sub new {
my ( $class, %args ) = @_;
my %me = %args;
return bless \%me, $class;
}
sub fetch {
my ( $self, @args ) = @_;
return $self->{_next_fetch_response} || [];
}
sub Escaped_results {
my ( $self, @args ) = @_;
return $self->{_next_fetch_response} || [];
}
package main;
sub run_tests {
my ( $imap, $tests ) = @_;
for my $test (@$tests) {
my ( $comment, $fetch, $request, $expect ) = @$test;
$imap->{_next_fetch_response} = $fetch;
my $r = $imap->fetch_hash(@$request);
is_deeply( $r, $expect, $comment );
}
}
my $imap = Test::Mail::IMAPClient->new( Uid => 0 );
run_tests( $imap, \@tests );
$imap->Uid(1);
run_tests( $imap, \@uid_tests );

View file

@ -0,0 +1,37 @@
#!/usr/bin/perl
use strict;
use warnings;
use Test::More tests => 7;
BEGIN { use_ok('Mail::IMAPClient::MessageSet') or exit; }
my $one = q/1:4,3:6,10:15,20:25,2:8/;
my $range = Mail::IMAPClient::MessageSet->new($one);
is( $range, "1:8,10:15,20:25", 'range simplify' );
is(
join( ",", $range->unfold ),
"1,2,3,4,5,6,7,8,10,11,12,13,14,15,20,21,22,23,24,25",
'range unfold'
);
$range .= "30,31,32,31:34,40:44";
is( $range, "1:8,10:15,20:25,30:34,40:44", 'overload concat' );
is(
join( ",", $range->unfold ),
"1,2,3,4,5,6,7,8,10,11,12,13,14,15,20,21,22,23,24,25,"
. "30,31,32,33,34,40,41,42,43,44",
'unfold extended'
);
$range -= "1:2";
is( $range, "3:8,10:15,20:25,30:34,40:44", 'overload subtract' );
is(
join( ",", $range->unfold ),
"3,4,5,6,7,8,10,11,12,13,14,15,20,21,22,23,24,25,"
. "30,31,32,33,34,40,41,42,43,44",
'subtract unfold'
);

View file

@ -0,0 +1,10 @@
#!/usr/bin/perl
use strict;
use warnings;
use Test::More;
eval "use Test::Pod 1.00";
plan skip_all => "Test::Pod 1.00 required for testing POD" if $@;
all_pod_files_ok();

View file

@ -0,0 +1,36 @@
#!/usr/bin/perl
use strict;
use warnings;
use Test::More tests => 13;
BEGIN { use_ok('Mail::IMAPClient') or exit; }
{
my $obj = Mail::IMAPClient->new();
my %t = ( 0 => "01-Jan-1970" );
foreach my $k ( sort keys %t ) {
my $v = $t{$k};
my $s = $v . ' 00:00:00 +0000';
is( Mail::IMAPClient::Rfc2060_date($k), $v, "Rfc2060_date($k)=$v" );
is( Mail::IMAPClient::Rfc3501_date($k), $v, "Rfc3501_date($k)=$v" );
is( Mail::IMAPClient::Rfc3501_datetime($k),
$s, "Rfc3501_datetime($k)=$s" );
is( Mail::IMAPClient::Rfc2060_datetime($k),
$s, "Rfc3501_datetime($k)=$s" );
is( $obj->Rfc3501_date($k), $v, "->Rfc3501_date($k)=$v" );
is( $obj->Rfc2060_date($k), $v, "->Rfc2060_date($k)=$v" );
is( $obj->Rfc3501_datetime($k), $s, "->Rfc3501_datetime($k)=$s" );
is( $obj->Rfc2060_datetime($k), $s, "->Rfc2060_datetime($k)=$s" );
foreach my $z (qw(+0000 -0500)) {
my $vz = $v . ' 00:00:00 ' . $z;
is( Mail::IMAPClient::Rfc2060_datetime( $k, $z ),
$vz, "Rfc2060_datetime($k)=$vz" );
is( Mail::IMAPClient::Rfc3501_datetime( $k, $z ),
$vz, "Rfc3501_datetime($k)=$vz" );
}
}
}

View file

@ -0,0 +1,30 @@
#!/usr/bin/perl
use strict;
use warnings;
use Test::More tests => 7;
BEGIN { use_ok('Mail::IMAPClient::Thread') or exit; }
my $t1 = <<'e1';
* THREAD (166)(167)(168)(169)(172)(170)(171)(173)(174 175 176 178 181 180)(179)(177 183 182 188 184 185 186 187 189)(190)(191)(192)(193)(194 195)(196 197 198)(199)(200 202)(201)(203)(204)(205)(206 207)(208)
e1
my $t2 = <<'e2';
* THREAD (166)(167)(168)(169)(172)((170)(179))(171)(173)((174)(175)(176)(178)(181)(180))((177)(183)(182)(188 (184)(189))(185 186)(187))(190)(191)(192)(193)((194)(195 196))(197 198)(199)(200 202)(201)(203)(204)(205 206 207)(208)
e2
my $parser = Mail::IMAPClient::Thread->new;
ok( defined $parser, 'created parser' );
isa_ok( $parser, 'Parse::RecDescent' ); # !!!
my $thr1 = $parser->start($t1);
ok( defined $thr1, 'thread1 start' );
cmp_ok( scalar(@$thr1), '==', 25 );
my $thr2 = $parser->start($t2);
ok( defined $thr2, 'thread2 start' );
cmp_ok( scalar(@$thr2), '==', 23 );

View file

@ -0,0 +1,5 @@
server=imap.server.hostname
user=username
passed=password
port=143
authmechanism=LOGIN

29
W/OSI_request.txt Executable file
View file

@ -0,0 +1,29 @@
Rationale:Clearly state rationale for a new license
There is few licenses on the free work market allowing anything
from the author point of view. The purpose of any license is
to write what can be done without having to contact the authors.
There is no such permissive license in the OSI list.
CC0 WTFPL and Bugroff are too restrictive licenses
CC0 https://creativecommons.org/about/cc0
WTFPL http://www.wtfpl.net/about/
Bugroff http://tunes.org/legalese/bugroff.html
I
Distinguish: Compare to and contrast with the most similar OSI-approved license(s)
There is no similar OSI-approved license. All
Legal review: Describe any legal review the license has been through, and provide results of any legal analysis if available
None.
Proliferation category: Recommend which license proliferation category is appropriate
The NOLIMIT license allows any work under it to be relicensed under any other license.

View file

View file

@ -1,14 +1,13 @@
REM $Id: build_exe.bat,v 1.28 2015/05/11 01:09:57 gilles Exp gilles $
REM $Id: build_exe.bat,v 1.33 2015/11/23 16:47:21 gilles Exp gilles $
@ECHO OFF
ECHO Building imapsync.exe
@REM Allow to be called from anywhere;
@REM the following command cd to dirname of the current batch pathname
cd /D %~dp0
CALL .\install_modules.bat
REM CALL .\install_modules.bat
perl ^
-mAuthen::NTLM ^
@ -33,15 +32,48 @@ perl ^
-mLWP::UserAgent ^
-mHTML::Entities ^
-mJSON ^
-mCrypt::OpenSSL::RSA ^
-e ''
cd
@ECHO ON
@REM --link libssl32_.dll
del imapsync.exe
pp -o imapsync.exe ^
--link libeay32_.dll ^
--link zlib1_.dll ^
--link ssleay32_.dll ^
.\imapsync
echo Done building imapsync.exe
@REM Previous options to pp
@REM Previous options to pp
@REM --link libeay32_.dll ^
@REM --link zlib1_.dll ^
@REM --link ssleay32_.dll ^
@REM -M Mail::IMAPClient ^
@REM -M IO::Socket ^
@REM -M IO::Socket::IP ^
@REM -M IO::Socket::SSL ^
@REM -M IO::Socket::INET ^
@REM -M Digest::MD5 ^
@REM -M Digest::HMAC_MD5 ^
@REM -M Digest::HMAC_SHA1 ^
@REM -M Term::ReadKey ^
@REM -M File::Spec ^
@REM -M Authen::NTLM ^
@REM -M Time::Local ^
@REM -M URI::Escape ^
@REM -M Data::Uniqid ^
@REM -M File::Copy::Recursive ^
@REM -M IO::Tee ^
@REM -M Unicode::String ^
@REM -M JSON::WebToken ^
@REM -M LWP::UserAgent ^
@REM -M HTML::Entities ^
@REM -M JSON ^
EXIT
-M Mail::IMAPClient ^
-M IO::Socket ^
-M IO::Socket::IP ^
@ -62,8 +94,5 @@ pp -o imapsync.exe ^
-M JSON::WebToken ^
-M LWP::UserAgent ^
-M HTML::Entities ^
-M Crypt::OpenSSL::RSA ^
-M JSON ^
.\imapsync
echo Done building imapsync.exe

View file

@ -1,5 +1,7 @@
#!/bin/sh
# $Id: build_mac.sh,v 1.2 2015/11/04 18:19:48 gilles Exp gilles $
eval `perl -I $HOME/perl5/lib/perl5 -Mlocal::lib`
export MANPATH=$HOME/perl5/man:$MANPATH
@ -11,10 +13,13 @@ echo "$HOSTNAME $ARCH $KERNEL"
VERSION=`./imapsync --version`
BIN_NAME=imapsync_bin_Darwin
cpanm Mail::IMAPClient
pp -o $BIN_NAME \
-M Mail::IMAPClient -M IO::Socket -M IO::Socket::SSL \
-M Digest::MD5 -M Digest::HMAC_MD5 -M Term::ReadKey \
-M Authen::NTLM \
-M Crypt::OpenSSL::RSA -M JSON -M JSON::WebToken -M LWP -M HTML::Entities \
imapsync
./imapsync_bin_Darwin

View file

@ -124,7 +124,7 @@
.\" ========================================================================
.\"
.IX Title "IMAPSYNC 1"
.TH IMAPSYNC 1 "2015-07-17" "perl v5.14.2" "User Contributed Perl Documentation"
.TH IMAPSYNC 1 "2015-12-03" "perl v5.14.2" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
@ -132,10 +132,10 @@
.SH "NAME"
imapsync \- IMAP synchronisation, sync, copy or migration tool.
Synchronises mailboxes between two imap servers.
Good at IMAP migration. More than 52 different IMAP server softwares
Good at IMAP migration. More than 66 different IMAP server softwares
supported with success, few failures.
.PP
$Revision: 1.644 $
$Revision: 1.670 $
.SH "SYNOPSIS"
.IX Header "SYNOPSIS"
To synchronize imap account \*(L"foo\*(R" on \*(L"imap.truc.org\*(R"
@ -206,36 +206,36 @@ The option list:
.PP
.Vb 10
\& imapsync [\-\-host1 server1] [\-\-port1 <num>]
\& [\-\-user1 <string>] [\-\-passfile1 <string>]
\& [\-\-user1 str ] [\-\-passfile1 str ]
\& [\-\-host2 server2] [\-\-port2 <num>]
\& [\-\-user2 <string>] [\-\-passfile2 <string>]
\& [\-\-user2 str ] [\-\-passfile2 str ]
\& [\-\-ssl1] [\-\-ssl2]
\& [\-\-tls1] [\-\-tls2]
\& [\-\-authmech1 <string>] [\-\-authmech2 <string>]
\& [\-\-authmech1 str ] [\-\-authmech2 str ]
\& [\-\-proxyauth1] [\-\-proxyauth2]
\& [\-\-domain1] [\-\-domain2]
\& [\-\-authmd51] [\-\-authmd52]
\& [\-\-folder <string> \-\-folder <string> ...]
\& [\-\-folderrec <string> \-\-folderrec <string> ...]
\& [\-\-include <regex>] [\-\-exclude <regex>]
\& [\-\-prefix2 <string>] [\-\-prefix1 <string>]
\& [\-\-regextrans2 <regex> \-\-regextrans2 <regex> ...]
\& [\-\-folder str \-\-folder str ...]
\& [\-\-folderrec str \-\-folderrec str ...]
\& [\-\-include reg ] [\-\-exclude reg ]
\& [\-\-prefix2 str ] [\-\-prefix1 str ]
\& [\-\-regextrans2 reg \-\-regextrans2 reg ...]
\& [\-\-sep1 <char>]
\& [\-\-sep2 <char>]
\& [\-\-justfolders] [\-\-justfoldersizes] [\-\-justconnect] [\-\-justbanner]
\& [\-\-syncinternaldates]
\& [\-\-idatefromheader]
\& [\-\-syncacls]
\& [\-\-regexmess <regex>] [\-\-regexmess <regex>]
\& [\-\-skipmess <regex>] [\-\-skipmess <regex>]
\& [\-\-maxsize <int>]
\& [\-\-minsize <int>]
\& [\-\-maxage <int>]
\& [\-\-minage <int>]
\& [\-\-search <string>]
\& [\-\-search1 <string>]
\& [\-\-search2 <string>]
\& [\-\-useheader <string>] [\-\-useheader <string>]
\& [\-\-regexmess reg ] [\-\-regexmess reg ]
\& [\-\-skipmess reg ] [\-\-skipmess reg ]
\& [\-\-maxsize int ]
\& [\-\-minsize int ]
\& [\-\-maxage int ]
\& [\-\-minage int ]
\& [\-\-search str ]
\& [\-\-search1 str ]
\& [\-\-search2 str ]
\& [\-\-useheader str ] [\-\-useheader str ]
\& [\-\-nouid1] [\-\-nouid2]
\& [\-\-usecache]
\& [\-\-noskipsize]
@ -247,7 +247,7 @@ The option list:
\& [\-\-nofoldersizes] [\-\-nofoldersizesatend]
\& [\-\-dry]
\& [\-\-debug] [\-\-debugimap][\-\-debugimap1][\-\-debugimap2] [\-\-debugcontent]
\& [\-\-timeout <int>]
\& [\-\-timeout int ]
\& [\-\-noreleasecheck]
\& [\-\-releasecheck]
\& [\-\-pidfile <filepath>] [\-\-pidfilelocking]
@ -569,4 +569,4 @@ https://web.archive.org/web/20070202005121/http://www.imap.org/products/showall.
.PP
Feedback (good or bad) will often be welcome.
.PP
\&\f(CW$Id:\fR imapsync,v 1.644 2015/07/17 01:22:52 gilles Exp gilles $
\&\f(CW$Id:\fR imapsync,v 1.670 2015/12/03 02:36:41 gilles Exp gilles $

28
W/install_module_one.bat Normal file
View file

@ -0,0 +1,28 @@
@REM $Id: install_module_one.bat,v 1.1 2015/11/23 16:49:17 gilles Exp gilles $
@ECHO OFF
SET SHELL=
SET
REM EXIT
ECHO Installing Perl module IO::Socket::SSL for imapsync
REM CD /D %~dp0
perl -v
IF ERRORLEVEL 1 ECHO Perl needed. Install Strawberry Perl. Get it at http://strawberryperl.com/ ^
&& EXIT /B
@ECHO perl is here
FOR %%M in (
IO::Socket::SSL ^
) DO perl -m%%M -e "print qq{Updating %%M $%%M::VERSION \n}" ^
& cpanm %%M
REM IO::Socket::SSL
@ECHO Perl modules for imapsync installed
PAUSE

28
W/install_module_ssl.bat Normal file
View file

@ -0,0 +1,28 @@
@REM $Id: install_module_ssl.bat,v 1.1 2015/11/05 14:51:08 gilles Exp gilles $
@ECHO OFF
SET SHELL=
SET
REM EXIT
ECHO Installing Perl module IO::Socket::SSL for imapsync
REM CD /D %~dp0
perl -v
IF ERRORLEVEL 1 ECHO Perl needed. Install Strawberry Perl. Get it at http://strawberryperl.com/ ^
&& EXIT /B
@ECHO perl is here
FOR %%M in (
IO::Socket::SSL ^
) DO perl -m%%M -e "print qq{Updating %%M $%%M::VERSION \n}" ^
& cpanm %%M
REM IO::Socket::SSL
@ECHO Perl modules for imapsync installed
PAUSE

View file

@ -1,10 +1,13 @@
REM $Id: install_modules.bat,v 1.17 2015/05/23 09:40:38 gilles Exp gilles $
REM $Id: install_modules.bat,v 1.18 2015/11/04 18:15:11 gilles Exp gilles $
@ECHO OFF
@REM Needed with remote ssh
SET SHELL=
SET
ECHO Installing Perl modules for imapsync
REM CD /D %~dp0
CD /D %~dp0
perl -v
IF ERRORLEVEL 1 ECHO Perl needed. Install Strawberry Perl. Get it at http://strawberryperl.com/ ^
@ -21,6 +24,7 @@ FOR %%M in ( ^
Digest::MD5 ^
File::Copy::Recursive ^
Getopt::ArgvFile ^
Socket6 ^
IO::Socket::INET ^
IO::Socket::INET6 ^
IO::Socket::SSL ^
@ -33,16 +37,15 @@ FOR %%M in ( ^
Test::Pod ^
Unicode::String ^
URI::Escape ^
Crypt::OpenSSL::RSA ^
JSON ^
JSON::WebToken ^
LWP ^
HTML::Entities ^
JSON ^
) DO ECHO Updating %%M ^
& perl -MCPAN -e "install %%M"
) DO @perl -m%%M -e "print qq{Updating %%M $%%M::VERSION \n}" ^
& cpanm %%M
REM & perl -m%%M -e "" || perl -MCPAN -e "install %%M"
ECHO Perl modules for imapsync installed
ECHO Perl modules for imapsync updated
REM PAUSE

1
W/learn/10990.txt Normal file

File diff suppressed because one or more lines are too long

450
W/learn/10_99.txt Normal file
View file

@ -0,0 +1,450 @@
10
Hello Guys
LLLLLLLLLL
END
11
Hello Guys
LLLLLLLLLLL
END
12
Hello Guys
LLLLLLLLLLLL
END
13
Hello Guys
LLLLLLLLLLLLL
END
14
Hello Guys
LLLLLLLLLLLLLL
END
15
Hello Guys
LLLLLLLLLLLLLLL
END
16
Hello Guys
LLLLLLLLLLLLLLLL
END
17
Hello Guys
LLLLLLLLLLLLLLLLL
END
18
Hello Guys
LLLLLLLLLLLLLLLLLL
END
19
Hello Guys
LLLLLLLLLLLLLLLLLLL
END
20
Hello Guys
LLLLLLLLLLLLLLLLLLLL
END
21
Hello Guys
LLLLLLLLLLLLLLLLLLLLL
END
22
Hello Guys
LLLLLLLLLLLLLLLLLLLLLL
END
23
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLL
END
24
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLL
END
25
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLL
END
26
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLL
END
27
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLL
END
28
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
29
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
30
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
31
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
32
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
33
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
34
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
35
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
36
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
37
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
38
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
39
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
40
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
41
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
42
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
43
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
44
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
45
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
46
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
47
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
48
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
49
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
50
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
51
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
52
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
53
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
54
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
55
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
56
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
57
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
58
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
59
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
60
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
61
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
62
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
63
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
64
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
65
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
66
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
67
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
68
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
69
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
70
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
71
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
72
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
73
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
74
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
75
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
76
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
77
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
78
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
79
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
80
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
81
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
82
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
83
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
84
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
85
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
86
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
87
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
88
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
89
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
90
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
91
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
92
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
93
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
94
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
95
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
96
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
97
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
98
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END
99
Hello Guys
LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
END

14
W/learn/getoptlong Executable file
View file

@ -0,0 +1,14 @@
#!/usr/bin/perl -w
use strict ;
use Getopt::Long ;
use Data::Dumper ;
my %define ;
GetOptions (
"define=s" => \%define
) ;
print Dumper( \%define ) ;

46
W/learn/imap_rename_regex Executable file
View file

@ -0,0 +1,46 @@
#!/usr/bin/perl -w
# $Id: imap_rename_regex,v 1.5 2015/08/15 03:42:01 gilles Exp gilles $
use Mail::IMAPClient;
++$| ;
$ARGV[3] or die "usage: $0 host user password regex do_it\n";
my $host = $ARGV[0] ;
my $user = $ARGV[1] ;
my $password = $ARGV[2] ;
my $regex = $ARGV[3] ;
my $doit = $ARGV[4] || 0 ;
my $imap = Mail::IMAPClient->new( ) ;
$imap->Debug( 1 ) ;
$imap->Server( $host ) ;
$imap->Ssl( 1 ) ;
$imap->connect( ) or die ;
$imap->IsUnconnected( ) ;
$imap->User( $user ) ;
$imap->Password( $password ) ;
$imap->login( ) or die ;
$imap->Uid( 1 ) ;
$imap->Peek( 1 ) ;
my @folders = $imap->folders( ) ;
foreach my $folder ( @folders ) {
print "$folder\n" ;
my $folder_new = $folder ;
if ( eval( "\$folder_new =~ $regex" )
and ( $folder_new ne $folder ) ) {
print "Renaming [$folder] -> [$folder_new]\n" ;
$imap->noop( ) ;
if ( $doit and $imap->rename( $folder, $folder_new ) ) {
print "renamed ok [$folder] -> [$folder_new]\n" ;
}else{
print "KO renamed [$folder] -> [$folder_new]\n" ;
}
}
}
$imap->logout();

View file

@ -0,0 +1,7 @@
# Removing trailing blanks in folders names
./imap_rename_regex lamiral.info tata `cat /g/var/pass/secret.tata` 's,([^ ]+) +$,$1,'
#./imap_rename_regex lamiral.info tata `cat /g/var/pass/secret.tata` 's,([^ ]+) +$,$1,' doit

View file

@ -19,11 +19,9 @@ sub imap_utf7_decode {
# On remplace , par / dans les BASE 64 (, entre & et -)
# On remplace les &, non suivi d'un - par +
# On remplace les &- par &
$s =~ s/\+/PLUSPLACEHOLDER/g;
$s =~ s/&([^,&\-]*),([^,\-&]*)\-/&$1\/$2\-/g;
$s =~ s/&(?!\-)/\+/g;
$s =~ s/&\-/&/g;
$s =~ s/PLUSPLACEHOLDER/+-/g;
return( Unicode::String::utf7( $s )->utf8 ) ;
}

23
W/learn/imap_utf7_encode Executable file
View file

@ -0,0 +1,23 @@
#!/usr/bin/perl
use Unicode::String ;
while (<>) {
chomp ;
push( @result, sprintf( "%s\n", imap_utf7_encode( $_ ) ) ) ;
}
print @result ;
# http://cpansearch.perl.org/src/FABPOT/Unicode-IMAPUtf7-2.01/lib/Unicode/IMAPUtf7.pm
sub imap_utf7_encode {
my ( $s ) = @_ ;
$s = Unicode::String::utf8( $s )->utf7 ;
$s =~ s/\+([^\/&\-]*)\/([^\/\-&]*)\-/\+$1,$2\-/g ;
$s =~ s/&/&\-/g ;
$s =~ s/\+([^+\-]+)?\-/&$1\-/g ;
return( $s ) ;
}

Some files were not shown because too many files have changed in this diff Show more