first commit

This commit is contained in:
MaddoScientisto 2026-03-14 20:04:39 +01:00
commit 4d332ef662
27586 changed files with 3281783 additions and 0 deletions

View file

@ -0,0 +1,263 @@
COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
1. Definitions.
1.1. Contributor. means each individual or entity that creates or contributes to the creation of Modifications.
1.2. Contributor Version. means the combination of the Original Software, prior Modifications used by a Contributor (if any), and the Modifications made by that particular Contributor.
1.3. Covered Software. means (a) the Original Software, or (b) Modifications, or (c) the combination of files containing Original Software with files containing Modifications, in each case including portions thereof.
1.4. Executable. means the Covered Software in any form other than Source Code.
1.5. Initial Developer. means the individual or entity that first makes Original Software available under this License.
1.6. Larger Work. means a work which combines Covered Software or portions thereof with code not governed by the terms of this License.
1.7. License. means this document.
1.8. Licensable. means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein.
1.9. Modifications. means the Source Code and Executable form of any of the following:
A. Any file that results from an addition to, deletion from or modification of the contents of a file containing Original Software or previous Modifications;
B. Any new file that contains any part of the Original Software or previous Modification; or
C. Any new file that is contributed or otherwise made available under the terms of this License.
1.10. Original Software. means the Source Code and Executable form of computer software code that is originally released under this License.
1.11. Patent Claims. means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor.
1.12. Source Code. means (a) the common form of computer software code in which modifications are made and (b) associated documentation included in or with such code.
1.13. You. (or .Your.) means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License. For legal entities, .You. includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, .control. means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity.
2. License Grants.
2.1. The Initial Developer Grant.
Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, the Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license:
(a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer, to use, reproduce, modify, display, perform, sublicense and distribute the Original Software (or portions thereof), with or without Modifications, and/or as part of a Larger Work; and
(b) under Patent Claims infringed by the making, using or selling of Original Software, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Software (or portions thereof).
(c) The licenses granted in Sections 2.1(a) and (b) are effective on the date Initial Developer first distributes or otherwise makes the Original Software available to a third party under the terms of this License.
(d) Notwithstanding Section 2.1(b) above, no patent license is granted: (1) for code that You delete from the Original Software, or (2) for infringements caused by: (i) the modification of the Original Software, or (ii) the combination of the Original Software with other software or devices.
2.2. Contributor Grant.
Conditioned upon Your compliance with Section 3.1 below and subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license:
(a) under intellectual property rights (other than patent or trademark) Licensable by Contributor to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof), either on an unmodified basis, with other Modifications, as Covered Software and/or as part of a Larger Work; and
(b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: (1) Modifications made by that Contributor (or portions thereof); and (2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination).
(c) The licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first distributes or otherwise makes the Modifications available to a third party.
(d) Notwithstanding Section 2.2(b) above, no patent license is granted: (1) for any code that Contributor has deleted from the Contributor Version; (2) for infringements caused by: (i) third party modifications of Contributor Version, or (ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or (3) under Patent Claims infringed by Covered Software in the absence of Modifications made by that Contributor.
3. Distribution Obligations.
3.1. Availability of Source Code.
Any Covered Software that You distribute or otherwise make available in Executable form must also be made available in Source Code form and that Source Code form must be distributed only under the terms of this License. You must include a copy of this License with every copy of the Source Code form of the Covered Software You distribute or otherwise make available. You must inform recipients of any such Covered Software in Executable form as to how they can obtain such Covered Software in Source Code form in a reasonable manner on or through a medium customarily used for software exchange.
3.2. Modifications.
The Modifications that You create or to which You contribute are governed by the terms of this License. You represent that You believe Your Modifications are Your original creation(s) and/or You have sufficient rights to grant the rights conveyed by this License.
3.3. Required Notices.
You must include a notice in each of Your Modifications that identifies You as the Contributor of the Modification. You may not remove or alter any copyright, patent or trademark notices contained within the Covered Software, or any notices of licensing or any descriptive text giving attribution to any Contributor or the Initial Developer.
3.4. Application of Additional Terms.
You may not offer or impose any terms on any Covered Software in Source Code form that alters or restricts the applicable version of this License or the recipients. rights hereunder. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Software. However, you may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear that any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer.
3.5. Distribution of Executable Versions.
You may distribute the Executable form of the Covered Software under the terms of this License or under the terms of a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable form does not attempt to limit or alter the recipient.s rights in the Source Code form from the rights set forth in this License. If You distribute the Covered Software in Executable form under a different license, You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer.
3.6. Larger Works.
You may create a Larger Work by combining Covered Software with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Software.
4. Versions of the License.
4.1. New Versions.
Sun Microsystems, Inc. is the initial license steward and may publish revised and/or new versions of this License from time to time. Each version will be given a distinguishing version number. Except as provided in Section 4.3, no one other than the license steward has the right to modify this License.
4.2. Effect of New Versions.
You may always continue to use, distribute or otherwise make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. If the Initial Developer includes a notice in the Original Software prohibiting it from being distributed or otherwise made available under any subsequent version of the License, You must distribute and make the Covered Software available under the terms of the version of the License under which You originally received the Covered Software. Otherwise, You may also choose to use, distribute or otherwise make the Covered Software available under the terms of any subsequent version of the License published by the license steward.
4.3. Modified Versions.
When You are an Initial Developer and You want to create a new license for Your Original Software, You may create and use a modified version of this License if You: (a) rename the license and remove any references to the name of the license steward (except to note that the license differs from this License); and (b) otherwise make it clear that the license contains terms which differ from this License.
5. DISCLAIMER OF WARRANTY.
COVERED SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN .AS IS. BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED SOFTWARE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED SOFTWARE IS WITH YOU. SHOULD ANY COVERED SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
6. TERMINATION.
6.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive.
6.2. If You assert a patent infringement claim (excluding declaratory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You assert such claim is referred to as .Participant.) alleging that the Participant Software (meaning the Contributor Version where the Participant is a Contributor or the Original Software where the Participant is the Initial Developer) directly or indirectly infringes any patent, then any and all rights granted directly or indirectly to You by such Participant, the Initial Developer (if the Initial Developer is not the Participant) and all Contributors under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively and automatically at the expiration of such 60 day notice period, unless if within such 60 day period You withdraw Your claim with respect to the Participant Software against such Participant either unilaterally or pursuant to a written agreement with Participant.
6.3. In the event of termination under Sections 6.1 or 6.2 above, all end user licenses that have been validly granted by You or any distributor hereunder prior to termination (excluding licenses granted to You by any distributor) shall survive termination.
7. LIMITATION OF LIABILITY.
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED SOFTWARE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOST PROFITS, LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY.S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
8. U.S. GOVERNMENT END USERS.
The Covered Software is a .commercial item,. as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of .commercial computer software. (as that term is defined at 48 C.F.R. º 252.227-7014(a)(1)) and .commercial computer software documentation. as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Software with only those rights set forth herein. This U.S. Government Rights clause is in lieu of, and supersedes, any other FAR, DFAR, or other clause or provision that addresses Government rights in computer software under this License.
9. MISCELLANEOUS.
This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by the law of the jurisdiction specified in a notice contained within the Original Software (except to the extent applicable law, if any, provides otherwise), excluding such jurisdiction.s conflict-of-law provisions. Any litigation relating to this License shall be subject to the jurisdiction of the courts located in the jurisdiction and venue specified in a notice contained within the Original Software, with the losing party responsible for costs, including, without limitation, court costs and reasonable attorneys. fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. You agree that You alone are responsible for compliance with the United States export administration regulations (and the export control laws and regulation of any other countries) when You use, distribute or otherwise make available any Covered Software.
10. RESPONSIBILITY FOR CLAIMS.
As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability.
NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL)
The code released under the CDDL shall be governed by the laws of the State of California (excluding conflict-of-law provisions). Any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California and the state courts of the State of California, with venue lying in Santa Clara County, California.
The GNU General Public License (GPL) Version 2, June 1991
Copyright (C) 1989, 1991 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 licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU 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. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.
When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), 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 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 show them these terms so they know 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.
Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and modification follow.
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License 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 derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.
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 License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.
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.
2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.
c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary 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 License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.
In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.
3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 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 Sections 1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.
If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.
5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing 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 for copying, distributing or modifying the Program or works based on it.
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. You are not responsible for enforcing compliance by third parties to this License.
7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.
This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.
9. 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 this 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 this License, you may choose any version ever published by the Free Software Foundation.
10. 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
11. 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.
12. 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
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 the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.
One line to give the program's name and a brief idea of what it does.
Copyright (C)
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 2 of the License, 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) year 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 is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker.
signature of Ty Coon, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.
"CLASSPATH" EXCEPTION TO THE GPL VERSION 2
Certain source files distributed by Sun Microsystems, Inc. are subject to the following clarification and special exception to the GPL Version 2, but only where Sun has expressly included in the particular source file's header the words
"Sun designates this particular file as subject to the "Classpath" exception as provided by Sun in the License file that accompanied this code."
Linking this library statically or dynamically with other modules is making a combined work based on this library. Thus, the terms and conditions of the GNU General Public License Version 2 cover the whole combination.
As a special exception, the copyright holders of this library give you permission to link this library with independent modules to produce an executable, regardless of the license terms of these independent modules, and to copy and distribute the resulting executable under terms of your choice, provided that you also meet, for each linked independent module, the terms and conditions of the license of that module.? An independent module is a module which is not derived from or based on this library.? If you modify this library, you may extend this exception to your version of the library, but you are not obligated to do so.? If you do not wish to do so, delete this exception statement from your version.

View file

@ -0,0 +1,60 @@
Manifest-Version: 1.0
Bundle-License: https://glassfish.java.net/public/CDDL+GPL_1_1.html
Bundle-SymbolicName: com.sun.mail.javax.mail
Archiver-Version: Plexus Archiver
Built-By: shannon
Bnd-LastModified: 1435006445969
Implementation-Vendor-Id: com.sun
Specification-Title: JavaMail(TM) API Design Specification
Bundle-DocURL: http://www.oracle.com
Import-Package: com.sun.mail.handlers;version="1.5",com.sun.mail.iap;v
ersion="1.5",com.sun.mail.imap;version="1.5",com.sun.mail.imap.protoc
ol;version="1.5",com.sun.mail.pop3;version="1.5",com.sun.mail.smtp;ve
rsion="1.5",com.sun.mail.util;version="1.5",com.sun.mail.util.logging
;version="1.5",javax.activation,javax.crypto,javax.crypto.spec,javax.
mail;version="1.5",javax.mail.event;version="1.5",javax.mail.internet
;version="1.5",javax.mail.search;version="1.5",javax.mail.util;versio
n="1.5",javax.net,javax.net.ssl,javax.security.auth.callback,javax.se
curity.auth.x500,javax.security.sasl;resolution:=optional,javax.xml.t
ransform,javax.xml.transform.stream,sun.security.util;resolution:=opt
ional
DynamicImport-Package: *
Export-Package: javax.mail.internet;uses:="javax.mail,com.sun.mail.uti
l,javax.activation,javax.mail.util";version="1.5",javax.mail.event;us
es:="javax.mail";version="1.5",javax.mail.util;uses:="javax.mail.inte
rnet,javax.activation";version="1.5",javax.mail;uses:="javax.mail.eve
nt,javax.mail.search,javax.activation,com.sun.mail.util";version="1.5
",javax.mail.search;uses:="javax.mail,javax.mail.internet";version="1
.5",com.sun.mail.imap;uses:="com.sun.mail.imap.protocol,javax.mail,co
m.sun.mail.iap,com.sun.mail.util,javax.mail.internet,javax.activation
,javax.mail.event,javax.mail.search";version="1.5.4",com.sun.mail.ima
p.protocol;uses:="com.sun.mail.iap,com.sun.mail.util,javax.mail.inter
net,javax.mail,com.sun.mail.imap,javax.mail.search,javax.security.sas
l,javax.security.auth.callback";version="1.5.4",com.sun.mail.iap;uses
:="com.sun.mail.util,javax.net.ssl";version="1.5.4",com.sun.mail.pop3
;uses:="javax.mail,com.sun.mail.util,javax.mail.event,javax.mail.inte
rnet,javax.net.ssl,javax.mail.util";version="1.5.4",com.sun.mail.smtp
;uses:="com.sun.mail.util,javax.mail,javax.mail.internet,javax.securi
ty.sasl,javax.security.auth.callback,javax.mail.event,javax.net.ssl";
version="1.5.4",com.sun.mail.util;uses:="javax.mail,javax.net.ssl,jav
ax.mail.internet,javax.mail.util,javax.security.auth.x500,javax.net";
version="1.5.4",com.sun.mail.util.logging;uses:="javax.mail,javax.mai
l.internet,javax.mail.util,javax.activation";version="1.5.4",com.sun.
mail.handlers;uses:="javax.activation,javax.mail,javax.mail.internet,
javax.xml.transform.stream,javax.xml.transform";version="1.5.4"
Bundle-Name: JavaMail API
Extension-Name: javax.mail
Implementation-Title: javax.mail
Bundle-Description: JavaMail API
Implementation-Version: 1.5.4
Specification-Vendor: Oracle
Bundle-ManifestVersion: 2
Bundle-Vendor: Oracle
Tool: Bnd-0.0.357
Implementation-Vendor: Oracle
Probe-Provider-XML-File-Names: META-INF/gfprobe-provider.xml
Bundle-Version: 1.5.4
Created-By: 1.8.0_45 (Oracle Corporation)
Build-Jdk: 1.8.0_45
Specification-Version: 1.5

View file

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
Copyright (c) 2010 Oracle and/or its affiliates. All rights reserved.
The contents of this file are subject to the terms of either the GNU
General Public License Version 2 only ("GPL") or the Common Development
and Distribution License("CDDL") (collectively, the "License"). You
may not use this file except in compliance with the License. You can
obtain a copy of the License at
https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
or packager/legal/LICENSE.txt. See the License for the specific
language governing permissions and limitations under the License.
When distributing the software, include this License Header Notice in each
file and include the License file at packager/legal/LICENSE.txt.
GPL Classpath Exception:
Oracle designates this particular file as subject to the "Classpath"
exception as provided by Oracle in the GPL Version 2 section of the License
file that accompanied this code.
Modifications:
If applicable, add the following below the License Header, with the fields
enclosed by brackets [] replaced by your own identifying information:
"Portions Copyright [year] [name of copyright owner]"
Contributor(s):
If you wish your version of this file to be governed by only the CDDL or
only the GPL Version 2, indicate your decision by adding "[Contributor]
elects to include this software in this distribution under the [CDDL or GPL
Version 2] license." If you don't indicate a single choice of license, a
recipient has the option to distribute your version of this file under
either the CDDL, the GPL Version 2 or to extend the choice of license to
its licensees as provided above. However, if you add GPL Version 2 code
and therefore, elected the GPL Version 2 license, then the option applies
only if the new code is made subject to such option by the copyright
holder.
-->
<probe-providers>
<probe-provider moduleProviderName="glassfish" moduleName="javamail"
probeProviderName="smtp-transport"
class="com.sun.mail.smtp.SMTPTransport">
<probe name="sendMessageStart">
<method>sendMessageStart</method>
<probe-param type="java.lang.String" name="subject" />
<return-param type="void" />
</probe>
<probe name="sendMessageEnd">
<method>sendMessageEnd</method>
<return-param type="void" />
</probe>
</probe-provider>
<probe-provider moduleProviderName="glassfish" moduleName="javamail"
probeProviderName="iap-protocol"
class="com.sun.mail.iap.Protocol">
<probe name="commandStart">
<method>commandStart</method>
<probe-param type="java.lang.String" name="command" />
<return-param type="void" />
</probe>
<probe name="commandEnd">
<method>commandEnd</method>
<return-param type="void" />
</probe>
</probe-provider>
<probe-provider moduleProviderName="glassfish" moduleName="javamail"
probeProviderName="pop3-protocol"
class="com.sun.mail.pop3.Protocol">
<probe name="simpleCommandStart">
<method>simpleCommandStart</method>
<probe-param type="java.lang.String" name="command" />
<return-param type="void" />
</probe>
<probe name="simpleCommandEnd">
<method>simpleCommandEnd</method>
<return-param type="void" />
</probe>
<probe name="multilineCommandStart">
<method>multilineCommandStart</method>
<probe-param type="java.lang.String" name="command" />
<return-param type="void" />
</probe>
<probe name="multilineCommandEnd">
<method>multilineCommandEnd</method>
<return-param type="void" />
</probe>
</probe-provider>
</probe-providers>

View file

@ -0,0 +1,9 @@
#
# This metadata allows com.sun.mail.util.logging.MailHandler to be
# configured in the logging.properties file and used in GlassFish.
# This file was created by hand to avoid a compile time dependency
# on the HK2 annotations.
#
[com.sun.mail.util.logging.MailHandler]
contract={java.util.logging.Handler}
scope=javax.inject.Singleton

View file

@ -0,0 +1,67 @@
### JDK-to-MIME charset mapping table ####
### This should be the first mapping table ###
8859_1 ISO-8859-1
iso8859_1 ISO-8859-1
ISO8859-1 ISO-8859-1
8859_2 ISO-8859-2
iso8859_2 ISO-8859-2
ISO8859-2 ISO-8859-2
8859_3 ISO-8859-3
iso8859_3 ISO-8859-3
ISO8859-3 ISO-8859-3
8859_4 ISO-8859-4
iso8859_4 ISO-8859-4
ISO8859-4 ISO-8859-4
8859_5 ISO-8859-5
iso8859_5 ISO-8859-5
ISO8859-5 ISO-8859-5
8859_6 ISO-8859-6
iso8859_6 ISO-8859-6
ISO8859-6 ISO-8859-6
8859_7 ISO-8859-7
iso8859_7 ISO-8859-7
ISO8859-7 ISO-8859-7
8859_8 ISO-8859-8
iso8859_8 ISO-8859-8
ISO8859-8 ISO-8859-8
8859_9 ISO-8859-9
iso8859_9 ISO-8859-9
ISO8859-9 ISO-8859-9
SJIS Shift_JIS
JIS ISO-2022-JP
ISO2022JP ISO-2022-JP
EUC_JP euc-jp
KOI8_R koi8-r
EUC_CN euc-cn
EUC_TW euc-tw
EUC_KR euc-kr
--DIVIDER: this line *must* start with "--" and end with "--" --
#### XXX-to-JDK charset mapping table ####
iso-2022-cn ISO2022CN
iso-2022-kr ISO2022KR
utf-8 UTF8
utf8 UTF8
ja_jp.iso2022-7 ISO2022JP
ja_jp.eucjp EUCJIS
# these two are not needed in 1.1.6. (since EUC_KR exists
# and KSC5601 will map to the correct converter)
euc-kr KSC5601
euckr KSC5601
# in JDK 1.1.6 we will no longer need the "us-ascii" convert
us-ascii ISO-8859-1
x-us-ascii ISO-8859-1

View file

@ -0,0 +1 @@
rfc822=smtp

View file

@ -0,0 +1,9 @@
# JavaMail IMAP provider Oracle
protocol=imap; type=store; class=com.sun.mail.imap.IMAPStore; vendor=Oracle;
protocol=imaps; type=store; class=com.sun.mail.imap.IMAPSSLStore; vendor=Oracle;
# JavaMail SMTP provider Oracle
protocol=smtp; type=transport; class=com.sun.mail.smtp.SMTPTransport; vendor=Oracle;
protocol=smtps; type=transport; class=com.sun.mail.smtp.SMTPSSLTransport; vendor=Oracle;
# JavaMail POP3 provider Oracle
protocol=pop3; type=store; class=com.sun.mail.pop3.POP3Store; vendor=Oracle;
protocol=pop3s; type=store; class=com.sun.mail.pop3.POP3SSLStore; vendor=Oracle;

View file

@ -0,0 +1,16 @@
#
#
# Default mailcap file for the JavaMail System.
#
# JavaMail content-handlers:
#
text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain
text/html;; x-java-content-handler=com.sun.mail.handlers.text_html
text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml
multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed; x-java-fallback-entry=true
message/rfc822;; x-java-content-handler=com.sun.mail.handlers.message_rfc822
#
# can't support image types because java.awt.Toolkit doesn't work on servers
#
#image/gif;; x-java-content-handler=com.sun.mail.handlers.image_gif
#image/jpeg;; x-java-content-handler=com.sun.mail.handlers.image_jpeg

View file

@ -0,0 +1,5 @@
#Generated by Maven
#Mon Jun 22 13:54:03 PDT 2015
version=1.5.4
groupId=com.sun.mail
artifactId=javax.mail

View file

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!--
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
Copyright (c) 1997-2015 Oracle and/or its affiliates. All rights reserved.
The contents of this file are subject to the terms of either the GNU
General Public License Version 2 only ("GPL") or the Common Development
and Distribution License("CDDL") (collectively, the "License"). You
may not use this file except in compliance with the License. You can
obtain a copy of the License at
https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
or packager/legal/LICENSE.txt. See the License for the specific
language governing permissions and limitations under the License.
When distributing the software, include this License Header Notice in each
file and include the License file at packager/legal/LICENSE.txt.
GPL Classpath Exception:
Oracle designates this particular file as subject to the "Classpath"
exception as provided by Oracle in the GPL Version 2 section of the License
file that accompanied this code.
Modifications:
If applicable, add the following below the License Header, with the fields
enclosed by brackets [] replaced by your own identifying information:
"Portions Copyright [year] [name of copyright owner]"
Contributor(s):
If you wish your version of this file to be governed by only the CDDL or
only the GPL Version 2, indicate your decision by adding "[Contributor]
elects to include this software in this distribution under the [CDDL or GPL
Version 2] license." If you don't indicate a single choice of license, a
recipient has the option to distribute your version of this file under
either the CDDL, the GPL Version 2 or to extend the choice of license to
its licensees as provided above. However, if you add GPL Version 2 code
and therefore, elected the GPL Version 2 license, then the option applies
only if the new code is made subject to such option by the copyright
holder.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>com.sun.mail</groupId>
<artifactId>all</artifactId>
<version>1.5.4</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<packaging>jar</packaging>
<name>JavaMail API</name>
<properties>
<mail.extensionName>
javax.mail
</mail.extensionName>
<mail.specificationTitle>
JavaMail(TM) API Design Specification
</mail.specificationTitle>
<mail.implementationTitle>
javax.mail
</mail.implementationTitle>
<mail.packages.export>
javax.mail.*; version=${mail.spec.version},
com.sun.mail.imap; version=${mail.osgiversion},
com.sun.mail.imap.protocol; version=${mail.osgiversion},
com.sun.mail.iap; version=${mail.osgiversion},
com.sun.mail.pop3; version=${mail.osgiversion},
com.sun.mail.smtp; version=${mail.osgiversion},
com.sun.mail.util; version=${mail.osgiversion},
com.sun.mail.util.logging; version=${mail.osgiversion},
com.sun.mail.handlers; version=${mail.osgiversion}
</mail.packages.export>
<mail.probeFile>
META-INF/gfprobe-provider.xml
</mail.probeFile>
<findbugs.skip>
false
</findbugs.skip>
<findbugs.exclude>
${project.basedir}/exclude.xml
</findbugs.exclude>
</properties>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<!--
Configure compiler plugin to print lint warnings.
-->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<executions>
<execution>
<id>default-compile</id>
<configuration>
<source>1.5</source>
<target>1.5</target>
<fork>true</fork>
<!--
ignore some of the errors that are
too hard to fix for now
-->
<compilerArguments>
<Xlint:all/>
<Xlint:-rawtypes/>
<Xlint:-unchecked/>
<Xlint:-finally/>
</compilerArguments>
<showWarnings>true</showWarnings>
</configuration>
</execution>
<execution>
<id>default-testCompile</id>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</execution>
</executions>
</plugin>
<!--
Configure test plugin to find *TestSuite classes.
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/*Test.java</include>
<include>**/*TestSuite.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
<optional>true</optional>
</dependency>
</dependencies>
</project>

View file

@ -0,0 +1,199 @@
package com.sun.mail.auth;
public final class MD4 {
private final int[] state;
private final int[] x;
private static final int blockSize = 64;
private final byte[] buffer = new byte[64];
private int bufOfs;
private long bytesProcessed;
private static final int S11 = 3;
private static final int S12 = 7;
private static final int S13 = 11;
private static final int S14 = 19;
private static final int S21 = 3;
private static final int S22 = 5;
private static final int S23 = 9;
private static final int S24 = 13;
private static final int S31 = 3;
private static final int S32 = 9;
private static final int S33 = 11;
private static final int S34 = 15;
private static final byte[] padding = new byte[136];
static {
padding[0] = Byte.MIN_VALUE;
}
public MD4() {
this.state = new int[4];
this.x = new int[16];
implReset();
}
public byte[] digest(byte[] in) {
implReset();
engineUpdate(in, 0, in.length);
byte[] out = new byte[16];
implDigest(out, 0);
return out;
}
private void implReset() {
this.state[0] = 1732584193;
this.state[1] = -271733879;
this.state[2] = -1732584194;
this.state[3] = 271733878;
this.bufOfs = 0;
this.bytesProcessed = 0L;
}
private void implDigest(byte[] out, int ofs) {
long bitsProcessed = this.bytesProcessed << 3L;
int index = (int)this.bytesProcessed & 0x3F;
int padLen = (index < 56) ? (56 - index) : (120 - index);
engineUpdate(padding, 0, padLen);
this.buffer[56] = (byte)(int)bitsProcessed;
this.buffer[57] = (byte)(int)(bitsProcessed >> 8L);
this.buffer[58] = (byte)(int)(bitsProcessed >> 16L);
this.buffer[59] = (byte)(int)(bitsProcessed >> 24L);
this.buffer[60] = (byte)(int)(bitsProcessed >> 32L);
this.buffer[61] = (byte)(int)(bitsProcessed >> 40L);
this.buffer[62] = (byte)(int)(bitsProcessed >> 48L);
this.buffer[63] = (byte)(int)(bitsProcessed >> 56L);
implCompress(this.buffer, 0);
for (int i = 0; i < this.state.length; i++) {
int x = this.state[i];
out[ofs++] = (byte)x;
out[ofs++] = (byte)(x >> 8);
out[ofs++] = (byte)(x >> 16);
out[ofs++] = (byte)(x >> 24);
}
}
private void engineUpdate(byte[] b, int ofs, int len) {
if (len == 0)
return;
if (ofs < 0 || len < 0 || ofs > b.length - len)
throw new ArrayIndexOutOfBoundsException();
if (this.bytesProcessed < 0L)
implReset();
this.bytesProcessed += (long)len;
if (this.bufOfs != 0) {
int n = Math.min(len, 64 - this.bufOfs);
System.arraycopy(b, ofs, this.buffer, this.bufOfs, n);
this.bufOfs += n;
ofs += n;
len -= n;
if (this.bufOfs >= 64) {
implCompress(this.buffer, 0);
this.bufOfs = 0;
}
}
while (len >= 64) {
implCompress(b, ofs);
len -= 64;
ofs += 64;
}
if (len > 0) {
System.arraycopy(b, ofs, this.buffer, 0, len);
this.bufOfs = len;
}
}
private static int FF(int a, int b, int c, int d, int x, int s) {
a += (b & c | (b ^ 0xFFFFFFFF) & d) + x;
return a << s | a >>> 32 - s;
}
private static int GG(int a, int b, int c, int d, int x, int s) {
a += (b & c | b & d | c & d) + x + 1518500249;
return a << s | a >>> 32 - s;
}
private static int HH(int a, int b, int c, int d, int x, int s) {
a += (b ^ c ^ d) + x + 1859775393;
return a << s | a >>> 32 - s;
}
private void implCompress(byte[] buf, int ofs) {
for (int xfs = 0; xfs < this.x.length; xfs++) {
this.x[xfs] = buf[ofs] & 0xFF | (buf[ofs + 1] & 0xFF) << 8 | (buf[ofs + 2] & 0xFF) << 16 | (buf[ofs + 3] & 0xFF) << 24;
ofs += 4;
}
int a = this.state[0];
int b = this.state[1];
int c = this.state[2];
int d = this.state[3];
a = FF(a, b, c, d, this.x[0], 3);
d = FF(d, a, b, c, this.x[1], 7);
c = FF(c, d, a, b, this.x[2], 11);
b = FF(b, c, d, a, this.x[3], 19);
a = FF(a, b, c, d, this.x[4], 3);
d = FF(d, a, b, c, this.x[5], 7);
c = FF(c, d, a, b, this.x[6], 11);
b = FF(b, c, d, a, this.x[7], 19);
a = FF(a, b, c, d, this.x[8], 3);
d = FF(d, a, b, c, this.x[9], 7);
c = FF(c, d, a, b, this.x[10], 11);
b = FF(b, c, d, a, this.x[11], 19);
a = FF(a, b, c, d, this.x[12], 3);
d = FF(d, a, b, c, this.x[13], 7);
c = FF(c, d, a, b, this.x[14], 11);
b = FF(b, c, d, a, this.x[15], 19);
a = GG(a, b, c, d, this.x[0], 3);
d = GG(d, a, b, c, this.x[4], 5);
c = GG(c, d, a, b, this.x[8], 9);
b = GG(b, c, d, a, this.x[12], 13);
a = GG(a, b, c, d, this.x[1], 3);
d = GG(d, a, b, c, this.x[5], 5);
c = GG(c, d, a, b, this.x[9], 9);
b = GG(b, c, d, a, this.x[13], 13);
a = GG(a, b, c, d, this.x[2], 3);
d = GG(d, a, b, c, this.x[6], 5);
c = GG(c, d, a, b, this.x[10], 9);
b = GG(b, c, d, a, this.x[14], 13);
a = GG(a, b, c, d, this.x[3], 3);
d = GG(d, a, b, c, this.x[7], 5);
c = GG(c, d, a, b, this.x[11], 9);
b = GG(b, c, d, a, this.x[15], 13);
a = HH(a, b, c, d, this.x[0], 3);
d = HH(d, a, b, c, this.x[8], 9);
c = HH(c, d, a, b, this.x[4], 11);
b = HH(b, c, d, a, this.x[12], 15);
a = HH(a, b, c, d, this.x[2], 3);
d = HH(d, a, b, c, this.x[10], 9);
c = HH(c, d, a, b, this.x[6], 11);
b = HH(b, c, d, a, this.x[14], 15);
a = HH(a, b, c, d, this.x[1], 3);
d = HH(d, a, b, c, this.x[9], 9);
c = HH(c, d, a, b, this.x[5], 11);
b = HH(b, c, d, a, this.x[13], 15);
a = HH(a, b, c, d, this.x[3], 3);
d = HH(d, a, b, c, this.x[11], 9);
c = HH(c, d, a, b, this.x[7], 11);
b = HH(b, c, d, a, this.x[15], 15);
this.state[0] = this.state[0] + a;
this.state[1] = this.state[1] + b;
this.state[2] = this.state[2] + c;
this.state[3] = this.state[3] + d;
}
}

