This commit is contained in:
Nick Bebout 2011-03-12 02:44:51 +00:00
parent 95aab825e8
commit 5f67654c6f
53 changed files with 32864 additions and 289 deletions

24
CREDITS
View file

@ -1,5 +1,5 @@
#!/bin/cat #!/bin/cat
# $Id: CREDITS,v 1.128 2010/01/16 01:20:06 gilles Exp gilles $ # $Id: CREDITS,v 1.129 2010/02/15 17:41:48 gilles Exp gilles $
If you want to make a donation to the author, Gilles LAMIRAL: If you want to make a donation to the author, Gilles LAMIRAL:
@ -19,6 +19,20 @@ to remove one.
I thank very much all of these people. I thank very much all of these people.
Gary MacIsaac
Contributed by giving the books
32.00 "The Mathematical Theory of Communication"
34.61 "Beautiful Teams: Inspiring and Cautionary Tales from Veteran Team Leaders"
91.26 "Mathematics: A Human Endeavor (3rd Edition)"
Benjamin Clayton
Contributed by giving the book
38.20 "Beautiful Data: The Stories Behind Elegant Data Solutions"
Sandra Hallenbeck
Contributed by giving the book
40.09 "Feynman Lectures on Computation"
Robert Bauer Robert Bauer
Contributed by giving the book Contributed by giving the book
31.50 "Programming Interactivity: A Designer's Guide to Processing, Arduino, and Openframeworks" by Joshua Noble 31.50 "Programming Interactivity: A Designer's Guide to Processing, Arduino, and Openframeworks" by Joshua Noble
@ -776,6 +790,12 @@ Eric Yung
Total amount of book prices : Total amount of book prices :
c \ c \
32.00+\
34.61+\
91.26+\
38.20+\
40.09+\
\
31.50+\ 31.50+\
25.60+\ 25.60+\
23.09+\ 23.09+\
@ -866,4 +886,4 @@ c \
31.20+\ 31.20+\
40.00 40.00
= =
2136.15 2372.31

View file

@ -1,17 +1,54 @@
RCS file: RCS/imapsync,v RCS file: RCS/imapsync,v
Working file: imapsync Working file: imapsync
head: 1.303 head: 1.310
branch: branch:
locks: strict locks: strict
gilles: 1.303 gilles: 1.310
access list: access list:
symbolic names: symbolic names:
keyword substitution: kv keyword substitution: kv
total revisions: 303; selected revisions: 303 total revisions: 310; selected revisions: 310
description: description:
---------------------------- ----------------------------
revision 1.303 locked by: gilles; revision 1.310 locked by: gilles;
date: 2010/02/26 01:24:59; author: gilles; state: Exp; lines: +10 -11
Removed modules_VERSION() call (useless)
Replaced Phil regex with /e one.
----------------------------
revision 1.309
date: 2010/02/25 23:18:04; author: gilles; state: Exp; lines: +63 -65
Better imap banner handling (first line read).
removed sub myconnect_v2()
Removed Mail::IMAPClient::Socket use.
Added sub RawSocket2() (RawSocket 3.23 failed as is, do not know why)
Added Mail::IMAPClient::Ignoresizeerrors for 2.2.9
Honot --allowsizemismatch with 2.2.9
----------------------------
revision 1.308
date: 2010/02/24 01:29:11; author: gilles; state: Exp; lines: +15 -9
Fixed STARTTLS missing imap begin line.
----------------------------
revision 1.307
date: 2010/02/09 17:49:34; author: gilles; state: Exp; lines: +68 -9
Added tests_imap2_folder_name()
's/.*?(?:(\\(?:Answered|Flagged|Deleted|Seen|Recent|Draft)\s?)|$)/$1/g' check (good!)
----------------------------
revision 1.306
date: 2010/02/07 21:38:15; author: gilles; state: Exp; lines: +71 -6
Added regression test about the "keep only" --regexflag example.
Added debug to understand all the regexflag transformations.
----------------------------
revision 1.305
date: 2010/01/20 22:26:03; author: gilles; state: Exp; lines: +14 -14
Better output.
----------------------------
revision 1.304
date: 2010/01/20 22:10:24; author: gilles; state: Exp; lines: +32 -23
Added statistic about messages deleted
Added statistic about average bandwith rate
----------------------------
revision 1.303
date: 2010/01/20 04:12:52; author: gilles; state: Exp; lines: +13 -12 date: 2010/01/20 04:12:52; author: gilles; state: Exp; lines: +13 -12
cosmetic changes. cosmetic changes.
---------------------------- ----------------------------

362
FAQ
View file

