diff --git a/ChangeLog b/ChangeLog index a27da4b..0c7bcf8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,17 +1,63 @@ RCS file: RCS/imapsync,v Working file: imapsync -head: 1.525 +head: 1.536 branch: locks: strict - gilles: 1.525 + gilles: 1.536 access list: symbolic names: keyword substitution: kv -total revisions: 525; selected revisions: 525 +total revisions: 536; selected revisions: 536 description: ---------------------------- -revision 1.525 locked by: gilles; +revision 1.536 locked by: gilles; +date: 2013/04/17 14:33:12; author: gilles; state: Exp; lines: +7 -7 +Added --delete1 as an alias for --delete +---------------------------- +revision 1.535 +date: 2013/04/17 12:47:58; author: gilles; state: Exp; lines: +42 -33 +Updated README part. +---------------------------- +revision 1.534 +date: 2013/04/16 15:31:50; author: gilles; state: Exp; lines: +26 -17 +Added --search1 and --search2 to allow different searches on each host. +---------------------------- +revision 1.533 +date: 2013/04/10 12:03:39; author: gilles; state: Exp; lines: +8 -6 +Comment in select_msgs() +---------------------------- +revision 1.532 +date: 2013/04/10 08:33:52; author: gilles; state: Exp; lines: +11 -9 +Fixed Scott issue again. Was not enough. +---------------------------- +revision 1.531 +date: 2013/04/09 08:10:38; author: gilles; state: Exp; lines: +7 -7 +Fixed Scott issue, took long time (all messages list) even with --useuid --delete --nousecache --maxage 1 +---------------------------- +revision 1.530 +date: 2013/04/09 08:00:54; author: gilles; state: Exp; lines: +13 -14 +Clarified select_msgs() a little. +---------------------------- +revision 1.529 +date: 2013/03/29 14:32:26; author: gilles; state: Exp; lines: +14 -12 +Phil patch. +---------------------------- +revision 1.528 +date: 2013/03/29 03:12:45; author: gilles; state: Exp; lines: +60 -21 +Applied Phil patch. +---------------------------- +revision 1.527 +date: 2013/03/29 01:15:05; author: gilles; state: Exp; lines: +10 -8 +Mail2World Server +Zarafa Gateway +---------------------------- +revision 1.526 +date: 2013/02/27 22:40:45; author: gilles; state: Exp; lines: +9 -7 +Apple Server +Zarafa server +---------------------------- +revision 1.525 date: 2013/02/05 12:52:10; author: gilles; state: Exp; lines: +9 -9 Typo synchronise -> synchronize. ---------------------------- @@ -36,7 +82,7 @@ revision 1.520 date: 2013/01/23 07:41:48; author: gilles; state: Exp; lines: +103 -30 Fix. Removed reference to DWTFPL since license is NOLIMIT now. License file is LICENSE now, no longer COPYING. -Fix. Handle the case where several folders on host2 go to one folder on host1 with --delete2 option. +Fix. Handle the case where several folders on host1 go to one folder on host2 with --delete2 option. The bug was imapsync was copying messages and deleting them on next folder. ---------------------------- revision 1.519 diff --git a/FAQ b/FAQ index 55a0798..37127af 100644 --- a/FAQ +++ b/FAQ @@ -1,5 +1,5 @@ #!/bin/cat -# $Id: FAQ,v 1.124 2013/02/05 18:40:50 gilles Exp gilles $ +# $Id: FAQ,v 1.130 2013/04/17 12:46:10 gilles Exp gilles $ +------------------+ | FAQ for imapsync | @@ -8,6 +8,11 @@ http://imapsync.lamiral.info/FAQ Unix versus Windows syntax. +There are several differences between Unix and Windows +in the command line syntax. +- Character \ versus ^ +- Character ' versus " + A) \ versus ^ @@ -103,6 +108,34 @@ post to this list if you want to stay private. Thank you for your participation. +======================================================================= +Q. Can I copy or sync Calendar or Contacts with imapsync? + +R. No. It's because most IMAP servers don't get contacts and calendar +events via IMAP. In other words, messages synced by imapsync from +Calendar or Contacts folders are not used by email servers to set +or get the contacts or calendars. +No way via IMAP, no way via imapsync. + +======================================================================= +Q. How can I copy or synchronize Calendars or Contacts? + +R1. It can't be done with imapsync. + +R2. It can be done, depending on the email server softwares used. + +a) From Exchange to Exchange, export contacts and calendar to + PST format files on host1 and import them on host2. + +b) From Gmail to Gmail, export and import calandars in ical format, + extension for those files is .ics. + Contacts can be copied using a csv file. See the help page + http://support.google.com/mail/bin/topic.py?hl=en&topic=1669027 + +c) Etc. Search the web. There's also specific tools and paid services. + There's no silver bullet to migrate Calendars and Contacts, + if you find one, tell me! + ======================================================================= Q. I need to migrate hundred accounts, how can I do? @@ -145,10 +178,10 @@ Q. Where I can find free open and gratis imapsync releases? R. Search the internet. -Q. Is is legal? +Q. Is is legal to find imapsync gratis (or not) elsewhere? R. Yes, the license permits it - http://imapsync.lamiral.info/COPYING + http://imapsync.lamiral.info/LICENSE ======================================================================= Q. I use --useuid which uses a cache in /tmp or --tmpdir, the hostnames @@ -265,7 +298,13 @@ R2. Use --useuid then imapsync will avoid dealing with headers. ======================================================================= Q. How can I try imapsync with Mail::IMAPClient 3.xx perl module? -R. - Download latest Mail::IMAPClient 3.xx at +R. The answer R2 deals with any Perl module use. + +R1 - Look at the script named i3 in the tarball, it can be used to + run imapsync with included Mail-IMAPClient-3.32/ wherever you + unpacked the imapsync tarball + +R2 - Download latest Mail::IMAPClient 3.xx at http://search.cpan.org/dist/Mail-IMAPClient/ - untar it anywhere: tar xzvf Mail-IMAPClient-3.xx.tar.gz @@ -280,29 +319,11 @@ R. - Download latest Mail::IMAPClient 3.xx at or if imapsync is in directory /path/ perl -I./Mail-IMAPClient-3.32/lib /path/imapsync ... - - Look at the script named i3 in the tarball, it can be used to - run imapsync with included Mail-IMAPClient-3.32/ wherever you - unpacked the imapsync tarball ======================================================================= Q. How can I use imapsync with Mail::IMAPClient 2.2.9 perl module? -R. - Download Mail::IMAPClient 2.2.9 at - http://search.cpan.org/~djkernen/Mail-IMAPClient-2.2.9/ - http://search.cpan.org/CPAN/authors/id/D/DJ/DJKERNEN/Mail-IMAPClient-2.2.9.tar.gz - - untar it anywhere: - tar xzvf Mail-IMAPClient-2.2.9.tar.gz - - - run imapsync with perl and -I option tailing to use Mail-IMAPClient-2.2.9: - perl -I./Mail-IMAPClient-2.2.9 ./imapsync [...] - - or if imapsync is in directory /path/ - perl -I./Mail-IMAPClient-2.2.9 /path/imapsync [...] - - - Look at the script named i2 in the tarball, it can be used to - run imapsync with included Mail-IMAPClient-2.2.9/ wherever you - unpacked the imapsync tarball - +R. Mail::IMAPClient 2.2.9 is no longer supported. ======================================================================= Q. Can I use imapsync to migrate emails from pop3 server to imap server? @@ -408,12 +429,17 @@ R. Use redirections of both standard and error outputs "> log.txt 2>&1" imapsync ... > log.txt 2>&1 +This syntax is available both on Windows and Unix. + ======================================================================= Q. I need to log every output on a file named log.txt and also to the screen in order to keep seeing what's going on during execution R. Use the tee program (also available on Windows) http://en.wikipedia.org/wiki/Tee_%28command%29 +http://stackoverflow.com/questions/796476/displaying-windows-command-prompt-output-and-redirecting-it-to-a-file +http://code.google.com/p/wintee/ + imapsync ... 2>&1 | tee log.txt @@ -1380,25 +1406,24 @@ imapsync --host1 mail.oldhost.com \ --user2 my_email@gmail.com \ --password2 password \ --exitwhenover 500000000 \ - --folder "INBOX.Sent" \ - --regextrans2 "s,^Sent$,[Gmail]/Sent Mail," \ - --addheader + --exclude "\[Gmail\]$" \ + --addheader \ + --regextrans2 "s,^Sent$,[Gmail]/Sent Mail," If you're using a different language in Gmail you might adapt this example with the folder name translated, an example in French: imapsync ... - --folder 'INBOX.Messages envoy&AOk-s' \ --regextrans2 "s,^Messages envoy&AOk-s$,[Gmail]/Messages envoy&AOk-s," \ -The --addheader option is there because Sent folder messages +The --addheader option is there because "Sent" folder messages sometimes lack the "Message-Id" header needed by imapsync -when --useuid is not used. So option --addheader adds a "Message-Id" header. +to identify messages (only when --useuid is not used). +So option --addheader adds a "Message-Id" header. -You can remove --folder "INBOX.Sent" in the example in case -you want to sync all folders, the --regextrans2 option will -still apply only on "INBOX.Sent" folder. +You can add --folder "INBOX.Sent" in the example in case +you want to sync only the "Sent" folder. The "All Mail" archive pseudo-folder should be updated automaticaly. @@ -1406,8 +1431,13 @@ The "All Mail" archive pseudo-folder should be updated automaticaly. exceed maximum limit. See http://support.google.com/a/bin/answer.py?hl=en&answer=1071518 +--exclude "\[Gmail\]$" is there to avoid a small examine/select error: +"Could not examine: 43 NO [NONEXISTENT] Unknown Mailbox: [Gmail] +(now in authenticated state) (Failure)". + + You can select folders exported to imap within the gmail preferences, -unselect all "System labels". +unselect all "System labels" depending on your needs. ======================================================================= diff --git a/INSTALL b/INSTALL index f689922..712219f 100644 --- a/INSTALL +++ b/INSTALL @@ -1,4 +1,4 @@ -# $Id: INSTALL,v 1.26 2012/09/11 21:00:06 gilles Exp gilles $ +# $Id: INSTALL,v 1.27 2013/04/17 12:35:18 gilles Exp gilles $ # # INSTALL file for imapsync # imapsync : IMAP sync or copy tool. @@ -70,18 +70,17 @@ Here is some individual module help: Get the latest Mail::IMAPClient module here: http://search.cpan.org/dist/Mail-IMAPClient/ - In fact I use both Mail-IMAPClient-2.2.9 and latest Mail-IMAPClient-3.xx - (xx >= 31 now) To know the version you have on your system try : + I use always the latest Mail-IMAPClient-3.xx + To know the version you have on your system try : perl -mMail::IMAPClient -e 'print $Mail::IMAPClient::VERSION, "\n"' - New Mail-IMAPClient-3.xx works now very well with imapsync, - better than old Mail-IMAPClient-2.2.9, with memory and other things. + New Mail-IMAPClient-3.xx works very well with imapsync, Use at least Mail-IMAPClient-3.25 (previous may bug). - Don't hesitate to use latest Mail-IMAPClient-3.xx (3.xx >= 3.32 at the time - of this writing) + Don't hesitate to use latest Mail-IMAPClient-3.xx + (3.xx >= 3.32 at the time of this writing) - Look at the script named i3 in the tarball, it can be used to + Look at the script named "i3" in the tarball, it can be used to run imapsync with included Mail-IMAPClient-3.32/ wherever you unpacked the imapsync tarball. diff --git a/Makefile b/Makefile index 192a156..a5a7c6d 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ -# $Id: Makefile,v 1.114 2013/01/29 00:26:51 gilles Exp gilles $ +# $Id: Makefile,v 1.116 2013/04/18 01:24:25 gilles Exp gilles $ .PHONY: help usage all @@ -11,8 +11,6 @@ usage: @echo "make testf # run tests" @echo "make testv # run tests verbosely" @echo "make test_quick # few tests verbosely" - @echo "make test3xx # run tests with (last) Mail-IMAPClient-3.xy" - @echo "make test229 # run tests with Mail-IMAPClient-2.2.9" @echo "make tests_win32 # run tests on win32" @echo "make tests_win32_dev # run test2.bat on win32" @echo "make all " @@ -31,7 +29,6 @@ VERSION=$(shell perl -I$(IMAPClient) ./imapsync --version) VERSION_EXE=$(shell cat ./VERSION_EXE) HELLO=$(shell date;uname -a) -IMAPClient_2xx=./W/Mail-IMAPClient-2.2.9 IMAPClient_3xx=./W/Mail-IMAPClient-3.32/lib IMAPClient=$(IMAPClient_3xx) @@ -61,7 +58,7 @@ VERSION: imapsync clean: clean_tilde clean_man clean_test: - rm -f .test_3xx .test_229 + rm -f .test_3xx clean_tilde: rm -f *~ @@ -98,20 +95,13 @@ cidone: ############### -.PHONY: test tests testp testf test3xx testv2 testv3 +.PHONY: test tests testp testf test3xx testv3 -test_quick : test_quick_3xx test_quick_229 - -test_quick_229: imapsync tests.sh - CMD_PERL='perl -I./$(IMAPClient_2xx)' /usr/bin/time sh -x tests.sh locallocal +test_quick : test_quick_3xx test_quick_3xx: imapsync tests.sh CMD_PERL='perl -I./$(IMAPClient_3xx)' /usr/bin/time sh -x tests.sh locallocal -testv2: imapsync tests.sh - CMD_PERL='perl -I./$(IMAPClient_2xx)' /usr/bin/time sh tests.sh - touch .test_229 - testv3: imapsync tests.sh CMD_PERL='perl -I./$(IMAPClient_3xx)' /usr/bin/time sh tests.sh touch .test_3xx @@ -122,14 +112,6 @@ test: .test_3xx tests: test -test3xx: .test_3xx - -test229: .test_229 - -.test_229: imapsync tests.sh - CMD_PERL='perl -I./$(IMAPClient_2xx)' /usr/bin/time sh tests.sh 1>/dev/null - touch .test_229 - .test_3xx: imapsync tests.sh CMD_PERL='perl -I./$(IMAPClient_3xx)' /usr/bin/time sh tests.sh 1>/dev/null touch .test_3xx @@ -223,7 +205,7 @@ tarball: .tarball cd examples && rcsdiff RCS/* mkdir -p dist mkdir -p ../prepa_dist/$(DIST_NAME) - rsync -aCv --delete --omit-dir-times --exclude dist/ --exclude imapsync.exe ./ ../prepa_dist/$(DIST_NAME)/ + rsync -aCvH --delete --omit-dir-times --exclude dist/ --exclude imapsync.exe ./ ../prepa_dist/$(DIST_NAME)/ #rsync -av ./imapsync.exe ../prepa_dist/$(DIST_NAME)/ cd ../prepa_dist && (tar czfv $(DIST_FILE) $(DIST_NAME) || tar czfv $(DIST_FILE) $(DIST_NAME)) #ln -f ../prepa_dist/$(DIST_FILE) dist/ @@ -277,7 +259,7 @@ ksa: publish: upload_ks ksa ml -PUBLIC_FILES = ./ChangeLog ./COPYING ./LICENSE ./CREDITS ./FAQ \ +PUBLIC_FILES = ./ChangeLog ./NOLIMIT ./LICENSE ./CREDITS ./FAQ \ ./index.shtml ./INSTALL \ ./VERSION ./VERSION_EXE \ ./README ./TODO @@ -321,7 +303,7 @@ upload_lfo: upload_index: FAQ LICENSE CREDITS W/*.bat examples/*.bat examples/sync_loop_unix.sh index.shtml rcsdiff index.shtml FAQ LICENSE CREDITS W/*.bat examples/*.bat index.shtml validate --verbose index.shtml - rsync -avH index.shtml FAQ COPYING LICENSE CREDITS root@ks.lamiral.info:/var/www/imapsync/ + rsync -avH index.shtml FAQ NOLIMIT LICENSE CREDITS root@ks.lamiral.info:/var/www/imapsync/ rsync -avH W/*.bat root@ks.lamiral.info:/var/www/imapsync/W/ rsync -avH examples/*.bat examples/sync_loop_unix.sh root@ks.lamiral.info:/var/www/imapsync/examples/ diff --git a/COPYING b/NOLIMIT similarity index 100% rename from COPYING rename to NOLIMIT diff --git a/README b/README index ee0fb99..8bd78e1 100644 --- a/README +++ b/README @@ -1,9 +1,10 @@ NAME imapsync - IMAP synchronisation, sync, copy or migration tool. - Synchronise mailboxes between two imap servers. Good at IMAP migration. - More than 44 different IMAP server softwares supported with success. + Synchronises mailboxes between two imap servers. Good at IMAP migration. + More than 52 different IMAP server softwares supported with success, few + failures. - $Revision: 1.525 $ + $Revision: 1.536 $ SYNOPSIS To synchronize imap account "foo" on "imap.truc.org" to imap account @@ -16,8 +17,8 @@ SYNOPSIS INSTALL imapsync works fine under any Unix OS with perl. - imapsync works fine under Windows (2000, XP) - with Strawberry Perl 5.10 or 5.12 + imapsync works fine under Windows (2000, XP, Vista, Seven) + with Strawberry Perl (5.10, 5.12 or higher) or as a standalone binary software imapsync.exe imapsync can be available directly on the following distributions: @@ -76,6 +77,9 @@ USAGE [--minsize ] [--maxage ] [--minage ] + [--search ] + [--search1 ] + [--search2 ] [--skipheader ] [--useheader ] [--useheader ] [--nouid1] [--nouid2] @@ -101,7 +105,8 @@ DESCRIPTION The command imapsync is a tool allowing incremental and recursive imap transfer from one mailbox to another. - By default all folders are transferred, recursively. + By default all folders are transferred, recursively, all possible flags + (\Seen \Answered \Flagged etc.) are synced too. We sometimes need to transfer mailboxes from one imap server to another. This is called migration. @@ -115,7 +120,7 @@ DESCRIPTION You can decide to delete the messages from the source mailbox after a successful transfer, it can be a good feature when migrating live - mailboxes since messages will be only one side. In that case, use the + mailboxes since messages will be only on one side. In that case, use the --delete option. Option --delete implies also option --expunge so all messages marked deleted on host1 will be really deleted. (you can use --noexpunge to avoid this but I don't see any good real world scenario @@ -179,7 +184,8 @@ SECURITY on host1. In this case, --authmech1 PLAIN will be used by default since it is the only way to go for now. So don't use --authmech1 SOMETHING with --authuser1 "adminuser", it will not work. Same behavior with the - --authuser2 option. + --authuser2 option. Authenticate with an admin account must be supported + by your imap server to work with imapsync. When working on Sun/iPlanet/Netscape IMAP servers you must use --proxyauth1 to enable administrative user to masquerade as another @@ -199,11 +205,11 @@ EXIT STATUS LICENSE imapsync is free, open, public but not always gratis software cover by the NOLIMIT Public License. See the LICENSE file included in the - distribution or just read this: No limit to do anything with this work - and this license. + distribution or just read this simple sentence as it is the licence + text: No limit to do anything with this work and this license. MAILING-LIST - The public mailing-list may be the best way to get support. + The public mailing-list may be the best way to get free support. To write on the mailing-list, the address is: @@ -218,7 +224,7 @@ MAILING-LIST To contact the person in charge for the list: - The list archives may be available at: + The list archives are available at: http://www.linux-france.org/prj/imapsync_list/ So consider that the list is public, anyone can see your post. Use a pseudonym or do not post to this list if you want to stay private. @@ -226,17 +232,15 @@ MAILING-LIST Thank you for your participation. AUTHOR - Gilles LAMIRAL + Gilles LAMIRAL - Feedback good or bad is always welcome. + Feedback good or bad is very often welcome. - The newsgroup comp.mail.imap may be a good place to talk about imapsync. - I read it when imapsync is concerned. A better place is the public - imapsync mailing-list (see below). - - Gilles LAMIRAL earns his living writing, installing, configuring and - teaching free, open and often gratis softwares. Do not hesitate to pay - him for that services. + Gilles LAMIRAL earns his living by writing, installing, configuring and + teaching free, open and often gratis softwares. It used to be "always + gratis" but now it is "often" because imapsync is sold by its author, a + good way to stay maintening and supporting free open public softwares + (see the license) over decades. BUG REPORT GUIDELINES Help us to help you: follow the following guidelines. @@ -258,8 +262,8 @@ BUG REPORT GUIDELINES "problem", a good title is made of keywords summary, not too long (one visible line). - Don't write imapsync in uppercase in the email title, we'll know you run - Windows and you haven't read this README yet. + Don't write imapsync in uppercase in the email title, I'll then know you + run Windows and you haven't read this README yet. Help us to help you: in your report, please include: @@ -277,7 +281,8 @@ BUG REPORT GUIDELINES - IMAPClient.pm version. - - the run context. Do you run imapsync.exe, a unix binary or the perl script imapsync. + - the run context. Do you run imapsync.exe, a unix binary + or the perl script imapsync. - operating system running imapsync. @@ -287,7 +292,8 @@ BUG REPORT GUIDELINES you run imapsync on a foreign host from the both. Most of those values can be found as a copy/paste at the begining of the - output. + output, so a copy of the output is a very easy and very good debug + report for me. One time in your life, read the paper "How To Ask Questions The Smart Way" http://www.catb.org/~esr/faqs/smart-questions.html and then forget @@ -303,12 +309,15 @@ IMAP SERVERS - (2011) MDaemon 12.0.3 as host2 but MDaemon is supported as host1. MDaemon is simply buggy with the APPEND IMAP command with any IMAP email client. + - Hotmail since hotmail.com does not provide IMAP access + - Outlook.com since outlook.com does not provide IMAP access - Success stories reported with the following 48 imap servers (software + Success stories reported with the following 52 imap servers (software names are in alphabetic order): - - 1und1 H mimap1 84498 [host1] + - 1und1 H mimap1 84498 [host1] H mibap4 95231 [host1] - a1.net imap.a1.net IMAP4 Ready [host1] + - Apple Server 10.6 Snow Leopard [host1] - Archiveopteryx 2.03, 2.04, 2.09, 2.10 [host2], 3.0.0 [host2] (OSL 3.0) http://www.archiveopteryx.org/ - Axigen Mail Server Version 8.0.0 @@ -340,6 +349,7 @@ IMAP SERVERS - iPlanet Messaging server 4.15, 5.1, 5.2 - IMail 7.15 (Ipswitch/Win2003), 8.12, 11.03 [host1] - Kerio 7.2.0 Patch 1 [host1] [host2] + - Mail2World IMAP4 Server 2.5 [host1] (http://www.mail2world.com/) - MailEnable 4.23 [host1] [host2], 4.26 [host1][host2], 5 [host1] - MDaemon 7.0.1, 8.0.2, 8.1, 9.5.4 (Windows server 2003 R2 platform), 12 [host2], 12.0.3 [host1], 12.5.5 [host1], @@ -352,6 +362,7 @@ IMAP SERVERS - Mirapoint, 4.1.9-GA [host1] - Netscape Mail Server 3.6 (Wintel !) - Netscape Messaging Server 4.15 Patch 7 + - Office 365 [host1] [host2] - OpenMail IMAP server B.07.00.k0 (Samsung Contact ?) - OpenWave - Oracle Beehive [host1] @@ -370,6 +381,8 @@ IMAP SERVERS - UW - QMail v2.1 - VMS, Imap part of TCP/IP suite of VMS 7.3.2 - Yahoo [host1] + - Zarafa 6,40,0,20653 [host1] (http://www.zarafa.com/) + - Zarafa ZCP 7.1.4 IMAP Gateway [host2] - Zimbra-IMAP 3.0.1 GA 160, 3.1.0 Build 279, 4.0.5, 4.5.2, 4.5.6, Zimbra 5.0.24_GA_3356.RHEL4 [host1], 5.5, 6.x @@ -445,5 +458,5 @@ SIMILAR SOFTWARES Feedback (good or bad) will often be welcome. - $Id: imapsync,v 1.525 2013/02/05 12:52:10 gilles Exp gilles $ + $Id: imapsync,v 1.536 2013/04/17 14:33:12 gilles Exp gilles $ diff --git a/TODO b/TODO index 772443c..877ef5f 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,5 @@ #!/bin/cat -# $Id: TODO,v 1.118 2013/02/08 06:28:40 gilles Exp gilles $ +# $Id: TODO,v 1.119 2013/04/17 13:04:21 gilles Exp gilles $ TODO file for imapsync ---------------------- @@ -23,6 +23,9 @@ http://www.yippiemove.com/ http://www.migrationwiz.com/ http://www.microsoft.com/download/en/details.aspx?id=1329 "Microsoft Transporter Suite" +Add an exit value when exiting because of --exitwhenover +The goal is to know easily why to restart later. + Add --delete1 as an alias for --delete Add --mark-as-deleted1 --mark-as-deleted2 as aliases for --noexpunge1 --delete1 and --noexpunge2 --delete2 @@ -46,6 +49,9 @@ Fix long path over than 260 character on Win32. Think about Digest::SHA or Digest::SHA::PurePerl. Think about a file database like DBM instead. +Add OAUTH autentication support +https://developers.google.com/google-apps/gmail/oauth_overview + Find a way to avoid passwords in --debugimap unless needed. Explain that users can win time/bandwidth by using --expunge diff --git a/VERSION b/VERSION index 6e43d5b..e84694e 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.525 +1.536 diff --git a/VERSION_EXE b/VERSION_EXE index 6e43d5b..e84694e 100644 --- a/VERSION_EXE +++ b/VERSION_EXE @@ -1 +1 @@ -1.525 +1.536 diff --git a/W/.BUILD_EXE_TIME b/W/.BUILD_EXE_TIME index eec9dda..d274a7c 100644 --- a/W/.BUILD_EXE_TIME +++ b/W/.BUILD_EXE_TIME @@ -172,3 +172,15 @@ 1359421989 END 1.522 : mardi 29 janvier 2013, 02:13:09 (UTC+0100) 1360108747 BEGIN 1.525 : mercredi 6 février 2013, 00:59:07 (UTC+0100) 1360109581 END 1.525 : mercredi 6 février 2013, 01:13:01 (UTC+0100) +1364528510 BEGIN 1.528 : vendredi 29 mars 2013, 04:41:51 (UTC+0100) +1364529434 END 1.528 : vendredi 29 mars 2013, 04:57:14 (UTC+0100) +1365000098 BEGIN 1.529 : mercredi 3 avril 2013, 16:41:38 (UTC+0200) +1365001150 END 1.529 : mercredi 3 avril 2013, 16:59:10 (UTC+0200) +1365595458 BEGIN 1.533 : mercredi 10 avril 2013, 14:04:18 (UTC+0200) +1365596319 END 1.533 : mercredi 10 avril 2013, 14:18:39 (UTC+0200) +1366126390 BEGIN 1.534 : mardi 16 avril 2013, 17:33:10 (UTC+0200) +1366127411 END 1.534 : mardi 16 avril 2013, 17:50:11 (UTC+0200) +1366202919 BEGIN 1.535 : mercredi 17 avril 2013, 14:48:39 (UTC+0200) +1366203902 END 1.535 : mercredi 17 avril 2013, 15:05:02 (UTC+0200) +1366209307 BEGIN 1.536 : mercredi 17 avril 2013, 16:35:07 (UTC+0200) +1366210370 END 1.536 : mercredi 17 avril 2013, 16:52:50 (UTC+0200) diff --git a/W/Mail-IMAPClient-2.2.9/Artistic b/W/Mail-IMAPClient-2.2.9/Artistic deleted file mode 100644 index 5f22124..0000000 --- a/W/Mail-IMAPClient-2.2.9/Artistic +++ /dev/null @@ -1,131 +0,0 @@ - - - - - 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 diff --git a/W/Mail-IMAPClient-2.2.9/BUG_REPORTS b/W/Mail-IMAPClient-2.2.9/BUG_REPORTS deleted file mode 100644 index 5fff255..0000000 --- a/W/Mail-IMAPClient-2.2.9/BUG_REPORTS +++ /dev/null @@ -1,9 +0,0 @@ -REPORING BUGS - -See the section on "REPORTING BUGS" in the module's documentation if you are -having problems. - -YOU MUST FOLLOW THE INSTRUCTIONS IN THE DOCUMENTATION AND PROVIDE ALL OF THE NECESSARY -INFORMATION if you expect a response from your bug report. You should also look at -the data you gather before you send it, since doing so will often solve your problem. - diff --git a/W/Mail-IMAPClient-2.2.9/BodyStructure/BodyStructure.pm b/W/Mail-IMAPClient-2.2.9/BodyStructure/BodyStructure.pm deleted file mode 100755 index 99eccab..0000000 --- a/W/Mail-IMAPClient-2.2.9/BodyStructure/BodyStructure.pm +++ /dev/null @@ -1,725 +0,0 @@ -package Mail::IMAPClient::BodyStructure; -#$Id: BodyStructure.pm,v 1.3 2003/06/12 21:41:37 dkernen Exp $ -#use Parse::RecDescent; -use Mail::IMAPClient; -use Mail::IMAPClient::BodyStructure::Parse; -use vars qw/$parser/; -use Exporter; -push @ISA, "Exporter"; -push @EXPORT_OK , '$parser'; - -$Mail::IMAPClient::BodyStructure::VERSION = '0.0.2'; -# Do it once more to show we mean it! -$Mail::IMAPClient::BodyStructure::VERSION = '0.0.2'; - -$parser = Mail::IMAPClient::BodyStructure::Parse->new() - - or die "Cannot parse rules: $@\n" . - "Try remaking Mail::IMAPClient::BodyStructure::Parse.\n" - and return undef; - - -sub new { - my $class = shift; - my $bodystructure = shift; - my $self = $parser->start($bodystructure) or return undef; - $self->{_prefix} = ""; - - if ( exists $self->{bodystructure} ) { - $self->{_id} = 'HEAD' ; - } else { - $self->{_id} = 1; - } - - $self->{_top} = 1; - - return bless($self ,ref($class)||$class); -} - -sub _get_thingy { - my $thingy = shift; - my $object = shift||(ref($thingy)?$thingy:undef); - unless ( defined($object) and ref($object) ) { - $@ = "No argument passed to $thingy method." ; - $^W and print STDERR "$@\n" ; - return undef; - } - unless ( "$object" =~ /HASH/ - and exists($object->{$thingy}) - ) { - $@ = ref($object) . - " $object does not have " . - ( $thingy =~ /^[aeiou]/i ? "an " : "a " ) . - "${thingy}. " . - ( ref($object) =~ /HASH/ ? "It has " . join(", ",keys(%$object)) : "") ; - $^W and print STDERR "$@\n" ; - return undef; - } - return Unwrapped($object->{$thingy}); -} - -BEGIN { - foreach my $datum (qw/ bodytype bodysubtype bodyparms bodydisp bodyid - bodydesc bodyenc bodysize bodylang - envelopestruct textlines - / - ) { - no strict 'refs'; - *$datum = sub { _get_thingy($datum, @_); }; - } - -} - -sub parts { - my $self = shift; - - - if ( exists $self->{PartsList} ) { - return wantarray ? @{$self->{PartsList}} : $self->{PartsList} ; - } - - my @parts = (); - $self->{PartsList} = \@parts; - - unless ( exists($self->{bodystructure}) ) { - $self->{PartsIndex}{1} = $self ; - @parts = ("HEAD",1); - return wantarray ? @parts : \@parts; - } - #@parts = ( 1 ); - #} else { - - foreach my $p ($self->bodystructure()) { - push @parts, $p->id(); - $self->{PartsIndex}{$p->id()} = $p ; - if ( uc($p->bodytype()||"") eq "MESSAGE" ) { - #print "Part $parts[-1] is a ",$p->bodytype,"\n"; - push @parts,$parts[-1] . ".HEAD"; - #} else { - # print "Part $parts[-1] is a ",$p->bodytype,"\n"; - } - } - - #} - - return wantarray ? @parts : \@parts; -} - -sub oldbodystructure { - my $self = shift; - if ( exists $self->{_bodyparts} ) { - return wantarray ? @{$self->{_bodyparts}} : $self->{_bodyparts} ; - } - my @bodyparts = ( $self ); - $self->{_id} ||= "HEAD"; # aka "0" - my $count = 0; - #print STDERR "Analyzing a ",$self->bodytype, " part which I think is part number ", - # $self->{_id},"\n"; - my $dump = Data::Dumper->new( [ $self ] , [ 'bodystructure' ] ); - $dump->Indent(1); - - foreach my $struct (@{$self->{bodystructure}}) { - $struct->{_prefix} ||= $self->{_prefix} . +$count . "." unless $struct->{_top}; - $struct->{_id} ||= $self->{_prefix} . $count unless $struct->{_top}; - #if ( - # uc($struct->bodytype) eq 'MULTIPART' or - # uc($struct->bodytype) eq 'MESSAGE' - #) { - #} else { - #} - push @bodyparts, $struct, - ref($struct->{bodystructure}) ? $struct->bodystructure : () ; - } - $self->{_bodyparts} = \@bodyparts ; - return wantarray ? @bodyparts : $self->bodyparts ; -} - -sub bodystructure { - my $self = shift; - my @parts = (); - my $partno = 0; - - my $prefix = $self->{_prefix} || ""; - - #print STDERR "Analyzing a ",($self->bodytype||"unknown ") , - # " part which I think is part number ", - # $self->{_id},"\n"; - - my $bs = $self; - $prefix = "$prefix." if ( $prefix and $prefix !~ /\.$/); - - if ( $self->{_top} ) { - $self->{_id} ||= "HEAD"; - $self->{_prefix} ||= "HEAD"; - $partno = 0; - for (my $x = 0; $x < scalar(@{$self->{bodystructure}}) ; $x++) { - $self->{bodystructure}[$x]{_id} = ++$partno ; - $self->{bodystructure}[$x]{_prefix} = $partno ; - push @parts, $self->{bodystructure}[$x] , - $self->{bodystructure}[$x]->bodystructure; - } - - - } else { - $partno = 0; - foreach my $p ( @{$self->{bodystructure}} ) { - $partno++; - if ( - ! exists $p->{_prefix} - ) { - $p->{_prefix} = "$prefix$partno"; - } - $p->{_prefix} = "$prefix$partno"; - $p->{_id} ||= "$prefix$partno"; - #my $bt = $p->bodytype; - #if ($bt eq 'MESSAGE') { - #$p->{_id} = $prefix . - #$partno = 0; - #} - push @parts, $p, $p->{bodystructure} ? $p->bodystructure : (); - } - } - - return wantarray ? @parts : \@parts; -} - -sub id { - my $self = shift; - - return $self->{_id} if exists $self->{_id}; - return "HEAD" if $self->{_top}; - #if ($self->bodytype eq 'MESSAGE') { - # return - #} - - if ($self->{bodytype} eq 'MULTIPART') { - my $p = $self->{_id}||$self->{_prefix} ; - $p =~ s/\.$//; - return $p; - } else { - return $self->{_id} ||= 1; - } -} - -sub Unwrapped { - my $unescape = Mail::IMAPClient::Unescape(@_); - $unescape =~ s/^"(.*)"$/$1/ if defined($unescape); - return $unescape; -} - -package Mail::IMAPClient::BodyStructure::Part; -@ISA = qw/Mail::IMAPClient::BodyStructure/; - - -package Mail::IMAPClient::BodyStructure::Envelope; -@ISA = qw/Mail::IMAPClient::BodyStructure/; - -sub new { - my $class = shift; - my $envelope = shift; - my $self = $Mail::IMAPClient::BodyStructure::parser->envelope($envelope); - return $self; -} - - -sub _do_accessor { - my $datum = shift; - if (scalar(@_) > 1) { - return $_[0]->{$datum} = $_[1] ; - } else { - return $_[0]->{$datum}; - } -} - -# the following for loop sets up accessor methods for -# the object's address attributes: - -sub _mk_address_method { - my $datum = shift; - my $method1 = $datum . "_addresses" ; - no strict 'refs'; - *$method1 = sub { - my $self = shift; - return undef unless ref($self->{$datum}) eq 'ARRAY'; - my @list = map { - my $pn = $_->personalname ; - $pn = "" if $pn eq 'NIL' ; - ( $pn ? "$pn " : "" ) . - "<" . - $_->mailboxname . - '@' . - $_->hostname . - ">" - } @{$self->{$datum}} ; - if ( $senderFields{$datum} ) { - return wantarray ? @list : $list[0] ; - } else { - return wantarray ? @list : \@list ; - } - }; -} - -BEGIN { - - for my $datum ( - qw( subject inreplyto from messageid bcc date replyto to sender cc ) - ) { - no strict 'refs'; - *$datum = sub { _do_accessor($datum, @_); }; - } - my %senderFields = map { ($_ => 1) } qw/from sender replyto/ ; - for my $datum ( - qw( from bcc replyto to sender cc ) - ) { - _mk_address_method($datum); - } -} - - -package Mail::IMAPClient::BodyStructure::Address; -@ISA = qw/Mail::IMAPClient::BodyStructure/; - -for my $datum ( - qw( personalname mailboxname hostname sourcename ) - ) { - no strict 'refs'; - *$datum = sub { return $_[0]->{$datum}; }; -} - -1; -__END__ - -=head1 NAME - -Mail::IMAPClient::BodyStructure - Perl extension to Mail::IMAPClient to facilitate -the parsing of server responses to the FETCH BODYSTRUCTURE and FETCH ENVELOPE -IMAP client commands. - -=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 $new (@recent) { - - my $struct = Mail::IMAPClient::BodyStructure->new( - $imap->fetch($new,"bodystructure") - ); - - print "Msg $new (Content-type: ",$struct->bodytype,"/",$struct->bodysubtype, - ") contains these parts:\n\t",join("\n\t",$struct->parts),"\n\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 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 object, then you might as well save yourself -some work and use B's B method, which -accepts a message sequence number (or UID if I is true) and returns a -B object. It's functionally equivalent to issuing the -FETCH BODYSTRUCTURE IMAP client command and then passing the results to -B's B method but it does those things in one -simple method call. - -=head1 Object Methods - -The following object methods are available: - -=head2 bodytype - -The B object method requires no arguments. -It returns the bodytype for the message whose structure is described by the calling -B object. - -=cut - -=head2 bodysubtype - -The B object method requires no arguments. -It returns the bodysubtype for the message whose structure is described by the calling -B object. - -=cut - - - -=head2 bodyparms - -The B object method requires no arguments. -It returns the bodyparms for the message whose structure is described by the calling -B object. - -=cut - - - -=head2 bodydisp - -The B object method requires no arguments. -It returns the bodydisp for the message whose structure is described by the calling -B object. - -=cut - - - -=head2 bodyid - -The B object method requires no arguments. -It returns the bodyid for the message whose structure is described by the calling -B object. - -=cut - - - -=head2 bodydesc - -The B object method requires no arguments. -It returns the bodydesc for the message whose structure is described by the calling -B object. - -=cut - - - -=head2 bodyenc - -The B object method requires no arguments. -It returns the bodyenc for the message whose structure is described by the calling -B object. - -=cut - - - -=head2 bodysize - -The B object method requires no arguments. -It returns the bodysize for the message whose structure is described by the calling -B object. - -=cut - - - -=head2 bodylang - -The B object method requires no arguments. -It returns the bodylang for the message whose structure is described by the calling -B object. - -=cut - -=head2 bodystructure - -The B object method requires no arguments. -It returns the bodystructure for the message whose structure is described by the calling -B object. - -=cut - - - -=head2 envelopestruct - -The B object method requires no arguments. -It returns the envelopestruct for the message whose structure is described by the -calling B object. This envelope structure is blessed -into the B subclass, which is explained more -fully below. - -=cut - - -=head2 textlines - -The B object method requires no arguments. -It returns the textlines for the message whose structure is described by the calling -B object. - -=cut - -=head1 Envelopes and the Mail::IMAPClient::BodyStructure::Envelope Subclass - -The IMAP standard specifies that output from the IMAP B command -will be an RFC2060 envelope structure. It further specifies that output from the -B command may also contain embedded envelope structures (if, -for example, a message's subparts contain one or more included messages). Objects -belonging to B 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, -C<$imap->fetch($msgid,"ENVELOPE")> or Cget_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 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 objects, which are perl -data structures representing RFC2060 address structures. Some of these arrays would naturally -contain one element (such as B, 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", 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. - -=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 arrays) also has an analagous method -that will return a list of E-Mail addresses instead. The addresses are in the -format Cmailboxname@hostnameE> (see the section on -B, 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, 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 parses each of these into -an array of B 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: - -Cmailboxname@hostnameE> - -Note that because the B objects come in -arrays, it's generally easier to use the methods available to -B 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 need them anyway.) - -=cut - -=head1 AUTHOR - -David J. Kernen - -=head1 SEE ALSO - -perl(1), Mail::IMAPClient, and RFC2060. See also Parse::RecDescent if you want -to understand the internals of this module. - -=cut - - -# History: -# $Log: BodyStructure.pm,v $ -# Revision 1.3 2003/06/12 21:41:37 dkernen -# Cleaning up cvs repository -# -# Revision 1.1 2003/06/12 21:37:03 dkernen -# -# Preparing 2.2.8 -# Added Files: COPYRIGHT -# Modified Files: Parse.grammar -# Added Files: Makefile.old -# Makefile.PL Todo sample.perldb -# BodyStructure.pm -# -# Revision 1.2 2002/09/26 17:56:14 dkernen -# -# Modified Files: -# BUG_REPORTS Changes IMAPClient.pm INSTALL_perl5.80 MANIFEST -# Makefile.PL for version 2.2.3. See the Changes file for details. -# Modified Files: BodyStructure.pm -- cosmetic changes to pod doc -# -# Revision 1.1 2002/08/30 20:58:51 dkernen -# -# In Mail::IMAPClient/IMAPClient, added files: BUG_REPORTS getGrammer runtest sample.perldb -# In Mail::IMAPClient/IMAPClient/BodyStructure, added files: BodyStructure.pm Makefile.PL debug.ksh runtest -# diff --git a/W/Mail-IMAPClient-2.2.9/BodyStructure/COPYRIGHT b/W/Mail-IMAPClient-2.2.9/BodyStructure/COPYRIGHT deleted file mode 100644 index d5cdcf8..0000000 --- a/W/Mail-IMAPClient-2.2.9/BodyStructure/COPYRIGHT +++ /dev/null @@ -1,21 +0,0 @@ -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. - diff --git a/W/Mail-IMAPClient-2.2.9/BodyStructure/Makefile.PL b/W/Mail-IMAPClient-2.2.9/BodyStructure/Makefile.PL deleted file mode 100755 index 8fc4004..0000000 --- a/W/Mail-IMAPClient-2.2.9/BodyStructure/Makefile.PL +++ /dev/null @@ -1,12 +0,0 @@ -use ExtUtils::MakeMaker; -# See lib/ExtUtils/MakeMaker.pm for details of how to influence -# the contents of the Makefile that is written. -WriteMakefile( - 'DIR' => [ 'Parse' ] , - 'NAME' => 'Mail::IMAPClient::BodyStructure', - 'VERSION_FROM' => '../IMAPClient.pm', # finds $VERSION - 'PREREQ_PM' => { - "Parse::RecDescent" => '1.94', - "Exporter" => 0, - }, -); diff --git a/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/Makefile.PL b/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/Makefile.PL deleted file mode 100755 index a375142..0000000 --- a/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/Makefile.PL +++ /dev/null @@ -1,46 +0,0 @@ -use ExtUtils::MakeMaker; -use Parse::RecDescent; - -unlink "./Parse.pm" if -f "./Parse.pm"; -sub MY::top_targets { - package MY; - - my $inherit = shift->SUPER::top_targets(@_); - my @inherit = split("\n",$inherit); - for (@inherit) { - if ( /^\s*all\s*:{1,2}/ ) { - s/(all\s*:{1,2}\s*)/$1Parse\.pm /; - } - } - return join("\n",@inherit); -} - -sub MY::clean { - package MY; - - my $inherit = shift->SUPER::clean(@_); - return join("\n",$inherit," rm Parse.pm") ; -} - -sub MY::postamble { - my $string = - '@$(PERL) "-MParse::RecDescent" "-" ' . - '"Parse.grammar" '. - '"Mail::IMAPClient::BodyStructure::Parse"' ; - return "Parse.pm: Parse.grammar\n\t$string\n\n"; -} - -# See lib/ExtUtils/MakeMaker.pm for details of how to influence -# the contents of the Makefile that is written. -#print "",MY->top_target; - -WriteMakefile( - 'NAME' => 'Mail::IMAPClient::Parse', - 'VERSION_FROM' => '../../IMAPClient.pm', - 'PREREQ_PM' => {"Parse::RecDescent" => 0 }, - 'PM' => { - 'Parse.pm' => - '$(INST_LIBDIR)/BodyStructure/Parse.pm' - }, -); - diff --git a/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/Parse.grammar_new b/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/Parse.grammar_new deleted file mode 100755 index e418422..0000000 --- a/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/Parse.grammar_new +++ /dev/null @@ -1,288 +0,0 @@ -# Directives -# ( none) -# Start-up Actions - -{ - my $subpartCount = 0; - my $partCount = 0; -} - -# -# 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]; $return||defined($return);} - -# Strings: - -SINGLE_QUOTED_STRING: "'" /(?:\\'|[^'])*/ "'" { - - $return = $item{__PATTERN1__} ; - $return||defined($return); -} - -DOUBLE_QUOTED_STRING: '"' /(?:\\"|[^"])*/ '"' { - - $return = $item{__PATTERN1__} ; - $return||defined($return); -} - -QUOTED_STRING: DOUBLE_QUOTED_STRING | SINGLE_QUOTED_STRING { - - $return = $item{DOUBLE_QUOTED_STRING}||$item{SINGLE_QUOTED_STRING} ; - $return||defined($return); -} - -BARESTRING: ...!/^[)('"]/ /^(?!\(|\))(?:\\ |\S)+/ { - $return = $item{__PATTERN1__} ; $return||defined($return); -} - -STRING: QUOTED_STRING | BARESTRING { - $return = $item{QUOTED_STRING}||$item{BARESTRING} ; - $return||defined($return); -} - -OLDSTRING: /^"((?:[^"\\]|\\.)*)"/ | /^([^ \(\)]+)/ - { $item{__PATTERN1__} =~ s/^"(.*)"$/$1/; - $return = $item{__PATTERN1__} || $item{__PATTERN2__} ; - $return||defined($return); - } - -#BARESTRING: /^[^(]+\s+(?=\()/ -# { $return = $item[1] ; $return||defined($return);} - -textlines: NIL | NUMBER { $return = $item[1] || $item[2]; $return||defined($return); } -rfc822message: MESSAGE RFC822 { $return = "MESSAGE RFC822" } -key: STRING { $return = $item{STRING} ; $return||defined($return);} -value: NIL | '(' kvpair(s) ')'| NUMBER | STRING - { $return = $item{NIL} || - $item{NUMBER} || - $item{STRING} || - { map { (%$_) } @{$item{'kvpair(s)'}} } ; - $return||defined($return); - } -kvpair: ...!")" key value - { $return = { $item{key} => $item{value} }; $return||defined($return);} -bodytype: STRING - { $return = $item{STRING} ; $return||defined($return);} -bodysubtype: PLAIN | HTML | NIL | STRING - { $return = $item{PLAIN}||$item{HTML}||$item{NIL}||$item{STRING} ; - $return||defined($return); - } -bodyparms: NIL | '(' kvpair(s) ')' - { - $return = $item{NIL} || - { map { (%$_) } @{$item{'kvpair(s)'}} }; - $return || defined($return); - } -bodydisp: NIL | '(' kvpair(s) ')' - { - $return = $item{NIL} || - { map { (%$_) } @{$item{'kvpair(s)'}} }; - $return || defined($return); - } -bodyid: ...!/[()]/ NIL | STRING - { $return = $item{NIL} || $item{STRING} ; $return||defined($return);} -bodydesc: ...!/[()]/ NIL | STRING - { $return = $item{NIL} || $item{STRING} ; $return||defined($return);} -bodyenc: NIL | STRING | '(' kvpair(s) ')' - { - $return = $item{NIL} || - $item{STRING} || - { map { (%$_) } @{$item{'kvpair(s)'}} }; - $return||defined($return); - } -bodysize: ...!/[()]/ NIL | NUMBER - { $return = $item{NIL} || $item{NUMBER} ;$return||defined($return);} - -bodyMD5: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} -bodylang: NIL | STRING | "(" STRING(s) ")" - { $return = $item{NIL} || $item{'STRING(s)'} ;$return||defined($return);} -personalname: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} -sourceroute: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} -mailboxname: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} -hostname: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} -addressstruct: "(" personalname sourceroute mailboxname hostname ")" - { $return = { - personalname => $item{personalname} , - sourceroute => $item{sourceroute} , - mailboxname => $item{mailboxname} , - hostname => $item{hostname} , - } ; - bless($return, "Mail::IMAPClient::BodyStructure::Address"); - } -subject: NIL | STRING - { - $return = $item{NIL} || $item{STRING} ; - $return||defined($return); - } -inreplyto: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} - -messageid: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} - -date: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} - -cc: NIL | "(" addressstruct(s) ")" - { $return = $item{NIL} || $item{'addressstruct(s)'} } - -bcc: NIL | "(" addressstruct(s) ")" - { $return = $item{NIL} || $item{'addressstruct(s)'} } - -from: NIL | "(" addressstruct(s) ")" - { $return = $item{NIL} || $item{'addressstruct(s)'} } - -replyto: NIL | "(" addressstruct(s) ")" - { $return = $item{NIL} || $item{'addressstruct(s)'} } - -sender: NIL | "(" addressstruct(s) ")" - { $return = $item{NIL} || $item{'addressstruct(s)'} } - -to: NIL | "(" addressstruct(s) ")" - { $return = $item{NIL} || $item{'addressstruct(s)'} } - -envelopestruct: "(" date subject from sender replyto to cc bcc inreplyto messageid ")" - { $return = {}; - foreach my $what (qw/date subject from sender replyto to cc bcc inreplyto messageid/) { - $return->{$what} = $item{$what}; - } - bless $return, "Mail::IMAPClient::BodyStructure::Envelope"; - $return||defined($return); - } - -basicfields: bodysubtype bodyparms bodyid(?) - bodydesc(?) bodyenc(?) - bodysize(?) { - - $return = { - bodysubtype => $item{bodysubtype} , - - bodyparms => $item{bodyparms} , - - bodyid => (ref $item{'bodyid(?)'} ? - $item{'bodyid(?)'}[0] : - $item{'bodyid(?)'} ), - - 'bodydesc' => (ref $item{'bodydesc(?)'} ? - $item{'bodydesc(?)'}[0] : - $item{'bodydesc(?)'} ), - - 'bodyenc' => (ref $item{'bodyenc(?)'} ? - $item{'bodyenc(?)'}[0] : - $item{'bodyenc(?)'} ), - - 'bodysize' => (ref $item{'bodysize(?)'} ? - $item{'bodysize(?)'}[0] : - $item{'bodysize(?)'} ), - }; - $return; -} - -textmessage: TEXT basicfields textlines(?) bodyMD5(?) bodydisp(?) bodylang(?) - { - $return = $item{basicfields}||{}; - $return->{bodytype} = 'TEXT'; - foreach my $what (qw/textlines(?) bodyMD5(?) bodydisp(?) bodylang(?)/) { - my $k = $what; $k =~ s/\(\?\)$//; - ref($item{$what}) and $return->{$k} = $item{$what}[0]; - } - $return||defined($return); - } - -othertypemessage: bodytype basicfields bodyparms(?) bodydisp(?) bodylang(?) - { $return = {}; - foreach my $what (qw/bodytype bodyparms(?) bodydisp(?) bodylang(?)/) { - my $k = $what; $k =~ s/\(\?\)$//; - $return->{$k} = ref($item{$what})? $item{$what}[0] : $item{$what} ; - } - while ( my($k,$v) = each %{$item{basicfields}} ) { $return->{$k} = $v } - $return||defined($return); - } - -messagerfc822message: - rfc822message bodyparms bodyid bodydesc bodyenc bodysize - envelopestruct bodystructure textlines - bodyMD5(?) bodydisp(?) bodylang(?) - { - $return = {}; - foreach my $what (qw/ bodyparms bodyid bodydesc bodyenc bodysize - envelopestruct bodystructure textlines - bodyMD5(?) bodydisp(?) bodylang(?) - / - ) { - my $k = $what; $k =~ s/\(\?\)$//; - $return->{$k} = ref $item{$what} =~ 'ARRAY'? - $item{$what}[0] : $item{$what}; - } - while ( my($k,$v) = each %{$item{bodystructure}[0]} ) { $return->{$k} = $v } - while ( my($k,$v) = each %{$item{basicfields}} ) { $return->{$k} = $v } - $return->{bodytype} = "MESSAGE" ; - $return->{bodysubtype}= "RFC822" ; - $return||defined($return); - } - -subpart: "(" part ")" - { - $return = $item{part} ; - $return||defined($return); - } - - -part: subpart(s) basicfields - bodyparms(?) bodydisp(?) bodylang(?) - - { - $return = bless($item{basicfields}, - "Mail::IMAPClient::BodyStructure"); - $return->{bodytype} = "MULTIPART"; - $return->{bodystructure} = $item{'subpart(s)'}; - foreach my $b (qw/bodyparms(?) bodydisp(?) bodylang(?)/) { - my $k = $b; $k =~ s/\(\?\)$//; - $return->{$k} = ref($item{$b}) ? $item{$b}[0] : $item{$b}; - } - $return||defined($return) ; - } - | textmessage - { - $return = bless $item{textmessage}, "Mail::IMAPClient::BodyStructure"; - $return||defined($return); - } - | messagerfc822message - { - $return = bless $item{messagerfc822message}, "Mail::IMAPClient::BodyStructure"; - $return||defined($return); - } - | othertypemessage - { - $return = bless $item{othertypemessage}, "Mail::IMAPClient::BodyStructure"; - $return||defined($return); - } - -bodystructure: "(" part(s) ")" - { - $return = $item{'part(s)'} ; - $return||defined($return); - } - -start: /.*\(.*BODYSTRUCTURE \(/i part(1) /\).*\)\r?\n?/ - { - #print STDERR "item = ",Data::Dumper->Dump([\%item],['$item']); - $return = $item{'part(1)'}[0]; - $return||defined($return); - } - -envelope: /.*\(.*ENVELOPE/ envelopestruct /.*\)/ { - $return = $item{envelopestruct} ; - $return||defined($return) ; - } diff --git a/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/Parse.grammar_old b/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/Parse.grammar_old deleted file mode 100755 index 4f6c518..0000000 --- a/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/Parse.grammar_old +++ /dev/null @@ -1,281 +0,0 @@ -# Directives -# ( none) -# Start-up Actions -{ - my $subpartCount = 0; - my $partCount = 0; -} - -# -# 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]; $return||defined($return);} - -# Strings: - -SINGLE_QUOTED_STRING: "'" /(?:\\'|[^'])*/ "'" { - - $return = $item{__PATTERN1__} ; - $return||defined($return); -} - -DOUBLE_QUOTED_STRING: '"' /(?:\\"|[^"])*/ '"' { - - $return = $item{__PATTERN1__} ; - $return||defined($return); -} - -QUOTED_STRING: DOUBLE_QUOTED_STRING | SINGLE_QUOTED_STRING { - - $return = $item{DOUBLE_QUOTED_STRING}||$item{SINGLE_QUOTED_STRING} ; - $return||defined($return); -} - -BARESTRING: ...!/^[)('"]/ /^(?!\(|\))(?:\\ |\S)+/ { - $return = $item{__PATTERN1__} ; $return||defined($return); -} - -STRING: QUOTED_STRING | BARESTRING { - $return = $item{QUOTED_STRING}||$item{BARESTRING} ; - $return||defined($return); -} - -OLDSTRING: /^"((?:[^"\\]|\\.)*)"/ | /^([^ \(\)]+)/ - { $item{__PATTERN1__} =~ s/^"(.*)"$/$1/; - $return = $item{__PATTERN1__} || $item{__PATTERN2__} ; - $return||defined($return); - } - -#BARESTRING: /^[^(]+\s+(?=\()/ -# { $return = $item[1] ; $return||defined($return);} - -textlines: NIL | NUMBER { $return = $item[1] || $item[2]; $return||defined($return); } -rfc822message: MESSAGE RFC822 { $return = "MESSAGE RFC822" } -key: STRING { $return = $item{STRING} ; $return||defined($return);} -value: NIL | '(' kvpair(s) ')'| NUMBER | STRING - { $return = $item{NIL} || - $item{NUMBER} || - $item{STRING} || - { map { (%$_) } @{$item{kvpair}} } ; - $return||defined($return); - } -kvpair: ...!")" key value - { $return = { $item{key} => $item{value} }; $return||defined($return);} -bodytype: STRING - { $return = $item{STRING} ; $return||defined($return);} -bodysubtype: PLAIN | HTML | NIL | STRING - { $return = $item{PLAIN}||$item{HTML}||$item{NIL}||$item{STRING} ; - $return||defined($return); - } -bodyparms: NIL | '(' kvpair(s) ')' - { - $return = $item{NIL} || - { map { (%$_) } @{$item{kvpair}} }; - $return || defined($return); - } -bodydisp: NIL | '(' kvpair(s) ')' - { - $return = $item{NIL} || - { map { (%$_) } @{$item{kvpair}} }; - $return || defined($return); - } -bodyid: ...!/[()]/ NIL | STRING - { $return = $item{NIL} || $item{STRING} ; $return||defined($return);} -bodydesc: ...!/[()]/ NIL | STRING - { $return = $item{NIL} || $item{STRING} ; $return||defined($return);} -bodyenc: NIL | STRING | '(' kvpair(s) ')' - { - $return = $item{NIL} || - $item{STRING} || - { map { (%$_) } @{$item{kvpair}} }; - $return||defined($return); - } -bodysize: ...!/[()]/ NIL | NUMBER - { $return = $item{NIL} || $item{NUMBER} ;$return||defined($return);} - -bodyMD5: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} -bodylang: NIL | STRING | "(" STRING(s) ")" - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} -personalname: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} -sourceroute: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} -mailboxname: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} -hostname: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} -addressstruct: "(" personalname sourceroute mailboxname hostname ")" - { $return = { - personalname => $item{personalname} , - sourceroute => $item{sourceroute} , - mailboxname => $item{mailboxname} , - hostname => $item{hostname} , - } ; - bless($return, "Mail::IMAPClient::BodyStructure::Address"); - } -subject: NIL | STRING - { - $return = $item{NIL} || $item{STRING} ; - $return||defined($return); - } -inreplyto: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} - -messageid: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} - -date: NIL | STRING - { $return = $item{NIL} || $item{STRING} ;$return||defined($return);} - -cc: NIL | "(" addressstruct(s) ")" - { $return = $item{NIL} || $item{addressstruct} } - -bcc: NIL | "(" addressstruct(s) ")" - { $return = $item{NIL} || $item{addressstruct} } - -from: NIL | "(" addressstruct(s) ")" - { $return = $item{NIL} || $item{addressstruct} } - -replyto: NIL | "(" addressstruct(s) ")" - { $return = $item{NIL} || $item{addressstruct} } - -sender: NIL | "(" addressstruct(s) ")" - { $return = $item{NIL} || $item{addressstruct} } - -to: NIL | "(" addressstruct(s) ")" - { $return = $item{NIL} || $item{addressstruct} } - -envelopestruct: "(" date subject from sender replyto to cc bcc inreplyto messageid ")" - { $return = {}; - foreach my $what (qw/date subject from sender replyto to cc bcc inreplyto messageid/) { - $return->{$what} = $item{$what}; - } - bless $return, "Mail::IMAPClient::BodyStructure::Envelope"; - $return||defined($return); - } - -basicfields: bodysubtype bodyparms bodyid(?) - bodydesc(?) bodyenc(?) - bodysize(?) { - - $return = { - bodysubtype => $item{bodysubtype} , - - bodyparms => $item{bodyparms} , - - bodyid => (ref $item{bodyid} ? - $item{bodyid}[0] : - $item{bodyid} ), - - bodydesc => (ref $item{bodydesc} ? - $item{bodydesc}[0] : - $item{bodydesc} ), - - bodyenc => (ref $item{bodyenc} ? - $item{bodyenc}[0] : - $item{bodyenc} ), - - bodysize => (ref $item{bodysize} ? - $item{bodysize}[0] : - $item{bodysize} ), - }; - $return; -} - -textmessage: TEXT basicfields textlines(?) bodyMD5(?) bodydisp(?) bodylang(?) - { - $return = $item{basicfields}||{}; - $return->{bodytype} = 'TEXT'; - foreach my $what (qw/textlines bodyMD5 bodydisp bodylang/) { - ref($item{$what}) and $return->{$what} = $item{$what}[0]; - } - $return||defined($return); - } - -othertypemessage: bodytype basicfields bodyparms(?) bodydisp(?) bodylang(?) - { $return = {}; - foreach my $what (qw/bodytype bodyparms bodydisp bodylang/) { - $return->{$what} = ref($item{$what})? $item{$what}[0] : $item{$what} ; - } - while ( my($k,$v) = each %{$item{basicfields}} ) { $return->{$k} = $v } - $return||defined($return); - } - -messagerfc822message: - rfc822message bodyparms bodyid bodydesc bodyenc bodysize - envelopestruct bodystructure textlines - bodyMD5(?) bodydisp(?) bodylang(?) - { - $return = {}; - foreach my $what (qw/ bodyparms bodyid bodydesc bodyenc bodysize - envelopestruct bodystructure textlines - bodyMD5 bodydisp bodylang - / - ) { - $return->{$what} = ref $item{$what} =~ 'ARRAY'? - $item{$what}[0] : $item{$what}; - } - while ( my($k,$v) = each %{$item{bodystructure}[0]} ) { $return->{$k} = $v } - while ( my($k,$v) = each %{$item{basicfields}} ) { $return->{$k} = $v } - $return->{bodytype} = "MESSAGE" ; - $return->{bodysubtype}= "RFC822" ; - $return||defined($return); - } - -subpart: "(" part ")" - { - $return = $item{part} ; - $return||defined($return); - } - - -part: subpart(s) basicfields - bodyparms(?) bodydisp(?) bodylang(?) - - { - $return = bless($item{basicfields}, "Mail::IMAPClient::BodyStructure"); - $return->{bodytype} = "MULTIPART"; - $return->{bodystructure} = $item{subpart}; - foreach my $b (qw/bodyparms bodydisp bodylang/) { - $return->{$b} = ref($item{$b}) ? $item{$b}[0] : $item{$b}; - } - $return||defined($return) ; - } - | textmessage - { - $return = bless $item{textmessage}, "Mail::IMAPClient::BodyStructure"; - $return||defined($return); - } - | messagerfc822message - { - $return = bless $item{messagerfc822message}, "Mail::IMAPClient::BodyStructure"; - $return||defined($return); - } - | othertypemessage - { - $return = bless $item{othertypemessage}, "Mail::IMAPClient::BodyStructure"; - $return||defined($return); - } - -bodystructure: "(" part(s) ")" - { - $return = $item{part} ; - $return||defined($return); - } - -start: /.*\(.*BODYSTRUCTURE \(/i part(1) /\).*\)\r?\n?/ - { - $return = $item{part}[0] ; - $return||defined($return); - } - -envelope: /.*\(.*ENVELOPE/ envelopestruct /.*\)/ { - $return = $item{envelopestruct} ; - $return||defined($return) ; - } diff --git a/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/Parse.pod b/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/Parse.pod deleted file mode 100755 index 16813ef..0000000 --- a/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/Parse.pod +++ /dev/null @@ -1,21 +0,0 @@ -package Mail::IMAPClient::BodyStructure::Parse; -$Mail::IMAPClient::BodyStructure::Parse::VERSION = "0.0.1"; -$Mail::IMAPClient::BodyStructure::Parse::VERSION = "0.0.1"; - -=head1 NAME - -Mail::IMAPClient::BodyStructure::Parse -- used internally by Mail::IMAPClient::BodyStructure - -=head1 DESCRIPTION - -This module is used internally by L and is -generated using L. 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 and is not meant to -be used or called directly from applications. So don't do that. - -=cut - diff --git a/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/t/parse.t b/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/t/parse.t deleted file mode 100755 index 33042b9..0000000 --- a/W/Mail-IMAPClient-2.2.9/BodyStructure/Parse/t/parse.t +++ /dev/null @@ -1,39 +0,0 @@ -# Before `make install' is performed this script should be runnable with -# `make test'. After `make install' it should work as `perl test.pl' -# $Id: parse.t,v 1.2 2002/08/30 20:48:34 dkernen Exp $ -######################### We start with some black magic to print on failure. - -# Change 1..1 below to 1..last_test_to_print . - -use Mail::IMAPClient::BodyStructure::Parse; - -BEGIN { - print "1..1\n"; - $main::loaded = 1; - $| = 1; - print "ok 1\n"; -} -END {print "not ok 1\n" unless $main::loaded;} - - -# History: -# $Log: parse.t,v $ -# Revision 1.2 2002/08/30 20:48:34 dkernen -# -# # -# Modified Files: -# Changes IMAPClient.pm MANIFEST Makefile Makefile.PL README -# Todo test.txt -# BodyStructure/Parse/Makefile -# BodyStructure/Parse/Parse.pm -# BodyStructure/Parse/Parse.pod -# BodyStructure/Parse/t/parse.t -# for version 2.2.1 -# # -# -# Revision 1.1 2002/08/23 14:34:29 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 -# diff --git a/W/Mail-IMAPClient-2.2.9/BodyStructure/t/bodystructure.t b/W/Mail-IMAPClient-2.2.9/BodyStructure/t/bodystructure.t deleted file mode 100755 index ed57256..0000000 --- a/W/Mail-IMAPClient-2.2.9/BodyStructure/t/bodystructure.t +++ /dev/null @@ -1,55 +0,0 @@ -# Before `make install' is performed this script should be runnable with -# `make test'. After `make install' it should work as `perl test.pl' -# $Id: bodystructure.t,v 1.1 2002/08/23 14:34:40 dkernen Exp $ -######################### We start with some black magic to print on failure. - -# Change 1..1 below to 1..last_test_to_print . - -use Mail::IMAPClient::BodyStructure; -use warnings; - -BEGIN { - print "1..8\n"; - $main::loaded = 1; - $| = 1; - print "ok 1\n"; -} -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) ; -if ($bsobj) { print "ok 2\n" } else { - print "not ok 2\n"; - exit; -} -if ($bsobj->bodytype eq 'TEXT') { print "ok 3\n" } -else {print "not ok 3 (expected 'TEXT' ; got '" . $bsobj->bodytype . "')\n"} -if ($bsobj->bodysubtype eq 'PLAIN') { print "ok 4\n" } -else {print "not ok 4 (expected 'PLAIN' ; got '" . $bsobj->bodytype . "')\n"} - -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) ; -if ($bsobj) { print "ok 5\n" } else {print "not ok 5\n"} -if ($bsobj->bodytype eq 'MULTIPART') { print "ok 6\n" } -else {print "not ok 6 (expected 'MULTIPART' ; got '" . $bsobj->bodytype . "')\n"} -if ($bsobj->bodysubtype eq 'MIXED') { print "ok 7\n" } -else {print "not ok 7 (expected 'MIXED' ; got '" . $bsobj->bodytype . "')\n"} -if (join("#",$bsobj->parts) eq "1#2#2.HEAD#2.1#2.2#2.2.HEAD#2.2.1#2.2.1.1#2.2.1.2") { -print "ok 8\n"; -} else {print "not ok 8\n"} - -END {print "not ok 1\n" unless $main::loaded;} - - -# History: -# $Log: bodystructure.t,v $ -# Revision 1.1 2002/08/23 14:34:40 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 -# diff --git a/W/Mail-IMAPClient-2.2.9/COPYRIGHT b/W/Mail-IMAPClient-2.2.9/COPYRIGHT deleted file mode 100644 index d5cdcf8..0000000 --- a/W/Mail-IMAPClient-2.2.9/COPYRIGHT +++ /dev/null @@ -1,21 +0,0 @@ -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. - diff --git a/W/Mail-IMAPClient-2.2.9/Changes b/W/Mail-IMAPClient-2.2.9/Changes deleted file mode 100644 index 359084e..0000000 --- a/W/Mail-IMAPClient-2.2.9/Changes +++ /dev/null @@ -1,1306 +0,0 @@ -Revision History for Perl extension Mail::IMAPClient. -Changes in version 2.2.9 ------------------------- -Fixed problem in migrate that caused problems in versions of perl earlier than -5.6. Thanks go to Steven Roberts for reporting the problem and identifying its -cause. - -Fixed problem in the make process that caused tests for BodyStructure subclass -to fail if the grammer had been compiled under a different version of -Parse::RecDescent. This problem was detected by the dedicated people at -testers@cpan.org. - -Fixed a compatibility problem using Parse::RecDescent version 1.94. -This caused BodyStructure and Thread to fail for 5.8.x users. A number -of people reported this bug to CPAN but it took me a while to realize what -was going on. Really it took me a while to realize my Parse::RecDescent was -out of date. ;-) Now this module is delivered with two versions of each of -the affected grammars and Makefile.PL determines which version to use. -Upgrading to Parse::RecDescent 1.94 will require you to re-run Makefile.PL -and reinstall Mail::IMAPClient. - -Changes in version 2.2.8 ------------------------- -Change the login method so that it always send password as a literal to get around -problem 2544 reported by Phil Tracy which caused passwords containing asterisks to -fail on some systems (but not any of mine...). Good catch, Phil. - -Added a new example that demonstrates the use of imtest (a utility that comes with -Cyrus IMAP) and Mail::IMAPClient together. The example uses imtest to do secure -authentication and then "passes" the connection over to Mail::IMAPClient (but -imtest is still brokering the encryption/decryption). This example comes from -an idea of Tara L. Andrews', whose brainstorm it was to use imtest to broker secure -connections. (But I still want to get encryption working with Mail::IMAPClient some -day!) - -Fixed an error in which a "+" was used as a conncatenation error instead of a ".". -Thanks to Andrew Bramble for reporting this, even though he mistakenly identified -it as a "typo". It is not a typo; a plus sign is the correct concatenation operator, -as any decent Java book will tell you ;-) - -Fixed an error in the login method when the password contains a special character -(such as an asterisk.) Thanks to Phil Tracey for reporting this bug. - -Fixed some bugs in _send_line (the "O" side of the I/O engine) that were -reported by Danny Smith. - -Fixed a bug in the migrate method in the optimization code (which -gets called when socket writes are delayed due to a slow or busy target -host, aka EAGAIN errors). Thanks to Pedro Carvalho for identifying -this bug and its cause. - -Fixed a bug in migrate that caused migration of unread messages to fail. -This was due to the way Mail::IMAPClient's migrate method would try to send -an empty list of flags to the target server in the APPEND. Thanks to -Stephen Fralich at Syracuse University and for reporting this bug. - -Fixed another bug in the migrate method that caused flags to get lost. Thanks -go to Jean-Michel Besnard for reporting this. - -Fixed a bug in migrate that caused -Fixed a bug in get_envelope that caused it to fail under certain conditions. -Thanks go to Bob Brown for reporting this bug. - - -Changes in version 2.2.7 ------------------------- - -Added some new parameters to support alternate authentication mechanisms: - - Prewritemethod - Readmethod - -Mail::IMAPClient has supported cram-md5 authentication "out of the box" -as of 2.2.6 (courtesy of Ville Skyttä). I also have digest-md5 working -in my lab with quality of protection levels "auth" and "integrity", but -not "confidentiality". I'm hoping to get the confidentiality part working -soon but so far have only managed to authenticate, send an encrypted command, -and receive and decrypt the response. This may sound like enough but I can't -seem to send a second command or receive a second response;-( In any event -2.2.8 will support at least qop=auth and qop=auth-int but maybe not -qop=auth-conf. - -Fixed a bug reported by Adrian that caused get_bodystructure to -fail if the server returned a bodystructure with an embedded -literal. Also fixed the same bug in get_envelope, so I guess now -everyone knows that get_envelope was just a tinkered-with copy of -get_bodystructure... - -Fixed two related bugs in Parser.pm that caused -get_bodystructure and get_envelope to fail if the -UID nnnnn part of a fetch response follows all the -other stuff. Thanks to Raphaël Langella for reporting this bug. - -Enhanced several methods to use MessageSets when the -Ranges parameter is true. There are still more methods that -need to be retrofitted to take advantage of the Range method -(and its underlying MessageSet object). In the meantime, if you -need to get the functionality of the shorter message ranges provided -by the Range method from a method that does not honor the Ranges -parameter, then you should a) create a message set by passing the -messages to the Range method and then pass the scalar as a string -to the method you want to use. For example, if you want to move -a whole lot of messages to Trash, do something like this: -> ->my $range = $imap->Range(scalar($imap->search("SentBefore", "01-Jan-2000"))); ->$imap->move("Trash","$range"); -> -This will cause the range object to stringify out to what looks like -a non-reference scalar before the move method gets the argument. If you -omit the quotes around "$range" then this won't work. - -Fixed a bug in the list method that caused LIST "" "" to fail miserably. -Thanks to John W Sopko Jr. for reporting this bug. - -Fixed a bug in the test suite that caused the cram-md5 tests to fail -if you are not running the extended tests. (Introduced in 2.2.6) - -Fixed a bug that affected users on platforms that do not support -fcntl (i.e. NT). Thanks to Raphaël Langella for reporting this bug. - -Changes in version 2.2.6 ------------------------- - -Fixed a bug in the migrate method that caused the internaldate -of migrated messages to sometimes be wrong. Credit goes to Jen Wu -for identifying both bug and fix. - -Added a new method, "get_header", to provide a short-cut for a common -use of parse_headers. Added two other methods, "subject" and "date", -to provide shortcuts to get_header. - -Changed the Mail::IMAPClient::MessageSet module to override array -dereferencing. (See below.) - -Changed fetch and search methods to use the Range method (and thus the -Mail::IMAPClient::MessageSet module) for messages. The fetch method will -use MessageSet objects all the time, but the search method will only -return MessageSet objects if you specify "Ranges => 1" (with Ranges being -a new parameter). The default will be "Ranges => 0" (which preserves -the old behavior) but this default will go away in some future release. -There should be no need to override the fetch method's new behavior, since -it will be transparent to you unless you tend to fetch a lot of messages -at once, in which case your fetches may be faster and perhaps less likely -to fail due to the request exceeding your server's line limit. If you set -the Ranges parameter to true, then you still should not see a difference, -because a) when fetch is called in a list context then you will not get -a MessageSet object, you'll get the same list as always, and b) the -MessageSet objects now override array de-referencing operations, so if you -treat the returned MessageSet object as if it were an array then the object -will humour you and act like a reference to an array of messages sequence -numbers or message uids. - -Also changed the flags method to use the Range method. This should also -be transparent since the methods arguments and return values do not change. - -Added built-in support for CRAM-MD5 authentication. This authentication -method will in this release be used only when requested. In future releases -the default authentication will probably be the strongest authentication -supported "out of the box" that is available on your server. Since CRAM-MD5 -is the only authentication other than plain text that is currently supported -"out of the box", it will be the default authentication mechanism for any -server that supports it. See the pod for the Authmechanism and Authcallback -parameters (which were also added in this release) and the doc for the -authenticate method (which has been around a while). Many thanks to Ville Skyttä -for providing the code that makes up the heart of this new support, as well -as to Gisle Aas for the Digest::HMAC_MD5 and MIME::Base64. - -Made minor tweaks to the documentation. Again. (Will it ever be 100% right?) - -Changes in version 2.2.5 ------------------------- -Added the Range method to convert a bunch of message UID's or sequence numbers -into compact ranges. Also added a supporting class for the returned range -objects with overloaded operators that support stringifying, adding to, and -deleting from a range object's message set (Mail::IMAPClient::MessageSet). -I also wrote documentation for same, so check it out. In future releases, -I will probably enhance the base module to use MessageSet objects when -feasible (i.e. whenever I know that the argument in question should in fact -be a message specification). But I'll let you find all the bugs in the -MessageSet module first ;-) Thanks goes to Stefan Schmidt, who is the first -to report using a server that restricted the size of a client request to -something smaller than what Mail::IMAPClient was generating for him. -(Originally the Range method was just supposed condense a message set into -the shortest possible RFC2060-compliant string, but then I got all happy and -started adding features. You know how it is...) - - -Changes in version 2.2.4 -------------------------- -Fixed a bug in the done method (new in 2.2.3). - -Added tests for idle and done. (That's how I found the bug in the done method, above.) - -Fixed minor bugs in test suite. (The test suite worked but wasn't always using the options -I wanted tested. ) - - -Changes in version 2.2.3 -------------------------- - -NOTE: This version was distributed to beta testers only. - -Fixed the "Changes in version 2.2.2" section so that it correctly specifies -version 2.2.2 (instead of being yet another 2.2.1 section). - -Fixed a bug in the migrate method that affected folders with spaces in their -names. - -Fixed a bug in the Massage method that affected folders with braces ({}) in -their names. - -Added a new class method, "Quote", that will quote your arguments for you. (So you -no longer have to worry so much about quoting your quotes. - -Added optimizations to the migrate method and to the core I/O engine inspired -by Jules Agee. (Actually they were not so much inspired by him as they were -lifted right out of a patch he had out on sourceForge.net. I had to refit them -for this version, and reformat his comments so they could fit in my window. Thanks -Jules, wherever you are.) - -Added the fetch_hash method, which will fetch an entire folder's contents into a -hash indexed by message UID (or message sequence number if that's all you've got). - -Added a new example to the examples subdirectory, and corrected some minor bugs -in existing examples. - -Added the idle and done methods, which together implement the IMAP IDLE extension -(RFC2177), at John Rudd's suggestion. - -Changes in version 2.2.2 ------------------------- -Fixed a bug in Massage method (generally only used by other IMAPClient methods) -that broke folder names with parens. - -Updated bug reporting procedures. Also added a section in the documentation -for REPORTING THINGS THAT ARE NOT BUGS. Bug tracking is now done via -rt.cpan.org, which I stumbled upon quite by accident and with which I am -really pleased. A lot of credit goes to _somebody_ for putting this -out on CPAN. Unfortunately as of this writing I don't whom. - -Fixed a bug in the documentation regarding the logoff method, which is never -implicitly invoked anymore; I gave up on that because the DESTROY method would -sometimes be called after the Socket handle was already destroyed. (This is -especially likely at program exit, when everything still in scope goes out of -scope at the same time.) You should always log off explicitly if you want to -be a well behaviod IMAP client. - -Changes in version 2.2.1 ------------------------- -Updated append_string to wrap the date argument in double quotes if the argument was -provided without quotes. Thanks to Grant Waldram for pointing out that some IMAP -servers require this behavior. - -Added a new method, selectable, which returns a true value if a folder is selectable. - -Documented in this Changes file a change that was actually made for 2.2.0, in which -newlines are chomped off of $@ (but not LastError). - -Added pointers in the documentation to point to Mark Bush's Authen::NTLM module. This -module will allow you to use NTML authentication with Mail::IMAPClient connections. -Also changed the authenticate method so that it will work with Authen::NTML without -the update mentioned in NTLM::Authen's README. - -Added a second example on using the new migrate method, migrate_mail2.pl. This example -demonstrates more advanced techniques then the first, such as using the separator method -to massage folder names and stuff like that. - -Added support for the IMAP THREAD extension. Added Mail::IMAPClient::Thread.pm to support -this. (This pm file is generated during make from Thread/Thread.grammar.) This new -function should be considered experimental. Note also that this extension has nothing -to do with threaded perl or anything like that. This is still on the TODO list. - -Updated the search, sort, and thread methods to set $@ to "" before attempting their -respective operations so that text in $@ won't be left over from some other error and -therefore always indicative of an error in search, sort, or thread, respectively. - -Made many many tweaks to the documentation, including adding more examples (albeit -simple ones) and fixing some errors. - -Changes in version 2.2.0 ------------------------- -Fixed some tests so that they are less likely to give false negatives. For example, test -41 would fail if the test account happened to have an empty inbox. - -Made improvements to Mail::IMAPClient::BodyStructure and renamed Mail::IMAPClient::Parse -to Mail::IMAPClient::BodyStructure::Parse. (This should be transparent to apps since the -...Parse helper module is used by BodyStructure.pm only.) I also resumed my earlier practice -of using ...Parse.pm from within BodyStructure.pm to avoid the overhead of compiling the -grammar every time you use BodyStructure.pm. (Parse.pm is just the output from saving -the compiled Parse::RecDescent grammar.) In a related change, I've moved the grammar into -its own file (Parse.grammar) and taught Makefile.PL how to write a Makefile that converts -the .grammar file into a .pm file. This work includes a number of fixes to how a body structure -gets parsed and the parts list returned by the parts method, among other things. I was able -to successfully parse every bodystructure I could get my hands on, and that's a lot. - -Also added a bunch of new methods to Mail::IMAPClient::BodyStructure and its child classes. -The child classes don't even have files of their own yet; they still live with -their parent class! Notable amoung these changes is support for the FETCH ENVELOPE IMAP -command (which was easy to build in once the BODYSTRUCTURE stuff was working) and some -helper modules to get at the envelope info (as well as envelope information for -MESSAGE/RFC822 attachments from the BODYSTRUCTURE output). Have a look at the -documentation for Mail::IMAPClient::BodyStructure for more information. - -Fixed a bug in the folders method regarding quotes and folders with spaces in the names. The -bug must have been around for a while but rarely manifested itself because of the way -methods that take folder name arguments always try to get the quoting right anyway but -it was still there. Noticing it was the hard part (none of you guys reported it to me!). - -Fixed a bug reported by Jeremy Hinton regarding how the search method handles dates. It was -screwing it all up but it should be much better now. - -Added the get_envelope method which is like the get_bodystructure method except for in ways -in which it's different. - -Added the messages method (a suggestion from Danny Carroll), which is functionally -equivalent to $imap->search("ALL") but easier to type. - -Added new arguments to the bodypart_string method so that you can get just a part of a part -(or a part of a subpart for that matter...) I did this so I could verify BodyStructure's -parts method by fetching the first few bytes of a part (just to prove that the part has a -valid part number). - -Added new tests to test the migrate function and to do more thorough testing of the -BodyStructure stuff. Also added a test to make sure that searches that come up empty handed -return an undef instead of an empty array (reference), regardless of context. Which reminds -me... - -Fixed a bug in which searches that don't find any hits would return a reference to an empty -array instead of undef when called in a scalar context. This bug sounds awfully familiar, -which is why I added the test mentioned above... - - -Changes in version 2.1.5 ------------------------- -Fixed the migrate method so now it not only works, but also works as originally -planned (i.e. without requiring source messages to be read entirely into memory). -If the message is smaller than the value in the Buffer parameter (default is 4096) then -a normal $imap2->append($folder,$imap1->message_string) is done. However, if the message -is over the buffer size then it is retrieved and written a bufferful at a time until the -whole message has been read and sent. (The receiving server still expects the entire -message at once, but it will have to wait because the message is being read from the -source in smaller chunks and then written to the destination a chunk at a time.) -This needs extensive testing before I'd be willing to trust it (or at least extensive -logging so you know when something has gone terribly wrong) and I consider this method -to be in BETA in this release. (Numerous people wrote complaining that migrate didn't -work, and some even included patches to make it work, but the real bug in the last -release wasn't that migrate was broken but that I had inadvertently included the pod -for the method which I knew perfectly well was not ready to be released. My apologies -to anyone who was affected by this.) The migrate method does seem to work okay on -iPlanet (i.e. Netscape) Messenger Server 4.x. Please let me know if you have any -issues on this or any other platform. - -Added a new example, migrate_mbox.pl, which will demonstrate the migrate method. - -Fixed a bug that will cause Mail::IMAPClient's message reading methods to misbehave if -the last line of the email message starts with a number followed by a space and either -"OK", "NO", or "BAD". This bug was originally introduced in 1.04 as a fix for another -bug, but since the fix supports noncompliant behavior I'm disabling this behavior by -default. If your IMAP clients start hanging every time you try to read literal text -(i.e. a message's test, or a folder name with spaces or funky characters) then you -may want to turn this on with the EnableServerResponseInLiteral parameter. Thanks go -to Manpreet Singh for reporting this bug. - -Fixed a bug in imap_to_mbox.pl that has been there since 2.0.0 (when the Uid -parameter started defaulting to "True"). Thanks to Christoph Viethen for reporting -the bug and suggesting the fix. BUT NOTE THIS: I often don't test the example programs, -so you should think of them as examples and not free production programs. Eventually -I would like to add tests to my test suite (either the 'make test' test suite that you -run or my own more extensive test suite) but it's not a super high priority right now. - -Significant improvements to the whole Mail::IMAPClient::BodyStructure module -were contributed by Pedro Melo Cunha. It's really much better now. - -Bullet-proofing added to some private methods. (Private meaning they are undocumented -and not part of the module's API. This is perl not java.) - -Fix applied to unset_flag to support user-defined flags (thanks to E.Priogov -for submitting the bug report and patch). - - -Changes in version 2.1.4 ------------------------- -Added Paul Warren's bugfix to the sort method. - -Added Mike Halderman's bugfix for the get_bodystructure method. - -Fixed a localization problem reported by Ivo Panecek. Because of this fix, -the Errno.pm file is now a prerequisite to this module. This way I can just -test to see if the error is an "EAGAIN" error (as defined in sys/errno.h and thus -Errno.pm) instead of awkwardly checking the string value of $!. - -I also renamed the MaxTempErrors parameter to Maxtemperrors in response the same -bug report. Added a "MaxTempErrors" accessor method that will set and return -Maxtemperrors for backwards compatibility. Also, the number of temporary errors -gets reset after each successful I/O, so that the socket i/o operation fails only if -you if your temporary I/O errors happen more than "Maxtemperrors" times in a row. -The old behavior was to continue incrementing the count of temporary errors until -either the entire message was written or until a total of Maxtemperrors had occurred, -regardless of how many intervening successful syswrites occurred. This was a bug, but -Ivo politely suggested the new behavior as an enhancement. ;-) Also, you can now -specify "UNLIMITED" as the Maxtemperrors, in which case these errors will be ignored. -And the default for Maxtemperrors is now 100, but I'm open to any feedback you may -have in this regard. - -I also fixed the operator precedence problem that was reported by many folks in that -very same part of the code. (As you may have guessed, that code was new in the last -version!) - -One of the people who reported the precedence problem was Jules Agee, who also submitted -a patch that may in the end provide an optimal solution to handling EAGAIN errors. -Unfortunately I have not had time to retrofit his patch into the current version of the -module. But if I can manage to do this soon and it tests well I'll include it in the next -release, in which case the Maxtemperrors parameter will be of interest only to historians. - -I also received a patch from John Ello that adds support for Netscape's proprietary -PROXYAUTH IMAP client command. I haven't included that support in this release because -you can already use the proxyauth method. It's one of those famous "default" methods -that, despite their fame and my documentation, nobody seems to know about. But you -can always say "$imap->proxyauth($uid)", for example, providing that $imap and $uid -are already what they're supposed to be. (I've been doing this myself for years.) - -However, John's patch does provide a cleaner interface (it remembers who you are as -well as who you were, for example) so I may include it later as part of a separate -module that extends Mail::IMAPClient. This would also give me an excuse for providing -the framework for plugging in Administrative methods that are proprietary to other imap -servers, so if you have a technique for acquiring administrative access to your users' -mailboxes (besides proxyauth) please let me know what it is. Perhaps we'll get something cool out of it, like a document on how to write administrative scripts for various -platforms and a suite of supporting methods for each. - -Changes in version 2.1.3 ------------------------- -Added the new method append_string. It works similarly to append but will allow extra -arguments to supply the flags and internal date of the appended message. See the pod -for more details. - -(Thanks to Federico Edelman Anaya for suggesting this fix.) - -Fixed a bug in the AUTOLOAD subroutine that caused "myrights" (and possibly other -non-existant methods) to fail. Thanks go to Larry Rosenbaum for reporting the bug -and identifying the fix. - -Added the new method Escaped_results, which preprocesses results so that data -containing certain special characters are returned quoted with special characters -(like quotes!) escaped. (I needed this for the bodystructure stuff, below.) - -NEW! Added support for parsing bodystructures (as provided in the server response to -FETCH BODYSTRUCTURE). This support requires Parse::RecDescent and is implemented via two -new modules, Mail::IMAPClient::BodyStructure and Mail::IMAPClient::Parse. Note that -the latter module is used by the former; your programs need not and should not use it -directly so don't. Also, these modules are ALPHA and EXPERIMENTAL so no screaming when -they don't work. (Polite bug reports will of course be gratefully accepted.) Many -thanks to Damian Conway, the author of Parse::RecDescent, without which this feature -would not have been possible (or at least not very likely). - -Enhanced support for DOS systems (and DOS's offspring, such as windows) by removing -the "\c\n"s and replacing them with "\x0d\x0a". Thanks go to Marcio Marchini for his -help with this effort. - -Fixed the list of symbols imported along with Fcntl.pm. (Paul Linder asked me to put -this in the last release but I forgot.) - -Changes in version 2.1.2 ------------------------- - -Fixed a bug in the is_parent method which made it inaccurate on some servers. - -Added new method "sort", which implements the SORT extenstion and which was contributed -by Josh Rotenberg. The SORT extension is documented at -http://search.ietf.org/internet-drafts/draft-ietf-imapext-sort-06.txt. A copy of the -draft is also included with the Mail::IMAPClient distribution, which means I also: - -Added draft-ietf-imapext-sort-06.txt to the docs subdirectory of the distribution. - -Fixed a bug in the folders method and the subscribed method (same bug, appeared twice) -which broke these methods under some conditions. Thanks again Josh Rotenberg for supplying the fix. - -Fixed bugs in getacl and listacl. Changed the interface for getacl significantly; -existing scripts using getacl will not behave the same way. But then on the other hand, -getacl was never documented before, so how could you be using it? - -Implemented improvements to reduce memory usage by up to 30%. Thanks go Paul Linder, -who developed the memory usage patch after a considerable amount of analysis. The -improvements include the use of 'use constant', so your perl needs to support that -pragma in order to use Mail::IMAPClient. - -Added a new parameter, MaxTempErrors, which allows the programmer to control the number -of consecutive "Resource Temporarily Unavailable" errors that can occur before a write -to the server will fail. Also changed the behavior of the client when one of these -errors occurs. Previously, Mail::IMAPClient waited .25 seconds (a quarter of one -second) before retrying the read operation. Now it will wait (.25 * the number of -consecutive temporary errors) seconds before retrying the read. - -Documented the "Buffer" parameter, which has been secretly available for some time. I -just forgot to document it. It sets the size of the read buffer when Fast_io is turned -on. (NOTE: As of version 2.1.5 it also controls the size of the buffer used by the -migrate method.) - -Updated the Todo file. It was nice to see that a number of lines in the "Todo" file were now deletable. It was depressing to see that a number of original lines need to stay -in there. - - -Changes in version 2.1.1 ------------------------- -Added the "mark", "unmark", and imap4rev1 methods. - -Updated the documentation to include the new methods and to document "create", "store", -and "delete". - -Updated "message_string" to be smart about whether you're using IMAP4 or IMAP4REV1. - -Updated "message_to_file" to be smart about whether you're using IMAP4 or IMAP4REV1. - -Added several bug fixes to authenticate method. Many thanks to Daniel Wright who -reported these bugs and provided the information necessary to fix them. - - -Changes in version 2.1.0 ------------------------- - -Fixed a serious bug introduced in 2.0.9 when appending large messages. - -Made minor changes to improve the cyrus_expunge.pl example script. - -Made the set_flags routine RFC2060-compliant. Previously it prepended flag names with -backslashes, even if the flags were not reserved flags. This broke support for -user-defined flags, which I didn't realize was supposed to even be there until Scott -Renner clued me in. (Thanks, Scott.) - -Promoted the release level to "1". - -Added a new 'internaldate' method. (Thanks to the folks at jwm3.org for donating the -code!) - -Added a new example, cyrus_expire.pl. - -Changes in version 2.0.8/2.0.9 ------------------------------- -Made minor changes to the tests in t/basic.t so that folders are explicitly closed -before they are deleted. (Don't worry, only folders created by the tests are -deleted. :-) Thanks go to Alan Young for reporting that some servers require this. - -Changed the routine that massages folder names into IMAP-compliant strings so that -single-quotes in a name do not force the folder to go through as "LITERAL" strings -(as defined in RFC2060). This shouldn't cause a problem for anybody (and in fact -should make life easier for some folks) but if you do have any trouble with -single-quotes in folder names PLEASE LET ME KNOW ASAP!! - -Divided the sending of literal strings into two I/O operations (as required by RFC2060). -This should correct problems with sending literals to some servers that will not read -any data sent before they reply with the "+ go ahead" message. (Thanks go to Keith Clay, -who reported seeing this problem with the M-Store IMAP server.) - -Changed the "create" method so that it will autoquote the first argument to create -rather than the last. Normally the first argument is the last, but Cyrus users can -specify an optional 2nd argument, except when using pre-2.0.8 versions of -Mail::IMAPClient ;-) Thank you Chris Stratford for reporting this bug and -identifying its cause. - -Fixed a bug in body_string when the message is empty. (Thanks go to Vladimir Jebelev for -finding this bug and providing the fix.) - -Added a new example to the examples subdirectory. cyrus_expunge.pl is a script you -can use (after making minor tweaks) to periodically expunge your server's mail store. - -Changes in version 2.0.7 ------------------------- -Fixed a bug in message_count. Thanks go to Alistair Adams for reporting this bug. - -Fixed a bug in folders that caused some foldernames to not be reported in the -returned array. - -Changes in version 2.0.6 ------------------------- - -Applied patches from Phil Lobbe to tighten up sysreads and 'writes and to correct a -bug in the I/O engine. - -Changes in version 2.0.5 ------------------------- - -Fixed bug in parse_headers so that RFC822 headers now match the pattern /(\S*):\s*/ -instead of /(\S*): /. Thanks go to Paul Warren for reporting this bug and providing the -fix. - -Added more robust error checking to prevent infinite loops during read attempts and -fixed bugs in parse_headers. Thanks go to Phil Lobbes, who provided several useful -patches and who performed valuable pre-release testing. - -Changes in version 2.0.4 ------------------------- - -Fixed bug in parse_headers when connected to an Exchange server with UID=>1. (Kudos to -Wilber Pol for that fix.) - -Fixed bugs in parse_headers and tightened reliability of I/O engine by implementing -many improvements suggested by Phil Lobbes, who also provided code for same. - -Added bugfix that under certain conditions caused server responses to be "repeated" -when fast_io is turned on. Thanks to Jason Hellman for providing bug report and -diagnostic data to fix this. - -Added a "LastIMAPCommand" method, which returns the last IMAP client command that -was sent to the server. - -Removed the "=begin debugging" paragraph that somehow got included in CPAN's -html pages (even though it shouldn't have). - -Began a process of redesigning the documentation. I would like to be able to present -a more formal syntax for the various methods and hope to have that ready for the next -release. - -Tested successfully against Cyrus v 2.0.7. - -Tested unsuccessfully against mdaemon. This appears to be due to mdaemon's -noncompliance with rfc2060 so future support for mdaemon should not be expected -any time soon. ;-( - - -Changes in version 2.0.3 ------------------------- - -Did major rewrite of message_string method, which should now be both cleaner -and more reliable. - -Fixed bug in move method that caused some folders to be incorrectly quoted. -Thanks go to Felix Finch for reporting this bug. Also, at his suggestion I -added information to move documentation explaining the need to expunge. - -Made many fixes and tweaks to pod text. - -Added a new method, Rfc2060_date, which takes times in the "seconds since 1/1/1970" -format and returns a string in RFC2060's "dd-Mon-yyyy" format (which is the format -you need to use in IMAP SEARCH commands). - -Changes in version 2.0.2 ------------------------- -Fixed bug that caused a compile error on some earlier versions of perl5. - -Noticed that some older versions of perl give spurious "Ambiguous use" warnings -here and there, mostly because I'm not quoting the name of the "History" member -of the underlying Mail::IMAPClient hash. These warnings will go away when you upgrade -perl. (I may fix them later, or maybe not. Depends on if I have time.) - -Added new parameter (and eponymous method) Peek, along with new tests for 'make test' -for same. See the pod for further info. - -Added some error checking to avoid trying to read or write with an -unconnected IMAPClient object. - -Made bug fixes to parse_headers and flags. - -Added missing documentation for the exciting new message_to_file method (oops). -Also cleaned up a few typos in the pod while I happened to be there. (I'm sure -there are still plenty left.) - -Fixed bugs in append and append_file. (Thanks to Mauro Bartolomeoli and to the people -at jwm3.org for reporting these bugs.) - -Made changes to call to syswrite to guarantee delivery of entire message. (Only affects -appends of very large messages.) - -Added the 'close' method to the list of lower-case-is-okay methods (see the section -under version 2.0.0 on "NEW ERROR MESSAGES"). - -Changes in version 2.0.1 ------------------------- -Several bug fixes related to the flags method and to spurious warning messages -when run with warnings turned on. - -A new method, message_to_file, writes message text directly into a file. This -bypasses saving the text in the history buffer and the overhead that entails, which -could be especially important when processing big ass messages. Of course the bad news -is that now you'll have to write all that shtuff out to a filehandle, but maybe you -wanted to do that anyway. Anyhow, between append_file and message_to_file, both -of which take filehandle arguments, there should be a way to "short circuit" the -copying of mail between two imap sessions. I just haven't got it completely figured -out yet how it would work. Got any ideas? Anyhow, this method is currently considered -experimental. - -A couple of new tests have been added to go along with our new little method. - -I've added a whole bunch more IMAP-related rfc's to the docs/ subdirectory. Trust me, -you are going to need them. - -Changes in version 2.0.0 ------------------------ -NEW I/O ENGINE -This version includes a major rewrite of the I/O engine. It's now cleaner and more -reliable. Also, output processing is less likely to match patterns that look like -server output but are really, say, message text contained in a literal or something -like that. Also, various problems with blank lines at the ends of messages either -magically appearing or disappearing should now go away. Basically, it's much better -is what I'm trying to say. - -NEW DEFAULT -The Uid parameter now defaults to true. This should be transparent to existing scripts -(except for those scripts that produce embarrassing results because someone forgot to -specify Uid=>1, in which case they'll magically start behaving somehow). - -NEW METHOD -The namespace method has been added, thus implementing RFC2342. If you have any scripts -that rely on the old, "default method" style of namespace implementation then you should -rename those method calls to be mixed case (thus forcing the AUTOLOADed default method). - -NEW ERROR MESSAGES -Mail::IMAPClient now issues a lot more warning messages when run in warn mode -(i.e. $^W is true). Of particular interest are methods implemented via the "default -method" AUTOLOAD hack. They will generate a warning telling you to use mixed- or -upper-case method names (but only if warnings are turned on, say with the -w switch -or $^W++ or something). The exceptions are certain unimplemented yet quite popular -methods that, if ever explicitly implemented, will behave the same way as they do via -the default method. (Or at least they will remain downwardly compatible. I may add -bells and whistles by not by default.) Those methods are listed in the pod and right -here: store, copy, subscribe, close, create, delete and expunge. - -NEW VERSION NUMBERING SCHEME -Changed the version numbering scheme to match perl's (as of perl v5.6.0). - -NEW INSTALLATION TESTS -Added a few new tests to the test suite. (Still need more, though.) Also changed fast_io -and uidplus test suites so that they just "do" the basic tests but with different -options set (i.e. Fast_io and Uid, respectively). - -OTHER CHANGES -- The expunge method now optionally accepts the name of the folder to be expunged. It's -also been documented, even though it technically doesn't exist. (That won't stop it from -working, though.) Since expunge deletes messages that you thought were already deleted, -it's only appropriate to use a method that you thought existed but really doesn't, don't -you think? And if you're wondering how I managed to change the behavior of a method that -doesn't exist, well, I don't want to talk about it. - -- Speaking of methods that don't exist (also known as methods implemented via "the -default method"), effective with this release there are a number of unimplemented -methods that are guaranteed to always exhibit their current behavior. In other words, -even if I do eventually implement these methods explicitly, they will continue to -accept the same arguments and return the same results that they do now via the default -method. (Why I would even bother to do that is specifically not addressed in this -document.) Currently this means that these methods will not trigger warnings when -called via all-lowercase letters (see "NEW ERROR MESSAGES", above). In the future I -hope that it will also mean that these non-existant but functioning methods will also -be documented in the pod. - -- Fixed a bug in the flags method introduced in 1.19. (Thanks to the people at jwm3.org -for reporting this!) - - -Changes in version 1.19 ------------------------ -Fixed a bug in which the Folder parameter returned quoted folder names, which sometimes -caused other methods to requote the folders an extra time. (The IMAP protocol is real -picky about that.) Thanks go to Felix Finch for both reporting the bug and identifying -the fix. - -Siggy Thorarinsson contributed the new "unseen_count" method and suggested a new -"peek mode" parameter. I have not yet gotten around to implementing the new parameter -but have included the unseen_count method, since a) he was kind enough to write it, and -b) it tests well. - -In the meantime, you cannot tell methods like "parse_headers" and "message_string" and -so forth whether or not you want them to mark messages as "\Seen". So, to make life -easier for you in particular I added a bunch of new methods: set_flag, unset_flag, -see, and deny_seeing. The latter two are derivitives of the former two, respectively, -which should make this sentence almost as difficult to parse as an IMAP conversation. - -Fixed bug in which "BAD" "OK" or "NO" lines prefixed by an asterisk (*) instead of the -tag are not handled correctly. This is especially likely when LOGIN to a UW IMAP server -fails. Thanks go to Phil Lobbes for squashing this bug. - -Fixed bug in logout that caused the socket handle to linger. Credit goes to -Jean-Philippe Bouchard for reporting this bug and for identifying the fix. - -Fixed bug in uidvalidity method where folder has special characters in it. - -Made several bug fixes to the example script examples/find_dup_msgs.pl. Thanks to Steve -Mayer for identifying these bugs. - -Changed Fast_io to automatically turn itself off if running on a platform that does -not provide the necessary fcntl macros (I won't mention any names, but it's initials -are "NT"). This will occur silently unless warnings are turned on or unless the Debug -parameter is set to true. Previously scripts running on this platform had to turn off -fast_io by hand, which is lame. (Thank you Kevin Cutts for reporting this problem.) - -Updated logic that X's out login credentials when printing debug output so that funky -characters in "User" or "Password" parameters won't break the regexp. (Kevin Cutts found -this one, too.) - -Tinkered with the Strip_cr method so it can accept multiple arguments OR an array -reference as an argument. See the updated pod for more info. - -Fixed a typo in the documentation in the section describing the fetch method. There -has been an entire paragraph missing from this section for who knows how long. Thanks -to Adam Wells, who reported this documentation error. - -Fixed bug in seen, recent, and unseen methods that caused them to return empty arrays -erroneously under certain conditions. - -Changes in version 1.18 ------------------------ -Timeouts during read operations now work correctly. - -Fixed several bugs in the I/O engine. This should correct various problems with Fast_io -turned on (which is now the default). - -Reworked message_string and body_string methods to avoid bugs when Uid set to true. - -Changes in version 1.17 ------------------------ - -Added support for the Oracle IMAP4r1 server. - -Tinkered with the DESTROY method so that it does a local($@) before doing its evals. -This will perserve the value of $@ when the "new" method fails during a login but the -DESTROY's "logout" succeeds. The module was setting the $@ variable, but on some -versions of perl the DESTROY method would clobber $@ before anything useful could be -done with it! Thanks to Kimmo Hovi for reporting this problem, which was harder to -debug than you might think. - -Changes in version 1.16 ------------------------ - -IMPORTANT: Made Fast_IO the default. You must specify Fast_io => 0 in your new method -call or invoke the Fast_io method (and supply 0 as an arg) to get the old behavior. -(This should be transparent to most users, but as always your mileage may vary.) - -Reduced the number of debug msgs printed in the _read_line internal method and added a -debug msg to report perl and Mail::IMAPClient versions. - -The message_count method will now return the number of messages in the currently select -folder if no folder argument is supplied. - -The message_string method now does an IMAP FETCH RFC822 (instead of a -FETCH RFC822.HEADERS and a FETCH RFC822.TEXT), which should eliminate missing blank -lines at the ends of some messages on some IMAP server platforms. It also returns undef -if for some reason the underlying FETCH fails (i.e. there is no folder selected), -thanks to a suggestion by Pankaj Garg. It has also been slightly re-worked to support -the changes in the I/O engine from version 1.14. - -Re-worked the body_string method to support the I/O engine changes from v1.14. - -Fixed a bug in parse_headers when used with multiple headers and the Uid parameter set -to a true value. - -Documented in this file a fix for a bug in the flags method with the Uid parameter -turned on. (Belated thanks to Michael Lieberman for reporting this bug.) - -Changes in version 1.15 ------------------------ -Fixes the test suite, which in v1.14 had an "exit" stmt that caused early termination -of the tests. (I had put that "exit" in there on purpose, and left it in there by -accident.) - -Changes in version 1.14 ------------------------ -Fixed a bug in the _readline subroutine (part of the I/O engine) that was caused by my -less-than-perfect interpretation of RFC2060. This fix will allow the Mail::IMAPClient -module to function correctly with servers that imbed literal datatypes in the middle -of response lines (rather than just at the end of them). Thanks to Pankaj Garg for -reporting this problem and providing the debugging output necessary to correct it. - -Fixed a bug in parse_headers that was introduced with the fix to the I/O engine -described above. - -Changes in version 1.13 ------------------------ -Changed the parse_headers method so that it uses BODY.PEEK instead of BODY. This -prevents the parse_headers method from implicitly setting the "\Seen" flag for messages -that have not been otherwise read. This change could produce an incompatibility in -scripts that relied on the parse_headers previous behavior. - -Fixed a bug in the flags method with the Uid parameter turned on. (Thanks to Michael -Lieberman for reporting this bug.) - -Changes in version 1.12 ------------------------ -Fixed a bug in the folders method when called first with a second arg and then without -a second arg. - -Tested sucessfully with perl-5.6.0. - -Added a section to the pod documentation on how to report bugs. I've had to ask for -output from scripts with "Debug => 1" so many times that I eventually decided to -include the procedure for documenting bugs in the distribution. (Duh! It only took me -11 releases to come up with that brainstorm.) Often following the procedures to obtain -the documentation is enough; once people see what's going on (by turning on Debug =>1) -they no longer want to report a bug. - -Did I mention it's a good idea to turn on debugging when trying to figure out why a -script isn't working? (It is.) - -In order to make the Debug parameter friendlier, it now prints to STDERR by default. -You can override this by supplying the spanking brand new Debug_fh parameter, which -if supplied had better well point to a filehandle (either by glob or by reference), -and by 'filehandle' I mean something besides STDIN! - -Debugging mode will now also X-out the login credentials used to login. This will make -it easier to share your debugging output. - -Added documentation for the State parameter, which must be set manually by programmers -who are not using Mail::IMAPClient's connect and/or login methods but who are instead -making their own connections and then using the Socket parameter to turn their -connections into IMAP clients. - -Fixed bug in parse_headers with Uid turned on. - -Fixed bug in parse_headers when using the argument "ALL". - -Changes in version 1.11 ------------------------ -Added new example script, copy_folder.pl, to demonstrate one way to copy entire -folders between imap accounts (which may or may not be on the same server). This -example is right next to all the others, in the examples/ subdirectory of the -distribution. - -Changed error handling slightly. $@ now contains pretty much the same stuff as what -gets returned by LastError, even when LastError won't work (i.e. when an implicit -connect or login fails and so no object reference is returned by new). You can thank -John Milton for the friendly nagging that got me to do this. - -Added new test suite for the fast_io engine. This should make it easier to determine -whether or not the fast_io engine will work on your platform. - -Implemented a work-around to allow the Port parameter to default despite a known bug in -IO::Socket::INET version 1.25 (distributed with perl 5.6.0). - -Fixed a bug in the message_string method in which the resulting text string for some -mime messages to be incompatible with append. - -Fixed a bug in the Fast_io i/o engine that could cause hangs during an append operation. - -Changed a number of regular expressions to accept mixed-case "Ok", "No" or "Bad" -responses from the server and to do multi-line matching. - -Fixed a bug in the append method that was causing extra carriage returns to appear in -messages whose lines were already terminated with the CR-LF sequence. Thanks to Heather -Adkins for reporting this bug. - -Enhanced the parse_headers routine so that it is less sensitive to variations of -case in message headers. Now, the case of the returned key matches the case of the -field as specified in the parse_headers method's arguments, regardless of its case -in the message being parsed. (You can thank Heather Atkins for this suggestion as -well.) See below for more changes to parse_headers in this release. - -Improved the append method so that it has better error handling and error recovery. -Thanks to Mark Keisler for pointing out some bugs in the error handling code in -this method. - -Added the append_file method, which is like the append method but it works on files -instead of strings. The file provided to append must contain an RFC822-formatted -message. Use of the append_file method avoids having to stuff huge messages into -variables before appending them. Thanks to jwmIII (http://jwm3.org) for suggesting -this method. - -Changed the flags method and the parse_headers method so that a reference to an array -of message sequence numbers (or message UIDS if the Uid parameter is turned on) can -optionally be passed instead of a single message sequence number (or UID). Use of this -enhancement will change your return values so be sure to read the pod. Thanks to -Adrian Smith (adrian.smith@ucpag.com) for delivering this enhancement. - -Fixed a bug in "message_string" that caused the blank lines between headers and body -to fall out of the string. - -Tinkered with the undocumented _send_line method to permit an optional argument -to suppress the automatic insertion of at the end of strings being sent. -(NOTE: I'm telling you this because I'm a nice guy. This doesn't mean that _send_line -is now a programming interface.) - -Changes in version 1.10 ------------------------ - -Added two new methods, lsub and subscribed. lsub replaces the behavior of the default -method and should be downwardly compatible. The subscribed method works like the -folders method but the results include only subscribed folders. Thanks to Alexei -Kharchenko for providing the code for lsub (which is the foundation upon which -'subscribed' was built). - -Changes in version 1.09 ------------------------ - -Changed login method so that values for the User parameter that do not start and end -with quotes will be quoted when sent to the server. This is to support user id's -with embedded spaces, which are legal on some platforms. - -Changed name of test input file created by perl Makefile.PL and used by 'make test' -from .test to test.txt to support weird, offbeat OS platforms that cannot handle -filenames beginning with a dot. - -Fixed bugs in seen, unseen, and recent methods. (These are almost the same method -anyway; they are dynamically created at compile time from the same code, with -variable substitution filling in the places where "seen", "unseen", or "recent" -belong.) The bug caused these methods to return the transaction number of the -search as if it were the last message sequence number (or message uid) in -the result set. - -Added the 'since' method, which accepts a date in either standard perl format (seconds -since 1/1/1970, or as output by time and as accepted by localtime) or in the date_text -format as defined in RFC2060 (dd-Mon-yyyy, where Mon is the English-language -three-letter abbreviation for the month). It searches for items in the currently -selected folder for messages sent since the day whose date is provided as an argument. - -Added 'sentsince', 'senton', 'sentbefore', 'on', and 'before' methods which are -totally 100% just like the 'since' method, except that they run different searches. -(Did I mention that it's useful to have RFC2060 handy when writing IMAP clients?) - -Added two new methods, run and tag_and_run, to allow IMAP client programmers finer -control over the IMAP conversation. These methods allow the programmer to compose -the entire IMAP command string and pass it as-is to the IMAP server. The difference -between these two methods is that the run method requires that the string include -the tag while the tag_and_run method requires that it does not. - -To a similar end, the pre-existing Socket parameter and eponymous accessor method -has been documented to allow direct access to the IMAP socket handle and to allow -the socket handle to be replaced with some other file handle, presumably one derived -from a more interesting technology (such as SSL). - -Fixed a bug that caused blank lines to be removed from 'literal' output (as defined -in RFC2060) when fast_io was not used. This bug was especially likely to show up in -routines that fetched a message's body text. The fact that this bug did not occur -in the newer fast_io code may indicate that I've learned something, but on the other -hand we shouldn't jump to rash conclusions. - -I've run benchmarks on the fast_io code to determine whether or not it is faster and, -if so, under what circumstances. It appears that the fast_io code is quite faster, -except when reading large 'literal' strings (i.e. message bodies), in which case it -appears to take the same amount of time as the older i/o code but at the cost of -more cpu cycles (which means it may actually be slower on cpu-constrained systems). -The reason for this is that reads of literal strings are by their nature already -optimized, but without the overhead of fcntl calls. So if you expect to be doing -lots of message text (or multipart message body parts) fetching you should not use -fast_io, but in pretty much any other case you should go ahead and use it. In any -event, a number of people have tested fast_io so I no longer consider it -experimental, unless you're running perl on NT or CP/M or something funky like that, -in which case let me know how you make out! - -Changes in version 1.08 ------------------------ - -Maintenance release 1.08a fixes a bug in the folders method when supplying the -optional argument (see "Enhanced folders method..." below) with some IMAP servers. - -Added option to build_ldif.pl (in the examples subdirectory) to allow new options and -to better handle quoted comments in e-mail addresses. Thanks to Jeffrey Fiedl, -whose book _Mastering Regular Expressions_ (O'Reilly) helped me to figure out a -good way to do this. - -Fixed documentation error that failed to mention constraints on when the append -method will return the uid of the appended message. (This feature only works with -servers that have the UIDPLUS capability.) - -Added/improved documentation somewhat. - -The copy method now returns a comma-separated list of uids if successful and if the -IMAP server supports UIDPLUS extentions. The move method now works similarly. - -Added new method uidnext, which accepts the name of a folder as an argument and returns -the next available message UID for that folder. - -The exists and append methods now will handle unquoted foldernames with embedded -spaces or quotes or whatever. Including quotes as part of the argument string is no -longer required but is still supported for backwards compatibility reasons. In other -words, $imap->exists(q("Some Folder")) is now no longer necessary (but will still work). $imap->exists(some folder) is good enough. - -Mail::IMAPClient has been tested successfully on Mirapoint 2.0.2. (Thanks to Jim -Hickstein.) - -I've now installed the UW imapd IMAP4rev1 v12.264 on one of my machines so I'm better -able to certify that platform. All the tests in 'make test' work there (or are at least -gently skipped). - -Fixed bug in getacl in which folder names were quoted twice. (Thanks to Albert Chin for -squashing this bug.) Similar bugs existed in the other ACL methods and were similarly -fixed. - -Fixed a bug in message_uid that basically caused it to not work. Muchos gracias to -Luvox (aka fluvoxamine hydrochloride) for providing me with just the help I needed to -discover and fix this bug. - -Enhanced folders method to allow an argument. If an argument is supplied, then -the folders method will restrict its results to subfolders of the supplied argument -(which should be the name of a parent folder, IMHO). This is implemented by supplying -arguments to the LIST IMAP Client command so we are optimizing network I/O at the -expense of possible server incompatibilities. If you find server incompatibilities -with this then please let me know, and in the meantime you can always -grep(/^parent/,$imap->folders) or something. Or re-implement the folders -method yourself. - - -Changes in version 1.07 ------------------------ -Added a new parameter, Fast_io, which, if set to a true value, will attempt to -implement a faster I/O engine. USE THIS AT YOUR OWN RISK. It is alpha code. I don't -even know yet if it even helps. - -Added support for spaces in folder names for the autoloaded subscribe method. - -Added new methods setacl, getacl, deleteacl, and listrights. These methods are not yet -fully tested and should be considered beta for this release. - -Enhanced support for the myrights method (which is implemented via the default method). - -Fixed bug in append method that caused it to hang if server replied to original APPEND -with a NO (because, say, the mailbox's quota has been exceeded). - -Removed the autodiscovery of the folder hierarchy from the login method. This will -speed up logging in but may delay certain other methods later (but see the next item, -below). - -Updated the exists method to issue a "STATUS" IMAP Client command, rather than depend -on the folder hierarchy being discovered via 'LIST "" "*"'. Apparently this speeds -things up a lot for some configurations, although the difference will be negligable to -many. - -Updated Makefile.PL to support the PREFIX=~/ directive. Thanks to Henry C. Barta -(hbarta@wwa.com) for this fix. - -Added the Timeout parameter and eponymous accessor method, which, if set to a true -value, causes reads to time out after the number of seconds specified in the Timeout -parameter. The value can be in fractions of a second. This has not been fully tested -though, so use of this parameter is strictly "Beta". - -Enhanced support for the UID IMAP client command. Setting the new Uid parameter to a -true value will now cause the object to treat all message numbers as message UID -numbers rather than message sequence numbers. Setting the Uid parameter to a false -value will turn off this behavior again. - -Updated test suite to handle servers that cannot do UIDPLUS and to add tests for -the Uid parameter. - -Incorporated bug fixes for recent_count and message_count in which some servers are -sticking in extra \r's, and updated DESTROY to remove spurious warning messages under -some versions of perl (thanks to Scott Wilson for catching and killing these bugs). - - -Changes in version 1.06 ------------------------ -Changed folders method so that it correctly handles mail folders whose names start and -end with quotes. - -Changed append method so that it returns the uid of the newly appended message if -successful. Since the uid is a "true" value this should not affect the behavior of -existing scripts, although it may enhance the behavior of new scripts ;-) - -Fixed bug in parse_headers that could cause script to die if there were no headers of -the type requested and if there was a space on the blank line returned from FETCH. -(Some blank lines are blanker than others...) - -Added the "flags" method, which returns an array (or array reference if called in scalar -context) containing the flags that have been set for the message whose sequence number -has been provided as the argument to the method. - -Added the "message_string" method, which accepts a message sequence number as an -argument and returns the contents of the message (including RFC822 headers) as a -single string. - -Added the "body_string" method, which accepts a message sequence number as an argument -and returns the contents of the message (not including RFC822 headers) as a single -string. - -Changes in version 1.05 ------------------------ - -Patched the 'make test' basic test to work correctly on systems that do not -support double quotes in folder names. Thanks to Rex Walters for this fix. - -Added a new example script, build_dist.pl, that rumages through a folder -(specified on the command line) and collects the "From:" address, and then -appends a message to that folder with all those addresses in both the To: field -and the text, to facilitate cuting and pasting (or dragging and dropping) -into address books and so forth. (Note that the message doesn't actually get -sent to all those people; it just kind of looks that way.) - -Also added another example, build_ldif.pl, that is similar to build_dist.pl -except that instead of listing addresses in the message text, it creates a -MIME attachment and attaches a text file in LDIF format, which can then be -imported into any address book that supports LDIF as an import file format. -This example requires the MIME::Lite module. MIME::Lite was written by Eryq -(okay, Erik Dorfman is his legal name), and is totally available on CPAN. - -This distribution has now been tested on Mirapoint Message Server Appliances -(versions 1.6.1 and 1.7.1). Many thanks to Rex Walters for certifying this -platform and for providing a test account for future releases. - -Changes in version 1.04 ------------------------ - -Fixed situation in which servers that include the " OK\r\n" line -as part of a literal (i.e. text delivered via {}\r\n bytes\r\n) -caused the module to hang. This situation is pretty rare; I've only run across -one server that does it. I'm sure it's a bug; I'm not sure whose. ;-} -Many thanks to Thomas Stromberg for 1) pointing out this bug and 2) providing -me with facilities to find and fix it! - -Fixed potential bug in I/O engine that could cause module to hang when reading -a literal if the first read did not capture the entire literal. - -Cleaned up some unnecessary runtime warnings when a script is executed with -the -w switch. - -Added new tests to 'make test'. I just can't keep my hands off it! ;-) - -Enhanced the append method and several tests in 'make test' to be more widely -compatible. Successfully tested on UW-IMAP, Cyrus v1.5.19, Netscape Messenger -4.1, and Netscape Messenger v3.6. If you know of others please add them to -the list! - -Fixed a bug in the separator method (new in 1.03) that caused it to fail if -'inbox' was specified in lowercase characters as the method's argument. - -Added a new example, imap_to_mbox.pl, contributed by Thomas Stromberg. This -example converts a user's IMAP folders on an IMAP server into mbox format. - -Changes in version 1.03 ------------------------ -Reworked several methods to support double-quote characters within folder -names. This was kind of hard. This has been successfully tested with create, -delete, select, and folders, to name the ones that come to mind. - -Reworked the undocumented method that reads the socket to accept and handle -more gracefully lines ending in {nnn}\r\n ( where nnn is a number of -characters to read). This seems to be part of the IMAP protocol although I -am at a total loss as to where it's explained, other than a brief description -of a "literal's" bnf syntax, which hardly counts. - -Added separator object method, which returns the separator character in use -by the current server. - -Added is_parent method, which returns 1, 0, or undef depending on whether a -folder has children, has no children, or is not permitted to have children. - -Added tests to 'make test' to test new function. Also changed 'make test' to -support IMAP systems that allow folders to be created only in the user's INBOX -(which is the exact opposite of what my IMAP server allows...oh, well). - -Fixed a bug that caused search to return an array of one undef'ed element -rather than undef if there were no hits. - -Changes in version 1.02 ------------------------ -Fixed bugs in search and folders methods. - -Fixed bug in new method that ignored Clear => 0 when specified as arguments to -new. - -Changes in version 1.01 ------------------------ -Fixed a bug in test.pl that caused tests to fail if the extended tests were not used. - -Added method 'parse_headers' to parse the header fields of a message in the -IMAP store into a perl data structure. - -Changes in version 1.00 ------------------------ -Made cosmetic changes to documentation. - -Fixed a bug introduced into the 'folders' method in .99. - -Changed 'new' method so that it returns undef if an implicit connection or -login is attempted but fails. Previous releases returned a Mail::IMAPClient -object that was not connected or not logged in, depending on what failed. - -Changed installation script so that it reuses the parameter file for test.pl -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 described in test_template.txt) is even better, as it will -allow you to do a thorough 'make test'. - -Changes in version .99 ----------------------- -Added the Rfc822_date class method to create RFC822-compliant date fields in -messages being appended with the append method. - -Added the recent, seen, and unseen methods to return an array of sequence -numbers from a SEARCH RECENT, SEARCH SEEN, or SEARCH UNSEEN method call. -These methods are shortcuts to $imap->search("RECENT"), etc. - -Added the recent_count method to return the number of RECENT messages in a -folder. Contributed by Rob Deker. - -Added 'use strict' compliance, courtesy of Mihai Ibanescu. - -Fixed a bug in the search method that resulted in a list with one empty member -being returned if a search had no hits. The search method now returns undef -if there are no hits. - -Added 'authenticate' method to provide very crude support for the IMAP -AUTHENTICATE command. The previous release didn't support AUTHENTICATE at all, -unless you used very low-level (and undocumented) methods. With the -'authenticate' method, the programmer still has to figure out how to -respond to the server's challenge. I hope to make it friendlier in the -next release. Or maybe the one after that. This method is at least a start, -albeit a pretty much untested one. - -Added Rfc822_date class method to facilitate creation of "Date:" header -field when creating text for the "append" method, although the method may -come in handy whenever you're creating a Date: header, even if it's not -in conjuction with an IMAP session. - -Added more tests, which will optionally run at 'make test' time, provided all -the necessary data (like username, hostname, password for testing an IMAP -session) are available. - - -Changes in version 0.09 ------------------------ -Thu Aug 26 14:10:03 1999 - original version; created by h2xs 1.19 - -# $Id: Changes,v 20001010.18 2003/06/12 21:35:48 dkernen Exp $ diff --git a/W/Mail-IMAPClient-2.2.9/Copying b/W/Mail-IMAPClient-2.2.9/Copying deleted file mode 100644 index 43cd72c..0000000 --- a/W/Mail-IMAPClient-2.2.9/Copying +++ /dev/null @@ -1,248 +0,0 @@ - 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. - - - Copyright (C) 19yy - - 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. - - , 1 April 1989 - Ty Coon, President of Vice - -That's all there is to it! diff --git a/W/Mail-IMAPClient-2.2.9/IMAPClient b/W/Mail-IMAPClient-2.2.9/IMAPClient deleted file mode 120000 index 945c9b4..0000000 --- a/W/Mail-IMAPClient-2.2.9/IMAPClient +++ /dev/null @@ -1 +0,0 @@ -. \ No newline at end of file diff --git a/W/Mail-IMAPClient-2.2.9/IMAPClient.pm b/W/Mail-IMAPClient-2.2.9/IMAPClient.pm deleted file mode 100644 index 653dfdf..0000000 --- a/W/Mail-IMAPClient-2.2.9/IMAPClient.pm +++ /dev/null @@ -1,3767 +0,0 @@ -package Mail::IMAPClient; - -# $Id: IMAPClient.pm,v 20001010.20 2003/06/13 18:30:55 dkernen Exp $ - -$Mail::IMAPClient::VERSION = '2.2.9'; -$Mail::IMAPClient::VERSION = '2.2.9'; # do it twice to make sure it takes - -use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK); -use Socket(); -use IO::Socket(); -use IO::Select(); -use IO::File(); -use Carp qw(carp); -#use Data::Dumper; -use Errno qw/EAGAIN/; - -#print "Found Fcntl in $INC{'Fcntl.pm'}\n"; -#Fcntl->import; - -use constant Unconnected => 0; - -use constant Connected => 1; # connected; not logged in - -use constant Authenticated => 2; # logged in; no mailbox selected - -use constant Selected => 3; # mailbox selected - -use constant INDEX => 0; # Array index for output line number - -use constant TYPE => 1; # Array index for line type - # (either OUTPUT, INPUT, or LITERAL) - -use constant DATA => 2; # Array index for output line data - -use constant NonFolderArg => 1; # Value to pass to Massage to - # indicate non-folder argument - - - -my %SEARCH_KEYS = map { ( $_ => 1 ) } qw/ - ALL ANSWERED BCC BEFORE BODY CC DELETED DRAFT FLAGGED - FROM HEADER KEYWORD LARGER NEW NOT OLD ON OR RECENT - SEEN SENTBEFORE SENTON SENTSINCE SINCE SMALLER SUBJECT - TEXT TO UID UNANSWERED UNDELETED UNDRAFT UNFLAGGED - UNKEYWORD UNSEEN -/; - -sub _debug { - my $self = shift; - return unless $self->Debug; - my $fh = $self->{Debug_fh} || \*STDERR; - print $fh @_; -} - -sub MaxTempErrors { - my $self = shift; - $_[0]->{Maxtemperrors} = $_[1] if defined($_[1]); - return $_[0]->{Maxtemperrors}; -} - -# This function is used by the accessor methods -# -sub _do_accessor { - my $datum = shift; - - if ( defined($_[1]) and $datum eq 'Fast_io' and ref($_[0]->{Socket})) { - if ($_[1]) { # Passed the "True" flag - my $fcntl = 0; - eval { $fcntl=fcntl($_[0]->{Socket}, F_GETFL, 0) } ; - if ($@) { - $_[0]->{Fast_io} = 0; - carp ref($_[0]) . " not using Fast_IO; not available on this platform" - if ( ( $^W or $_[0]->Debug) and not $_[0]->{_fastio_warning_}++); - } else { - $_[0]->{Fast_io} = 1; - $_[0]->{_fcntl} = $fcntl; - my $newflags = $fcntl; - $newflags |= O_NONBLOCK; - fcntl($_[0]->{Socket}, F_SETFL, $newflags) ; - - } - } else { - eval { fcntl($_[0]->{Socket}, F_SETFL, $_[0]->{_fcntl}) } - if exists $_[0]->{_fcntl}; - $_[0]->{Fast_io} = 0; - delete $_[0]->{_fcntl} if exists $_[0]->{_fcntl}; - } - } elsif ( defined($_[1]) and $datum eq 'Socket' ) { - - # Get rid of fcntl settings for obsolete socket handles: - delete $_[0]->{_fcntl} ; - # Register this handle in a select vector: - $_[0]->{_select} = IO::Select->new($_[1]) ; - } - - if (scalar(@_) > 1) { - $@ = $_[1] if $datum eq 'LastError'; - chomp $@ if $datum eq 'LastError'; - return $_[0]->{$datum} = $_[1] ; - } else { - return $_[0]->{$datum}; - } -} - -# the following for loop sets up eponymous accessor methods for -# the object's parameters: - -BEGIN { - for my $datum ( - qw( State Port Server Folder Fast_io Peek - User Password Socket Timeout Buffer - Debug LastError Count Uid Debug_fh Maxtemperrors - EnableServerResponseInLiteral - Authmechanism Authcallback Ranges - Readmethod Showcredentials - Prewritemethod - ) - ) { - no strict 'refs'; - *$datum = sub { _do_accessor($datum, @_); }; - } - - eval { - require Digest::HMAC_MD5; - require MIME::Base64; - }; - if ($@) { - $Mail::IMAPClient::_CRAM_MD5_ERR = - "Internal CRAM-MD5 implementation not available: $@"; - $Mail::IMAPClient::_CRAM_MD5_ERR =~ s/\n+$/\n/; - } -} - -sub Wrap { shift->Clear(@_); } - -# The following class method is for creating valid dates in appended msgs: - -sub Rfc822_date { -my $class= shift; -#Date: Fri, 09 Jul 1999 13:10:55 -0000# -my $date = $class =~ /^\d+$/ ? $class : shift ; -my @date = gmtime($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 -%4.4d", - $dow[$date[6]], - $date[3], - $mnt[$date[4]], - $date[5]+=1900, - $date[2], - $date[1], - $date[0], - $date[8]) ; -} - -# The following class method is for creating valid dates for use in IMAP search strings: - -sub Rfc2060_date { -my $class= shift; -# 11-Jan-2000 -my $date = $class =~ /^\d+$/ ? $class : shift ; -my @date = gmtime($date); -my @mnt = qw{ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec}; -# -return sprintf( - "%2.2d-%s-%4.4s", - $date[3], - $mnt[$date[4]], - $date[5]+=1900 - ) ; -} - -# The following class method strips out 's so lines end with -# instead of : - -sub Strip_cr { - my $class = shift; - unless ( ref($_[0]) or scalar(@_) > 1 ) { - (my $string = $_[0]) =~ s/\x0d\x0a/\x0a/gm; - return $string; - } - return wantarray ? map { s/\x0d\x0a/\0a/gm ; $_ } - (ref($_[0]) ? @{$_[0]} : @_) : - [ map { s/\x0d\x0a/\x0a/gm ; $_ } - ref($_[0]) ? @{$_[0]} : @_ - ] ; -} - -# The following defines a special method to deal with the Clear parameter: - -sub Clear { - my $self = shift; - defined(my $clear = shift) or return $self->{Clear}; - - my $oldclear = $self->{Clear}; - $self->{Clear} = $clear; - - my (@keys) = sort { $b <=> $a } keys %{$self->{"History"}} ; - - for ( my $i = $clear; $i < @keys ; $i++ ) - { delete $self->{'History'}{$keys[$i]} } - - return $oldclear; -} - -# read-only access to the transaction number: -sub Transaction { shift->Count }; - -# the constructor: -sub new { - my $class = shift; - my $self = { - LastError => "", - Uid => 1, - Count => 0, - Fast_io => 1, - "Clear" => 5, - }; - while (scalar(@_)) { - $self->{ucfirst(lc($_[0]))} = $_[1]; shift, shift; - } - bless $self, ref($class)||$class; - - $self->State(Unconnected); - - $self->{Debug_fh} ||= \*STDERR; - select((select($self->{Debug_fh}),$|++)[0]) ; - $self->_debug("Using Mail::IMAPClient version $Mail::IMAPClient::VERSION " . - "and perl version " . (defined $^V ? join(".",unpack("CCC",$^V)) : "") . - " ($])\n") if $self->Debug; - $self->LastError(0); - $self->Maxtemperrors or $self->Maxtemperrors("unlimited") ; - return $self->connect if $self->Server and !$self->Socket; - return $self; -} - - -sub connect { - my $self = shift; - - $self->Port(143) - if defined ($IO::Socket::INET::VERSION) - and $IO::Socket::INET::VERSION eq '1.25' - and !$self->Port; - %$self = (%$self, @_); - my $sock = IO::Socket::INET->new( - PeerAddr => $self->Server , - PeerPort => $self->Port||'imap(143)' , - Proto => 'tcp' , - Timeout => $self->Timeout||0 , - Debug => $self->Debug , - ) ; - - unless ( defined($sock) ) { - - $self->LastError( "Unable to connect to $self->{Server}: $!\n"); - $@ = "Unable to connect to $self->{Server}: $!"; - carp "Unable to connect to $self->{Server}: $!" - unless defined wantarray; - return undef; - } - $self->Socket($sock); - $self->State(Connected); - - $sock->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 ; - } - - if ($self->User and $self->Password) { - return $self->login ; - } else { - return $self; - } -} - - -sub login { - my $self = shift; - return $self->authenticate($self->Authmechanism,$self->Authcallback) - if $self->{Authmechanism}; - - my $id = $self->User; - my $has_quotes = $id =~ /^".*"$/ ? 1 : 0; - my $string = "Login " . ( $has_quotes ? $id : qq("$id") ) . " " . - "{" . length($self->Password) . - "}\r\n".$self->Password."\r\n"; - $self->_imap_command($string) - and $self->State(Authenticated); - # $self->folders and $self->separator unless $self->NoAutoList; - unless ( $self->IsAuthenticated) { - my($carp) = $self->LastError; - $carp =~ s/^[\S]+ ([^\x0d\x0a]*)\x0d?\x0a/$1/; - carp $carp unless defined wantarray; - return undef; - } - return $self; -} - -sub separator { - my $self = shift; - my $target = shift ; - - unless ( defined($target) ) { - my $sep = ""; - # separator is namespace's 1st thing's 1st thing's 2nd thing: - eval { $sep = $self->namespace->[0][0][1] } ; - return $sep if $sep; - } - - defined($target) or $target = ""; - $target ||= '""' ; - - - - # The fact that the response might end with {123} doesn't really matter here: - - unless (exists $self->{"$target${;}SEPARATOR"}) { - my $list = (grep(/^\*\s+LIST\s+/,($self->list(undef,$target)||("NO")) ))[0] || - qq("/"); - my $s = (split(/\s+/,$list))[3]; - defined($s) and $self->{"$target${;}SEPARATOR"} = - ( $s eq 'NIL' ? 'NIL' : substr($s, 1,length($s)-2) ); - } - return $self->{$target,'SEPARATOR'}; -} - -sub sort { - my $self = shift; - my @hits; - my @a = @_; - $@ = ""; - $a[0] = "($a[0])" unless $a[0] =~ /^\(.*\)$/; # wrap criteria in parens - $self->_imap_command( ( $self->Uid ? "UID " : "" ) . "SORT ". join(' ',@a)) - or return wantarray ? @hits : \@hits ; - my @results = $self->History($self->Count); - - for my $r (@results) { - chomp $r; - $r =~ s/\r$//; - $r =~ s/^\*\s+SORT\s+// or next; - push @hits, grep(/\d/,(split(/\s+/,$r))); - } - return wantarray ? @hits : \@hits; -} - -sub list { - my $self = shift; - my ($reference, $target) = (shift, shift); - $reference = "" unless defined($reference); - $target = '*' unless defined($target); - $target = '""' if $target eq ""; - $target = $self->Massage($target) unless $target eq '*' or $target eq '""'; - my $string = qq(LIST "$reference" $target); - $self->_imap_command($string) or return undef; - return wantarray ? - $self->History($self->Count) : - [ map { $_->[DATA] } @{$self->{'History'}{$self->Count}}] ; -} - -sub lsub { - my $self = shift; - my ($reference, $target) = (shift, shift); - $reference = "" unless defined($reference); - $target = '*' unless defined($target); - $target = $self->Massage($target); - my $string = qq(LSUB "$reference" $target); - $self->_imap_command($string) or return undef; - return wantarray ? $self->History($self->Count) : - [ map { $_->[DATA] } @{$self->{'History'}{$self->Count}} ] ; -} - -sub subscribed { - my $self = shift; - my $what = shift ; - - my @folders ; - - my @list = $self->lsub(undef,( $what? "$what" . - $self->separator($what) . "*" : undef ) ); - push @list, $self->lsub(undef, $what) if $what and $self->exists($what) ; - - # my @list = map { $self->_debug("Pushing $_->[${\(DATA)}] \n"); $_->[DATA] } - # @$output; - - my $m; - - for ($m = 0; $m < scalar(@list); $m++ ) { - if ($list[$m] && $list[$m] !~ /\x0d\x0a$/ ) { - $list[$m] .= $list[$m+1] ; - $list[$m+1] = ""; - } - - - # $self->_debug("Subscribed: examining $list[$m]\n"); - - push @folders, $1||$2 - if $list[$m] =~ - / ^\*\s+LSUB # * LSUB - \s+\([^\)]*\)\s+ # (Flags) - (?:"[^"]*"|NIL)\s+ # "delimiter" or NIL - (?:"([^"]*)"|(.*))\x0d\x0a$ # Name or "Folder name" - /ix; - - } - - # for my $f (@folders) { $f =~ s/^\\FOLDER LITERAL:://;} - my @clean = () ; my %memory = (); - foreach my $f (@folders) { push @clean, $f unless $memory{$f}++ } - return wantarray ? @clean : \@clean ; -} - - -sub deleteacl { - my $self = shift; - my ($target, $user ) = @_; - $target = $self->Massage($target); - $user =~ s/^"(.*)"$/$1/; - $user =~ s/"/\\"/g; - my $string = qq(DELETEACL $target "$user"); - $self->_imap_command($string) or return undef; - - return wantarray ? $self->History($self->Count) : - [ map {$_->[DATA] } @{$self->{'History'}{$self->Count}}] ; -} - -sub setacl { - my $self = shift; - my ($target, $user, $acl) = @_; - $user = $self->User unless length($user); - $target = $self->Folder unless length($target); - $target = $self->Massage($target); - $user =~ s/^"(.*)"$/$1/; - $user =~ s/"/\\"/g; - $acl =~ s/^"(.*)"$/$1/; - $acl =~ s/"/\\"/g; - my $string = qq(SETACL $target "$user" "$acl"); - $self->_imap_command($string) or return undef; - return wantarray ? - $self->History($self->Count) : - [map{$_->[DATA]}@{$self->{'History'}{$self->Count}}] - ; -} - - -sub getacl { - my $self = shift; - my ($target) = @_; - $target = $self->Folder unless defined($target); - my $mtarget = $self->Massage($target); - my $string = qq(GETACL $mtarget); - $self->_imap_command($string) or return undef; - my @history = $self->History($self->Count); - #$self->_debug("Getacl history: ".join("|",@history).">>>End of History<<<" ) ; - my $perm = ""; - my $hash = {}; - for ( my $x = 0; $x < scalar(@history) ; $x++ ) { - if ( $history[$x] =~ /^\* ACL/ ) { - - $perm = $history[$x]=~ /^\* ACL $/ ? - $history[++$x].$history[++$x] : - $history[$x]; - - $perm =~ s/\s?\x0d\x0a$//; - piece: until ( $perm =~ /\Q$target\E"?$/ or !$perm) { - #$self->_debug(qq(Piece: permline=$perm and " - # "pattern = /\Q$target\E"? \$/)); - $perm =~ s/\s([^\s]+)\s?$// or last piece; - my($p) = $1; - $perm =~ s/\s([^\s]+)\s?$// or last piece; - my($u) = $1; - $hash->{$u} = $p; - $self->_debug("Permissions: $u => $p \n"); - } - - } - } - return $hash; -} - -sub listrights { - my $self = shift; - my ($target, $user) = @_; - $user = $self->User unless defined($user); - $target = $self->Folder unless defined($target); - $target = $self->Massage($target); - $user =~ s/^"(.*)"$/$1/; - $user =~ s/"/\\"/g; - my $string = qq(LISTRIGHTS $target "$user"); - $self->_imap_command($string) or return undef; - my $resp = ( grep(/^\* LISTRIGHTS/, $self->History($self->Count) ) )[0]; - my @rights = split(/\s/,$resp); - shift @rights, shift @rights, shift @rights, shift @rights; - my $rights = join("",@rights); - $rights =~ s/"//g; - return wantarray ? split(//,$rights) : $rights ; -} - -sub select { - my $self = shift; - my $target = shift ; - return undef unless defined($target); - - my $qqtarget = $self->Massage($target); - - my $string = qq/SELECT $qqtarget/; - - my $old = $self->Folder; - - if ($self->_imap_command($string) and $self->State(Selected)) { - $self->Folder($target); - return $old||$self; - } else { - return undef; - } -} - -sub message_string { - my $self = shift; - my $msg = shift; - my $expected_size = $self->size($msg); - return undef unless(defined $expected_size); # unable to get size - my $cmd = $self->has_capability('IMAP4REV1') ? - "BODY" . ( $self->Peek ? '.PEEK[]' : '[]' ) : - "RFC822" . ( $self->Peek ? '.PEEK' : '' ) ; - - $self->fetch($msg,$cmd) or return undef; - - my $string = ""; - - foreach my $result (@{$self->{"History"}{$self->Transaction}}) { - $string .= $result->[DATA] - if defined($result) and $self->_is_literal($result) ; - } - # BUG? should probably return undef if length != expected - if ( length($string) != $expected_size ) { - carp "${self}::message_string: " . - "expected $expected_size bytes but received " . - length($string) - if $self->Debug or $^W; - } - if ( length($string) > $expected_size ) - { $string = substr($string,0,$expected_size) } - if ( length($string) < $expected_size ) { - $self->LastError("${self}::message_string: expected ". - "$expected_size bytes but received " . - length($string)."\n"); - return undef; - } - return $string; -} - -sub bodypart_string { - my($self, $msg, $partno, $bytes, $offset) = @_; - - unless ( $self->has_capability('IMAP4REV1') ) { - $self->LastError( - "Unable to get body part; server " . - $self->Server . - " does not support IMAP4REV1" - ); - return undef; - } - my $cmd = "BODY" . ( $self->Peek ? ".PEEK[$partno]" : "[$partno]" ) ; - $offset ||= 0 ; - $cmd .= "<$offset.$bytes>" if $bytes; - - $self->fetch($msg,$cmd) or return undef; - - my $string = ""; - - foreach my $result (@{$self->{"History"}{$self->Transaction}}) { - $string .= $result->[DATA] - if defined($result) and $self->_is_literal($result) ; - } - return $string; -} - -sub message_to_file { - my $self = shift; - my $fh = shift; - my @msgs = @_; - my $handle; - - if ( ref($fh) ) { - $handle = $fh; - } else { - $handle = IO::File->new(">>$fh"); - unless ( defined($handle)) { - $@ = "Unable to open $fh: $!"; - $self->LastError("Unable to open $fh: $!\n"); - carp $@ if $^W; - return undef; - } - binmode $handle; # For those of you who need something like this... - } - - my $clear = $self->Clear; - my $cmd = $self->Peek ? 'BODY.PEEK[]' : 'BODY[]'; - $cmd = $self->Peek ? 'RFC822.PEEK' : 'RFC822' unless $self->imap4rev1; - - my $string = ( $self->Uid ? "UID " : "" ) . "FETCH " . join(",",@msgs) . " $cmd"; - - $self->Clear($clear) - if $self->Count >= $clear and $clear > 0; - - my $trans = $self->Count($self->Count+1); - - $string = "$trans $string" ; - - $self->_record($trans,[ 0, "INPUT", "$string\x0d\x0a"] ); - - my $feedback = $self->_send_line("$string"); - - unless ($feedback) { - $self->LastError( "Error sending '$string' to IMAP: $!\n"); - $@ = "Error sending '$string' to IMAP: $!"; - return undef; - } - - my ($code, $output); - $output = ""; - - READ: until ( $code) { - $output = $self->_read_line($handle) or return undef; # avoid possible infinite loop - for my $o (@$output) { - $self->_record($trans,$o); # $o is a ref - # $self->_debug("Received from readline: ${\($o->[DATA])}<>\n"); - next unless $self->_is_output($o); - ($code) = $o->[DATA] =~ /^$trans (OK|BAD|NO)/mi ; - if ($o->[DATA] =~ /^\*\s+BYE/im) { - $self->State(Unconnected); - return undef ; - } - } - } - - # $self->_debug("Command $string: returned $code\n"); - close $handle unless ref($fh); - return $code =~ /^OK/im ? $self : undef ; - -} - -sub message_uid { - my $self = shift; - my $msg = shift; - my @uid = $self->fetch($msg,"UID"); - my $uid; - while ( my $u = shift @uid and !$uid) { - ($uid) = $u =~ /\(UID\s+(\d+)\s*\)\r?$/; - } - return $uid; -} - -sub original_migrate { - my($self,$peer,$msgs,$folder) = @_; - unless ( eval { $peer->IsConnected } ) { - $self->LastError("Invalid or unconnected " . ref($self). - " object used as target for migrate." ); - return undef; - } - unless ($folder) { - $folder = $self->Folder; - $peer->exists($folder) or - $peer->create($folder) or - ( - $self->LastError("Unable to created folder $folder on target mailbox: ". - "$peer->LastError") and - return undef - ) ; - } - if ( $msgs =~ /^all$/i ) { $msgs = $self->search("ALL") } - foreach my $mid ( ref($msgs) ? @$msgs : $msgs ) { - my $uid = $peer->append($folder,$self->message_string($mid)); - $self->LastError("Trouble appending to peer: " . $peer->LastError . "\n"); - } -} - - -sub migrate { - - my($self,$peer,$msgs,$folder) = @_; - my($toSock,$fromSock) = ( $peer->Socket, $self->Socket); - my $bufferSize = $self->Buffer || 4096; - my $fromBuffer = ""; - my $clear = $self->Clear; - - unless ( eval { $peer->IsConnected } ) { - $self->LastError("Invalid or unconnected " . - ref($self) . " object used as target for migrate. $@"); - return undef; - } - - unless ($folder) { - $folder = $self->Folder or - $self->LastError( "No folder selected on source mailbox.") - and return undef; - - $peer->exists($folder) or - $peer->create($folder) or - ( - $self->LastError( - "Unable to create folder $folder on target mailbox: ". - $peer->LastError . "\n" - ) and return undef - ) ; - } - $msgs or $msgs eq "0" or $msgs = "all"; - if ( $msgs =~ /^all$/i ) { $msgs = $self->search("ALL") } - my $range = $self->Range($msgs) ; - $self->_debug("Migrating the following msgs from $folder: " . - " $range\n"); - # ( ref($msgs) ? join(", ",@$msgs) : $msgs) ); - - #MIGMSG: foreach my $mid ( ref($msgs) ? @$msgs : (split(/,\s*/,$msgs)) ) {#} - MIGMSG: foreach my $mid ( $range->unfold ) { - # Set up counters for size of msg and portion of msg remaining to - # process: - $self->_debug("Migrating message $mid in folder $folder\n") - if $self->Debug; - my $leftSoFar = my $size = $self->size($mid); - - # fetch internaldate and flags of original message: - my $intDate = '"' . $self->internaldate($mid) . '"' ; - my $flags = "(" . join(" ",grep(!/\\Recent/i,$self->flags($mid)) ) . ")" ; - $flags = "" if $flags eq "()" ; - - # set up transaction numbers for from and to connections: - my $trans = $self->Count($self->Count+1); - my $ptrans = $peer->Count($peer->Count+1); - - # If msg size is less than buffersize then do whole msg in one - # transaction: - if ( $size <= $bufferSize ) { - my $new_mid = $peer->append_string($peer->Massage($folder), - $self->message_string($mid) ,$flags, - $intDate) ; - $self->_debug("Copied message $mid in folder $folder to " . - $peer->User . - '@' . $peer->Server . - ". New Message UID is $new_mid.\n" - ) if $self->Debug; - - $peer->_debug("Copied message $mid in folder $folder from " . - $self->User . - '@' . $self->Server . ". New Message UID is $new_mid.\n" - ) if $peer->Debug; - - - next MIGMSG; - } - - # otherwise break it up into digestible pieces: - my ($cmd, $pattern); - if ( $self->imap4rev1 ) { - # imap4rev1 supports FETCH BODY - $cmd = $self->Peek ? 'BODY.PEEK[]' : 'BODY[]'; - $pattern = sub { - #$self->_debug("Data fed to pattern: $_[0]\n"); - my($one) = $_[0] =~ /\(.*BODY\[\]<\d+> \{(\d+)\}/i ; # ;-) - # or $self->_debug("Didn't match pattern\n") ; - #$self->_debug("Returning from pattern: $1\n") if defined($1); - return $one ; - } ; - } else { - # older imaps use (deprecated) FETCH RFC822: - $cmd = $self->Peek ? 'RFC822.PEEK' : 'RFC822' ; - $pattern = sub { - my($one) = shift =~ /\(RFC822\[\]<\d+> \{(\d+)\}/i; - return $one ; - }; - } - - - # Now let's warn the peer that there's a message coming: - - my $pstring = "$ptrans APPEND " . - $self->Massage($folder). - " " . - ( $flags ? "$flags " : () ) . - ( $intDate ? "$intDate " : () ) . - "{" . $size . "}" ; - - $self->_debug("About to issue APPEND command to peer " . - "for msg $mid\n") if $self->Debug; - - my $feedback2 = $peer->_send_line( $pstring ) ; - - $peer->_record($ptrans,[ - 0, - "INPUT", - "$pstring" , - ] ) ; - unless ($feedback2) { - $self->LastError("Error sending '$pstring' to target IMAP: $!\n"); - return undef; - } - # Get the "+ Go ahead" response: - my $code = 0; - until ($code eq '+' or $code =~ /NO|BAD|OK/ ) { - my $readSoFar = 0 ; - $readSoFar += sysread($toSock,$fromBuffer,1,$readSoFar)||0 - until $fromBuffer =~ /\x0d\x0a/; - - #$peer->_debug("migrate: response from target server: " . - # "$fromBuffer\n") if $peer->Debug; - - ($code)= $fromBuffer =~ /^(\+)|^(?:\d+\s(?:BAD|NO))/ ; - $code ||=0; - - $peer->_debug( "$folder: received $fromBuffer from server\n") - if $peer->Debug; - - # ... and log it in the history buffers - $self->_record($trans,[ - 0, - "OUTPUT", - "Mail::IMAPClient migrating message $mid to $peer->User\@$peer->Server" - ] ) ; - $peer->_record($ptrans,[ - 0, - "OUTPUT", - $fromBuffer - ] ) ; - - - } - unless ( $code eq '+' ) { - $^W and warn "$@\n"; - $self->Debug and $self->_debug("Error writing to target host: $@\n"); - next MIGMSG; - } - # Here is where we start sticking in UID if that parameter - # is turned on: - my $string = ( $self->Uid ? "UID " : "" ) . "FETCH $mid $cmd"; - - # Clean up history buffer if necessary: - $self->Clear($clear) - if $self->Count >= $clear and $clear > 0; - - - # position will tell us how far from beginning of msg the - # next IMAP FETCH should start (1st time start at offet zero): - my $position = 0; - #$self->_debug("There are $leftSoFar bytes left versus a buffer of $bufferSize bytes.\n"); - my $chunkCount = 0; - while ( $leftSoFar > 0 ) { - $self->_debug("Starting chunk " . ++$chunkCount . "\n"); - - my $newstring ="$trans $string<$position." . - ( $leftSoFar > $bufferSize ? $bufferSize : $leftSoFar ) . - ">" ; - - $self->_record($trans,[ 0, "INPUT", "$newstring\x0d\x0a"] ); - $self->_debug("Issuing migration command: $newstring\n" ) - if $self->Debug;; - - my $feedback = $self->_send_line("$newstring"); - - unless ($feedback) { - $self->LastError("Error sending '$newstring' to source IMAP: $!\n"); - return undef; - } - my $chunk = ""; - until ($chunk = $pattern->($fromBuffer) ) { - $fromBuffer = "" ; - until ( $fromBuffer=~/\x0d\x0a$/ ) { - sysread($fromSock,$fromBuffer,1,length($fromBuffer)) ; - #$self->_debug("migrate chunk $chunkCount:" . - # "Read from source: $fromBuffer\n"); - } - - $self->_record($trans,[ 0, "OUTPUT", "$fromBuffer"] ) ; - - if ( $fromBuffer =~ /^$trans (?:NO|BAD)/ ) { - $self->LastError($fromBuffer) ; - next MIGMSG; - } - - if ( $fromBuffer =~ /^$trans (?:OK)/ ) { - $self->LastError("Unexpected good return code " . - "from source host: " . $fromBuffer) ; - next MIGMSG; - } - - } - $fromBuffer = ""; - my $readSoFar = 0 ; - $readSoFar += sysread($fromSock,$fromBuffer,$chunk-$readSoFar,$readSoFar)||0 - until $readSoFar >= $chunk; - #$self->_debug("migrateRead: chunk=$chunk readSoFar=$readSoFar " . - # "Buffer=$fromBufferDebug; - - my $wroteSoFar = 0; - my $temperrs = 0; - my $optimize = 0; - - until ( $wroteSoFar >= $chunk ) { - #$peer->_debug("Chunk $chunkCount: Next write will attempt to write " . - # "this substring:\n" . - # substr($fromBuffer,$wroteSoFar,$chunk-$wroteSoFar) . - # "\n" - #); - - until ( $wroteSoFar >= $readSoFar ) { - $!=0; - my $ret = syswrite( - $toSock, - $fromBuffer, - $chunk - $wroteSoFar, - $wroteSoFar )||0 ; - - $wroteSoFar += $ret; - - if ($! == &EAGAIN ) { - if ( $self->{Maxtemperrors} !~ /^unlimited/i - and $temperrs++ > ($self->{Maxtemperrors}||10) - ) { - $self->LastError("Persistent '${!}' errors\n"); - $self->_debug("Persistent '${!}' errors\n"); - return undef; - } - $optimize = 1; - } else { - # avoid infinite loops on syswrite error - return undef unless(defined $ret); - } - # Optimization of wait time between syswrite calls - # only runs if syscalls run too fast and fill the - # buffer causing "EAGAIN: Resource Temp. Unavail" errors. The - # premise is that $maxwrite will be approx. the same as - # the smallest buffer between the sending and receiving side. - # Waiting time between syscalls should ideally be exactly as - # long as it takes the receiving side to empty that buffer, - # minus a little bit to prevent it from - # emptying completely and wasting time in the select call. - if ($optimize) { - my $waittime = .02; - $maxwrite = $ret if $maxwrite < $ret; - push( @last5writes, $ret ); - shift( @last5writes ) if $#last5writes > 5; - my $bufferavail = 0; - $bufferavail += $_ for ( @last5writes ); - $bufferavail /= ($#last5writes||1); - # Buffer is staying pretty full; - # we should increase the wait period - # to reduce transmission overhead/number of packets sent - if ( $bufferavail < .4 * $maxwrite ) { - $waittime *= 1.3; - - # Buffer is nearly or totally empty; - # we're wasting time in select - # call that could be used to send data, - # so reduce the wait period - } elsif ( $bufferavail > .9 * $maxwrite ) { - $waittime *= .5; - } - CORE::select(undef, undef, undef, $waittime); - } - if ( defined($ret) ) { - $temperrs = 0 ; - } - $peer->_debug("Chunk $chunkCount: " . - "Wrote $wroteSoFar bytes (out of $chunk)\n"); - } - } - $position += $readSoFar ; - $leftSoFar -= $readSoFar; - $fromBuffer = ""; - # Finish up reading the server response from the fetch cmd - # on the source system: - { - my $code = 0; - until ( $code) { - - # escape infinite loop if read_line never returns any data: - - $self->_debug("Reading from source server; expecting " . - "') OK' type response\n") if $self->Debug; - - $output = $self->_read_line or return undef; - for my $o (@$output) { - - $self->_record($trans,$o); # $o is a ref - - # $self->_debug("Received from readline: " . - # "${\($o->[DATA])}<>\n"); - - next unless $self->_is_output($o); - - ($code) = $o->[DATA] =~ /^$trans (OK|BAD|NO)/mi ; - - if ($o->[DATA] =~ /^\*\s+BYE/im) { - $self->State(Unconnected); - return undef ; - } - } - } - } # end scope for my $code - } - # Now let's send a to the peer to signal end of APPEND cmd: - { - my $wroteSoFar = 0; - $fromBuffer = "\x0d\x0a"; - $!=0; - $wroteSoFar += syswrite($toSock,$fromBuffer,2-$wroteSoFar,$wroteSoFar)||0 - until $wroteSoFar >= 2; - - } - # Finally, let's get the new message's UID from the peer: - my $new_mid = ""; - { - my $code = 0; - until ( $code) { - # escape infinite loop if read_line never returns any data: - $peer->_debug("Reading from target: " . - "expecting new uid in response\n") if $peer->Debug; - - $output = $peer->_read_line or next MIGMSG; - - for my $o (@$output) { - - $peer->_record($ptrans,$o); # $o is a ref - - # $peer->_debug("Received from readline: " . - # "${\($o->[DATA])}<>\n"); - - next unless $peer->_is_output($o); - - ($code) = $o->[DATA] =~ /^$ptrans (OK|BAD|NO)/mi ; - ($new_mid)= $o->[DATA] =~ /APPENDUID \d+ (\d+)/ if $code; - #$peer->_debug("Code line: " . $o->[DATA] . - # "\nCode=$code mid=$new_mid\n" ) if $code; - - if ($o->[DATA] =~ /^\*\s+BYE/im) { - $peer->State(Unconnected); - return undef ; - } - } - $new_mid||="unknown" ; - } - } # end scope for my $code - - $self->_debug("Copied message $mid in folder $folder to " . $peer->User . - '@' . $peer->Server . ". New Message UID is $new_mid.\n" - ) if $self->Debug; - - $peer->_debug("Copied message $mid in folder $folder from " . $self->User . - '@' . $self->Server . ". New Message UID is $new_mid.\n" - ) if $peer->Debug; - - - # ... and finish up reading the server response from the fetch cmd - # on the source system: - # { - # my $code = 0; - # until ( $code) { - # # escape infinite loop if read_line never returns any data: - # unless ($output = $self->_read_line ) { - # $self->_debug($self->LastError) ; - # next MIGMSG; - # } - # for my $o (@$output) { -# -# $self->_record($trans,$o); # $o is a ref -# -# # $self->_debug("Received from readline: " . -# # "${\($o->[DATA])}<>\n"); -# -# next unless $self->_is_output($o); -# -# ($code) = $o->[DATA] =~ /^$trans (OK|BAD|NO)/mi ; -# -# if ($o->[DATA] =~ /^\*\s+BYE/im) { -# $self->State(Unconnected); -# return undef ; -# } -# } -# } -# } - - # and clean up the I/O buffer: - $fromBuffer = ""; - } - return $self; -} - - -sub body_string { - my $self = shift; - my $msg = shift; - my $ref = $self->fetch($msg,"BODY" . ( $self->Peek ? ".PEEK" : "" ) . "[TEXT]"); - - my $string = ""; - foreach my $result (@{$ref}) { - $string .= $result->[DATA] if defined($result) and $self->_is_literal($result) ; - } - return $string if $string; - - my $head = shift @$ref; - $self->_debug("body_string: first shift = '$head'\n"); - - until ( (! $head) or $head =~ /(?:.*FETCH .*\(.*BODY\[TEXT\])|(?:^\d+ BAD )|(?:^\d NO )/i ) { - $self->_debug("body_string: shifted '$head'\n"); - $head = shift(@$ref) ; - } - unless ( scalar(@$ref) ) { - $self->LastError("Unable to parse server response from " . $self->LastIMAPCommand ); - return undef ; - } - my $popped ; $popped = pop @$ref until - ( - ( defined($popped) and - # (-: Smile! - $popped =~ /\)\x0d\x0a$/ - ) or - not grep( - # (-: Smile again! - /\)\x0d\x0a$/, - @$ref - ) - ); - - if ($head =~ /BODY\[TEXT\]\s*$/i ) { # Next line is a literal - $string .= shift @$ref while scalar(@$ref); - $self->_debug("String is now $string\n") if $self->Debug; - } - - return $string||undef; -} - - -sub examine { - my $self = shift; - my $target = shift ; return undef unless defined($target); - $target = $self->Massage($target); - my $string = qq/EXAMINE $target/; - - my $old = $self->Folder; - - if ($self->_imap_command($string) and $self->State(Selected)) { - $self->Folder($target); - return $old||$self; - } else { - return undef; - } -} - -sub idle { - my $self = shift; - my $good = '+'; - my $count = $self->Count +1; - return $self->_imap_command("IDLE",$good) ? $count : undef; -} - -sub done { - my $self = shift; - - my $count = shift||$self->Count; - - my $clear = ""; - $clear = $self->Clear; - - $self->Clear($clear) - if $self->Count >= $clear and $clear > 0; - - my $string = "DONE\x0d\x0a"; - $self->_record($count,[ $self->_next_index($count), "INPUT", "$string\x0d\x0a"] ); - - my $feedback = $self->_send_line("$string",1); - - unless ($feedback) { - $self->LastError( "Error sending '$string' to IMAP: $!\n"); - return undef; - } - - my ($code, $output); - $output = ""; - - until ( $code and $code =~ /(OK|BAD|NO)/m ) { - - $output = $self->_read_line or return undef; - for my $o (@$output) { - $self->_record($count,$o); # $o is a ref - next unless $self->_is_output($o); - ($code) = $o->[DATA] =~ /^(?:$count) (OK|BAD|NO)/m ; - if ($o->[DATA] =~ /^\*\s+BYE/) { - $self->State(Unconnected); - } - } - } - return $code =~ /^OK/ ? @{$self->Results} : undef ; - -} - -sub tag_and_run { - my $self = shift; - my $string = shift; - my $good = shift; - $self->_imap_command($string,$good); - return @{$self->Results}; -} -# _{name} methods are undocumented and meant to be private. - -# _imap_command runs a command, inserting the correct tag -# and and whatnot. -# When updating _imap_command, remember to examine the run method, too, since it is very similar. -# - -sub _imap_command { - - my $self = shift; - my $string = shift or return undef; - my $good = shift || 'GOOD'; - - my $qgood = quotemeta($good); - - my $clear = ""; - $clear = $self->Clear; - - $self->Clear($clear) - if $self->Count >= $clear and $clear > 0; - - my $count = $self->Count($self->Count+1); - - $string = "$count $string" ; - - $self->_record($count,[ 0, "INPUT", "$string\x0d\x0a"] ); - - my $feedback = $self->_send_line("$string"); - - unless ($feedback) { - $self->LastError( "Error sending '$string' to IMAP: $!\n"); - $@ = "Error sending '$string' to IMAP: $!"; - carp "Error sending '$string' to IMAP: $!" if $^W; - return undef; - } - - my ($code, $output); - $output = ""; - - READ: until ( $code) { - # escape infinite loop if read_line never returns any data: - $output = $self->_read_line or return undef; - - for my $o (@$output) { - $self->_record($count,$o); # $o is a ref - # $self->_debug("Received from readline: ${\($o->[DATA])}<>\n"); - next unless $self->_is_output($o); - if ( $good eq '+' ) { - $o->[DATA] =~ /^$count (OK|BAD|NO|$qgood)|^($qgood)/mi ; - $code = $1||$2 ; - } else { - ($code) = $o->[DATA] =~ /^$count (OK|BAD|NO|$qgood)/mi ; - } - if ($o->[DATA] =~ /^\*\s+BYE/im) { - $self->State(Unconnected); - return undef ; - } - } - } - - # $self->_debug("Command $string: returned $code\n"); - return $code =~ /^OK|$qgood/im ? $self : undef ; - -} - -sub run { - my $self = shift; - my $string = shift or return undef; - my $good = shift || 'GOOD'; - my $count = $self->Count($self->Count+1); - my($tag) = $string =~ /^(\S+) / ; - - unless ($tag) { - $self->LastError("Invalid string passed to run method; no tag found.\n"); - } - - my $qgood = quotemeta($good); - - my $clear = ""; - $clear = $self->Clear; - - $self->Clear($clear) - if $self->Count >= $clear and $clear > 0; - - $self->_record($count,[ $self->_next_index($count), "INPUT", "$string"] ); - - my $feedback = $self->_send_line("$string",1); - - unless ($feedback) { - $self->LastError( "Error sending '$string' to IMAP: $!\n"); - return undef; - } - - my ($code, $output); - $output = ""; - - until ( $code =~ /(OK|BAD|NO|$qgood)/m ) { - - $output = $self->_read_line or return undef; - for my $o (@$output) { - $self->_record($count,$o); # $o is a ref - next unless $self->_is_output($o); - if ( $good eq '+' ) { - $o->[DATA] =~ /^(?:$tag|\*) (OK|BAD|NO|$qgood)|(^$qgood)/m ; - $code = $1||$2; - } else { - ($code) = - $o->[DATA] =~ /^(?:$tag|\*) (OK|BAD|NO|$qgood)/m ; - } - if ($o->[DATA] =~ /^\*\s+BYE/) { - $self->State(Unconnected); - } - } - } - $self->{'History'}{$tag} = $self->{"History"}{$count} unless $tag eq $count; - return $code =~ /^OK|$qgood/ ? @{$self->Results} : undef ; - -} -#sub bodystruct { # return bodystruct -#} - -# _record saves the conversation into the History structure: -sub _record { - - my ($self,$count,$array) = ( shift, shift, shift); - local($^W)= undef; - - #$self->_debug(sprintf("in _record: count is $count, values are %s/%s/%s and caller is " . - # join(":",caller()) . "\n",@$array)); - - if ( # $array->[DATA] and - $array->[DATA] =~ /^\d+ LOGIN/i and - ! $self->Showcredentials - ) { - - $array->[DATA] =~ s/LOGIN.*/LOGIN XXXXXXXX XXXXXXXX/i ; - } - - push @{$self->{"History"}{$count}}, $array; - - if ( $array->[DATA] =~ /^\d+\s+(BAD|NO)\s/im ) { - $self->LastError("$array->[DATA]") ; - $@ = $array->[DATA]; - carp "$array->[DATA]" if $^W ; - } - return $self; -} - -#_send_line writes to the socket: -sub _send_line { - my($self,$string,$suppress) = (shift, shift, shift); - - #$self->_debug("_send_line: Connection state = " . - # $self->State . " and socket fh = " . - # ($self->Socket||"undef") . "\n") - #if $self->Debug; - - unless ($self->IsConnected and $self->Socket) { - $self->LastError("NO Not connected.\n"); - carp "Not connected" if $^W; - return undef; - } - - unless ($string =~ /\x0d\x0a$/ or $suppress ) { - - chomp $string; - $string .= "\x0d" unless $string =~ /\x0d$/; - $string .= "\x0a" ; - } - if ( - $string =~ /^[^\x0a{]*\{(\d+)\}\x0d\x0a/ # ;-} - ) { - my($p1,$p2,$len) ; - if ( ($p1,$len) = - $string =~ /^([^\x0a{]*\{(\d+)\}\x0d\x0a)/ # } for vi - and ( - $len < 32766 ? - ( ($p2) = $string =~ / - ^[^\x0a{]* - \{\d+\} - \x0d\x0a - ( - .{$len} - .*\x0d\x0a - ) - /x ) : - - ( ($p2) = $string =~ / ^[^\x0a{]* - \{\d+\} - \x0d\x0a - (.*\x0d\x0a) - /x - and length($p2) == $len ) # }} for vi - ) - ) { - $self->_debug("Sending literal string " . - "in two parts: $p1\n\tthen: $p2\n"); - $self->_send_line($p1) or return undef; - $output = $self->_read_line or return undef; - foreach my $o (@$output) { - # $o is already an array ref: - $self->_record($self->Count,$o); - ($code) = $o->[DATA] =~ /(^\+|NO|BAD)/i; - if ($o->[DATA] =~ /^\*\s+BYE/) { - $self->State(Unconnected); - close $fh; - return undef ; - } elsif ( $o->[DATA]=~ /^\d+\s+(NO|BAD)/i ) { - close $fh; - return undef; - } - } - if ( $code eq '+' ) { $string = $p2; } - else { return undef ; } - } - - } - if ($self->Debug) { - my $dstring = $string; - if ( $dstring =~ m[\d+\s+Login\s+]i) { - $dstring =~ - s(\b(?:\Q$self->{Password}\E|\Q$self->{User}\E)\b) - ('X' x length($self->{Password}))eg; - } - _debug $self, "Sending: $dstring\n" if $self->Debug; - } - my $total = 0; - my $temperrs = 0; - my $optimize = 0; - my $maxwrite = 0; - my $waittime = .02; - my @last5writes = (1); - $string = $self->Prewritemethod->($self,$string) if $self->Prewritemethod; - _debug $self, "Sending: $string\n" if $self->Debug and $self->Prewritemethod; - - until ($total >= length($string)) { - my $ret = 0; - $!=0; - $ret = syswrite( - $self->Socket, - $string, - length($string)-$total, - $total - ); - $ret||=0; - if ($! == &EAGAIN ) { - if ( $self->{Maxtemperrors} !~ /^unlimited/i - and $temperrs++ > ($self->{Maxtemperrors}||10) - ) { - $self->LastError("Persistent '${!}' errors\n"); - $self->_debug("Persistent '${!}' errors\n"); - return undef; - } - $optimize = 1; - } else { - # avoid infinite loops on syswrite error - return undef unless(defined $ret); - } - # Optimization of wait time between syswrite calls - # only runs if syscalls run too fast and fill the - # buffer causing "EAGAIN: Resource Temp. Unavail" errors. The - # premise is that $maxwrite will be approx. the same as - # the smallest buffer between the sending and receiving side. - # Waiting time between syscalls should ideally be exactly as - # long as it takes the receiving side to empty that buffer, - # minus a little bit to prevent it from - # emptying completely and wasting time in the select call. - if ($optimize) { - $maxwrite = $ret if $maxwrite < $ret; - push( @last5writes, $ret ); - shift( @last5writes ) if $#last5writes > 5; - my $bufferavail = 0; - $bufferavail += $_ for ( @last5writes ); - $bufferavail /= $#last5writes; - # Buffer is staying pretty full; - # we should increase the wait period - # to reduce transmission overhead/number of packets sent - if ( $bufferavail < .4 * $maxwrite ) { - $waittime *= 1.3; - - # Buffer is nearly or totally empty; - # we're wasting time in select - # call that could be used to send data, - # so reduce the wait period - } elsif ( $bufferavail > .9 * $maxwrite ) { - $waittime *= .5; - } - $self->_debug("Output buffer full; waiting $waittime seconds for relief\n"); - CORE::select(undef, undef, undef, $waittime); - } - if ( defined($ret) ) { - $temperrs = 0 ; - $total += $ret ; - } - } - _debug $self,"Sent $total bytes\n" if $self->Debug; - return $total; -} - -# _read_line reads from the socket. It is called by: -# append append_file authenticate connect _imap_command -# -# It is also re-implemented in: -# message_to_file -# -# syntax: $output = $self->_readline( ( $literal_callback|undef ) , ( $output_callback|undef ) ) ; -# Both input argument are optional, but if supplied must either be a filehandle, coderef, or undef. -# -# Returned argument is a reference to an array of arrays, ie: -# $output = [ -# [ $index, 'OUTPUT'|'LITERAL', $output_line ] , -# [ $index, 'OUTPUT'|'LITERAL', $output_line ] , -# ... # etc, -# ]; - -sub _read_line { - my $self = shift; - my $sh = $self->Socket; - my $literal_callback = shift; - my $output_callback = shift; - - unless ($self->IsConnected and $self->Socket) { - $self->LastError("NO Not connected.\n"); - carp "Not connected" if $^W; - return undef; - } - - my $iBuffer = ""; - my $oBuffer = []; - my $count = 0; - my $index = $self->_next_index($self->Transaction); - my $rvec = my $ready = my $errors = 0; - my $timeout = $self->Timeout; - - my $readlen = 1; - my $fast_io = $self->Fast_io; # Remember setting to reduce future method calls - - if ( $fast_io ) { - - # set fcntl if necessary: - exists $self->{_fcntl} or $self->Fast_io($fast_io); - $readlen = $self->{Buffer}||4096; - } - until ( - # there's stuff in output buffer: - scalar(@$oBuffer) and - - # the last thing there has cr-lf: - $oBuffer->[-1][DATA] =~ /\x0d\x0a$/ and - - # that thing is an output line: - $oBuffer->[-1][TYPE] eq "OUTPUT" and - - # and the input buffer has been MT'ed: - $iBuffer eq "" - - ) { - my $transno = $self->Transaction; # used below in several places - if ($timeout) { - vec($rvec, fileno($self->Socket), 1) = 1; - my @ready = $self->{_select}->can_read($timeout) ; - unless ( @ready ) { - $self->LastError("Tag $transno: " . - "Timeout after $timeout seconds " . - "waiting for data from server\n"); - $self->_record($transno, - [ $self->_next_index($transno), - "ERROR", - "$transno * NO Timeout after ". - "$timeout seconds " . - "during read from " . - "server\x0d\x0a" - ] - ); - $self->LastError( - "Timeout after $timeout seconds " . - "during read from server\x0d\x0a" - ); - return undef; - } - } - - local($^W) = undef; # Now quiet down warnings - - # read "$readlen" bytes (or less): - # need to check return code from $self->_sysread - # in case other end has shut down!!! - my $ret = $self->_sysread( $sh, \$iBuffer, $readlen, length($iBuffer)) ; - # $self->_debug("Read so far: $iBuffer<>\n"); - if($timeout and ! defined($ret)) { # Blocking read error... - my $msg = "Error while reading data from server: $!\x0d\x0a"; - $self->_record($transno, - [ $self->_next_index($transno), - "ERROR", "$transno * NO $msg " - ]); - $@ = "$msg"; - return undef; - } - elsif(defined($ret) and $ret == 0) { # Caught EOF... - my $msg="Socket closed while reading data from server.\x0d\x0a"; - $self->_record($transno, - [ $self->_next_index($transno), - "ERROR", "$transno * NO $msg " - ]); - $@ = "$msg"; - return undef; - } - # successfully wrote to other end, keep going... - $count += $ret; - LINES: while ( $iBuffer =~ s/^(.*?\x0d?\x0a)// ) { - my $current_line = $1; - - # $self->_debug("BUFFER: pulled from buffer: ${current_line}\n" . - # "and left with buffer contents of: ${iBuffer}\n"); - - LITERAL: if ($current_line =~ s/\{(\d+)\}\x0d\x0a$//) { - # This part handles IMAP "Literals", - # which according to rfc2060 look something like this: - # [tag]|* BLAH BLAH {nnn}\r\n - # [nnn bytes of literally transmitted stuff] - # [part of line that follows literal data]\r\n - - # Set $len to be length of impending literal: - my $len = $1 ; - - $self->_debug("LITERAL: received literal in line ". - "$current_line of length $len; ". - "attempting to ". - "retrieve from the " . length($iBuffer) . - " bytes in: $iBuffer\n"); - - # Xfer up to $len bytes from front of $iBuffer to $litstring: - my $litstring = substr($iBuffer, 0, $len); - $iBuffer = substr($iBuffer, length($litstring), - length($iBuffer) - length($litstring) ) ; - - # Figure out what's left to read (i.e. what part of - # literal wasn't in buffer): - my $remainder_count = $len - length($litstring); - my $callback_value = ""; - - if ( defined($literal_callback) ) { - if ( $literal_callback =~ /GLOB/) { - print $literal_callback $litstring ; - $litstring = ""; - } elsif ($literal_callback =~ /CODE/ ) { - # Don't do a thing - - } else { - $self->LastError( - ref($literal_callback) . - " is an invalid callback type; " . - "must be a filehandle or coderef\n" - ); - } - - - } - if ($remainder_count > 0 and $timeout) { - # If we're doing timeouts then here we set up select - # and wait for data from the the IMAP socket. - vec($rvec, fileno($self->Socket), 1) = 1; - unless ( CORE::select( $ready = $rvec, - undef, - $errors = $rvec, - $timeout) - ) { - # Select failed; that means bad news. - # Better tell someone. - $self->LastError("Tag " . $transno . - ": Timeout waiting for literal data " . - "from server\n"); - carp "Tag " . $transno . - ": Timeout waiting for literal data " . - "from server\n" - if $self->Debug or $^W; - return undef; - } - } - - fcntl($sh, F_SETFL, $self->{_fcntl}) - if $fast_io and defined($self->{_fcntl}); - while ( $remainder_count > 0 ) { # As long as not done, - $self->_debug("Still need $remainder_count to " . - "complete literal string\n"); - my $ret = $self->_sysread( # bytes read - $sh, # IMAP handle - \$litstring, # place to read into - $remainder_count, # bytes left to read - length($litstring) # offset to read into - ) ; - $self->_debug("Received ret=$ret and buffer = " . - "\n$litstring\nwhile processing LITERAL\n"); - if ( $timeout and !defined($ret)) { # possible timeout - $self->_record($transno, [ - $self->_next_index($transno), - "ERROR", - "$transno * NO Error reading data " . - "from server: $!\n" - ] - ); - return undef; - } elsif ( $ret == 0 and eof($sh) ) { - $self->_record($transno, [ - $self->_next_index($transno), - "ERROR", - "$transno * ". - "BYE Server unexpectedly " . - "closed connection: $!\n" - ] - ); - $self->State(Unconnected); - return undef; - } - # decrement remaining bytes by amt read: - $remainder_count -= $ret; - - if ( length($litstring) > $len ) { - # copy the extra struff into the iBuffer: - $iBuffer = substr( - $litstring, - $len, - length($litstring) - $len - ); - $litstring = substr($litstring, 0, $len) ; - } - - if ( defined($literal_callback) ) { - if ( $literal_callback =~ /GLOB/ ) { - print $literal_callback $litstring; - $litstring = ""; - } - } - - } - $literal_callback->($litstring) - if defined($litstring) and - $literal_callback =~ /CODE/; - - $self->Fast_io($fast_io) if $fast_io; - - # Now let's make sure there are no IMAP server output lines - # (i.e. [tag|*] BAD|NO|OK Text) embedded in the literal string - # (There shouldn't be but I've seen it done!), but only if - # EnableServerResponseInLiteral is set to true - - my $embedded_output = 0; - my $lastline = ( split(/\x0d?\x0a/,$litstring))[-1] - if $litstring; - - if ( $self->EnableServerResponseInLiteral and - $lastline and - $lastline =~ /^(?:\*|(\d+))\s(BAD|NO|OK)/i - ) { - $litstring =~ s/\Q$lastline\E\x0d?\x0a//; - $embedded_output++; - - $self->_debug("Got server output mixed in " . - "with literal: $lastline\n" - ) if $self->Debug; - - } - # Finally, we need to stuff the literal onto the - # end of the oBuffer: - push @$oBuffer, [ $index++, "OUTPUT" , $current_line], - [ $index++, "LITERAL", $litstring ]; - push @$oBuffer, [ $index++, "OUTPUT", $lastline ] - if $embedded_output; - - } else { - push @$oBuffer, [ $index++, "OUTPUT" , $current_line ]; - } - - } - #$self->_debug("iBuffer is now: $iBuffer<>\n"); - } - # _debug $self, "Buffer is now $buffer\n"; - _debug $self, "Read: " . join("",map {$_->[DATA]} @$oBuffer) ."\n" - if $self->Debug; - return scalar(@$oBuffer) ? $oBuffer : undef ; -} - -sub _sysread { - my $self = shift @_; - if ( exists $self->{Readmethod} ) { - return $self->Readmethod->($self,@_) ; - } else { - my($handle,$buffer,$count,$offset) = @_; - return sysread( $handle, $$buffer, $count, $offset); - } -} - -=begin obsolete - -sub old_read_line { - my $self = shift; - my $sh = $self->Socket; - my $literal_callback = shift; - my $output_callback = shift; - - unless ($self->IsConnected and $self->Socket) { - $self->LastError("NO Not connected.\n"); - carp "Not connected" if $^W; - return undef; - } - - my $iBuffer = ""; - my $oBuffer = []; - my $count = 0; - my $index = $self->_next_index($self->Transaction); - my $rvec = my $ready = my $errors = 0; - my $timeout = $self->Timeout; - - my $readlen = 1; - my $fast_io = $self->Fast_io; # Remember setting to reduce future method calls - - if ( $fast_io ) { - - # set fcntl if necessary: - exists $self->{_fcntl} or $self->Fast_io($fast_io); - $readlen = $self->{Buffer}||4096; - } - until ( - # there's stuff in output buffer: - scalar(@$oBuffer) and - - # the last thing there has cr-lf: - $oBuffer->[-1][DATA] =~ /\x0d\x0a$/ and - - # that thing is an output line: - $oBuffer->[-1][TYPE] eq "OUTPUT" and - - # and the input buffer has been MT'ed: - $iBuffer eq "" - - ) { - my $transno = $self->Transaction; # used below in several places - if ($timeout) { - vec($rvec, fileno($self->Socket), 1) = 1; - my @ready = $self->{_select}->can_read($timeout) ; - unless ( @ready ) { - $self->LastError("Tag $transno: " . - "Timeout after $timeout seconds " . - "waiting for data from server\n"); - $self->_record($transno, - [ $self->_next_index($transno), - "ERROR", - "$transno * NO Timeout after ". - "$timeout seconds " . - "during read from " . - "server\x0d\x0a" - ] - ); - $self->LastError( - "Timeout after $timeout seconds " . - "during read from server\x0d\x0a" - ); - return undef; - } - } - - local($^W) = undef; # Now quiet down warnings - - # read "$readlen" bytes (or less): - # need to check return code from sysread in case other end has shut down!!! - my $ret = sysread( $sh, $iBuffer, $readlen, length($iBuffer)) ; - # $self->_debug("Read so far: $iBuffer<>\n"); - if($timeout and ! defined($ret)) { # Blocking read error... - my $msg = "Error while reading data from server: $!\x0d\x0a"; - $self->_record($transno, - [ $self->_next_index($transno), - "ERROR", "$transno * NO $msg " - ]); - $@ = "$msg"; - return undef; - } - elsif(defined($ret) and $ret == 0) { # Caught EOF... - my $msg="Socket closed while reading data from server.\x0d\x0a"; - $self->_record($transno, - [ $self->_next_index($transno), - "ERROR", "$transno * NO $msg " - ]); - $@ = "$msg"; - return undef; - } - # successfully wrote to other end, keep going... - $count += $ret; - LINES: while ( $iBuffer =~ s/^(.*?\x0d?\x0a)// ) { - my $current_line = $1; - - # $self->_debug("BUFFER: pulled from buffer: ${current_line}\n" . - # "and left with buffer contents of: ${iBuffer}\n"); - - LITERAL: if ($current_line =~ s/\{(\d+)\}\x0d\x0a$//) { - # This part handles IMAP "Literals", which according to rfc2060 look something like this: - # [tag]|* BLAH BLAH {nnn}\r\n - # [nnn bytes of literally transmitted stuff] - # [part of line that follows literal data]\r\n - - # Set $len to be length of impending literal: - my $len = $1 ; - - $self->_debug("LITERAL: received literal in line $current_line of length $len; ". - "attempting to ". - "retrieve from the " . length($iBuffer) . " bytes in: $iBuffer\n"); - - # Transfer up to $len bytes from front of $iBuffer to $litstring: - my $litstring = substr($iBuffer, 0, $len); - $iBuffer = substr($iBuffer, length($litstring), length($iBuffer) - length($litstring) ) ; - - # Figure out what's left to read (i.e. what part of literal wasn't in buffer): - my $remainder_count = $len - length($litstring); - my $callback_value = ""; - - if ( defined($literal_callback) ) { - if ( $literal_callback =~ /GLOB/) { - print $literal_callback $litstring ; - $litstring = ""; - } elsif ($literal_callback =~ /CODE/ ) { - # Don't do a thing - - } else { - $self->LastError( - ref($literal_callback) . - " is an invalid callback type; must be a filehandle or coderef" - ); - } - - - } - if ($remainder_count > 0 and $timeout) { - # If we're doing timeouts then here we set up select and wait for data from the - # the IMAP socket. - vec($rvec, fileno($self->Socket), 1) = 1; - unless ( CORE::select( $ready = $rvec, - undef, - $errors = $rvec, - $timeout) - ) { - # Select failed; that means bad news. - # Better tell someone. - $self->LastError("Tag " . $transno . - ": Timeout waiting for literal data " . - "from server\n"); - carp "Tag " . $transno . - ": Timeout waiting for literal data " . - "from server\n" - if $self->Debug or $^W; - return undef; - } - } - - fcntl($sh, F_SETFL, $self->{_fcntl}) - if $fast_io and defined($self->{_fcntl}); - while ( $remainder_count > 0 ) { # As long as not done, - - my $ret = sysread( # bytes read - $sh, # IMAP handle - $litstring, # place to read into - $remainder_count, # bytes left to read - length($litstring) # offset to read into - ) ; - if ( $timeout and !defined($ret)) { # possible timeout - $self->_record($transno, [ - $self->_next_index($transno), - "ERROR", - "$transno * NO Error reading data " . - "from server: $!\n" - ] - ); - return undef; - } elsif ( $ret == 0 and eof($sh) ) { - $self->_record($transno, [ - $self->_next_index($transno), - "ERROR", - "$transno * ". - "BYE Server unexpectedly " . - "closed connection: $!\n" - ] - ); - $self->State(Unconnected); - return undef; - } - # decrement remaining bytes by amt read: - $remainder_count -= $ret; - - if ( defined($literal_callback) ) { - if ( $literal_callback =~ /GLOB/ ) { - print $literal_callback $litstring; - $litstring = ""; - } - } - - } - $literal_callback->($litstring) - if defined($litstring) and - $literal_callback =~ /CODE/; - - $self->Fast_io($fast_io) if $fast_io; - - # Now let's make sure there are no IMAP server output lines - # (i.e. [tag|*] BAD|NO|OK Text) embedded in the literal string - # (There shouldn't be but I've seen it done!), but only if - # EnableServerResponseInLiteral is set to true - - my $embedded_output = 0; - my $lastline = ( split(/\x0d?\x0a/,$litstring))[-1] - if $litstring; - - if ( $self->EnableServerResponseInLiteral and - $lastline and - $lastline =~ /^(?:\*|(\d+))\s(BAD|NO|OK)/i - ) { - $litstring =~ s/\Q$lastline\E\x0d?\x0a//; - $embedded_output++; - - $self->_debug("Got server output mixed in " . - "with literal: $lastline\n" - ) if $self->Debug; - - } - # Finally, we need to stuff the literal onto the - # end of the oBuffer: - push @$oBuffer, [ $index++, "OUTPUT" , $current_line], - [ $index++, "LITERAL", $litstring ]; - push @$oBuffer, [ $index++, "OUTPUT", $lastline ] - if $embedded_output; - - } else { - push @$oBuffer, [ $index++, "OUTPUT" , $current_line ]; - } - - } - #$self->_debug("iBuffer is now: $iBuffer<>\n"); - } - # _debug $self, "Buffer is now $buffer\n"; - _debug $self, "Read: " . join("",map {$_->[DATA]} @$oBuffer) ."\n" - if $self->Debug; - return scalar(@$oBuffer) ? $oBuffer : undef ; -} - -=end obsolete - -=cut - - -sub Report { - my $self = shift; -# $self->_debug( "Dumper: " . Data::Dumper::Dumper($self) . -# "\nReporting on following keys: " . join(", ",keys %{$self->{'History'}}). "\n"); - return map { - map { $_->[DATA] } @{$self->{"History"}{$_}} - } sort { $a <=> $b } keys %{$self->{"History"}} - ; -} - - -sub Results { - my $self = shift ; - my $transaction = shift||$self->Count; - - return wantarray ? - map {$_->[DATA] } @{$self->{"History"}{$transaction}} : - [ map {$_->[DATA] } @{$self->{"History"}{$transaction}} ] ; -} - - -sub LastIMAPCommand { - my @a = map { $_->[DATA] } @{$_[0]->{"History"}{$_[1]||$_[0]->Transaction}}; - return shift @a; -} - - -sub History { - my @a = map { $_->[DATA] } @{$_[0]->{"History"}{$_[1]||$_[0]->Transaction}}; - shift @a; - return wantarray ? @a : \@a ; - -} - -sub Escaped_results { - my @a; - foreach my $line (@{$_[0]->{"History"}{$_[1]||$_[0]->Transaction}} ) { - if ( defined($line) and $_[0]->_is_literal($line) ) { - $line->[DATA] =~ s/([\\\(\)"\x0d\x0a])/\\$1/g ; - push @a, qq("$line->[DATA]"); - } else { - push @a, $line->[DATA] ; - } - } - # $a[0] is the ALWAYS the command ; I make sure of that in _imap_command - shift @a; - return wantarray ? @a : \@a ; -} - -sub Unescape { - shift @_ if $_[1]; - my $whatever = shift; - $whatever =~ s/\\([\\\(\)"\x0d\x0a])/$1/g if defined $whatever; - return $whatever; -} - -sub logout { - my $self = shift; - my $string = "LOGOUT"; - $self->_imap_command($string) ; - $self->{Folders} = undef; - $self->{_IMAP4REV1} = undef; - eval {$self->Socket->close if defined($self->Socket)} ; - $self->{Socket} = undef; - $self->State(Unconnected); - return $self; -} - -sub folders { - my $self = shift; - my $what = shift ; - return wantarray ? @{$self->{Folders}} : - $self->{Folders} - if ref($self->{Folders}) and !$what; - - my @folders ; - my @list = $self->list(undef,( $what? "$what" . $self->separator($what) . "*" : undef ) ); - push @list, $self->list(undef, $what) if $what and $self->exists($what) ; - # my @list = - # foreach (@list) { $self->_debug("Pushing $_\n"); } - my $m; - - for ($m = 0; $m < scalar(@list); $m++ ) { - # $self->_debug("Folders: examining $list[$m]\n"); - - if ($list[$m] && $list[$m] !~ /\x0d\x0a$/ ) { - $self->_debug("folders: concatenating $list[$m] and " . $list[$m+1] . "\n") ; - $list[$m] .= $list[$m+1] ; - $list[$m+1] = ""; - $list[$m] .= "\x0d\x0a" unless $list[$m] =~ /\x0d\x0a$/; - } - - - - push @folders, $1||$2 - if $list[$m] =~ - / ^\*\s+LIST # * LIST - \s+\([^\)]*\)\s+ # (Flags) - (?:"[^"]*"|NIL)\s+ # "delimiter" or NIL - (?:"([^"]*)"|(.*))\x0d\x0a$ # Name or "Folder name" - /ix; - $folders[-1] = '"' . $folders[-1] . '"' - if $1 and !$self->exists($folders[-1]) ; - # $self->_debug("folders: line $list[$m]: 1=$1 and 2=$2\n"); - } - - # for my $f (@folders) { $f =~ s/^\\FOLDER LITERAL:://;} - my @clean = (); my %memory = (); - foreach my $f (@folders) { push @clean, $f unless $memory{$f}++ } - $self->{Folders} = \@clean unless $what; - - return wantarray ? @clean : \@clean ; -} - - -sub exists { - my ($self,$what) = (shift,shift); - return $self if $self->STATUS($self->Massage($what),"(MESSAGES)"); - return undef; -} - -# Updated to handle embedded literal strings -sub get_bodystructure { - my($self,$msg) = @_; - unless ( eval {require Mail::IMAPClient::BodyStructure ; 1 } ) { - $self->LastError("Unable to use get_bodystructure: $@\n"); - return undef; - } - my @out = $self->fetch($msg,"BODYSTRUCTURE"); - my $bs = ""; - my $output = grep( - /BODYSTRUCTURE \(/i, @out # Wee! ;-) - ); - if ( $output =~ /\r\n$/ ) { - eval { $bs = Mail::IMAPClient::BodyStructure->new( $output )}; - } else { - $self->_debug("get_bodystructure: reassembling original response\n"); - my $start = 0; - foreach my $o (@{$self->{"History"}{$self->Transaction}}) { - next unless $self->_is_output_or_literal($o); - $self->_debug("o->[DATA] is ".$o->[DATA]."\n"); - next unless $start or - $o->[DATA] =~ /BODYSTRUCTURE \(/i and ++$start; # Hi, vi! ;-) - if ( length($output) and $self->_is_literal($o) ) { - my $data = $o->[DATA]; - $data =~ s/"/\\"/g; - $data =~ s/\(/\\\(/g; - $data =~ s/\)/\\\)/g; - $output .= '"'.$data.'"'; - } else { - $output .= $o->[DATA] ; - } - $self->_debug("get_bodystructure: reassembled output=$output\n"); - } - eval { $bs = Mail::IMAPClient::BodyStructure->new( $output )}; - } - $self->_debug("get_bodystructure: msg $msg returns this ref: ". - ( $bs ? " $bs" : " UNDEF" ) - ."\n"); - return $bs; -} - -# Updated to handle embedded literal strings -sub get_envelope { - my($self,$msg) = @_; - unless ( eval {require Mail::IMAPClient::BodyStructure ; 1 } ) { - $self->LastError("Unable to use get_envelope: $@\n"); - return undef; - } - my @out = $self->fetch($msg,"ENVELOPE"); - my $bs = ""; - my $output = grep( - /ENVELOPE \(/i, @out # Wee! ;-) - ); - if ( $output =~ /\r\n$/ ) { - eval { - $bs = Mail::IMAPClient::BodyStructure::Envelope->new($output) - }; - } else { - $self->_debug("get_envelope: " . - "reassembling original response\n"); - my $start = 0; - foreach my $o (@{$self->{"History"}{$self->Transaction}}) { - next unless $self->_is_output_or_literal($o); - $self->_debug("o->[DATA] is ".$o->[DATA]."\n"); - next unless $start or - $o->[DATA] =~ /ENVELOPE \(/i and ++$start; - # Hi, vi! ;-) - if ( length($output) and $self->_is_literal($o) ) { - my $data = $o->[DATA]; - $data =~ s/"/\\"/g; - $data =~ s/\(/\\\(/g; - $data =~ s/\)/\\\)/g; - $output .= '"'.$data.'"'; - } else { - $output .= $o->[DATA] ; - } - $self->_debug("get_envelope: " . - "reassembled output=$output\n"); - } - eval { - $bs=Mail::IMAPClient::BodyStructure::Envelope->new($output) - }; - } - $self->_debug("get_envelope: msg $msg returns this ref: ". - ( $bs ? " $bs" : " UNDEF" ) - ."\n"); - return $bs; -} - -=begin obsolete - -sub old_get_envelope { - my($self,$msg) = @_; - unless ( eval {require Mail::IMAPClient::BodyStructure ; 1 } ) { - $self->LastError("Unable to use get_envelope: $@\n"); - return undef; - } - my $bs = ""; - my @out = $self->fetch($msg,"ENVELOPE"); - my $output = grep( - /ENVELOPE \(/i, @out # Wee! ;-) - ); - if ( $output =~ /\r\n$/ ) { - eval { $bs = Mail::IMAPClient::BodyStructure::Envelope->new( $output )}; - } else { - $self->_debug("get_envelope: reassembling original response\n"); - my $start = 0; - foreach my $o (@{$self->{"History"}{$self->Transaction}}) { - next unless $self->_is_output_or_literal($o); - $self->_debug("o->[DATA] is ".$o->[DATA]."\n"); - next unless $start or - $o->[DATA] =~ /ENVELOPE \(/i and ++$start; # Hi, vi! ;-) - if ( length($output) and $self->_is_literal($o) ) { - my $data = $o->[DATA]; - $data =~ s/"/\\"/g; - $data =~ s/\(/\\\(/g; - $data =~ s/\)/\\\)/g; - $output .= '"'.$data.'"'; - } else { - $output .= $o->[DATA] ; - } - } - $self->_debug("get_envelope: reassembled output=$output\n"); - eval { $bs = Mail::IMAPClient::BodyStructure->new( $output )}; - } - $self->_debug("get_envelope: msg $msg returns this ref: ". - ( $bs ? " $bs" : " UNDEF" ) - ."\n"); - return $bs; -} - -=end obsolete - -=cut - - -sub fetch { - - my $self = shift; - my $what = shift||"ALL"; - #ref($what) and $what = join(",",@$what); - if ( $what eq 'ALL' ) { - $what = $self->Range($self->messages ); - } elsif (ref($what) or $what =~ /^[,:\d]+\w*$/) { - $what = $self->Range($what); - } - $self->_imap_command( ( $self->Uid ? "UID " : "" ) . - "FETCH $what" . ( @_ ? " " . join(" ",@_) : '' ) - ) or return undef; - return wantarray ? $self->History($self->Count) : - [ map { $_->[DATA] } @{$self->{'History'}{$self->Count}} ]; - -} - - -sub fetch_hash { - my $self = shift; - my $hash = ref($_[-1]) ? pop @_ : {}; - my @words = @_; - for (@words) { - s/([\( ])FAST([\) ])/${1}FLAGS INTERNALDATE RFC822\.SIZE$2/i ; - s/([\( ])FULL([\) ])/${1}FLAGS INTERNALDATE RFC822\.SIZE ENVELOPE BODY$2/i ; - } - my $msgref = scalar($self->messages); - my $output = scalar($self->fetch($msgref,"(" . join(" ",@_) . ")")) - ; # unless grep(/\b(?:FAST|FULL)\b/i,@words); - my $x; - for ($x = 0; $x <= $#$output ; $x++) { - my $entry = {}; - my $l = $output->[$x]; - if ($self->Uid) { - my($uid) = $l =~ /\((?:.* )?UID (\d+).*\)/i; - next unless $uid; - if ( exists $hash->{$uid} ) { - $entry = $hash->{$uid} ; - } else { - $hash->{$uid} ||= $entry; - } - } else { - my($mid) = $l =~ /^\* (\d+) FETCH/i; - next unless $mid; - if ( exists $hash->{$mid} ) { - $entry = $hash->{$mid} ; - } else { - $hash->{$mid} ||= $entry; - } - } - - foreach my $w (@words) { - if ( $l =~ /\Q$w\E\s*$/i ) { - $entry->{$w} = $output->[$x+1]; - $entry->{$w} =~ s/(?:\x0a?\x0d)+$//g; - chomp $entry->{$w}; - } else { - $l =~ /\( # open paren followed by ... - (?:.*\s)? # ...optional stuff and a space - \Q$w\E\s # escaped fetch field - (?:" # then: a dbl-quote - (\\.| # then bslashed anychar(s) or ... - [^"]+) # ... nonquote char(s) - "| # then closing quote; or ... - \( # ...an open paren - (\\.| # then bslashed anychar or ... - [^\)]+) # ... non-close-paren char - \)| # then closing paren; or ... - (\S+)) # unquoted string - (?:\s.*)? # possibly followed by space-stuff - \) # close paren - /xi; - $entry->{$w}=defined($1)?$1:defined($2)?$2:$3; - } - } - } - return wantarray ? %$hash : $hash; -} -sub AUTOLOAD { - - my $self = shift; - return undef if $Mail::IMAPClient::AUTOLOAD =~ /DESTROY$/; - delete $self->{Folders} ; - my $autoload = $Mail::IMAPClient::AUTOLOAD; - $autoload =~ s/.*:://; - if ( - $^W - and $autoload =~ /^[a-z]+$/ - and $autoload !~ - /^ (?: - store | - copy | - subscribe| - create | - delete | - close | - expunge - )$ - /x - ) { - carp "$autoload is all lower-case. " . - "May conflict with future methods. " . - "Change method name to be mixed case or all upper case to ensure " . - "upward compatability" - } - if (scalar(@_)) { - my @a = @_; - if ( - $autoload =~ - /^(?:subscribe|delete|myrights)$/i - ) { - $a[-1] = $self->Massage($a[-1]) ; - } elsif ( - $autoload =~ - /^(?:create)$/i - ) { - $a[0] = $self->Massage($a[0]) ; - } elsif ( - $autoload =~ /^(?:store|copy)$/i - ) { - $autoload = "UID $autoload" - if $self->Uid; - } elsif ( - $autoload =~ /^(?:expunge)$/i and defined($_[0]) - ) { - my $old; - if ( $_[0] ne $self->Folder ) { - $old = $self->Folder; $self->select($_[0]); - } - my $succ = $self->_imap_command(qq/$autoload/) ; - $self->select($old); - return undef unless $succ; - return wantarray ? $self->History($self->Count) : - map {$_->[DATA]}@{$self->{'History'}{$self->Count}} ; - - } - $self->_debug("Autoloading: $autoload " . ( @a ? join(" ",@a):"" ) ."\n" ) - if $self->Debug; - return undef - unless $self->_imap_command( - qq/$autoload/ . ( @a ? " " . join(" ",@a) : "" ) - ) ; - } else { - $self->Folder(undef) if $autoload =~ /^(?:close)/i ; - $self->_imap_command(qq/$autoload/) or return undef; - } - return wantarray ? $self->History($self->Count) : - [map {$_->[DATA] } @{$self->{'History'}{$self->Count}}] ; - -} - -sub rename { - my $self = shift; - my ($from, $to) = @_; - local($_); - if ($from =~ /^"(.*)"$/) { - $from = $1 unless $self->exists($from); - $from =~ s/"/\\"/g; - } - if ($to =~ /^"(.*)"$/) { - $to = $1 unless $self->exists($from) and $from =~ /^".*"$/; - $to =~ s/"/\\"/g; - } - $self->_imap_command(qq(RENAME "$from" "$to")) or return undef; - return $self; -} - -sub status { - - my $self = shift; - my $box = shift ; - return undef unless defined($box); - $box = $self->Massage($box); - my @pieces = @_; - $self->_imap_command("STATUS $box (". (join(" ",@_)||'MESSAGES'). ")") or return undef; - return wantarray ? $self->History($self->Count) : - [map{$_->[DATA]}@{$self->{'History'}{$self->Count}}]; - -} - - -# Can take a list of messages now. -# If a single message, returns array or ref to array of flags -# If a ref to array of messages, returns a ref to hash of msgid => flag arr -# See parse_headers for more information -# 2000-03-22 Adrian Smith (adrian.smith@ucpag.com) - -sub flags { - my $self = shift; - my $msgspec = shift; - my $flagset = {}; - my $msg; - my $u_f = $self->Uid; - - # Determine if set of messages or just one - if (ref($msgspec) eq 'ARRAY' ) { - $msg = $self->Range($msgspec) ; - } elsif ( !ref($msgspec) ) { - $msg = $msgspec; - if ( scalar(@_) ) { - $msgspec = $self->Range($msg) ; - $msgspec += $_ for (@_); - $msg = $msgspec; - } - } elsif ( ref($msgspec) =~ /MessageSet/ ) { - if ( scalar(@_) ) { - $msgspec += $_ for @_; - } - } else { - $self->LastError("Invalid argument passed to fetch.\n"); - return undef; - } - - # Send command - unless ( $self->fetch($msg,"FLAGS") ) { - return undef; - } - - # Parse results, setting entry in result hash for each line - foreach my $resultline ($self->Results) { - $self->_debug("flags: line = '$resultline'\n") ; - if ( $resultline =~ - /\*\s+(\d+)\s+FETCH\s+ # * nnn FETCH - \( # open-paren - (?:\s?UID\s(\d+)\s?)? # optional: UID nnn - FLAGS\s?\((.*)\)\s? # FLAGS (\Flag1 \Flag2) - (?:\s?UID\s(\d+))? # optional: UID nnn - \) # close-paren - /x - ) { - { local($^W=0); - $self->_debug("flags: line = '$resultline' " . - "and 1,2,3,4 = $1,$2,$3,$4\n") - if $self->Debug; - } - my $mailid = $u_f ? ( $2||$4) : $1; - my $flagsString = $3 ; - my @flags = map { s/\s+$//; $_ } split(/\s+/, $flagsString); - $flagset->{$mailid} = \@flags; - } - } - - # Did the guy want just one response? Return it if so - unless (ref($msgspec) ) { - my $flagsref = $flagset->{$msgspec}; - return wantarray ? @$flagsref : $flagsref; - } - - # Or did he want a hash from msgid to flag array? - return $flagset; -} - -# parse_headers modified to allow second param to also be a -# reference to a list of numbers. If this is a case, the headers -# are read from all the specified messages, and a reference to -# an hash of mail numbers to references to hashes, are returned. -# I found, with a mailbox of 300 messages, this was -# *significantly* faster against our mailserver (< 1 second -# vs. 20 seconds) -# -# 2000-03-22 Adrian Smith (adrian.smith@ucpag.com) - -sub parse_headers { - my($self,$msgspec,@fields) = @_; - my(%fieldmap) = map { ( lc($_),$_ ) } @fields; - my $msg; my $string; my $field; - - # Make $msg a comma separated list, of messages we want - if (ref($msgspec) eq 'ARRAY') { - #$msg = join(',', @$msgspec); - $msg = $self->Range($msgspec); - } else { - $msg = $msgspec; - } - - if ($fields[0] =~ /^[Aa][Ll]{2}$/ ) { - - $string = "$msg body" . - # use ".peek" if Peek parameter is a) defined and true, - # or b) undefined, but not if it's defined and untrue: - - ( defined($self->Peek) ? - ( $self->Peek ? ".peek" : "" ) : - ".peek" - ) . "[header]" ; - - } else { - $string = "$msg body" . - # use ".peek" if Peek parameter is a) defined and true, or - # b) undefined, but not if it's defined and untrue: - - ( defined($self->Peek) ? - ( $self->Peek ? ".peek" : "" ) : - ".peek" - ) . "[header.fields (" . join(" ",@fields) . ')]' ; - } - - my @raw=$self->fetch( $string ) or return undef; - - my $headers = {}; # hash from message ids to header hash - my $h = 0; # reference to hash of current msgid, or 0 between msgs - - for my $header (map { split(/(?:\x0d\x0a)/,$_) } @raw) { - local($^W) = undef; - if ( $header =~ /^\*\s+\d+\s+FETCH\s+\(.*BODY\[HEADER(?:\]|\.FIELDS)/i) { - if ($self->Uid) { - if ( my($msgid) = $header =~ /UID\s+(\d+)/ ) { - $h = {}; - $headers->{$msgid} = $h; - } else { - $h = {}; - } - } else { - if ( my($msgid) = $header =~ /^\*\s+(\d+)/ ) { - #start of new message header: - $h = {}; - $headers->{$msgid} = $h; - } - } - } - next if $header =~ /^\s+$/; - - # ( for vi - if ($header =~ /^\)/) { # end of this message - $h = 0; # set to be between messages - next; - } - # check for 'UID)' - # when parsing headers by UID. - if ($self->Uid and my($msgid) = $header =~ /^\s*UID\s+(\d+)\s*\)/) { - $headers->{$msgid} = $h; # store in results against this message - $h = 0; # set to be between messages - next; - } - - if ($h != 0) { # do we expect this to be a header? - my $hdr = $header; - chomp $hdr; - $hdr =~ s/\r$//; - if ($hdr =~ s/^(\S+):\s*//) { - $field = exists $fieldmap{lc($1)} ? $fieldmap{lc($1)} : $1 ; - push @{$h->{$field}} , $hdr ; - } elsif ($hdr =~ s/^.*FETCH\s\(.*BODY\[HEADER\.FIELDS.*\)\]\s(\S+):\s*//) { - $field = exists $fieldmap{lc($1)} ? $fieldmap{lc($1)} : $1 ; - push @{$h->{$field}} , $hdr ; - } elsif ( ref($h->{$field}) eq 'ARRAY') { - - $hdr =~ s/^\s+/ /; - $h->{$field}[-1] .= $hdr ; - } - } - } - my $candump = 0; - if ($self->Debug) { - eval { - require Data::Dumper; - Data::Dumper->import; - }; - $candump++ unless $@; - } - # if we asked for one message, just return its hash, - # otherwise, return hash of numbers => header hash - # if (ref($msgspec) eq 'ARRAY') { - if (ref($msgspec) ) { - #_debug $self,"Structure from parse_headers:\n", - # Dumper($headers) - # if $self->Debug; - return $headers; - } else { - #_debug $self, "Structure from parse_headers:\n", - # Dumper($headers->{$msgspec}) - # if $self->Debug; - return $headers->{$msgspec}; - } -} - -sub subject { return $_[0]->get_header($_[1],"Subject") } -sub date { return $_[0]->get_header($_[1],"Date") } -sub rfc822_header { get_header(@_) } - -sub get_header { - my($self , $msg, $header ) = @_; - my $val = 0; - eval { $val = $self->parse_headers($msg,$header)->{$header}[0] }; - return defined($val)? $val : undef; -} - -sub recent_count { - my ($self, $folder) = (shift, shift); - - $self->status($folder, 'RECENT') or return undef; - - chomp(my $r = ( grep { s/\*\s+STATUS\s+.*\(RECENT\s+(\d+)\s*\)/$1/ } - $self->History($self->Transaction) - )[0]); - - $r =~ s/\D//g; - - return $r; -} - -sub message_count { - - my ($self, $folder) = (shift, shift); - $folder ||= $self->Folder; - - $self->status($folder, 'MESSAGES') or return undef; - foreach my $result (@{$self->{"History"}{$self->Transaction}}) { - return $1 if $result->[DATA] =~ /\(MESSAGES\s+(\d+)\s*\)/ ; - } - - return undef; - -} - -{ -for my $datum ( - qw( recent seen - unseen messages - ) -) { - no strict 'refs'; - *$datum = sub { - my $self = shift; - #my @hits; - - #my $hits = $self->search($datum eq "messages" ? "ALL" : "$datum") - # or return undef; - #print "Received $hits from search and array context flag is ", - # wantarry,"\n"; - #if ( scalar(@$hits) ) { - # return wantarray ? @$hits : $hits ; - #} - return $self->search($datum eq "messages" ? "ALL" : "$datum") ; - - - }; -} -} -{ -for my $datum ( - qw( sentbefore sentsince senton - since before on - ) -) { - no strict 'refs'; - *$datum = sub { - - my($self,$time) = (shift,shift); - - my @hits; my $imapdate; - my @mnt = qw{ Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec}; - - if ( $time =~ /\d\d-\D\D\D-\d\d\d\d/ ) { - $imapdate = $time; - } elsif ( $time =~ /^\d+$/ ) { - my @ltime = localtime($time); - $imapdate = sprintf( "%2.2d-%s-%4.4d", - $ltime[3], $mnt[$ltime[4]], $ltime[5] + 1900); - } else { - $self->LastError("Invalid date format supplied to '$datum' method."); - return undef; - } - $self->_imap_command( ($self->Uid ? "UID " : "") . "SEARCH $datum $imapdate") - or return undef; - my @results = $self->History($self->Count) ; - - for my $r (@results) { - - chomp $r; - $r =~ s/\r$//; - $r =~ s/^\*\s+SEARCH\s+//i or next; - push @hits, grep(/\d/,(split(/\s+/,$r))); - _debug $self, "Hits are now: ",join(',',@hits),"\n" if $self->Debug; - } - - return wantarray ? @hits : \@hits; - } -} -} - -sub or { - - my $self = shift ; - my @what = @_; - my @hits; - - if ( scalar(@what) < 2 ) { - $self->LastError("Invalid number of arguments passed to or method.\n"); - return undef; - } - - my $or = "OR " . $self->Massage(shift @what); - $or .= " " . $self->Massage(shift @what); - - - for my $w ( @what ) { - my $w = $self->Massage($w) ; - $or = "OR " . $or . " " . $w ; - } - - $self->_imap_command( ($self->Uid ? "UID " : "") . "SEARCH $or") - or return undef; - my @results = $self->History($self->Count) ; - - for my $r (@results) { - - chomp $r; - $r =~ s/\r$//; - $r =~ s/^\*\s+SEARCH\s+//i or next; - push @hits, grep(/\d/,(split(/\s+/,$r))); - _debug $self, "Hits are now: ",join(',',@hits),"\n" - if $self->Debug; - } - - return wantarray ? @hits : \@hits; -} - -#sub Strip_cr { -# my $self = shift; - -# my $in = $_[0]||$self ; - -# $in =~ s/\r//g ; - -# return $in; -#} - - -sub disconnect { $_[0]->logout } - - -sub search { - - my $self = shift; - my @hits; - my @a = @_; - $@ = ""; - # massage? - $a[-1] = $self->Massage($a[-1],1) - if scalar(@a) > 1 and !exists($SEARCH_KEYS{uc($a[-1])}); - $self->_imap_command( ( $self->Uid ? "UID " : "" ) . "SEARCH ". join(' ',@a)) - or return undef; - my $results = $self->History($self->Count) ; - - - for my $r (@$results) { - #$self->_debug("Considering the search result line: $r"); - chomp $r; - $r =~ s/\r\n?/ /g; - $r =~ s/^\*\s+SEARCH\s+(?=.*\d.*)// or next; - my @h = grep(/^\d+$/,(split(/\s+/,$r))); - push @hits, @h if scalar(@h) ; # and grep(/\d/,@h) ); - - } - - $self->{LastError}="Search completed successfully but found no matching messages\n" - unless scalar(@hits); - - if ( wantarray ) { - return @hits; - } else { - if ($self->Ranges) { - #print STDERR "Fetch: Returning range\n"; - return scalar(@hits) ? $self->Range(\@hits) : undef; - } else { - #print STDERR "Fetch: Returning ref\n"; - return scalar(@hits) ? \@hits : undef; - } - } -} - -sub thread { - # returns a Thread data structure - # - # $imap->thread($algorythm, $charset, @search_args); - my $self = shift; - - my $algorythm = shift; - $algorythm ||= $self->has_capability("THREAD=REFERENCES") ? "REFERENCES" : "ORDEREDSUBJECT"; - my $charset = shift; - $charset ||= "UTF-8"; - - my @a = @_; - - $a[0]||="ALL" ; - my @hits; - # massage? - - $a[-1] = $self->Massage($a[-1],1) - if scalar(@a) > 1 and !exists($SEARCH_KEYS{uc($a[-1])}); - $self->_imap_command( ( $self->Uid ? "UID " : "" ) . - "THREAD $algorythm $charset " . - join(' ',@a) - ) or return undef; - my $results = $self->History($self->Count) ; - - my $thread = ""; - for my $r (@$results) { - #$self->_debug("Considering the search result line: $r"); - chomp $r; - $r =~ s/\r\n?/ /g; - if ( $r =~ /^\*\s+THREAD\s+/ ) { - eval { require "Mail/IMAPClient/Thread.pm" } - or ( $self->LastError($@), return undef); - my $parser = Mail::IMAPClient::Thread->new(); - $thread = $parser->start($r) ; - } else { - next; - } - #while ( $r =~ /(\([^\)]*\))/ ) { - # push @hits, [ split(/ /,$1) ] ; - #} - } - - $self->{LastError}="Thread search completed successfully but found no matching messages\n" - unless ref($thread); - return $thread ||undef; - - if ( wantarray ) { - - return @hits; - } else { - return scalar(@hits) ? \@hits : undef; - } -} - - - - -sub delete_message { - - my $self = shift; - my $count = 0; - my @msgs = (); - for my $arg (@_) { - if (ref($arg) eq 'ARRAY') { - push @msgs, @{$arg}; - } else { - push @msgs, split(/\,/,$arg); - } - } - - - $self->store(join(',',@msgs),'+FLAGS.SILENT','(\Deleted)') and $count = scalar(@msgs); - - return $count; -} - -sub restore_message { - - my $self = shift; - my @msgs = (); - for my $arg (@_) { - if (ref($arg) eq 'ARRAY') { - push @msgs, @{$arg}; - } else { - push @msgs, split(/\,/,$arg); - } - } - - - $self->store(join(',',@msgs),'-FLAGS','(\Deleted)') ; - my $count = grep( - / - ^\* # Start with an asterisk - \s\d+ # then a space then a number - \sFETCH # then a space then the string 'FETCH' - \s\( # then a space then an open paren :-) - .* # plus optional anything - FLAGS # then the string "FLAGS" - .* # plus anything else - (?!\\Deleted) # but never "\Deleted" - /x, - $self->Results - ); - - - return $count; -} - - -sub uidvalidity { - - my $self = shift; my $folder = shift; - - my $vline = (grep(/UIDVALIDITY/i, $self->status($folder, "UIDVALIDITY")))[0]; - - my($validity) = $vline =~ /\(UIDVALIDITY\s+([^\)]+)/; - - return $validity; -} - -# 3 status folder (uidnext) -# * STATUS folder (UIDNEXT 290) - -sub uidnext { - - my $self = shift; my $folder = $self->Massage(shift); - - my $line = (grep(/UIDNEXT/i, $self->status($folder, "UIDNEXT")))[0]; - - my($uidnext) = $line =~ /\(UIDNEXT\s+([^\)]+)/; - - return $uidnext; -} - -sub capability { - - my $self = shift; - - $self->_imap_command('CAPABILITY') or return undef; - - my @caps = ref($self->{CAPABILITY}) ? - keys %{$self->{CAPABILITY}} : - map { split } - grep (s/^\*\s+CAPABILITY\s+//, - $self->History($self->Count)); - - unless ( exists $self->{CAPABILITY} ) { - for (@caps) { - $self->{CAPABILITY}{uc($_)}++ ; - if (/=/) { - my($k,$v)=split(/=/,$_) ; - $self->{uc($k)} = uc($v) ; - } - } - } - - - return wantarray ? @caps : \@caps; -} - -sub has_capability { - my $self = shift; - $self->capability; - local($^W)=0; - return $self->{CAPABILITY}{uc($_[0])}; -} - -sub imap4rev1 { - my $self = shift; - return exists($self->{_IMAP4REV1}) ? - $self->{_IMAP4REV1} : - $self->{_IMAP4REV1} = $self->has_capability(IMAP4REV1) ; -} - -sub namespace { - # Returns a (reference to a?) nested list as follows: - # [ - # [ - # [ $user_prefix, $user_delim ] (,[$user_prefix2 ,$user_delim ], [etc,etc] ), - # ], - # [ - # [ $shared_prefix,$shared_delim] (,[$shared_prefix2,$shared_delim], [etc,etc] ), - # ], - # [ - # [$public_prefix, $public_delim] (,[$public_prefix2,$public_delim], [etc,etc] ), - # ], - # ] ; - - my $self = shift; - unless ( $self->has_capability("NAMESPACE") ) { - my $error = $self->Count . " NO NAMESPACE not supported by " . $self->Server ; - $self->LastError("$error\n") ; - $self->_debug("$error\n") ; - $@ = $error; - carp "$@" if $^W; - return undef; - } - my $namespace = (map({ /^\* NAMESPACE (.*)/ ? $1 : () } @{$self->_imap_command("NAMESPACE")->Results}))[0] ; - $namespace =~ s/\x0d?\x0a$//; - my($personal,$shared,$public) = $namespace =~ m# - (NIL|\((?:\([^\)]+\)\s*)+\))\s - (NIL|\((?:\([^\)]+\)\s*)+\))\s - (NIL|\((?:\([^\)]+\)\s*)+\)) - #xi; - - my @ns = (); - $self->_debug("NAMESPACE: pers=$personal, shared=$shared, pub=$public\n"); - push @ns, map { - $_ =~ s/^\((.*)\)$/$1/; - my @pieces = m#\(([^\)]*)\)#g; - $self->_debug("NAMESPACE pieces: " . join(", ",@pieces) . "\n"); - my $ref = []; - foreach my $atom (@pieces) { - push @$ref, [ $atom =~ m#"([^"]*)"\s*#g ] ; - } - $_ =~ /^NIL$/i ? undef : $ref; - } ( $personal, $shared, $public) ; - return wantarray ? @ns : \@ns; -} - -# Contributed by jwm3 -sub internaldate { - my $self = shift; - my $msg = shift; - $self->_imap_command( ( $self->Uid ? "UID " : "" ) . "FETCH $msg INTERNALDATE") or return undef; - my $internalDate = join("", $self->History($self->Count)); - $internalDate =~ s/^.*INTERNALDATE "//si; - $internalDate =~ s/\".*$//s; - return $internalDate; -} - -sub is_parent { - my ($self, $folder) = (shift, shift); - # $self->_debug("Checking parentage ".( $folder ? "for folder $folder" : "" )."\n"); - my $list = $self->list(undef, $folder)||"NO NO BAD BAD"; - my $line = ''; - - for (my $m = 0; $m < scalar(@$list); $m++ ) { - #$self->_debug("Judging whether or not $list->[$m] is fit for parenthood\n"); - return undef - if $list->[$m] =~ /NoInferior/i; # let's not beat around the bush! - - if ($list->[$m] =~ s/(\{\d+\})\x0d\x0a$// ) { - $list->[$m] .= $list->[$m+1]; - $list->[$m+1] = ""; - } - - $line = $list->[$m] - if $list->[$m] =~ - / ^\*\s+LIST # * LIST - \s+\([^\)]*\)\s+ # (Flags) - "[^"]*"\s+ # "delimiter" - (?:"([^"]*)"|(.*))\x0d\x0a$ # Name or "Folder name" - /x; - } - if ( $line eq "" ) { - $self->_debug("Warning: separator method found no correct o/p in:\n\t" . - join("\t",@list)."\n"); - } - my($f) = $line =~ /^\*\s+LIST\s+\(([^\)]*)\s*\)/ if $line; - return 1 if $f =~ /HasChildren/i ; - return 0 if $f =~ /HasNoChildren/i ; - unless ( $f =~ /\\/) { # no flags at all unless there's a backslash - my $sep = $self->separator($folder); - return 1 if scalar(grep /^${folder}${sep}/, $self->folders); - return 0; - } -} - -sub selectable {my($s,$f)=@_;return grep(/NoSelect/i,$s->list("",$f))?0:1;} - -sub append_string { - - my $self = shift; - my $folder = $self->Massage(shift); - - my $text = shift; - $text =~ s/\x0d?\x0a/\x0d\x0a/g; - - my($flags,$date) = (shift,shift); - - if (defined($flags)) { - $flags =~ s/^\s+//g; - $flags =~ s/\s+$//g; - } - - if (defined($date)) { - $date =~ s/^\s+//g; - $date =~ s/\s+$//g; - } - - $flags = "($flags)" if $flags and $flags !~ /^\(.*\)$/ ; - $date = qq/"$date"/ if $date and $date !~ /^"/ ; - - my $clear = $self->Clear; - - $self->Clear($clear) - if $self->Count >= $clear and $clear > 0; - - my $count = $self->Count($self->Count+1); - - my $string = "$count APPEND $folder " . - ( $flags ? "$flags " : "" ) . - ( $date ? "$date " : "" ) . - "{" . length($text) . "}\x0d\x0a" ; - - $self->_record($count,[ $self->_next_index($count), "INPUT", "$string\x0d\x0a" ] ); - - # Step 1: Send the append command. - - my $feedback = $self->_send_line("$string"); - - unless ($feedback) { - $self->LastError("Error sending '$string' to IMAP: $!\n"); - return undef; - } - - my ($code, $output) = ("",""); - - # Step 2: Get the "+ go ahead" response - until ( $code ) { - $output = $self->_read_line or return undef; - foreach my $o (@$output) { - - $self->_record($count,$o); # $o is already an array ref - next unless $self->_is_output($o); - - ($code) = $o->[DATA] =~ /(^\+|^\d*\s*NO|^\d*\s*BAD)/i ; - - if ($o->[DATA] =~ /^\*\s+BYE/i) { - $self->LastError("Error trying to append string: " . - $o->[DATA]. "; Disconnected.\n"); - $self->_debug("Error trying to append string: " . $o->[DATA]. - "; Disconnected.\n"); - carp("Error trying to append string: " . $o->[DATA] ."; Disconnected") if $^W; - $self->State(Unconnected); - - } elsif ( $o->[DATA] =~ /^\d*\s*(NO|BAD)/i ) { # i and / transposed!!! - $self->LastError("Error trying to append string: " . $o->[DATA] . "\n"); - $self->_debug("Error trying to append string: " . $o->[DATA] . "\n"); - carp("Error trying to append string: " . $o->[DATA]) if $^W; - return undef; - } - } - } - - $self->_record($count,[ $self->_next_index($count), "INPUT", "$text\x0d\x0a" ] ); - - # Step 3: Send the actual text of the message: - $feedback = $self->_send_line("$text\x0d\x0a"); - - unless ($feedback) { - $self->LastError("Error sending append msg text to IMAP: $!\n"); - return undef; - } - $code = undef; # clear out code - - # Step 4: Figure out the results: - until ($code) { - $output = $self->_read_line or return undef; - $self->_debug("Append results: " . map({ $_->[DATA] } @$output) . "\n" ) - if $self->Debug; - foreach my $o (@$output) { - $self->_record($count,$o); # $o is already an array ref - - ($code) = $o->[DATA] =~ /^(?:$count|\*) (OK|NO|BAD)/im ; - - if ($o->[DATA] =~ /^\*\s+BYE/im) { - $self->State(Unconnected); - $self->LastError("Error trying to append: " . $o->[DATA] . "\n"); - $self->_debug("Error trying to append: " . $o->[DATA] . "\n"); - carp("Error trying to append: " . $o->[DATA] ) if $^W; - } - if ($code and $code !~ /^OK/im) { - $self->LastError("Error trying to append: " . $o->[DATA] . "\n"); - $self->_debug("Error trying to append: " . $o->[DATA] . "\n"); - carp("Error trying to append: " . $o->[DATA] ) if $^W; - return undef; - } - } - } - - my($uid) = join("",map { $_->[TYPE] eq "OUTPUT" ? $_->[DATA] : () } @$output ) =~ m#\s+(\d+)\]#; - - return defined($uid) ? $uid : $self; -} -sub append { - - my $self = shift; - # now that we're passing thru to append_string we won't massage here - # my $folder = $self->Massage(shift); - my $folder = shift; - - my $text = join("\x0d\x0a",@_); - $text =~ s/\x0d?\x0a/\x0d\x0a/g; - return $self->append_string($folder,$text); -} - -sub append_file { - - my $self = shift; - my $folder = $self->Massage(shift); - my $file = shift; - my $control = shift || undef; - my $count = $self->Count($self->Count+1); - - - unless ( -f $file ) { - $self->LastError("File $file not found.\n"); - return undef; - } - - my $fh = IO::File->new($file) ; - - unless ($fh) { - $self->LastError("Unable to open $file: $!\n"); - $@ = "Unable to open $file: $!" ; - carp "unable to open $file: $!" if $^W; - return undef; - } - - my $bare_nl_count = scalar grep { /^\x0a$|[^\x0d]\x0a$/} <$fh>; - - seek($fh,0,0); - - my $clear = $self->Clear; - - $self->Clear($clear) - if $self->Count >= $clear and $clear > 0; - - my $length = ( -s $file ) + $bare_nl_count; - - my $string = "$count APPEND $folder {" . $length . "}\x0d\x0a" ; - - $self->_record($count,[ $self->_next_index($count), "INPUT", "$string" ] ); - - my $feedback = $self->_send_line("$string"); - - unless ($feedback) { - $self->LastError("Error sending '$string' to IMAP: $!\n"); - close $fh; - return undef; - } - - my ($code, $output) = ("",""); - - until ( $code ) { - $output = $self->_read_line or close $fh, return undef; - foreach my $o (@$output) { - $self->_record($count,$o); # $o is already an array ref - ($code) = $o->[DATA] =~ /(^\+|^\d+\sNO|^\d+\sBAD)/i; - if ($o->[DATA] =~ /^\*\s+BYE/) { - carp $o->[DATA] if $^W; - $self->State(Unconnected); - close $fh; - return undef ; - } elsif ( $o->[DATA]=~ /^\d+\s+(NO|BAD)/i ) { - carp $o->[DATA] if $^W; - close $fh; - return undef; - } - } - } - - { # Narrow scope - # Slurp up headers: later we'll make this more efficient I guess - local $/ = "\x0d\x0a\x0d\x0a"; - my $text = <$fh>; - $text =~ s/\x0d?\x0a/\x0d\x0a/g; - $self->_record($count,[ $self->_next_index($count), "INPUT", "{From file $file}" ] ) ; - $feedback = $self->_send_line($text); - - unless ($feedback) { - $self->LastError("Error sending append msg text to IMAP: $!\n"); - close $fh; - return undef; - } - _debug $self, "control points to $$control\n" if ref($control) and $self->Debug; - $/ = ref($control) ? "\x0a" : $control ? $control : "\x0a"; - while (defined($text = <$fh>)) { - $text =~ s/\x0d?\x0a/\x0d\x0a/g; - $self->_record( $count, - [ $self->_next_index($count), "INPUT", "{from $file}\x0d\x0a" ] - ); - $feedback = $self->_send_line($text,1); - - unless ($feedback) { - $self->LastError("Error sending append msg text to IMAP: $!\n"); - close $fh; - return undef; - } - } - $feedback = $self->_send_line("\x0d\x0a"); - - unless ($feedback) { - $self->LastError("Error sending append msg text to IMAP: $!\n"); - close $fh; - return undef; - } - } - - # Now for the crucial test: Did the append work or not? - ($code, $output) = ("",""); - - my $uid = undef; - until ( $code ) { - $output = $self->_read_line or return undef; - foreach my $o (@$output) { - $self->_record($count,$o); # $o is already an array ref - $self->_debug("append_file: Deciding if " . $o->[DATA] . " has the code.\n") - if $self->Debug; - ($code) = $o->[DATA] =~ /^\d+\s(NO|BAD|OK)/i; - # try to grab new msg's uid from o/p - $o->[DATA] =~ m#UID\s+\d+\s+(\d+)\]# and $uid = $1; - if ($o->[DATA] =~ /^\*\s+BYE/) { - carp $o->[DATA] if $^W; - $self->State(Unconnected); - close $fh; - return undef ; - } elsif ( $o->[DATA]=~ /^\d+\s+(NO|BAD)/i ) { - carp $o->[DATA] if $^W; - close $fh; - return undef; - } - } - } - close $fh; - - if ($code !~ /^OK/i) { - return undef; - } - - - return defined($uid) ? $uid : $self; -} - - -sub authenticate { - - my $self = shift; - my $scheme = shift; - my $response = shift; - - $scheme ||= $self->Authmechanism; - $response ||= $self->Authcallback; - my $clear = $self->Clear; - - $self->Clear($clear) - if $self->Count >= $clear and $clear > 0; - - my $count = $self->Count($self->Count+1); - - - my $string = "$count AUTHENTICATE $scheme"; - - $self->_record($count,[ $self->_next_index($self->Transaction), - "INPUT", "$string\x0d\x0a"] ); - - my $feedback = $self->_send_line("$string"); - - unless ($feedback) { - $self->LastError("Error sending '$string' to IMAP: $!\n"); - return undef; - } - - my ($code, $output); - - until ($code) { - $output = $self->_read_line or return undef; - foreach my $o (@$output) { - $self->_record($count,$o); # $o is a ref - ($code) = $o->[DATA] =~ /^\+(.*)$/ ; - if ($o->[DATA] =~ /^\*\s+BYE/) { - $self->State(Unconnected); - return undef ; - } - } - } - - return undef if $code =~ /^BAD|^NO/ ; - - if ('CRAM-MD5' eq $scheme && ! $response) { - if ($Mail::IMAPClient::_CRAM_MD5_ERR) { - $self->LastError($Mail::IMAPClient::_CRAM_MD5_ERR); - carp $Mail::IMAPClient::_CRAM_MD5_ERR if $^W; - } else { - $response = \&_cram_md5; - } - } - - $feedback = $self->_send_line($response->($code, $self)); - - unless ($feedback) { - $self->LastError("Error sending append msg text to IMAP: $!\n"); - return undef; - } - - $code = ""; # clear code - until ($code) { - $output = $self->_read_line or return undef; - foreach my $o (@$output) { - $self->_record($count,$o); # $o is a ref - if ( ($code) = $o->[DATA] =~ /^\+ (.*)$/ ) { - $feedback = $self->_send_line($response->($code,$self)); - unless ($feedback) { - $self->LastError("Error sending append msg text to IMAP: $!\n"); - return undef; - } - $code = "" ; # Clear code; we're still not finished - } else { - $o->[DATA] =~ /^$count (OK|NO|BAD)/ and $code = $1; - if ($o->[DATA] =~ /^\*\s+BYE/) { - $self->State(Unconnected); - return undef ; - } - } - } - } - - $code =~ /^OK/ and $self->State(Authenticated) ; - return $code =~ /^OK/ ? $self : undef ; - -} - -# UIDPLUS response from a copy: [COPYUID (uidvalidity) (origuid) (newuid)] -sub copy { - - my($self, $target, @msgs) = @_; - - $target = $self->Massage($target); - if ( $self->Ranges ) { - @msgs = ($self->Range(@msgs)); - } else { - @msgs = sort { $a <=> $b } map { ref($_)? @$_ : split(',',$_) } @msgs; - } - - $self->_imap_command( - ( $self->Uid ? "UID " : "" ) . - "COPY " . - ( $self->Ranges ? $self->Range(@msgs) : - join(',',map { ref($_)? @$_ : $_ } @msgs)) . - " $target" - ) or return undef ; - my @results = $self->History($self->Count) ; - - my @uids; - - for my $r (@results) { - - chomp $r; - $r =~ s/\r$//; - $r =~ s/^.*\[COPYUID\s+\d+\s+[\d:,]+\s+([\d:,]+)\].*/$1/ or next; - push @uids, ( $r =~ /(\d+):(\d+)/ ? $1 ... $2 : split(/,/,$r) ) ; - - } - - return scalar(@uids) ? join(",",@uids) : $self; -} - -sub move { - - my($self, $target, @msgs) = @_; - - $self->create($target) and $self->subscribe($target) - unless $self->exists($target); - - my $uids = $self->copy($target, map { ref($_) =~ /ARRAY/ ? @{$_} : $_ } @msgs) - or return undef; - - $self->delete_message(@msgs) or carp $self->LastError; - - return $uids; -} - -sub set_flag { - my($self, $flag, @msgs) = @_; - if ( ref($msgs[0]) =~ /ARRAY/ ) { @msgs = @{$msgs[0]} }; - $flag =~ /^\\/ or $flag = "\\" . $flag - if $flag =~ /^(Answered|Flagged|Deleted|Seen|Draft)$/i; - if ( $self->Ranges ) { - $self->store( $self->Range(@msgs), "+FLAGS.SILENT (" . $flag . ")" ); - } else { - $self->store( join(",",@msgs), "+FLAGS.SILENT (" . $flag . ")" ); - } -} - -sub see { - my($self, @msgs) = @_; - if ( ref($msgs[0]) =~ /ARRAY/ ) { @msgs = @{$msgs[0]} }; - $self->set_flag('\\Seen', @msgs); -} - -sub mark { - my($self, @msgs) = @_; - if ( ref($msgs[0]) =~ /ARRAY/ ) { @msgs = @{$msgs[0]} }; - $self->set_flag('\\Flagged', @msgs); -} - -sub unmark { - my($self, @msgs) = @_; - if ( ref($msgs[0]) =~ /ARRAY/ ) { @msgs = @{$msgs[0]} }; - $self->unset_flag('\\Flagged', @msgs); -} - -sub unset_flag { - my($self, $flag, @msgs) = @_; - if ( ref($msgs[0]) =~ /ARRAY/ ) { @msgs = @{$msgs[0]} }; - $flag =~ /^\\/ or $flag = "\\" . $flag - if $flag =~ /^(Answered|Flagged|Deleted|Seen|Draft)$/i; - $self->store( join(",",@msgs), "-FLAGS.SILENT (" . $flag . ")" ); -} - -sub deny_seeing { - my($self, @msgs) = @_; - if ( ref($msgs[0]) =~ /ARRAY/ ) { @msgs = @{$msgs[0]} }; - $self->unset_flag('\\Seen', @msgs); -} - -sub size { - - my ($self,$msg) = @_; - # return undef unless fetch is successful - my @data = $self->fetch($msg,"(RFC822.SIZE)"); - return undef unless defined($data[0]); - my($size) = grep(/RFC822\.SIZE/,@data); - - $size =~ /RFC822\.SIZE\s+(\d+)/; - - return $1; -} - -sub getquotaroot { - my $self = shift; - my $what = shift; - $what = ( $what ? $self->Massage($what) : "INBOX" ) ; - $self->_imap_command("getquotaroot $what") or return undef; - return $self->Results; -} - -sub getquota { - my $self = shift; - my $what = shift; - $what = ( $what ? $self->Massage($what) : "user/$self->{User}" ) ; - $self->_imap_command("getquota $what") or return undef; - return $self->Results; -} - -sub quota { - my $self = shift; - my ($what) = shift||"INBOX"; - $self->_imap_command("getquota $what")||$self->getquotaroot("$what"); - return ( map { s/.*STORAGE\s+\d+\s+(\d+).*\n$/$1/ ? $_ : () } $self->Results - )[0] ; -} - -sub quota_usage { - my $self = shift; - my ($what) = shift||"INBOX"; - $self->_imap_command("getquota $what")||$self->getquotaroot("$what"); - return ( map { s/.*STORAGE\s+(\d+)\s+\d+.*\n$/$1/ ? $_ : () } $self->Results - )[0] ; -} -sub Quote { - my($class,$arg) = @_; - return $class->Massage($arg,NonFolderArg); -} - -sub Massage { - my $self= shift; - my $arg = shift; - my $notFolder = shift; - return unless $arg; - my $escaped_arg = $arg; $escaped_arg =~ s/"/\\"/g; - $arg = substr($arg,1,length($arg)-2) if $arg =~ /^".*"$/ - and ! ( $notFolder or $self->STATUS(qq("$escaped_arg"),"(MESSAGES)")); - - if ($arg =~ /["\\]/) { - $arg = "{" . length($arg) . "}\x0d\x0a$arg" ; - } elsif ($arg =~ /\s|[{}()]/) { - $arg = qq("${arg}") unless $arg =~ /^"/; - } - - return $arg; -} - -sub unseen_count { - - my ($self, $folder) = (shift, shift); - $folder ||= $self->Folder; - $self->status($folder, 'UNSEEN') or return undef; - - chomp( my $r = ( grep - { s/\*\s+STATUS\s+.*\(UNSEEN\s+(\d+)\s*\)/$1/ } - $self->History($self->Transaction) - )[0] - ); - - $r =~ s/\D//g; - return $r; -} - - - -# Status Routines: - - -sub Status { $_[0]->State ; } -sub IsUnconnected { ($_[0]->State == Unconnected) ? 1 : 0 ; } -sub IsConnected { ($_[0]->State >= Connected) ? 1 : 0 ; } -sub IsAuthenticated { ($_[0]->State >= Authenticated)? 1 : 0 ; } -sub IsSelected { ($_[0]->State == Selected) ? 1 : 0 ; } - - -# The following private methods all work on an output line array. -# _data returns the data portion of an output array: -sub _data { defined $_[1] and ref $_[1] and defined $_[1]->[TYPE] or return undef; $_[1]->[DATA]; } - -# _index returns the index portion of an output array: -sub _index { defined $_[1] and ref $_[1] and defined $_[1]->[TYPE] or return undef; $_[1]->[INDEX]; } - -# _type returns the type portion of an output array: -sub _type { defined $_[1] and ref $_[1] and defined $_[1]->[TYPE] or return undef; $_[1]->[TYPE]; } - -# _is_literal returns true if this is a literal: -sub _is_literal { defined $_[1] and ref $_[1] and defined $_[1]->[TYPE] and $_[1]->[TYPE] eq "LITERAL" }; - -# _is_output_or_literal returns true if this is an -# output line (or the literal part of one): -sub _is_output_or_literal { - defined $_[1] and ref $_[1] and defined $_[1]->[TYPE] and - ($_[1]->[TYPE] eq "OUTPUT" || $_[1]->[TYPE] eq "LITERAL") -}; - -# _is_output returns true if this is an output line: -sub _is_output { defined $_[1] and ref $_[1] and defined $_[1]->[TYPE] and $_[1]->[TYPE] eq "OUTPUT" }; - -# _is_input returns true if this is an input line: -sub _is_input { defined $_[1] and ref $_[1] and defined $_[1]->[TYPE] and $_[1]->[TYPE] eq "INPUT" }; - -# _next_index returns next_index for a transaction; may legitimately return 0 when successful. -sub _next_index { - defined(scalar(@{$_[0]->{'History'}{$_[1]||$_[0]->Transaction}})) ? - scalar(@{$_[0]->{'History'}{$_[1]||$_[0]->Transaction}}) : 0 -}; - -sub _cram_md5 { - my ($code, $client) = @_; - my $hmac = Digest::HMAC_MD5::hmac_md5_hex(MIME::Base64::decode($code), - $client->Password()); - return MIME::Base64::encode($client->User() . " $hmac"); -} - - - -sub Range { - require "Mail/IMAPClient/MessageSet.pm"; - my $self = shift; - my $targ = $_[0]; - #print "Arg is ",ref($targ),"\n"; - if (@_ == 1 and ref($targ) =~ /Mail::IMAPClient::MessageSet/ ) { - return $targ; - } - my $range = Mail::IMAPClient::MessageSet->new(@_); - #print "Returning $range :",ref($range)," == $range\n"; - return $range; -} - -my $not_void = 1; diff --git a/W/Mail-IMAPClient-2.2.9/IMAPClient.pod b/W/Mail-IMAPClient-2.2.9/IMAPClient.pod deleted file mode 100644 index 3abe92f..0000000 --- a/W/Mail-IMAPClient-2.2.9/IMAPClient.pod +++ /dev/null @@ -1,3702 +0,0 @@ -package Mail::IMAPClient; - -# $Id: IMAPClient.pod,v 20001010.1 2003/06/12 21:35:53 dkernen Exp $ - -$Mail::IMAPClient::VERSION = '2.2.7'; -$Mail::IMAPClient::VERSION = '2.2.7'; # do it twice to make sure it takes - -=head1 NAME - -Mail::IMAPClient - An IMAP Client API - -=head1 DESCRIPTION - -This module provides methods implementing the IMAP protocol. It allows -perl scripts to interact with IMAP message stores. - -The module is used by constructing or instantiating a new IMAPClient -object via the L constructor method. Once the object has been -instantiated, the L method is either implicitly or explicitly -called. At that point methods are available that implement the IMAP -client commands as specified in I. When processing is -complete, the I object method should be called. - -This documentation is not meant to be a replacement for RFC2060, and -the wily programmer will have a copy of that document handy when coding -IMAP clients. - -Note that this documentation uses the term I in place of -RFC2060's use of I. This documentation reserves the use of the -term I to refer to the set of folders owned by a specific IMAP -id. - -RFC2060 defines four possible states for an IMAP connection: not -authenticated, authenticated, selected, and logged out. These -correspond to the B constants C, -C, C, and C, respectively. These -constants are implemented as class methods, and can be used in -conjunction with the L method to determine the status of an -B object and its underlying IMAP session. Note that an -B object can be in the C state both before a -server connection is made and after it has ended. This differs slightly -from RFC2060, which does not define a pre-connection status. For a -discussion of the methods available for examining the B -object's status, see the section labeled L<"Status Methods">, below. - -=head2 Advanced Authentication Mechanisms - -RFC2060 defines two commands for authenticating to an IMAP server: LOGIN for -plain text authentication and AUTHENTICATE for more secure authentication -mechanisms. Currently Mail::IMAPClient supports CRAM-MD5 and plain text -authentication. There are also a number of methods and parameters that you -can use to build your own authentication mechanism. Since this topic is a source -of many questions, I will provide a quick overview here. All of the methods and -parameters discussed here are described in more detail elsewhere in this document; -this section is meant to help you get started. - -First of all, if you just want to do plain text authentication and your server is -okay with that idea then you don't even need to read this section. - -Second of all, the intent of this section is to help you implement the authentication -mechanism of your choice, but you will have to understand how that mechanism works. -There are I of authentication mechanisms and most of them are not available to -me to test with for one reason or another. Even if this section does not answer -all of your authentication questions it I contain all the answers that I have, -which I admit are scant. - -Third of all, if you manage to get any advanced authentication mechanisms to work then -please consider donating them to this module. I don't quite have a framework visualized -for how different authentication mechanisms could "plug in" to this module but I would -like to eventually see this module distributed with a number of helper modules to -implement various authentication schemes. - -The B's support for add-on authentication mechanisms is pretty straight -forward and is built upon several assumptions. Basically you create a callback to be used to -provide the response to the server's challenge. The I parameter contains a -reference to the callback, which can be an anonymous subroutine or a named subroutine. -Then, you identify your authentication mechanism, either via the I parameter -or as an argument to L. - -You may also need to provide a subroutine to encrypt (or whatever) data before it is sent -to the server. The I parameter must contain a reference to this subroutine. -And, you will need to decrypt data from the server; a reference to the subroutine that -does this must be stored in the I parameter. - -This framework is based on the assumptions that a) the mechanism you are using requires -a challenge-response exchange, and b) the mechanism does not fundamentally alter the -exchange between client and server but merely wraps the exchange in a layer of -encryption. It particularly assumes that the line-oriented nature of the IMAP conversation -is preserved; authentication mechanisms that break up messages into blocks of a -predetermined size may still be possible but will certainly be more difficult to implement. - -Alternatively, if you have access to B, a utility included in the Cyrus IMAP -distribution, you can use that utility to broker your communications with the IMAP server. -This is quite easy to implement. An example, L, can be found in -the C subdirectory of the source distribution. - -The following list summarizes the methods and parameters that you may find useful in -implementing advanced autentication: - -=over 4 - -=item authenticate method - -This method implements the AUTHENTICATE IMAP client command as documented in RFC2060. -If you have set the I parameter then the L method will call -L instead of doing a clear text login, which is its normal behavior. -If you don't want B to call B on your behalf then you can call -it yourself. Instead of setting an I you can just pass the authmechanism -as the first argument to AUTHENTICATE. - -=item Socket Parameter - -The I parameter holds a reference to the socket connection. Normally this -is set for you by the L method, but if you are implementing an advanced -authentication technique you may choose to set up your own socket connection and then -set this parameter manually, bypassing the B method completely. - -=item State, Server, Password, and User Parameters - -If you need to make your own connection to the server and perform your authentication -manually, then you can set these parameters to keep your B object -in sync with its actual status. Of these, only the I parameter is always necessary. -The others need to be set only if you think your program will need them later. - -=item Authmechanism - -Set this to the value that AUTHENTICATE should send to the server as the authentication -mechanism. If you are brokering your own authentication then this parameter may be less -useful. It is also not needed by the L method. It exists solely so that you -can set it when you call L to instantiate your object. The B method will call -L, who will call L. If B sees that you've set an I -then it will call B, using your I and I -parameters as arguments. - -=item Authcallback - -The I parameter, if set, should contain a pointer to a subroutine. The -L method will use this as the callback argument to the B method -if the I and I parameters are both set. If you set -I but not I then the default callback for your mechanism -will be used. Unfortunately only the CRAM-MD5 authentication mechanism has a default -callback; in every other case not supplying the callback results in an error. - -Most advanced authentication mechanisms require a challenge-response exchange. After the -L method sends " AUTHENTICATE \r\n" to the IMAP -server, the server replies with a challenge. The B method then invokes -the code whose reference is stored in the I parameter as follows: - - $Authcallback->($challenge,$imap) - -where C<$Authcallback> is the code reference stored in the I parameter, -C<$challenge> is the challenge received from the IMAP server, and C<$imap> is a pointer -to the B object. The return value from the I routine -should be the response to the challenge, and that return value will be sent by the -L method to the server. - -=item Readmethod - -The I parameter points to a routine that will read data from the socket -connection. This read method will replace the B that would otherwise be -performed by B. The replacement method is called with five -arguments. The first is a pointer to the B object; the rest -are the four arguments required by the B function. Note the third argument -(which corresponds to the second argument to B) is a buffer to read into; -this will be a pointer to a scalar. So for example if your I were just -going to replace B without any intervening processing (which would be silly -but this is just an example after all) then you would set your I like this: - - $imap->Readmethod( - sub { - my($self) = shift; - my($handle,$buffer,$count,$offset) = @_; - return sysread( $handle, $$buffer, $count, $offset); - } - ); - -Note particularly the double dollar signs in C<$$buffer> in the B call; this -is not a typo! - -=item Prewritemethod - -The I, if defined, should contain a pointer to a subroutine. -It is called immediately prior to writing to the -socket connection. It is called by B with two arguments: -a reference to the B object and the ASCII text string to be written. -It should return another string that will be the actual string sent to the IMAP server. -The idea here is that your I will do whatever encryption is necessary -and then return the result to the caller so it in turn can be sent to the server. - -=back - -=head2 Errors - -If you attempt an operation that results in an error, then you can -retrieve the text of the error message by using the L -method. However, since the L method is an object method (and -not a class method) you will only be able to use this method if you've -successfully created your object. Errors in the L method can -prevent your object from ever being created. Additionally, if you -supply the I, I, and I parameters to L, it -will attempt to call B and B, either of which could -fail and cause your L method call to return C (in which case -your object will have been created but its reference will have been -discarded before ever having been returned to you). - -If this happens to you, you can always check C<$@>. B -will populate that variable with something useful if either of the -L, L, or L methods fail. In fact, as of version 2, -the C<$@> variable will always contain error info from the last error, -so you can print that instead of calling L if you wish. - -If you run your script with warnings turned on (which I'm sure you'll -do at some point because it's such a good idea) then any error message -that gets placed into the L slot (and/or in C<$@>) will -automatically generate a warning. - -=head2 Transactions - -RFC2060 requires that each line in an IMAP conversation be prefixed -with a tag. A typical conversation consists of the client issuing a -tag-prefixed command string, and the server replying with one of more -lines of output. Those lines of output will include a command -completion status code prefixed by the same tag as the original command -string. - -The B module uses a simple counter to ensure that each -client command is issued with a unique tag value. This tag value is -referred to by the B module as the transaction number. A -history is maintained by the B object documenting each -transaction. The L method returns the number of the last -transaction, and can be used to retrieve lines of text from the -object's history. - -The L parameter is used to control the size of the session -history so that long-running sessions do not eat up unreasonable -amounts of memory. See the discussion of L under L<"Parameters"> -for more information. - -The L transaction returns the history of the entire IMAP -session since the initial connection or for the last I -transactions. This provides a record of the entire conversation, -including client command strings and server responses, and is a -wonderful debugging tool as well as a useful source of raw data for -custom parsing. - -=head1 CLASS METHODS - -There are a couple of methods that can be invoked as class methods. -Generally they can be invoked as an object method as well, as a -convenience to the programmer. (That is, as a convenience to the -programmer who wrote this module, as well as the programmers using it. -It's easier I to enforce a class method's classiness.) Note that -if the L method is called as an object method, the object returned -is identical to what have would been returned if L had been called -as a class method. It doesn't give you a copy of the original object or -anything like that. - -=head2 new - -Example: - - Mail::IMAPClient->new(%args) or die "Could not new: $@\n"; - -The L method creates a new instance of an B object. If -the I parameter is passed as an argument to B, then B -will implicitly call the L method, placing the new object in -the I state. If I and I values are also -provided, then L will in turn call L, and the resulting -object will be returned from B in the I state. - -If the I parameter is not supplied then the B -object is created in the I state. - -If the B method is passed arguments then those arguments will be -treated as a list of key=>value pairs. The key should be one of the -parameters as documented under L<"Parameters">, below. - -Here are some examples: - - use Mail::IMAPClient; - - # returns an unconnected Mail::IMAPClient object: - my $imap = Mail::IMAPClient->new; - # ... - # intervening code using the 1st object, then: - # (returns a new, authenticated Mail::IMAPClient object) - $imap = Mail::IMAPClient->new( - Server => $host, - User => $id, - Password=> $pass, - Clear => 5, # Unnecessary since '5' is the default - # ... # Other key=>value pairs go here - ) or die "Cannot connect to $host as $id: $@"; - -See also L<"Parameters">, below, and L<"connect"> and L<"login"> for -information on how to manually connect and login after B. - -=cut - -=head2 Authenticated - -Example: - - $Authenticated = $imap->Authenticated(); - # or: - $imap->Authenticated($new_value); # But you'll probably never need to do this - -returns a value equal to the numerical value associated with an object -in the B state. This value is normally maintained by the -B module, so you typically will only query it and -won't need to set it. - -B For a more programmer-friendly idiom, see the L, -L, L, and L object methods. You -will usually want to use those methods instead of one of the above. - -=head2 Connected - -Example: - - $Connected = $imap->Connected(); - # or: - $imap->Connected($new_value); # But you'll probably never need to do this - -returns a value equal to the numerical value associated with an object -in the B state. This value is normally maintained by the -B module, so you typically will only query it and -won't need to set it. - -B For a more programmer-friendly idiom, see the L, -L, L, and L object methods. You -will usually want to use those methods instead of one of the above. - -=head2 Quote - -Example: - - $imap->search(HEADER => 'Message-id' => $imap->Quote($msg_id)); - -The B method accepts a value as an argument. It returns its -argument as a correctly quoted string or a literal string. - -Note that you should not use this on folder names, since methods that accept -folder names as an argument will quote the folder name arguments appropriately -for you. (Exceptions to this rule are methods that come with IMAP extensions -that are not explicitly supported by B.) - -If you are getting unexpected results when running methods with values that -have (or might have) embedded spaces, double quotes, braces, or parentheses, -then you may wish to call B to quote these values. You should B -use this method with foldernames or with arguments that are wrapped in quotes -or parens if those quotes or parens are there because the RFC2060 spec requires -them. So, for example, if RFC requires an argument in this format: - - ( argument ) - -and your argument is (or might be) "pennies (from heaven)", then you could just -use: - - $argument = "(" . $imap->Quote($argument) . ")" - -and be done with it. - -Of course, the fact that sometimes these characters are sometimes required -delimiters is precisely the reason you must quote them when they are I -delimiting. For example: - - - $imap->Search('SUBJECT',"(no subject)"); - # WRONG! Sends this to imap server: - # Search SUBJECT (no subject)\r\n - - $imap->Search('SUBJECT',$imap->Quote("(no subject)")); - # Correct! Sends this to imap server: - # Search SUBJECT "(no subject)"\r\n - - -On the other hand: - - $imap->store('+FLAGS',$imap->Quote("(\Deleted)")); - # WRONG! Sends this to imap server: - # [UID] STORE +FLAGS "(\Deleted)"\r\n - - - $imap->store($imap->Quota('+FLAGS'),"(\Deleted)"); - # CORRECT! Sends this to imap server: - # [UID] STORE +FLAGS (\Deleted)\r\n - -In the above, I had to abandon the many methods available to -B programmers (such as L and all-lowercase -L) for the sake of coming up with an example. However, there are -times when unexpected values in certain places will force you to B. -An example is RFC822 Message-id's, which I don't contain quotes or -parens. So you don't worry about it, until suddenly searches for certain -message-id's fail for no apparent reason. (A failed search is not simply a -search that returns no hits; it's a search that flat out didn't happen.) -This normally happens to me at about 5:00 pm on the one day when I was hoping -to leave on time. (By the way, my experience is that any character that can -possibly find its way into a Message-Id eventually will, so when dealing -with these values take proactive, defensive measures from the very start. -In fact, as I was typing the above, a buddy of mine came in to ask advice about -a logfile parsing routine he was writing in which the fields were delimited -by colons. One of the fields was a Message Id, and, you guessed it, some of the -message id's in the log had (unescaped!) colons embedded in them and were -screwing up his C. So there you have it, it's not just me. This is -everyone's problem.) - -=head2 Range - -Example: - - my %parsed = $imap->parse_headers( - $imap->Range($imap->messages), - "Date", - "Subject" - ); - -The B method will condense a list of message sequence numbers or -message UID's into the most compact format supported by RFC2060. It accepts -one or more arguments, each of which can be: - -=over 8 - -=item a) a message number, - -=item b) a comma-separated list of message numbers, - -=item c) a colon-separated range of message numbers (i.e. "$begin:$end") - -=item d) a combination of messages and message ranges, separated by commas -(i.e. 1,3,5:8,10), or - -=item e) a reference to an array whose elements are like I through I. - -=back - -The B method returns a reference to a B -object. The object has all kinds of magic properties, one of which being that -if you treat it as if it were just a string it will act like it's just a -string. This means you can ignore its objectivity and just treat it like a -string whose value is your message set expressed in compact format. - -You may want to use this method if you find that fetch operations on large -message sets seem to take a really long time, or if your server rejects -these requests with the claim that the input line is too long. You may also -want to use this if you need to add or remove messages to your message set -and want an easy way to manage this. - -For more information on the capabilities of the returned object reference, -see L. - -=head2 Rfc2060_date - -Example: - - $Rfc2060_date = $imap->Rfc2060_date($seconds); - # or: - $Rfc2060_date = Mail::IMAPClient->Rfc2060_date($seconds); - -The B method accepts one input argument, a number of -seconds since the epoch date. It returns an RFC2060 compliant date -string for that date (as required in date-related arguments to SEARCH, -such as "since", "before", etc.). - -=head2 Rfc822_date - -Example: - - $Rfc822_date = $imap->Rfc822_date($seconds); - # or: - $Rfc822_date = Mail::IMAPClient->Rfc822_date($seconds); - -The B method accepts one input argument, a number of -seconds since the epoch date. It returns an RFC822 compliant date -string for that date (without the 'Date:' prefix). Useful for putting -dates in message strings before calling L, L, etcetera. - -=head2 Selected - -Example: - - $Selected = $imap->Selected(); - # or: - $imap->Selected($new_value); # But you'll probably never need to do this - -returns a value equal to the numerical value associated with an object -in the B state. This value is normally maintained by the -B module, so you typically will only query it and -won't need to set it. - -B For a more programmer-friendly idiom, see the L, -L, L, and L object methods. You -will usually want to use those methods instead of one of the above. - -=head2 Strip_cr - -Example: - - $Strip_cr = $imap->Strip_cr(); - # or: - $imap->Strip_cr($new_value); - -The B method strips carriage returns from IMAP client command -output. Although RFC2060 specifies that lines in an IMAP conversation -end with , it is often cumbersome to have the carriage returns -in the returned data. This method accepts one or more lines of text as -arguments, and returns those lines with all sequences changed -to . Any input argument with no carriage returns is returned -unchanged. If the first argument (not counting the class name or object -reference) is an array reference, then members of that array are -processed as above and subsequent arguments are ignored. If the method -is called in scalar context then an array reference is returned instead -of an array of results. - -Taken together, these last two lines mean that you can do something -like: - - my @list = $imap->some_imap_method ; - @list = $imap->Strip_cr(@list) ; - # or: - my $list = [ $imap->some_imap_method ] ; # returns an array ref - $list = $imap->Strip_cr($list); - -B does not remove new line characters. - -=cut - -=head2 Unconnected - -Example: - - $Unconnected = $imap->Unconnected(); - # or: - $imap->Unconnected($new_value); - -returns a value equal to the numerical value associated with an object -in the B state. This value is normally maintained by the -B module, so you typically will only query it and -won't need to set it. - -B For a more programmer-friendly idiom, see the L, -L, L, and L object methods. You -will usually want to use those methods instead of one of the above. - -=head1 OBJECT METHODS - -Object methods must be invoked against objects created via the L -method. They cannot be invoked as class methods, which is why they are -called "object methods" and not "class methods". - -There are basically two types of object methods--mailbox methods, which -participate in the IMAP session's conversation (i.e. they issue IMAP -client commands) and object control methods, which do not result in -IMAP commands but which may affect later commands or provide details -of previous ones. This latter group can be further broken down into -two types, Parameter accessor methods, which affect the behavior of -future mailbox methods, and Status methods, which report on the affects -of previous mailbox methods. - -Methods that do not result in new IMAP client commands being issued -(such as the L, L, and L methods) all -begin with an uppercase letter, to distinguish them from methods that -do correspond to IMAP client commands. Class methods and eponymous -parameter methods likewise begin with an uppercase letter because -they also do not correspond to an IMAP client command. - -As a general rule, mailbox control methods return C on failure -and something besides C when they succeed. This rule is modified -in the case of methods that return search results. When called in a list -context, searches that do not find matching results return an empty list. -When called in a scalar context, searches with no hits return 'undef' -instead of an array reference. If you want to know why you received no hits, -you should check C<$@>, which will be empty if the search was successful -but had no matching results but populated with an error message if the -search encountered a problem (such as invalid parameters). - -A number of IMAP commands do not have corresponding B -methods. Instead, they are implemented via a default method and Perl's -L facility. If you are looking for a specific -IMAP client command (or IMAP extension) and do not see it documented in this -pod, then that does not necessarily mean you can not use B to -issue the command. In fact, you can issue almost any IMAP client -command simply by I that there is a corresponding -B method. See the section on -L<"Other IMAP Client Commands and the Default Object Method"> -below for details on the default method. - -=head1 Mailbox Control Methods - -=head2 append - -Example: - - my $uid = $imap->append($folder,$msg_text) - or die "Could not append: $@\n"; - -The B method adds a message to the specified folder. It takes -two arguments, the name of the folder to append the message to, and the -text of the message (including headers). Additional arguments are added -to the message text, separated with . - -The B method returns the UID of the new message (a true value) -if successful, or C if not, if the IMAP server has the UIDPLUS -capability. If it doesn't then you just get true on success and undef -on failure. - -Note that many servers will get really ticked off if you try to append -a message that contains "bare newlines", which is the titillating term -given to newlines that are not preceded by a carrage return. To protect -against this, B will insert a carrage return before any newline -that is "bare". If you don't like this behavior then you can avoid it -by not passing naked newlines to B. - -Note that B does not allow you to specify the internal date or -initial flags of an appended message. If you need this capability then -use L, below. - -=cut - -=head2 append_file - -Example: - - my $new_msg_uid = $imap->append_file( - $folder, - $filename - [ , $input_record_separator ] # optional (not arrayref) - ) or die "Could not append_file: $@\n"; - -The B method adds a message to the specified folder. It -takes two arguments, the name of the folder to append the message to, -and the file name of an RFC822-formatted message. - -An optional third argument is the value to use for -C. The default is to use "" for the first read -(to get the headers) and "\n" for the rest. Any valid value for C<$/> -is acceptable, even the funky stuff, like C<\1024>. (See L -for more information on C<$/>). (The brackets in the example indicate -that this argument is optional; they do not mean that the argument -should be an array reference.) - -The B method returns the UID of the new message (a true -value) if successful, or C if not, if the IMAP server has the -UIDPLUS capability. If it doesn't then you just get true on success and -undef on failure. If you supply a filename that doesn't exist then you -get an automatic C. The L method will remind you of this -if you forget that your file doesn't exist but somehow manage to -remember to check L. - -In case you're wondering, B is provided mostly as a way to -allow large messages to be appended without having to have the whole -file in memory. It uses the C<-s> operator to obtain the size of the -file and then reads and sends the contents line by line (or not, -depending on whether you supplied that optional third argument). - -=cut - -=head2 append_string - -Example: - - # brackets indicate optional arguments (not array refs): - - my $uid = $imap->append_string( $folder, $text [ , $flags [ , $date ] ]) - or die "Could not append_string: $@\n"; - -The B method adds a message to the specified folder. It -requires two arguments, the name of the folder to append the message -to, and the text of the message (including headers). The message text -must be included in a single string (unlike L, above). - -You can optionally specify a third and fourth argument to -B. The third argument, if supplied, is the list of flags -to set for the appended message. The list must be specified as a -space-separated list of flags, including any backslashes that may be -necessary. The enclosing parentheses that are required by RFC2060 are -optional for B. The fourth argument, if specified, is -the date to set as the internal date. It should be in the format -described for I fields in RFC2060, i.e. "dd-Mon-yyyy -hh:mm:ss +0000". - -If you want to specify a date/time but you don't want any flags then -specify I as the third argument. - -The B method returns the UID of the new message (a true -value) if successful, or C if not, if the IMAP server has the -UIDPLUS capability. If it doesn't then you just get true on success and -undef on failure. - -Note that many servers will get really ticked off if you try to append -a message that contains "bare newlines", which is the titillating term -given to newlines that are not preceded by a carrage return. To protect -against this, B will insert a carrage return before any -newline that is "bare". If you don't like this behavior then you can -avoid it by not passing naked newlines to B. - -=cut - -=head2 authenticate - -Example: - - $imap->authenticate($authentication_mechanism, $coderef) - or die "Could not authenticate: $@\n"; - -The B method accepts two arguments, an authentication -type to be used (ie CRAM-MD5) and a code or subroutine reference to -execute to obtain a response. The B method assumes that -the authentication type specified in the first argument follows a -challenge-response flow. The B method issues the IMAP -Client AUTHENTICATE command and receives a challenge from the server. -That challenge (minus any tag prefix or enclosing '+' characters but -still in the original base64 encoding) is passed as the only argument -to the code or subroutine referenced in the second argument. The return -value from the 2nd argument's code is written to the server as is, -except that a sequence is appended if neccessary. - -If one or both of the arguments are not specified in the call to -B but their corresponding parameters have been set -(I and I, respectively) then the parameter -values are used. Arguments provided to the method call however will -override parameter settings. - -If you do not specify a second argument and you have not set the -I parameter, then the first argument must be -one of the authentication mechanisms for which B has -built in support. Currently there is only built in support for CRAM-MD5, -but I hope to add more in future releases. - -If you are interested in doing NTLM authentication then please see Mark -Bush's L, which can work with B to -provide NTLM authentication. - -See also the L method, which is the simplest form of -authentication defined by RFC2060. - -=cut - -=head2 before - -Example: - - my @msgs = $imap->before($Rfc2060_date) - or warn "No messages found before $Rfc2060_date.\n"; - -The B method works just like the L<"since"> method, below, -except it returns a list of messages whose internal system dates are -before the date supplied as the argument to the B method. - -=cut - -=head2 body_string - -Example: - - my $string = $imap->body_string($msgId) - or die "Could not body_string: $@\n"; - -The B method accepts a message sequence number (or a -message UID, if the L parameter is set to true) as an argument and -returns the message body as a string. The returned value contains the -entire message in one scalar variable, without the message headers. - -=cut - -=head2 bodypart_string - -Example: - - my $string=$imap->bodypart_string( $msgid, $part_number , - $length ,$offset - ) or die "Could not get bodypart string: $@\n"; - - -The B method accepts a message sequence number (or a -message UID, if the L parameter is set to true) and a body part as -arguments and returns the message part as a string. The returned value -contains the entire message part (or, optionally, a portion of the part) -in one scalar variable. - -If an optional third argument is provided, that argument is the number -of bytes to fetch. (The default is the whole message part.) If an -optional fourth argument is provided then that fourth argument is the -offset into the part at which the fetch should begin. The default is -offset zero, or the beginning of the message part. - -If you specify an offset without specifying a length then the offset -will be ignored and the entire part will be returned. - -B will return C if it encounters an error. - -=cut - -=head2 capability - -Example: - - my @features = $imap->capability - or die "Could not determine capability: $@\n"; - -The B method returns an array of capabilities as returned -by the CAPABILITY IMAP Client command, or a reference to an array of -capabilities if called in scalar context. If the CAPABILITY IMAP Client -command fails for any reason then the B method will return -C. - -=head2 close - -Example: - - $imap->close or die "Could not close: $@\n"; - -The B method is implemented via the default method and is used -to close the currently selected folder via the CLOSE IMAP client -command. According to RFC2060, the CLOSE command performs an implicit -EXPUNGE, which means that any messages that you've flagged as -I<\Deleted> (say, with the L method) will now be -deleted. If you haven't deleted any messages then B can be -thought of as an "unselect". - -Note again that this closes the currently selected folder, not the -IMAP session. - -See also L, L, and your tattered copy of -RFC2060. - -=head2 connect - -Example: - - $imap->connect or die "Could not connect: $@\n"; - -The B method connects an imap object to the server. It returns -C if it fails to connect for any reason. If values are available -for the I and I parameters at the time that B -is invoked, then B will call the L method after -connecting and return the result of the L method to B's -caller. If either or both of the I and I parameters are -unavailable but the connection to the server succeeds then B -returns a pointer to the B object. - -The I parameter must be set (either during L method -invocation or via the L object method) before invoking -B. If the L parameter is supplied to the L method -then B is implicitly called during object construction. - -The B method sets the state of the object to C if -it successfully connects to the server. It returns C on failure. - -=head2 copy - -Example: - - # Here brackets indicate optional arguments: - my $uidList = $imap->copy($folder, $msg_1 [ , ... , $msg_n ]) - or die "Could not copy: $@\n"; - -Or: - - # Now brackets indicate an array ref! - my $uidList = $imap->copy($folder, [ $msg_1, ... , $msg_n ]) - or die "Could not copy: $@\n"; - - -The B method requires a folder name as the first argument, and a -list of one or more messages sequence numbers (or messages UID's, if -the I parameter is set to a true value). The message sequence -numbers or UID's should refer to messages in the currenly selected -folder. Those messages will be copied into the folder named in the -first argument. - -The B method returns C on failure and a true value if -successful. If the server to which the current Mail::IMAPClient object -is connected supports the UIDPLUS capability then the true value -returned by B will be a comma separated list of UID's, which are -the UID's of the newly copied messages in the target folder. - -=cut - -=head2 create - -Example: - - $imap->create($new_folder) - or die "Could not create $new_folder: $@\n"; - -The B method accepts one argument, the name of a folder (or -what RFC2060 calls a "mailbox") to create. If you specifiy additional -arguments to the B method and your server allows additional -arguments to the CREATE IMAP client command then the extra argument(s) -will be passed to your server. - -If you specifiy additional arguments to the B method and your -server does not allow additional arguments to the CREATE IMAP client -command then the extra argument(s) will still be passed to your server -and the create will fail, so don't do that. - -B returns a true value on success and C on failure, as -you've probably guessed. - -=head2 date - -Example: - - my $date = $imap->date($msg); - - -The B method accepts one argument, a message sequence number (or a -message UID if the I parameter is set to a true value). It returns -the date of message as specified in the message's RFC822 "Date: " header, -without the "Date: " prefix. - -The B method is a short-cut for: - - my $date = $imap->get_header($msg,"Date"); - - -=head2 delete - -Example: - - $imap->delete($folder) or die "Could not delete $folder: $@\n"; - -The B method accepts a single argument, the name of a folder to -delete. It returns a true value on success and C on failure. - -=head2 delete_message - -Example: - - my @msgs = $imap->seen; - scalar(@msgs) and $imap->delete_message(\@msgs) - or die "Could not delete_message: $@\n"; - -The above could also be rewritten like this: - - # scalar context returns array ref - my $msgs = scalar($imap->seen); - - scalar(@$msgs) and $imap->delete_message($msgs) - or die "Could not delete_message: $@\n"; - -Or, as a one-liner: - - - $imap->delete_message( scalar($imap->seen) ) - or warn "Could not delete_message: $@\n"; - # just give warning in case failure is - # due to having no 'seen' msgs in the 1st place! - - -The B method accepts a list of arguments. If the L -parameter is not set to a true value, then each item in the list should -be either: - -=over 4 - -=item > a message sequence number, - -=item > a comma-separated list of message sequence numbers, - -=item > a reference to an array of message sequence numbers, or - -=back - -If the L parameter is set to a true value, then each item in the -list should be either: - -=over 4 - -=item > a message UID, - -=item > a comma-separated list of UID's, or - -=item > a reference to an array of message UID's. - -=back - -The messages identified by the sequence numbers or UID's will be -deleted. If successful, B returns the number -of messages it was told to delete. However, since the delete is -done by issuing the I<+FLAGS.SILENT> option of the STORE IMAP -client command, there is no guarantee that the delete was successful -for every message. In this manner the B method sacrifices -accuracy for speed. Generally, though, if a single message in a list -of messages fails to be deleted it's because it was already deleted, -which is what you wanted anyway so why worry about it? If there is -a more severe error, i.e. the server replies "NO", "BAD", or, -banish the thought, "BYE", then B will return C. - -If you must have guaranteed results then use the IMAP STORE client -command (via the default method) and use the +FLAGS (\Deleted) option, -and then parse your results manually. - -Eg: - - $imap->store($msg_id,'+FLAGS (\Deleted)'); - my @results = $imap->History($imap->Transaction); - ... # code to parse output goes here - - - -(Frankly I see no reason to bother with any of that; if a message doesn't get -deleted it's almost always because it's already not there, which is what you -want anyway. But 'your milage may vary' and all that.) - -The B object must be in C status to use the -B method. - -B All the messages identified in the input argument(s) must be -in the currently selected folder. Failure to comply with this -requirement will almost certainly result in the wrong message(s) being -deleted. This would be a crying shame. - -B In the grand tradition of the IMAP protocol, -deleting a message doesn't actually delete the message. Really. If you -want to make sure the message has been deleted, you need to expunge the -folder (via the L method, which is implemented via the default -method). Or at least L it. This is generally considered a -feature, since after deleting a message, you can change your mind and -undelete it at any time before your L or L. - -I The L method, to delete a folder, the L -method, to expunge a folder, the L method to undelete -a message, and the L method (implemented here via the default -method) to close a folder. Oh, and don't forget about RFC2060. - -=cut - -=head2 deny_seeing - -Example: - - # Reset all read msgs to unread - # (produces error if there are no seen msgs): - $imap->deny_seeing( scalar($imap->seen) ) - or die "Could not deny_seeing: $@\n" ; - -The B method accepts a list of one or more message -sequence numbers, or a single reference to an array of one or more -message sequence numbers, as its argument(s). It then unsets the -"\Seen" flag for those messages (so that you can "deny" that you ever -saw them). Of course, if the L parameter is set to a true value -then those message sequence numbers should be unique message id's. - -Note that specifying C<$imap-Edeny_seeing(@msgs)> is just a -shortcut for specifying C<$imap-Eunset_flag("Seen",@msgs)>. - -=cut - -=head2 disconnect - -Example: - - $imap->disconnect or warn "Could not disconnect: $@\n"; - -Disconnects the B object from the server. Functionally -equivalent to the L method. (In fact it's actually a synonym -for L.) - -=cut - -=head2 done - -Example: - - my $idle = $imap->idle or warn "Couldn't idle: $@\n"; - &goDoOtherThings; - $imap->done($idle) or warn "Error from done: $@\n"; - -The B method tells the IMAP server that the connection is finished -idling. See L for more information. It accepts one argument, -which is the transaction number you received from the previous call -to L. - -If you pass the wrong transaction number to B then your perl program -will probably hang. If you don't pass any transaction number to B -then it will try to guess, and if it guesses wrong it will hang. - -If you call done without previously having called L then your -server will mysteriously respond with I<* BAD Invalid tag>. - -If you try to run any other mailbox method after calling L but -before calling L, then that method will not only fail but also -take you out of the IDLE state. This means that when you eventually -remember to call B you will just get that I<* BAD Invalid tag> -thing again. - -=head2 examine - -Example: - - $imap->examine($folder) or die "Could not examine: $@\n"; - -The B method selects a folder in read-only mode and changes -the object's state to "Selected". The folder selected via the -B method can be examined but no changes can be made unless it -is first selected via the L or L method to select it instead of trying something -funky). Note that RFC2683 contains warnings about the use of the IMAP -I command (and thus the L method and therefore the -B method) against the currenlty selected folder. -You should carefully consider this before using B -on the currently selected folder. You may be better off using -L or one of its variants (especially L), and then -counting the results. On the other hand, I regularly violate this -rule on my server without suffering any dire consequences. Your -milage may vary. - -=cut - -=head2 message_string - -Example: - - my $string = $imap->message_string($msgid) - or die "Could not message_string: $@\n"; - -The B method accepts a message sequence number (or -message UID if L is true) as an argument and returns the message -as a string. The returned value contains the entire message in one -scalar variable, including the message headers. Note that using this -method will set the message's "\Seen" flag as a side effect, unless -I is set to a true value. - -=cut - -=head2 message_to_file - -Example: - - $imap->message_to_file($file,@msgs) - or die "Could not message_to_file: $@\n"; - -The B method accepts a filename or file handle and one -or more message sequence numbers (or message UIDs if L is true) as -arguments and places the message string(s) (including RFC822 headers) -into the file named in the first argument (or prints them to the -filehandle, if a filehandle is passed). The returned value is true on -succes and C on failure. - -If the first argument is a reference, it is assumed to be an open -filehandle and will not be closed when the method completes, If it is a -file, it is opened in append mode, written to, then closed. - -Note that using this method will set the message's "\Seen" flag as a -side effect. But you can use the L method to set it back, -or set the L parameter to a true value to prevent setting the -"\Seen" flag at all. - -This method currently works by making some basic assumptions about the -server's behavior, notably that the message text will be returned as a -literal string but that nothing else will be. If you have a better idea -then I'd like to hear it. - -=cut - -=head2 message_uid - -Example: - - my $msg_uid = $imap->message_uid($msg_seq_no) - or die "Could not get uid for $msg_seq_no: $@\n"; - -The B method accepts a message sequence number (or message -UID if L is true) as an argument and returns the message's UID. -Yes, if L is true then it will use the IMAP UID FETCH UID client -command to obtain and return the very same argument you supplied. This -is an IMAP feature so don't complain to me about it. - -=cut - -=head2 messages - -Example: - - # Get a list of messages in the current folder: - my @msgs = $imap->messages or die "Could not messages: $@\n"; - # Get a reference to an array of messages in the current folder: - my $msgs = $imap->messages or die "Could not messages: $@\n"; - -If called in list context, the B method returns a list of all -the messages in the currenlty selected folder. If called in scalar -context, it returns a reference to an array containing all the messages -in the folder. If you have the L parameter turned off, then this -is the same as specifying C<1 ... $imap-EL>; if you -have UID set to true then this is the same as specifying -C<$imap-EL("ALL")>. - -=cut - -=head2 migrate - -Example: - - $imap->migrate($imap_2, "ALL", $targetFolder ) - or die "Could not migrate: $@\n"; - -The B method copies the indicated messages B the -currently selected folder B another B object's -session. It requires these arguments: - -=over 4 - -=item 1. - -a reference to the target B object (not the calling -object, which is connected to the source account); - -=item 2. - -the message(s) to be copied, specified as either a) the message -sequence number (or message UID if the UID parameter is true) of a -single message, b) a reference to an array of message sequence numbers -(or message UID's if the UID parameter is true) or c) the special -string "ALL", which is a shortcut for the results of -C("ALL")>. - -=item 3. - -the folder name of a folder on the target mailbox to receive the -message(s). If this argument is not supplied or if I is supplied -then a folder with the same name as the currently selected folder on -the calling object will be created if necessary and used. If you -specify something other then I for this argument, even if it's -'$imap1-EFolder' or the name of the currently selected folder, then -that folder will only be used if it exists on the target object's -mailbox; if it does not exist then B will fail. - -=back - -The target B object should not be the same as the -source. The source object is the calling object, i.e. the one whose -B method will be used. It cannot be the same object as the one -specified as the target, even if you are for some reason migrating -between folders on the same account (which would be silly anyway, since -L can do that much more efficiently). If you try to use the same -B object for both the caller and the reciever then -they'll both get all screwed up and it will be your fault because I -just warned you and you didn't listen. - -B will download messages from the source in chunks to minimize -memory usage. The size of the chunks can be controlled by changing the -source B object's the L parameter. The higher -the L value, the faster the migration, but the more memory your -program will require. TANSTAAFL. (See the L parameter and -eponymous accessor method, described above under the L<"Parameters"> -section.) - -The B method uses Black Magic to hardwire the I/O between the -two B objects in order to minimize resource -consumption. If you have older scripts that used L and -L to move large messages between IMAP mailboxes then you -may want to try this method as a possible replacement. - -=head2 move - -Example: - - my $newUid = $imap->move($newFolder, $oldUid) - or die "Could not move: $@\n"; - $imap->expunge; - -The B method moves messages from the currently selected folder to -the folder specified in the first argument to B. If the L -parameter is not true, then the rest of the arguments should be either: - -=over 4 - -=item > - -a message sequence number, - -=item > - -a comma-separated list of message sequence numbers, or - -=item > - -a reference to an array of message sequence numbers. - -=back - -If the L parameter is true, then the arguments should be: - -=over 4 - -=item > - -a message UID, - -=item > - -a comma-separated list of message UID's, or - -=item > - -a reference to an array of message UID's. - -=back - -If the target folder does not exist then it will be created. - -If move is sucessful, then it returns a true value. Furthermore, if the -B object is connected to a server that has the -UIDPLUS capability, then the true value will be the comma-separated -list of UID's for the newly copied messages. The list will be in the -order in which the messages were moved. (Since B uses the copy -method, the messages will be moved in numerical order.) - -If the move is not successful then B returns C. - -Note that a move really just involves copying the message to the new -folder and then setting the I<\Deleted> flag. To actually delete the -original message you will need to run L (or L). - -=cut - -=head2 namespace - -Example: - - my @refs = $imap->namespace - or die "Could not namespace: $@\n"; - -The namespace method runs the NAMESPACE IMAP command (as defined in RFC -2342). When called in a list context, it returns a list of three -references. Each reference looks like this: - - [ [ $prefix_1, $separator_1 ] , - [ $prefix_2, $separator_2 ], - [ $prefix_n , $separator_n] - ] - -The first reference provides a list of prefices and separator -charactors for the available personal namespaces. The second reference -provides a list of prefices and separator charactors for the available -shared namespaces. The third reference provides a list of prefices and -separator charactors for the available public namespaces. - -If any of the three namespaces are unavailable on the current server -then an 'undef' is returned instead of a reference. So for example if -shared folders were not supported on the server but personal and public -namespaces were both available (with one namespace each), the returned -value might resemble this: - - ( [ "", "/" ] , undef, [ "#news", "." ] ) ; - -If the B method is called in scalar context, it returns a -reference to the above-mentioned list of three references, thus -creating a single structure that would pretty-print something like -this: - - $VAR1 = [ - [ - [ $user_prefix_1, $user_separator_1 ] , - [ $user_prefix_2, $user_separator_2], - [ $user_prefix_n , $user_separator_n] - ] , # or undef - [ - [ $shared_prefix_1, $shared_separator_1 ] , - [ $shared_prefix_2, $shared_separator_2], - [ $shared_prefix_n , $shared_separator_n] - ] , # or undef - [ - [ $public_prefix_1, $public_separator_1 ] , - [ $public_prefix_2, $public_separator_2], - [ $public_prefix_n , $public_separator_n] - ] , # or undef - ]; - -Or, to look at our previous example (where shared folders are -unsupported) called in scalar context: - - $VAR1 = [ - [ - [ - "" , - "/", - ], - ], - - undef, - - [ - [ - "#news", - "." - ], - ], - ]; - -=cut - -=head2 on - -Example: - - my @msgs = $imap->on($Rfc2060_date) - or warn "Could not find messages sent on $Rfc2060_date: $@\n"; - -The B method works just like the L method, below, except it -returns a list of messages whose internal system dates are the same as -the date supplied as the argument. - -=head2 parse_headers - -Example: - - my $hashref = $imap->parse_headers($msg||@msgs, "Date", "Subject") - or die "Could not parse_headers: $@\n"; - -The B method accepts as arguments a message sequence -number and a list of header fields. It returns a hash reference in -which the keys are the header field names (without the colon) and the -values are references to arrays of values. A picture would look -something like this: - - $hashref = $imap->parse_headers(1,"Date","Received","Subject","To"); - $hashref = { - "Date" => [ "Thu, 09 Sep 1999 09:49:04 -0400" ] , - "Received" => [ q/ - from mailhub ([111.11.111.111]) by mailhost.bigco.com - (Netscape Messaging Server 3.6) with ESMTP id AAA527D for - ; Fri, 18 Jun 1999 16:29:07 +0000 - /, q/ - from directory-daemon by mailhub.bigco.com (PMDF V5.2-31 #38473) - id <0FDJ0010174HF7@mailhub.bigco.com> for bigshot@bigco.com - (ORCPT rfc822;big.shot@bigco.com); Fri, 18 Jun 1999 16:29:05 +0000 (GMT) - /, q/ - from someplace ([999.9.99.99]) by smtp-relay.bigco.com (PMDF V5.2-31 #38473) - with ESMTP id <0FDJ0000P74H0W@smtp-relay.bigco.com> for big.shot@bigco.com; Fri, - 18 Jun 1999 16:29:05 +0000 (GMT) - /] , - "Subject" => [ qw/ Help! I've fallen and I can't get up!/ ] , - "To" => [ "Big Shot ] , - } ; - -The text in the example for the "Received" array has been formated to -make reading the example easier. The actual values returned are just -strings of words separated by spaces and with newlines and carriage -returns stripped off. The I header is probably the main -reason that the B method creates a hash of lists rather -than a hash of values. - -If the second argument to B is 'ALL' or if it is -unspecified then all available headers are included in the returned -hash of lists. - -If you're not emotionally prepared to deal with a hash of lists then -you can always call the L method yourself with the appropriate -parameters and parse the data out any way you want to. Also, in the -case of headers whose contents are also reflected in the envelope, you -can use the L method as an alternative to -L. - -If the L parameter is true then the first argument will be treated -as a message UID. If the first argument is a reference to an array of -message sequence numbers (or UID's if L is true), then -B will be run against each message in the array. In this -case the return value is a hash, in which the key is the message -sequence number (or UID) and the value is a reference to a hash as -described above. - -An example of using B to print the date and subject of -every message in your smut folder could look like this: - - use Mail::IMAPClient; - my $imap = Mail::IMAPClient->new( Server => $imaphost, - User => $login, - Password=> $pass, - Uid => 1, # optional - ); - - $imap->select("smut"); - - for my $h ( - - # grab the Subject and Date from every message in my (fictional!) smut folder; - # the first argument is a reference to an array listing all messages in the folder - # (which is what gets returned by the $imap->search("ALL") method when called in - # scalar context) and the remaining arguments are the fields to parse out - - # The key is the message number, which in this case we don't care about: - values %{$imap->parse_headers( scalar($imap->search("ALL")) , "Subject", "Date")} - ) { - # $h is the value of each element in the hash ref returned from parse_headers, - # and $h is also a reference to a hash. - # We'll only print the first occurance of each field because we don't expect more - # than one Date: or Subject: line per message. - print map { "$_:\t$h->{$_}[0]\n"} keys %$h ; - } - - -=cut - -=head2 recent - -Example: - - my @recent = $imap->recent or warn "No recent msgs: $@\n"; - -The B method performs an IMAP SEARCH RECENT search against the -selected folder and returns an array of sequence numbers (or UID's, if -the L parameter is true) of messages that are recent. - -=cut - -=head2 recent_count - -Example: - - my $count = 0; - defined($count = $imap->recent_count($folder)) - or die "Could not recent_count: $@\n"; - -The B method accepts as an argument a folder name. It -returns the number of recent messages in the folder (as returned by the -IMAP client command "STATUS folder RECENT"), or C in the case of an -error. The B method was contributed by Rob Deker -(deker@ikimbo.com). - -=cut - -=head2 rename - -Example: - - $imap->rename($oldname,$nedwname) - or die "Could not rename: $@\n"; - -The B method accepts two arguments: the name of an existing -folder, and a new name for the folder. The existing folder will be -renamed to the new name using the RENAME IMAP client command. B -will return a true value if successful, or C if unsuccessful. - -=cut - -=head2 restore_message - -Example: - - $imap->restore_message(@msgs) or die "Could not restore_message: $@\n"; - -The B method is used to undo a previous -L operation (but not if there has been an intervening -L or L). The B object must be in -L status to use the B method. - -The B method accepts a list of arguments. If the -L parameter is not set to a true value, then each item in the list -should be either: - -=over 4 - -=item > - -a message sequence number, - -=item > - -a comma-separated list of message sequence numbers, - -=item > - -a reference to an array of message sequence numbers, or - -=back - -If the L parameter is set to a true value, then each item in the -list should be either: - -=over 4 - -=item > - -a message UID, - -=item > - -a comma-separated list of UID's, or - -=item > - -a reference to an array of message UID's. - -=back - -The messages identified by the sequence numbers or UID's will have -their I<\Deleted> flags cleared, effectively "undeleting" the messages. -B returns the number of messages it was able to -restore. - -Note that B is similar to calling -C("\Deleted",@msgs)>, except that B -returns a (slightly) more meaningful value. Also it's easier to type. - -=cut - -=head2 run - -Example: - - $imap->run(@args) or die "Could not run: $@\n"; - -Like Perl itself, the B module is designed to make -common things easy and uncommon things possible. The B method is -provided to make those uncommon things possible. - -The B method excepts one or two arguments. The first argument is a -string containing an IMAP Client command, including a tag and all -required arguments. The optional second argument is a string to look -for that will indicate success. (The default is C). The B -method returns an array of output lines from the command, which you are -free to parse as you see fit. - -The B method does not do any syntax checking, other than -rudimentary checking for a tag. - -When B processes the command, it increments the transaction count -and saves the command and responses in the History buffer in the same -way other commands do. However, it also creates a special entry in the -History buffer named after the tag supplied in the string passed as the -first argument. If you supply a numeric value as the tag then you may -risk overwriting a previous transaction's entry in the History buffer. - -If you want the control of B but you don't want to worry about the -damn tags then see L<"tag_and_run">, below. - -=cut - -=head2 search - -Example: - - my @msgs = $imap->search(@args) or warn "search: None found\n"; - if ($@) { - warn "Error in search: $@\n"; - } - -The B method implements the SEARCH IMAP client command. Any -argument supplied to B is prefixed with a space and appended to -the SEARCH IMAP client command. This method is another one of those -situations where it will really help to have your copy of RFC2060 -handy, since the SEARCH IMAP client command contains a plethora of -options and possible arguments. I'm not going to repeat them here. - -Remember that if your argument needs quotes around it then you must -make sure that the quotes will be preserved when passing the argument. -I.e. use C instead of C<"$arg">. When in doubt, use the -L method. - -The B method returns an array containing sequence numbers of -messages that passed the SEARCH IMAP client command's search criteria. -If the L parameter is true then the array will contain message -UID's. If B is called in scalar context then a pointer to the -array will be passed, instead of the array itself. If no messages meet -the criteria then B returns an empty list (when in list context) -or C (in scalar context). - -Since a valid, successful search can legitimately return zero matches, -you may wish to distinguish between a search that correctly returns -zero hits and a search that has failed for some other reason (i.e. -invalid search parameters). Therefore, the C<$@> variable will always -be cleared before the I command is issued to the server, and -will thus remain empty unless the server gives a I or I response -to the I command. - -=cut - -=head2 see - -Example: - - $imap->see(@msgs) or die "Could not see: $@\n"; - -The B method accepts a list of one or more messages sequence -numbers, or a single reference to an array of one or more message -sequence numbers, as its argument(s). It then sets the I<\Seen> flag -for those message(s). Of course, if the L parameter is set to a -true value then those message sequence numbers had better be unique -message id's, but then you already knew that, didn't you? - -Note that specifying C<$imap-Esee(@msgs)> is just a shortcut for -specifying C<$imap-EL("Seen",@msgs)>. - -=cut - -=head2 seen - -Example: - - my @seenMsgs = $imap->seen or warn "No seen msgs: $@\n"; - -The B method performs an IMAP SEARCH SEEN search against the -selected folder and returns an array of sequence numbers of messages -that have already been seen (ie their I<\Seen> flag is set). If the -L parameter is true then an array of message UID's will be -returned instead. If called in scalar context than a reference to the -array (rather than the array itself) will be returned. - -=cut - -=head2 select - -Example: - - $imap->select($folder) or die "Could not select: $@\n"; - -The B method (or L or L object methods for that. -Generally, the I parameter should only be queried (by using the -no-argument form of the B method). You will only need to set the -I parameter if you use some mysterious technique of your own for -selecting a folder, which you probably won't do. - -=cut - -=head2 Maxtemperrors - -Example: - - $Maxtemperrors = $imap->Maxtemperrors(); - # or: - $imap->Maxtemperrors($new_value); - -The I parameter specifies the number of times a write -operation is allowed to fail on a "Resource Temporarily Available" -error. These errors can occur from time to time if the server is too -busy to empty out its read buffer (which is logically the "other end" -of the client's write buffer). By default, B will -retry an unlimited number of times, but you can adjust this -behavior by setting I. Note that after each temporary -error, the server will wait for a number of seconds equal to the number -of consecutive temporary errors times .25, so very high values for -I can slow you down in a big way if your "temporary -error" is not all that temporary. - -You can set this parameter to "UNLIMITED" to ignore "Resource -Temporarily Unavailable" errors. This is the default. - -=head2 Password - -Example: - - $Password = $imap->Password(); - # or: - $imap->Password($new_value); - -Specifies the password to use when logging into the IMAP service on the -host specified in the I parameter as the user specified in the -I parameter. Can be supplied with the B method call or -separately by calling the B object method. - -If I, I, and I are all provided to the L -method, then the newly instantiated object will be connected to the -host specified in I (at either the port specified in I or -the default port 143) and then logged on as the user specified in the -I parameter (using the password provided in the I -parameter). See the discussion of the L<"new"> method, below. - -=head2 Peek - -Example: - - $Peek = $imap->Peek(); - # or: - $imap->Peek($true_or_false); - -Setting I to a true value will prevent the L, -L and L methods from automatically -setting the I<\Seen> flag. Setting L<"Peek"> to 0 (zero) will force -L<"body_string">, L<"message_string">, L<"message_to_file">, and -L<"parse_headers"> to always set the I<\Seen> flag. - -The default is to set the seen flag whenever you fetch the body of a -message but not when you just fetch the headers. Passing I to -the eponymous B method will reset the I parameter to its -pristine, default state. - -=cut - -=head2 Port - -Example: - - $Port = $imap->Port(); - # or: - $imap->Port($new_value); - -Specifies the port on which the IMAP server is listening. The default -is 143, which is the standard IMAP port. Can be supplied with the -L method call or separately by calling the L object method. - -=head2 Prewritemethod - -Specifies a method to call if your authentication mechanism requires you to -to do pre-write processing of the data sent to the server. If defined, then the -I parameter should contain a reference to a subroutine that -will do Special Things to data before it is sent to the IMAP server (such as -encryption or signing). - -This method will be called immediately prior to sending an IMAP client command -to the server. Its first argument is a reference to the I object -and the second argument is a string containing the command that will be sent to -the server. Your I should return a string that has been signed or -encrypted or whatever; this returned string is what will actually be sent to the -server. - -Your I will probably need to know more than this to do whatever it does. -It is recommended that you tuck all other pertinent information into a hash, and store a -reference to this hash somewhere where your method can get to it, possibly in the -I object itself. - -Note that this method should not actually send anything over the socket connection to -the server; it merely converts data prior to sending. - -If you need a I then you probably need a L as well. - -=head2 Ranges - -Example: - - $imap->Ranges(1); - # or: - my $search = $imap->search(@search_args); - if ( $imap->Ranges) { # $search is a MessageSet object - print "This is my condensed search result: $search\n"; - print "This is every message in the search result: ", - join(",",@$search),"\n; - } - - -If set to a true value, then the L method will return a -L object if called in a scalar context, -instead of the array reference that B normally returns when -called in a scalar context. If set to zero or if undefined, then B -will continue to return an array reference when called in scalar context. - -This parameter has no affect on the B method when B is called -in a list context. - -=head2 Readmethod - -This parameter, if supplied, should contain a reference to a subroutine that will -replace sysreads. The subroutine will be passed the following arguments: - -=over 4 - -1. imap_object_ref - a reference to the current imap object - -2. scalar_ref - a reference to a scalar variable into which data is read. The data -place in here should be "finished data", so if you are decrypting or removing signatures -then be sure to do that before you place data into this buffer. - -3. read_length - the number of bytes requested to be read - -4. offset - the offset into C into which data should be read. If not supplied it -should default to zero. - -=back - -Note that this method completely replaces reads from the connection to the server, so if -you define one of these then your subroutine will have to actually do the read. It is for -things like this that we have the L parameter and eponymous accessor method. - -Your I will probably need to know more than this to do whatever it does. -It is recommended that you tuck all other pertinent information into a hash, and store -a reference to this hash somewhere where your method can get to it, possibly in the -I object itself. - -If you need a I then you probably need a L as well. - -=head2 Server - -Example: - - $Server = $imap->Server(); - # or: - $imap->Server($hostname); - -Specifies the hostname or IP address of the host running the IMAP -server. If provided as part of the L method call, then the new -IMAP object will automatically be connected at the time of -instantiation. (See the L method, below.) Can be supplied with the -L method call or separately by calling the B object -method. - -=cut - -=head2 Showcredentials - -Normally debugging output will mask the login credentials when the plain text -login mechanism is used. Setting I to a true value will suppress -this, so that you can see the string being passed back and forth during plain text -login. Only set this to true when you are debugging problems with the IMAP LOGIN -command, and then turn it off right away when you're finished working on that problem. - -Example: - - print "This is very risky!\n" if $imap->Showcredentials(); - # or: - $imap->Showcredentials(0); # mask credentials again - - -=head2 Socket - -Example: - - $Socket = $imap->Socket(); - # or: - $imap->Socket($socket_fh); - -The I method can be used to obtain the socket handle of the -current connection (say, to do I/O on the connection that is not -otherwise supported by B) or to replace the current -socket with a new handle (perhaps an SSL handle, for example). - -If you supply a socket handle yourself, either by doing something like: - - $imap=Mail::IMAPClient->new(Socket=>$sock, User => ... ); - -or by doing something like: - - $imap=Mail::IMAPClient->new(User => $user, Password => $pass, Server => $host); - # blah blah blah - $imap->Socket($ssl); - -then it will be up to you to establish the connection AND to -authenticate, either via the L method, or the fancier -L, or, since you know so much anyway, by just doing raw -I/O against the socket until you're logged in. If you do any of this -then you should also set the L parameter yourself to reflect the -current state of the object (i.e. Connected, Authenticated, etc). - -=cut - -=head2 Timeout - -Example: - - $Timeout = $imap->Timeout(); - # or: - $imap->Timeout($new_value); - -Specifies the timeout value in seconds for reads. Specifying a true -value for I will prevent B from blocking in -a read. - -Since timeouts are implemented via the perl L -operator, the I parameter may be set to a fractional number of -seconds. Not supplying a I, or (re)setting it to zero, -disables the timeout feature. - -=cut - -=head2 Uid - -Example: - - $Uid = $imap->Uid(); - # or: - $imap->Uid($true_or_false); - -If L is set to a true value (i.e. 1) then the behavior of the -L, L, L, and L methods (and their -derivatives) is changed so that arguments that would otherwise be -message sequence numbers are treated as message UID's and so that -return values (in the case of the L method and its derivatives) -that would normally be message sequence numbers are instead message -UID's. - -Internally this is implemented as a switch that, if turned on, causes -methods that would otherwise issue an IMAP FETCH, STORE, SEARCH, or -COPY client command to instead issue UID FETCH, UID STORE, UID SEARCH, -or UID COPY, respectively. The main difference between message sequence -numbers and message UID's is that, according to RFC2060, UID's must not -change during a session and should not change between sessions, and -must never be reused. Sequence numbers do not have that same guarantee -and in fact may be reused right away. - -Since foldernames also have a unique identifier (UIDVALIDITY), which is -provided when the folder is L a non-existing folder, then L