View file

@ -0,0 +1,278 @@
package com.sun.mail.auth;
import com.sun.mail.util.BASE64DecoderStream;
import com.sun.mail.util.BASE64EncoderStream;
import com.sun.mail.util.MailLogger;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException;
import java.util.Locale;
import java.util.logging.Level;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
public class Ntlm {
private byte[] type1;
private byte[] type3;
private SecretKeyFactory fac;
private Cipher cipher;
private MD4 md4;
private String hostname;
private String ntdomain;
private String username;
private String password;
private MailLogger logger;
private void init0() {
this.type1 = new byte[256];
this.type3 = new byte[256];
System.arraycopy(new byte[] { 78, 84, 76, 77, 83, 83, 80, 0, 1 }, 0, this.type1, 0, 9);
this.type1[12] = 3;
this.type1[13] = -78;
this.type1[28] = 32;
System.arraycopy(new byte[] { 78, 84, 76, 77, 83, 83, 80, 0, 3 }, 0, this.type3, 0, 9);
this.type3[12] = 24;
this.type3[14] = 24;
this.type3[20] = 24;
this.type3[22] = 24;
this.type3[32] = 64;
this.type3[60] = 1;
this.type3[61] = -126;
try {
this.fac = SecretKeyFactory.getInstance("DES");
this.cipher = Cipher.getInstance("DES/ECB/NoPadding");
this.md4 = new MD4();
} catch (NoSuchPaddingException e) {
assert false;
} catch (NoSuchAlgorithmException e) {
assert false;
}
}
public Ntlm(String ntdomain, String hostname, String username, String password, MailLogger logger) {
int i = hostname.indexOf('.');
if (i != -1)
hostname = hostname.substring(0, i);
i = username.indexOf('\\');
if (i != -1) {
ntdomain = username.substring(0, i).toUpperCase(Locale.ENGLISH);
username = username.substring(i + 1);
} else if (ntdomain == null) {
ntdomain = "";
}
this.ntdomain = ntdomain;
this.hostname = hostname;
this.username = username;
this.password = password;
this.logger = logger.getLogger(getClass(), "DEBUG NTLM");
init0();
}
private void copybytes(byte[] dest, int destpos, String src, String enc) {
try {
byte[] x = src.getBytes(enc);
System.arraycopy(x, 0, dest, destpos, x.length);
} catch (UnsupportedEncodingException e) {
assert false;
}
}
public String generateType1Msg(int flags) {
int dlen = this.ntdomain.length();
this.type1[16] = (byte)(dlen % 256);
this.type1[17] = (byte)(dlen / 256);
this.type1[18] = this.type1[16];
this.type1[19] = this.type1[17];
if (dlen == 0)
this.type1[13] = (byte)(this.type1[13] & 0xFFFFFFEF);
int hlen = this.hostname.length();
this.type1[24] = (byte)(hlen % 256);
this.type1[25] = (byte)(hlen / 256);
this.type1[26] = this.type1[24];
this.type1[27] = this.type1[25];
copybytes(this.type1, 32, this.hostname, "iso-8859-1");
copybytes(this.type1, hlen + 32, this.ntdomain, "iso-8859-1");
this.type1[20] = (byte)((hlen + 32) % 256);
this.type1[21] = (byte)((hlen + 32) / 256);
byte[] msg = new byte[32 + hlen + dlen];
System.arraycopy(this.type1, 0, msg, 0, 32 + hlen + dlen);
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("type 1 message: " + toHex(msg));
String result = null;
try {
result = new String(BASE64EncoderStream.encode(msg), "iso-8859-1");
} catch (UnsupportedEncodingException e) {
assert false;
}
return result;
}
private byte[] makeDesKey(byte[] input, int off) {
int[] in = new int[input.length];
for (int i = 0; i < in.length; i++)
in[i] = (input[i] < 0) ? (input[i] + 256) : input[i];
byte[] out = new byte[8];
out[0] = (byte)in[off + 0];
out[1] = (byte)(in[off + 0] << 7 & 0xFF | in[off + 1] >> 1);
out[2] = (byte)(in[off + 1] << 6 & 0xFF | in[off + 2] >> 2);
out[3] = (byte)(in[off + 2] << 5 & 0xFF | in[off + 3] >> 3);
out[4] = (byte)(in[off + 3] << 4 & 0xFF | in[off + 4] >> 4);
out[5] = (byte)(in[off + 4] << 3 & 0xFF | in[off + 5] >> 5);
out[6] = (byte)(in[off + 5] << 2 & 0xFF | in[off + 6] >> 6);
out[7] = (byte)(in[off + 6] << 1 & 0xFF);
return out;
}
private byte[] calcLMHash() throws GeneralSecurityException {
byte[] magic = { 75, 71, 83, 33, 64, 35, 36, 37 };
byte[] pwb = null;
try {
pwb = this.password.toUpperCase(Locale.ENGLISH).getBytes("iso-8859-1");
} catch (UnsupportedEncodingException ex) {
assert false;
}
byte[] pwb1 = new byte[14];
int len = this.password.length();
if (len > 14)
len = 14;
System.arraycopy(pwb, 0, pwb1, 0, len);
DESKeySpec dks1 = new DESKeySpec(makeDesKey(pwb1, 0));
DESKeySpec dks2 = new DESKeySpec(makeDesKey(pwb1, 7));
SecretKey key1 = this.fac.generateSecret(dks1);
SecretKey key2 = this.fac.generateSecret(dks2);
this.cipher.init(1, key1);
byte[] out1 = this.cipher.doFinal(magic, 0, 8);
this.cipher.init(1, key2);
byte[] out2 = this.cipher.doFinal(magic, 0, 8);
byte[] result = new byte[21];
System.arraycopy(out1, 0, result, 0, 8);
System.arraycopy(out2, 0, result, 8, 8);
return result;
}
private byte[] calcNTHash() throws GeneralSecurityException {
byte[] pw = null;
try {
pw = this.password.getBytes("UnicodeLittleUnmarked");
} catch (UnsupportedEncodingException e) {
assert false;
}
byte[] out = this.md4.digest(pw);
byte[] result = new byte[21];
System.arraycopy(out, 0, result, 0, 16);
return result;
}
private byte[] calcResponse(byte[] key, byte[] text) throws GeneralSecurityException {
assert key.length == 21;
DESKeySpec dks1 = new DESKeySpec(makeDesKey(key, 0));
DESKeySpec dks2 = new DESKeySpec(makeDesKey(key, 7));
DESKeySpec dks3 = new DESKeySpec(makeDesKey(key, 14));
SecretKey key1 = this.fac.generateSecret(dks1);
SecretKey key2 = this.fac.generateSecret(dks2);
SecretKey key3 = this.fac.generateSecret(dks3);
this.cipher.init(1, key1);
byte[] out1 = this.cipher.doFinal(text, 0, 8);
this.cipher.init(1, key2);
byte[] out2 = this.cipher.doFinal(text, 0, 8);
this.cipher.init(1, key3);
byte[] out3 = this.cipher.doFinal(text, 0, 8);
byte[] result = new byte[24];
System.arraycopy(out1, 0, result, 0, 8);
System.arraycopy(out2, 0, result, 8, 8);
System.arraycopy(out3, 0, result, 16, 8);
return result;
}
public String generateType3Msg(String challenge) {
try {
byte[] type2 = null;
try {
type2 = BASE64DecoderStream.decode(challenge.getBytes("us-ascii"));
} catch (UnsupportedEncodingException ex) {
assert false;
}
byte[] nonce = new byte[8];
System.arraycopy(type2, 24, nonce, 0, 8);
int ulen = this.username.length() * 2;
this.type3[38] = (byte)(ulen % 256);
this.type3[36] = (byte)(ulen % 256);
this.type3[39] = (byte)(ulen / 256);
this.type3[37] = (byte)(ulen / 256);
int dlen = this.ntdomain.length() * 2;
this.type3[30] = (byte)(dlen % 256);
this.type3[28] = (byte)(dlen % 256);
this.type3[31] = (byte)(dlen / 256);
this.type3[29] = (byte)(dlen / 256);
int hlen = this.hostname.length() * 2;
this.type3[46] = (byte)(hlen % 256);
this.type3[44] = (byte)(hlen % 256);
this.type3[47] = (byte)(hlen / 256);
this.type3[45] = (byte)(hlen / 256);
int l = 64;
copybytes(this.type3, l, this.ntdomain, "UnicodeLittleUnmarked");
this.type3[32] = (byte)(l % 256);
this.type3[33] = (byte)(l / 256);
l += dlen;
copybytes(this.type3, l, this.username, "UnicodeLittleUnmarked");
this.type3[40] = (byte)(l % 256);
this.type3[41] = (byte)(l / 256);
l += ulen;
copybytes(this.type3, l, this.hostname, "UnicodeLittleUnmarked");
this.type3[48] = (byte)(l % 256);
this.type3[49] = (byte)(l / 256);
l += hlen;
byte[] lmhash = calcLMHash();
byte[] lmresponse = calcResponse(lmhash, nonce);
byte[] nthash = calcNTHash();
byte[] ntresponse = calcResponse(nthash, nonce);
System.arraycopy(lmresponse, 0, this.type3, l, 24);
this.type3[16] = (byte)(l % 256);
this.type3[17] = (byte)(l / 256);
l += 24;
System.arraycopy(ntresponse, 0, this.type3, l, 24);
this.type3[24] = (byte)(l % 256);
this.type3[25] = (byte)(l / 256);
l += 24;
this.type3[56] = (byte)(l % 256);
this.type3[57] = (byte)(l / 256);
byte[] msg = new byte[l];
System.arraycopy(this.type3, 0, msg, 0, l);
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("type 3 message: " + toHex(msg));
String result = null;
try {
result = new String(BASE64EncoderStream.encode(msg), "iso-8859-1");
} catch (UnsupportedEncodingException e) {
assert false;
}
return result;
} catch (GeneralSecurityException ex) {
this.logger.log(Level.FINE, "GeneralSecurityException", (Throwable)ex);
return "";
}
}
private static char[] hex = new char[] {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'A', 'B', 'C', 'D', 'E', 'F' };
private static String toHex(byte[] b) {
StringBuffer sb = new StringBuffer(b.length * 3);
for (int i = 0; i < b.length; i++)
sb.append(hex[b[i] >> 4 & 0xF]).append(hex[b[i] & 0xF]).append(' ');
return sb.toString();
}
}

View file

@ -0,0 +1,77 @@
package com.sun.mail.auth;
import com.sun.mail.util.ASCIIUtility;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslException;
public class OAuth2SaslClient implements SaslClient {
private CallbackHandler cbh;
private boolean complete = false;
public OAuth2SaslClient(Map<String, ?> props, CallbackHandler cbh) {
this.cbh = cbh;
}
public String getMechanismName() {
return "XOAUTH2";
}
public boolean hasInitialResponse() {
return true;
}
public byte[] evaluateChallenge(byte[] challenge) throws SaslException {
byte[] response;
if (this.complete)
return new byte[0];
NameCallback ncb = new NameCallback("User name:");
PasswordCallback pcb = new PasswordCallback("OAuth token:", false);
try {
this.cbh.handle(new Callback[] { ncb, pcb });
} catch (UnsupportedCallbackException ex) {
throw new SaslException("Unsupported callback", ex);
} catch (IOException ex) {
throw new SaslException("Callback handler failed", ex);
}
String user = ncb.getName();
String token = new String(pcb.getPassword());
pcb.clearPassword();
String resp = "user=" + user + "\001auth=Bearer " + token + "\001\001";
try {
response = resp.getBytes("utf-8");
} catch (UnsupportedEncodingException ex) {
response = ASCIIUtility.getBytes(resp);
}
this.complete = true;
return response;
}
public boolean isComplete() {
return this.complete;
}
public byte[] unwrap(byte[] incoming, int offset, int len) throws SaslException {
throw new IllegalStateException("OAUTH2 unwrap not supported");
}
public byte[] wrap(byte[] outgoing, int offset, int len) throws SaslException {
throw new IllegalStateException("OAUTH2 wrap not supported");
}
public Object getNegotiatedProperty(String propName) {
if (!this.complete)
throw new IllegalStateException("OAUTH2 getNegotiatedProperty");
return null;
}
public void dispose() throws SaslException {}
}

View file

@ -0,0 +1,43 @@
package com.sun.mail.auth;
import java.security.Provider;
import java.security.Security;
import java.util.Map;
import javax.security.auth.callback.CallbackHandler;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslClientFactory;
import javax.security.sasl.SaslException;
public class OAuth2SaslClientFactory implements SaslClientFactory {
private static final String PROVIDER_NAME = "JavaMail-OAuth2";
private static final String MECHANISM_NAME = "SaslClientFactory.XOAUTH2";
static class OAuth2Provider extends Provider {
private static final long serialVersionUID = -5371795551562287059L;
public OAuth2Provider() {
super("JavaMail-OAuth2", 1.0D, "XOAUTH2 SASL Mechanism");
put("SaslClientFactory.XOAUTH2", OAuth2SaslClientFactory.class.getName());
}
}
public SaslClient createSaslClient(String[] mechanisms, String authorizationId, String protocol, String serverName, Map<String, ?> props, CallbackHandler cbh) throws SaslException {
for (String m : mechanisms) {
if (m.equals("XOAUTH2"))
return new OAuth2SaslClient(props, cbh);
}
return null;
}
public String[] getMechanismNames(Map<String, ?> props) {
return new String[] { "XOAUTH2" };
}
public static void init() {
try {
if (Security.getProvider("JavaMail-OAuth2") == null)
Security.addProvider(new OAuth2Provider());
} catch (SecurityException e) {}
}
}

View file

@ -0,0 +1,60 @@
package com.sun.mail.handlers;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.datatransfer.DataFlavor;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.activation.ActivationDataFlavor;
import javax.activation.DataContentHandler;
import javax.activation.DataSource;
public class image_gif implements DataContentHandler {
private static ActivationDataFlavor myDF = new ActivationDataFlavor(Image.class, "image/gif", "GIF Image");
protected ActivationDataFlavor getDF() {
return myDF;
}
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { (DataFlavor)getDF() };
}
public Object getTransferData(DataFlavor df, DataSource ds) throws IOException {
if (getDF().equals(df))
return getContent(ds);
return null;
}
public Object getContent(DataSource ds) throws IOException {
InputStream is = ds.getInputStream();
int pos = 0;
byte[] buf = new byte[1024];
int count;
while ((count = is.read(buf, pos, buf.length - pos)) != -1) {
pos += count;
if (pos >= buf.length) {
int size = buf.length;
if (size < 262144) {
size += size;
} else {
size += 262144;
}
byte[] tbuf = new byte[size];
System.arraycopy(buf, 0, tbuf, 0, pos);
buf = tbuf;
}
}
Toolkit tk = Toolkit.getDefaultToolkit();
return tk.createImage(buf, 0, pos);
}
public void writeTo(Object obj, String type, OutputStream os) throws IOException {
if (!(obj instanceof Image))
throw new IOException("\"" + getDF().getMimeType() + "\" DataContentHandler requires Image object, " + "was given object of type " +
obj.getClass().toString());
throw new IOException(getDF().getMimeType() + " encoding not supported");
}
}

View file

@ -0,0 +1,12 @@
package com.sun.mail.handlers;
import java.awt.Image;
import javax.activation.ActivationDataFlavor;
public class image_jpeg extends image_gif {
private static ActivationDataFlavor myDF = new ActivationDataFlavor(Image.class, "image/jpeg", "JPEG Image");
protected ActivationDataFlavor getDF() {
return myDF;
}
}

View file

@ -0,0 +1,58 @@
package com.sun.mail.handlers;
import java.awt.datatransfer.DataFlavor;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
import javax.activation.ActivationDataFlavor;
import javax.activation.DataContentHandler;
import javax.activation.DataSource;
import javax.mail.Message;
import javax.mail.MessageAware;
import javax.mail.MessageContext;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.MimeMessage;
public class message_rfc822 implements DataContentHandler {
ActivationDataFlavor ourDataFlavor = new ActivationDataFlavor(Message.class, "message/rfc822", "Message");
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { (DataFlavor)this.ourDataFlavor };
}
public Object getTransferData(DataFlavor df, DataSource ds) throws IOException {
if (this.ourDataFlavor.equals(df))
return getContent(ds);
return null;
}
public Object getContent(DataSource ds) throws IOException {
try {
Session session;
if (ds instanceof MessageAware) {
MessageContext mc = ((MessageAware)ds).getMessageContext();
session = mc.getSession();
} else {
session = Session.getDefaultInstance(new Properties(), null);
}
return new MimeMessage(session, ds.getInputStream());
} catch (MessagingException me) {
throw new IOException("Exception creating MimeMessage in message/rfc822 DataContentHandler: " +
me.toString());
}
}
public void writeTo(Object obj, String mimeType, OutputStream os) throws IOException {
if (obj instanceof Message) {
Message m = (Message)obj;
try {
m.writeTo(os);
} catch (MessagingException me) {
throw new IOException(me.toString());
}
} else {
throw new IOException("unsupported object");
}
}
}

View file

@ -0,0 +1,43 @@
package com.sun.mail.handlers;
import java.awt.datatransfer.DataFlavor;
import java.io.IOException;
import java.io.OutputStream;
import javax.activation.ActivationDataFlavor;
import javax.activation.DataContentHandler;
import javax.activation.DataSource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMultipart;
public class multipart_mixed implements DataContentHandler {
private ActivationDataFlavor myDF = new ActivationDataFlavor(MimeMultipart.class, "multipart/mixed", "Multipart");
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { (DataFlavor)this.myDF };
}
public Object getTransferData(DataFlavor df, DataSource ds) throws IOException {
if (this.myDF.equals(df))
return getContent(ds);
return null;
}
public Object getContent(DataSource ds) throws IOException {
try {
return new MimeMultipart(ds);
} catch (MessagingException e) {
IOException ioex = new IOException("Exception while constructing MimeMultipart");
ioex.initCause(e);
throw ioex;
}
}
public void writeTo(Object obj, String mimeType, OutputStream os) throws IOException {
if (obj instanceof MimeMultipart)
try {
((MimeMultipart)obj).writeTo(os);
} catch (MessagingException e) {
throw new IOException(e.toString());
}
}
}

View file

@ -0,0 +1,11 @@
package com.sun.mail.handlers;
import javax.activation.ActivationDataFlavor;
public class text_html extends text_plain {
private static ActivationDataFlavor myDF = new ActivationDataFlavor(String.class, "text/html", "HTML String");
protected ActivationDataFlavor getDF() {
return myDF;
}
}

View file

@ -0,0 +1,105 @@
package com.sun.mail.handlers;
import java.awt.datatransfer.DataFlavor;
import java.io.FilterOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import javax.activation.ActivationDataFlavor;
import javax.activation.DataContentHandler;
import javax.activation.DataSource;
import javax.mail.internet.ContentType;
import javax.mail.internet.MimeUtility;
public class text_plain implements DataContentHandler {
private static ActivationDataFlavor myDF = new ActivationDataFlavor(String.class, "text/plain", "Text String");
private static class NoCloseOutputStream extends FilterOutputStream {
public NoCloseOutputStream(OutputStream os) {
super(os);
}
public void close() {}
}
protected ActivationDataFlavor getDF() {
return myDF;
}
public DataFlavor[] getTransferDataFlavors() {
return new DataFlavor[] { (DataFlavor)getDF() };
}
public Object getTransferData(DataFlavor df, DataSource ds) throws IOException {
if (getDF().equals(df))
return getContent(ds);
return null;
}
public Object getContent(DataSource ds) throws IOException {
String enc = null;
InputStreamReader is = null;
try {
enc = getCharset(ds.getContentType());
is = new InputStreamReader(ds.getInputStream(), enc);
} catch (IllegalArgumentException iex) {
throw new UnsupportedEncodingException(enc);
}
try {
int pos = 0;
char[] buf = new char[1024];
int count;
while ((count = is.read(buf, pos, buf.length - pos)) != -1) {
pos += count;
if (pos >= buf.length) {
int size = buf.length;
if (size < 262144) {
size += size;
} else {
size += 262144;
}
char[] tbuf = new char[size];
System.arraycopy(buf, 0, tbuf, 0, pos);
buf = tbuf;
}
}
return new String(buf, 0, pos);
} finally {
try {
is.close();
} catch (IOException e) {}
}
}
public void writeTo(Object obj, String type, OutputStream os) throws IOException {
if (!(obj instanceof String))
throw new IOException("\"" + getDF().getMimeType() + "\" DataContentHandler requires String object, " + "was given object of type " +
obj.getClass().toString());
String enc = null;
OutputStreamWriter osw = null;
try {
enc = getCharset(type);
osw = new OutputStreamWriter(new NoCloseOutputStream(os), enc);
} catch (IllegalArgumentException iex) {
throw new UnsupportedEncodingException(enc);
}
String s = (String)obj;
osw.write(s, 0, s.length());
osw.close();
}
private String getCharset(String type) {
try {
ContentType ct = new ContentType(type);
String charset = ct.getParameter("charset");
if (charset == null)
charset = "us-ascii";
return MimeUtility.javaCharset(charset);
} catch (Exception ex) {
return null;
}
}
}

View file

@ -0,0 +1,83 @@
package com.sun.mail.handlers;
import java.awt.datatransfer.DataFlavor;
import java.io.IOException;
import java.io.OutputStream;
import javax.activation.ActivationDataFlavor;
import javax.activation.DataSource;
import javax.mail.internet.ContentType;
import javax.mail.internet.ParseException;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
public class text_xml extends text_plain {
private final DataFlavor[] flavors = new DataFlavor[] { new ActivationDataFlavor(String.class, "text/xml", "XML String"), new ActivationDataFlavor(String.class, "application/xml", "XML String"), new ActivationDataFlavor(StreamSource.class, "text/xml", "XML"), new ActivationDataFlavor(StreamSource.class, "application/xml", "XML") };
public DataFlavor[] getTransferDataFlavors() {
return (DataFlavor[])this.flavors.clone();
}
public Object getTransferData(DataFlavor df, DataSource ds) throws IOException {
for (int i = 0; i < this.flavors.length; i++) {
DataFlavor aFlavor = this.flavors[i];
if (aFlavor.equals(df)) {
if (aFlavor.getRepresentationClass() == String.class)
return getContent(ds);
if (aFlavor.getRepresentationClass() == StreamSource.class)
return new StreamSource(ds.getInputStream());
return null;
}
}
return null;
}
public void writeTo(Object obj, String mimeType, OutputStream os) throws IOException {
if (!isXmlType(mimeType))
throw new IOException("Invalid content type \"" + mimeType + "\" for text/xml DCH");
if (obj instanceof String) {
super.writeTo(obj, mimeType, os);
return;
}
if (!(obj instanceof DataSource) && !(obj instanceof Source))
throw new IOException("Invalid Object type = " + obj.getClass() + ". XmlDCH can only convert DataSource or Source to XML.");
try {
Transformer transformer = TransformerFactory.newInstance().newTransformer();
StreamResult result = new StreamResult(os);
if (obj instanceof DataSource) {
transformer.transform(new StreamSource(((DataSource)obj)
.getInputStream()), result);
} else {
transformer.transform((Source)obj, result);
}
} catch (TransformerException ex) {
IOException ioex = new IOException("Unable to run the JAXP transformer on a stream " +
ex.getMessage());
ioex.initCause(ex);
throw ioex;
} catch (RuntimeException ex) {
IOException ioex = new IOException("Unable to run the JAXP transformer on a stream " +
ex.getMessage());
ioex.initCause(ex);
throw ioex;
}
}
private boolean isXmlType(String type) {
try {
ContentType ct = new ContentType(type);
return (ct.getSubType().equals("xml") && (
ct.getPrimaryType().equals("text") ||
ct.getPrimaryType().equals("application")));
} catch (ParseException ex) {
return false;
} catch (RuntimeException ex) {
return false;
}
}
}

View file

@ -0,0 +1,9 @@
package com.sun.mail.iap;
class AString {
byte[] bytes;
AString(byte[] b) {
this.bytes = b;
}
}

View file

@ -0,0 +1,203 @@
package com.sun.mail.iap;
import com.sun.mail.util.ASCIIUtility;
import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.List;
public class Argument {
protected List items = new ArrayList(1);
public Argument append(Argument arg) {
this.items.addAll(arg.items);
return this;
}
public Argument writeString(String s) {
this.items.add(new AString(ASCIIUtility.getBytes(s)));
return this;
}
public Argument writeString(String s, String charset) throws UnsupportedEncodingException {
if (charset == null) {
writeString(s);
} else {
this.items.add(new AString(s.getBytes(charset)));
}
return this;
}
public Argument writeNString(String s) {
if (s == null) {
this.items.add(new NString(null));
} else {
this.items.add(new NString(ASCIIUtility.getBytes(s)));
}
return this;
}
public Argument writeNString(String s, String charset) throws UnsupportedEncodingException {
if (s == null) {
this.items.add(new NString(null));
} else if (charset == null) {
writeString(s);
} else {
this.items.add(new NString(s.getBytes(charset)));
}
return this;
}
public Argument writeBytes(byte[] b) {
this.items.add(b);
return this;
}
public Argument writeBytes(ByteArrayOutputStream b) {
this.items.add(b);
return this;
}
public Argument writeBytes(Literal b) {
this.items.add(b);
return this;
}
public Argument writeAtom(String s) {
this.items.add(new Atom(s));
return this;
}
public Argument writeNumber(int i) {
this.items.add(Integer.valueOf(i));
return this;
}
public Argument writeNumber(long i) {
this.items.add(Long.valueOf(i));
return this;
}
public Argument writeArgument(Argument c) {
this.items.add(c);
return this;
}
public void write(Protocol protocol) throws IOException, ProtocolException {
int size = (this.items != null) ? this.items.size() : 0;
DataOutputStream os = (DataOutputStream)protocol.getOutputStream();
for (int i = 0; i < size; i++) {
if (i > 0)
os.write(32);
Object o = this.items.get(i);
if (o instanceof Atom) {
os.writeBytes(((Atom)o).string);
} else if (o instanceof Number) {
os.writeBytes(((Number)o).toString());
} else if (o instanceof AString) {
astring(((AString)o).bytes, protocol);
} else if (o instanceof NString) {
nstring(((NString)o).bytes, protocol);
} else if (o instanceof byte[]) {
literal((byte[])o, protocol);
} else if (o instanceof ByteArrayOutputStream) {
literal((ByteArrayOutputStream)o, protocol);
} else if (o instanceof Literal) {
literal((Literal)o, protocol);
} else if (o instanceof Argument) {
os.write(40);
((Argument)o).write(protocol);
os.write(41);
}
}
}
private void astring(byte[] bytes, Protocol protocol) throws IOException, ProtocolException {
nastring(bytes, protocol, false);
}
private void nstring(byte[] bytes, Protocol protocol) throws IOException, ProtocolException {
if (bytes == null) {
DataOutputStream os = (DataOutputStream)protocol.getOutputStream();
os.writeBytes("NIL");
} else {
nastring(bytes, protocol, true);
}
}
private void nastring(byte[] bytes, Protocol protocol, boolean doQuote) throws IOException, ProtocolException {
DataOutputStream os = (DataOutputStream)protocol.getOutputStream();
int len = bytes.length;
if (len > 1024) {
literal(bytes, protocol);
return;
}
boolean quote = (len == 0) ? true : doQuote;
boolean escape = false;
for (int i = 0; i < len; i++) {
byte b = bytes[i];
if (b == 0 || b == 13 || b == 10 || (b & 0xFF) > 127) {
literal(bytes, protocol);
return;
}
if (b == 42 || b == 37 || b == 40 || b == 41 || b == 123 || b == 34 || b == 92 || (b & 0xFF) <= 32) {
quote = true;
if (b == 34 || b == 92)
escape = true;
}
}
if (!quote && bytes.length == 3 && (bytes[0] == 78 || bytes[0] == 110) && (bytes[1] == 73 || bytes[1] == 105) && (bytes[2] == 76 || bytes[2] == 108))
quote = true;
if (quote)
os.write(34);
if (escape) {
for (int j = 0; j < len; j++) {
byte b = bytes[j];
if (b == 34 || b == 92)
os.write(92);
os.write(b);
}
} else {
os.write(bytes);
}
if (quote)
os.write(34);
}
private void literal(byte[] b, Protocol protocol) throws IOException, ProtocolException {
startLiteral(protocol, b.length).write(b);
}
private void literal(ByteArrayOutputStream b, Protocol protocol) throws IOException, ProtocolException {
b.writeTo(startLiteral(protocol, b.size()));
}
private void literal(Literal b, Protocol protocol) throws IOException, ProtocolException {
b.writeTo(startLiteral(protocol, b.size()));
}
private OutputStream startLiteral(Protocol protocol, int size) throws IOException, ProtocolException {
DataOutputStream os = (DataOutputStream)protocol.getOutputStream();
boolean nonSync = protocol.supportsNonSyncLiterals();
os.write(123);
os.writeBytes(Integer.toString(size));
if (nonSync) {
os.writeBytes("+}\r\n");
} else {
os.writeBytes("}\r\n");
}
os.flush();
if (!nonSync)
while (true) {
Response r = protocol.readResponse();
if (r.isContinuation())
break;
if (r.isTagged())
throw new LiteralException(r);
}
return os;
}
}

View file

@ -0,0 +1,9 @@
package com.sun.mail.iap;
class Atom {
String string;
Atom(String s) {
this.string = s;
}
}

View file

@ -0,0 +1,15 @@
package com.sun.mail.iap;
public class BadCommandException extends ProtocolException {
private static final long serialVersionUID = 5769722539397237515L;
public BadCommandException() {}
public BadCommandException(String s) {
super(s);
}
public BadCommandException(Response r) {
super(r);
}
}

View file