@ -1,27 +1,33 @@
#!/bin/cat #!/bin/cat
# $Id: FAQ,v 1.59 2009/04/30 02:09:09 gilles Exp gilles $ # $Id: FAQ,v 1.65 2010/02/26 01:07:01 gilles Exp gilles $
+------------------+ +------------------+
| FAQ for imapsync | | FAQ for imapsync |
+------------------+ +------------------+
======================================================================= =======================================================================
Q. How to install impasync ? Q. How to install imapsync?
R. http://www.linux-france.org/prj/imapsync/INSTALL R. http://www.linux-france.org/prj/imapsync/INSTALL
======================================================================= =======================================================================
Q. How to configure impasync ? Q. How to configure imapsync?
R. http://www.linux-france.org/prj/imapsync/README R. http://www.linux-france.org/prj/imapsync/README
======================================================================= =======================================================================
Q. Can you give some configuration examples ? Q. Can you give some configuration examples?
R. http://www.linux-france.org/prj/imapsync/FAQ R. http://www.linux-france.org/prj/imapsync/FAQ
======================================================================= =======================================================================
Q. How can I have support ? Q. How can I have commercial support?
R. Ask the imapsync author and expert: Gilles LAMIRAL
Rates per hour (2010) : 81 euros (111 USD)
=======================================================================
Q. How can I have gratis support?
R. Use the mailing-list R. Use the mailing-list
@ -46,7 +52,7 @@ post to this list if you want to stay private.
Thank you for your participation. Thank you for your participation.
======================================================================= =======================================================================
Q. Where I can read IMAP RFCs ? Q. Where I can read up on the various IMAP RFCs?
R. Here: R. Here:
@ -67,12 +73,12 @@ http://www.faqs.org/rfcs/rfc4549.html
======================================================================= =======================================================================
Q. Where I can find old imapsync releases ? Q. Where I can find old imapsync releases?
R. ftp://www.linux-france.org/pub/prj/imapsync/ R. ftp://www.linux-france.org/pub/prj/imapsync/
======================================================================= =======================================================================
Q. How can I try imapsync with Mail::IMAPClient 3.xx perl library? Q. How can I try imapsync with the new Mail::IMAPClient 3.xx perl library?
R. - Download latest Mail::IMAPClient 3.xx at R. - Download latest Mail::IMAPClient 3.xx at
http://search.cpan.org/dist/Mail-IMAPClient/ http://search.cpan.org/dist/Mail-IMAPClient/
@ -82,9 +88,10 @@ R. - Download latest Mail::IMAPClient 3.xx at
- Download latest imapsync at - Download latest imapsync at
http://lamiral.info/~gilles/imapsync/imapsync http://lamiral.info/~gilles/imapsync/imapsync
- run imapsync with perl and -I option tailing to use Mail-IMAPClient-3.xx - run imapsync with perl and -I option tailing to use the perl
and add also option --allow3xx: module Mail-IMAPClient-3.xx. Example:
perl -I./Mail-IMAPClient-3.16/lib imapsync ... --allow3xx
perl -I./Mail-IMAPClient-3.23/lib imapsync ...
======================================================================= =======================================================================
Q. imapsync does not work with Mail::IMAPClient 3.xx Q. imapsync does not work with Mail::IMAPClient 3.xx
@ -104,9 +111,9 @@ R. - Download Mail::IMAPClient 2.2.9 at
======================================================================= =======================================================================
Q. I am interested in creating a local clone of the IMAP on a LAN Q. I am interested in creating a local clone of the IMAP on a LAN
server for faster synchronisations, Email will always be delivered server for faster synchronisations, email will always be delivered
to the remote server and so the synchronisation will be one way from to the remote server and so the synchronisation will be one way - from
remote to local. How suited is ImapSync to continouous one-way remote to local. How suited is imapsync for continuous one-way
synchronisation of mailboxes? Is there a better solution? synchronisation of mailboxes? Is there a better solution?
R. If messages are delivered remotely and you play locally with the R. If messages are delivered remotely and you play locally with the
@ -130,17 +137,16 @@ R. This is the case with:
- Mutt - Mutt
- Thunderbird - Thunderbird
Eurora shows by default the time the imap server received the email. Eurora shows by default the time the imap server received the email. I
I think it is quite a wrong behavior since the messages can think it is quite a wrong behavior since the messages can have
have travelled some time before the reception. travelled some time before the reception.
The sent time and date are given by the "Date:" header The sent time and date are given by the "Date:" header and it is set
and it is set most of the time by the MUA (Mail User Agent, most of the time by the MUA (Mail User Agent, Mutt, Eudora,
Mutt, Eudora, Thunderbird etc.). Thunderbird etc.).
imapsync does not touch any header since the imapsync does not touch any header since the header is used to
header is used to identify the messages in identify the messages in both parts.
both parts.
Solutions: Solutions:
a) Don't use buggy Eudora. a) Don't use buggy Eudora.
@ -148,6 +154,31 @@ b) Use the --syncinternaldates option and keep using Eudora :-)
c) Use the script learn/adjust_time.pl to change the internal dates c) Use the script learn/adjust_time.pl to change the internal dates
from the "Date:" header. from the "Date:" header.
=======================================================================
Q. Couldn't create [INBOX.Ops/foo/bar]: NO Invalid mailbox name:
INBOX.Ops/foo/bar
Example:
sep1=/
sep2=.
imapsync revert each separator automaticaly.
a) All / character coming from host1 are converted to . (convert the separator)
b) All . character coming from host1 are converted to / (to avoid
intermediate unwanted folder creation).
Sometimes the sep1 character is not valid on host2 (character "/" usualy)
R. Try :
--regextrans2 's,/,X,g'
It'll convert / character to X
Choose X as you wish: _ or SEP or
any string (including the empty string).
======================================================================= =======================================================================
Q. The option --subscribe does not seem to work Q. The option --subscribe does not seem to work
@ -156,12 +187,39 @@ R. Use it with --subscribed
======================================================================= =======================================================================
Q. Does imapsync retain the \Answered and $Forwarded flags? Q. Does imapsync retain the \Answered and $Forwarded flags?
R. imapsync retains all flags except \Recent R. It depends on the destination server.
(RFC 3501 says "This flag can not be altered by the client.")
a) If the destination server honors the "PERMAENTFLAGS \*"
directive or no PERMAENTFLAGS at all then imapsync synchronises
all flags except the flag \Recent
(RFC 3501 says "This flag can not be altered by the client.").
b) If the destination server honors the "PERMAENTFLAGS without the
special "\*" (meaning it accepts any flag) then imapsync synchronises
only the flags listed in PERMANENTFLAGS.
Some imap servers have problems with flags not beginning with Some imap servers have problems with flags not beginning with
the backslash character \ the backslash character \
=======================================================================
Q. I need to keep only a defind list of flags, how can I do?
The destination imap server complains about bad flags (Exchange).
R. For example if you want to keep only the following flags
\Seen \Answered \Flagged \Deleted \Draft
then use these magic --regexflag options (thanks to Phil):
--regexflag 's/.*?(?:(\\(?:Answered|Flagged|Deleted|Seen|Draft)\s?)|$)/defined($1)?$1:q()/eg'
Analysis is left to the reader.
This one is longer and may be use with old perl (no /e regex extension):
--regexflag 's/(.*)/$1 jrdH8u/' \
--regexflag 's/.*?(\\Seen|\\Answered|\\Flagged|\\Deleted|\\Draft|jrdH8u)/$1 /g' \
--regexflag 's/(\\Seen|\\Answered|\\Flagged|\\Deleted|\\Draft|jrdH8u) (?!(\\Seen|\\Answered|\\Flagged|\\Deleted|\\Draft|jrdH8u)).*/$1 /g' \
--regexflag 's/jrdH8u *//'
====================================================================== ======================================================================
Q. imapsync fails with the following error: Q. imapsync fails with the following error:
flags from : [\Seen NonJunk]["10-Aug-2006 13:00:30 -0400"] flags from : [\Seen NonJunk]["10-Aug-2006 13:00:30 -0400"]
@ -180,7 +238,7 @@ System flags are just flags defined by an RFC instead of by users.
Conclusion, some imap server coders don't read the RFCs (so do I). Conclusion, some imap server coders don't read the RFCs (so do I).
======================================================================= =======================================================================
Q. Flags are not well synchonized. Is it a bug ? Q. Flags are not well synchonized. Is it a bug?
R. It happens with some servers on the first sync. R. It happens with some servers on the first sync.
Also, it was a bug from revision 1.200 to revision 1.207 Also, it was a bug from revision 1.200 to revision 1.207
@ -188,6 +246,7 @@ Also, it was a bug from revision 1.200 to revision 1.207
Solution: run imapsync a second time. imapsync synchronizes flags Solution: run imapsync a second time. imapsync synchronizes flags
on each run unless option --fast is used. on each run unless option --fast is used.
=======================================================================
Q. imapsync hangs taking up 99.8% cpu right after start, Q. imapsync hangs taking up 99.8% cpu right after start,
after printing imapd doesn't support MD5 auth. after printing imapd doesn't support MD5 auth.
@ -195,11 +254,11 @@ R. Try option --noauthmd5
======================================================================= =======================================================================
Q. Some passwords contain * and " characters. Login fails. Q. Some passwords contain * and " characters. Login fails.
R. Use R. Use a backslash to escape the characters:
imapsync --password1 \"password\" imapsync --password1 \"password\"
Ii works for the star * character, It works for the star * character,
I don't know if it works for the " character. I don't know if it works for the " character.
======================================================================= =======================================================================
@ -222,7 +281,7 @@ kern.maxdsiz="1024M"
Q. With huge account (many messages) when it comes to reading the Q. With huge account (many messages) when it comes to reading the
destination server it comes out this error: destination server it comes out this error:
"To Folder [INBOX.foobar] Not connected" "To Folder [INBOX.foobar] Not connected"
What can I do ? What can I do?
R. May be spending too much time on the source server, the connection R. May be spending too much time on the source server, the connection
timed out on the destination server. timed out on the destination server.
@ -231,7 +290,7 @@ Try options :
======================================================================= =======================================================================
Q. imapsync failed with a "word too long" error from the imap server, Q. imapsync failed with a "word too long" error from the imap server,
What can I do ? What can I do?
R. Use imapsync release 1.172 or at least 1.166 with options R. Use imapsync release 1.172 or at least 1.166 with options
--split1 500 --split2 500 --split1 500 --split2 500
@ -260,7 +319,7 @@ b) Use stunnel
======================================================================= =======================================================================
Q: How to have an imaps server ? Q: How to have an imaps server?
R. R.
a) Install one a) Install one
@ -273,46 +332,43 @@ c) or use stunnel on inetd
imaps stream tcp nowait cyrus /usr/sbin/stunnel -s cyrus -p /etc/ssl/certs/imapd.pem -r localhost:imap2 imaps stream tcp nowait cyrus /usr/sbin/stunnel -s cyrus -p /etc/ssl/certs/imapd.pem -r localhost:imap2
======================================================================= =======================================================================
Q: I'm trying to use imapsync on win32 for gmail, but it requires ssl, Q: I'm trying to use imapsync on win32 for gmail, but it requires ssl,
or at least claims to. Imapsync appears to require io-socket-ssl, or at least claims to. Imapsync appears to require io-socket-ssl,
which doesn't seem to be available on win32. Are there any other options? which doesn't seem to be available on win32. Are there any other
options?
R: (Q and R come as is from Bryce Walter) R: (Q and R come as is from Bryce Walter)
I think I'm having success using cygwin perl instead of
ActiveState Perl. I wasn't able to get CPAN working and I think I'm having success using cygwin perl instead of ActiveState
building IO::Socket::SSL in ActiveState, but cygwin did Perl. I wasn't able to get CPAN working and building IO::Socket::SSL
all right. I had to force the install of the Net::SSLeay in ActiveState, but cygwin did all right. I had to force the install
dependency, because it partially failed one test, but I think of the Net::SSLeay dependency, because it partially failed one test,
it worked anyway. In order to get working in cygwin, I but I think it worked anyway. In order to get working in cygwin, I
installed the entire "perl" category, lynx, ncftp, and lftp installed the entire "perl" category, lynx, ncftp, and lftp (specified
(specified as ftp program in cpan setup). I'm not sure if I as ftp program in cpan setup). I'm not sure if I needed all those, or
needed all those, or if cpan just kept asking because I didn't if cpan just kept asking because I didn't have any installed at the
have any installed at the time. Anyway, cpan worked, and time. Anyway, cpan worked, and I installed all dependencies that
I installed all dependencies that imapsync complained imapsync complained about until it started working.
about until it started working.
======================================================================= =======================================================================
Q: Multiple copies when I run imapsync twice ore more. Q: Multiple copies when I run imapsync twice ore more.
R. Multiple copies of the emails on the destination R. Multiple copies of the emails on the destination server. Some IMAP
server. Some IMAP servers (Domino for example) add some servers (Domino for example) add some headers for each message
headers for each message transfered. The message is transfered. The message is transfered again and again each time you
transfered again and again each time you run imapsync. This run imapsync. This is bad of course. The explanation is that imapsync
is bad of course. The explanation is that imapsync considers considers the message is not the same since headers have changed (one
the message is not the same since headers have changed (one
line added) and size too (the header part). line added) and size too (the header part).
You can look at the headers found by imapsync by using the You can look at the headers found by imapsync by using the --debug
--debug option (and search for the message on both part), option (and search for the message on both part), Header lines from
Header lines from the source server begin with a "FH:" prefix, the source server begin with a "FH:" prefix, Header lines from the
Header lines from the destination server begin with a "TH:" prefix. destination server begin with a "TH:" prefix. Since --debug is very
Since --debug is very verbose I suggest to isolate a verbose I suggest to isolate a email in a specific folder in case you
email in a specific folder in case you want to forward want to forward me the output.
me the output.
The way to avoid this problem is by using options --skipheader and The way to avoid this problem is by using options --skipheader and
--skipsize, like this (avoid headers beginning whith the --skipsize, like this (avoid headers beginning whith the string "X-"):
string "X-"):
imapsync ... --skipheader '^X-' --skipsize imapsync ... --skipheader '^X-' --skipsize
@ -325,11 +381,11 @@ If you think you have too many header to avoid just use
imapsync ... --useheader 'Message-ID' --skipsize imapsync ... --useheader 'Message-ID' --skipsize
Remark. (Trick found by Tomasz Kaczmarski) Remark. (Trick found by Tomasz Kaczmarski)
Option --useheader 'Message-ID' asks the server
to send only header lines begining with 'Message-ID'. Option --useheader 'Message-ID' asks the server to send only header
Some (buggy) servers send the whole header (all lines) lines begining with 'Message-ID'. Some (buggy) servers send the whole
instead of the 'Message-ID' line. In that case, a trick header (all lines) instead of the 'Message-ID' line. In that case, a
to keep the --useheader filtering behavior is to use trick to keep the --useheader filtering behavior is to use
--skipheader with a negative lookahead pattern : --skipheader with a negative lookahead pattern :
imapsync ... --skipheader '^(?!Message-ID)' --skipsize imapsync ... --skipheader '^(?!Message-ID)' --skipsize
@ -357,14 +413,14 @@ R. Use
or maybe or maybe
--exclude '^"public\.' --exclude '^"public\.'
In the example given the character "." is the folder separator, In the example given the character "." is the folder separator, you
you can ommit it. Just take the string as it appears on the can ommit it. Just take the string as it appears on the imapsync
imapsync output line : output line :
From folders list : [INBOX] [public.dreams] [etc.] From folders list : [INBOX] [public.dreams] [etc.]
====================================================================== ======================================================================
Q. I want the --folder 'MyFolder' option be recurse. Q. I want the --folder 'MyFolder' option be recursive.
R. Do not use the --folder option. R. Do not use the --folder option.
Instead, use --include '^MyFolder' Instead, use --include '^MyFolder'
@ -377,14 +433,14 @@ R. Use
====================================================================== ======================================================================
Q. How to migrate from uw-imap with an admin/authuser account ? Q. How to migrate from uw-imap with an admin/authuser account?
R. Use R. Use
--user1="user*admin_user" --password1 "admin_user_password" --user1="user*admin_user" --password1 "admin_user_password"
====================================================================== ======================================================================
Q. How to migrate from cyrus with an admin account ? Q. How to migrate from cyrus with an admin account?
R. Use R. Use
--authuser1 admin_user ----password1 admin_user_password \ --authuser1 admin_user ----password1 admin_user_password \
@ -412,17 +468,17 @@ Here is an example:
--exclude '^user\.' --exclude '^user\.'
====================================================================== ======================================================================
Q. Is anyway imapsync to purge destionation folder when the source Q. Is there anyway of making imapsync purge the destination folder
folder is deleted? when the source folder is deleted?
R. No, that's too much dangerous. R. No, that's too dangerous.
But if the source folder is empty (not deleted) and
options --delete2 --expunge2 are used then But if the source folder is empty (not deleted) and options --delete2
the destination folder will be empty. --expunge2 are used then the destination folder will be empty.
====================================================================== ======================================================================
Q. Is it possible to synchronize all messages from one server to Q. Is it possible to synchronize all messages from one server to
another whithout recreating the folder structure and the target server. another without recreating the folder structure and the target server.
R. Yes. R. Yes.
1) First try (safe mode): 1) First try (safe mode):
@ -437,15 +493,15 @@ imapsync \
3) Remove --dry 3) Remove --dry
Check the imap folder tree on the target side, you should Check the imap folder tree on the target side, you should
only have one : the classical INBOX. only have one: the classical INBOX.
4) Remove --justfolders 4) Remove --justfolders
====================================================================== ======================================================================
Q. I have moved from Braunschweig to Graz, so I would like to have my whole Q. I have moved from Braunschweig to Graz, so I would like to have my
Braunschweig mail sorted into a folder INBOX.Braunschweig of my new mail whole Braunschweig mail sorted into a folder INBOX.Braunschweig of my
account. new mail account.
R. R.
1) First try (safe mode): 1) First try (safe mode):
@ -468,30 +524,29 @@ Q. Give examples about --regextrans2
R. Examples: R. Examples:
0) First try with --dry --justfolders options since imapsync shows the 0) First try with --dry --justfolders options since imapsync shows the
transformations it will do without really doing them. Then when happy transformations it will do without really doing them. Then when
with the output remove the --dry --justfolders options. happy with the output remove the --dry --justfolders options.
1) To remove INBOX. in the name of destination folders: 1) To remove INBOX. in the name of destination folders:
--regextrans2 's/^INBOX\.(.+)/$1/' --regextrans2 's/^INBOX\.(.+)/$1/'
2) To sync a complete account in a subfolder called FOO: 2) To sync a complete account in a subfolder called FOO:
a) Separator is dot character "." and "INBOX" prefixes every folder a) Seperator is dot character "." and "INBOX" prefixes every folder
--regextrans2 's/^INBOX(.*)/INBOX.FOO$1/' --regextrans2 's/^INBOX(.*)/INBOX.FOO$1/'
Or Or
b) Separator is slash character "/" b) Seperator is slash character "/"
--regextrans2 's#(.*)#FOO/$1#' --regextrans2 's#(.*)#FOO/$1#'
3) to substitute all characters dot "." by underscores "_" 3) to substitute all characters dot "." by underscores "_"
--regextrans2 's/\./_/g' --regextrans2 's/\./_/g'
======================================================================= =======================================================================
Q. I would like to move emails from InBox to a sub-folder Q. I would like to move emails from InBox to a sub-folder called,
called , say "2005-InBox" based on the date (Like all emails say "2005-InBox" based on the date (Like all emails received in the
received in the Year 2005 should be moved to the folder Year 2005 should be moved to the folder called "2005-InBox").
called "2005-InBox").
R. 2 ways : R. 2 ways :
@ -499,17 +554,18 @@ a) Manually:
------------ ------------
1) You create a folder INBOX.2005-INBOX 1) You create a folder INBOX.2005-INBOX
2) Mostly every email software allow sorting by date.
In inbox, you select from 1 january to 31 december 2) Mostly every email software allow sorting by date. In inbox, you
messages with the shift key. select from 1 january to 31 december messages with the shift key.
(in mutt, use ~d)
3) Cut/paste in INBOX.2005-INBOX 3) Cut/paste in INBOX.2005-INBOX
b) With imapsync: b) With imapsync:
----------------- -----------------
You have to calculate the day of year (and You have to calculate the day of year (and add 365). For example,
add 365). For example, running it today, running it today, Sat Mar 11 13:06:01 CET 2006:
Sat Mar 11 13:06:01 CET 2006:
imapsync ... imapsync ...
--host1 imap.truc.org --host2 imap.trac.org \ --host1 imap.truc.org --host2 imap.trac.org \
@ -528,9 +584,9 @@ Sat Mar 11 13:06:01 CET 2006
$ date +%j $ date +%j
070 070
Also, you must take imapsync 1.159 at least since I tested Also, you must take imapsync 1.159 at least since I tested what I just
what I just wrote above and found 2 bugs about --mindate wrote above and found 2 bugs about --mindate --maxdate options
--maxdate options behavior. behavior.
======================================================================= =======================================================================
Q. I want to play with headers line and --regexmess but I want to leave Q. I want to play with headers line and --regexmess but I want to leave
@ -560,7 +616,7 @@ This example just add an header line "X-Date:" based on "Date:" line.
======================================================================= =======================================================================
Q. My imap server does not accept a message and warns Q. My imap server does not accept a message and warns
"Invalid header". What is the problem ? "Invalid header". What is the problem?
R. You fall in the classical mbox versus Maildir/ format R. You fall in the classical mbox versus Maildir/ format
problem. May be you use a misconfigured procmail rule. problem. May be you use a misconfigured procmail rule.
@ -573,42 +629,39 @@ From foo@yoyo.org Sat Jun 22 01:10:21 2002
Return-Path: <foo@yoyo.org> Return-Path: <foo@yoyo.org>
Received: ... Received: ...
Any Maidir/ configured imap server may refuse this message Any Maildir/ configured imap server may refuse this message since its
since its header is invalid. The first "From " line is not header is invalid. The first "From " line is not valid. It lacks a
valid. It lacks a colon character ":". colon character ":". To solve this problem you have several solutions
To solve this problem you have several solutions a) or b):
a) Remove these first "From " line manually for each message a) Remove these first "From " line manually for each message before
before using imapsync. Don't think to add a colon to this using imapsync. Don't think to add a colon to this line since you
line since you will end with two "From:" lines (just look at will end with two "From:" lines (just look at the other lines)
the other lines)
b) Run imapsync with the following options : b) Run imapsync with the following options :
--regexmess 's/\AFrom \w .*\n//' --skipsize --regexmess 's/\AFrom \w .*\n//' --skipsize
======================================================================= =======================================================================
Q. The contact folder isn't well copied. Q. The contact folder isn't well copied.
How to copy the contact folder ? How to copy the contact folder?
R. Forget the destination server (chose the same) R. Forget the destination server (choose the same)
Change the script around line 1426 Change the script around line 1426
# ITSD # ITSD
$new_id = $from->copy($t_fold,$f_msg); $new_id = $from->copy($t_fold,$f_msg);
#$new_id = $to->append_string($t_fold,$string, $flags_f, $d); #$new_id = $to->append_string($t_fold,$string, $flags_f, $d);
and tried a copy of the mail instead an append_string.
Because we are using the same server, we can use $from->copy and tried a copy of the mail instead an append_string. Because we are
Therefore we seem to not download and upload the message and therefore using the same server, we can use $from->copy Therefore we seem to not
we do not have any format issues. download and upload the message and therefore we do not have any
And now it works fine. format issues. And now it works fine. (Thanks to Hansjoerg.Maurer)
(Thanks to Hansjoerg.Maurer)
======================================================================= =======================================================================
Q. Synchronysing from XXX to Gmail Q. Synchronising from XXX to Gmail
R. There are some details to get the special [Gmail] R. There are some details to get the special [Gmail] sub-folders
sub-folders right. Here's an example of migrating an old "Sent" right. Here's an example of migrating an old "Sent" folder to
folder to Gmail's structure: Gmail's structure:
imapsync --syncinternaldates \ imapsync --syncinternaldates \
--host1 mail.oldhost.com \ --host1 mail.oldhost.com \
@ -625,9 +678,9 @@ imapsync --syncinternaldates \
The same goes for the "All Mail" archive psuedo-folder. The same goes for the "All Mail" archive psuedo-folder.
======================================================================= =======================================================================
Q. Synchronysing from Gmail to XXX Q. Synchronising from Gmail to XXX
R. Gmail needs ssl. R. Gmail needs SSL
./imapsync \ ./imapsync \
--host1 imap.gmail.com --ssl1 \ --host1 imap.gmail.com --ssl1 \
@ -661,6 +714,7 @@ http://mark.ossdl.de/2009/02/migrating-from-exchange-2007-to-google-apps-mail/
Q. Syncing from Google Apps domain to Googlemail account Q. Syncing from Google Apps domain to Googlemail account
A known bug encountered with this output (Alexander is a folder name): A known bug encountered with this output (Alexander is a folder name):
++++ Verifying [Alexander] -> [Alexander] ++++ ++++ Verifying [Alexander] -> [Alexander] ++++
+ NO msg #16 [A96Dh4AwlLVphOAW5MS/eQ:779824] in Alexander + NO msg #16 [A96Dh4AwlLVphOAW5MS/eQ:779824] in Alexander
+ Copying msg #16:779824 to folder Alexander + Copying msg #16:779824 to folder Alexander
@ -679,9 +733,9 @@ R. Just run imapsync a time like this :
imapsync ... --folder Alexander imapsync ... --folder Alexander
======================================================================= =======================================================================
Q. I'm migrating from WU to Cyrus, and the mail folders are Q. I'm migrating from WU to Cyrus, and the mail folders are under
under /home/user/mail but the tool copies everything in /home/user/mail but the tool copies everything in /home/user, how
/home/user, how can i avoid that? can i avoid that?
R. Use R. Use
imapsync ... --include '^mail' imapsync ... --include '^mail'
@ -690,12 +744,11 @@ or (better)
======================================================================= =======================================================================
Q. I'm migrating from WU to Cyrus, and the mail folders are Q. I'm migrating from WU to Cyrus, and the mail folders are under
under /home/user/mail directory. When imapsync creates the /home/user/mail directory. When imapsync creates the folders in
folders in the new cyrus imap server, it makes a folder the new cyrus imap server, it makes a folder "mail" and below that
"mail" and below that folder puts all the mail folders the folder puts all the mail folders the user have in /home/user/mail,
user have in /home/user/mail, i would like to have all those i would like to have all those folders directly under INBOX.
folders directly under INBOX.
R. Use R. Use
imapsync ... --regextrans2 's/^mail/INBOX/' --dry imapsync ... --regextrans2 's/^mail/INBOX/' --dry
@ -719,30 +772,32 @@ following options:
--skipheader '^Content-Type' --skipheader '^Content-Type'
- MIME separator IDs seem to change every time a mail is accessed so - MIME separator IDs seem to change every time a mail is accessed so
this is required to stop duplicates. this is required to stop duplicates.
--maxage 3650 --maxage 3650
- some messages just don't seem to want to transfer and produce the - 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 perl errors I mentioned before. This prevents the errors, but the
messages don't transfer. bad messages don't transfer.
Even though the mail migrated OK, there are a couple of gotchas with Even though the mail migrated OK, there are a couple of gotchas with
Groupwise IMAP: Groupwise IMAP:
1) Some of the GW folders are not real folders and are not available to 1) Some of the GW folders are not real folders and are not available
IMAP, the main problem one being "Sent Items". I could find no way of to IMAP, the main problem one being "Sent Items". I could find no way
coping the contents of these folders. The nearest I got was to create a of coping the contents of these folders. The nearest I got was to
"real" folder and copy/move the sent items into it, but imapsync still create a "real" folder and copy/move the sent items into it, but
didn't see the messages (I think because there is something funny about imapsync still didn't see the messages (I think because there is
the reported dates/sizes). something funny about the reported dates/sizes).
It think this problem has been rectified in GW6.5. It think this problem has been rectified in GW6.5.
2) The "skipheader '^Content-Type'" directive is required to stop 2) The "skipheader '^Content-Type'" directive is required to stop
duplicate messages being created. GW seems to generate this field on the duplicate messages being created. GW seems to generate this field on
fly for messages that have MIME separators and so it's different every time. 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 3) Version 6.0.1 of the Groupwise Internet Connector sucks. I was
getting server abends when I pushed it a bit hard! I eventually had to 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. upgrade to 6.0.4 which seems to be a lot more stable.
@ -816,18 +871,19 @@ imapsync --host1 cyrus --user1 x --authuser1 x --password1 x --ssl1 \
--sep1 '/' --exclude 'user/demo/Trash' \ --sep1 '/' --exclude 'user/demo/Trash' \
--regextrans2 's/^user.//' --syncinternaldates --regextrans2 's/^user.//' --syncinternaldates
The 'exclude user/demo/Trash' was used because there was one message The 'exclude user/demo/Trash' was used because there was one message
there with 8 bit headers which dbmail doesn't accept, so I had to skip there with 8 bit headers which dbmail doesn't accept, so I had to skip
the whole folder. It would be nice to have an option to just ignore and the whole folder. It would be nice to have an option to just ignore
log unsyncable messages, but do the rest, instead of stopping. and log unsyncable messages, but do the rest, instead of stopping.
****************** ******************
There are two other major problems: There are two other major problems:
1) dbmail doesn't accept utf8 header, while cyrus does. imapsync stops
1) dbmail doesn't accept utf8 header, while cyrus does. imapsync stops
in that case, making sync impossible in that case, making sync impossible
To convert the wholes messages from 8bit to 7bit, use option : To convert the whole messages from 8bit to 7bit, use option :
--regexmess 's/[\x80-\xff]/X/g' --regexmess 's/[\x80-\xff]/X/g'
@ -861,7 +917,7 @@ R. See and run patches/imapsync_1.267_jari
Q. From any to Exchange2007 Q. From any to Exchange2007
Several problems: Several problems:
- Big messages: increse the "send- and receive-connector" - Big messages: increase the "send- and receive-connector"
in exchange2007 to 40 MB. in exchange2007 to 40 MB.
R. 2 solutions R. 2 solutions

View file