@ -0,0 +1,53 @@
package com.sun.mail.iap;
import java.io.ByteArrayInputStream;
public class ByteArray {
private byte[] bytes;
private int start;
private int count;
public ByteArray(byte[] b, int start, int count) {
this.bytes = b;
this.start = start;
this.count = count;
}
public ByteArray(int size) {
this(new byte[size], 0, size);
}
public byte[] getBytes() {
return this.bytes;
}
public byte[] getNewBytes() {
byte[] b = new byte[this.count];
System.arraycopy(this.bytes, this.start, b, 0, this.count);
return b;
}
public int getStart() {
return this.start;
}
public int getCount() {
return this.count;
}
public void setCount(int count) {
this.count = count;
}
public ByteArrayInputStream toByteArrayInputStream() {
return new ByteArrayInputStream(this.bytes, this.start, this.count);
}
public void grow(int incr) {
byte[] nbuf = new byte[this.bytes.length + incr];
System.arraycopy(this.bytes, 0, nbuf, 0, this.bytes.length);
this.bytes = nbuf;
}
}

View file

@ -0,0 +1,15 @@
package com.sun.mail.iap;
public class CommandFailedException extends ProtocolException {
private static final long serialVersionUID = 793932807880443631L;
public CommandFailedException() {}
public CommandFailedException(String s) {
super(s);
}
public CommandFailedException(Response r) {
super(r);
}
}

View file

@ -0,0 +1,22 @@
package com.sun.mail.iap;
public class ConnectionException extends ProtocolException {
private transient Protocol p;
private static final long serialVersionUID = 5749739604257464727L;
public ConnectionException() {}
public ConnectionException(String s) {
super(s);
}
public ConnectionException(Protocol p, Response r) {
super(r);
this.p = p;
}
public Protocol getProtocol() {
return this.p;
}
}

View file

@ -0,0 +1,10 @@
package com.sun.mail.iap;
import java.io.IOException;
import java.io.OutputStream;
public interface Literal {
int size();
void writeTo(OutputStream paramOutputStream) throws IOException;
}

View file

@ -0,0 +1,10 @@
package com.sun.mail.iap;
public class LiteralException extends ProtocolException {
private static final long serialVersionUID = -6919179828339609913L;
public LiteralException(Response r) {
super(r.toString());
this.response = r;
}
}

View file

@ -0,0 +1,9 @@
package com.sun.mail.iap;
class NString {
byte[] bytes;
NString(byte[] b) {
this.bytes = b;
}
}

View file

@ -0,0 +1,15 @@
package com.sun.mail.iap;
public class ParsingException extends ProtocolException {
private static final long serialVersionUID = 7756119840142724839L;
public ParsingException() {}
public ParsingException(String s) {
super(s);
}
public ParsingException(Response r) {
super(r);
}
}

View file

@ -0,0 +1,315 @@
package com.sun.mail.iap;
import com.sun.mail.util.MailLogger;
import com.sun.mail.util.PropUtil;
import com.sun.mail.util.SocketFetcher;
import com.sun.mail.util.TraceInputStream;
import com.sun.mail.util.TraceOutputStream;
import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.channels.SocketChannel;
import java.util.Properties;
import java.util.Vector;
import java.util.logging.Level;
public class Protocol {
protected String host;
private Socket socket;
protected boolean quote;
protected MailLogger logger;
protected MailLogger traceLogger;
protected Properties props;
protected String prefix;
private TraceInputStream traceInput;
private volatile ResponseInputStream input;
private TraceOutputStream traceOutput;
private volatile DataOutputStream output;
private int tagCounter = 0;
private String localHostName;
private final Vector handlers = new Vector();
private volatile long timestamp;
private static final byte[] CRLF = new byte[] { 13, 10 };
public Protocol(String host, int port, Properties props, String prefix, boolean isSSL, MailLogger logger) throws IOException, ProtocolException {
boolean connected = false;
try {
this.host = host;
this.props = props;
this.prefix = prefix;
this.logger = logger;
this.traceLogger = logger.getSubLogger("protocol", null);
this.socket = SocketFetcher.getSocket(host, port, props, prefix, isSSL);
this.quote = PropUtil.getBooleanProperty(props, "mail.debug.quote", false);
initStreams();
processGreeting(readResponse());
this.timestamp = System.currentTimeMillis();
connected = true;
} finally {
if (!connected)
disconnect();
}
}
private void initStreams() throws IOException {
this.traceInput = new TraceInputStream(this.socket.getInputStream(), this.traceLogger);
this.traceInput.setQuote(this.quote);
this.input = new ResponseInputStream(this.traceInput);
this
.traceOutput = new TraceOutputStream(this.socket.getOutputStream(), this.traceLogger);
this.traceOutput.setQuote(this.quote);
this.output = new DataOutputStream(new BufferedOutputStream(this.traceOutput));
}
public Protocol(InputStream in, PrintStream out, Properties props, boolean debug) throws IOException {
this.host = "localhost";
this.props = props;
this.quote = false;
this.logger = new MailLogger(getClass(), "DEBUG", debug, System.out);
this.traceLogger = this.logger.getSubLogger("protocol", null);
this.traceInput = new TraceInputStream(in, this.traceLogger);
this.traceInput.setQuote(this.quote);
this.input = new ResponseInputStream(this.traceInput);
this.traceOutput = new TraceOutputStream(out, this.traceLogger);
this.traceOutput.setQuote(this.quote);
this.output = new DataOutputStream(new BufferedOutputStream(this.traceOutput));
this.timestamp = System.currentTimeMillis();
}
public long getTimestamp() {
return this.timestamp;
}
public void addResponseHandler(ResponseHandler h) {
this.handlers.addElement(h);
}
public void removeResponseHandler(ResponseHandler h) {
this.handlers.removeElement(h);
}
public void notifyResponseHandlers(Response[] responses) {
if (this.handlers.size() == 0)
return;
for (int i = 0; i < responses.length; i++) {
Response r = responses[i];
if (r != null) {
Object[] h = this.handlers.toArray();
for (int j = 0; j < h.length; j++) {
if (h[j] != null)
((ResponseHandler)h[j]).handleResponse(r);
}
}
}
}
protected void processGreeting(Response r) throws ProtocolException {
if (r.isBYE())
throw new ConnectionException(this, r);
}
protected ResponseInputStream getInputStream() {
return this.input;
}
protected OutputStream getOutputStream() {
return this.output;
}
protected synchronized boolean supportsNonSyncLiterals() {
return false;
}
public Response readResponse() throws IOException, ProtocolException {
return new Response(this);
}
public boolean hasResponse() {
try {
return (this.input.available() > 0);
} catch (IOException e) {
return false;
}
}
protected ByteArray getResponseBuffer() {
return null;
}
public String writeCommand(String command, Argument args) throws IOException, ProtocolException {
String tag = "A" + Integer.toString(this.tagCounter++, 10);
this.output.writeBytes(tag + " " + command);
if (args != null) {
this.output.write(32);
args.write(this);
}
this.output.write(CRLF);
this.output.flush();
return tag;
}
public synchronized Response[] command(String command, Argument args) {
commandStart(command);
Vector<Response> v = new Vector();
boolean done = false;
String tag = null;
Response r = null;
try {
tag = writeCommand(command, args);
} catch (LiteralException lex) {
v.addElement(lex.getResponse());
done = true;
} catch (Exception ex) {
v.addElement(Response.byeResponse(ex));
done = true;
}
Response byeResp = null;
while (!done) {
try {
r = readResponse();
} catch (IOException ioex) {
if (byeResp != null)
break;
r = Response.byeResponse(ioex);
} catch (ProtocolException pex) {
this.logger.log(Level.FINE, "ignoring bad response", (Throwable)pex);
continue;
}
if (r.isBYE()) {
byeResp = r;
continue;
}
v.addElement(r);
if (r.isTagged() && r.getTag().equals(tag))
done = true;
}
if (byeResp != null)
v.addElement(byeResp);
Response[] responses = new Response[v.size()];
v.copyInto(responses);
this.timestamp = System.currentTimeMillis();
commandEnd();
return responses;
}
public void handleResult(Response response) throws ProtocolException {
if (response.isOK())
return;
if (response.isNO())
throw new CommandFailedException(response);
if (response.isBAD())
throw new BadCommandException(response);
if (response.isBYE()) {
disconnect();
throw new ConnectionException(this, response);
}
}
public void simpleCommand(String cmd, Argument args) throws ProtocolException {
Response[] r = command(cmd, args);
notifyResponseHandlers(r);
handleResult(r[r.length - 1]);
}
public synchronized void startTLS(String cmd) throws IOException, ProtocolException {
if (this.socket instanceof javax.net.ssl.SSLSocket)
return;
simpleCommand(cmd, null);
this.socket = SocketFetcher.startTLS(this.socket, this.host, this.props, this.prefix);
initStreams();
}
public boolean isSSL() {
return this.socket instanceof javax.net.ssl.SSLSocket;
}
public InetAddress getInetAddress() {
return this.socket.getInetAddress();
}
public SocketChannel getChannel() {
return this.socket.getChannel();
}
protected synchronized void disconnect() {
if (this.socket != null) {
try {
this.socket.close();
} catch (IOException e) {}
this.socket = null;
}
}
protected synchronized String getLocalHost() {
if (this.localHostName == null || this.localHostName.length() <= 0)
this
.localHostName = this.props.getProperty(this.prefix + ".localhost");
if (this.localHostName == null || this.localHostName.length() <= 0)
this
.localHostName = this.props.getProperty(this.prefix + ".localaddress");
try {
if (this.localHostName == null || this.localHostName.length() <= 0) {
InetAddress localHost = InetAddress.getLocalHost();
this.localHostName = localHost.getCanonicalHostName();
if (this.localHostName == null)
this.localHostName = "[" + localHost.getHostAddress() + "]";
}
} catch (UnknownHostException e) {}
if ((this.localHostName == null || this.localHostName.length() <= 0) &&
this.socket != null && this.socket.isBound()) {
InetAddress localHost = this.socket.getLocalAddress();
this.localHostName = localHost.getCanonicalHostName();
if (this.localHostName == null)
this.localHostName = "[" + localHost.getHostAddress() + "]";
}
return this.localHostName;
}
protected boolean isTracing() {
return this.traceLogger.isLoggable(Level.FINEST);
}
protected void suspendTracing() {
if (this.traceLogger.isLoggable(Level.FINEST)) {
this.traceInput.setTrace(false);
this.traceOutput.setTrace(false);
}
}
protected void resumeTracing() {
if (this.traceLogger.isLoggable(Level.FINEST)) {
this.traceInput.setTrace(true);
this.traceOutput.setTrace(true);
}
}
protected void finalize() throws Throwable {
super.finalize();
disconnect();
}
private void commandStart(String command) {}
private void commandEnd() {}
}

View file

@ -0,0 +1,26 @@
package com.sun.mail.iap;
public class ProtocolException extends Exception {
protected transient Response response = null;
private static final long serialVersionUID = -4360500807971797439L;
public ProtocolException() {}
public ProtocolException(String message) {
super(message);
}
public ProtocolException(String message, Throwable cause) {
super(message, cause);
}
public ProtocolException(Response r) {
super(r.toString());
this.response = r;
}
public Response getResponse() {
return this.response;
}
}

View file

@ -0,0 +1,348 @@
package com.sun.mail.iap;
import com.sun.mail.util.ASCIIUtility;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Vector;
public class Response {
protected int index;
protected int pindex;
protected int size;
protected byte[] buffer = null;
protected int type = 0;
protected String tag = null;
protected Exception ex;
private static final int increment = 100;
public static final int TAG_MASK = 3;
public static final int CONTINUATION = 1;
public static final int TAGGED = 2;
public static final int UNTAGGED = 3;
public static final int TYPE_MASK = 28;
public static final int OK = 4;
public static final int NO = 8;
public static final int BAD = 12;
public static final int BYE = 16;
public static final int SYNTHETIC = 32;
private static String ATOM_CHAR_DELIM = " (){%*\"\\]";
private static String ASTRING_CHAR_DELIM = " (){%*\"\\";
public Response(String s) {
this.buffer = ASCIIUtility.getBytes(s);
this.size = this.buffer.length;
parse();
}
public Response(Protocol p) throws IOException, ProtocolException {
ByteArray ba = p.getResponseBuffer();
ByteArray response = p.getInputStream().readResponse(ba);
this.buffer = response.getBytes();
this.size = response.getCount() - 2;
parse();
}
public Response(Response r) {
this.index = r.index;
this.size = r.size;
this.buffer = r.buffer;
this.type = r.type;
this.tag = r.tag;
}
public static Response byeResponse(Exception ex) {
String err = "* BYE JavaMail Exception: " + ex.toString();
err = err.replace('\r', ' ').replace('\n', ' ');
Response r = new Response(err);
r.type |= 0x20;
r.ex = ex;
return r;
}
private void parse() {
this.index = 0;
if (this.size == 0)
return;
if (this.buffer[this.index] == 43) {
this.type |= 0x1;
this.index++;
return;
}
if (this.buffer[this.index] == 42) {
this.type |= 0x3;
this.index++;
} else {
this.type |= 0x2;
this.tag = readAtom();
if (this.tag == null)
this.tag = "";
}
int mark = this.index;
String s = readAtom();
if (s == null)
s = "";
if (s.equalsIgnoreCase("OK")) {
this.type |= 0x4;
} else if (s.equalsIgnoreCase("NO")) {
this.type |= 0x8;
} else if (s.equalsIgnoreCase("BAD")) {
this.type |= 0xC;
} else if (s.equalsIgnoreCase("BYE")) {
this.type |= 0x10;
} else {
this.index = mark;
}
this.pindex = this.index;
}
public void skipSpaces() {
while (this.index < this.size && this.buffer[this.index] == 32)
this.index++;
}
public void skipToken() {
while (this.index < this.size && this.buffer[this.index] != 32)
this.index++;
}
public void skip(int count) {
this.index += count;
}
public byte peekByte() {
if (this.index < this.size)
return this.buffer[this.index];
return 0;
}
public byte readByte() {
if (this.index < this.size)
return this.buffer[this.index++];
return 0;
}
public String readAtom() {
return readDelimString(ATOM_CHAR_DELIM);
}
private String readDelimString(String delim) {
skipSpaces();
if (this.index >= this.size)
return null;
int start = this.index;
byte b;
while (this.index < this.size && (b = this.buffer[this.index]) > 32 &&
delim.indexOf((char)b) < 0 && b >= 32 && b != Byte.MAX_VALUE)
this.index++;
return ASCIIUtility.toString(this.buffer, start, this.index);
}
public String readString(char delim) {
skipSpaces();
if (this.index >= this.size)
return null;
int start = this.index;
while (this.index < this.size && this.buffer[this.index] != delim)
this.index++;
return ASCIIUtility.toString(this.buffer, start, this.index);
}
public String[] readStringList() {
return readStringList(false);
}
public String[] readAtomStringList() {
return readStringList(true);
}
private String[] readStringList(boolean atom) {
skipSpaces();
if (this.buffer[this.index] != 40)
return null;
this.index++;
Vector<String> v = new Vector();
do {
v.addElement(atom ? readAtomString() : readString());
} while (this.buffer[this.index++] != 41);
int size = v.size();
if (size > 0) {
String[] s = new String[size];
v.copyInto(s);
return s;
}
return null;
}
public int readNumber() {
skipSpaces();
int start = this.index;
while (this.index < this.size && Character.isDigit((char)this.buffer[this.index]))
this.index++;
if (this.index > start)
try {
return ASCIIUtility.parseInt(this.buffer, start, this.index);
} catch (NumberFormatException e) {}
return -1;
}
public long readLong() {
skipSpaces();
int start = this.index;
while (this.index < this.size && Character.isDigit((char)this.buffer[this.index]))
this.index++;
if (this.index > start)
try {
return ASCIIUtility.parseLong(this.buffer, start, this.index);
} catch (NumberFormatException e) {}
return -1L;
}
public String readString() {
return (String)parseString(false, true);
}
public ByteArrayInputStream readBytes() {
ByteArray ba = readByteArray();
if (ba != null)
return ba.toByteArrayInputStream();
return null;
}
public ByteArray readByteArray() {
if (isContinuation()) {
skipSpaces();
return new ByteArray(this.buffer, this.index, this.size - this.index);
}
return (ByteArray)parseString(false, false);
}
public String readAtomString() {
return (String)parseString(true, true);
}
private Object parseString(boolean parseAtoms, boolean returnString) {
skipSpaces();
byte b = this.buffer[this.index];
if (b == 34) {
int start = ++this.index;
int copyto = this.index;
while (this.index < this.size && (b = this.buffer[this.index]) != 34) {
if (b == 92)
this.index++;
if (this.index != copyto)
this.buffer[copyto] = this.buffer[this.index];
copyto++;
this.index++;
}
if (this.index >= this.size)
return null;
this.index++;
if (returnString)
return ASCIIUtility.toString(this.buffer, start, copyto);
return new ByteArray(this.buffer, start, copyto - start);
}
if (b == 123) {
int start = ++this.index;
while (this.buffer[this.index] != 125)
this.index++;
int count = 0;
try {
count = ASCIIUtility.parseInt(this.buffer, start, this.index);
} catch (NumberFormatException nex) {
return null;
}
start = this.index + 3;
this.index = start + count;
if (returnString)
return ASCIIUtility.toString(this.buffer, start, start + count);
return new ByteArray(this.buffer, start, count);
}
if (parseAtoms) {
int start = this.index;
String s = readDelimString(ASTRING_CHAR_DELIM);
if (returnString)
return s;
return new ByteArray(this.buffer, start, this.index);
}
if (b == 78 || b == 110) {
this.index += 3;
return null;
}
return null;
}
public int getType() {
return this.type;
}
public boolean isContinuation() {
return ((this.type & 0x3) == 1);
}
public boolean isTagged() {
return ((this.type & 0x3) == 2);
}
public boolean isUnTagged() {
return ((this.type & 0x3) == 3);
}
public boolean isOK() {
return ((this.type & 0x1C) == 4);
}
public boolean isNO() {
return ((this.type & 0x1C) == 8);
}
public boolean isBAD() {
return ((this.type & 0x1C) == 12);
}
public boolean isBYE() {
return ((this.type & 0x1C) == 16);
}
public boolean isSynthetic() {
return ((this.type & 0x20) == 32);
}
public String getTag() {
return this.tag;
}
public String getRest() {
skipSpaces();
return ASCIIUtility.toString(this.buffer, this.index, this.size);
}
public Exception getException() {
return this.ex;
}
public void reset() {
this.index = this.pindex;
}
public String toString() {
return ASCIIUtility.toString(this.buffer, 0, this.size);
}
}

View file

@ -0,0 +1,5 @@
package com.sun.mail.iap;
public interface ResponseHandler {
void handleResponse(Response paramResponse);
}

View file

@ -0,0 +1,82 @@
package com.sun.mail.iap;
import com.sun.mail.util.ASCIIUtility;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
public class ResponseInputStream {
private static final int minIncrement = 256;
private static final int maxIncrement = 262144;
private static final int incrementSlop = 16;
private BufferedInputStream bin;
public ResponseInputStream(InputStream in) {
this.bin = new BufferedInputStream(in, 2048);
}
public ByteArray readResponse() throws IOException {
return readResponse(null);
}
public ByteArray readResponse(ByteArray ba) throws IOException {
if (ba == null)
ba = new ByteArray(new byte[128], 0, 128);
byte[] buffer = ba.getBytes();
int idx = 0;
while (true) {
int b = 0;
boolean gotCRLF = false;
while (!gotCRLF && (
b = this.bin.read()) != -1) {
if (b == 10 &&
idx > 0 && buffer[idx - 1] == 13)
gotCRLF = true;
if (idx >= buffer.length) {
int incr = buffer.length;
if (incr > 262144)
incr = 262144;
ba.grow(incr);
buffer = ba.getBytes();
}
buffer[idx++] = (byte)b;
}
if (b == -1)
throw new IOException("Connection dropped by server?");
if (idx < 5 || buffer[idx - 3] != 125)
break;
int i;
for (i = idx - 4; i >= 0 &&
buffer[i] != 123; i--);
if (i < 0)
break;
int count = 0;
try {
count = ASCIIUtility.parseInt(buffer, i + 1, idx - 3);
} catch (NumberFormatException e) {
break;
}
if (count > 0) {
int avail = buffer.length - idx;
if (count + 16 > avail) {
ba.grow((256 > count + 16 - avail) ? 256 : (count + 16 - avail));
buffer = ba.getBytes();
}
while (count > 0) {
int actual = this.bin.read(buffer, idx, count);
count -= actual;
idx += actual;
}
}
}
ba.setCount(idx);
return ba;
}
public int available() throws IOException {
return this.bin.available();
}
}

View file

@ -0,0 +1,35 @@
package com.sun.mail.imap;
public class ACL implements Cloneable {
private String name;
private Rights rights;
public ACL(String name) {
this.name = name;
this.rights = new Rights();
}
public ACL(String name, Rights rights) {
this.name = name;
this.rights = rights;
}
public String getName() {
return this.name;
}
public void setRights(Rights rights) {
this.rights = rights;
}
public Rights getRights() {
return this.rights;
}
public Object clone() throws CloneNotSupportedException {
ACL acl = (ACL)super.clone();
acl.rights = (Rights)this.rights.clone();
return acl;
}
}

View file

@ -0,0 +1,12 @@
package com.sun.mail.imap;
public class AppendUID {
public long uidvalidity = -1L;
public long uid = -1L;
public AppendUID(long uidvalidity, long uid) {
this.uidvalidity = uidvalidity;
this.uid = uid;
}
}

View file

@ -0,0 +1,17 @@
package com.sun.mail.imap;
import com.sun.mail.imap.protocol.UIDSet;
public class CopyUID {
public long uidvalidity = -1L;
public UIDSet[] src;
public UIDSet[] dst;
public CopyUID(long uidvalidity, UIDSet[] src, UIDSet[] dst) {
this.uidvalidity = uidvalidity;
this.src = src;
this.dst = dst;
}
}

View file

@ -0,0 +1,79 @@
package com.sun.mail.imap;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.imap.protocol.IMAPProtocol;
import com.sun.mail.imap.protocol.ListInfo;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.MethodNotSupportedException;
public class DefaultFolder extends IMAPFolder {
protected DefaultFolder(IMAPStore store) {
super("", Character.MAX_VALUE, store, null);
this.exists = true;
this.type = 2;
}
public synchronized String getName() {
return this.fullName;
}
public Folder getParent() {
return null;
}
public synchronized Folder[] list(final String pattern) throws MessagingException {
ListInfo[] li = null;
li = (ListInfo[])doCommand(new IMAPFolder.ProtocolCommand() {
public Object doCommand(IMAPProtocol p) throws ProtocolException {
return p.list("", pattern);
}
});
if (li == null)
return new Folder[0];
IMAPFolder[] folders = new IMAPFolder[li.length];
for (int i = 0; i < folders.length; i++)
folders[i] = ((IMAPStore)this.store).newIMAPFolder(li[i]);
return folders;
}
public synchronized Folder[] listSubscribed(final String pattern) throws MessagingException {
ListInfo[] li = null;
li = (ListInfo[])doCommand(new IMAPFolder.ProtocolCommand() {
public Object doCommand(IMAPProtocol p) throws ProtocolException {
return p.lsub("", pattern);
}
});
if (li == null)
return new Folder[0];
IMAPFolder[] folders = new IMAPFolder[li.length];
for (int i = 0; i < folders.length; i++)
folders[i] = ((IMAPStore)this.store).newIMAPFolder(li[i]);
return folders;
}
public boolean hasNewMessages() throws MessagingException {
return false;
}
public Folder getFolder(String name) throws MessagingException {
return ((IMAPStore)this.store).newIMAPFolder(name, Character.MAX_VALUE);
}
public boolean delete(boolean recurse) throws MessagingException {
throw new MethodNotSupportedException("Cannot delete Default Folder");
}
public boolean renameTo(Folder f) throws MessagingException {
throw new MethodNotSupportedException("Cannot rename Default Folder");
}
public void appendMessages(Message[] msgs) throws MessagingException {
throw new MethodNotSupportedException("Cannot append to Default Folder");
}
public Message[] expunge() throws MessagingException {
throw new MethodNotSupportedException("Cannot expunge Default Folder");
}
}

View file

@ -0,0 +1,304 @@
package com.sun.mail.imap;
import com.sun.mail.iap.ConnectionException;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.imap.protocol.BODY;
import com.sun.mail.imap.protocol.BODYSTRUCTURE;
import com.sun.mail.imap.protocol.IMAPProtocol;
import com.sun.mail.util.LineOutputStream;
import com.sun.mail.util.PropUtil;
import com.sun.mail.util.ReadableMime;
import com.sun.mail.util.SharedByteArrayOutputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import javax.activation.DataHandler;
import javax.mail.FolderClosedException;
import javax.mail.IllegalWriteException;
import javax.mail.MessagingException;
import javax.mail.Multipart;
import javax.mail.internet.ContentType;
import javax.mail.internet.InternetHeaders;
import javax.mail.internet.MimeBodyPart;
import javax.mail.internet.MimeUtility;
public class IMAPBodyPart extends MimeBodyPart implements ReadableMime {
private IMAPMessage message;
private BODYSTRUCTURE bs;
private String sectionId;
private String type;
private String description;
private boolean headersLoaded = false;
private static final boolean decodeFileName = PropUtil.getBooleanSystemProperty("mail.mime.decodefilename", false);
protected IMAPBodyPart(BODYSTRUCTURE bs, String sid, IMAPMessage message) {
this.bs = bs;
this.sectionId = sid;
this.message = message;
ContentType ct = new ContentType(bs.type, bs.subtype, bs.cParams);
this.type = ct.toString();
}
protected void updateHeaders() {}
public int getSize() throws MessagingException {
return this.bs.size;
}
public int getLineCount() throws MessagingException {
return this.bs.lines;
}
public String getContentType() throws MessagingException {
return this.type;
}
public String getDisposition() throws MessagingException {
return this.bs.disposition;
}
public void setDisposition(String disposition) throws MessagingException {
throw new IllegalWriteException("IMAPBodyPart is read-only");
}
public String getEncoding() throws MessagingException {
return this.bs.encoding;
}
public String getContentID() throws MessagingException {
return this.bs.id;
}
public String getContentMD5() throws MessagingException {
return this.bs.md5;
}
public void setContentMD5(String md5) throws MessagingException {
throw new IllegalWriteException("IMAPBodyPart is read-only");
}
public String getDescription() throws MessagingException {
if (this.description != null)
return this.description;
if (this.bs.description == null)
return null;
try {
this.description = MimeUtility.decodeText(this.bs.description);
} catch (UnsupportedEncodingException ex) {
this.description = this.bs.description;
}
return this.description;
}
public void setDescription(String description, String charset) throws MessagingException {
throw new IllegalWriteException("IMAPBodyPart is read-only");
}
public String getFileName() throws MessagingException {
String filename = null;
if (this.bs.dParams != null)
filename = this.bs.dParams.get("filename");
if (filename == null && this.bs.cParams != null)
filename = this.bs.cParams.get("name");
if (decodeFileName && filename != null)
try {
filename = MimeUtility.decodeText(filename);
} catch (UnsupportedEncodingException ex) {
throw new MessagingException("Can't decode filename", ex);
}
return filename;
}
public void setFileName(String filename) throws MessagingException {
throw new IllegalWriteException("IMAPBodyPart is read-only");
}
protected InputStream getContentStream() throws MessagingException {
InputStream is = null;
boolean pk = this.message.getPeek();
synchronized (this.message.getMessageCacheLock()) {
try {
BODY b;
IMAPProtocol p = this.message.getProtocol();
this.message.checkExpunged();
if (p.isREV1() && this.message.getFetchBlockSize() != -1)
return new IMAPInputStream(this.message, this.sectionId,
this.message.ignoreBodyStructureSize() ? -1 : this.bs.size, pk);
int seqnum = this.message.getSequenceNumber();
if (pk) {
b = p.peekBody(seqnum, this.sectionId);
} else {
b = p.fetchBody(seqnum, this.sectionId);
}
if (b != null)
is = b.getByteArrayInputStream();
} catch (ConnectionException cex) {
throw new FolderClosedException(
this.message.getFolder(), cex.getMessage());
} catch (ProtocolException pex) {
throw new MessagingException(pex.getMessage(), pex);
}
}
if (is == null)
throw new MessagingException("No content");
return is;
}
private InputStream getHeaderStream() throws MessagingException {
if (!this.message.isREV1())
loadHeaders();
synchronized (this.message.getMessageCacheLock()) {
IMAPProtocol p = this.message.getProtocol();
this.message.checkExpunged();
if (p.isREV1()) {
int seqnum = this.message.getSequenceNumber();
BODY b = p.peekBody(seqnum, this.sectionId + ".MIME");
if (b == null)
throw new MessagingException("Failed to fetch headers");
ByteArrayInputStream bis = b.getByteArrayInputStream();
if (bis == null)
throw new MessagingException("Failed to fetch headers");
return bis;
}
SharedByteArrayOutputStream bos = new SharedByteArrayOutputStream(0);
LineOutputStream los = new LineOutputStream(bos);
try {
Enumeration<String> hdrLines = super.getAllHeaderLines();
while (hdrLines.hasMoreElements())
los.writeln(hdrLines.nextElement());
los.writeln();
} catch (IOException e) {
} finally {
try {
los.close();
} catch (IOException e) {}
}
return bos.toStream();
}
}
public InputStream getMimeStream() throws MessagingException {
return new SequenceInputStream(getHeaderStream(), getContentStream());
}
public synchronized DataHandler getDataHandler() throws MessagingException {
if (this.dh == null)
if (this.bs.isMulti()) {
this.dh = new DataHandler(new IMAPMultipartDataSource(this, this.bs.bodies, this.sectionId, this.message));
} else if (this.bs.isNested() && this.message.isREV1() && this.bs.envelope != null) {
this.dh = new DataHandler(new IMAPNestedMessage(this.message, this.bs.bodies[0], this.bs.envelope, this.sectionId), this.type);
}
return super.getDataHandler();
}
public void setDataHandler(DataHandler content) throws MessagingException {
throw new IllegalWriteException("IMAPBodyPart is read-only");
}
public void setContent(Object o, String type) throws MessagingException {
throw new IllegalWriteException("IMAPBodyPart is read-only");
}
public void setContent(Multipart mp) throws MessagingException {
throw new IllegalWriteException("IMAPBodyPart is read-only");
}
public String[] getHeader(String name) throws MessagingException {
loadHeaders();
return super.getHeader(name);
}
public void setHeader(String name, String value) throws MessagingException {
throw new IllegalWriteException("IMAPBodyPart is read-only");
}
public void addHeader(String name, String value) throws MessagingException {
throw new IllegalWriteException("IMAPBodyPart is read-only");
}
public void removeHeader(String name) throws MessagingException {
throw new IllegalWriteException("IMAPBodyPart is read-only");
}
public Enumeration getAllHeaders() throws MessagingException {
loadHeaders();
return super.getAllHeaders();
}
public Enumeration getMatchingHeaders(String[] names) throws MessagingException {
loadHeaders();
return super.getMatchingHeaders(names);
}
public Enumeration getNonMatchingHeaders(String[] names) throws MessagingException {
loadHeaders();
return super.getNonMatchingHeaders(names);
}
public void addHeaderLine(String line) throws MessagingException {
throw new IllegalWriteException("IMAPBodyPart is read-only");
}
public Enumeration getAllHeaderLines() throws MessagingException {
loadHeaders();
return super.getAllHeaderLines();
}
public Enumeration getMatchingHeaderLines(String[] names) throws MessagingException {
loadHeaders();
return super.getMatchingHeaderLines(names);
}
public Enumeration getNonMatchingHeaderLines(String[] names) throws MessagingException {
loadHeaders();
return super.getNonMatchingHeaderLines(names);
}
private synchronized void loadHeaders() throws MessagingException {
if (this.headersLoaded)
return;
if (this.headers == null)
this.headers = new InternetHeaders();
synchronized (this.message.getMessageCacheLock()) {
try {
IMAPProtocol p = this.message.getProtocol();
this.message.checkExpunged();
if (p.isREV1()) {
int seqnum = this.message.getSequenceNumber();
BODY b = p.peekBody(seqnum, this.sectionId + ".MIME");
if (b == null)
throw new MessagingException("Failed to fetch headers");
ByteArrayInputStream bis = b.getByteArrayInputStream();
if (bis == null)
throw new MessagingException("Failed to fetch headers");
this.headers.load(bis);
} else {
this.headers.addHeader("Content-Type", this.type);
this.headers.addHeader("Content-Transfer-Encoding", this.bs.encoding);
if (this.bs.description != null)
this.headers.addHeader("Content-Description", this.bs.description);
if (this.bs.id != null)
this.headers.addHeader("Content-ID", this.bs.id);
if (this.bs.md5 != null)
this.headers.addHeader("Content-MD5", this.bs.md5);
}
} catch (ConnectionException cex) {
throw new FolderClosedException(
this.message.getFolder(), cex.getMessage());
} catch (ProtocolException pex) {
throw new MessagingException(pex.getMessage(), pex);
}
}
this.headersLoaded = true;
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,156 @@
package com.sun.mail.imap;
import com.sun.mail.iap.ByteArray;
import com.sun.mail.iap.ConnectionException;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.imap.protocol.BODY;
import com.sun.mail.imap.protocol.IMAPProtocol;
import com.sun.mail.util.FolderClosedIOException;
import com.sun.mail.util.MessageRemovedIOException;
import java.io.IOException;
import java.io.InputStream;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.FolderClosedException;
import javax.mail.MessagingException;
public class IMAPInputStream extends InputStream {
private IMAPMessage msg;
private String section;
private int pos;
private int blksize;
private int max;
private byte[] buf;
private int bufcount;
private int bufpos;
private boolean lastBuffer;
private boolean peek;
private ByteArray readbuf;
private static final int slop = 64;
public IMAPInputStream(IMAPMessage msg, String section, int max, boolean peek) {
this.msg = msg;
this.section = section;
this.max = max;
this.peek = peek;
this.pos = 0;
this.blksize = msg.getFetchBlockSize();
}
private void forceCheckExpunged() throws MessageRemovedIOException, FolderClosedIOException {
synchronized (this.msg.getMessageCacheLock()) {
try {
this.msg.getProtocol().noop();
} catch (ConnectionException cex) {
throw new FolderClosedIOException(this.msg.getFolder(),
cex.getMessage());
} catch (FolderClosedException fex) {
throw new FolderClosedIOException(fex.getFolder(),
fex.getMessage());
} catch (ProtocolException e) {}
}
if (this.msg.isExpunged())
throw new MessageRemovedIOException();
}
private void fill() throws IOException {
ByteArray ba;
int cnt;
if (this.lastBuffer || (this.max != -1 && this.pos >= this.max)) {
if (this.pos == 0)
checkSeen();
this.readbuf = null;
return;
}
BODY b = null;
if (this.readbuf == null)
this.readbuf = new ByteArray(this.blksize + 64);
synchronized (this.msg.getMessageCacheLock()) {
try {
IMAPProtocol p = this.msg.getProtocol();
if (this.msg.isExpunged())
throw new MessageRemovedIOException("No content for expunged message");
int seqnum = this.msg.getSequenceNumber();
cnt = this.blksize;
if (this.max != -1 && this.pos + this.blksize > this.max)
cnt = this.max - this.pos;
if (this.peek) {
b = p.peekBody(seqnum, this.section, this.pos, cnt, this.readbuf);
} else {
b = p.fetchBody(seqnum, this.section, this.pos, cnt, this.readbuf);
}
} catch (ProtocolException pex) {
forceCheckExpunged();
throw new IOException(pex.getMessage());
} catch (FolderClosedException fex) {
throw new FolderClosedIOException(fex.getFolder(),
fex.getMessage());
}
if (b == null || (ba = b.getByteArray()) == null) {
forceCheckExpunged();
throw new IOException("No content");
}
}
if (this.pos == 0)
checkSeen();
this.buf = ba.getBytes();
this.bufpos = ba.getStart();
int n = ba.getCount();
this.lastBuffer = (n < cnt);
this.bufcount = this.bufpos + n;
this.pos += n;
}
public synchronized int read() throws IOException {
if (this.bufpos >= this.bufcount) {
fill();
if (this.bufpos >= this.bufcount)
return -1;
}
return this.buf[this.bufpos++] & 0xFF;
}
public synchronized int read(byte[] b, int off, int len) throws IOException {
int avail = this.bufcount - this.bufpos;
if (avail <= 0) {
fill();
avail = this.bufcount - this.bufpos;
if (avail <= 0)
return -1;
}
int cnt = (avail < len) ? avail : len;
System.arraycopy(this.buf, this.bufpos, b, off, cnt);
this.bufpos += cnt;
return cnt;
}
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
public synchronized int available() throws IOException {
return this.bufcount - this.bufpos;
}
private void checkSeen() {
if (this.peek)
return;
try {
Folder f = this.msg.getFolder();
if (f != null && f.getMode() != 1 &&
!this.msg.isSet(Flags.Flag.SEEN))
this.msg.setFlag(Flags.Flag.SEEN, true);
} catch (MessagingException e) {}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,32 @@
package com.sun.mail.imap;
import com.sun.mail.imap.protocol.BODYSTRUCTURE;
import java.util.Vector;
import javax.mail.BodyPart;
import javax.mail.MessagingException;
import javax.mail.MultipartDataSource;
import javax.mail.internet.MimePart;
import javax.mail.internet.MimePartDataSource;
public class IMAPMultipartDataSource extends MimePartDataSource implements MultipartDataSource {
private Vector parts;
protected IMAPMultipartDataSource(MimePart part, BODYSTRUCTURE[] bs, String sectionId, IMAPMessage msg) {
super(part);
this.parts = new Vector(bs.length);
for (int i = 0; i < bs.length; i++)
this.parts.addElement(new IMAPBodyPart(bs[i], (sectionId == null) ?
Integer.toString(i + 1) : (sectionId + "." +
Integer.toString(i + 1)), msg));
}
public int getCount() {
return this.parts.size();
}
public BodyPart getBodyPart(int index) throws MessagingException {
return this.parts.elementAt(index);
}
}

View file

@ -0,0 +1,64 @@
package com.sun.mail.imap;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.imap.protocol.BODYSTRUCTURE;
import com.sun.mail.imap.protocol.ENVELOPE;
import com.sun.mail.imap.protocol.IMAPProtocol;
import javax.mail.Flags;
import javax.mail.FolderClosedException;
import javax.mail.MessageRemovedException;
import javax.mail.MessagingException;
import javax.mail.MethodNotSupportedException;
public class IMAPNestedMessage extends IMAPMessage {
private IMAPMessage msg;
IMAPNestedMessage(IMAPMessage m, BODYSTRUCTURE b, ENVELOPE e, String sid) {
super(m._getSession());
this.msg = m;
this.bs = b;
this.envelope = e;
this.sectionId = sid;
setPeek(m.getPeek());
}
protected IMAPProtocol getProtocol() throws ProtocolException, FolderClosedException {
return this.msg.getProtocol();
}
protected boolean isREV1() throws FolderClosedException {
return this.msg.isREV1();
}
protected Object getMessageCacheLock() {
return this.msg.getMessageCacheLock();
}
protected int getSequenceNumber() {
return this.msg.getSequenceNumber();
}
protected void checkExpunged() throws MessageRemovedException {
this.msg.checkExpunged();
}
public boolean isExpunged() {
return this.msg.isExpunged();
}
protected int getFetchBlockSize() {
return this.msg.getFetchBlockSize();
}
protected boolean ignoreBodyStructureSize() {
return this.msg.ignoreBodyStructureSize();
}
public int getSize() throws MessagingException {
return this.bs.size;
}
public synchronized void setFlags(Flags flag, boolean set) throws MessagingException {
throw new MethodNotSupportedException("Cannot set flags on this nested message");
}
}

View file

@ -0,0 +1,10 @@
package com.sun.mail.imap;
import javax.mail.Session;
import javax.mail.URLName;
public class IMAPSSLStore extends IMAPStore {
public IMAPSSLStore(Session session, URLName url) {
super(session, url, "imaps", true);
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,207 @@
package com.sun.mail.imap;
import com.sun.mail.util.MailLogger;
import java.io.IOException;
import java.io.InterruptedIOException;
import java.net.Socket;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Queue;
import java.util.Set;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.Executor;
import java.util.logging.Level;
import javax.mail.Folder;
import javax.mail.MessagingException;
import javax.mail.Session;
public class IdleManager {
private Executor es;
private Selector selector;
private MailLogger logger;
private volatile boolean die = false;
private Queue<IMAPFolder> toWatch = new ConcurrentLinkedQueue<IMAPFolder>();
private Queue<IMAPFolder> toAbort = new ConcurrentLinkedQueue<IMAPFolder>();
public IdleManager(Session session, Executor es) throws IOException {
this.es = es;
this.logger = new MailLogger(getClass(), "DEBUG IMAP", session);
this.selector = Selector.open();
es.execute(new Runnable() {
public void run() {
IdleManager.this.logger.fine("IdleManager select starting");
try {
IdleManager.this.select();
} finally {
IdleManager.this.logger.fine("IdleManager select terminating");
}
}
});
}
public synchronized void watch(Folder folder) throws MessagingException {
if (!(folder instanceof IMAPFolder))
throw new MessagingException("Can only watch IMAP folders");
IMAPFolder ifolder = (IMAPFolder)folder;
SocketChannel sc = ifolder.getChannel();
if (sc == null)
throw new MessagingException("Folder is not using SocketChannels");
this.logger.log(Level.FINEST, "IdleManager watching {0}", ifolder);
while (!ifolder.startIdle(this));
this.toWatch.add(ifolder);
this.selector.wakeup();
}
void requestAbort(IMAPFolder folder) {
this.toAbort.add(folder);
this.selector.wakeup();
}
private void select() {
this.die = false;
try {
while (true) {
try {
if (!this.die) {
watchAll();
this.logger.finest("IdleManager waiting...");
int ns = this.selector.select();
if (this.logger.isLoggable(Level.FINEST))
this.logger.log(Level.FINEST, "IdleManager selected {0} channels",
Integer.valueOf(ns));
if (!this.die && !Thread.currentThread().isInterrupted()) {
while (processKeys() && this.selector.selectNow() > 0);
continue;
}
}
} catch (InterruptedIOException ex) {
this.logger.log(Level.FINE, "IdleManager interrupted", (Throwable)ex);
} catch (IOException ex) {
this.logger.log(Level.FINE, "IdleManager got exception", (Throwable)ex);
}
return;
}
} finally {
this.logger.fine("IdleManager unwatchAll");
try {
unwatchAll();
this.selector.close();
} catch (IOException ex2) {
this.logger.log(Level.FINE, "IdleManager unwatch exception", (Throwable)ex2);
}
this.logger.fine("IdleManager exiting");
}
}
private void watchAll() {
IMAPFolder folder;
while ((folder = this.toWatch.poll()) != null) {
this.logger.log(Level.FINEST, "IdleManager adding {0} to selector", folder);
try {
SocketChannel sc = folder.getChannel();
if (sc == null)
continue;
sc.configureBlocking(false);
sc.register(this.selector, 1, folder);
} catch (IOException ex) {
this.logger.log(Level.FINEST, "IdleManager can't register folder", (Throwable)ex);
}
}
}
private boolean processKeys() throws IOException {
boolean more = false;
Set<SelectionKey> selectedKeys = this.selector.selectedKeys();
Iterator<SelectionKey> it = selectedKeys.iterator();
while (it.hasNext()) {
SelectionKey sk = it.next();
it.remove();
sk.cancel();
IMAPFolder iMAPFolder = (IMAPFolder)sk.attachment();
this.logger.log(Level.FINE, "IdleManager selected folder: {0}", iMAPFolder);
SelectableChannel sc = sk.channel();
sc.configureBlocking(true);
try {
if (iMAPFolder.handleIdle(false)) {
this.logger.log(Level.FINE, "IdleManager continue watching folder {0}", iMAPFolder);
this.toWatch.add(iMAPFolder);
more = true;
continue;
}
this.logger.log(Level.FINE, "IdleManager done watching folder {0}", iMAPFolder);
} catch (MessagingException ex) {
this.logger.log(Level.FINE, "IdleManager got exception for folder: " + iMAPFolder, (Throwable)ex);
}
}
IMAPFolder folder;
while ((folder = this.toAbort.poll()) != null) {
this.logger.log(Level.FINE, "IdleManager aborting IDLE for folder: {0}", folder);
SocketChannel sc = folder.getChannel();
if (sc == null)
continue;
SelectionKey sk = sc.keyFor(this.selector);
if (sk != null)
sk.cancel();
sc.configureBlocking(true);
Socket sock = sc.socket();
if (sock != null && sock.getSoTimeout() > 0) {
this.logger.fine("IdleManager requesting DONE with timeout");
this.toWatch.remove(folder);
final IMAPFolder folder0 = folder;
this.es.execute(new Runnable() {
public void run() {
folder0.idleAbortWait();
}
});
continue;
}
folder.idleAbort();
this.toWatch.add(folder);
more = true;
}
return more;
}
private void unwatchAll() {
Set<SelectionKey> keys = this.selector.keys();
for (SelectionKey sk : keys) {
sk.cancel();
IMAPFolder iMAPFolder = (IMAPFolder)sk.attachment();
this.logger.log(Level.FINE, "IdleManager no longer watching folder: {0}", iMAPFolder);
SelectableChannel sc = sk.channel();
try {
sc.configureBlocking(true);
iMAPFolder.idleAbortWait();
} catch (IOException ex) {
this.logger.log(Level.FINE, "IdleManager exception while aborting idle for folder: " + iMAPFolder, (Throwable)ex);
}
}
IMAPFolder folder;
while ((folder = this.toWatch.poll()) != null) {
this.logger.log(Level.FINE, "IdleManager aborting IDLE for unwatched folder: {0}", folder);
SocketChannel sc = folder.getChannel();
if (sc == null)
continue;
try {
sc.configureBlocking(true);
folder.idleAbortWait();
} catch (IOException ex) {
this.logger.log(Level.FINE, "IdleManager exception while aborting idle for folder: " + folder, (Throwable)ex);
}
}
}
public synchronized void stop() {
this.die = true;
this.logger.finest("IdleManager stopping");
this.selector.wakeup();
}
}

View file

@ -0,0 +1,65 @@
package com.sun.mail.imap;
import java.io.IOException;
import java.io.OutputStream;
class LengthCounter extends OutputStream {
private int size = 0;
private byte[] buf;
private int maxsize;
public LengthCounter(int maxsize) {
this.buf = new byte[8192];
this.maxsize = maxsize;
}
public void write(int b) {
int newsize = this.size + 1;
if (this.buf != null)
if (newsize > this.maxsize && this.maxsize >= 0) {
this.buf = null;
} else if (newsize > this.buf.length) {
byte[] newbuf = new byte[Math.max(this.buf.length << 1, newsize)];
System.arraycopy(this.buf, 0, newbuf, 0, this.size);
this.buf = newbuf;
this.buf[this.size] = (byte)b;
} else {
this.buf[this.size] = (byte)b;
}
this.size = newsize;
}
public void write(byte[] b, int off, int len) {
if (off < 0 || off > b.length || len < 0 || off + len > b.length || off + len < 0)
throw new IndexOutOfBoundsException();
if (len == 0)
return;
int newsize = this.size + len;
if (this.buf != null)
if (newsize > this.maxsize && this.maxsize >= 0) {
this.buf = null;
} else if (newsize > this.buf.length) {
byte[] newbuf = new byte[Math.max(this.buf.length << 1, newsize)];
System.arraycopy(this.buf, 0, newbuf, 0, this.size);
this.buf = newbuf;
System.arraycopy(b, off, this.buf, this.size, len);
} else {
System.arraycopy(b, off, this.buf, this.size, len);
}
this.size = newsize;
}
public void write(byte[] b) throws IOException {
write(b, 0, b.length);
}
public int getSize() {
return this.size;
}
public byte[] getBytes() {
return this.buf;
}
}

View file

@ -0,0 +1,262 @@
package com.sun.mail.imap;
import com.sun.mail.util.MailLogger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import javax.mail.Message;
public class MessageCache {
private IMAPMessage[] messages;
private int[] seqnums;
private int size;
private IMAPFolder folder;
private MailLogger logger;
private static final int SLOP = 64;
MessageCache(IMAPFolder folder, IMAPStore store, int size) {
this.folder = folder;
this.logger = folder.logger.getSubLogger("messagecache", "DEBUG IMAP MC",
store.getMessageCacheDebug());
if (this.logger.isLoggable(Level.CONFIG))
this.logger.config("create cache of size " + size);
ensureCapacity(size, 1);
}
MessageCache(int size, boolean debug) {
this.folder = null;
this
.logger = new MailLogger(getClass(), "messagecache", "DEBUG IMAP MC", debug, System.out);
if (this.logger.isLoggable(Level.CONFIG))
this.logger.config("create DEBUG cache of size " + size);
ensureCapacity(size, 1);
}
public int size() {
return this.size;
}
public IMAPMessage getMessage(int msgnum) {
if (msgnum < 1 || msgnum > this.size)
throw new ArrayIndexOutOfBoundsException("message number (" + msgnum + ") out of bounds (" + this.size + ")");
IMAPMessage msg = this.messages[msgnum - 1];
if (msg == null) {
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("create message number " + msgnum);
msg = this.folder.newIMAPMessage(msgnum);
this.messages[msgnum - 1] = msg;
if (seqnumOf(msgnum) <= 0) {
this.logger.fine("it's expunged!");
msg.setExpunged(true);
}
}
return msg;
}
public IMAPMessage getMessageBySeqnum(int seqnum) {
int msgnum = msgnumOf(seqnum);
if (msgnum < 0) {
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("no message seqnum " + seqnum);
return null;
}
return getMessage(msgnum);
}
public void expungeMessage(int seqnum) {
int msgnum = msgnumOf(seqnum);
if (msgnum < 0) {
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("expunge no seqnum " + seqnum);
return;
}
IMAPMessage msg = this.messages[msgnum - 1];
if (msg != null) {
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("expunge existing " + msgnum);
msg.setExpunged(true);
}
if (this.seqnums == null) {
this.logger.fine("create seqnums array");
this.seqnums = new int[this.messages.length];
for (int j = 1; j < msgnum; j++)
this.seqnums[j - 1] = j;
this.seqnums[msgnum - 1] = 0;
for (int i = msgnum + 1; i <= this.seqnums.length; i++)
this.seqnums[i - 1] = i - 1;
} else {
this.seqnums[msgnum - 1] = 0;
for (int i = msgnum + 1; i <= this.seqnums.length; i++) {
assert this.seqnums[i - 1] != 1;
if (this.seqnums[i - 1] > 0)
this.seqnums[i - 1] = this.seqnums[i - 1] - 1;
}
}
}
public IMAPMessage[] removeExpungedMessages() {
this.logger.fine("remove expunged messages");
List<IMAPMessage> mlist = new ArrayList();
int oldnum = 1;
int newnum = 1;
while (oldnum <= this.size) {
if (seqnumOf(oldnum) <= 0) {
IMAPMessage m = getMessage(oldnum);
mlist.add(m);
} else {
if (newnum != oldnum) {
this.messages[newnum - 1] = this.messages[oldnum - 1];
if (this.messages[newnum - 1] != null)
this.messages[newnum - 1].setMessageNumber(newnum);
}
newnum++;
}
oldnum++;
}
this.seqnums = null;
shrink(newnum, oldnum);
IMAPMessage[] rmsgs = new IMAPMessage[mlist.size()];
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("return " + rmsgs.length);
mlist.<IMAPMessage>toArray(rmsgs);
return rmsgs;
}
public IMAPMessage[] removeExpungedMessages(Message[] msgs) {
this.logger.fine("remove expunged messages");
List<IMAPMessage> mlist = new ArrayList();
int[] mnum = new int[msgs.length];
for (int i = 0; i < msgs.length; i++)
mnum[i] = msgs[i].getMessageNumber();
Arrays.sort(mnum);
int oldnum = 1;
int newnum = 1;
int mnumi = 0;
boolean keepSeqnums = false;
while (oldnum <= this.size) {
if (mnumi < mnum.length && oldnum == mnum[mnumi] &&
seqnumOf(oldnum) <= 0) {
IMAPMessage m = getMessage(oldnum);
mlist.add(m);
while (mnumi < mnum.length && mnum[mnumi] <= oldnum)
mnumi++;
} else {
if (newnum != oldnum) {
this.messages[newnum - 1] = this.messages[oldnum - 1];
if (this.messages[newnum - 1] != null)
this.messages[newnum - 1].setMessageNumber(newnum);
if (this.seqnums != null)
this.seqnums[newnum - 1] = this.seqnums[oldnum - 1];
}
if (this.seqnums != null && this.seqnums[newnum - 1] != newnum)
keepSeqnums = true;
newnum++;
}
oldnum++;
}
if (!keepSeqnums)
this.seqnums = null;
shrink(newnum, oldnum);
IMAPMessage[] rmsgs = new IMAPMessage[mlist.size()];
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("return " + rmsgs.length);
mlist.<IMAPMessage>toArray(rmsgs);
return rmsgs;
}
private void shrink(int newend, int oldend) {
this.size = newend - 1;
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("size now " + this.size);
if (this.size == 0) {
this.messages = null;
this.seqnums = null;
} else if (this.size > 64 && this.size < this.messages.length / 2) {
this.logger.fine("reallocate array");
IMAPMessage[] newm = new IMAPMessage[this.size + 64];
System.arraycopy(this.messages, 0, newm, 0, this.size);
this.messages = newm;
if (this.seqnums != null) {
int[] news = new int[this.size + 64];
System.arraycopy(this.seqnums, 0, news, 0, this.size);
this.seqnums = news;
}
} else {
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("clean " + newend + " to " + oldend);
for (int msgnum = newend; msgnum < oldend; msgnum++) {
this.messages[msgnum - 1] = null;
if (this.seqnums != null)
this.seqnums[msgnum - 1] = 0;
}
}
}
public void addMessages(int count, int newSeqNum) {
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("add " + count + " messages");
ensureCapacity(this.size + count, newSeqNum);
}
private void ensureCapacity(int newsize, int newSeqNum) {
if (this.messages == null) {
this.messages = new IMAPMessage[newsize + 64];
} else if (this.messages.length < newsize) {
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("expand capacity to " + newsize);
IMAPMessage[] newm = new IMAPMessage[newsize + 64];
System.arraycopy(this.messages, 0, newm, 0, this.messages.length);
this.messages = newm;
if (this.seqnums != null) {
int[] news = new int[newsize + 64];
System.arraycopy(this.seqnums, 0, news, 0, this.seqnums.length);
for (int i = this.size; i < news.length; i++)
news[i] = newSeqNum++;
this.seqnums = news;
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("message " + newsize + " has sequence number " + this.seqnums[newsize - 1]);
}
} else if (newsize < this.size) {
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("shrink capacity to " + newsize);
for (int msgnum = newsize + 1; msgnum <= this.size; msgnum++) {
this.messages[msgnum - 1] = null;
if (this.seqnums != null)
this.seqnums[msgnum - 1] = -1;
}
}
this.size = newsize;
}
public int seqnumOf(int msgnum) {
if (this.seqnums == null)
return msgnum;
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("msgnum " + msgnum + " is seqnum " + this.seqnums[msgnum - 1]);
return this.seqnums[msgnum - 1];
}
private int msgnumOf(int seqnum) {
if (this.seqnums == null)
return seqnum;
if (seqnum < 1) {
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("bad seqnum " + seqnum);
return -1;
}
for (int msgnum = seqnum; msgnum <= this.size; msgnum++) {
if (this.seqnums[msgnum - 1] == seqnum)
return msgnum;
if (this.seqnums[msgnum - 1] > seqnum)
break;
}
return -1;
}
}

View file

@ -0,0 +1,43 @@
package com.sun.mail.imap;
import com.sun.mail.iap.Literal;
import com.sun.mail.util.CRLFOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.mail.Message;
import javax.mail.MessagingException;
class MessageLiteral implements Literal {
private Message msg;
private int msgSize = -1;
private byte[] buf;
public MessageLiteral(Message msg, int maxsize) throws MessagingException, IOException {
this.msg = msg;
LengthCounter lc = new LengthCounter(maxsize);
OutputStream os = new CRLFOutputStream(lc);
msg.writeTo(os);
os.flush();
this.msgSize = lc.getSize();
this.buf = lc.getBytes();
}
public int size() {
return this.msgSize;
}
public void writeTo(OutputStream os) throws IOException {
try {
if (this.buf != null) {
os.write(this.buf, 0, this.msgSize);
} else {
os = new CRLFOutputStream(os);
this.msg.writeTo(os);
}
} catch (MessagingException mex) {
throw new IOException("MessagingException while appending message: " + mex);
}
}
}

View file

@ -0,0 +1,22 @@
package com.sun.mail.imap;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.event.MessageCountEvent;
public class MessageVanishedEvent extends MessageCountEvent {
private long[] uids;
private static final Message[] noMessages = new Message[0];
private static final long serialVersionUID = 2142028010250024922L;
public MessageVanishedEvent(Folder folder, long[] uids) {
super(folder, 2, true, noMessages);
this.uids = uids;
}
public long[] getUIDs() {
return this.uids;
}
}

View file

@ -0,0 +1,42 @@
package com.sun.mail.imap;
import javax.mail.Message;
import javax.mail.search.SearchTerm;
public final class ModifiedSinceTerm extends SearchTerm {
private long modseq;
private static final long serialVersionUID = 5151457469634727992L;
public ModifiedSinceTerm(long modseq) {
this.modseq = modseq;
}
public long getModSeq() {
return this.modseq;
}
public boolean match(Message msg) {
long m;
try {
if (msg instanceof IMAPMessage) {
m = ((IMAPMessage)msg).getModSeq();
} else {
return false;
}
} catch (Exception e) {
return false;
}
return (m >= this.modseq);
}
public boolean equals(Object obj) {
if (!(obj instanceof ModifiedSinceTerm))
return false;
return (this.modseq == ((ModifiedSinceTerm)obj).modseq);
}
public int hashCode() {
return (int)this.modseq;
}
}

View file

@ -0,0 +1,42 @@
package com.sun.mail.imap;
import java.util.Date;
import javax.mail.Message;
import javax.mail.search.SearchTerm;
public final class OlderTerm extends SearchTerm {
private int interval;
private static final long serialVersionUID = 3951078948727995682L;
public OlderTerm(int interval) {
this.interval = interval;
}
public int getInterval() {
return this.interval;
}
public boolean match(Message msg) {
Date d;
try {
d = msg.getReceivedDate();
} catch (Exception e) {
return false;
}
if (d == null)
return false;
return
(d.getTime() <= System.currentTimeMillis() - (long)this.interval * 1000L);
}
public boolean equals(Object obj) {
if (!(obj instanceof OlderTerm))
return false;
return (this.interval == ((OlderTerm)obj).interval);
}
public int hashCode() {
return this.interval;
}
}

View file

@ -0,0 +1,43 @@
package com.sun.mail.imap;
import com.sun.mail.imap.protocol.UIDSet;
public class ResyncData {
private long uidvalidity = -1L;
private long modseq = -1L;
private UIDSet[] uids = null;
public static final ResyncData CONDSTORE = new ResyncData(-1L, -1L);
public ResyncData(long uidvalidity, long modseq) {
this.uidvalidity = uidvalidity;
this.modseq = modseq;
this.uids = null;
}
public ResyncData(long uidvalidity, long modseq, long uidFirst, long uidLast) {
this.uidvalidity = uidvalidity;
this.modseq = modseq;
this.uids = new UIDSet[] { new UIDSet(uidFirst, uidLast) };
}
public ResyncData(long uidvalidity, long modseq, long[] uids) {
this.uidvalidity = uidvalidity;
this.modseq = modseq;
this.uids = UIDSet.createUIDSets(uids);
}
public long getUIDValidity() {
return this.uidvalidity;
}
public long getModSeq() {
return this.modseq;
}
UIDSet[] getUIDSet() {
return this.uids;
}
}

View file

@ -0,0 +1,148 @@
package com.sun.mail.imap;
import java.util.Vector;
public class Rights implements Cloneable {
private boolean[] rights = new boolean[128];
public Rights() {}
public static final class Right {
private static Right[] cache = new Right[128];
public static final Right LOOKUP = getInstance('l');
public static final Right READ = getInstance('r');
public static final Right KEEP_SEEN = getInstance('s');
public static final Right WRITE = getInstance('w');
public static final Right INSERT = getInstance('i');
public static final Right POST = getInstance('p');
public static final Right CREATE = getInstance('c');
public static final Right DELETE = getInstance('d');
public static final Right ADMINISTER = getInstance('a');
char right;
private Right(char right) {
if (right >= '\u0080')
throw new IllegalArgumentException("Right must be ASCII");
this.right = right;
}
public static synchronized Right getInstance(char right) {
if (right >= '\u0080')
throw new IllegalArgumentException("Right must be ASCII");
if (cache[right] == null)
cache[right] = new Right(right);
return cache[right];
}
public String toString() {
return String.valueOf(this.right);
}
}
public Rights(Rights rights) {
System.arraycopy(rights.rights, 0, this.rights, 0, this.rights.length);
}
public Rights(String rights) {
for (int i = 0; i < rights.length(); i++)
add(Right.getInstance(rights.charAt(i)));
}
public Rights(Right right) {
this.rights[right.right] = true;
}
public void add(Right right) {
this.rights[right.right] = true;
}
public void add(Rights rights) {
for (int i = 0; i < rights.rights.length; i++) {
if (rights.rights[i])
this.rights[i] = true;
}
}
public void remove(Right right) {
this.rights[right.right] = false;
}
public void remove(Rights rights) {
for (int i = 0; i < rights.rights.length; i++) {
if (rights.rights[i])
this.rights[i] = false;
}
}
public boolean contains(Right right) {
return this.rights[right.right];
}
public boolean contains(Rights rights) {
for (int i = 0; i < rights.rights.length; i++) {
if (rights.rights[i] && !this.rights[i])
return false;
}
return true;
}
public boolean equals(Object obj) {
if (!(obj instanceof Rights))
return false;
Rights rights = (Rights)obj;
for (int i = 0; i < rights.rights.length; i++) {
if (rights.rights[i] != this.rights[i])
return false;
}
return true;
}
public int hashCode() {
int hash = 0;
for (int i = 0; i < this.rights.length; i++) {
if (this.rights[i])
hash++;
}
return hash;
}
public Right[] getRights() {
Vector<Right> v = new Vector();
for (int i = 0; i < this.rights.length; i++) {
if (this.rights[i])
v.addElement(Right.getInstance((char)i));
}
Right[] rights = new Right[v.size()];
v.copyInto(rights);
return rights;
}
public Object clone() {
Rights r = null;
try {
r = (Rights)super.clone();
r.rights = new boolean[128];
System.arraycopy(this.rights, 0, r.rights, 0, this.rights.length);
} catch (CloneNotSupportedException e) {}
return r;
}
public String toString() {
StringBuffer sb = new StringBuffer();
for (int i = 0; i < this.rights.length; i++) {
if (this.rights[i])
sb.append((char)i);
}
return sb.toString();
}
}

View file

@ -0,0 +1,29 @@
package com.sun.mail.imap;
public final class SortTerm {
public static final SortTerm ARRIVAL = new SortTerm("ARRIVAL");
public static final SortTerm CC = new SortTerm("CC");
public static final SortTerm DATE = new SortTerm("DATE");
public static final SortTerm FROM = new SortTerm("FROM");
public static final SortTerm REVERSE = new SortTerm("REVERSE");
public static final SortTerm SIZE = new SortTerm("SIZE");
public static final SortTerm SUBJECT = new SortTerm("SUBJECT");
public static final SortTerm TO = new SortTerm("TO");
private String term;
private SortTerm(String term) {
this.term = term;
}
public String toString() {
return this.term;
}
}

View file

@ -0,0 +1,93 @@
package com.sun.mail.imap;
import com.sun.mail.imap.protocol.MessageSet;
import com.sun.mail.imap.protocol.UIDSet;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Vector;
import javax.mail.Message;
public final class Utility {
public static MessageSet[] toMessageSet(Message[] msgs, Condition cond) {
Vector<MessageSet> v = new Vector(1);
for (int i = 0; i < msgs.length; i++) {
IMAPMessage msg = (IMAPMessage)msgs[i];
if (!msg.isExpunged()) {
int current = msg.getSequenceNumber();
if (cond == null || cond.test(msg)) {
MessageSet set = new MessageSet();
set.start = current;
for (; ++i < msgs.length; i++) {
msg = (IMAPMessage)msgs[i];
if (!msg.isExpunged()) {
int next = msg.getSequenceNumber();
if (cond == null || cond.test(msg))
if (next == current + 1) {
current = next;
} else {
i--;
break;
}
}
}
set.end = current;
v.addElement(set);
}
}
}
if (v.isEmpty())
return null;
MessageSet[] sets = new MessageSet[v.size()];
v.copyInto(sets);
return sets;
}
public static MessageSet[] toMessageSetSorted(Message[] msgs, Condition cond) {
msgs = (Message[])msgs.clone();
Arrays.<Message>sort(msgs, new Comparator<Message>() {
public int compare(Message msg1, Message msg2) {
return msg1.getMessageNumber() - msg2.getMessageNumber();
}
});
return toMessageSet(msgs, cond);
}
public static interface Condition {
boolean test(IMAPMessage param1IMAPMessage);
}
public static UIDSet[] toUIDSet(Message[] msgs) {
Vector<UIDSet> v = new Vector(1);
for (int i = 0; i < msgs.length; i++) {
IMAPMessage msg = (IMAPMessage)msgs[i];
if (!msg.isExpunged()) {
long current = msg.getUID();
UIDSet set = new UIDSet();
set.start = current;
for (; ++i < msgs.length; i++) {
msg = (IMAPMessage)msgs[i];
if (!msg.isExpunged()) {
long next = msg.getUID();
if (next == current + 1L) {
current = next;
} else {
i--;
break;
}
}
}
set.end = current;
v.addElement(set);
}
}
if (v.isEmpty())
return null;
UIDSet[] sets = new UIDSet[v.size()];
v.copyInto(sets);
return sets;
}
public static UIDSet[] getResyncUIDSet(ResyncData rd) {
return rd.getUIDSet();
}
}

View file

@ -0,0 +1,42 @@
package com.sun.mail.imap;
import java.util.Date;
import javax.mail.Message;
import javax.mail.search.SearchTerm;
public final class YoungerTerm extends SearchTerm {
private int interval;
private static final long serialVersionUID = 1592714210688163496L;
public YoungerTerm(int interval) {
this.interval = interval;
}
public int getInterval() {
return this.interval;
}
public boolean match(Message msg) {
Date d;
try {
d = msg.getReceivedDate();
} catch (Exception e) {
return false;
}
if (d == null)
return false;
return
(d.getTime() >= System.currentTimeMillis() - (long)this.interval * 1000L);
}
public boolean equals(Object obj) {
if (!(obj instanceof YoungerTerm))
return false;
return (this.interval == ((YoungerTerm)obj).interval);
}
public int hashCode() {
return this.interval;
}
}

View file

@ -0,0 +1,104 @@
package com.sun.mail.imap.protocol;
import java.text.CharacterIterator;
import java.text.StringCharacterIterator;
public class BASE64MailboxDecoder {
public static String decode(String original) {
if (original == null || original.length() == 0)
return original;
boolean changedString = false;
int copyTo = 0;
char[] chars = new char[original.length()];
StringCharacterIterator iter = new StringCharacterIterator(original);
for (char c = iter.first(); c != Character.MAX_VALUE;
c = iter.next()) {
if (c == '&') {
changedString = true;
copyTo = base64decode(chars, copyTo, iter);
} else {
chars[copyTo++] = c;
}
}
if (changedString)
return new String(chars, 0, copyTo);
return original;
}
protected static int base64decode(char[] buffer, int offset, CharacterIterator iter) {
boolean firsttime = true;
int leftover = -1;
while (true) {
byte orig_0 = (byte)iter.next();
if (orig_0 == -1)
break;
if (orig_0 == 45) {
if (firsttime) {
buffer[offset++] = '&';
break;
}
break;
}
firsttime = false;
byte orig_1 = (byte)iter.next();
if (orig_1 == -1 || orig_1 == 45)
break;
byte a = pem_convert_array[orig_0 & 0xFF];
byte b = pem_convert_array[orig_1 & 0xFF];
byte current = (byte)(a << 2 & 0xFC | b >>> 4 & 0x3);
if (leftover != -1) {
buffer[offset++] = (char)(leftover << 8 | current & 0xFF);
leftover = -1;
} else {
leftover = current & 0xFF;
}
byte orig_2 = (byte)iter.next();
if (orig_2 == 61)
continue;
if (orig_2 == -1 || orig_2 == 45)
break;
a = b;
b = pem_convert_array[orig_2 & 0xFF];
current = (byte)(a << 4 & 0xF0 | b >>> 2 & 0xF);
if (leftover != -1) {
buffer[offset++] = (char)(leftover << 8 | current & 0xFF);
leftover = -1;
} else {
leftover = current & 0xFF;
}
byte orig_3 = (byte)iter.next();
if (orig_3 == 61)
continue;
if (orig_3 == -1 || orig_3 == 45)
break;
a = b;
b = pem_convert_array[orig_3 & 0xFF];
current = (byte)(a << 6 & 0xC0 | b & 0x3F);
if (leftover != -1) {
buffer[offset++] = (char)(leftover << 8 | current & 0xFF);
leftover = -1;
continue;
}
leftover = current & 0xFF;
}
return offset;
}
static final char[] pem_array = new char[] {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '+', ',' };
private static final byte[] pem_convert_array = new byte[256];
static {
for (int j = 0; j < 255; j++)
pem_convert_array[j] = -1;
for (int i = 0; i < pem_array.length; i++)
pem_convert_array[pem_array[i]] = (byte)i;
}
}

View file

@ -0,0 +1,116 @@
package com.sun.mail.imap.protocol;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.io.Writer;
public class BASE64MailboxEncoder {
protected byte[] buffer = new byte[4];
protected int bufsize = 0;
protected boolean started = false;
protected Writer out = null;
public static String encode(String original) {
BASE64MailboxEncoder base64stream = null;
char[] origchars = original.toCharArray();
int length = origchars.length;
boolean changedString = false;
CharArrayWriter writer = new CharArrayWriter(length);
for (int index = 0; index < length; index++) {
char current = origchars[index];
if (current >= ' ' && current <= '~') {
if (base64stream != null)
base64stream.flush();
if (current == '&') {
changedString = true;
writer.write(38);
writer.write(45);
} else {
writer.write(current);
}
} else {
if (base64stream == null) {
base64stream = new BASE64MailboxEncoder(writer);
changedString = true;
}
base64stream.write(current);
}
}
if (base64stream != null)
base64stream.flush();
if (changedString)
return writer.toString();
return original;
}
public BASE64MailboxEncoder(Writer what) {
this.out = what;
}
public void write(int c) {
try {
if (!this.started) {
this.started = true;
this.out.write(38);
}
this.buffer[this.bufsize++] = (byte)(c >> 8);
this.buffer[this.bufsize++] = (byte)(c & 0xFF);
if (this.bufsize >= 3) {
encode();
this.bufsize -= 3;
}
} catch (IOException e) {}
}
public void flush() {
try {
if (this.bufsize > 0) {
encode();
this.bufsize = 0;
}
if (this.started) {
this.out.write(45);
this.started = false;
}
} catch (IOException e) {}
}
protected void encode() throws IOException {
if (this.bufsize == 1) {
byte a = this.buffer[0];
byte b = 0;
byte c = 0;
this.out.write(pem_array[a >>> 2 & 0x3F]);
this.out.write(pem_array[(a << 4 & 0x30) + (b >>> 4 & 0xF)]);
} else if (this.bufsize == 2) {
byte a = this.buffer[0];
byte b = this.buffer[1];
byte c = 0;
this.out.write(pem_array[a >>> 2 & 0x3F]);
this.out.write(pem_array[(a << 4 & 0x30) + (b >>> 4 & 0xF)]);
this.out.write(pem_array[(b << 2 & 0x3C) + (c >>> 6 & 0x3)]);
} else {
byte a = this.buffer[0];
byte b = this.buffer[1];
byte c = this.buffer[2];
this.out.write(pem_array[a >>> 2 & 0x3F]);
this.out.write(pem_array[(a << 4 & 0x30) + (b >>> 4 & 0xF)]);
this.out.write(pem_array[(b << 2 & 0x3C) + (c >>> 6 & 0x3)]);
this.out.write(pem_array[c & 0x3F]);
if (this.bufsize == 4)
this.buffer[0] = this.buffer[3];
}
}
private static final char[] pem_array = new char[] {
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x',
'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', '+', ',' };
}

View file

@ -0,0 +1,55 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ByteArray;
import com.sun.mail.iap.ParsingException;
import java.io.ByteArrayInputStream;
public class BODY implements Item {
static final char[] name = new char[] { 'B', 'O', 'D', 'Y' };
private final int msgno;
private final ByteArray data;
private final String section;
private final int origin;
private final boolean isHeader;
public BODY(FetchResponse r) throws ParsingException {
this.msgno = r.getNumber();
r.skipSpaces();
if (r.readByte() != 91)
throw new ParsingException("BODY parse error: missing ``['' at section start");
this.section = r.readString(']');
if (r.readByte() != 93)
throw new ParsingException("BODY parse error: missing ``]'' at section end");
this.isHeader = this.section.regionMatches(true, 0, "HEADER", 0, 6);
if (r.readByte() == 60) {
this.origin = r.readNumber();
r.skip(1);
} else {
this.origin = 0;
}
this.data = r.readByteArray();
}
public ByteArray getByteArray() {
return this.data;
}
public ByteArrayInputStream getByteArrayInputStream() {
if (this.data != null)
return this.data.toByteArrayInputStream();
return null;
}
public boolean isHeader() {
return this.isHeader;
}
public String getSection() {
return this.section;
}
}

View file

@ -0,0 +1,312 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ParsingException;
import com.sun.mail.iap.Response;
import com.sun.mail.util.PropUtil;
import java.util.ArrayList;
import java.util.List;
import javax.mail.internet.ParameterList;
public class BODYSTRUCTURE implements Item {
static final char[] name = new char[] {
'B', 'O', 'D', 'Y', 'S', 'T', 'R', 'U', 'C', 'T',
'U', 'R', 'E' };
public int msgno;
public String type;
public String subtype;
public String encoding;
public int lines = -1;
public int size = -1;
public String disposition;
public String id;
public String description;
public String md5;
public String attachment;
public ParameterList cParams;
public ParameterList dParams;
public String[] language;
public BODYSTRUCTURE[] bodies;
public ENVELOPE envelope;
private static int SINGLE = 1;
private static int MULTI = 2;
private static int NESTED = 3;
private int processedType;
private static final boolean parseDebug = PropUtil.getBooleanSystemProperty("mail.imap.parse.debug", false);
public BODYSTRUCTURE(FetchResponse r) throws ParsingException {
if (parseDebug)
System.out.println("DEBUG IMAP: parsing BODYSTRUCTURE");
this.msgno = r.getNumber();
if (parseDebug)
System.out.println("DEBUG IMAP: msgno " + this.msgno);
r.skipSpaces();
if (r.readByte() != 40)
throw new ParsingException("BODYSTRUCTURE parse error: missing ``('' at start");
if (r.peekByte() == 40) {
if (parseDebug)
System.out.println("DEBUG IMAP: parsing multipart");
this.type = "multipart";
this.processedType = MULTI;
List<BODYSTRUCTURE> v = new ArrayList<BODYSTRUCTURE>(1);
int i = 1;
do {
v.add(new BODYSTRUCTURE(r));
r.skipSpaces();
} while (r.peekByte() == 40);
this.bodies = v.<BODYSTRUCTURE>toArray(new BODYSTRUCTURE[v.size()]);
this.subtype = r.readString();
if (parseDebug)
System.out.println("DEBUG IMAP: subtype " + this.subtype);
if (r.readByte() == 41) {
if (parseDebug)
System.out.println("DEBUG IMAP: parse DONE");
return;
}
if (parseDebug)
System.out.println("DEBUG IMAP: parsing extension data");
this.cParams = parseParameters(r);
if (r.readByte() == 41) {
if (parseDebug)
System.out.println("DEBUG IMAP: body parameters DONE");
return;
}
byte b = r.readByte();
if (b == 40) {
if (parseDebug)
System.out.println("DEBUG IMAP: parse disposition");
this.disposition = r.readString();
if (parseDebug)
System.out.println("DEBUG IMAP: disposition " + this.disposition);
this.dParams = parseParameters(r);
if (r.readByte() != 41)
throw new ParsingException("BODYSTRUCTURE parse error: missing ``)'' at end of disposition in multipart");
if (parseDebug)
System.out.println("DEBUG IMAP: disposition DONE");
} else if (b == 78 || b == 110) {
if (parseDebug)
System.out.println("DEBUG IMAP: disposition NIL");
r.skip(2);
} else {
throw new ParsingException("BODYSTRUCTURE parse error: " + this.type + "/" + this.subtype + ": " + "bad multipart disposition, b " + b);
}
if ((b = r.readByte()) == 41) {
if (parseDebug)
System.out.println("DEBUG IMAP: no body-fld-lang");
return;
}
if (b != 32)
throw new ParsingException("BODYSTRUCTURE parse error: missing space after disposition");
if (r.peekByte() == 40) {
this.language = r.readStringList();
if (parseDebug)
System.out.println("DEBUG IMAP: language len " + this.language.length);
} else {
String l = r.readString();
if (l != null) {
String[] la = { l };
this.language = la;
if (parseDebug)
System.out.println("DEBUG IMAP: language " + l);
}
}
while (r.readByte() == 32)
parseBodyExtension(r);
} else {
if (r.peekByte() == 41)
throw new ParsingException("BODYSTRUCTURE parse error: missing body content");
if (parseDebug)
System.out.println("DEBUG IMAP: single part");
this.type = r.readString();
if (parseDebug)
System.out.println("DEBUG IMAP: type " + this.type);
this.processedType = SINGLE;
this.subtype = r.readString();
if (parseDebug)
System.out.println("DEBUG IMAP: subtype " + this.subtype);
if (this.type == null) {
this.type = "application";
this.subtype = "octet-stream";
}
this.cParams = parseParameters(r);
if (parseDebug)
System.out.println("DEBUG IMAP: cParams " + this.cParams);
this.id = r.readString();
if (parseDebug)
System.out.println("DEBUG IMAP: id " + this.id);
this.description = r.readString();
if (parseDebug)
System.out.println("DEBUG IMAP: description " + this.description);
this.encoding = r.readAtomString();
if (this.encoding != null && this.encoding.equalsIgnoreCase("NIL"))
this.encoding = null;
if (parseDebug)
System.out.println("DEBUG IMAP: encoding " + this.encoding);
this.size = r.readNumber();
if (parseDebug)
System.out.println("DEBUG IMAP: size " + this.size);
if (this.size < 0)
throw new ParsingException("BODYSTRUCTURE parse error: bad ``size'' element");
if (this.type.equalsIgnoreCase("text")) {
this.lines = r.readNumber();
if (parseDebug)
System.out.println("DEBUG IMAP: lines " + this.lines);
if (this.lines < 0)
throw new ParsingException("BODYSTRUCTURE parse error: bad ``lines'' element");
} else if (this.type.equalsIgnoreCase("message") &&
this.subtype.equalsIgnoreCase("rfc822")) {
this.processedType = NESTED;
r.skipSpaces();
if (r.peekByte() == 40) {
this.envelope = new ENVELOPE(r);
if (parseDebug)
System.out.println("DEBUG IMAP: got envelope of nested message");
BODYSTRUCTURE[] bs = { new BODYSTRUCTURE(r) };
this.bodies = bs;
this.lines = r.readNumber();
if (parseDebug)
System.out.println("DEBUG IMAP: lines " + this.lines);
if (this.lines < 0)
throw new ParsingException("BODYSTRUCTURE parse error: bad ``lines'' element");
} else if (parseDebug) {
System.out.println("DEBUG IMAP: missing envelope and body of nested message");
}
} else {
r.skipSpaces();
byte bn = r.peekByte();
if (Character.isDigit((char)bn))
throw new ParsingException("BODYSTRUCTURE parse error: server erroneously included ``lines'' element with type " + this.type + "/" + this.subtype);
}
if (r.peekByte() == 41) {
r.readByte();
if (parseDebug)
System.out.println("DEBUG IMAP: parse DONE");
return;
}
this.md5 = r.readString();
if (r.readByte() == 41) {
if (parseDebug)
System.out.println("DEBUG IMAP: no MD5 DONE");
return;
}
byte b = r.readByte();
if (b == 40) {
this.disposition = r.readString();
if (parseDebug)
System.out.println("DEBUG IMAP: disposition " + this.disposition);
this.dParams = parseParameters(r);
if (parseDebug)
System.out.println("DEBUG IMAP: dParams " + this.dParams);
if (r.readByte() != 41)
throw new ParsingException("BODYSTRUCTURE parse error: missing ``)'' at end of disposition");
} else if (b == 78 || b == 110) {
if (parseDebug)
System.out.println("DEBUG IMAP: disposition NIL");
r.skip(2);
} else {
throw new ParsingException("BODYSTRUCTURE parse error: " + this.type + "/" + this.subtype + ": " + "bad single part disposition, b " + b);
}
if (r.readByte() == 41) {
if (parseDebug)
System.out.println("DEBUG IMAP: disposition DONE");
return;
}
if (r.peekByte() == 40) {
this.language = r.readStringList();
if (parseDebug)
System.out.println("DEBUG IMAP: language len " + this.language.length);
} else {
String l = r.readString();
if (l != null) {
String[] la = { l };
this.language = la;
if (parseDebug)
System.out.println("DEBUG IMAP: language " + l);
}
}
while (r.readByte() == 32)
parseBodyExtension(r);
if (parseDebug)
System.out.println("DEBUG IMAP: all DONE");
}
}
public boolean isMulti() {
return (this.processedType == MULTI);
}
public boolean isSingle() {
return (this.processedType == SINGLE);
}
public boolean isNested() {
return (this.processedType == NESTED);
}
private ParameterList parseParameters(Response r) throws ParsingException {
r.skipSpaces();
ParameterList list = null;
byte b = r.readByte();
if (b == 40) {
list = new ParameterList();
while (true) {
String name = r.readString();
if (parseDebug)
System.out.println("DEBUG IMAP: parameter name " + name);
if (name == null)
throw new ParsingException("BODYSTRUCTURE parse error: " + this.type + "/" + this.subtype + ": " + "null name in parameter list");
String value = r.readString();
if (parseDebug)
System.out.println("DEBUG IMAP: parameter value " + value);
list.set(name, value);
if (r.readByte() == 41) {
list.combineSegments();
return list;
}
}
}
if (b == 78 || b == 110) {
if (parseDebug)
System.out.println("DEBUG IMAP: parameter list NIL");
r.skip(2);
} else {
throw new ParsingException("Parameter list parse error");
}
return list;
}
private void parseBodyExtension(Response r) throws ParsingException {
r.skipSpaces();
byte b = r.peekByte();
if (b == 40) {
r.skip(1);
do {
parseBodyExtension(r);
} while (r.readByte() != 41);
} else if (Character.isDigit((char)b)) {
r.readNumber();
} else {
r.readString();
}
}
}

View file

@ -0,0 +1,115 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ParsingException;
import com.sun.mail.iap.Response;
import com.sun.mail.util.PropUtil;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MailDateFormat;
public class ENVELOPE implements Item {
static final char[] name = new char[] { 'E', 'N', 'V', 'E', 'L', 'O', 'P', 'E' };
public int msgno;
public Date date = null;
public String subject;
public InternetAddress[] from;
public InternetAddress[] sender;
public InternetAddress[] replyTo;
public InternetAddress[] to;
public InternetAddress[] cc;
public InternetAddress[] bcc;
public String inReplyTo;
public String messageId;
private static MailDateFormat mailDateFormat = new MailDateFormat();
private static final boolean parseDebug = PropUtil.getBooleanSystemProperty("mail.imap.parse.debug", false);
public ENVELOPE(FetchResponse r) throws ParsingException {
if (parseDebug)
System.out.println("parse ENVELOPE");
this.msgno = r.getNumber();
r.skipSpaces();
if (r.readByte() != 40)
throw new ParsingException("ENVELOPE parse error");
String s = r.readString();
if (s != null)
try {
this.date = mailDateFormat.parse(s);
} catch (ParseException e) {
} catch (RuntimeException e) {}
if (parseDebug)
System.out.println(" Date: " + this.date);
this.subject = r.readString();
if (parseDebug)
System.out.println(" Subject: " + this.subject);
if (parseDebug)
System.out.println(" From addresses:");
this.from = parseAddressList(r);
if (parseDebug)
System.out.println(" Sender addresses:");
this.sender = parseAddressList(r);
if (parseDebug)
System.out.println(" Reply-To addresses:");
this.replyTo = parseAddressList(r);
if (parseDebug)
System.out.println(" To addresses:");
this.to = parseAddressList(r);
if (parseDebug)
System.out.println(" Cc addresses:");
this.cc = parseAddressList(r);
if (parseDebug)
System.out.println(" Bcc addresses:");
this.bcc = parseAddressList(r);
this.inReplyTo = r.readString();
if (parseDebug)
System.out.println(" In-Reply-To: " + this.inReplyTo);
this.messageId = r.readString();
if (parseDebug)
System.out.println(" Message-ID: " + this.messageId);
if (r.readByte() != 41)
throw new ParsingException("ENVELOPE parse error");
}
private InternetAddress[] parseAddressList(Response r) throws ParsingException {
r.skipSpaces();
byte b = r.readByte();
if (b == 40) {
if (r.peekByte() == 41) {
r.skip(1);
return null;
}
List<InternetAddress> v = new ArrayList<InternetAddress>();
do {
IMAPAddress a = new IMAPAddress(r);
if (parseDebug)
System.out.println(" Address: " + a);
if (a.isEndOfGroup())
continue;
v.add(a);
} while (r.peekByte() != 41);
r.skip(1);
return v.<InternetAddress>toArray(new InternetAddress[v.size()]);
}
if (b == 78 || b == 110) {
r.skip(2);
return null;
}
throw new ParsingException("ADDRESS parse error");
}
}

View file

@ -0,0 +1,59 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ParsingException;
import javax.mail.Flags;
public class FLAGS extends Flags implements Item {
static final char[] name = new char[] { 'F', 'L', 'A', 'G', 'S' };
public int msgno;
private static final long serialVersionUID = 439049847053756670L;
public FLAGS(IMAPResponse r) throws ParsingException {
this.msgno = r.getNumber();
r.skipSpaces();
String[] flags = r.readSimpleList();
if (flags != null)
for (int i = 0; i < flags.length; i++) {
String s = flags[i];
if (s.length() >= 2 && s.charAt(0) == '\\') {
switch (Character.toUpperCase(s.charAt(1))) {
case 'S':
add(Flags.Flag.SEEN);
break;
case 'R':
add(Flags.Flag.RECENT);
break;
case 'D':
if (s.length() >= 3) {
char c = s.charAt(2);
if (c == 'e' || c == 'E') {
add(Flags.Flag.DELETED);
break;
}
if (c == 'r' || c == 'R')
add(Flags.Flag.DRAFT);
} else {
add(s);
}
break;
case 'A':
add(Flags.Flag.ANSWERED);
break;
case 'F':
add(Flags.Flag.FLAGGED);
break;
case '*':
add(Flags.Flag.USER);
break;
default:
add(s);
break;
}
} else {
add(s);
}
}
}
}

View file

@ -0,0 +1,25 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ParsingException;
import javax.mail.FetchProfile;
public abstract class FetchItem {
private String name;
private FetchProfile.Item fetchProfileItem;
public FetchItem(String name, FetchProfile.Item fetchProfileItem) {
this.name = name;
this.fetchProfileItem = fetchProfileItem;
}
public String getName() {
return this.name;
}
public FetchProfile.Item getFetchProfileItem() {
return this.fetchProfileItem;
}
public abstract Object parseItem(FetchResponse paramFetchResponse) throws ParsingException;
}

View file

@ -0,0 +1,215 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ParsingException;
import com.sun.mail.iap.Protocol;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.iap.Response;
import com.sun.mail.util.ASCIIUtility;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class FetchResponse extends IMAPResponse {
private Item[] items;
private Map extensionItems;
private final FetchItem[] fitems;
public FetchResponse(Protocol p) throws IOException, ProtocolException {
super(p);
this.fitems = null;
parse();
}
public FetchResponse(IMAPResponse r) throws IOException, ProtocolException {
this(r, null);
}
public FetchResponse(IMAPResponse r, FetchItem[] fitems) throws IOException, ProtocolException {
super(r);
this.fitems = fitems;
parse();
}
public int getItemCount() {
return this.items.length;
}
public Item getItem(int index) {
return this.items[index];
}
public <T extends Item> T getItem(Class<T> c) {
for (int i = 0; i < this.items.length; i++) {
if (c.isInstance(this.items[i]))
return c.cast(this.items[i]);
}
return null;
}
public static <T extends Item> T getItem(Response[] r, int msgno, Class<T> c) {
if (r == null)
return null;
for (int i = 0; i < r.length; i++) {
if (r[i] != null && r[i] instanceof FetchResponse && ((FetchResponse)r[i])
.getNumber() == msgno) {
FetchResponse f = (FetchResponse)r[i];
for (int j = 0; j < f.items.length; j++) {
if (c.isInstance(f.items[j]))
return c.cast(f.items[j]);
}
}
}
return null;
}
public static <T extends Item> List<T> getItems(Response[] r, int msgno, Class<T> c) {
List<T> items = new ArrayList<T>();
if (r == null)
return items;
for (int i = 0; i < r.length; i++) {
if (r[i] != null && r[i] instanceof FetchResponse && ((FetchResponse)r[i])
.getNumber() == msgno) {
FetchResponse f = (FetchResponse)r[i];
for (int j = 0; j < f.items.length; j++) {
if (c.isInstance(f.items[j]))
items.add(c.cast(f.items[j]));
}
}
}
return items;
}
public Map getExtensionItems() {
if (this.extensionItems == null)
this.extensionItems = new HashMap();
return this.extensionItems;
}
private static final char[] HEADER = new char[] { '.', 'H', 'E', 'A', 'D', 'E', 'R' };
private static final char[] TEXT = new char[] { '.', 'T', 'E', 'X', 'T' };
private void parse() throws ParsingException {
skipSpaces();
if (this.buffer[this.index] != 40)
throw new ParsingException("error in FETCH parsing, missing '(' at index " + this.index);
List<Item> v = new ArrayList<Item>();
Item i = null;
do {
this.index++;
if (this.index >= this.size)
throw new ParsingException("error in FETCH parsing, ran off end of buffer, size " + this.size);
i = parseItem();
if (i != null) {
v.add(i);
} else if (!parseExtensionItem()) {
throw new ParsingException("error in FETCH parsing, unrecognized item at index " + this.index + ", starts with \"" +
next20() + "\"");
}
} while (this.buffer[this.index] != 41);
this.index++;
this.items = v.<Item>toArray(new Item[v.size()]);
}
private String next20() {
if (this.index + 20 > this.size)
return ASCIIUtility.toString(this.buffer, this.index, this.index + this.size);
return ASCIIUtility.toString(this.buffer, this.index, this.index + 20) + "...";
}
private Item parseItem() throws ParsingException {
switch (this.buffer[this.index]) {
case 69:
case 101:
if (match(ENVELOPE.name))
return new ENVELOPE(this);
break;
case 70:
case 102:
if (match(FLAGS.name))
return new FLAGS(this);
break;
case 73:
case 105:
if (match(INTERNALDATE.name))
return new INTERNALDATE(this);
break;
case 66:
case 98:
if (match(BODYSTRUCTURE.name))
return new BODYSTRUCTURE(this);
if (match(BODY.name)) {
if (this.buffer[this.index] == 91)
return new BODY(this);
return new BODYSTRUCTURE(this);
}
break;
case 82:
case 114:
if (match(RFC822SIZE.name))
return new RFC822SIZE(this);
if (match(RFC822DATA.name)) {
boolean isHeader = false;
if (match(HEADER)) {
isHeader = true;
} else if (match(TEXT)) {
}
return new RFC822DATA(this, isHeader);
}
break;
case 85:
case 117:
if (match(UID.name))
return new UID(this);
break;
case 77:
case 109:
if (match(MODSEQ.name))
return new MODSEQ(this);
break;
}
return null;
}
private boolean parseExtensionItem() throws ParsingException {
if (this.fitems == null)
return false;
for (int i = 0; i < this.fitems.length; i++) {
if (match(this.fitems[i].getName())) {
getExtensionItems().put(this.fitems[i].getName(), this.fitems[i]
.parseItem(this));
return true;
}
}
return false;
}
private boolean match(char[] itemName) {
int len = itemName.length;
for (int i = 0, j = this.index; i < len;) {
if (Character.toUpperCase((char)this.buffer[j++]) != itemName[i++])
return false;
}
this.index += len;
return true;
}
private boolean match(String itemName) {
int len = itemName.length();
for (int i = 0, j = this.index; i < len;) {
if (Character.toUpperCase((char)this.buffer[j++]) !=
itemName.charAt(i++))
return false;
}
this.index += len;
return true;
}
}

View file

@ -0,0 +1,53 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.Argument;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.iap.Response;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ID {
private Map<String, String> serverParams = null;
public ID(Response r) throws ProtocolException {
r.skipSpaces();
int c = r.peekByte();
if (c == 78 || c == 110)
return;
if (c != 40)
throw new ProtocolException("Missing '(' at start of ID");
this.serverParams = new HashMap<String, String>();
String[] v = r.readStringList();
if (v != null)
for (int i = 0; i < v.length; i += 2) {
String name = v[i];
if (name == null)
throw new ProtocolException("ID field name null");
if (i + 1 >= v.length)
throw new ProtocolException("ID field without value: " + name);
String value = v[i + 1];
this.serverParams.put(name, value);
}
this.serverParams = Collections.<String, String>unmodifiableMap(this.serverParams);
}
Map<String, String> getServerParams() {
return this.serverParams;
}
static Argument getArgumentList(Map<String, String> clientParams) {
Argument arg = new Argument();
if (clientParams == null) {
arg.writeAtom("NIL");
return arg;
}
Argument list = new Argument();
for (Map.Entry<String, String> e : clientParams.entrySet()) {
list.writeNString(e.getKey());
list.writeNString(e.getValue());
}
arg.writeArgument(list);
return arg;
}
}

View file

@ -0,0 +1,72 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ParsingException;
import com.sun.mail.iap.Response;
import java.util.ArrayList;
import java.util.List;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
class IMAPAddress extends InternetAddress {
private boolean group = false;
private InternetAddress[] grouplist;
private String groupname;
private static final long serialVersionUID = -3835822029483122232L;
IMAPAddress(Response r) throws ParsingException {
r.skipSpaces();
if (r.readByte() != 40)
throw new ParsingException("ADDRESS parse error");
this.encodedPersonal = r.readString();
r.readString();
String mb = r.readString();
String host = r.readString();
r.skipSpaces();
if (r.readByte() != 41)
throw new ParsingException("ADDRESS parse error");
if (host == null) {
this.group = true;
this.groupname = mb;
if (this.groupname == null)
return;
StringBuffer sb = new StringBuffer();
sb.append(this.groupname).append(':');
List<InternetAddress> v = new ArrayList<InternetAddress>();
while (r.peekByte() != 41) {
IMAPAddress a = new IMAPAddress(r);
if (a.isEndOfGroup())
break;
if (v.size() != 0)
sb.append(',');
sb.append(a.toString());
v.add(a);
}
sb.append(';');
this.address = sb.toString();
this.grouplist = v.<InternetAddress>toArray(new IMAPAddress[v.size()]);
} else if (mb == null || mb.length() == 0) {
this.address = host;
} else if (host.length() == 0) {
this.address = mb;
} else {
this.address = mb + "@" + host;
}
}
boolean isEndOfGroup() {
return (this.group && this.groupname == null);
}
public boolean isGroup() {
return this.group;
}
public InternetAddress[] getGroup(boolean strict) throws AddressException {
if (this.grouplist == null)
return null;
return (InternetAddress[])this.grouplist.clone();
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,77 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.Protocol;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.iap.Response;
import com.sun.mail.util.ASCIIUtility;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class IMAPResponse extends Response {
private String key;
private int number;
public IMAPResponse(Protocol c) throws IOException, ProtocolException {
super(c);
init();
}
private void init() throws IOException, ProtocolException {
if (isUnTagged() && !isOK() && !isNO() && !isBAD() && !isBYE()) {
this.key = readAtom();
try {
this.number = Integer.parseInt(this.key);
this.key = readAtom();
} catch (NumberFormatException e) {}
}
}
public IMAPResponse(IMAPResponse r) {
super(r);
this.key = r.key;
this.number = r.number;
}
public IMAPResponse(String r) throws IOException, ProtocolException {
super(r);
init();
}
public String[] readSimpleList() {
skipSpaces();
if (this.buffer[this.index] != 40)
return null;
this.index++;
List<String> v = new ArrayList<String>();
int start;
for (start = this.index; this.buffer[this.index] != 41; this.index++) {
if (this.buffer[this.index] == 32) {
v.add(ASCIIUtility.toString(this.buffer, start, this.index));
start = this.index + 1;
}
}
if (this.index > start)
v.add(ASCIIUtility.toString(this.buffer, start, this.index));
this.index++;
int size = v.size();
if (size > 0)
return v.<String>toArray(new String[size]);
return null;
}
public String getKey() {
return this.key;
}
public boolean keyEquals(String k) {
if (this.key != null && this.key.equalsIgnoreCase(k))
return true;
return false;
}
public int getNumber() {
return this.number;
}
}

View file

@ -0,0 +1,210 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.auth.OAuth2SaslClientFactory;
import com.sun.mail.iap.Argument;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.iap.Response;
import com.sun.mail.util.ASCIIUtility;
import com.sun.mail.util.BASE64DecoderStream;
import com.sun.mail.util.BASE64EncoderStream;
import com.sun.mail.util.MailLogger;
import com.sun.mail.util.PropUtil;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.logging.Level;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.sasl.RealmCallback;
import javax.security.sasl.RealmChoiceCallback;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslException;
public class IMAPSaslAuthenticator implements SaslAuthenticator {
private IMAPProtocol pr;
private String name;
private Properties props;
private MailLogger logger;
private String host;
static {
try {
OAuth2SaslClientFactory.init();
} catch (Throwable e) {}
}
public IMAPSaslAuthenticator(IMAPProtocol pr, String name, Properties props, MailLogger logger, String host) {
this.pr = pr;
this.name = name;
this.props = props;
this.logger = logger;
this.host = host;
}
public boolean authenticate(String[] mechs, final String realm, String authzid, final String u, final String p) throws ProtocolException {
synchronized (this.pr) {
SaslClient sc;
List<Response> v = new ArrayList<Response>();
String tag = null;
Response r = null;
boolean done = false;
if (this.logger.isLoggable(Level.FINE)) {
this.logger.fine("SASL Mechanisms:");
for (int i = 0; i < mechs.length; i++)
this.logger.fine(" " + mechs[i]);
this.logger.fine("");
}
CallbackHandler cbh = new CallbackHandler() {
public void handle(Callback[] callbacks) {
if (IMAPSaslAuthenticator.this.logger.isLoggable(Level.FINE))
IMAPSaslAuthenticator.this.logger.fine("SASL callback length: " + callbacks.length);
for (int i = 0; i < callbacks.length; i++) {
if (IMAPSaslAuthenticator.this.logger.isLoggable(Level.FINE))
IMAPSaslAuthenticator.this.logger.fine("SASL callback " + i + ": " + callbacks[i]);
if (callbacks[i] instanceof NameCallback) {
NameCallback ncb = (NameCallback)callbacks[i];
ncb.setName(u);
} else if (callbacks[i] instanceof PasswordCallback) {
PasswordCallback pcb = (PasswordCallback)callbacks[i];
pcb.setPassword(p.toCharArray());
} else if (callbacks[i] instanceof RealmCallback) {
RealmCallback rcb = (RealmCallback)callbacks[i];
rcb.setText((realm != null) ? realm :
rcb.getDefaultText());
} else if (callbacks[i] instanceof RealmChoiceCallback) {
RealmChoiceCallback rcb = (RealmChoiceCallback)callbacks[i];
if (realm == null) {
rcb.setSelectedIndex(rcb.getDefaultChoice());
} else {
String[] choices = rcb.getChoices();
for (int k = 0; k < choices.length; k++) {
if (choices[k].equals(realm)) {
rcb.setSelectedIndex(k);
break;
}
}
}
}
}
}
};
try {
sc = Sasl.createSaslClient(mechs, authzid, this.name, this.host, (Map<String, ?>)this.props, cbh);
} catch (SaslException sex) {
this.logger.log(Level.FINE, "Failed to create SASL client", (Throwable)sex);
throw new UnsupportedOperationException(sex.getMessage(), sex);
}
if (sc == null) {
this.logger.fine("No SASL support");
throw new UnsupportedOperationException("No SASL support");
}
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("SASL client " + sc.getMechanismName());
try {
Argument args = new Argument();
args.writeAtom(sc.getMechanismName());
if (this.pr.hasCapability("SASL-IR") && sc.hasInitialResponse()) {
String irs;
byte[] ba = sc.evaluateChallenge(new byte[0]);
if (ba.length > 0) {
ba = BASE64EncoderStream.encode(ba);
irs = ASCIIUtility.toString(ba, 0, ba.length);
} else {
irs = "=";
}
args.writeAtom(irs);
}
tag = this.pr.writeCommand("AUTHENTICATE", args);
} catch (Exception ex) {
this.logger.log(Level.FINE, "SASL AUTHENTICATE Exception", (Throwable)ex);
return false;
}
OutputStream os = this.pr.getIMAPOutputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] CRLF = { 13, 10 };
boolean isXGWTRUSTEDAPP = (
sc.getMechanismName().equals("XGWTRUSTEDAPP") &&
PropUtil.getBooleanProperty(this.props, "mail." + this.name + ".sasl.xgwtrustedapphack.enable", true));
while (!done) {
try {
r = this.pr.readResponse();
if (r.isContinuation()) {
byte[] ba = null;
if (!sc.isComplete()) {
ba = r.readByteArray().getNewBytes();
if (ba.length > 0)
ba = BASE64DecoderStream.decode(ba);
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("SASL challenge: " +
ASCIIUtility.toString(ba, 0, ba.length) + " :");
ba = sc.evaluateChallenge(ba);
}
if (ba == null) {
this.logger.fine("SASL no response");
os.write(CRLF);
os.flush();
bos.reset();
continue;
}
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("SASL response: " +
ASCIIUtility.toString(ba, 0, ba.length) + " :");
ba = BASE64EncoderStream.encode(ba);
if (isXGWTRUSTEDAPP)
bos.write(ASCIIUtility.getBytes("XGWTRUSTEDAPP "));
bos.write(ba);
bos.write(CRLF);
os.write(bos.toByteArray());
os.flush();
bos.reset();
continue;
}
if (r.isTagged() && r.getTag().equals(tag)) {
done = true;
continue;
}
if (r.isBYE()) {
done = true;
continue;
}
v.add(r);
} catch (Exception ioex) {
this.logger.log(Level.FINE, "SASL Exception", (Throwable)ioex);
r = Response.byeResponse(ioex);
done = true;
}
}
if (sc.isComplete()) {
String qop = (String)sc.getNegotiatedProperty("javax.security.sasl.qop");
if (qop != null && (qop.equalsIgnoreCase("auth-int") ||
qop.equalsIgnoreCase("auth-conf"))) {
this.logger.fine("SASL Mechanism requires integrity or confidentiality");
return false;
}
}
Response[] responses = v.<Response>toArray(new Response[v.size()]);
this.pr.notifyResponseHandlers(responses);
this.pr.handleResult(r);
this.pr.setCapabilities(r);
if (isXGWTRUSTEDAPP && authzid != null) {
Argument args = new Argument();
args.writeString(authzid);
responses = this.pr.command("LOGIN", args);
this.pr.notifyResponseHandlers(responses);
this.pr.handleResult(responses[responses.length - 1]);
this.pr.setCapabilities(responses[responses.length - 1]);
}
return true;
}
}
}

View file

@ -0,0 +1,64 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ParsingException;
import java.text.FieldPosition;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
import javax.mail.internet.MailDateFormat;
public class INTERNALDATE implements Item {
static final char[] name = new char[] {
'I', 'N', 'T', 'E', 'R', 'N', 'A', 'L', 'D', 'A',
'T', 'E' };
public int msgno;
protected Date date;
private static MailDateFormat mailDateFormat = new MailDateFormat();
public INTERNALDATE(FetchResponse r) throws ParsingException {
this.msgno = r.getNumber();
r.skipSpaces();
String s = r.readString();
if (s == null)
throw new ParsingException("INTERNALDATE is NIL");
try {
this.date = mailDateFormat.parse(s);
} catch (ParseException pex) {
throw new ParsingException("INTERNALDATE parse error");
}
}
public Date getDate() {
return this.date;
}
private static SimpleDateFormat df = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss ", Locale.US);
public static String format(Date d) {
StringBuffer sb = new StringBuffer();
synchronized (df) {
df.format(d, sb, new FieldPosition(0));
}
TimeZone tz = TimeZone.getDefault();
int offset = tz.getOffset(d.getTime());
int rawOffsetInMins = offset / 60 / 1000;
if (rawOffsetInMins < 0) {
sb.append('-');
rawOffsetInMins = -rawOffsetInMins;
} else {
sb.append('+');
}
int offsetInHrs = rawOffsetInMins / 60;
int offsetInMins = rawOffsetInMins % 60;
sb.append(Character.forDigit(offsetInHrs / 10, 10));
sb.append(Character.forDigit(offsetInHrs % 10, 10));
sb.append(Character.forDigit(offsetInMins / 10, 10));
sb.append(Character.forDigit(offsetInMins % 10, 10));
return sb.toString();
}
}

View file

@ -0,0 +1,3 @@
package com.sun.mail.imap.protocol;
public interface Item {}

View file

@ -0,0 +1,55 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ParsingException;
import java.util.ArrayList;
import java.util.List;
public class ListInfo {
public String name = null;
public char separator = '/';
public boolean hasInferiors = true;
public boolean canOpen = true;
public int changeState = 3;
public String[] attrs;
public static final int CHANGED = 1;
public static final int UNCHANGED = 2;
public static final int INDETERMINATE = 3;
public ListInfo(IMAPResponse r) throws ParsingException {
String[] s = r.readSimpleList();
List<String> v = new ArrayList<String>();
if (s != null)
for (int i = 0; i < s.length; i++) {
if (s[i].equalsIgnoreCase("\\Marked")) {
this.changeState = 1;
} else if (s[i].equalsIgnoreCase("\\Unmarked")) {
this.changeState = 2;
} else if (s[i].equalsIgnoreCase("\\Noselect")) {
this.canOpen = false;
} else if (s[i].equalsIgnoreCase("\\Noinferiors")) {
this.hasInferiors = false;
}
v.add(s[i]);
}
this.attrs = v.<String>toArray(new String[v.size()]);
r.skipSpaces();
if (r.readByte() == 34) {
if ((this.separator = (char)r.readByte()) == '\\')
this.separator = (char)r.readByte();
r.skip(1);
} else {
r.skip(2);
}
r.skipSpaces();
this.name = r.readAtomString();
this.name = BASE64MailboxDecoder.decode(this.name);
}
}

View file

@ -0,0 +1,21 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ParsingException;
public class MODSEQ implements Item {
static final char[] name = new char[] { 'M', 'O', 'D', 'S', 'E', 'Q' };
public int seqnum;
public long modseq;
public MODSEQ(FetchResponse r) throws ParsingException {
this.seqnum = r.getNumber();
r.skipSpaces();
if (r.readByte() != 40)
throw new ParsingException("MODSEQ parse error");
this.modseq = r.readLong();
if (r.readByte() != 41)
throw new ParsingException("MODSEQ parse error");
}
}

View file

@ -0,0 +1,89 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ParsingException;
import com.sun.mail.iap.Response;
import java.util.ArrayList;
import java.util.List;
import javax.mail.Flags;
public class MailboxInfo {
public Flags availableFlags = null;
public Flags permanentFlags = null;
public int total = -1;
public int recent = -1;
public int first = -1;
public long uidvalidity = -1L;
public long uidnext = -1L;
public long highestmodseq = -1L;
public int mode;
public List<IMAPResponse> responses;
public MailboxInfo(Response[] r) throws ParsingException {
for (int i = 0; i < r.length; i++) {
if (r[i] != null && r[i] instanceof IMAPResponse) {
IMAPResponse ir = (IMAPResponse)r[i];
if (ir.keyEquals("EXISTS")) {
this.total = ir.getNumber();
r[i] = null;
} else if (ir.keyEquals("RECENT")) {
this.recent = ir.getNumber();
r[i] = null;
} else if (ir.keyEquals("FLAGS")) {
this.availableFlags = new FLAGS(ir);
r[i] = null;
} else if (ir.keyEquals("VANISHED")) {
if (this.responses == null)
this.responses = new ArrayList<IMAPResponse>();
this.responses.add(ir);
r[i] = null;
} else if (ir.keyEquals("FETCH")) {
if (this.responses == null)
this.responses = new ArrayList<IMAPResponse>();
this.responses.add(ir);
r[i] = null;
} else if (ir.isUnTagged() && ir.isOK()) {
ir.skipSpaces();
if (ir.readByte() != 91) {
ir.reset();
} else {
boolean handled = true;
String s = ir.readAtom();
if (s.equalsIgnoreCase("UNSEEN")) {
this.first = ir.readNumber();
} else if (s.equalsIgnoreCase("UIDVALIDITY")) {
this.uidvalidity = ir.readLong();
} else if (s.equalsIgnoreCase("PERMANENTFLAGS")) {
this.permanentFlags = new FLAGS(ir);
} else if (s.equalsIgnoreCase("UIDNEXT")) {
this.uidnext = ir.readLong();
} else if (s.equalsIgnoreCase("HIGHESTMODSEQ")) {
this.highestmodseq = ir.readLong();
} else {
handled = false;
}
if (handled) {
r[i] = null;
} else {
ir.reset();
}
}
}
}
}
if (this.permanentFlags == null)
if (this.availableFlags != null) {
this.permanentFlags = new Flags(this.availableFlags);
} else {
this.permanentFlags = new Flags();
}
}
}

View file

@ -0,0 +1,67 @@
package com.sun.mail.imap.protocol;
import java.util.ArrayList;
import java.util.List;
public class MessageSet {
public int start;
public int end;
public MessageSet() {}
public MessageSet(int start, int end) {
this.start = start;
this.end = end;
}
public int size() {
return this.end - this.start + 1;
}
public static MessageSet[] createMessageSets(int[] msgs) {
List<MessageSet> v = new ArrayList<MessageSet>();
for (int i = 0; i < msgs.length; i++) {
MessageSet ms = new MessageSet();
ms.start = msgs[i];
int j;
for (j = i + 1; j < msgs.length &&
msgs[j] == msgs[j - 1] + 1; j++);
ms.end = msgs[j - 1];
v.add(ms);
i = j - 1;
}
return v.<MessageSet>toArray(new MessageSet[v.size()]);
}
public static String toString(MessageSet[] msgsets) {
if (msgsets == null || msgsets.length == 0)
return null;
int i = 0;
StringBuffer s = new StringBuffer();
int size = msgsets.length;
while (true) {
int start = (msgsets[i]).start;
int end = (msgsets[i]).end;
if (end > start) {
s.append(start).append(':').append(end);
} else {
s.append(start);
}
i++;
if (i >= size)
break;
s.append(',');
}
return s.toString();
}
public static int size(MessageSet[] msgsets) {
int count = 0;
if (msgsets == null)
return 0;
for (int i = 0; i < msgsets.length; i++)
count += msgsets[i].size();
return count;
}
}

View file

@ -0,0 +1,78 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ProtocolException;
import com.sun.mail.iap.Response;
import java.util.ArrayList;
import java.util.List;
public class Namespaces {
public Namespace[] personal;
public Namespace[] otherUsers;
public Namespace[] shared;
public static class Namespace {
public String prefix;
public char delimiter;
public Namespace(Response r) throws ProtocolException {
if (r.readByte() != 40)
throw new ProtocolException("Missing '(' at start of Namespace");
this.prefix = BASE64MailboxDecoder.decode(r.readString());
r.skipSpaces();
if (r.peekByte() == 34) {
r.readByte();
this.delimiter = (char)r.readByte();
if (this.delimiter == '\\')
this.delimiter = (char)r.readByte();
if (r.readByte() != 34)
throw new ProtocolException("Missing '\"' at end of QUOTED_CHAR");
} else {
String s = r.readAtom();
if (s == null)
throw new ProtocolException("Expected NIL, got null");
if (!s.equalsIgnoreCase("NIL"))
throw new ProtocolException("Expected NIL, got " + s);
this.delimiter = '\000';
}
if (r.peekByte() != 41) {
r.skipSpaces();
r.readString();
r.skipSpaces();
r.readStringList();
}
if (r.readByte() != 41)
throw new ProtocolException("Missing ')' at end of Namespace");
}
}
public Namespaces(Response r) throws ProtocolException {
this.personal = getNamespaces(r);
this.otherUsers = getNamespaces(r);
this.shared = getNamespaces(r);
}
private Namespace[] getNamespaces(Response r) throws ProtocolException {
r.skipSpaces();
if (r.peekByte() == 40) {
List<Namespace> v = new ArrayList<Namespace>();
r.readByte();
while (true) {
Namespace ns = new Namespace(r);
v.add(ns);
if (r.peekByte() == 41) {
r.readByte();
return v.<Namespace>toArray(new Namespace[v.size()]);
}
}
}
String s = r.readAtom();
if (s == null)
throw new ProtocolException("Expected NIL, got null");
if (!s.equalsIgnoreCase("NIL"))
throw new ProtocolException("Expected NIL, got " + s);
return null;
}
}

View file

@ -0,0 +1,40 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ByteArray;
import com.sun.mail.iap.ParsingException;
import java.io.ByteArrayInputStream;
public class RFC822DATA implements Item {
static final char[] name = new char[] { 'R', 'F', 'C', '8', '2', '2' };
private final int msgno;
private final ByteArray data;
private final boolean isHeader;
public RFC822DATA(FetchResponse r) throws ParsingException {
this(r, false);
}
public RFC822DATA(FetchResponse r, boolean isHeader) throws ParsingException {
this.isHeader = isHeader;
this.msgno = r.getNumber();
r.skipSpaces();
this.data = r.readByteArray();
}
public ByteArray getByteArray() {
return this.data;
}
public ByteArrayInputStream getByteArrayInputStream() {
if (this.data != null)
return this.data.toByteArrayInputStream();
return null;
}
public boolean isHeader() {
return this.isHeader;
}
}

View file

@ -0,0 +1,19 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ParsingException;
public class RFC822SIZE implements Item {
static final char[] name = new char[] {
'R', 'F', 'C', '8', '2', '2', '.', 'S', 'I', 'Z',
'E' };
public int msgno;
public int size;
public RFC822SIZE(FetchResponse r) throws ParsingException {
this.msgno = r.getNumber();
r.skipSpaces();
this.size = r.readNumber();
}
}

View file

@ -0,0 +1,7 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ProtocolException;
public interface SaslAuthenticator {
boolean authenticate(String[] paramArrayOfString, String paramString1, String paramString2, String paramString3, String paramString4) throws ProtocolException;
}

View file

@ -0,0 +1,351 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.Argument;
import com.sun.mail.imap.ModifiedSinceTerm;
import com.sun.mail.imap.OlderTerm;
import com.sun.mail.imap.YoungerTerm;
import java.io.IOException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.mail.Flags;
import javax.mail.Message;
import javax.mail.search.AddressTerm;
import javax.mail.search.AndTerm;
import javax.mail.search.BodyTerm;
import javax.mail.search.DateTerm;
import javax.mail.search.FlagTerm;
import javax.mail.search.FromStringTerm;
import javax.mail.search.FromTerm;
import javax.mail.search.HeaderTerm;
import javax.mail.search.MessageIDTerm;
import javax.mail.search.NotTerm;
import javax.mail.search.OrTerm;
import javax.mail.search.ReceivedDateTerm;
import javax.mail.search.RecipientStringTerm;
import javax.mail.search.RecipientTerm;
import javax.mail.search.SearchException;
import javax.mail.search.SearchTerm;
import javax.mail.search.SentDateTerm;
import javax.mail.search.SizeTerm;
import javax.mail.search.StringTerm;
import javax.mail.search.SubjectTerm;
public class SearchSequence {
public Argument generateSequence(SearchTerm term, String charset) throws SearchException, IOException {
if (term instanceof AndTerm)
return and((AndTerm)term, charset);
if (term instanceof OrTerm)
return or((OrTerm)term, charset);
if (term instanceof NotTerm)
return not((NotTerm)term, charset);
if (term instanceof HeaderTerm)
return header((HeaderTerm)term, charset);
if (term instanceof FlagTerm)
return flag((FlagTerm)term);
if (term instanceof FromTerm) {
FromTerm fterm = (FromTerm)term;
return from(fterm.getAddress().toString(), charset);
}
if (term instanceof FromStringTerm) {
FromStringTerm fterm = (FromStringTerm)term;
return from(fterm.getPattern(), charset);
}
if (term instanceof RecipientTerm) {
RecipientTerm rterm = (RecipientTerm)term;
return recipient(rterm.getRecipientType(),
rterm.getAddress().toString(), charset);
}
if (term instanceof RecipientStringTerm) {
RecipientStringTerm rterm = (RecipientStringTerm)term;
return recipient(rterm.getRecipientType(),
rterm.getPattern(), charset);
}
if (term instanceof SubjectTerm)
return subject((SubjectTerm)term, charset);
if (term instanceof BodyTerm)
return body((BodyTerm)term, charset);
if (term instanceof SizeTerm)
return size((SizeTerm)term);
if (term instanceof SentDateTerm)
return sentdate((SentDateTerm)term);
if (term instanceof ReceivedDateTerm)
return receiveddate((ReceivedDateTerm)term);
if (term instanceof OlderTerm)
return older((OlderTerm)term);
if (term instanceof YoungerTerm)
return younger((YoungerTerm)term);
if (term instanceof MessageIDTerm)
return messageid((MessageIDTerm)term, charset);
if (term instanceof ModifiedSinceTerm)
return modifiedSince((ModifiedSinceTerm)term);
throw new SearchException("Search too complex");
}
public static boolean isAscii(SearchTerm term) {
if (term instanceof AndTerm)
return isAscii(((AndTerm)term).getTerms());
if (term instanceof OrTerm)
return isAscii(((OrTerm)term).getTerms());
if (term instanceof NotTerm)
return isAscii(((NotTerm)term).getTerm());
if (term instanceof StringTerm)
return isAscii(((StringTerm)term).getPattern());
if (term instanceof AddressTerm)
return isAscii(((AddressTerm)term).getAddress().toString());
return true;
}
public static boolean isAscii(SearchTerm[] terms) {
for (int i = 0; i < terms.length; i++) {
if (!isAscii(terms[i]))
return false;
}
return true;
}
public static boolean isAscii(String s) {
int l = s.length();
for (int i = 0; i < l; i++) {
if (s.charAt(i) > '\u007F')
return false;
}
return true;
}
protected Argument and(AndTerm term, String charset) throws SearchException, IOException {
SearchTerm[] terms = term.getTerms();
Argument result = generateSequence(terms[0], charset);
for (int i = 1; i < terms.length; i++)
result.append(generateSequence(terms[i], charset));
return result;
}
protected Argument or(OrTerm term, String charset) throws SearchException, IOException {
SearchTerm[] terms = term.getTerms();
if (terms.length > 2) {
SearchTerm t = terms[0];
for (int i = 1; i < terms.length; i++)
t = new OrTerm(t, terms[i]);
term = (OrTerm)t;
terms = term.getTerms();
}
Argument result = new Argument();
if (terms.length > 1)
result.writeAtom("OR");
if (terms[0] instanceof AndTerm || terms[0] instanceof FlagTerm) {
result.writeArgument(generateSequence(terms[0], charset));
} else {
result.append(generateSequence(terms[0], charset));
}
if (terms.length > 1)
if (terms[1] instanceof AndTerm || terms[1] instanceof FlagTerm) {
result.writeArgument(generateSequence(terms[1], charset));
} else {
result.append(generateSequence(terms[1], charset));
}
return result;
}
protected Argument not(NotTerm term, String charset) throws SearchException, IOException {
Argument result = new Argument();
result.writeAtom("NOT");
SearchTerm nterm = term.getTerm();
if (nterm instanceof AndTerm || nterm instanceof FlagTerm) {
result.writeArgument(generateSequence(nterm, charset));
} else {
result.append(generateSequence(nterm, charset));
}
return result;
}
protected Argument header(HeaderTerm term, String charset) throws SearchException, IOException {
Argument result = new Argument();
result.writeAtom("HEADER");
result.writeString(term.getHeaderName());
result.writeString(term.getPattern(), charset);
return result;
}
protected Argument messageid(MessageIDTerm term, String charset) throws SearchException, IOException {
Argument result = new Argument();
result.writeAtom("HEADER");
result.writeString("Message-ID");
result.writeString(term.getPattern(), charset);
return result;
}
protected Argument flag(FlagTerm term) throws SearchException {
boolean set = term.getTestSet();
Argument result = new Argument();
Flags flags = term.getFlags();
Flags.Flag[] sf = flags.getSystemFlags();
String[] uf = flags.getUserFlags();
if (sf.length == 0 && uf.length == 0)
throw new SearchException("Invalid FlagTerm");
for (int j = 0; j < sf.length; j++) {
if (sf[j] == Flags.Flag.DELETED) {
result.writeAtom(set ? "DELETED" : "UNDELETED");
} else if (sf[j] == Flags.Flag.ANSWERED) {
result.writeAtom(set ? "ANSWERED" : "UNANSWERED");
} else if (sf[j] == Flags.Flag.DRAFT) {
result.writeAtom(set ? "DRAFT" : "UNDRAFT");
} else if (sf[j] == Flags.Flag.FLAGGED) {
result.writeAtom(set ? "FLAGGED" : "UNFLAGGED");
} else if (sf[j] == Flags.Flag.RECENT) {
result.writeAtom(set ? "RECENT" : "OLD");
} else if (sf[j] == Flags.Flag.SEEN) {
result.writeAtom(set ? "SEEN" : "UNSEEN");
}
}
for (int i = 0; i < uf.length; i++) {
result.writeAtom(set ? "KEYWORD" : "UNKEYWORD");
result.writeAtom(uf[i]);
}
return result;
}
protected Argument from(String address, String charset) throws SearchException, IOException {
Argument result = new Argument();
result.writeAtom("FROM");
result.writeString(address, charset);
return result;
}
protected Argument recipient(Message.RecipientType type, String address, String charset) throws SearchException, IOException {
Argument result = new Argument();
if (type == Message.RecipientType.TO) {
result.writeAtom("TO");
} else if (type == Message.RecipientType.CC) {
result.writeAtom("CC");
} else if (type == Message.RecipientType.BCC) {
result.writeAtom("BCC");
} else {
throw new SearchException("Illegal Recipient type");
}
result.writeString(address, charset);
return result;
}
protected Argument subject(SubjectTerm term, String charset) throws SearchException, IOException {
Argument result = new Argument();
result.writeAtom("SUBJECT");
result.writeString(term.getPattern(), charset);
return result;
}
protected Argument body(BodyTerm term, String charset) throws SearchException, IOException {
Argument result = new Argument();
result.writeAtom("BODY");
result.writeString(term.getPattern(), charset);
return result;
}
protected Argument size(SizeTerm term) throws SearchException {
Argument result = new Argument();
switch (term.getComparison()) {
case 5:
result.writeAtom("LARGER");
break;
case 2:
result.writeAtom("SMALLER");
break;
default:
throw new SearchException("Cannot handle Comparison");
}
result.writeNumber(term.getNumber());
return result;
}
private static String[] monthTable = new String[] {
"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct",
"Nov", "Dec" };
protected Calendar cal = new GregorianCalendar();
protected String toIMAPDate(Date date) {
StringBuffer s = new StringBuffer();
this.cal.setTime(date);
s.append(this.cal.get(5)).append("-");
s.append(monthTable[this.cal.get(2)]).append('-');
s.append(this.cal.get(1));
return s.toString();
}
protected Argument sentdate(DateTerm term) throws SearchException {
Argument result = new Argument();
String date = toIMAPDate(term.getDate());
switch (term.getComparison()) {
case 5:
result.writeAtom("NOT SENTON " + date + " SENTSINCE " + date);
break;
case 3:
result.writeAtom("SENTON " + date);
break;
case 2:
result.writeAtom("SENTBEFORE " + date);
break;
case 6:
result.writeAtom("SENTSINCE " + date);
break;
case 1:
result.writeAtom("OR SENTBEFORE " + date + " SENTON " + date);
break;
case 4:
result.writeAtom("NOT SENTON " + date);
break;
default:
throw new SearchException("Cannot handle Date Comparison");
}
return result;
}
protected Argument receiveddate(DateTerm term) throws SearchException {
Argument result = new Argument();
String date = toIMAPDate(term.getDate());
switch (term.getComparison()) {
case 5:
result.writeAtom("NOT ON " + date + " SINCE " + date);
break;
case 3:
result.writeAtom("ON " + date);
break;
case 2:
result.writeAtom("BEFORE " + date);
break;
case 6:
result.writeAtom("SINCE " + date);
break;
case 1:
result.writeAtom("OR BEFORE " + date + " ON " + date);
break;
case 4:
result.writeAtom("NOT ON " + date);
break;
default:
throw new SearchException("Cannot handle Date Comparison");
}
return result;
}
protected Argument older(OlderTerm term) throws SearchException {
Argument result = new Argument();
result.writeAtom("OLDER");
result.writeNumber(term.getInterval());
return result;
}
protected Argument younger(YoungerTerm term) throws SearchException {
Argument result = new Argument();
result.writeAtom("YOUNGER");
result.writeNumber(term.getInterval());
return result;
}
protected Argument modifiedSince(ModifiedSinceTerm term) throws SearchException {
Argument result = new Argument();
result.writeAtom("MODSEQ");
result.writeNumber(term.getModSeq());
return result;
}
}

View file

@ -0,0 +1,106 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ParsingException;
import com.sun.mail.iap.Response;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public class Status {
public String mbox = null;
public int total = -1;
public int recent = -1;
public long uidnext = -1L;
public long uidvalidity = -1L;
public int unseen = -1;
public long highestmodseq = -1L;
public Map<String, Long> items;
static final String[] standardItems = new String[] { "MESSAGES", "RECENT", "UNSEEN", "UIDNEXT", "UIDVALIDITY" };
public Status(Response r) throws ParsingException {
this.mbox = r.readAtomString();
StringBuffer buffer = new StringBuffer();
boolean onlySpaces = true;
while (r.peekByte() != 40 && r.peekByte() != 0) {
char next = (char)r.readByte();
buffer.append(next);
if (next != ' ')
onlySpaces = false;
}
if (!onlySpaces)
this.mbox = (this.mbox + buffer).trim();
if (r.readByte() != 40)
throw new ParsingException("parse error in STATUS");
do {
String attr = r.readAtom();
if (attr.equalsIgnoreCase("MESSAGES")) {
this.total = r.readNumber();
} else if (attr.equalsIgnoreCase("RECENT")) {
this.recent = r.readNumber();
} else if (attr.equalsIgnoreCase("UIDNEXT")) {
this.uidnext = r.readLong();
} else if (attr.equalsIgnoreCase("UIDVALIDITY")) {
this.uidvalidity = r.readLong();
} else if (attr.equalsIgnoreCase("UNSEEN")) {
this.unseen = r.readNumber();
} else if (attr.equalsIgnoreCase("HIGHESTMODSEQ")) {
this.highestmodseq = r.readLong();
} else {
if (this.items == null)
this.items = new HashMap<String, Long>();
this.items.put(attr.toUpperCase(Locale.ENGLISH),
Long.valueOf(r.readLong()));
}
} while (r.readByte() != 41);
}
public long getItem(String item) {
item = item.toUpperCase(Locale.ENGLISH);
long ret = -1L;
Long v;
if (this.items != null && (v = this.items.get(item)) != null) {
ret = v;
} else if (item.equals("MESSAGES")) {
ret = (long)this.total;
} else if (item.equals("RECENT")) {
ret = (long)this.recent;
} else if (item.equals("UIDNEXT")) {
ret = this.uidnext;
} else if (item.equals("UIDVALIDITY")) {
ret = this.uidvalidity;
} else if (item.equals("UNSEEN")) {
ret = (long)this.unseen;
} else if (item.equals("HIGHESTMODSEQ")) {
ret = this.highestmodseq;
}
return ret;
}
public static void add(Status s1, Status s2) {
if (s2.total != -1)
s1.total = s2.total;
if (s2.recent != -1)
s1.recent = s2.recent;
if (s2.uidnext != -1L)
s1.uidnext = s2.uidnext;
if (s2.uidvalidity != -1L)
s1.uidvalidity = s2.uidvalidity;
if (s2.unseen != -1)
s1.unseen = s2.unseen;
if (s2.highestmodseq != -1L)
s1.highestmodseq = s2.highestmodseq;
if (s1.items == null) {
s1.items = s2.items;
} else if (s2.items != null) {
s1.items.putAll(s2.items);
}
}
}

View file

@ -0,0 +1,17 @@
package com.sun.mail.imap.protocol;
import com.sun.mail.iap.ParsingException;
public class UID implements Item {
static final char[] name = new char[] { 'U', 'I', 'D' };
public int seqnum;
public long uid;
public UID(FetchResponse r) throws ParsingException {
this.seqnum = r.getNumber();
r.skipSpaces();
this.uid = r.readLong();
}
}

View file

@ -0,0 +1,146 @@
package com.sun.mail.imap.protocol;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
public class UIDSet {
public long start;
public long end;
public UIDSet() {}
public UIDSet(long start, long end) {
this.start = start;
this.end = end;
}
public long size() {
return this.end - this.start + 1L;
}
public static UIDSet[] createUIDSets(long[] uids) {
if (uids == null)
return null;
List<UIDSet> v = new ArrayList<UIDSet>();
for (int i = 0; i < uids.length; i++) {
UIDSet ms = new UIDSet();
ms.start = uids[i];
int j;
for (j = i + 1; j < uids.length &&
uids[j] == uids[j - 1] + 1L; j++);
ms.end = uids[j - 1];
v.add(ms);
i = j - 1;
}
UIDSet[] uidset = new UIDSet[v.size()];
return v.<UIDSet>toArray(uidset);
}
public static UIDSet[] parseUIDSets(String uids) {
if (uids == null)
return null;
List<UIDSet> v = new ArrayList<UIDSet>();
StringTokenizer st = new StringTokenizer(uids, ",:", true);
long start = -1L;
UIDSet cur = null;
try {
while (st.hasMoreTokens()) {
String s = st.nextToken();
if (s.equals(",")) {
if (cur != null)
v.add(cur);
cur = null;
continue;
}
if (s.equals(":"))
continue;
long n = Long.parseLong(s);
if (cur != null) {
cur.end = n;
continue;
}
cur = new UIDSet(n, n);
}
} catch (NumberFormatException e) {}
if (cur != null)
v.add(cur);
UIDSet[] uidset = new UIDSet[v.size()];
return v.<UIDSet>toArray(uidset);
}
public static String toString(UIDSet[] uidset) {
if (uidset == null)
return null;
if (uidset.length == 0)
return "";
int i = 0;
StringBuilder s = new StringBuilder();
int size = uidset.length;
while (true) {
long start = (uidset[i]).start;
long end = (uidset[i]).end;
if (end > start) {
s.append(start).append(':').append(end);
} else {
s.append(start);
}
i++;
if (i >= size)
break;
s.append(',');
}
return s.toString();
}
public static long[] toArray(UIDSet[] uidset) {
if (uidset == null)
return null;
long[] uids = new long[(int)size(uidset)];
int i = 0;
for (UIDSet u : uidset) {
for (long n = u.start; n <= u.end; n++)
uids[i++] = n;
}
return uids;
}
public static long[] toArray(UIDSet[] uidset, long uidmax) {
if (uidset == null)
return null;
long[] uids = new long[(int)size(uidset, uidmax)];
int i = 0;
for (UIDSet u : uidset) {
for (long n = u.start; n <= u.end && (
uidmax < 0L || n <= uidmax); n++)
uids[i++] = n;
}
return uids;
}
public static long size(UIDSet[] uidset) {
long count = 0L;
if (uidset != null)
for (UIDSet u : uidset)
count += u.size();
return count;
}
private static long size(UIDSet[] uidset, long uidmax) {
long count = 0L;
if (uidset != null)
for (UIDSet u : uidset) {
if (uidmax < 0L) {
count += u.size();
} else if (u.start <= uidmax) {
if (u.end < uidmax) {
count += u.end - u.start + 1L;
} else {
count += uidmax - u.start + 1L;
}
}
}
return count;
}
}

View file

@ -0,0 +1,44 @@
package com.sun.mail.pop3;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.RandomAccessFile;
class AppendStream extends OutputStream {
private final WritableSharedFile tf;
private RandomAccessFile raf;
private final long start;
private long end;
public AppendStream(WritableSharedFile tf) throws IOException {
this.tf = tf;
this.raf = tf.getWritableFile();
this.start = this.raf.length();
this.raf.seek(this.start);
}
public void write(int b) throws IOException {
this.raf.write(b);
}
public void write(byte[] b) throws IOException {
this.raf.write(b);
}
public void write(byte[] b, int off, int len) throws IOException {
this.raf.write(b, off, len);
}
public synchronized void close() throws IOException {
this.end = this.tf.updateLength();
this.raf = null;
}
public synchronized InputStream getInputStream() throws IOException {
return this.tf.newStream(this.start, this.end);
}
}

View file

@ -0,0 +1,100 @@
package com.sun.mail.pop3;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.MethodNotSupportedException;
public class DefaultFolder extends Folder {
DefaultFolder(POP3Store store) {
super(store);
}
public String getName() {
return "";
}
public String getFullName() {
return "";
}
public Folder getParent() {
return null;
}
public boolean exists() {
return true;
}
public Folder[] list(String pattern) throws MessagingException {
Folder[] f = { getInbox() };
return f;
}
public char getSeparator() {
return '/';
}
public int getType() {
return 2;
}
public boolean create(int type) throws MessagingException {
return false;
}
public boolean hasNewMessages() throws MessagingException {
return false;
}
public Folder getFolder(String name) throws MessagingException {
if (!name.equalsIgnoreCase("INBOX"))
throw new MessagingException("only INBOX supported");
return getInbox();
}
protected Folder getInbox() throws MessagingException {
return getStore().getFolder("INBOX");
}
public boolean delete(boolean recurse) throws MessagingException {
throw new MethodNotSupportedException("delete");
}
public boolean renameTo(Folder f) throws MessagingException {
throw new MethodNotSupportedException("renameTo");
}
public void open(int mode) throws MessagingException {
throw new MethodNotSupportedException("open");
}
public void close(boolean expunge) throws MessagingException {
throw new MethodNotSupportedException("close");
}
public boolean isOpen() {
return false;
}
public Flags getPermanentFlags() {
return new Flags();
}
public int getMessageCount() throws MessagingException {
return 0;
}
public Message getMessage(int msgno) throws MessagingException {
throw new MethodNotSupportedException("getMessage");
}
public void appendMessages(Message[] msgs) throws MessagingException {
throw new MethodNotSupportedException("Append not supported");
}
public Message[] expunge() throws MessagingException {
throw new MethodNotSupportedException("expunge");
}
}

View file

@ -0,0 +1,364 @@
package com.sun.mail.pop3;
import com.sun.mail.util.LineInputStream;
import com.sun.mail.util.MailLogger;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.logging.Level;
import javax.mail.FetchProfile;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.FolderClosedException;
import javax.mail.FolderNotFoundException;
import javax.mail.Message;
import javax.mail.MessageRemovedException;
import javax.mail.MessagingException;
import javax.mail.MethodNotSupportedException;
import javax.mail.UIDFolder;
public class POP3Folder extends Folder {
private String name;
private POP3Store store;
private volatile Protocol port;
private int total;
private int size;
private boolean exists = false;
private volatile boolean opened = false;
private Vector message_cache;
private boolean doneUidl = false;
private volatile TempFile fileCache = null;
MailLogger logger;
protected POP3Folder(POP3Store store, String name) {
super(store);
this.name = name;
this.store = store;
if (name.equalsIgnoreCase("INBOX"))
this.exists = true;
this
.logger = new MailLogger(getClass(), "DEBUG POP3", store.getSession());
}
public String getName() {
return this.name;
}
public String getFullName() {
return this.name;
}
public Folder getParent() {
return new DefaultFolder(this.store);
}
public boolean exists() {
return this.exists;
}
public Folder[] list(String pattern) throws MessagingException {
throw new MessagingException("not a directory");
}
public char getSeparator() {
return '\000';
}
public int getType() {
return 1;
}
public boolean create(int type) throws MessagingException {
return false;
}
public boolean hasNewMessages() throws MessagingException {
return false;
}
public Folder getFolder(String name) throws MessagingException {
throw new MessagingException("not a directory");
}
public boolean delete(boolean recurse) throws MessagingException {
throw new MethodNotSupportedException("delete");
}
public boolean renameTo(Folder f) throws MessagingException {
throw new MethodNotSupportedException("renameTo");
}
public synchronized void open(int mode) throws MessagingException {
checkClosed();
if (!this.exists)
throw new FolderNotFoundException(this, "folder is not INBOX");
try {
this.port = this.store.getPort(this);
Status s = this.port.stat();
this.total = s.total;
this.size = s.size;
this.mode = mode;
if (this.store.useFileCache)
try {
this.fileCache = new TempFile(this.store.fileCacheDir);
} catch (IOException ex) {
this.logger.log(Level.FINE, "failed to create file cache", (Throwable)ex);
throw ex;
}
this.opened = true;
} catch (IOException ioex) {
try {
if (this.port != null)
this.port.quit();
} catch (IOException e) {
} finally {
this.port = null;
this.store.closePort(this);
}
throw new MessagingException("Open failed", ioex);
}
this.message_cache = new Vector(this.total);
this.message_cache.setSize(this.total);
this.doneUidl = false;
notifyConnectionListeners(1);
}
public synchronized void close(boolean expunge) throws MessagingException {
checkOpen();
try {
if (this.store.rsetBeforeQuit)
this.port.rset();
if (expunge && this.mode == 2)
for (int j = 0; j < this.message_cache.size(); j++) {
POP3Message m;
if ((m = this.message_cache.elementAt(j)) != null &&
m.isSet(Flags.Flag.DELETED))
try {
this.port.dele(j + 1);
} catch (IOException ioex) {
throw new MessagingException("Exception deleting messages during close", ioex);
}
}
for (int i = 0; i < this.message_cache.size(); i++) {
POP3Message m;
if ((m = this.message_cache.elementAt(i)) != null)
m.invalidate(true);
}
this.port.quit();
} catch (IOException e) {
} finally {
this.port = null;
this.store.closePort(this);
this.message_cache = null;
this.opened = false;
notifyConnectionListeners(3);
if (this.fileCache != null) {
this.fileCache.close();
this.fileCache = null;
}
}
}
public synchronized boolean isOpen() {
if (!this.opened)
return false;
try {
if (!this.port.noop())
throw new IOException("NOOP failed");
} catch (IOException ioex) {
try {
close(false);
} catch (MessagingException e) {
} finally {
return false;
}
}
return true;
}
public Flags getPermanentFlags() {
return new Flags();
}
public synchronized int getMessageCount() throws MessagingException {
if (!this.opened)
return -1;
checkReadable();
return this.total;
}
public synchronized Message getMessage(int msgno) throws MessagingException {
checkOpen();
POP3Message m;
if ((m = this.message_cache.elementAt(msgno - 1)) == null) {
m = createMessage(this, msgno);
this.message_cache.setElementAt(m, msgno - 1);
}
return m;
}
protected POP3Message createMessage(Folder f, int msgno) throws MessagingException {
POP3Message m = null;
Constructor<POP3Message> cons = this.store.messageConstructor;
if (cons != null)
try {
Object[] o = { this, msgno };
m = cons.newInstance(o);
} catch (Exception e) {}
if (m == null)
m = new POP3Message(this, msgno);
return m;
}
public void appendMessages(Message[] msgs) throws MessagingException {
throw new MethodNotSupportedException("Append not supported");
}
public Message[] expunge() throws MessagingException {
throw new MethodNotSupportedException("Expunge not supported");
}
public synchronized void fetch(Message[] msgs, FetchProfile fp) throws MessagingException {
checkReadable();
if (!this.doneUidl && this.store.supportsUidl &&
fp.contains(UIDFolder.FetchProfileItem.UID)) {
String[] uids = new String[this.message_cache.size()];
try {
if (!this.port.uidl(uids))
return;
} catch (EOFException eex) {
close(false);
throw new FolderClosedException(this, eex.toString());
} catch (IOException ex) {
throw new MessagingException("error getting UIDL", ex);
}
for (int i = 0; i < uids.length; i++) {
if (uids[i] != null) {
POP3Message m = (POP3Message)getMessage(i + 1);
m.uid = uids[i];
}
}
this.doneUidl = true;
}
if (fp.contains(FetchProfile.Item.ENVELOPE))
for (int i = 0; i < msgs.length; i++) {
try {
POP3Message msg = (POP3Message)msgs[i];
msg.getHeader("");
msg.getSize();
} catch (MessageRemovedException e) {}
}
}
public synchronized String getUID(Message msg) throws MessagingException {
checkOpen();
if (!(msg instanceof POP3Message))
throw new MessagingException("message is not a POP3Message");
POP3Message m = (POP3Message)msg;
try {
if (!this.store.supportsUidl)
return null;
if (m.uid == "UNKNOWN")
m.uid = this.port.uidl(m.getMessageNumber());
return m.uid;
} catch (EOFException eex) {
close(false);
throw new FolderClosedException(this, eex.toString());
} catch (IOException ex) {
throw new MessagingException("error getting UIDL", ex);
}
}
public synchronized int getSize() throws MessagingException {
checkOpen();
return this.size;
}
public synchronized int[] getSizes() throws MessagingException {
checkOpen();
int[] sizes = new int[this.total];
InputStream is = null;
LineInputStream lis = null;
try {
is = this.port.list();
lis = new LineInputStream(is);
String line;
while ((line = lis.readLine()) != null) {
try {
StringTokenizer st = new StringTokenizer(line);
int msgnum = Integer.parseInt(st.nextToken());
int size = Integer.parseInt(st.nextToken());
if (msgnum > 0 && msgnum <= this.total)
sizes[msgnum - 1] = size;
} catch (RuntimeException e) {}
}
} catch (IOException e) {
} finally {
try {
if (lis != null)
lis.close();
} catch (IOException e) {}
try {
if (is != null)
is.close();
} catch (IOException e) {}
}
return sizes;
}
public synchronized InputStream listCommand() throws MessagingException, IOException {
checkOpen();
return this.port.list();
}
protected void finalize() throws Throwable {
super.finalize();
close(false);
}
private void checkOpen() throws IllegalStateException {
if (!this.opened)
throw new IllegalStateException("Folder is not Open");
}
private void checkClosed() throws IllegalStateException {
if (this.opened)
throw new IllegalStateException("Folder is Open");
}
private void checkReadable() throws IllegalStateException {
if (!this.opened || (this.mode != 1 && this.mode != 2))
throw new IllegalStateException("Folder is not Readable");
}
Protocol getProtocol() throws MessagingException {
Protocol p = this.port;
checkOpen();
return p;
}
protected void notifyMessageChangedListeners(int type, Message m) {
super.notifyMessageChangedListeners(type, m);
}
TempFile getFileCache() {
return this.fileCache;
}
}

View file

@ -0,0 +1,322 @@
package com.sun.mail.pop3;
import com.sun.mail.util.ReadableMime;
import java.io.BufferedOutputStream;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.ref.SoftReference;
import java.util.Enumeration;
import java.util.logging.Level;
import javax.mail.Flags;
import javax.mail.Folder;
import javax.mail.FolderClosedException;
import javax.mail.IllegalWriteException;
import javax.mail.MessageRemovedException;
import javax.mail.MessagingException;
import javax.mail.internet.InternetHeaders;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.SharedInputStream;
public class POP3Message extends MimeMessage implements ReadableMime {
static final String UNKNOWN = "UNKNOWN";
private POP3Folder folder;
private int hdrSize = -1;
private int msgSize = -1;
String uid = "UNKNOWN";
private SoftReference rawData = new SoftReference(null);
public POP3Message(Folder folder, int msgno) throws MessagingException {
super(folder, msgno);
assert folder instanceof POP3Folder;
this.folder = (POP3Folder)folder;
}
public synchronized void setFlags(Flags newFlags, boolean set) throws MessagingException {
Flags oldFlags = (Flags)this.flags.clone();
super.setFlags(newFlags, set);
if (!this.flags.equals(oldFlags))
this.folder.notifyMessageChangedListeners(1, this);
}
public int getSize() throws MessagingException {
try {
synchronized (this) {
if (this.msgSize > 0)
return this.msgSize;
}
if (this.headers == null)
loadHeaders();
synchronized (this) {
if (this.msgSize < 0)
this.msgSize = this.folder.getProtocol().list(this.msgnum) - this.hdrSize;
return this.msgSize;
}
} catch (EOFException eex) {
this.folder.close(false);
throw new FolderClosedException(this.folder, eex.toString());
} catch (IOException ex) {
throw new MessagingException("error getting size", ex);
}
}
private InputStream getRawStream(boolean skipHeader) throws MessagingException {
InputStream rawcontent = null;
try {
synchronized (this) {
rawcontent = this.rawData.get();
if (rawcontent == null) {
TempFile cache = this.folder.getFileCache();
if (cache != null) {
if (this.folder.logger.isLoggable(Level.FINE))
this.folder.logger.fine("caching message #" + this.msgnum + " in temp file");
AppendStream os = cache.getAppendStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
try {
this.folder.getProtocol().retr(this.msgnum, bos);
} finally {
bos.close();
}
rawcontent = os.getInputStream();
} else {
rawcontent = this.folder.getProtocol().retr(this.msgnum, (this.msgSize > 0) ? (this.msgSize + this.hdrSize) : 0);
}
if (rawcontent == null) {
this.expunged = true;
throw new MessageRemovedException("can't retrieve message #" + this.msgnum + " in POP3Message.getContentStream");
}
if (this.headers == null || ((POP3Store)
this.folder.getStore()).forgetTopHeaders) {
this.headers = new InternetHeaders(rawcontent);
this
.hdrSize = (int)((SharedInputStream)rawcontent).getPosition();
} else {
int len;
int offset = 0;
do {
len = 0;
int c1;
while ((c1 = rawcontent.read()) >= 0 &&
c1 != 10) {
if (c1 == 13) {
if (rawcontent.available() > 0) {
rawcontent.mark(1);
if (rawcontent.read() != 10) {
rawcontent.reset();
break;
}
break;
}
break;
}
len++;
}
if (rawcontent.available() == 0)
break;
} while (len != 0);
this
.hdrSize = (int)((SharedInputStream)rawcontent).getPosition();
}
this.msgSize = rawcontent.available();
this.rawData = new SoftReference<InputStream>(rawcontent);
}
}
} catch (EOFException eex) {
this.folder.close(false);
throw new FolderClosedException(this.folder, eex.toString());
} catch (IOException ex) {
throw new MessagingException("error fetching POP3 content", ex);
}
rawcontent = ((SharedInputStream)rawcontent).newStream(skipHeader ? (long)this.hdrSize : 0L, -1L);
return rawcontent;
}
protected synchronized InputStream getContentStream() throws MessagingException {
if (this.contentStream != null)
return ((SharedInputStream)this.contentStream).newStream(0L, -1L);
InputStream cstream = getRawStream(true);
TempFile cache = this.folder.getFileCache();
if (cache != null || ((POP3Store)
this.folder.getStore()).keepMessageContent)
this.contentStream = ((SharedInputStream)cstream).newStream(0L, -1L);
return cstream;
}
public InputStream getMimeStream() throws MessagingException {
return getRawStream(false);
}
public synchronized void invalidate(boolean invalidateHeaders) {
this.content = null;
InputStream rstream = this.rawData.get();
if (rstream != null) {
try {
rstream.close();
} catch (IOException e) {}
this.rawData = new SoftReference(null);
}
if (this.contentStream != null) {
try {
this.contentStream.close();
} catch (IOException e) {}
this.contentStream = null;
}
this.msgSize = -1;
if (invalidateHeaders) {
this.headers = null;
this.hdrSize = -1;
}
}
public InputStream top(int n) throws MessagingException {
try {
synchronized (this) {
return this.folder.getProtocol().top(this.msgnum, n);
}
} catch (EOFException eex) {
this.folder.close(false);
throw new FolderClosedException(this.folder, eex.toString());
} catch (IOException ex) {
throw new MessagingException("error getting size", ex);
}
}
public String[] getHeader(String name) throws MessagingException {
if (this.headers == null)
loadHeaders();
return this.headers.getHeader(name);
}
public String getHeader(String name, String delimiter) throws MessagingException {
if (this.headers == null)
loadHeaders();
return this.headers.getHeader(name, delimiter);
}
public void setHeader(String name, String value) throws MessagingException {
throw new IllegalWriteException("POP3 messages are read-only");
}
public void addHeader(String name, String value) throws MessagingException {
throw new IllegalWriteException("POP3 messages are read-only");
}
public void removeHeader(String name) throws MessagingException {
throw new IllegalWriteException("POP3 messages are read-only");
}
public Enumeration getAllHeaders() throws MessagingException {
if (this.headers == null)
loadHeaders();
return this.headers.getAllHeaders();
}
public Enumeration getMatchingHeaders(String[] names) throws MessagingException {
if (this.headers == null)
loadHeaders();
return this.headers.getMatchingHeaders(names);
}
public Enumeration getNonMatchingHeaders(String[] names) throws MessagingException {
if (this.headers == null)
loadHeaders();
return this.headers.getNonMatchingHeaders(names);
}
public void addHeaderLine(String line) throws MessagingException {
throw new IllegalWriteException("POP3 messages are read-only");
}
public Enumeration getAllHeaderLines() throws MessagingException {
if (this.headers == null)
loadHeaders();
return this.headers.getAllHeaderLines();
}
public Enumeration getMatchingHeaderLines(String[] names) throws MessagingException {
if (this.headers == null)
loadHeaders();
return this.headers.getMatchingHeaderLines(names);
}
public Enumeration getNonMatchingHeaderLines(String[] names) throws MessagingException {
if (this.headers == null)
loadHeaders();
return this.headers.getNonMatchingHeaderLines(names);
}
public void saveChanges() throws MessagingException {
throw new IllegalWriteException("POP3 messages are read-only");
}
public synchronized void writeTo(OutputStream os, String[] ignoreList) throws IOException, MessagingException {
InputStream rawcontent = this.rawData.get();
if (rawcontent == null && ignoreList == null &&
!((POP3Store)this.folder.getStore()).cacheWriteTo) {
if (this.folder.logger.isLoggable(Level.FINE))
this.folder.logger.fine("streaming msg " + this.msgnum);
if (!this.folder.getProtocol().retr(this.msgnum, os)) {
this.expunged = true;
throw new MessageRemovedException("can't retrieve message #" + this.msgnum + " in POP3Message.writeTo");
}
} else if (rawcontent != null && ignoreList == null) {
InputStream in = ((SharedInputStream)rawcontent).newStream(0L, -1L);
try {
byte[] buf = new byte[16384];
int len;
while ((len = in.read(buf)) > 0)
os.write(buf, 0, len);
} finally {
try {
if (in != null)
in.close();
} catch (IOException e) {}
}
} else {
super.writeTo(os, ignoreList);
}
}
private void loadHeaders() throws MessagingException {
assert !Thread.holdsLock(this);
try {
boolean fetchContent = false;
synchronized (this) {
if (this.headers != null)
return;
InputStream hdrs = null;
if (((POP3Store)this.folder.getStore()).disableTop || (
hdrs = this.folder.getProtocol().top(this.msgnum, 0)) == null) {
fetchContent = true;
} else {
try {
this.hdrSize = hdrs.available();
this.headers = new InternetHeaders(hdrs);
} finally {
hdrs.close();
}
}
}
if (fetchContent) {
InputStream cs = null;
try {
cs = getContentStream();
} finally {
if (cs != null)
cs.close();
}
}
} catch (EOFException eex) {
this.folder.close(false);
throw new FolderClosedException(this.folder, eex.toString());
} catch (IOException ex) {
throw new MessagingException("error loading POP3 headers", ex);
}
}
}

View file

@ -0,0 +1,10 @@
package com.sun.mail.pop3;
import javax.mail.Session;
import javax.mail.URLName;
public class POP3SSLStore extends POP3Store {
public POP3SSLStore(Session session, URLName url) {
super(session, url, "pop3s", true);
}
}

View file

@ -0,0 +1,290 @@
package com.sun.mail.pop3;
import com.sun.mail.util.MailConnectException;
import com.sun.mail.util.MailLogger;
import com.sun.mail.util.PropUtil;
import com.sun.mail.util.SocketConnectException;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.util.Collections;
import java.util.Map;
import java.util.logging.Level;
import javax.mail.AuthenticationFailedException;
import javax.mail.Folder;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.Store;
import javax.mail.URLName;
public class POP3Store extends Store {
private String name = "pop3";
private int defaultPort = 110;
private boolean isSSL = false;
private Protocol port = null;
private POP3Folder portOwner = null;
private String host = null;
private int portNum = -1;
private String user = null;
private String passwd = null;
private boolean useStartTLS = false;
private boolean requireStartTLS = false;
private boolean usingSSL = false;
private Map capabilities;
private MailLogger logger;
volatile Constructor messageConstructor = null;
volatile boolean rsetBeforeQuit = false;
volatile boolean disableTop = false;
volatile boolean forgetTopHeaders = false;
volatile boolean supportsUidl = true;
volatile boolean cacheWriteTo = false;
volatile boolean useFileCache = false;
volatile File fileCacheDir = null;
volatile boolean keepMessageContent = false;
public POP3Store(Session session, URLName url) {
this(session, url, "pop3", false);
}
public POP3Store(Session session, URLName url, String name, boolean isSSL) {
super(session, url);
if (url != null)
name = url.getProtocol();
this.name = name;
this.logger = new MailLogger(getClass(), "DEBUG POP3", session);
if (!isSSL)
isSSL = PropUtil.getBooleanSessionProperty(session, "mail." + name + ".ssl.enable", false);
if (isSSL) {
this.defaultPort = 995;
} else {
this.defaultPort = 110;
}
this.isSSL = isSSL;
this.rsetBeforeQuit = getBoolProp("rsetbeforequit");
this.disableTop = getBoolProp("disabletop");
this.forgetTopHeaders = getBoolProp("forgettopheaders");
this.cacheWriteTo = getBoolProp("cachewriteto");
this.useFileCache = getBoolProp("filecache.enable");
String dir = session.getProperty("mail." + name + ".filecache.dir");
if (dir != null && this.logger.isLoggable(Level.CONFIG))
this.logger.config("mail." + name + ".filecache.dir: " + dir);
if (dir != null)
this.fileCacheDir = new File(dir);
this.keepMessageContent = getBoolProp("keepmessagecontent");
this.useStartTLS = getBoolProp("starttls.enable");
this.requireStartTLS = getBoolProp("starttls.required");
String s = session.getProperty("mail." + name + ".message.class");
if (s != null) {
this.logger.log(Level.CONFIG, "message class: {0}", s);
try {
ClassLoader cl = getClass().getClassLoader();
Class<?> messageClass = null;
try {
messageClass = Class.forName(s, false, cl);
} catch (ClassNotFoundException ex1) {
messageClass = Class.forName(s);
}
Class[] c = { Folder.class, int.class };
this.messageConstructor = messageClass.getConstructor(c);
} catch (Exception ex) {
this.logger.log(Level.CONFIG, "failed to load message class", (Throwable)ex);
}
}
}
private final synchronized boolean getBoolProp(String prop) {
prop = "mail." + this.name + "." + prop;
boolean val = PropUtil.getBooleanSessionProperty(this.session, prop, false);
if (this.logger.isLoggable(Level.CONFIG))
this.logger.config(prop + ": " + val);
return val;
}
synchronized Session getSession() {
return this.session;
}
protected synchronized boolean protocolConnect(String host, int portNum, String user, String passwd) throws MessagingException {
if (host == null || passwd == null || user == null)
return false;
if (portNum == -1)
portNum = PropUtil.getIntSessionProperty(this.session, "mail." + this.name + ".port", -1);
if (portNum == -1)
portNum = this.defaultPort;
this.host = host;
this.portNum = portNum;
this.user = user;
this.passwd = passwd;
try {
this.port = getPort(null);
} catch (EOFException eex) {
throw new AuthenticationFailedException(eex.getMessage());
} catch (SocketConnectException scex) {
throw new MailConnectException(scex);
} catch (IOException ioex) {
throw new MessagingException("Connect failed", ioex);
}
return true;
}
public synchronized boolean isConnected() {
if (!super.isConnected())
return false;
try {
if (this.port == null) {
this.port = getPort(null);
} else if (!this.port.noop()) {
throw new IOException("NOOP failed");
}
return true;
} catch (IOException ioex) {
try {
super.close();
} catch (MessagingException e) {
} finally {
return false;
}
while (true);
}
}
synchronized Protocol getPort(POP3Folder owner) throws IOException {
if (this.port != null && this.portOwner == null) {
this.portOwner = owner;
return this.port;
}
Protocol p = new Protocol(this.host, this.portNum, this.logger,
this.session.getProperties(), "mail." + this.name, this.isSSL);
if (this.useStartTLS || this.requireStartTLS)
if (p.hasCapability("STLS")) {
if (p.stls()) {
p.setCapabilities(p.capa());
} else if (this.requireStartTLS) {
this.logger.fine("STLS required but failed");
try {
p.quit();
} catch (IOException e) {
} finally {
throw new EOFException("STLS required but failed");
}
}
} else if (this.requireStartTLS) {
this.logger.fine("STLS required but not supported");
try {
p.quit();
} catch (IOException e) {
} finally {
throw new EOFException("STLS required but not supported");
}
}
this.capabilities = p.getCapabilities();
this.usingSSL = p.isSSL();
if (!this.disableTop && this.capabilities != null &&
!this.capabilities.containsKey("TOP")) {
this.disableTop = true;
this.logger.fine("server doesn't support TOP, disabling it");
}
this.supportsUidl = (this.capabilities == null || this.capabilities.containsKey("UIDL"));
String msg = null;
if ((msg = p.login(this.user, this.passwd)) != null)
try {
p.quit();
} catch (IOException e) {
} finally {
throw new EOFException(msg);
}
if (this.port == null && owner != null) {
this.port = p;
this.portOwner = owner;
}
if (this.portOwner == null)
this.portOwner = owner;
return p;
}
synchronized void closePort(POP3Folder owner) {
if (this.portOwner == owner) {
this.port = null;
this.portOwner = null;
}
}
public synchronized void close() throws MessagingException {
try {
if (this.port != null)
this.port.quit();
} catch (IOException e) {
} finally {
this.port = null;
super.close();
}
}
public Folder getDefaultFolder() throws MessagingException {
checkConnected();
return new DefaultFolder(this);
}
public Folder getFolder(String name) throws MessagingException {
checkConnected();
return new POP3Folder(this, name);
}
public Folder getFolder(URLName url) throws MessagingException {
checkConnected();
return new POP3Folder(this, url.getFile());
}
public Map capabilities() throws MessagingException {
Map<?, ?> c;
synchronized (this) {
c = this.capabilities;
}
if (c != null)
return Collections.unmodifiableMap(c);
return Collections.EMPTY_MAP;
}
public synchronized boolean isSSL() {
return this.usingSSL;
}
protected void finalize() throws Throwable {
super.finalize();
if (this.port != null)
close();
}
private void checkConnected() throws MessagingException {
if (!super.isConnected())
throw new MessagingException("Not connected");
}
}

View file

@ -0,0 +1,624 @@
package com.sun.mail.pop3;
import com.sun.mail.util.LineInputStream;
import com.sun.mail.util.MailLogger;
import com.sun.mail.util.PropUtil;
import com.sun.mail.util.SharedByteArrayOutputStream;
import com.sun.mail.util.SocketFetcher;
import com.sun.mail.util.TraceInputStream;
import com.sun.mail.util.TraceOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.InterruptedIOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.Socket;
import java.net.SocketException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import java.util.StringTokenizer;
import java.util.logging.Level;
class Protocol {
private Socket socket;
private String host;
private Properties props;
private String prefix;
private BufferedReader input;
private PrintWriter output;
private TraceInputStream traceInput;
private TraceOutputStream traceOutput;
private MailLogger logger;
private MailLogger traceLogger;
private String apopChallenge;
private Map capabilities;
private boolean pipelining;
private boolean noauthdebug;
private boolean traceSuspended;
private static final int POP3_PORT = 110;
private static final String CRLF = "\r\n";
private static final int SLOP = 128;
Protocol(String host, int port, MailLogger logger, Properties props, String prefix, boolean isSSL) throws IOException {
Response r;
this.apopChallenge = null;
this.capabilities = null;
this.noauthdebug = true;
this.host = host;
this.props = props;
this.prefix = prefix;
this.logger = logger;
this.traceLogger = logger.getSubLogger("protocol", null);
this.noauthdebug = !PropUtil.getBooleanProperty(props, "mail.debug.auth", false);
boolean enableAPOP = getBoolProp(props, prefix + ".apop.enable");
boolean disableCapa = getBoolProp(props, prefix + ".disablecapa");
try {
if (port == -1)
port = 110;
if (logger.isLoggable(Level.FINE))
logger.fine("connecting to host \"" + host + "\", port " + port + ", isSSL " + isSSL);
this.socket = SocketFetcher.getSocket(host, port, props, prefix, isSSL);
initStreams();
r = simpleCommand(null);
} catch (IOException ioe) {
try {
this.socket.close();
} finally {
throw ioe;
}
}
if (!r.ok)
try {
this.socket.close();
} finally {
throw new IOException("Connect failed");
}
if (enableAPOP) {
int challStart = r.data.indexOf('<');
int challEnd = r.data.indexOf('>', challStart);
if (challStart != -1 && challEnd != -1)
this.apopChallenge = r.data.substring(challStart, challEnd + 1);
logger.log(Level.FINE, "APOP challenge: {0}", this.apopChallenge);
}
if (!disableCapa)
setCapabilities(capa());
this
.pipelining = (hasCapability("PIPELINING") || PropUtil.getBooleanProperty(props, prefix + ".pipelining", false));
if (this.pipelining)
logger.config("PIPELINING enabled");
}
private final synchronized boolean getBoolProp(Properties props, String prop) {
boolean val = PropUtil.getBooleanProperty(props, prop, false);
if (this.logger.isLoggable(Level.CONFIG))
this.logger.config(prop + ": " + val);
return val;
}
private void initStreams() throws IOException {
boolean quote = PropUtil.getBooleanProperty(this.props, "mail.debug.quote", false);
this
.traceInput = new TraceInputStream(this.socket.getInputStream(), this.traceLogger);
this.traceInput.setQuote(quote);
this
.traceOutput = new TraceOutputStream(this.socket.getOutputStream(), this.traceLogger);
this.traceOutput.setQuote(quote);
this.input = new BufferedReader(new InputStreamReader(this.traceInput, "iso-8859-1"));
this.output = new PrintWriter(new BufferedWriter(new OutputStreamWriter(this.traceOutput, "iso-8859-1")));
}
protected void finalize() throws Throwable {
super.finalize();
if (this.socket != null)
quit();
}
synchronized void setCapabilities(InputStream in) {
if (in == null) {
this.capabilities = null;
return;
}
this.capabilities = new HashMap(10);
BufferedReader r = null;
try {
r = new BufferedReader(new InputStreamReader(in, "us-ascii"));
} catch (UnsupportedEncodingException ex) {
assert false;
}
while (true) {
try {
String s;
if ((s = r.readLine()) != null) {
String cap = s;
int i = cap.indexOf(' ');
if (i > 0)
cap = cap.substring(0, i);
this.capabilities.put(cap.toUpperCase(Locale.ENGLISH), s);
continue;
}
} catch (IOException e) {}
try {
in.close();
} catch (IOException e) {}
break;
}
}
synchronized boolean hasCapability(String c) {
return (this.capabilities != null &&
this.capabilities.containsKey(c.toUpperCase(Locale.ENGLISH)));
}
synchronized Map getCapabilities() {
return this.capabilities;
}
synchronized String login(String user, String password) throws IOException {
boolean batch = (this.pipelining && this.socket instanceof javax.net.ssl.SSLSocket);
try {
Response r;
if (this.noauthdebug && isTracing()) {
this.logger.fine("authentication command trace suppressed");
suspendTracing();
}
String dpw = null;
if (this.apopChallenge != null)
dpw = getDigest(password);
if (this.apopChallenge != null && dpw != null) {
r = simpleCommand("APOP " + user + " " + dpw);
} else if (batch) {
String cmd = "USER " + user;
batchCommandStart(cmd);
issueCommand(cmd);
cmd = "PASS " + password;
batchCommandContinue(cmd);
issueCommand(cmd);
r = readResponse();
if (!r.ok) {
String err = (r.data != null) ? r.data : "USER command failed";
readResponse();
batchCommandEnd();
return err;
}
r = readResponse();
batchCommandEnd();
} else {
r = simpleCommand("USER " + user);
if (!r.ok)
return (r.data != null) ? r.data : "USER command failed";
r = simpleCommand("PASS " + password);
}
if (this.noauthdebug && isTracing())
this.logger.log(Level.FINE, "authentication command {0}", r.ok ? "succeeded" : "failed");
if (!r.ok)
return (r.data != null) ? r.data : "login failed";
return null;
} finally {
resumeTracing();
}
}
private String getDigest(String password) {
byte[] digest;
String key = this.apopChallenge + password;
try {
MessageDigest md = MessageDigest.getInstance("MD5");
digest = md.digest(key.getBytes("iso-8859-1"));
} catch (NoSuchAlgorithmException nsae) {
return null;
} catch (UnsupportedEncodingException uee) {
return null;
}
return toHex(digest);
}
private static char[] digits = new char[] {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };
private static String toHex(byte[] bytes) {
char[] result = new char[bytes.length * 2];
for (int index = 0, i = 0; index < bytes.length; index++) {
int temp = bytes[index] & 0xFF;
result[i++] = digits[temp >> 4];
result[i++] = digits[temp & 0xF];
}
return new String(result);
}
synchronized boolean quit() throws IOException {
boolean ok = false;
try {
Response r = simpleCommand("QUIT");
ok = r.ok;
} finally {
try {
this.socket.close();
} finally {
this.socket = null;
this.input = null;
this.output = null;
}
}
return ok;
}
synchronized Status stat() throws IOException {
Response r = simpleCommand("STAT");
Status s = new Status();
if (!r.ok)
throw new IOException("STAT command failed: " + r.data);
if (r.data != null)
try {
StringTokenizer st = new StringTokenizer(r.data);
s.total = Integer.parseInt(st.nextToken());
s.size = Integer.parseInt(st.nextToken());
} catch (RuntimeException e) {}
return s;
}
synchronized int list(int msg) throws IOException {
Response r = simpleCommand("LIST " + msg);
int size = -1;
if (r.ok && r.data != null)
try {
StringTokenizer st = new StringTokenizer(r.data);
st.nextToken();
size = Integer.parseInt(st.nextToken());
} catch (RuntimeException e) {}
return size;
}
synchronized InputStream list() throws IOException {
Response r = multilineCommand("LIST", 128);
return r.bytes;
}
synchronized InputStream retr(int msg, int size) throws IOException {
Response r;
boolean batch = (size == 0 && this.pipelining);
if (batch) {
String cmd = "LIST " + msg;
batchCommandStart(cmd);
issueCommand(cmd);
cmd = "RETR " + msg;
batchCommandContinue(cmd);
issueCommand(cmd);
r = readResponse();
if (r.ok && r.data != null)
try {
StringTokenizer st = new StringTokenizer(r.data);
st.nextToken();
size = Integer.parseInt(st.nextToken());
if (size > 1073741824 || size < 0) {
size = 0;
} else {
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("pipeline message size " + size);
size += 128;
}
} catch (RuntimeException e) {}
r = readResponse();
if (r.ok)
r.bytes = readMultilineResponse(size + 128);
batchCommandEnd();
} else {
String cmd = "RETR " + msg;
multilineCommandStart(cmd);
issueCommand(cmd);
r = readResponse();
if (!r.ok) {
multilineCommandEnd();
return null;
}
if (size <= 0 && r.data != null)
try {
StringTokenizer st = new StringTokenizer(r.data);
String s = st.nextToken();
String octets = st.nextToken();
if (octets.equals("octets")) {
size = Integer.parseInt(s);
if (size > 1073741824 || size < 0) {
size = 0;
} else {
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("guessing message size: " + size);
size += 128;
}
}
} catch (RuntimeException e) {}
r.bytes = readMultilineResponse(size);
multilineCommandEnd();
}
if (r.ok &&
size > 0 && this.logger.isLoggable(Level.FINE))
this.logger.fine("got message size " + r.bytes.available());
return r.bytes;
}
synchronized boolean retr(int msg, OutputStream os) throws IOException {
int b;
String cmd = "RETR " + msg;
multilineCommandStart(cmd);
issueCommand(cmd);
Response r = readResponse();
if (!r.ok) {
multilineCommandEnd();
return false;
}
Throwable terr = null;
int lastb = 10;
try {
while ((b = this.input.read()) >= 0) {
if (lastb == 10 && b == 46) {
b = this.input.read();
if (b == 13) {
b = this.input.read();
break;
}
}
if (terr == null)
try {
os.write(b);
} catch (IOException ex) {
this.logger.log(Level.FINE, "exception while streaming", (Throwable)ex);
terr = ex;
} catch (RuntimeException ex) {
this.logger.log(Level.FINE, "exception while streaming", (Throwable)ex);
terr = ex;
}
lastb = b;
}
} catch (InterruptedIOException iioex) {
try {
this.socket.close();
} catch (IOException e) {}
throw iioex;
}
if (b < 0)
throw new EOFException("EOF on socket");
if (terr != null) {
if (terr instanceof IOException)
throw (IOException)terr;
if (terr instanceof RuntimeException)
throw (RuntimeException)terr;
assert false;
}
multilineCommandEnd();
return true;
}
synchronized InputStream top(int msg, int n) throws IOException {
Response r = multilineCommand("TOP " + msg + " " + n, 0);
return r.bytes;
}
synchronized boolean dele(int msg) throws IOException {
Response r = simpleCommand("DELE " + msg);
return r.ok;
}
synchronized String uidl(int msg) throws IOException {
Response r = simpleCommand("UIDL " + msg);
if (!r.ok)
return null;
int i = r.data.indexOf(' ');
if (i > 0)
return r.data.substring(i + 1);
return null;
}
synchronized boolean uidl(String[] uids) throws IOException {
Response r = multilineCommand("UIDL", 15 * uids.length);
if (!r.ok)
return false;
LineInputStream lis = new LineInputStream(r.bytes);
String line = null;
while ((line = lis.readLine()) != null) {
int i = line.indexOf(' ');
if (i < 1 || i >= line.length())
continue;
int n = Integer.parseInt(line.substring(0, i));
if (n > 0 && n <= uids.length)
uids[n - 1] = line.substring(i + 1);
}
try {
r.bytes.close();
} catch (IOException e) {}
return true;
}
synchronized boolean noop() throws IOException {
Response r = simpleCommand("NOOP");
return r.ok;
}
synchronized boolean rset() throws IOException {
Response r = simpleCommand("RSET");
return r.ok;
}
synchronized boolean stls() throws IOException {
if (this.socket instanceof javax.net.ssl.SSLSocket)
return true;
Response r = simpleCommand("STLS");
if (r.ok)
try {
this.socket = SocketFetcher.startTLS(this.socket, this.host, this.props, this.prefix);
initStreams();
} catch (IOException ioex) {
try {
this.socket.close();
} finally {
this.socket = null;
this.input = null;
this.output = null;
}
IOException sioex = new IOException("Could not convert socket to TLS");
sioex.initCause(ioex);
throw sioex;
}
return r.ok;
}
synchronized boolean isSSL() {
return this.socket instanceof javax.net.ssl.SSLSocket;
}
synchronized InputStream capa() throws IOException {
Response r = multilineCommand("CAPA", 128);
if (!r.ok)
return null;
return r.bytes;
}
private Response simpleCommand(String cmd) throws IOException {
simpleCommandStart(cmd);
issueCommand(cmd);
Response r = readResponse();
simpleCommandEnd();
return r;
}
private void issueCommand(String cmd) throws IOException {
if (this.socket == null)
throw new IOException("Folder is closed");
if (cmd != null) {
cmd = cmd + "\r\n";
this.output.print(cmd);
this.output.flush();
}
}
private Response readResponse() throws IOException {
String line = null;
try {
line = this.input.readLine();
} catch (InterruptedIOException iioex) {
try {
this.socket.close();
} catch (IOException e) {}
throw new EOFException(iioex.getMessage());
} catch (SocketException ex) {
try {
this.socket.close();
} catch (IOException e) {}
throw new EOFException(ex.getMessage());
}
if (line == null) {
this.traceLogger.finest("<EOF>");
throw new EOFException("EOF on socket");
}
Response r = new Response();
if (line.startsWith("+OK")) {
r.ok = true;
} else if (line.startsWith("-ERR")) {
r.ok = false;
} else {
throw new IOException("Unexpected response: " + line);
}
int i;
if ((i = line.indexOf(' ')) >= 0)
r.data = line.substring(i + 1);
return r;
}
private Response multilineCommand(String cmd, int size) throws IOException {
multilineCommandStart(cmd);
issueCommand(cmd);
Response r = readResponse();
if (!r.ok) {
multilineCommandEnd();
return r;
}
r.bytes = readMultilineResponse(size);
multilineCommandEnd();
return r;
}
private InputStream readMultilineResponse(int size) throws IOException {
int b;
SharedByteArrayOutputStream buf = new SharedByteArrayOutputStream(size);
int lastb = 10;
try {
while ((b = this.input.read()) >= 0) {
if (lastb == 10 && b == 46) {
b = this.input.read();
if (b == 13) {
b = this.input.read();
break;
}
}
buf.write(b);
lastb = b;
}
} catch (InterruptedIOException iioex) {
try {
this.socket.close();
} catch (IOException e) {}
throw iioex;
}
if (b < 0)
throw new EOFException("EOF on socket");
return buf.toStream();
}
protected boolean isTracing() {
return this.traceLogger.isLoggable(Level.FINEST);
}
private void suspendTracing() {
if (this.traceLogger.isLoggable(Level.FINEST)) {
this.traceInput.setTrace(false);
this.traceOutput.setTrace(false);
}
}
private void resumeTracing() {
if (this.traceLogger.isLoggable(Level.FINEST)) {
this.traceInput.setTrace(true);
this.traceOutput.setTrace(true);
}
}
private void simpleCommandStart(String command) {}
private void simpleCommandEnd() {}
private void multilineCommandStart(String command) {}
private void multilineCommandEnd() {}
private void batchCommandStart(String command) {}
private void batchCommandContinue(String command) {}
private void batchCommandEnd() {}
}

View file

@ -0,0 +1,11 @@
package com.sun.mail.pop3;
import java.io.InputStream;
class Response {
boolean ok = false;
String data = null;
InputStream bytes = null;
}

View file

@ -0,0 +1,7 @@
package com.sun.mail.pop3;
class Status {
int total = 0;
int size = 0;
}

View file

@ -0,0 +1,32 @@
package com.sun.mail.pop3;
import java.io.File;
import java.io.IOException;
class TempFile {
private File file;
private WritableSharedFile sf;
public TempFile(File dir) throws IOException {
this.file = File.createTempFile("pop3.", ".mbox", dir);
this.file.deleteOnExit();
this.sf = new WritableSharedFile(this.file);
}
public AppendStream getAppendStream() throws IOException {
return this.sf.getAppendStream();
}
public void close() {
try {
this.sf.close();
} catch (IOException e) {}
this.file.delete();
}
protected void finalize() throws Throwable {
super.finalize();
close();
}
}

View file

@ -0,0 +1,46 @@
package com.sun.mail.pop3;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import javax.mail.util.SharedFileInputStream;
class WritableSharedFile extends SharedFileInputStream {
private RandomAccessFile raf;
private AppendStream af;
public WritableSharedFile(File file) throws IOException {
super(file);
try {
this.raf = new RandomAccessFile(file, "rw");
} catch (IOException ex) {
super.close();
}
}
public RandomAccessFile getWritableFile() {
return this.raf;
}
public void close() throws IOException {
try {
super.close();
} finally {
this.raf.close();
}
}
synchronized long updateLength() throws IOException {
this.datalen = this.in.length();
this.af = null;
return this.datalen;
}
public synchronized AppendStream getAppendStream() throws IOException {
if (this.af != null)
throw new IOException("POP3 file cache only supports single threaded access");
this.af = new AppendStream(this);
return this.af;
}
}

View file

@ -0,0 +1,136 @@
package com.sun.mail.smtp;
import com.sun.mail.util.ASCIIUtility;
import com.sun.mail.util.BASE64DecoderStream;
import com.sun.mail.util.BASE64EncoderStream;
import com.sun.mail.util.MailLogger;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.StreamTokenizer;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.logging.Level;
public class DigestMD5 {
private MailLogger logger;
private MessageDigest md5;
private String uri;
private String clientResponse;
public DigestMD5(MailLogger logger) {
this.logger = logger.getLogger(getClass(), "DEBUG DIGEST-MD5");
logger.config("DIGEST-MD5 Loaded");
}
public byte[] authClient(String host, String user, String passwd, String realm, String serverChallenge) throws IOException {
SecureRandom random;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
OutputStream b64os = new BASE64EncoderStream(bos, Integer.MAX_VALUE);
try {
random = new SecureRandom();
this.md5 = MessageDigest.getInstance("MD5");
} catch (NoSuchAlgorithmException ex) {
this.logger.log(Level.FINE, "NoSuchAlgorithmException", (Throwable)ex);
throw new IOException(ex.toString());
}
StringBuffer result = new StringBuffer();
this.uri = "smtp/" + host;
String nc = "00000001";
String qop = "auth";
byte[] bytes = new byte[32];
this.logger.fine("Begin authentication ...");
Hashtable map = tokenize(serverChallenge);
if (realm == null) {
String text = (String)map.get("realm");
realm = (text != null) ? new StringTokenizer(text, ",").nextToken() : host;
}
String nonce = (String)map.get("nonce");
random.nextBytes(bytes);
b64os.write(bytes);
b64os.flush();
String cnonce = bos.toString("iso-8859-1");
bos.reset();
this.md5.update(this.md5.digest(
ASCIIUtility.getBytes(user + ":" + realm + ":" + passwd)));
this.md5.update(ASCIIUtility.getBytes(":" + nonce + ":" + cnonce));
this.clientResponse = toHex(this.md5.digest()) + ":" + nonce + ":" + nc + ":" + cnonce + ":" + qop + ":";
this.md5.update(ASCIIUtility.getBytes("AUTHENTICATE:" + this.uri));
this.md5.update(ASCIIUtility.getBytes(this.clientResponse + toHex(this.md5.digest())));
result.append("username=\"" + user + "\"");
result.append(",realm=\"" + realm + "\"");
result.append(",qop=" + qop);
result.append(",nc=" + nc);
result.append(",nonce=\"" + nonce + "\"");
result.append(",cnonce=\"" + cnonce + "\"");
result.append(",digest-uri=\"" + this.uri + "\"");
result.append(",response=" + toHex(this.md5.digest()));
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("Response => " + result.toString());
b64os.write(ASCIIUtility.getBytes(result.toString()));
b64os.flush();
return bos.toByteArray();
}
public boolean authServer(String serverResponse) throws IOException {
Hashtable map = tokenize(serverResponse);
this.md5.update(ASCIIUtility.getBytes(":" + this.uri));
this.md5.update(ASCIIUtility.getBytes(this.clientResponse + toHex(this.md5.digest())));
String text = toHex(this.md5.digest());
if (!text.equals(map.get("rspauth"))) {
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("Expected => rspauth=" + text);
return false;
}
return true;
}
private Hashtable tokenize(String serverResponse) throws IOException {
Hashtable<String, String> map = new Hashtable();
byte[] bytes = serverResponse.getBytes("iso-8859-1");
String key = null;
StreamTokenizer tokens = new StreamTokenizer(new InputStreamReader(new BASE64DecoderStream(new ByteArrayInputStream(bytes, 4, bytes.length - 4)), "iso-8859-1"));
tokens.ordinaryChars(48, 57);
tokens.wordChars(48, 57);
int ttype;
while ((ttype = tokens.nextToken()) != -1) {
switch (ttype) {
case -3:
if (key == null)
key = tokens.sval;
case 34:
if (this.logger.isLoggable(Level.FINE))
this.logger.fine("Received => " + key + "='" + tokens.sval + "'");
if (map.containsKey(key)) {
map.put(key, new StringBuilder().append((Object)map.get(key)).append(",").append(tokens.sval).toString());
} else {
map.put(key, tokens.sval);
}
key = null;
}
}
return map;
}
private static char[] digits = new char[] {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'a', 'b', 'c', 'd', 'e', 'f' };
private static String toHex(byte[] bytes) {
char[] result = new char[bytes.length * 2];
for (int index = 0, i = 0; index < bytes.length; index++) {
int temp = bytes[index] & 0xFF;
result[i++] = digits[temp >> 4];
result[i++] = digits[temp & 0xF];
}
return new String(result);
}
}

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