@ -0,0 +1,401 @@
COPYRIGHT
Copyright 1999, 2000, 2001, 2002 , 2003 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:
a) the "Artistic License" which comes with this Kit, or
b) the GNU General Public License as published by the Free Software
Foundation; either version 1, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either the GNU
General Public License or the Artistic License for more details. All your
base are belong to us.
=============
The "Artistic License"
Preamble
The intent of this document is to state the conditions under which a
Package may be copied, such that the Copyright Holder maintains some
semblance of artistic control over the development of the package,
while giving the users of the package the right to use and distribute
the Package in a more-or-less customary fashion, plus the right to make
reasonable modifications.
Definitions:
"Package" refers to the collection of files distributed by the
Copyright Holder, and derivatives of that collection of files
created through textual modification.
"Standard Version" refers to such a Package if it has not been
modified, or has been modified in accordance with the wishes
of the Copyright Holder as specified below.
"Copyright Holder" is whoever is named in the copyright or
copyrights for the package.
"You" is you, if you're thinking about copying or distributing
this Package.
"Reasonable copying fee" is whatever you can justify on the
basis of media cost, duplication charges, time of people involved,
and so on. (You will not be required to justify it to the
Copyright Holder, but only to the computing community at large
as a market that must bear the fee.)
"Freely Available" means that no fee is charged for the item
itself, though there may be fees involved in handling the item.
It also means that recipients of the item may redistribute it
under the same conditions they received it.
1. You may make and give away verbatim copies of the source form of the
Standard Version of this Package without restriction, provided that you
duplicate all of the original copyright notices and associated disclaimers.
2. You may apply bug fixes, portability fixes and other modifications
derived from the Public Domain or from the Copyright Holder. A Package
modified in such a way shall still be considered the Standard Version.
3. You may otherwise modify your copy of this Package in any way, provided
that you insert a prominent notice in each changed file stating how and
when you changed that file, and provided that you do at least ONE of the
following:
a) place your modifications in the Public Domain or otherwise make them
Freely Available, such as by posting said modifications to Usenet or
an equivalent medium, or placing the modifications on a major archive
site such as uunet.uu.net, or by allowing the Copyright Holder to include
your modifications in the Standard Version of the Package.
b) use the modified Package only within your corporation or organization.
c) rename any non-standard executables so the names do not conflict
with standard executables, which must also be provided, and provide
a separate manual page for each non-standard executable that clearly
documents how it differs from the Standard Version.
d) make other distribution arrangements with the Copyright Holder.
4. You may distribute the programs of this Package in object code or
executable form, provided that you do at least ONE of the following:
a) distribute a Standard Version of the executables and library files,
together with instructions (in the manual page or equivalent) on where
to get the Standard Version.
b) accompany the distribution with the machine-readable source of
the Package with your modifications.
c) give non-standard executables non-standard names, and clearly
document the differences in manual pages (or equivalent), together
with instructions on where to get the Standard Version.
d) make other distribution arrangements with the Copyright Holder.
5. You may charge a reasonable copying fee for any distribution of this
Package. You may charge any fee you choose for support of this
Package. You may not charge a fee for this Package itself. However,
you may distribute this Package in aggregate with other (possibly
commercial) programs as part of a larger (possibly commercial) software
distribution provided that you do not advertise this Package as a
product of your own. You may embed this Package's interpreter within
an executable of yours (by linking); this shall be construed as a mere
form of aggregation, provided that the complete Standard Version of the
interpreter is so embedded.
6. The scripts and library files supplied as input to or produced as
output from the programs of this Package do not automatically fall
under the copyright of this Package, but belong to whoever generated
them, and may be sold commercially, and may be aggregated with this
Package. If such scripts or library files are aggregated with this
Package via the so-called "undump" or "unexec" methods of producing a
binary executable image, then distribution of such an image shall
neither be construed as a distribution of this Package nor shall it
fall under the restrictions of Paragraphs 3 and 4, provided that you do
not represent such an executable image as a Standard Version of this
Package.
7. C subroutines (or comparably compiled subroutines in other
languages) supplied by you and linked into this Package in order to
emulate subroutines and variables of the language defined by this
Package shall not be considered part of this Package, but are the
equivalent of input as in Paragraph 6, provided these subroutines do
not change the language in any way that would cause it to fail the
regression tests for the language.
8. Aggregation of this Package with a commercial distribution is always
permitted provided that the use of this Package is embedded; that is,
when no overt attempt is made to make this Package's interfaces visible
to the end user of the commercial distribution. Such use shall not be
construed as a distribution of this Package.
9. The name of the Copyright Holder may not be used to endorse or promote
products derived from this software without specific prior written permission.
10. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
The End
=============
GNU GENERAL PUBLIC LICENSE
Version 1, February 1989
Copyright (C) 1989 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The license agreements of most software companies try to keep users
at the mercy of those companies. By contrast, our General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. The
General Public License applies to the Free Software Foundation's
software and to any other program whose authors commit to using it.
You can use it for your programs, too.
When we speak of free software, we are referring to freedom, not
price. Specifically, the General Public License is designed to make
sure that you have the freedom to give away or sell copies of free
software, that you receive source code or can get it if you want it,
that you can change the software or use pieces of it in new free
programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of a such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must tell them their rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any program or other work which
contains a notice placed by the copyright holder saying it may be
distributed under the terms of this General Public License. The
"Program", below, refers to any such program or work, and a "work based
on the Program" means either the Program or any work containing the
Program or a portion of it, either verbatim or with modifications. Each
licensee is addressed as "you".
1. You may copy and distribute verbatim copies of the Program's source
code as you receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice and
disclaimer of warranty; keep intact all the notices that refer to this
General Public License and to the absence of any warranty; and give any
other recipients of the Program a copy of this General Public License
along with the Program. You may charge a fee for the physical act of
transferring a copy.
2. You may modify your copy or copies of the Program or any portion of
it, and copy and distribute such modifications under the terms of Paragraph
1 above, provided that you also do the following:
a) cause the modified files to carry prominent notices stating that
you changed the files and the date of any change; and
b) cause the whole of any work that you distribute or publish, that
in whole or in part contains the Program or any part thereof, either
with or without modifications, to be licensed at no charge to all
third parties under the terms of this General Public License (except
that you may choose to grant warranty protection to some or all
third parties, at your option).
c) If the modified program normally reads commands interactively when
run, you must cause it, when started running for such interactive use
in the simplest and most usual way, to print or display an
announcement including an appropriate copyright notice and a notice
that there is no warranty (or else, saying that you provide a
warranty) and that users may redistribute the program under these
conditions, and telling the user how to view a copy of this General
Public License.
d) You may charge a fee for the physical act of transferring a
copy, and you may at your option offer warranty protection in
exchange for a fee.
Mere aggregation of another independent work with the Program (or its
derivative) on a volume of a storage or distribution medium does not bring
the other work under the scope of these terms.
3. You may copy and distribute the Program (or a portion or derivative of
it, under Paragraph 2) in object code or executable form under the terms of
Paragraphs 1 and 2 above provided that you also do one of the following:
a) accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of
Paragraphs 1 and 2 above; or,
b) accompany it with a written offer, valid for at least three
years, to give any third party free (except for a nominal charge
for the cost of distribution) a complete machine-readable copy of the
corresponding source code, to be distributed under the terms of
Paragraphs 1 and 2 above; or,
c) accompany it with the information you received as to where the
corresponding source code may be obtained. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form alone.)
Source code for a work means the preferred form of the work for making
modifications to it. For an executable file, complete source code means
all the source code for all modules it contains; but, as a special
exception, it need not include source code for modules which are standard
libraries that accompany the operating system on which the executable
file runs, or for standard header files or definitions files that
accompany that operating system.
4. You may not copy, modify, sublicense, distribute or transfer the
Program except as expressly provided under this General Public License.
Any attempt otherwise to copy, modify, sublicense, distribute or transfer
the Program is void, and will automatically terminate your rights to use
the Program under this License. However, parties who have received
copies, or rights to use copies, from you under this General Public
License will not have their licenses terminated so long as such parties
remain in full compliance.
5. By copying, distributing or modifying the Program (or any work based
on the Program) you indicate your acceptance of this license to do so,
and all its terms and conditions.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the original
licensor to copy, distribute or modify the Program subject to these
terms and conditions. You may not impose any further restrictions on the
recipients' exercise of the rights granted herein.
7. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of the license which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
the license, you may choose any version ever published by the Free Software
Foundation.
8. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
Appendix: How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to humanity, the best way to achieve this is to make it
free software which everyone can redistribute and change under these
terms.
To do so, attach the following notices to the program. It is safest to
attach them to the start of each source file to most effectively convey
the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) 19yy <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 1, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) 19xx name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the
appropriate parts of the General Public License. Of course, the
commands you use may be called something other than `show w' and `show
c'; they could even be mouse-clicks or menu items--whatever suits your
program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
program `Gnomovision' (a program to direct compilers to make passes
at assemblers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
That's all there is to it!

2031
Mail-IMAPClient-3.23/Changes Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,82 @@
Mail::IMAPClient Installation
The Mail::IMAPClient is written entirely in Perl, so it should install
on any reasonably recent version of Perl. See the README file for a perl
one-liner that you can run to verify that your perl has what it takes
to run Mail::IMAPClient.
The installation is standard:
0) cd to installation directory
1) perl Makefile.PL (and reply to the prompts)
2) make (optional)
3) make test (optional)
4) make install
The 'make install' and 'make test' will both do step 2 ('make') if you
haven't done it already. Currently the test script is lame (although
not as lame as in the last release!) but I hope to incorporate more
thorough testing in a future version. You should at least try it and
let me know if your tests fail.
Version 1.0 changed the installation script so that it reuses the
parameter file for the tests if it finds one. Installation can be run in
the background if the test.txt file exists. Touching it is good enough
to prevent prompts; having a correctly formatted version (as shown in
test_template.txt) is even better, as it will allow you to do a thorough
'make test'. Invalid data in test.txt (either from precreating it or from
responding inaccurately to prompts) will cause 'make test' to report 'not
ok' results but won't break anything important (like the IMAPClient.pm
file, or your car).
If you have tests that fail it may be more illuminating to run the
tests by hand. IE: perl -I./blib/lib t/basic.t from the installation
dir will pinpoint the failing test. Better yet, supply an argument to
basic/t (any 'true' argument will do; I use '1') to turn on debugging,
which will be placed in your installation directory in 'imap1.debug'
and 'imap2.debug'. E-mail me the results.
If you don't have a test.txt file in your installation directory then you
will have to answer at least one prompt. If you do have a test.txt file,
and you run 'make clean', then you won't have a test.txt file anymore,
so take precautions.
If you do have a test.txt file and you don't run 'make clean' then
a text file will be sitting around containing logon credentials, so,
again, take precautions. (It's just a test account anyway, right?)
If, when replying to the "perl Makefile.PL" prompts, you supply server,
id, and password credentials for an id that has a ridiculously huge number
of folders and subfolders then the 'make test' may run approximately
forever. Next time try an id with less stuff.
For examples on using Mail::IMAPClient, check out the examples
subdirectory. If you have better examples, then why haven't you e-mailed
them to me? Also, I totally recommend that you have a copy of RFC2060
handy when using this module, since the documentation for this module is
meant to compliment, not replace, RFC2060. In fact, I am so convinced that
you'll need the RFC that I've included a copy of it in the distribution,
under the "docs/" subdirectory. It's a smashing good read so have at
it. Other IMAP related rfcs are there as well.
One of the examples in the examples/ subdirectory is called
cleanTest.pl. If you find your 'make test' has had trouble and left some
folders named "IMAPClient_*" in your test account, you can run this
example to clean up the account. But probably only after you've fixed
any problems encountered with 'make test'!
This module uses Damian Conway's excellent Parse::RecDescent module
for some advanced features. If you don't have that module installed
then you can still install Mail::IMAPClient but you won't have the
full functionality. If you have Parse::RecDescent installed and then
upgrade it, you may find that some features in Mail::IMAPClient suddenly
start throwing compile-time errors. Just 'make clean' and then 'make',
'make test', and 'make install'. This happens because grammers compiled
under older releases of Parse::RecDescent are sometimes incompatible
with newer Parse::RecDescent runtime engines. This would never be a
problem if Mail::IMAPClient recompiled grammers at run time, but for
performance reasons it precompiles them at install time. TANSTAAFL.
Now go and write IMAP clients.
Dave Kernen

View file

@ -0,0 +1,41 @@
COPYRIGHT
Changes
INSTALL
MANIFEST
Makefile.PL
README
TODO
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/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
sample.perldb
t/basic.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)

View file

@ -0,0 +1,22 @@
# http://module-build.sourceforge.net/META-spec.html
#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
name: Mail-IMAPClient
version: 3.23
version_from: lib/Mail/IMAPClient.pm
installdirs: site
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
distribution_type: module
generated_by: ExtUtils::MakeMaker version 6.17

View file

@ -0,0 +1,145 @@
use ExtUtils::MakeMaker;
use warnings;
use strict;
my @missing;
my %optional = (
"Authen::NTLM" => { for => "Authmechanism 'NTLM'" },
"Authen::SASL" => { for => "Authmechanism 'DIGEST-MD5'" },
"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;
}
WriteMakefile(
NAME => 'Mail::IMAPClient',
,
ABSTRACT => 'IMAP4 client library',
VERSION_FROM => 'lib/Mail/IMAPClient.pm',
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' },
$] >= 5.005
? ## keywords supported since 5.005
( AUTHOR => 'Phil Lobbes <phil@zimbra.com>' )
: ()
);
set_test_data();
exit 0;
###
### HELPERS
###
sub set_test_data {
unless ( -f "lib/Mail/IMAPClient.pm" ) {
warn "ERROR: not in installation directory\n";
return;
}
return if -f "./test.txt";
print <<'__INTRO';
You have the option of running an extended suite of tests during
'make test'. This requires an IMAP server name, user account, and
password to test with.
__INTRO
my $yes = prompt "Do you want to run the extended tests? (n/y)";
return if $yes !~ /^y(?:es)?$/i;
unless ( open TST, '>', "./test.txt" ) {
warn "ERROR: couldn't open ./test.txt: $!\n";
return;
}
my $server = "";
until ($server) {
$server =
prompt "\nPlease provide the hostname or IP address of "
. "a host running an\nIMAP server (or QUIT to skip "
. "the extended tests)";
chomp $server;
return if $server =~ /^\s*quit\s*$/i;
}
print TST "server=$server\n";
my $user = "";
until ($user) {
$user =
prompt "\nProvide the username of an account on $server (or QUIT)";
chomp $user;
return if $user =~ /^\s*quit\s*$/i;
}
print TST "user=$user\n";
my $passed = "";
until ($passed) {
$passed = prompt "\nProvide the password for $user (or QUIT)";
chomp $passed;
return if $passed =~ /^\s+$|^quit$/i;
}
print TST "passed=$passed\n";
my $port = prompt "\nPlease provide the port to connect to on $server "
. "to run the test\n(default is 143)";
chomp $port;
$port ||= 143;
print TST "port=$port\n";
my $authmech = prompt "\nProvide the authentication mechanism to use "
. "on $server to\nrun the test (default is LOGIN)";
chomp $authmech;
$authmech ||= 'LOGIN';
print TST "authmechanism=$authmech\n";
close TST;
print <<'__THANKS';
The information you provided (including the password!) has been stored
in test.txt and SHOULD BE REMOVED (either by hand or by 'make clean')
after testing.
__THANKS
}

111
Mail-IMAPClient-3.23/README Normal file
View file

@ -0,0 +1,111 @@
Mail::IMAPClient
Copyright 1999-2003 The Kernen Group, Inc.
Copyright 2007 Mark Overmeer
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of either:
a) the "Artistic License" which comes with this Kit, or
b) the GNU General Public License as published by the Free Software
Foundation; either version 1, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See either
the GNU General Public License or the Artistic License for more details.
DESCRIPTION
This module provides perl routines that simplify a sockets connection
to and an IMAP conversation with an IMAP server.
COMPATIBILITY
[This paragraph has not been updated for many years]
This module was developed on Solaris 2.5.1 and 2.6 against Netscape IMAP
servers versions 3.6 and 4.1. However, since it is written in perl and
designed for flexibility, it should run on any OS with a TCP/IP stack and
a version of perl that includes the Socket and IO::Socket modules. It also
should be able to talk to any IMAP server, even those that have, um,
proprietary features (assuming that the programmer knows what those features
are).
To date, I know that the test suite runs successfully with the following IMAP
servers:
-Netscape Messenging Server v4.x
-Netscape Messenging Server v3.x
-UW-IMAP (I think it was 4.5)
-Cyrus IMAP4 v1.5.19
-Mirapoint Message Server Appliances (OS versions 1.6.1, 1.7.1, and 2.0.2)
Version 2.0.3 has been tested with the mdaemon server with mixed
results. It seems that mdaemon does not comply strictly with RFC2060 and
so you may have problems using this module with mdaemon, especially with
folder names with embedded spaces or embedded double quotes. You may be
able to get some simple tasks to work but you won't be able to run the
test suite successfully. Use with caution.
If your server requires the use of the AUTHENTICATE IMAP client command
(say, for strong authentication) then you can still use this module,
provided you can come up with the appropriate responses to any challenges
offered by your server. Mark Bush's Authen::NTLM module can assist with
this if you specifically are interested in NTLM authentication.
REPORING BUGS
See http://rt.cpan.org/Public/Dist/Display.html?Name=Mail-IMAPClient
INSTALLATION
Generally, gunzipping and untarring the source file, running 'perl
Makefile.PL' and 'make install' are all it takes to install this
module. And if that's too much work you can always use the CPAN module!
OVERVIEW OF FUNCTIONALITY
Mail::IMAPClient.pm provides methods to simplify the connection to and
the conversation between a perl script and an IMAP server. Virtually
all IMAP Client commands (as defined in rfc2060) are supported, either
through IMAPClient object methods or the 'default method', which is an
AUTOLOAD hack that assumes a default syntax for IMAP Client commands of:
tagvalue COMMAND [Arg1 [Arg2 [... Arg3]]]"
By remarkable coincidence, AUTOLOAD's default syntax mimics the
general syntax of IMAP Client commands. This means that if a script
tries to use any undefined method then that method will be interpreted
as an unimplemented IMAP command, and the default syntax will be used
to create the command string. I did this as a short cut to writing a
bunch of methods that were practically the same. There are inheritance
implications because of this approach but as far as I can tell this is
not a serious limitation. However, if you decide to write modules that
inherit from this class that require AUTOLOAD logic of their own then you
will have to take the Mail::IMAPClient's AUTOLOAD strategy into account.
Where methods are defined, they usually exist to add functionality,
perhaps by massaging output or by supplying default arguments. An example
is the search method, which accepts the same arguments as the SEARCH
IMAP Client command (as documented in RFC2060) but which massages the
results so that the return value is an array of message sequence numbers
matching the search criteria, rather than a line of text listing the
sequence numbers.
Some methods exists solely to add functionality, such as the folders
method, which invokes the list method but then massages the results to
produce an array containing all folder names. The message_count and
delete_messsage methods are similarly examples of methods that add
function to "raw" IMAP Client commands.
Further information is provided in the module's documentation, which you are
encouraged to read and enjoy.
Good Luck!
Dave Kernen
The Kernen Group, Inc.
DJKERNEN@cpan.org

68
Mail-IMAPClient-3.23/TODO Normal file
View file

@ -0,0 +1,68 @@
=== README
Starting with release 2.99_01, I (Mark Overmeer) try to revive the
module. The original author David Kernen cannot be reached and didn't
release any fixes in four years. That is far too long.
The code and installation procedure has been cleaned-up radically,
and some minimal improvements in the code are made to
fix things people reported.
=== wishlist:
- A start was made in cleanup of the code in Mail/IMAPClient.pm
The file Mail/IMAPClient-cleanup shows the progress (30%)
But I lack the time (a weeks work at least) to complete this
task. There is a lot of code replication to be stripped.
If anyone buys me time, I will complete that task.
=== wishlist from the original author:
The following is a list of some items that I hope to include in a future
release:
- Support for threaded perl programs (still pending as of version 2.2.0.).
- Support for imaps (Imap via SSL). I don't have any way to test this
right now but if you get this to work or know someone who has I'd be
really interested in hearing from you.
- Support for more authentication mechanisms. Currently plain
authentication and cram-md5 authentication are supported. I have
DIGEST-MD5 working at the AUTH qop, but haven't incorporated it into
a released version because I'm still trying to get at least the
integrity qop working, and maybe even privacy, but considering how
much trouble I'm having with just the integrity level I wouldn't
hold my breath if I were you ;-).
- Currently a number of IMAP Client commands are implemented using the
'default method', which is an AUTOLOAD hack. I'd like to reduce that
if possible to a bare minimum. (Some are still pending as of version 2.2.7.)
- I'd like to see this module certified for more OS's and more IMAP servers.
This is (hopefully) just a matter of testing; the code should already
be compatible with the IMAP servers that are out there and with any OS
that allows the IO::Socket module to work. ** A number of platforms
have been added to the list of tested platforms since this was first
written. Please contact DJKernen@cpan.org if you have any to add.
- Support for newer/older/other versions of IMAP. Currently only RFC2060 is
explicitly supported, although thanks to the 'default method'
(implemented via an AUTOLOAD hack) virtually any IMAP command is
supported, even proprietary commands, X- extensions, and so forth. But
not necessarily other authentication mechanisms... :-( (NOTE: the
AUTHENTICATE method partially addresses this issue.)
- Support for piping output from (some?) imap commands directly to a
thingy of some sort (perhaps a coderef, a filehandle, or both).
- Your thingy here!!! Send me your request, and I'll do it in the order of
($popularity/$difficulty ).
- Support for perl version 6. This will probably involve a rewrite that
will make portions of the Mail::IMAPClient module look more like the
Mail::IMAPClient::BodyStructure module. (Perl 6 will have built-in
support for semantics that look remarkably like Damian Conway's
Parse::RecDescent module, which will solve a lot of problems for me.)

View file

@ -0,0 +1,172 @@
#!/usr/local/bin/perl
#$Id: //depot/main/ZimbraPS/Mail-IMAPClient/examples/build_dist.pl#1 $
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: //depot/main/ZimbraPS/Mail-IMAPClient/examples/build_dist.pl#1 $
# $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: //depot/main/ZimbraPS/Mail-IMAPClient/examples/build_ldif.pl#1 $
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: //depot/main/ZimbraPS/Mail-IMAPClient/examples/build_ldif.pl#1 $
# $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: //depot/main/ZimbraPS/Mail-IMAPClient/examples/copy_folder.pl#1 $
++$|;
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: //depot/main/ZimbraPS/Mail-IMAPClient/examples/cyrus_expunge.pl#1 $
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: //depot/main/ZimbraPS/Mail-IMAPClient/examples/find_dup_msgs.pl#1 $
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,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: //depot/main/ZimbraPS/Mail-IMAPClient/examples/imap_to_mbox.pl#1 $
# 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: //depot/main/ZimbraPS/Mail-IMAPClient/examples/migrate_mail2.pl#1 $
#
# 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: //depot/main/ZimbraPS/Mail-IMAPClient/examples/migrate_mbox.pl#1 $
#
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: //depot/main/ZimbraPS/Mail-IMAPClient/examples/populate_mailbox.pl#1 $ #
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: //depot/main/ZimbraPS/Mail-IMAPClient/examples/populate_mailbox.pl#1 $
# $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: //depot/main/ZimbraPS/Mail-IMAPClient/examples/sharedFolder.pl#1 $
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,557 @@
use warnings;
use strict;
package Mail::IMAPClient::BodyStructure;
use Mail::IMAPClient::BodyStructure::Parse;
# 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;
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++;
$p->{_prefix} = "$prefix$partno";
$p->{_id} ||= "$prefix$partno";
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};
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 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::BodyStructure;
use Mail::IMAPClient;
my $imap = Mail::IMAPClient->new(Server=>$serv,User=>$usr,Password=>$pwd);
$imap->select("INBOX") or die "cannot select the inbox for $usr: $@\n";
my @recent = $imap->search("recent");
foreach my $id (@recent)
{ my $fetched = $imap->fetch($id, "bodystructure");
my $struct = Mail::IMAPClient::BodyStructure->new($fetched);
my $mime = $struct->bodytype."/".$struct->bodysubtype;
my $parts =join "\n\t", $struct->parts;
print "Msg $id (Content-type: $mime) contains these parts:\n\t$parts\n";
}
=head1 DESCRIPTION
This extension will parse the result of an IMAP FETCH BODYSTRUCTURE
command into a perl data structure. It also provides helper methods that
will help you pull information out of the data structure.
Use of this extension requires Parse::RecDescent. If you don't have
Parse::RecDescent then you must either get it or refrain from using
this module.
=head2 EXPORT
Nothing is exported by default. C<$parser> is exported upon
request. C<$parser> is the BodyStucture object's Parse::RecDescent object,
which you'll probably only need for debugging purposes.
=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. Only one message's body structure should be described in this
string, although that message may contain an arbitrary number of parts.
If you know the messages sequence number or unique ID (UID)
but haven't got its body structure, and you want to get the body
structure and parse it into a B<Mail::IMAPClient::BodyStructure>
object, then you might as well save yourself some work and use
B<Mail::IMAPClient>'s B<get_bodystructure> method, which accepts
a message sequence number (or UID if I<Uid> is true) and returns a
B<Mail::IMAPClient::BodyStructure> object. It's functionally equivalent
to issuing the FETCH BODYSTRUCTURE IMAP client command and then passing
the results to B<Mail::IMAPClient::BodyStructure>'s B<new> method but
it does those things in one simple method call.
=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
the envelopestruct for the message whose structure is described by the
calling B<Mail::IMAPClient::Bodystructure> object. This envelope structure
is blessed into the B<Mail::IMAPClient::BodyStructure::Envelope> subclass,
which is explained more fully below.
=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 Envelopes and the Mail::IMAPClient::BodyStructure::Envelope Subclass
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
analagous method that will return a list of E-Mail addresses instead. The
addresses are in the format C<personalname E<lt>mailboxname@hostnameE<gt>>
(see the section on B<Mail::IMAPClient::BodyStructure::Address>,
below) However, if the personal name is 'NIL' then it is omitted from
the address.
These methods are:
=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
David J. Kernen
Reworked and maintained by Mark Overmeer.
=head1 SEE ALSO
perl(1), Mail::IMAPClient, and RFC2060. See also Parse::RecDescent if you
want to understand the internals of this module.
=cut

View file

@ -0,0 +1,188 @@
# 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" }
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
| "(" 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 nummers
=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 specifiy 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 negligable. 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,37 @@
#!/usr/bin/perl
use warnings;
use strict;
use Parse::RecDescent 1.94;
use File::Slurp qw/read_file/;
use File::Copy qw/move/;
sub build_parser($$);
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 @@
&parse_options("NonStop=1 LineInfo=mail_imapclient_db.out");

View file

@ -0,0 +1,343 @@
#!/usr/bin/perl
use strict;
use warnings;
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 => 67;
}
BEGIN { use_ok('Mail::IMAPClient') or exit; }
my @new_args = (
Server => $parms{server},
Port => $parms{port},
User => $parms{user},
Password => $parms{passed},
Authmechanism => $parms{authmech},
Clear => 0,
Fast_IO => $fast,
Uid => $uidplus,
Debug => $debug,
);
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 $parms{server} as $parms{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: <$parms{user}\@$parms{server}>
From: Perl <$parms{user}\@$parms{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" );
my $sep = $imap->separator;
ok( defined $sep, "separator is '$sep'" );
my $ispar = $imap->is_parent('INBOX');
my ( $target, $target2 ) =
$ispar
? ( "INBOX${sep}IMAPClient_$$", "INBOX${sep}IMAPClient_2_$$" )
: ( "IMAPClient_$$", "IMAPClient_2_$$" );
ok( defined $ispar, "INBOX is_parent '$ispar' (note: target '$target')" );
ok( $imap->select('inbox'), "select inbox" );
ok( $imap->create($target), "create target" );
{
my $list = $imap->list();
is( ref($list), "ARRAY", "list" );
my $lsub = $imap->lsub();
is( ref($lsub), "ARRAY", "lsub" );
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" );
ok( $imap->tag_and_run("NOOP\r\n"), "tag_and_run" );
}
my $fwquotes = qq($target${sep}has "quotes");
if ( !$imap->is_parent($target) ) {
ok( 1, "not parent, skipping quote test 1/3" );
ok( 1, "not parent, skipping quote test 2/3" );
ok( 1, "not parent, skipping quote test 3/3" );
}
elsif ( $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 {
if ( $imap->LastError =~ /NO Invalid.*name/ ) {
ok( 1, "$parms{server} doesn't support quotes in folder names" );
}
else { ok( 0, "failed creation with quotes" ) }
ok( 1, "skipping 1/2 tests" );
ok( 1, "skipping 2/2 tests" );
}
ok( $imap->exists($target), "exists $target" );
ok( $imap->create($target2), "create $target2" );
ok( $imap->exists($target2), "exists $target2" );
my $uid = $imap->append( $target, $testmsg );
ok( defined $uid, "append 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 has size" );
{
my ( $fh, $fn ) = tempfile UNLINK => 1;
ok( $imap->message_to_file( $fn, $msg ), "to file $fn" );
cmp_ok( -s $fn, '==', $size, "correct size" );
}
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 $res1 = $imap->fetch_hash("RFC822.SIZE");
is( ref($res1), "HASH", "fetch_hash(RFC822.SIZE)" );
my $res2 = $imap->fetch_hash( 1, "RFC822.SIZE" );
is( ref($res2), "HASH", "fetch_hash(1,RFC822.SIZE)" );
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( $im2->logout, "logout" ) or diag("logout error: $@");
# 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" );
# Test STARTTLS - an optional feature so tests always succeed
{
ok( $imap->logout, "logout" ) or diag("logout error: $@");
$imap->connect( Starttls => 1 );
ok( 1, "OPTIONAL connect(Starttls=>1)" . ( $@ ? ": (error) $@ " : "" ) );
}

View file

@ -0,0 +1,58 @@
#!/usr/bin/perl
use strict;
use warnings;
use Test::More tests => 11;
BEGIN { use_ok('Mail::IMAPClient::BodyStructure') or exit; }
my $bs = <<'END_OF_BS';
(BODYSTRUCTURE ("TEXT" "PLAIN" ("CHARSET" "us-ascii") NIL NIL "7BIT" 511 20 NIL NIL NIL))^M
END_OF_BS
my $bsobj = Mail::IMAPClient::BodyStructure->new($bs);
ok( defined $bsobj, 'parsed first' );
is( $bsobj->bodytype, 'TEXT', 'bodytype' );
is( $bsobj->bodysubtype, 'PLAIN', 'bodysubtype' );
my $bs2 = <<'END_OF_BS2';
(BODYSTRUCTURE (("TEXT" "PLAIN" ("CHARSET" 'us-ascii') NIL NIL "7BIT" 2 1 NIL NIL NIL)("MESSAGE" "RFC822" NIL NIL NIL "7BIT" 3930 ("Tue, 16 Jul 2002 15:29:17 -0400" "Re: [Fwd: Here is the the list of uids]" (("Michael Etcetera" NIL "michael.etcetera" "generic.com")) (("Michael Etcetera" NIL "michael.etcetera" "generic.com")) (("Michael Etcetera" NIL "michael.etcetera" "generic.com")) (("Michael Etcetera" NIL "michael.etcetera" "generic.com")) (("David J Kavid" NIL "david.kavid" "generic.com")) NIL NIL "<72f9a217.a21772f9@generic.com>") (("TEXT" "PLAIN" ("CHARSET" "us-ascii") NIL NIL "7BIT" 369 11 NIL NIL NIL)("MESSAGE" "RFC822" NIL NIL NIL "7BIT" 2599 ("Tue, 9 Jul 2002 13:42:04 -0400" "Here is the the list of uids" (("Nicholas Kringle" NIL "nicholas.kringle" "generic.com")) (("Nicholas Kringle" NIL "nicholas.kringle" "generic.com")) (("Nicholas Kringle" NIL "nicholas.kringle" "generic.com")) (("Michael Etcetera" NIL "michael.etcetera" "generic.com")) (("Richard W Continued" NIL "richard.continued" "generic.com")) NIL NIL "<015401c2276f$f09b7c10$59cab08c@one.two.generic.com>") ((("TEXT" "PLAIN" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 256 10 NIL NIL NIL)("TEXT" "HTML" ("CHARSET" "iso-8859-1") NIL NIL "QUOTED-PRINTABLE" 791 22 NIL NIL NIL) "ALTERNATIVE" ("BOUNDARY" "----=_NextPart_001_0151_01C2274E.6969D0F0") NIL NIL) "MIXED" ("BOUNDARY" "----=_NextPart_000_0150_01C2274E.6969D0F0") NIL NIL) 75 NIL NIL NIL) "MIXED" ("BOUNDARY" "--1f34eac2082b02") NIL ("EN")) 118 NIL NIL NIL) "MIXED" ("BOUNDARY" "------------F600BD8FDDD648ABA72A09E0") NIL NIL))
END_OF_BS2
$bsobj = Mail::IMAPClient::BodyStructure->new($bs2);
ok( defined $bsobj, 'parsed second' );
is( $bsobj->bodytype, 'MULTIPART', 'bodytype' );
is( $bsobj->bodysubtype, 'MIXED', 'bodysubtype' );
is(
join( "#", $bsobj->parts ),
# Better parsing in version 3.03, changed this outcome
# "1#2#2.HEAD#2.1#2.2#2.2.HEAD#2.2.1#2.2.1.1#2.2.1.2"
"1#2#2.HEAD#2.1#2.1.1#2.1.2#2.1.2.HEAD#2.1.2.1#2.1.2.1.1#2.1.2.1.1.1#2.1.2.1.1.2",
'parts'
);
my $bs3 = <<'END_OF_BS3';
FETCH (UID 1 BODYSTRUCTURE (("TEXT" "PLAIN" ("charset" "ISO-8859-1")
NIL NIL "quoted-printable" 1744 0)("TEXT" "HTML" ("charset"
"ISO-8859-1") NIL NIL "quoted-printable" 1967 0) "ALTERNATIVE"))
END_OF_BS3
$bsobj = Mail::IMAPClient::BodyStructure->new($bs3);
ok( defined $bsobj, 'parsed third' );
my $bs4 = <<'END_OF_BS4';
* 9 FETCH (UID 9 BODYSTRUCTURE (("TEXT" "PLAIN" ("charset" "us-ascii") NIL "Notification" "7BIT" 588 0)("MESSAGE" "DELIVERY-STATUS" NIL NIL "Delivery report" "7BIT" 459)("MESSAGE" "RFC822" NIL NIL "Undelivered Message" "8bit" 10286 ("Thu, 31 May 2007 11:25:56 +0200 (CEST)" "*****SPAM***** RE: Daily News" (("admin@activtrades.com" NIL "polettld" "ensma.fr")) (("admin@activtrades.com" NIL "polettld" "ensma.fr")) (("admin@activtrades.com" NIL "polettld" "ensma.fr")) ((NIL NIL "polettld" "ensma.fr")) NIL NIL "NIL" "<20070531133257.92825.qmail@cc299962-a.haaks1.ov.home.nl>") (("TEXT" "PLAIN" ("charset" "iso-8859-1") NIL NIL "7bit" 1510 0)("MESSAGE" "RFC822" ("name" "message" "x-spam-type" "original") NIL "Original message" "8bit" 5718) "MIXED")) "REPORT"))
END_OF_BS4
$bsobj = Mail::IMAPClient::BodyStructure->new($bs4);
ok( defined $bsobj, 'parsed fourth' );
# test bodyMD5, contributed by Micheal Stok
my $bs5 = <<'END_OF_BS5';
* 6 FETCH (UID 17280 BODYSTRUCTURE ((("text" "plain" ("charset" "utf-8") NIL NIL "quoted-printable" 1143 37 NIL NIL NIL)("text" "html" ("charset" "utf-8") NIL NIL "quoted-printable" 4618 106 NIL NIL NIL) "alternative" ("boundary" "Boundary-00=_Z7P340MWKGMMYJ0CCJD0") NIL NIL)("image" "tiff" ("name" "8dd0e430.tif") NIL NIL "base64" 204134 "pmZp5QOBa9BIqFNmvxUiyQ==" ("attachment" ("filename" "8dd0e430.tif")) NIL) "mixed" ("boundary" "Boundary-00=_T7P340MWKGMMYJ0CCJD0") NIL NIL))
END_OF_BS5
$bsobj = Mail::IMAPClient::BodyStructure->new($bs5);
ok( defined $bsobj, 'parsed fifth' );

View file

@ -0,0 +1,233 @@
#!/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 => 18;
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}, }, },
],
[
"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)}, }, },
],
[
"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}, }, },
],
[
"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>
X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on pyro.home
X-Spam-Level:
X-Spam-Status: No, score=-0.5 required=5.0 tests=ALL_TRUSTED,BAYES_00,
FH_FROMEML_NOTLD,TO_MALFORMED autolearn=no version=3.2.5
X-Original-To: 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>
X-Bogosity: Spam, tests=bogofilter, spamicity=0.999693, version=1.2.1
Lines: 1
This is a test mailing
',
')
',
],
[
[1],
q{BODY.PEEK[HEADER.FIELDS (To From Date Subject)]},
qw(FLAGS INTERNALDATE RFC822.SIZE BODY[])
],
{
"1" => {
'BODY[]' => 'Return-Path: <rob@pyro>
X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on pyro.home
X-Spam-Level:
X-Spam-Status: No, score=-0.5 required=5.0 tests=ALL_TRUSTED,BAYES_00,
FH_FROMEML_NOTLD,TO_MALFORMED autolearn=no version=3.2.5
X-Original-To: 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>
X-Bogosity: Spam, tests=bogofilter, spamicity=0.999693, version=1.2.1
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'
},
},
],
);
my @uid_tests = (
[
"uid enabled",
[ q{* 1 FETCH (UID 123 UNQUOTED foobar)}, ],
[ [123], qw(UNQUOTED) ],
{ "123" => { "UNQUOTED" => q{foobar}, } },
],
);
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} || [];
}
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->fetch_hash(@$request);
is_deeply( $r, $response, $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

View file

@ -1,5 +1,5 @@
# $Id: Makefile,v 1.27 2010/01/19 15:26:12 gilles Exp gilles $ # $Id: Makefile,v 1.28 2010/02/25 23:17:25 gilles Exp gilles $
TARGET=imapsync TARGET=imapsync
@ -25,7 +25,7 @@ all: ChangeLog README VERSION
touch .test touch .test
.test_3xx: $(TARGET) tests.sh .test_3xx: $(TARGET) tests.sh
CMD_PERL='perl -I./Mail-IMAPClient-3.21/lib' /usr/bin/time sh tests.sh 1>/dev/null CMD_PERL='perl -I./Mail-IMAPClient-3.23/lib' /usr/bin/time sh tests.sh 1>/dev/null
touch .test_3xx touch .test_3xx
test_quick : test_quick_229 test_quick_3xx test_quick : test_quick_229 test_quick_3xx
@ -34,7 +34,7 @@ test_quick_229: $(TARGET) tests.sh
CMD_PERL='perl -I./Mail-IMAPClient-2.2.9' /usr/bin/time sh tests.sh locallocal 1>/dev/null CMD_PERL='perl -I./Mail-IMAPClient-2.2.9' /usr/bin/time sh tests.sh locallocal 1>/dev/null
test_quick_3xx: $(TARGET) tests.sh test_quick_3xx: $(TARGET) tests.sh
CMD_PERL='perl -I./Mail-IMAPClient-3.21/lib' /usr/bin/time sh tests.sh locallocal 1>/dev/null CMD_PERL='perl -I./Mail-IMAPClient-3.23/lib' /usr/bin/time sh tests.sh locallocal 1>/dev/null
testv: testv:
nice -40 sh -x tests.sh nice -40 sh -x tests.sh

26
README
View file

@ -3,7 +3,7 @@ NAME
Synchronise mailboxes between two imap servers. Good at IMAP migration. Synchronise mailboxes between two imap servers. Good at IMAP migration.
More than 32 different IMAP server softwares supported with success. More than 32 different IMAP server softwares supported with success.
$Revision: 1.303 $ $Revision: 1.310 $
INSTALL INSTALL
imapsync works fine under any Unix OS with perl. imapsync works fine under any Unix OS with perl.
@ -24,8 +24,8 @@ INSTALL
Go into the directory imapsync-x.xx and read the INSTALL file. Go into the directory imapsync-x.xx and read the INSTALL file.
The INSTALL file is also at The INSTALL file is also at
http://www.linux-france.org/prj/imapsync/INSTALL (for windows users) http://www.linux-france.org/prj/imapsync/INSTALL (for windows users)
The freshmeat record is at http://freshmeat.net/projects/imapsync/ The freshmeat record is at http://freshmeat.net/projects/imapsync/
SYNOPSIS SYNOPSIS
imapsync [options] imapsync [options]
@ -74,7 +74,7 @@ SYNOPSIS
[--split1] [--split2] [--split1] [--split2]
[--reconnectretry1 <int>] [--reconnectretry2 <int>] [--reconnectretry1 <int>] [--reconnectretry2 <int>]
[--version] [--help] [--version] [--help]
DESCRIPTION DESCRIPTION
The command imapsync is a tool allowing incremental and recursive imap The command imapsync is a tool allowing incremental and recursive imap
transfer from one mailbox to another. transfer from one mailbox to another.
@ -209,6 +209,9 @@ BUGS and BUG REPORT
Help us to help you: follow the following guidelines. Help us to help you: follow the following guidelines.
Read the paper "How To Ask Questions The Smart Way"
http://www.catb.org/~esr/faqs/smart-questions.html
Before reporting bugs, read the FAQ, the README and the TODO files. Before reporting bugs, read the FAQ, the README and the TODO files.
http://www.linux-france.org/prj/imapsync/ http://www.linux-france.org/prj/imapsync/
@ -246,10 +249,10 @@ IMAP SERVERS
Success stories reported with the following 35 imap servers (software Success stories reported with the following 35 imap servers (software
names are in alphabetic order): names are in alphabetic order):
- Archiveopteryx 2.03, 2.04, 2.09, 2.10 [dest], 3.0.0 [dest] - Archiveopteryx 2.03, 2.04, 2.09, 2.10 [host2], 3.0.0 [host2]
(OSL 3.0) http://www.archiveopteryx.org/ (OSL 3.0) http://www.archiveopteryx.org/
- BincImap 1.2.3 (GPL) (http://www.bincimap.org/) - BincImap 1.2.3 (GPL) (http://www.bincimap.org/)
- CommuniGatePro server (Redhat 8.0) (Solaris) - CommuniGatePro server (Redhat 8.0) (Solaris), CommuniGate Pro 5.2.17[host2] (CentOS 5.4)
- Courier IMAP 1.5.1, 2.2.0, 2.1.1, 2.2.1, 3.0.8, 3.0.3, 4.1.1 (GPL) - Courier IMAP 1.5.1, 2.2.0, 2.1.1, 2.2.1, 3.0.8, 3.0.3, 4.1.1 (GPL)
(http://www.courier-mta.org/) (http://www.courier-mta.org/)
- Critical Path (7.0.020) - Critical Path (7.0.020)
@ -265,10 +268,10 @@ IMAP SERVERS
- David Tobit V8 (proprietary Message system). - David Tobit V8 (proprietary Message system).
- DBMail 1.2.1, 2.0.4, 2.0.9, 2.2rc1 (GPL) (http://www.dbmail.org/). - DBMail 1.2.1, 2.0.4, 2.0.9, 2.2rc1 (GPL) (http://www.dbmail.org/).
2.0.7 seems buggy. 2.0.7 seems buggy.
- Deerfield VisNetic MailServer 5.8.6 [from] - Deerfield VisNetic MailServer 5.8.6 [host1]
- Domino (Notes) 4.61[host1], 6.5, 5.0.6, 5.0.7, 7.0.2, 6.0.2CF1, 7.0.1[host1], 8.0.1[host1]
- Dovecot 0.99.10.4, 0.99.14, 0.99.14-8.fc4, 1.0-0.beta2.7, - Dovecot 0.99.10.4, 0.99.14, 0.99.14-8.fc4, 1.0-0.beta2.7,
1.0.0 [dest/source] (LGPL) (http://www.dovecot.org/) 1.0.0 [dest/source] (LGPL) (http://www.dovecot.org/)
- Domino (Notes) 4.61[from], 6.5, 5.0.6, 5.0.7, 7.0.2, 6.0.2CF1, 7.0.1 [from]
- Eudora WorldMail v2 - Eudora WorldMail v2
- GMX IMAP4 StreamProxy. - GMX IMAP4 StreamProxy.
- Groupwise IMAP (Novell) 6.x and 7.0. Buggy so see the FAQ. - Groupwise IMAP (Novell) 6.x and 7.0. Buggy so see the FAQ.
@ -276,7 +279,10 @@ IMAP SERVERS
- IMail 7.15 (Ipswitch/Win2003), 8.12 - IMail 7.15 (Ipswitch/Win2003), 8.12
- MDaemon 7.0.1, 8.0.2, 8.1, 9.5.4 (Windows server 2003 R2 platform) - MDaemon 7.0.1, 8.0.2, 8.1, 9.5.4 (Windows server 2003 R2 platform)
- Mercury 4.1 (Windows server 2000 platform) - Mercury 4.1 (Windows server 2000 platform)
- Microsoft Exchange Server 5.5, 6.0.6249.0[from], 6.0.6487.0[from], 6.5.7638.1 [dest] - Microsoft Exchange Server 5.5, 6.0.6249.0[host1], 6.0.6487.0[host1],
6.5.7638.1 [host2], Exchange 2007 SP1 (with Update Rollup 2),
Exchange2007-EP-SP2,
Exchange 2010 RTM (Release to Manufacturing) [host2]
- Netscape Mail Server 3.6 (Wintel !) - Netscape Mail Server 3.6 (Wintel !)
- Netscape Messaging Server 4.15 Patch 7 - Netscape Messaging Server 4.15 Patch 7
- OpenMail IMAP server B.07.00.k0 (Samsung Contact ?) - OpenMail IMAP server B.07.00.k0 (Samsung Contact ?)
@ -363,5 +369,5 @@ SIMILAR SOFTWARES
Feedback (good or bad) will always be welcome. Feedback (good or bad) will always be welcome.
$Id: imapsync,v 1.303 2010/01/20 04:12:52 gilles Exp gilles $ $Id: imapsync,v 1.310 2010/02/26 01:24:59 gilles Exp gilles $

7
TODO
View file

@ -1,5 +1,5 @@
#!/bin/cat #!/bin/cat
# $Id: TODO,v 1.72 2010/01/20 04:13:42 gilles Exp gilles $ # $Id: TODO,v 1.73 2010/02/07 22:03:06 gilles Exp gilles $
TODO file for imapsync TODO file for imapsync
---------------------- ----------------------
@ -13,6 +13,11 @@ Start a wiki for imapsync.
Add a best practice migration tips document. Add a best practice migration tips document.
Fix the mailing-list archive bug with From at
the beginning of a line
http://www.linux-france.org/prj/imapsync_list/msg00307.html
Add "output to reflect everything that imapsync was doing". Add "output to reflect everything that imapsync was doing".
Not everything but flag synchronization will be nice" Not everything but flag synchronization will be nice"

View file

@ -1 +1 @@
1.303 1.310

View file

@ -19,5 +19,5 @@ Fixed in Mail-IMAPClient-3.10/
Wrong. Lacks isUnconnected() method. Wrong. Lacks isUnconnected() method.
5) Mail-IMAPClient-3.19 is a good one. 5) Mail-IMAPClient-3.19 is a good one.
No known bug --expunge does not expunge anything

2
i3
View file

@ -1,4 +1,4 @@
#!/bin/sh #!/bin/sh
perl -IMail-IMAPClient-3.19/lib ./imapsync "$@" perl -IMail-IMAPClient-3.23/lib ./imapsync "$@"

336
imapsync
View file

@ -9,7 +9,7 @@ tool. Synchronise mailboxes between two imap servers. Good
at IMAP migration. More than 32 different IMAP server softwares at IMAP migration. More than 32 different IMAP server softwares
supported with success. supported with success.
$Revision: 1.303 $ $Revision: 1.310 $
=head1 INSTALL =head1 INSTALL
@ -243,6 +243,9 @@ or to the author.
Help us to help you: follow the following guidelines. Help us to help you: follow the following guidelines.
Read the paper "How To Ask Questions The Smart Way"
http://www.catb.org/~esr/faqs/smart-questions.html
Before reporting bugs, read the FAQ, the README and the Before reporting bugs, read the FAQ, the README and the
TODO files. http://www.linux-france.org/prj/imapsync/ TODO files. http://www.linux-france.org/prj/imapsync/
@ -281,10 +284,10 @@ Failure stories reported with the following 4 imap servers:
Success stories reported with the following 35 imap servers Success stories reported with the following 35 imap servers
(software names are in alphabetic order): (software names are in alphabetic order):
- Archiveopteryx 2.03, 2.04, 2.09, 2.10 [dest], 3.0.0 [dest] - Archiveopteryx 2.03, 2.04, 2.09, 2.10 [host2], 3.0.0 [host2]
(OSL 3.0) http://www.archiveopteryx.org/ (OSL 3.0) http://www.archiveopteryx.org/
- BincImap 1.2.3 (GPL) (http://www.bincimap.org/) - BincImap 1.2.3 (GPL) (http://www.bincimap.org/)
- CommuniGatePro server (Redhat 8.0) (Solaris) - CommuniGatePro server (Redhat 8.0) (Solaris), CommuniGate Pro 5.2.17[host2] (CentOS 5.4)
- Courier IMAP 1.5.1, 2.2.0, 2.1.1, 2.2.1, 3.0.8, 3.0.3, 4.1.1 (GPL) - Courier IMAP 1.5.1, 2.2.0, 2.1.1, 2.2.1, 3.0.8, 3.0.3, 4.1.1 (GPL)
(http://www.courier-mta.org/) (http://www.courier-mta.org/)
- Critical Path (7.0.020) - Critical Path (7.0.020)
@ -300,10 +303,10 @@ Success stories reported with the following 35 imap servers
- David Tobit V8 (proprietary Message system). - David Tobit V8 (proprietary Message system).
- DBMail 1.2.1, 2.0.4, 2.0.9, 2.2rc1 (GPL) (http://www.dbmail.org/). - DBMail 1.2.1, 2.0.4, 2.0.9, 2.2rc1 (GPL) (http://www.dbmail.org/).
2.0.7 seems buggy. 2.0.7 seems buggy.
- Deerfield VisNetic MailServer 5.8.6 [from] - Deerfield VisNetic MailServer 5.8.6 [host1]
- Domino (Notes) 4.61[host1], 6.5, 5.0.6, 5.0.7, 7.0.2, 6.0.2CF1, 7.0.1[host1], 8.0.1[host1]
- Dovecot 0.99.10.4, 0.99.14, 0.99.14-8.fc4, 1.0-0.beta2.7, - Dovecot 0.99.10.4, 0.99.14, 0.99.14-8.fc4, 1.0-0.beta2.7,
1.0.0 [dest/source] (LGPL) (http://www.dovecot.org/) 1.0.0 [dest/source] (LGPL) (http://www.dovecot.org/)
- Domino (Notes) 4.61[from], 6.5, 5.0.6, 5.0.7, 7.0.2, 6.0.2CF1, 7.0.1 [from]
- Eudora WorldMail v2 - Eudora WorldMail v2
- GMX IMAP4 StreamProxy. - GMX IMAP4 StreamProxy.
- Groupwise IMAP (Novell) 6.x and 7.0. Buggy so see the FAQ. - Groupwise IMAP (Novell) 6.x and 7.0. Buggy so see the FAQ.
@ -311,7 +314,10 @@ Success stories reported with the following 35 imap servers
- IMail 7.15 (Ipswitch/Win2003), 8.12 - IMail 7.15 (Ipswitch/Win2003), 8.12
- MDaemon 7.0.1, 8.0.2, 8.1, 9.5.4 (Windows server 2003 R2 platform) - MDaemon 7.0.1, 8.0.2, 8.1, 9.5.4 (Windows server 2003 R2 platform)
- Mercury 4.1 (Windows server 2000 platform) - Mercury 4.1 (Windows server 2000 platform)
- Microsoft Exchange Server 5.5, 6.0.6249.0[from], 6.0.6487.0[from], 6.5.7638.1 [dest] - Microsoft Exchange Server 5.5, 6.0.6249.0[host1], 6.0.6487.0[host1],
6.5.7638.1 [host2], Exchange 2007 SP1 (with Update Rollup 2),
Exchange2007-EP-SP2,
Exchange 2010 RTM (Release to Manufacturing) [host2]
- Netscape Mail Server 3.6 (Wintel !) - Netscape Mail Server 3.6 (Wintel !)
- Netscape Messaging Server 4.15 Patch 7 - Netscape Messaging Server 4.15 Patch 7
- OpenMail IMAP server B.07.00.k0 (Samsung Contact ?) - OpenMail IMAP server B.07.00.k0 (Samsung Contact ?)
@ -420,7 +426,7 @@ Entries for imapsync:
Feedback (good or bad) will always be welcome. Feedback (good or bad) will always be welcome.
$Id: imapsync,v 1.303 2010/01/20 04:12:52 gilles Exp gilles $ $Id: imapsync,v 1.310 2010/02/26 01:24:59 gilles Exp gilles $
=cut =cut
@ -473,6 +479,7 @@ my(
$mess_size_total_skipped, $mess_size_total_skipped,
$mess_size_total_error, $mess_size_total_error,
$mess_trans, $mess_skipped, $mess_skipped_dry, $mess_trans, $mess_skipped, $mess_skipped_dry,
$h1_mess_deleted, $h2_mess_deleted,
$timeout, # whr (ESS/PRW) $timeout, # whr (ESS/PRW)
$timestart, $timeend, $timediff, $timestart, $timeend, $timediff,
$timesize, $timebefore, $timesize, $timebefore,
@ -490,7 +497,7 @@ my(
use vars qw ($opt_G); # missing code for this will be option. use vars qw ($opt_G); # missing code for this will be option.
$rcs = '$Id: imapsync,v 1.303 2010/01/20 04:12:52 gilles Exp gilles $ '; $rcs = '$Id: imapsync,v 1.310 2010/02/26 01:24:59 gilles Exp gilles $ ';
$rcs =~ m/,v (\d+\.\d+)/; $rcs =~ m/,v (\d+\.\d+)/;
$VERSION = ($1) ? $1: "UNKNOWN"; $VERSION = ($1) ? $1: "UNKNOWN";
@ -500,6 +507,7 @@ $mess_size_total_trans = 0;
$mess_size_total_skipped = 0; $mess_size_total_skipped = 0;
$mess_size_total_error = 0; $mess_size_total_error = 0;
$mess_trans = $mess_skipped = $mess_skipped_dry = 0; $mess_trans = $mess_skipped = $mess_skipped_dry = 0;
$h1_mess_deleted = $h2_mess_deleted = 0;
@ -554,8 +562,8 @@ while (@argv_copy) {
my $banner = join("", my $banner = join("",
'$RCSfile: imapsync,v $ ', '$RCSfile: imapsync,v $ ',
'$Revision: 1.303 $ ', '$Revision: 1.310 $ ',
'$Date: 2010/01/20 04:12:52 $ ', '$Date: 2010/02/26 01:24:59 $ ',
"\n",localhost_info(), "\n",localhost_info(),
" and the module Mail::IMAPClient version used here is ", " and the module Mail::IMAPClient version used here is ",
$VERSION_IMAPClient,"\n", $VERSION_IMAPClient,"\n",
@ -638,8 +646,8 @@ sub localhost_info {
), ),
")\n", ")\n",
"with perl ", "with perl ",
sprintf("%vd", $PERL_VERSION), sprintf("%vd", $PERL_VERSION),"\n",
modules_VERSION() "Mail::IMAPClient $Mail::IMAPClient::VERSION",
); );
return($infos); return($infos);
@ -851,11 +859,8 @@ sub plainauth() {
sub server_banner { sub server_banner {
my $imap = shift; my $imap = shift;
for my $line ($imap->Results()) { my $banner = $imap->Banner() || "No banner\n";
#print "LR: $line"; return $banner;
return $line if $line =~ /^\* (OK|NO|BAD)/;
}
return "No banner\n";
} }
@ -1209,7 +1214,7 @@ sub foldersizes {
foreach my $h1_fold (@h1_folders) { foreach my $h1_fold (@h1_folders) {
my $h2_fold; my $h2_fold;
$h2_fold = to_folder_name($h1_fold); $h2_fold = imap2_folder_name($h1_fold);
$h2_folders{$h2_fold}++; $h2_folders{$h2_fold}++;
} }
@ -1266,23 +1271,60 @@ sub separator_invert {
return($h2_fold); return($h2_fold);
} }
sub to_folder_name {
sub tests_imap2_folder_name {
$h1_prefix = $h2_prefix = '';
$h1_sep = '/';
$h2_sep = '.';
$debug and print
"prefix1: [$h1_prefix]
prefix2: [$h2_prefix]
sep1:[$h1_sep]
sep2:[$h2_sep]
";
ok('' eq imap2_folder_name(''), 'imap2_folder_name: empty string');
ok('blabla' eq imap2_folder_name('blabla'), 'imap2_folder_name: blabla');
ok('spam.spam' eq imap2_folder_name('spam/spam'), 'imap2_folder_name: spam/spam');
ok('spam/spam' eq imap2_folder_name('spam.spam'), 'imap2_folder_name: spam.spam');
ok('spam.spam/spam' eq imap2_folder_name('spam/spam.spam'), 'imap2_folder_name: spam/spam.spam');
@regextrans2 = ('s,/,X,g');
ok('' eq imap2_folder_name(''), 'imap2_folder_name: empty string [s,/,X,g]');
ok('blabla' eq imap2_folder_name('blabla'), 'imap2_folder_name: blabla [s,/,X,g]');
ok('spam.spam' eq imap2_folder_name('spam/spam'), 'imap2_folder_name: spam/spam [s,/,X,g]');
ok('spamXspam' eq imap2_folder_name('spam.spam'), 'imap2_folder_name: spam.spam [s,/,X,g]');
ok('spam.spamXspam' eq imap2_folder_name('spam/spam.spam'), 'imap2_folder_name: spam/spam.spam [s,/,X,g]');
@regextrans2 = ('s, ,_,g');
ok('blabla' eq imap2_folder_name('blabla'), 'imap2_folder_name: blabla [s, ,_,g]');
ok('bla_bla' eq imap2_folder_name('bla bla'), 'imap2_folder_name: blabla [s, ,_,g]');
@regextrans2 = ('s,(.*),\U$1,');
ok('BLABLA' eq imap2_folder_name('blabla'), 'imap2_folder_name: blabla [s,\U(.*)\E,$1,]');
}
sub imap2_folder_name {
my ($h2_fold); my ($h2_fold);
my ($x_fold) = @_; my ($x_fold) = @_;
# first we remove the prefix # first we remove the prefix
$x_fold =~ s/^\Q$h1_prefix\E//; $x_fold =~ s/^\Q$h1_prefix\E//;
$debug and print "removed source prefix: [$x_fold]\n"; $debug and print "removed host1 prefix: [$x_fold]\n";
$h2_fold = separator_invert($x_fold,$h1_sep, $h2_sep); $h2_fold = separator_invert($x_fold,$h1_sep, $h2_sep);
$debug and print "inverted separators: [$h2_fold]\n"; $debug and print "inverted separators: [$h2_fold]\n";
# Adding the prefix supplied by namespace or the --prefix2 option # Adding the prefix supplied by namespace or the --prefix2 option
$h2_fold = $h2_prefix . $h2_fold $h2_fold = $h2_prefix . $h2_fold
unless(($h2_prefix eq "INBOX" . $h2_sep) and ($h2_fold =~ m/^INBOX$/i)); unless(($h2_prefix eq "INBOX" . $h2_sep) and ($h2_fold =~ m/^INBOX$/i));
$debug and print "added target prefix: [$h2_fold]\n"; $debug and print "added host2 prefix: [$h2_fold]\n";
# Transforming the folder name by the --regextrans2 option(s) # Transforming the folder name by the --regextrans2 option(s)
foreach my $regextrans2 (@regextrans2) { foreach my $regextrans2 (@regextrans2) {
$debug and print "eval \$h2_fold =~ $regextrans2\n"; my $h2_fold_before = $h2_fold;
eval("\$h2_fold =~ $regextrans2"); eval("\$h2_fold =~ $regextrans2");
$debug and print "[$h2_fold_before] -> [$h2_fold] using re [$regextrans2]\n";
die("error: eval regextrans2 '$regextrans2': $@\n") if $@; die("error: eval regextrans2 '$regextrans2': $@\n") if $@;
} }
return($h2_fold); return($h2_fold);
@ -1306,14 +1348,98 @@ sub tests_flags_regex {
@regexflag = ('s/(\s|^)[^\\\\]\w+//g'); @regexflag = ('s/(\s|^)[^\\\\]\w+//g');
ok('\Seen \Middle \End' eq flags_regex('\Seen NonJunk \Middle $Spam \End'), 'flags_regex, only \word [' . flags_regex('\Seen NonJunk \Middle $Spam \End'.']')); ok('\Seen \Middle \End' eq flags_regex('\Seen NonJunk \Middle $Spam \End'), 'flags_regex, only \word [' . flags_regex('\Seen NonJunk \Middle $Spam \End'.']'));
ok(' \Seen \Middle \End1' eq flags_regex('Begin \Seen NonJunk \Middle $Spam \End1 End'), 'flags_regex, only \word [' . flags_regex('Begin \Seen NonJunk \Middle $Spam \End1 End'.']')); ok(' \Seen \Middle \End1' eq flags_regex('Begin \Seen NonJunk \Middle $Spam \End1 End'), 'flags_regex, only \word [' . flags_regex('Begin \Seen NonJunk \Middle $Spam \End1 End'.']'));
@regexflag = ('s/.*?(Keep1|Keep2|Keep3)/$1 /g');
ok('Keep1 Keep2 ReB' eq flags_regex('ReA Keep1 REM Keep2 ReB'), "Keep only regex");
#ok('Keep1 Keep2' eq flags_regex('Keep1 Keep2 Remove1'), "Keep only regex");
ok('Keep1 Keep2 ' eq flags_regex('REM REM Keep1 Keep2'), "Keep only regex");
ok('Keep1 Keep2 ' eq flags_regex('Keep1 REM REM Keep2'), "Keep only regex");
ok('Keep1 Keep2 ' eq flags_regex('REM Keep1 REM REM Keep2'), "Keep only regex");
ok('Keep1 Keep2 ' eq flags_regex('Keep1 Keep2'), "Keep only regex");
ok('Keep1 ' eq flags_regex('REM Keep1'), "Keep only regex");
@regexflag = ('s/(Keep1|Keep2|Keep3) (?!(Keep1|Keep2|Keep3)).*/$1 /g');
ok('Keep1 Keep2 ' eq flags_regex('Keep1 Keep2 ReB'), "Keep only regex");
ok('Keep1 Keep2 ' eq flags_regex('Keep1 Keep2 REM REM REM'), "Keep only regex");
ok('Keep2 ' eq flags_regex('Keep2 REM REM REM'), "Keep only regex");
#ok('' eq flags_regex('REM REM'), "Keep only regex");
@regexflag = ('s/.*?(Keep1|Keep2|Keep3)/$1 /g',
's/(Keep1|Keep2|Keep3) (?!(Keep1|Keep2|Keep3)).*/$1 /g');
ok('Keep1 Keep2 ' eq flags_regex('REM Keep1 REM Keep2 REM'), "Keep only regex");
ok('Keep1 Keep2 ' eq flags_regex('Keep1 REM Keep2 REM'), "Keep only regex");
ok('Keep1 Keep2 ' eq flags_regex('REM Keep1 Keep2 REM'), "Keep only regex");
ok('Keep1 Keep2 ' eq flags_regex('REM Keep1 REM Keep2'), "Keep only regex");
ok('Keep1 Keep2 Keep3 ' eq flags_regex('REM Keep1 REM Keep2 REM REM Keep3 REM'), "Keep only regex");
ok('Keep1 ' eq flags_regex('REM REM Keep1 REM REM REM '), "Keep only regex");
ok('Keep1 Keep3 ' eq flags_regex('RE1 Keep1 RE2 Keep3 RE3 RE4 RE5 '), "Keep only regex");
@regexflag = ('s/(.*)/$1 jrdH8u/');
ok('REM REM REM REM REM jrdH8u' eq flags_regex('REM REM REM REM REM'), "Keep only regex 's/(.*)/\$1 jrdH8u/'");
@regexflag = ('s/jrdH8u *//');
ok('REM REM REM REM REM ' eq flags_regex('REM REM REM REM REM jrdH8u'), "Keep only regex s/jrdH8u *//");
@regexflag = (
's/(.*)/$1 jrdH8u/',
's/.*?(Keep1|Keep2|Keep3|jrdH8u)/$1 /g',
's/(Keep1|Keep2|Keep3|jrdH8u) (?!(Keep1|Keep2|Keep3|jrdH8u)).*/$1 /g',
's/jrdH8u *//'
);
ok('Keep1 Keep2 ' eq flags_regex('REM Keep1 REM Keep2 REM'), "Keep only regex 'REM Keep1 REM Keep2 REM'");
ok('Keep1 Keep2 ' eq flags_regex('Keep1 REM Keep2 REM'), "Keep only regex");
ok('Keep1 Keep2 ' eq flags_regex('REM Keep1 Keep2 REM'), "Keep only regex");
ok('Keep1 Keep2 ' eq flags_regex('REM Keep1 REM Keep2'), "Keep only regex");
ok('Keep1 Keep2 Keep3 ' eq flags_regex('REM Keep1 REM Keep2 REM REM Keep3 REM'), "Keep only regex");
ok('Keep1 ' eq flags_regex('REM REM Keep1 REM REM REM '), "Keep only regex");
ok('Keep1 Keep3 ' eq flags_regex('RE1 Keep1 RE2 Keep3 RE3 RE4 RE5 '), "Keep only regex");
ok('' eq flags_regex('REM REM REM REM REM'), "Keep only regex");
@regexflag = (
's/(.*)/$1 jrdH8u/',
's/.*?(\\\\Seen|\\\\Answered|\\\\Flagged|\\\\Deleted|\\\\Draft|jrdH8u)/$1 /g',
's/(\\\\Seen|\\\\Answered|\\\\Flagged|\\\\Deleted|\\\\Draft|jrdH8u) (?!(\\\\Seen|\\\\Answered|\\\\Flagged|\\\\Deleted|\\\\Draft|jrdH8u)).*/$1 /g',
's/jrdH8u *//'
);
ok('\\Deleted \\Answered '
eq flags_regex('Blabla $Junk \\Deleted machin \\Answered truc'), "Keep only regex: Exchange case");
ok('' eq flags_regex(''), "Keep only regex: Exchange case, null string");
ok(''
eq flags_regex('Blabla $Junk machin truc'), "Keep only regex: Exchange case, no accepted flags ");
ok('\\Deleted \\Answered \\Draft \\Flagged '
eq flags_regex('\\Deleted \\Answered \\Draft \\Flagged '), "Keep only regex: Exchange case");
@regexflag = (
's/.*?(?:(\\\\(?:Answered|Flagged|Deleted|Seen|Draft)\s?)|$)/defined($1)?$1:q()/eg'
);
ok('\\Deleted \\Answered '
eq flags_regex('Blabla \$Junk \\Deleted machin \\Answered truc'),
"Keep only regex: Exchange case (Phil)");
ok('' eq flags_regex(''), "Keep only regex: Exchange case, null string (Phil)");
ok(''
eq flags_regex('Blabla $Junk machin truc'),
"Keep only regex: Exchange case, no accepted flags (Phil)");
ok('\\Deleted \\Answered \\Draft \\Flagged '
eq flags_regex('\\Deleted \\Answered \\Draft \\Flagged '),
"Keep only regex: Exchange case (Phil)");
} }
sub flags_regex { sub flags_regex {
my ($h1_flags) = @_; my ($h1_flags) = @_;
foreach my $regexflag (@regexflag) { foreach my $regexflag (@regexflag) {
my $h1_flags_orig = $h1_flags;
$debug and print "eval \$h1_flags =~ $regexflag\n"; $debug and print "eval \$h1_flags =~ $regexflag\n";
eval("\$h1_flags =~ $regexflag"); eval("\$h1_flags =~ $regexflag");
die("error: eval regexflag '$regexflag': $@\n") if $@; die("error: eval regexflag '$regexflag': $@\n") if $@;
$debug and print "regexflag $regexflag [$h1_flags_orig] -> [$h1_flags]\n";
} }
return($h1_flags); return($h1_flags);
} }
@ -1402,7 +1528,7 @@ print "++++ Looping on each folder ++++\n";
FOLDER: foreach my $h1_fold (@h1_folders) { FOLDER: foreach my $h1_fold (@h1_folders) {
my $h2_fold; my $h2_fold;
print "Host1 Folder [$h1_fold]\n"; print "Host1 Folder [$h1_fold]\n";
$h2_fold = to_folder_name($h1_fold); $h2_fold = imap2_folder_name($h1_fold);
print "Host2 Folder [$h2_fold]\n"; print "Host2 Folder [$h2_fold]\n";
last FOLDER if $imap1->IsUnconnected(); last FOLDER if $imap1->IsUnconnected();
@ -1528,7 +1654,7 @@ FOLDER: foreach my $h1_fold (@h1_folders) {
if (!$rc) { if (!$rc) {
my $reason = !defined($rc) ? "no header" : "duplicate"; my $reason = !defined($rc) ? "no header" : "duplicate";
my $h2_size = $h2_fir->{$m}->{"RFC822.SIZE"} || 0; my $h2_size = $h2_fir->{$m}->{"RFC822.SIZE"} || 0;
print "+ Skipping msg #$m:$h2_size in 'to' folder $h2_fold ($reason so we ignore this message)\n"; print "+ Skipping msg #$m:$h2_size in host2 folder $h2_fold ($reason so we ignore this message)\n";
#$mess_size_total_skipped += $msize; #$mess_size_total_skipped += $msize;
#$mess_skipped += 1; #$mess_skipped += 1;
} }
@ -1555,11 +1681,12 @@ FOLDER: foreach my $h1_fold (@h1_folders) {
my $h2_msg = $h2_hash{$m_id}{'m'}; my $h2_msg = $h2_hash{$m_id}{'m'};
my $h2_flags = $h2_hash{$m_id}{'F'} || ""; my $h2_flags = $h2_hash{$m_id}{'F'} || "";
my $isdel = $h2_flags =~ /\B\\Deleted\b/ ? 1 : 0; my $isdel = $h2_flags =~ /\B\\Deleted\b/ ? 1 : 0;
print "deleting message $m_id $h2_msg\n" print "deleting message [$m_id] #$h2_msg in host2 folder $h2_fold\n"
if ! $isdel; if ! $isdel;
push(@expunge,$h2_msg) if $uidexpunge2; push(@expunge,$h2_msg) if $uidexpunge2;
unless ($dry or $isdel) { unless ($dry or $isdel) {
$imap2->delete_message($h2_msg); $imap2->delete_message($h2_msg);
$h2_mess_deleted += 1;
last FOLDER if $imap2->IsUnconnected(); last FOLDER if $imap2->IsUnconnected();
} }
} }
@ -1581,7 +1708,7 @@ FOLDER: foreach my $h1_fold (@h1_folders) {
my $h1_idate = $h1_hash{$m_id}{'D'}; my $h1_idate = $h1_hash{$m_id}{'D'};
if (defined $maxsize and $h1_size > $maxsize) { if (defined $maxsize and $h1_size > $maxsize) {
print "+ Skipping msg #$h1_msg:$h1_size in folder $h1_fold (exceeds maxsize limit $maxsize bytes)\n"; print "+ Skipping msg #$h1_msg:$h1_size in host1 folder $h1_fold (exceeds maxsize limit $maxsize bytes)\n";
$mess_size_total_skipped += $h1_size; $mess_size_total_skipped += $h1_size;
$mess_skipped += 1; $mess_skipped += 1;
next MESS; next MESS;
@ -1715,9 +1842,10 @@ FOLDER: foreach my $h1_fold (@h1_folders) {
$mess_size_total_trans += $h1_size; $mess_size_total_trans += $h1_size;
$mess_trans += 1; $mess_trans += 1;
if($delete) { if($delete) {
print "Deleting msg #$h1_msg in folder $h1_fold\n"; print "Deleting msg #$h1_msg in host1 folder $h1_fold\n";
unless($dry) { unless($dry) {
$imap1->delete_message($h1_msg); $imap1->delete_message($h1_msg);
$h1_mess_deleted += 1;
last FOLDER if $imap1->IsUnconnected(); last FOLDER if $imap1->IsUnconnected();
$imap1->expunge() if ($expunge); $imap1->expunge() if ($expunge);
last FOLDER if $imap1->IsUnconnected(); last FOLDER if $imap1->IsUnconnected();
@ -1800,7 +1928,7 @@ FOLDER: foreach my $h1_fold (@h1_folders) {
# NO recopy CODE HERE. to be written if needed. # NO recopy CODE HERE. to be written if needed.
$error++; $error++;
if ($opt_G){ if ($opt_G){
print "Deleting msg f:#$h2_msg in folder $h2_fold\n"; print "Deleting msg f:#$h2_msg in host2 folder $h2_fold\n";
$imap2->delete_message($h2_msg) unless ($dry); $imap2->delete_message($h2_msg) unless ($dry);
last FOLDER if $imap2->IsUnconnected(); last FOLDER if $imap2->IsUnconnected();
} }
@ -1810,9 +1938,10 @@ FOLDER: foreach my $h1_fold (@h1_folders) {
$debug and print $debug and print
"Message $m_id SZ_GOOD f:$h1_msg:$h1_size t:$h2_msg:$h2_size\n"; "Message $m_id SZ_GOOD f:$h1_msg:$h1_size t:$h2_msg:$h2_size\n";
if($delete) { if($delete) {
print "Deleting msg #$h1_msg in folder $h1_fold\n"; print "Deleting msg #$h1_msg in host1 folder $h1_fold\n";
unless($dry) { unless($dry) {
$imap1->delete_message($h1_msg); $imap1->delete_message($h1_msg);
$h1_mess_deleted += 1;
last FOLDER if $imap1->IsUnconnected(); last FOLDER if $imap1->IsUnconnected();
$imap1->expunge() if ($expunge); $imap1->expunge() if ($expunge);
last FOLDER if $imap1->IsUnconnected(); last FOLDER if $imap1->IsUnconnected();
@ -1821,11 +1950,11 @@ FOLDER: foreach my $h1_fold (@h1_folders) {
} }
} }
if ($expunge1){ if ($expunge1){
print "Expunging source folder $h1_fold\n"; print "Expunging host1 folder $h1_fold\n";
unless($dry) { $imap1->expunge() }; unless($dry) { $imap1->expunge() };
} }
if ($expunge2){ if ($expunge2){
print "Expunging target folder $h2_fold\n"; print "Expunging host2 folder $h2_fold\n";
unless($dry) { $imap2->expunge() }; unless($dry) { $imap2->expunge() };
} }
@ -1914,17 +2043,21 @@ sub select_msgs {
} }
sub stats { sub stats {
print "++++ Statistics ++++\n"; print "++++ Statistics ++++\n";
print "Time : $timediff sec\n"; print "Time : $timediff sec\n";
print "Messages transferred : $mess_trans "; print "Messages transferred : $mess_trans ";
print "(could be $mess_skipped_dry without dry mode)" if ($dry); print "(could be $mess_skipped_dry without dry mode)" if ($dry);
print "\n"; print "\n";
print "Messages skipped : $mess_skipped\n"; print "Messages skipped : $mess_skipped\n";
print "Total bytes transferred: $mess_size_total_trans\n"; print "Messages deleted on host1: $h1_mess_deleted\n";
print "Total bytes skipped : $mess_size_total_skipped\n"; print "Messages deleted on host2: $h2_mess_deleted\n";
print "Total bytes error : $mess_size_total_error\n"; print "Total bytes transferred : $mess_size_total_trans\n";
print "Detected $error errors\n\n"; print "Total bytes skipped : $mess_size_total_skipped\n";
print thank_author(); print "Total bytes error : $mess_size_total_error\n";
$timediff ||= 1; # No division per 0
printf ("Average bandwith rate : %.1f Ko/s\n", $mess_size_total_trans / 1024 / $timediff);
print "Detected $error errors\n\n";
print thank_author();
} }
sub thank_author { sub thank_author {
@ -2327,6 +2460,7 @@ sub tests {
tests_flags_regex(); tests_flags_regex();
tests_permanentflags(); tests_permanentflags();
tests_flags_filter(); tests_flags_filter();
tests_imap2_folder_name();
} }
} }
@ -2869,18 +3003,21 @@ use constant NonFolderArg => 1; # Value to pass to Massage to
# BUG? should probably return undef if length != expected # BUG? should probably return undef if length != expected
# No bug, somme servers are buggy. # No bug, somme servers are buggy.
if ( length($string) != $expected_size ) { if (! $self->Ignoresizeerrors ) {
warn "message_string: " . if ( length($string) != $expected_size ) {
"expected $expected_size bytes but received " . warn "message_string: " .
length($string) . "\n"; "expected $expected_size bytes but received " .
$self->LastError("message_string: expected ". length($string) . "\n";
"$expected_size bytes but received " . $self->LastError("message_string: expected ".
length($string)."\n"); "$expected_size bytes but received " .
} length($string)."\n");
}
}
return $string; return $string;
}; };
{ {
no warnings 'once'; no warnings 'once';
@ -2899,6 +3036,16 @@ no warnings 'once';
return $self->{AUTHUSER}; return $self->{AUTHUSER};
}; };
*Mail::IMAPClient::Ignoresizeerrors = sub {
my $self = shift;
if (@_) { $self->{IGNORESIZEERRORS} = shift }
return $self->{IGNORESIZEERRORS};
};
} }
# End of sub override_imapclient (yes, very bad indentation) # End of sub override_imapclient (yes, very bad indentation)
@ -2928,32 +3075,24 @@ sub myconnect {
unless defined wantarray; unless defined wantarray;
return undef; return undef;
} }
$sock->autoflush(1);
my $banner = $sock->getline();
$debug and print "Read: $banner";
$self->Banner($banner);
$self->RawSocket2($sock);
$self->State(Connected);
if ($self->Tls) { if ($self->Tls) {
$debug and print "Calling starttls\n"; $debug and print "Calling starttls\n";
$sock->autoflush(1);
my $banner = starttls($sock); my $banner = starttls($self);
$debug and print "End starttls: $banner\n"; $debug and print "End starttls: $banner\n";
$self->State(Mail::IMAPClient::Connected);
} }
$debug and print "Calling Socket\n"; $self->Ignoresizeerrors($allowsizemismatch);
if ($Mail::IMAPClient::VERSION =~ /^3/ and $self->Tls) {
$self->RawSocket($sock);
}else{
$self->Socket($sock);
}
if ( $Mail::IMAPClient::VERSION =~ /^2/ ) {
$debug and print "Calling myconnect_v2\n";
return undef unless myconnect_v2($self);
$debug and print "End myconnect_v2\n";
}
else {
$self->Ignoresizeerrors($allowsizemismatch);
}
if ($self->User and $self->Password) { if ($self->User and $self->Password) {
$debug and print "Calling login\n"; $debug and print "Calling login\n";
return $self->login ; return $self->login ;
@ -2964,45 +3103,23 @@ sub myconnect {
} }
sub myconnect_v2 {
my $self = shift;
return $self if $self->Tls;
$self->State(Connected);
$self->Socket->autoflush(1);
my ($code, $output);
$output = "";
until ( $code ) {
$output = $self->_read_line or return undef;
for my $o (@$output) {
$self->_debug("Connect: Received this from readline: " .
join("/",@$o) . "\n");
$self->_record($self->Count,$o); # $o is a ref
next unless $o->[TYPE] eq "OUTPUT";
($code) = $o->[DATA] =~ /^\*\s+(OK|BAD|NO)/i ;
}
}
if ($code =~ /BYE|NO /) {
$self->State(Unconnected);
return undef ;
}
return $self;
}
sub starttls { sub starttls {
my $socket = shift; my $self = shift;
my $socket = $self->RawSocket2();
$debug and print "Entering starttls\n"; $debug and print "Entering starttls\n";
my $banner = $socket->getline(); my $banner = $self->Banner();
$debug and print $banner;
unless ($banner =~ /^\* OK \[CAPABILITY.*STARTTLS.*\]/) { unless ($banner =~ /^\* OK \[CAPABILITY.*STARTTLS.*\]/) {
die "No STARTTLS capability: $banner"; die "No STARTTLS capability: $banner";
} }
print $socket "STARTTLS\015\012"; print $socket, "\n";
print $socket "z00 STARTTLS\015\012";
my $txt = $socket->getline(); my $txt = $socket->getline();
$debug and print "$txt"; $debug and print "Read: $txt";
unless($txt =~ /^STARTTLS OK/){ unless($txt =~ /^z00 OK/){
die "Invalid response for STARTTLS: $txt\n"; die "Invalid response for STARTTLS: $txt\n";
} }
$debug and print "Calling start_SSL\n"; $debug and print "Calling start_SSL\n";
@ -3042,3 +3159,22 @@ sub Tls {
return $self->{TLS}; return $self->{TLS};
} }
sub Banner {
my $self = shift;
if (@_) { $self->{BANNER} = shift }
return $self->{BANNER};
}
sub RawSocket2 {
my ( $self, $sock ) = @_;
defined $sock
or return $self->{Socket};
$self->{Socket} = $sock;
$self->{_select} = IO::Select->new($sock);
delete $self->{_fcntl};
#$self->Fast_io( $self->Fast_io );
$sock;
}

529
patches/FAQ_ralph.patch Normal file
View file

@ -0,0 +1,529 @@
--- FAQ.orig 2009-04-30 04:09:14.000000000 +0200
+++ FAQ 2010-02-02 08:53:04.000000000 +0100
@@ -6,12 +6,12 @@
+------------------+
=======================================================================
-Q. How to install impasync ?
+Q. How to install imapsync ?
R. http://www.linux-france.org/prj/imapsync/INSTALL
=======================================================================
-Q. How to configure impasync ?
+Q. How to configure imapsync ?
R. http://www.linux-france.org/prj/imapsync/README
@@ -46,7 +46,7 @@
Thank you for your participation.
=======================================================================
-Q. Where I can read IMAP RFCs ?
+Q. Where I can read up on the various IMAP RFCs ?
R. Here:
@@ -67,12 +67,12 @@
=======================================================================
-Q. Where I can find old imapsync releases ?
+Q. Where I can find old imapsync releases?
R. ftp://www.linux-france.org/pub/prj/imapsync/
=======================================================================
-Q. How can I try imapsync with Mail::IMAPClient 3.xx perl library?
+Q. How can I try imapsync with the new Mail::IMAPClient 3.xx perl library?
R. - Download latest Mail::IMAPClient 3.xx at
http://search.cpan.org/dist/Mail-IMAPClient/
@@ -105,8 +105,8 @@
=======================================================================
Q. I am interested in creating a local clone of the IMAP on a LAN
server for faster synchronisations, Email will always be delivered
-to the remote server and so the synchronisation will be one way from
-remote to local. How suited is ImapSync to continouous one-way
+to the remote server and so the synchronisation will be one way - from
+remote to local. How suited is ImapSync for continuous one-way
synchronisation of mailboxes? Is there a better solution?
R. If messages are delivered remotely and you play locally with the
@@ -130,17 +130,16 @@
- Mutt
- Thunderbird
-Eurora shows by default the time the imap server received the email.
-I think it is quite a wrong behavior since the messages can
-have travelled some time before the reception.
-
-The sent time and date are given by the "Date:" header
-and it is set most of the time by the MUA (Mail User Agent,
-Mutt, Eudora, Thunderbird etc.).
-
-imapsync does not touch any header since the
-header is used to identify the messages in
-both parts.
+Eurora shows by default the time the imap server received the email. I
+think it is quite a wrong behavior since the messages can have
+travelled some time before the reception.
+
+The sent time and date are given by the "Date:" header and it is set
+most of the time by the MUA (Mail User Agent, Mutt, Eudora,
+Thunderbird etc.).
+
+imapsync does not touch any header since the header is used to
+identify the messages in both parts.
Solutions:
a) Don't use buggy Eudora.
@@ -156,7 +155,7 @@
=======================================================================
Q. Does imapsync retain the \Answered and $Forwarded flags?
-R. imapsync retains all flags except \Recent
+R. imapsync retains ALL flags except \Recent
(RFC 3501 says "This flag can not be altered by the client.")
Some imap servers have problems with flags not beginning with
@@ -195,11 +194,11 @@
=======================================================================
Q. Some passwords contain * and " characters. Login fails.
-R. Use
+R. Use a backslash to escape the characters:
imapsync --password1 \"password\"
-Ii works for the star * character,
+It works for the star * character,
I don't know if it works for the " character.
=======================================================================
@@ -273,46 +272,43 @@
imaps stream tcp nowait cyrus /usr/sbin/stunnel -s cyrus -p /etc/ssl/certs/imapd.pem -r localhost:imap2
=======================================================================
-Q: I'm trying to use imapsync on win32 for gmail, but it requires ssl,
-or at least claims to. Imapsync appears to require io-socket-ssl,
-which doesn't seem to be available on win32. Are there any other options?
+Q: I'm trying to use imapsync on win32 for gmail, but it requires ssl,
+or at least claims to. Imapsync appears to require io-socket-ssl,
+which doesn't seem to be available on win32. Are there any other
+options?
R: (Q and R come as is from Bryce Walter)
-I think I'm having success using cygwin perl instead of
-ActiveState Perl. I wasn't able to get CPAN working and
-building IO::Socket::SSL in ActiveState, but cygwin did
-all right. I had to force the install of the Net::SSLeay
-dependency, because it partially failed one test, but I think
-it worked anyway. In order to get working in cygwin, I
-installed the entire "perl" category, lynx, ncftp, and lftp
-(specified as ftp program in cpan setup). I'm not sure if I
-needed all those, or if cpan just kept asking because I didn't
-have any installed at the time. Anyway, cpan worked, and
-I installed all dependencies that imapsync complained
-about until it started working.
+
+I think I'm having success using cygwin perl instead of ActiveState
+Perl. I wasn't able to get CPAN working and building IO::Socket::SSL
+in ActiveState, but cygwin did all right. I had to force the install
+of the Net::SSLeay dependency, because it partially failed one test,
+but I think it worked anyway. In order to get working in cygwin, I
+installed the entire "perl" category, lynx, ncftp, and lftp (specified
+as ftp program in cpan setup). I'm not sure if I needed all those, or
+if cpan just kept asking because I didn't have any installed at the
+time. Anyway, cpan worked, and I installed all dependencies that
+imapsync complained about until it started working.
=======================================================================
Q: Multiple copies when I run imapsync twice ore more.
-R. Multiple copies of the emails on the destination
-server. Some IMAP servers (Domino for example) add some
-headers for each message transfered. The message is
-transfered again and again each time you run imapsync. This
-is bad of course. The explanation is that imapsync considers
-the message is not the same since headers have changed (one
+R. Multiple copies of the emails on the destination server. Some IMAP
+servers (Domino for example) add some headers for each message
+transfered. The message is transfered again and again each time you
+run imapsync. This is bad of course. The explanation is that imapsync
+considers the message is not the same since headers have changed (one
line added) and size too (the header part).
-You can look at the headers found by imapsync by using the
---debug option (and search for the message on both part),
-Header lines from the source server begin with a "FH:" prefix,
-Header lines from the destination server begin with a "TH:" prefix.
-Since --debug is very verbose I suggest to isolate a
-email in a specific folder in case you want to forward
-me the output.
+You can look at the headers found by imapsync by using the --debug
+option (and search for the message on both part), Header lines from
+the source server begin with a "FH:" prefix, Header lines from the
+destination server begin with a "TH:" prefix. Since --debug is very
+verbose I suggest to isolate a email in a specific folder in case you
+want to forward me the output.
The way to avoid this problem is by using options --skipheader and
---skipsize, like this (avoid headers beginning whith the
-string "X-"):
+--skipsize, like this (avoid headers beginning whith the string "X-"):
imapsync ... --skipheader '^X-' --skipsize
@@ -325,11 +321,11 @@
imapsync ... --useheader 'Message-ID' --skipsize
Remark. (Trick found by Tomasz Kaczmarski)
-Option --useheader 'Message-ID' asks the server
-to send only header lines begining with 'Message-ID'.
-Some (buggy) servers send the whole header (all lines)
-instead of the 'Message-ID' line. In that case, a trick
-to keep the --useheader filtering behavior is to use
+
+Option --useheader 'Message-ID' asks the server to send only header
+lines begining with 'Message-ID'. Some (buggy) servers send the whole
+header (all lines) instead of the 'Message-ID' line. In that case, a
+trick to keep the --useheader filtering behavior is to use
--skipheader with a negative lookahead pattern :
imapsync ... --skipheader '^(?!Message-ID)' --skipsize
@@ -357,14 +353,14 @@
or maybe
--exclude '^"public\.'
-In the example given the character "." is the folder separator,
-you can ommit it. Just take the string as it appears on the
-imapsync output line :
+In the example given the character "." is the folder separator, you
+can ommit it. Just take the string as it appears on the imapsync
+output line :
From folders list : [INBOX] [public.dreams] [etc.]
======================================================================
-Q. I want the --folder 'MyFolder' option be recurse.
+Q. I want the --folder 'MyFolder' option be recursive.
R. Do not use the --folder option.
Instead, use --include '^MyFolder'
@@ -412,17 +408,17 @@
--exclude '^user\.'
======================================================================
-Q. Is anyway imapsync to purge destionation folder when the source
- folder is deleted?
+Q. Is there anyway of making imapsync purge the destination folder
+ when the source folder is deleted?
+
+R. No, that's too dangerous.
-R. No, that's too much dangerous.
-But if the source folder is empty (not deleted) and
-options --delete2 --expunge2 are used then
-the destination folder will be empty.
+But if the source folder is empty (not deleted) and options --delete2
+--expunge2 are used then the destination folder will be empty.
======================================================================
Q. Is it possible to synchronize all messages from one server to
-another whithout recreating the folder structure and the target server.
+another without recreating the folder structure and the target server.
R. Yes.
1) First try (safe mode):
@@ -437,15 +433,15 @@
3) Remove --dry
Check the imap folder tree on the target side, you should
- only have one : the classical INBOX.
+ only have one: the classical INBOX.
4) Remove --justfolders
======================================================================
-Q. I have moved from Braunschweig to Graz, so I would like to have my whole
-Braunschweig mail sorted into a folder INBOX.Braunschweig of my new mail
-account.
+Q. I have moved from Braunschweig to Graz, so I would like to have my
+ whole Braunschweig mail sorted into a folder INBOX.Braunschweig of my
+ new mail account.
R.
1) First try (safe mode):
@@ -468,30 +464,29 @@
R. Examples:
-0) First try with --dry --justfolders options since imapsync shows the
-transformations it will do without really doing them. Then when happy
-with the output remove the --dry --justfolders options.
+0) First try with --dry --justfolders options since imapsync shows the
+ transformations it will do without really doing them. Then when
+ happy with the output remove the --dry --justfolders options.
1) To remove INBOX. in the name of destination folders:
--regextrans2 's/^INBOX\.(.+)/$1/'
2) To sync a complete account in a subfolder called FOO:
- a) Separator is dot character "." and "INBOX" prefixes every folder
+ a) Seperator is dot character "." and "INBOX" prefixes every folder
--regextrans2 's/^INBOX(.*)/INBOX.FOO$1/'
Or
- b) Separator is slash character "/"
+ b) Seperator is slash character "/"
--regextrans2 's#(.*)#FOO/$1#'
3) to substitute all characters dot "." by underscores "_"
--regextrans2 's/\./_/g'
=======================================================================
-Q. I would like to move emails from InBox to a sub-folder
-called , say "2005-InBox" based on the date (Like all emails
-received in the Year 2005 should be moved to the folder
-called "2005-InBox").
+Q. I would like to move emails from InBox to a sub-folder called,
+ say "2005-InBox" based on the date (Like all emails received in the
+ Year 2005 should be moved to the folder called "2005-InBox").
R. 2 ways :
@@ -499,17 +494,18 @@
------------
1) You create a folder INBOX.2005-INBOX
-2) Mostly every email software allow sorting by date.
-In inbox, you select from 1 january to 31 december
-messages with the shift key.
+
+2) Mostly every email software allow sorting by date. In inbox, you
+ select from 1 january to 31 december messages with the shift key.
+ (in mutt, use ~d)
+
3) Cut/paste in INBOX.2005-INBOX
b) With imapsync:
-----------------
-You have to calculate the day of year (and
-add 365). For example, running it today,
-Sat Mar 11 13:06:01 CET 2006:
+You have to calculate the day of year (and add 365). For example,
+running it today, Sat Mar 11 13:06:01 CET 2006:
imapsync ...
--host1 imap.truc.org --host2 imap.trac.org \
@@ -528,9 +524,9 @@
$ date +%j
070
-Also, you must take imapsync 1.159 at least since I tested
-what I just wrote above and found 2 bugs about --mindate
---maxdate options behavior.
+Also, you must take imapsync 1.159 at least since I tested what I just
+wrote above and found 2 bugs about --mindate --maxdate options
+behavior.
=======================================================================
Q. I want to play with headers line and --regexmess but I want to leave
@@ -573,42 +569,39 @@
Return-Path: <foo@yoyo.org>
Received: ...
-Any Maidir/ configured imap server may refuse this message
-since its header is invalid. The first "From " line is not
-valid. It lacks a colon character ":".
-To solve this problem you have several solutions a) or b):
-
-a) Remove these first "From " line manually for each message
-before using imapsync. Don't think to add a colon to this
-line since you will end with two "From:" lines (just look at
-the other lines)
+Any Maildir/ configured imap server may refuse this message since its
+header is invalid. The first "From " line is not valid. It lacks a
+colon character ":". To solve this problem you have several solutions
+
+a) Remove these first "From " line manually for each message before
+ using imapsync. Don't think to add a colon to this line since you
+ will end with two "From:" lines (just look at the other lines)
b) Run imapsync with the following options :
---regexmess 's/\AFrom \w .*\n//' --skipsize
+ --regexmess 's/\AFrom \w .*\n//' --skipsize
=======================================================================
Q. The contact folder isn't well copied.
- How to copy the contact folder ?
+ How to copy the contact folder?
-R. Forget the destination server (chose the same)
+R. Forget the destination server (choose the same)
Change the script around line 1426
# ITSD
$new_id = $from->copy($t_fold,$f_msg);
#$new_id = $to->append_string($t_fold,$string, $flags_f, $d);
-and tried a copy of the mail instead an append_string.
-Because we are 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)
+
+and tried a copy of the mail instead an append_string. Because we are
+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)
=======================================================================
-Q. Synchronysing from XXX to Gmail
+Q. Synchronising 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 Gmail's structure:
+R. There are some details to get the special [Gmail] sub-folders
+ right. Here's an example of migrating an old "Sent" folder to
+ Gmail's structure:
imapsync --syncinternaldates \
--host1 mail.oldhost.com \
@@ -625,9 +618,9 @@
The same goes for the "All Mail" archive psuedo-folder.
=======================================================================
-Q. Synchronysing from Gmail to XXX
+Q. Synchronising from Gmail to XXX
-R. Gmail needs ssl.
+R. Gmail needs SSL
./imapsync \
--host1 imap.gmail.com --ssl1 \
@@ -661,6 +654,7 @@
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
@@ -679,9 +673,9 @@
imapsync ... --folder Alexander
=======================================================================
-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?
+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?
R. Use
imapsync ... --include '^mail'
@@ -690,12 +684,11 @@
=======================================================================
-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.
+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
@@ -719,30 +712,32 @@
--skipheader '^Content-Type'
- MIME separator IDs seem to change every time a mail is accessed so
-this is required to stop duplicates.
+ 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.
+ 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).
+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.
+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 abends when I pushed it a bit hard! I eventually had to
+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.
@@ -816,18 +811,19 @@
--sep1 '/' --exclude 'user/demo/Trash' \
--regextrans2 's/^user.//' --syncinternaldates
-The 'exclude user/demo/Trash' was used because there was one message
-there with 8 bit headers which dbmail doesn't accept, so I had to skip
-the whole folder. It would be nice to have an option to just ignore and
-log unsyncable messages, but do the rest, instead of stopping.
+The 'exclude user/demo/Trash' was used because there was one message
+there with 8 bit headers which dbmail doesn't accept, so I had to skip
+the whole folder. It would be nice to have an option to just ignore
+and log unsyncable messages, but do the rest, instead of stopping.
******************
There are two other major problems:
-1) dbmail doesn't accept utf8 header, while cyrus does. imapsync stops
+
+1) dbmail doesn't accept utf8 header, while cyrus does. imapsync stops
in that case, making sync impossible
-To convert the wholes messages from 8bit to 7bit, use option :
+To convert the whole messages from 8bit to 7bit, use option :
--regexmess 's/[\x80-\xff]/X/g'
@@ -861,7 +857,7 @@
Q. From any to Exchange2007
Several problems:
-- Big messages: increse the "send- and receive-connector"
+- Big messages: increase the "send- and receive-connector"
in exchange2007 to 40 MB.
R. 2 solutions

View file

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# $Id: tests.sh,v 1.98 2010/01/20 04:13:59 gilles Exp gilles $ # $Id: tests.sh,v 1.101 2010/02/25 23:16:45 gilles Exp gilles $
# Example: # Example:
# CMD_PERL='perl -I./Mail-IMAPClient-3.14/lib' sh -x tests.sh # CMD_PERL='perl -I./Mail-IMAPClient-3.14/lib' sh -x tests.sh
@ -370,7 +370,7 @@ ll_authmd5()
--passfile1 ../../var/pass/secret.tata \ --passfile1 ../../var/pass/secret.tata \
--host2 $HOST2 --user2 titi \ --host2 $HOST2 --user2 titi \
--passfile2 ../../var/pass/secret.titi \ --passfile2 ../../var/pass/secret.titi \
--justfoldersizes --authmd5 \ --justlogin --authmd5 \
--allow3xx --allow3xx
} }
@ -509,10 +509,46 @@ ll_regextrans2()
--passfile1 ../../var/pass/secret.tata \ --passfile1 ../../var/pass/secret.tata \
--host2 $HOST2 --user2 titi \ --host2 $HOST2 --user2 titi \
--passfile2 ../../var/pass/secret.titi \ --passfile2 ../../var/pass/secret.titi \
--regextrans2 's/yop/yopX/' \ --justfolders \
--allow3xx --nofoldersize \
--regextrans2 's/yop/yoX/' \
--folder 'INBOX.yop.yap'
} }
ll_regextrans2_slash()
{
$CMD_PERL ./imapsync \
--host1 $HOST1 --user1 tata \
--passfile1 ../../var/pass/secret.tata \
--host2 $HOST2 --user2 titi \
--passfile2 ../../var/pass/secret.titi \
--justfolders \
--nofoldersize \
--folder 'INBOX.yop.yap' \
--sep1 '/' \
--regextrans2 's,/,_,'
}
ll_regextrans2_remove_space()
{
$CMD_PERL ./imapsync \
--host1 $HOST1 --user1 tata \
--passfile1 ../../var/pass/secret.tata \
--host2 $HOST2 --user2 titi \
--passfile2 ../../var/pass/secret.titi \
--justfolders \
--nofoldersize \
--folder 'INBOX.yop.y p' \
--regextrans2 's, ,,' \
--dry
}
ll_sep2() ll_sep2()
{ {
$CMD_PERL ./imapsync \ $CMD_PERL ./imapsync \
@ -679,6 +715,23 @@ ll_regex_flag3()
echo 'rm -f /home/vmail/titi/.yop.yap/cur/*' echo 'rm -f /home/vmail/titi/.yop.yap/cur/*'
} }
ll_regex_flag_keep_only()
{
$CMD_PERL ./imapsync \
--host1 $HOST1 --user1 tata \
--passfile1 ../../var/pass/secret.tata \
--host2 $HOST2 --user2 titi \
--passfile2 ../../var/pass/secret.titi \
--folder INBOX.yop.yap \
--debug \
--regexflag 's/(.*)/$1 jrdH8u/' \
--regexflag 's/.*?(\\Seen|\\Answered|\\Flagged|\\Deleted|\\Draft|jrdH8u)/$1 /g' \
--regexflag 's/(\\Seen|\\Answered|\\Flagged|\\Deleted|\\Draft|jrdH8u) (?!(\\Seen|\\Answered|\\Flagged|\\Deleted|\\Draft|jrdH8u)).*/$1 /g' \
--regexflag 's/jrdH8u *//'
echo 'rm -f /home/vmail/titi/.yop.yap/cur/*'
}
ll_tls_justconnect() { ll_tls_justconnect() {
$CMD_PERL ./imapsync \ $CMD_PERL ./imapsync \
@ -702,9 +755,9 @@ ll_tls_justlogin() {
ll_tls_devel() { ll_tls_devel() {
CMD_PERL='perl -I./Mail-IMAPClient-2.2.9' ll_justlogin ll_ssl_justlogin \ CMD_PERL='perl -I./Mail-IMAPClient-2.2.9' ll_justlogin ll_ssl_justlogin \
&& CMD_PERL='perl -I./Mail-IMAPClient-3.19/lib' ll_justlogin ll_ssl_justlogin \ && CMD_PERL='perl -I./Mail-IMAPClient-3.23/lib' ll_justlogin ll_ssl_justlogin \
&& CMD_PERL='perl -I./Mail-IMAPClient-2.2.9' ll_tls_justconnect ll_tls_justlogin \ && CMD_PERL='perl -I./Mail-IMAPClient-2.2.9' ll_tls_justconnect ll_tls_justlogin \
&& CMD_PERL='perl -I./Mail-IMAPClient-3.19/lib' ll_tls_justconnect ll_tls_justlogin && CMD_PERL='perl -I./Mail-IMAPClient-3.23/lib' ll_tls_justconnect ll_tls_justlogin
} }
ll_tls() { ll_tls() {
@ -805,7 +858,6 @@ ll_authmech_CRAMMD5() {
ll_delete2() { ll_delete2() {
if can_send; then if can_send; then
#echo3 Here is plume
sendtestmessage titi sendtestmessage titi
else else
: :
@ -816,10 +868,25 @@ ll_delete2() {
--host2 $HOST2 --user2 titi \ --host2 $HOST2 --user2 titi \
--passfile2 ../../var/pass/secret.titi \ --passfile2 ../../var/pass/secret.titi \
--folder INBOX \ --folder INBOX \
--delete2 --expunge2 \ --delete2 --expunge2
--allow3xx
} }
ll_delete() {
if can_send; then
sendtestmessage titi
else
:
fi
$CMD_PERL ./imapsync \
--host1 $HOST1 --user1 titi \
--passfile1 ../../var/pass/secret.titi \
--host2 $HOST2 --user2 tata \
--passfile2 ../../var/pass/secret.tata \
--folder INBOX \
--delete --expunge
}
ll_bigmail() { ll_bigmail() {
$CMD_PERL ./imapsync \ $CMD_PERL ./imapsync \
--host1 $HOST1 --user1 tata \ --host1 $HOST1 --user1 tata \
@ -903,21 +970,21 @@ gmail_gmail2() {
allow3xx() { allow3xx() {
perl -I./Mail-IMAPClient-3.19/lib ./imapsync \ $CMD_PERL ./imapsync \
--host1 $HOST1 --user1 tata \ --host1 $HOST1 --user1 tata \
--passfile1 ../../var/pass/secret.tata \ --passfile1 ../../var/pass/secret.tata \
--host2 $HOST2 --user2 titi \ --host2 $HOST2 --user2 titi \
--passfile2 ../../var/pass/secret.titi \ --passfile2 ../../var/pass/secret.titi \
--allow3xx --allow3xx --justlogin
} }
noallow3xx() { noallow3xx() {
! perl -I./Mail-IMAPClient-3.19/lib ./imapsync \ ! perl -I./Mail-IMAPClient-3.23/lib ./imapsync \
--host1 $HOST1 --user1 tata \ --host1 $HOST1 --user1 tata \
--passfile1 ../../var/pass/secret.tata \ --passfile1 ../../var/pass/secret.tata \
--host2 $HOST2 --user2 titi \ --host2 $HOST2 --user2 titi \
--passfile2 ../../var/pass/secret.titi \ --passfile2 ../../var/pass/secret.titi \
--noallow3xx --noallow3xx --justlogin
} }
@ -1234,6 +1301,7 @@ test $# -eq 0 && run_tests \
ll_regexmess_scwchu \ ll_regexmess_scwchu \
ll_flags \ ll_flags \
ll_regex_flag \ ll_regex_flag \
ll_regex_flag_keep_only \
ll_justconnect \ ll_justconnect \
ll_justlogin \ ll_justlogin \
ll_ssl \ ll_ssl \
@ -1247,6 +1315,7 @@ test $# -eq 0 && run_tests \
ll_authmech_CRAMMD5 \ ll_authmech_CRAMMD5 \
ll_authuser \ ll_authuser \
ll_delete2 \ ll_delete2 \
ll_delete \
ll_folderrec \ ll_folderrec \
ll_bigmail \ ll_bigmail \
gmail \ gmail \