Compare commits
No commits in common. "40e34e5fcf5677a8b603b119c85d35795d9d53d6" and "ebf8e781c80546e37249c9b513ac477dd9495332" have entirely different histories.
40e34e5fcf
...
ebf8e781c8
447 changed files with 6 additions and 95381 deletions
|
@ -15,7 +15,6 @@ ext {
|
|||
user = 'joerg'
|
||||
name = 'net'
|
||||
description = 'Network classes for Java'
|
||||
vendor = 'xbib.org'
|
||||
inceptionYear = '2016'
|
||||
url = 'https://xbib.org/' + user + '/' + name
|
||||
scmUrl = 'https://xbib.org/' + user + '/' + name
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
group = org.xbib
|
||||
name = net
|
||||
version = 4.8.0
|
||||
version = 4.7.0
|
||||
|
|
|
@ -11,18 +11,9 @@ java {
|
|||
|
||||
jar {
|
||||
manifest {
|
||||
attributes('Implementation-Name': project.name)
|
||||
attributes('Implementation-Version': project.version)
|
||||
attributes('Implementation-Vendor': project.vendor)
|
||||
attributes('X-Compile-Source-JDK': JavaLanguageVersion.of(21).toString())
|
||||
attributes('X-Compile-Target-JDK': JavaLanguageVersion.of(21).toString())
|
||||
}
|
||||
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||
from (project.file('.')) {
|
||||
include 'LICENSE.txt'
|
||||
include 'NOTICE.txt'
|
||||
into 'META-INF'
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile).configureEach {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
dependencies {
|
||||
testImplementation testLibs.junit.jupiter.api
|
||||
testImplementation testLibs.junit.jupiter.params
|
||||
testImplementation testLibs.hamcrest
|
||||
testRuntimeOnly testLibs.junit.jupiter.engine
|
||||
testRuntimeOnly testLibs.junit.jupiter.platform.launcher
|
||||
|
@ -18,8 +17,7 @@ test {
|
|||
'--add-opens=java.base/java.lang.reflect=ALL-UNNAMED',
|
||||
'--add-opens=java.base/java.io=ALL-UNNAMED',
|
||||
'--add-opens=java.base/java.nio=ALL-UNNAMED',
|
||||
'--add-opens=java.base/java.util=ALL-UNNAMED',
|
||||
'--add-opens=java.base/sun.security.util=ALL-UNNAMED'
|
||||
'--add-opens=java.base/java.util=ALL-UNNAMED'
|
||||
systemProperty 'java.util.logging.config.file', 'src/test/resources/logging.properties'
|
||||
environment 'NOTIFY_SOCKET', '/run/systemd/notify'
|
||||
testLogging {
|
||||
|
|
|
@ -1,637 +0,0 @@
|
|||
# Eclipse Public License - v 2.0
|
||||
|
||||
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE
|
||||
PUBLIC LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION
|
||||
OF THE PROGRAM CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT.
|
||||
|
||||
1. DEFINITIONS
|
||||
|
||||
"Contribution" means:
|
||||
|
||||
a) in the case of the initial Contributor, the initial content
|
||||
Distributed under this Agreement, and
|
||||
|
||||
b) in the case of each subsequent Contributor:
|
||||
i) changes to the Program, and
|
||||
ii) additions to the Program;
|
||||
where such changes and/or additions to the Program originate from
|
||||
and are Distributed by that particular Contributor. A Contribution
|
||||
"originates" from a Contributor if it was added to the Program by
|
||||
such Contributor itself or anyone acting on such Contributor's behalf.
|
||||
Contributions do not include changes or additions to the Program that
|
||||
are not Modified Works.
|
||||
|
||||
"Contributor" means any person or entity that Distributes the Program.
|
||||
|
||||
"Licensed Patents" mean patent claims licensable by a Contributor which
|
||||
are necessarily infringed by the use or sale of its Contribution alone
|
||||
or when combined with the Program.
|
||||
|
||||
"Program" means the Contributions Distributed in accordance with this
|
||||
Agreement.
|
||||
|
||||
"Recipient" means anyone who receives the Program under this Agreement
|
||||
or any Secondary License (as applicable), including Contributors.
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source Code or other
|
||||
form, that is based on (or derived from) the Program and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship.
|
||||
|
||||
"Modified Works" shall mean any work in Source Code or other form that
|
||||
results from an addition to, deletion from, or modification of the
|
||||
contents of the Program, including, for purposes of clarity any new file
|
||||
in Source Code form that contains any contents of the Program. Modified
|
||||
Works shall not include works that contain only declarations,
|
||||
interfaces, types, classes, structures, or files of the Program solely
|
||||
in each case in order to link to, bind by name, or subclass the Program
|
||||
or Modified Works thereof.
|
||||
|
||||
"Distribute" means the acts of a) distributing or b) making available
|
||||
in any manner that enables the transfer of a copy.
|
||||
|
||||
"Source Code" means the form of a Program preferred for making
|
||||
modifications, including but not limited to software source code,
|
||||
documentation source, and configuration files.
|
||||
|
||||
"Secondary License" means either the GNU General Public License,
|
||||
Version 2.0, or any later versions of that license, including any
|
||||
exceptions or additional permissions as identified by the initial
|
||||
Contributor.
|
||||
|
||||
2. GRANT OF RIGHTS
|
||||
|
||||
a) Subject to the terms of this Agreement, each Contributor hereby
|
||||
grants Recipient a non-exclusive, worldwide, royalty-free copyright
|
||||
license to reproduce, prepare Derivative Works of, publicly display,
|
||||
publicly perform, Distribute and sublicense the Contribution of such
|
||||
Contributor, if any, and such Derivative Works.
|
||||
|
||||
b) Subject to the terms of this Agreement, each Contributor hereby
|
||||
grants Recipient a non-exclusive, worldwide, royalty-free patent
|
||||
license under Licensed Patents to make, use, sell, offer to sell,
|
||||
import and otherwise transfer the Contribution of such Contributor,
|
||||
if any, in Source Code or other form. This patent license shall
|
||||
apply to the combination of the Contribution and the Program if, at
|
||||
the time the Contribution is added by the Contributor, such addition
|
||||
of the Contribution causes such combination to be covered by the
|
||||
Licensed Patents. The patent license shall not apply to any other
|
||||
combinations which include the Contribution. No hardware per se is
|
||||
licensed hereunder.
|
||||
|
||||
c) Recipient understands that although each Contributor grants the
|
||||
licenses to its Contributions set forth herein, no assurances are
|
||||
provided by any Contributor that the Program does not infringe the
|
||||
patent or other intellectual property rights of any other entity.
|
||||
Each Contributor disclaims any liability to Recipient for claims
|
||||
brought by any other entity based on infringement of intellectual
|
||||
property rights or otherwise. As a condition to exercising the
|
||||
rights and licenses granted hereunder, each Recipient hereby
|
||||
assumes sole responsibility to secure any other intellectual
|
||||
property rights needed, if any. For example, if a third party
|
||||
patent license is required to allow Recipient to Distribute the
|
||||
Program, it is Recipient's responsibility to acquire that license
|
||||
before distributing the Program.
|
||||
|
||||
d) Each Contributor represents that to its knowledge it has
|
||||
sufficient copyright rights in its Contribution, if any, to grant
|
||||
the copyright license set forth in this Agreement.
|
||||
|
||||
e) Notwithstanding the terms of any Secondary License, no
|
||||
Contributor makes additional grants to any Recipient (other than
|
||||
those set forth in this Agreement) as a result of such Recipient's
|
||||
receipt of the Program under the terms of a Secondary License
|
||||
(if permitted under the terms of Section 3).
|
||||
|
||||
3. REQUIREMENTS
|
||||
|
||||
3.1 If a Contributor Distributes the Program in any form, then:
|
||||
|
||||
a) the Program must also be made available as Source Code, in
|
||||
accordance with section 3.2, and the Contributor must accompany
|
||||
the Program with a statement that the Source Code for the Program
|
||||
is available under this Agreement, and informs Recipients how to
|
||||
obtain it in a reasonable manner on or through a medium customarily
|
||||
used for software exchange; and
|
||||
|
||||
b) the Contributor may Distribute the Program under a license
|
||||
different than this Agreement, provided that such license:
|
||||
i) effectively disclaims on behalf of all other Contributors all
|
||||
warranties and conditions, express and implied, including
|
||||
warranties or conditions of title and non-infringement, and
|
||||
implied warranties or conditions of merchantability and fitness
|
||||
for a particular purpose;
|
||||
|
||||
ii) effectively excludes on behalf of all other Contributors all
|
||||
liability for damages, including direct, indirect, special,
|
||||
incidental and consequential damages, such as lost profits;
|
||||
|
||||
iii) does not attempt to limit or alter the recipients' rights
|
||||
in the Source Code under section 3.2; and
|
||||
|
||||
iv) requires any subsequent distribution of the Program by any
|
||||
party to be under a license that satisfies the requirements
|
||||
of this section 3.
|
||||
|
||||
3.2 When the Program is Distributed as Source Code:
|
||||
|
||||
a) it must be made available under this Agreement, or if the
|
||||
Program (i) is combined with other material in a separate file or
|
||||
files made available under a Secondary License, and (ii) the initial
|
||||
Contributor attached to the Source Code the notice described in
|
||||
Exhibit A of this Agreement, then the Program may be made available
|
||||
under the terms of such Secondary Licenses, and
|
||||
|
||||
b) a copy of this Agreement must be included with each copy of
|
||||
the Program.
|
||||
|
||||
3.3 Contributors may not remove or alter any copyright, patent,
|
||||
trademark, attribution notices, disclaimers of warranty, or limitations
|
||||
of liability ("notices") contained within the Program from any copy of
|
||||
the Program which they Distribute, provided that Contributors may add
|
||||
their own appropriate notices.
|
||||
|
||||
4. COMMERCIAL DISTRIBUTION
|
||||
|
||||
Commercial distributors of software may accept certain responsibilities
|
||||
with respect to end users, business partners and the like. While this
|
||||
license is intended to facilitate the commercial use of the Program,
|
||||
the Contributor who includes the Program in a commercial product
|
||||
offering should do so in a manner which does not create potential
|
||||
liability for other Contributors. Therefore, if a Contributor includes
|
||||
the Program in a commercial product offering, such Contributor
|
||||
("Commercial Contributor") hereby agrees to defend and indemnify every
|
||||
other Contributor ("Indemnified Contributor") against any losses,
|
||||
damages and costs (collectively "Losses") arising from claims, lawsuits
|
||||
and other legal actions brought by a third party against the Indemnified
|
||||
Contributor to the extent caused by the acts or omissions of such
|
||||
Commercial Contributor in connection with its distribution of the Program
|
||||
in a commercial product offering. The obligations in this section do not
|
||||
apply to any claims or Losses relating to any actual or alleged
|
||||
intellectual property infringement. In order to qualify, an Indemnified
|
||||
Contributor must: a) promptly notify the Commercial Contributor in
|
||||
writing of such claim, and b) allow the Commercial Contributor to control,
|
||||
and cooperate with the Commercial Contributor in, the defense and any
|
||||
related settlement negotiations. The Indemnified Contributor may
|
||||
participate in any such claim at its own expense.
|
||||
|
||||
For example, a Contributor might include the Program in a commercial
|
||||
product offering, Product X. That Contributor is then a Commercial
|
||||
Contributor. If that Commercial Contributor then makes performance
|
||||
claims, or offers warranties related to Product X, those performance
|
||||
claims and warranties are such Commercial Contributor's responsibility
|
||||
alone. Under this section, the Commercial Contributor would have to
|
||||
defend claims against the other Contributors related to those performance
|
||||
claims and warranties, and if a court requires any other Contributor to
|
||||
pay any damages as a result, the Commercial Contributor must pay
|
||||
those damages.
|
||||
|
||||
5. NO WARRANTY
|
||||
|
||||
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
|
||||
PERMITTED BY APPLICABLE LAW, THE PROGRAM IS PROVIDED ON AN "AS IS"
|
||||
BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR
|
||||
IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF
|
||||
TITLE, NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR
|
||||
PURPOSE. Each Recipient is solely responsible for determining the
|
||||
appropriateness of using and distributing the Program and assumes all
|
||||
risks associated with its exercise of rights under this Agreement,
|
||||
including but not limited to the risks and costs of program errors,
|
||||
compliance with applicable laws, damage to or loss of data, programs
|
||||
or equipment, and unavailability or interruption of operations.
|
||||
|
||||
6. DISCLAIMER OF LIABILITY
|
||||
|
||||
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, AND TO THE EXTENT
|
||||
PERMITTED BY APPLICABLE LAW, NEITHER RECIPIENT NOR ANY CONTRIBUTORS
|
||||
SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION LOST
|
||||
PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE
|
||||
EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGES.
|
||||
|
||||
7. GENERAL
|
||||
|
||||
If any provision of this Agreement is invalid or unenforceable under
|
||||
applicable law, it shall not affect the validity or enforceability of
|
||||
the remainder of the terms of this Agreement, and without further
|
||||
action by the parties hereto, such provision shall be reformed to the
|
||||
minimum extent necessary to make such provision valid and enforceable.
|
||||
|
||||
If Recipient institutes patent litigation against any entity
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that the
|
||||
Program itself (excluding combinations of the Program with other software
|
||||
or hardware) infringes such Recipient's patent(s), then such Recipient's
|
||||
rights granted under Section 2(b) shall terminate as of the date such
|
||||
litigation is filed.
|
||||
|
||||
All Recipient's rights under this Agreement shall terminate if it
|
||||
fails to comply with any of the material terms or conditions of this
|
||||
Agreement and does not cure such failure in a reasonable period of
|
||||
time after becoming aware of such noncompliance. If all Recipient's
|
||||
rights under this Agreement terminate, Recipient agrees to cease use
|
||||
and distribution of the Program as soon as reasonably practicable.
|
||||
However, Recipient's obligations under this Agreement and any licenses
|
||||
granted by Recipient relating to the Program shall continue and survive.
|
||||
|
||||
Everyone is permitted to copy and distribute copies of this Agreement,
|
||||
but in order to avoid inconsistency the Agreement is copyrighted and
|
||||
may only be modified in the following manner. The Agreement Steward
|
||||
reserves the right to publish new versions (including revisions) of
|
||||
this Agreement from time to time. No one other than the Agreement
|
||||
Steward has the right to modify this Agreement. The Eclipse Foundation
|
||||
is the initial Agreement Steward. The Eclipse Foundation may assign the
|
||||
responsibility to serve as the Agreement Steward to a suitable separate
|
||||
entity. Each new version of the Agreement will be given a distinguishing
|
||||
version number. The Program (including Contributions) may always be
|
||||
Distributed subject to the version of the Agreement under which it was
|
||||
received. In addition, after a new version of the Agreement is published,
|
||||
Contributor may elect to Distribute the Program (including its
|
||||
Contributions) under the new version.
|
||||
|
||||
Except as expressly stated in Sections 2(a) and 2(b) above, Recipient
|
||||
receives no rights or licenses to the intellectual property of any
|
||||
Contributor under this Agreement, whether expressly, by implication,
|
||||
estoppel or otherwise. All rights in the Program not expressly granted
|
||||
under this Agreement are reserved. Nothing in this Agreement is intended
|
||||
to be enforceable by any entity that is not a Contributor or Recipient.
|
||||
No third-party beneficiary rights are created under this Agreement.
|
||||
|
||||
Exhibit A - Form of Secondary Licenses Notice
|
||||
|
||||
"This Source Code may also be made available under the following
|
||||
Secondary Licenses when the conditions for such availability set forth
|
||||
in the Eclipse Public License, v. 2.0 are satisfied: {name license(s),
|
||||
version(s), and exceptions or additional permissions here}."
|
||||
|
||||
Simply including a copy of this Agreement, including this Exhibit A
|
||||
is not sufficient to license the Source Code under Secondary Licenses.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to
|
||||
look for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
---
|
||||
|
||||
## The GNU General Public License (GPL) Version 2, June 1991
|
||||
|
||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
|
||||
51 Franklin Street, Fifth Floor
|
||||
Boston, MA 02110-1335
|
||||
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) <year> <name of author>
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 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
|
||||
|
||||
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.
|
|
@ -1,14 +0,0 @@
|
|||
dependencies {
|
||||
api project(':net-security-auth')
|
||||
}
|
||||
|
||||
def moduleName = 'org.xbib.net.mail.test'
|
||||
def patchArgs = ['--patch-module', "$moduleName=" + files(sourceSets.test.resources.srcDirs).asPath ]
|
||||
|
||||
tasks.named('compileTestJava') {
|
||||
options.compilerArgs += patchArgs
|
||||
}
|
||||
|
||||
tasks.named('test') {
|
||||
jvmArgs += patchArgs
|
||||
}
|
|
@ -1,219 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
/**
|
||||
* The ActivationDataFlavor class is similar to the JDK's
|
||||
* <code>java.awt.datatransfer.DataFlavor</code> class. It allows
|
||||
* Jakarta Activation to
|
||||
* set all three values stored by the DataFlavor class via a new
|
||||
* constructor. It also contains improved MIME parsing in the <code>equals
|
||||
* </code> method. Except for the improved parsing, its semantics are
|
||||
* identical to that of the JDK's DataFlavor class.
|
||||
*/
|
||||
|
||||
public class ActivationDataFlavor {
|
||||
|
||||
/*
|
||||
* Raison d'etre:
|
||||
*
|
||||
* The DataFlavor class included in JDK 1.1 has several limitations
|
||||
* including poor MIME type parsing, and the limitation of
|
||||
* only supporting serialized objects and InputStreams as
|
||||
* representation objects. This class 'fixes' that.
|
||||
*/
|
||||
|
||||
private final String mimeType;
|
||||
private MimeType mimeObject = null;
|
||||
private String humanPresentableName;
|
||||
private Class<?> representationClass = null;
|
||||
|
||||
/**
|
||||
* Construct an ActivationDataFlavor that represents an arbitrary
|
||||
* Java object.
|
||||
* <p>
|
||||
* The returned ActivationDataFlavor will have the following
|
||||
* characteristics:
|
||||
* <p>
|
||||
* representationClass = representationClass
|
||||
* mimeType = mimeType
|
||||
* humanName = humanName
|
||||
*
|
||||
* @param representationClass the class used in this ActivationDataFlavor
|
||||
* @param mimeType the MIME type of the data represented by this class
|
||||
* @param humanPresentableName the human presentable name of the flavor
|
||||
*/
|
||||
public ActivationDataFlavor(Class<?> representationClass,
|
||||
String mimeType, String humanPresentableName) {
|
||||
this.mimeType = mimeType;
|
||||
this.humanPresentableName = humanPresentableName;
|
||||
this.representationClass = representationClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an ActivationDataFlavor that represents a MimeType.
|
||||
* <p>
|
||||
* The returned ActivationDataFlavor will have the following
|
||||
* characteristics:
|
||||
* <p>
|
||||
* If the mimeType is "application/x-java-serialized-object;
|
||||
* class=", the result is the same as calling new
|
||||
* ActivationDataFlavor(Class.forName()) as above.
|
||||
* <p>
|
||||
* otherwise:
|
||||
* <p>
|
||||
* representationClass = InputStream<p>
|
||||
* mimeType = mimeType
|
||||
*
|
||||
* @param representationClass the class used in this ActivationDataFlavor
|
||||
* @param humanPresentableName the human presentable name of the flavor
|
||||
*/
|
||||
public ActivationDataFlavor(Class<?> representationClass,
|
||||
String humanPresentableName) {
|
||||
this.mimeType = "application/x-java-serialized-object";
|
||||
this.representationClass = representationClass;
|
||||
this.humanPresentableName = humanPresentableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an ActivationDataFlavor that represents a MimeType.
|
||||
* <p>
|
||||
* The returned ActivationDataFlavor will have the following
|
||||
* characteristics:
|
||||
* <p>
|
||||
* If the mimeType is "application/x-java-serialized-object; class=",
|
||||
* the result is the same as calling new
|
||||
* ActivationDataFlavor(Class.forName()) as above, otherwise:
|
||||
* <p>
|
||||
* representationClass = InputStream<br>
|
||||
* mimeType = mimeType
|
||||
*
|
||||
* @param mimeType the MIME type of the data represented by this class
|
||||
* @param humanPresentableName the human presentable name of the flavor
|
||||
*/
|
||||
public ActivationDataFlavor(String mimeType, String humanPresentableName) {
|
||||
this.mimeType = mimeType;
|
||||
try {
|
||||
this.representationClass = Class.forName("java.io.InputStream");
|
||||
} catch (ClassNotFoundException ex) {
|
||||
// XXX - should never happen, ignore it
|
||||
}
|
||||
this.humanPresentableName = humanPresentableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MIME type for this ActivationDataFlavor.
|
||||
*
|
||||
* @return the MIME type
|
||||
*/
|
||||
public String getMimeType() {
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the representation class.
|
||||
*
|
||||
* @return the representation class
|
||||
*/
|
||||
public Class<?> getRepresentationClass() {
|
||||
return representationClass;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Human Presentable name.
|
||||
*
|
||||
* @return the human presentable name
|
||||
*/
|
||||
public String getHumanPresentableName() {
|
||||
return humanPresentableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the human presentable name.
|
||||
*
|
||||
* @param humanPresentableName the name to set
|
||||
*/
|
||||
public void setHumanPresentableName(String humanPresentableName) {
|
||||
this.humanPresentableName = humanPresentableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the ActivationDataFlavor passed in with this
|
||||
* ActivationDataFlavor; calls the <code>isMimeTypeEqual</code> method.
|
||||
*
|
||||
* @param dataFlavor the ActivationDataFlavor to compare with
|
||||
* @return true if the MIME type and representation class
|
||||
* are the same
|
||||
*/
|
||||
public boolean equals(ActivationDataFlavor dataFlavor) {
|
||||
return (isMimeTypeEqual(dataFlavor.mimeType) &&
|
||||
dataFlavor.getRepresentationClass() == representationClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param o the <code>Object</code> to compare with
|
||||
* @return true if the object is also an ActivationDataFlavor
|
||||
* and is equal to this
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
return ((o instanceof ActivationDataFlavor) &&
|
||||
equals((ActivationDataFlavor) o));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns hash code for this <code>ActivationDataFlavor</code>.
|
||||
* For two equal <code>ActivationDataFlavor</code>s, hash codes are equal.
|
||||
* For the <code>String</code>
|
||||
* that matches <code>ActivationDataFlavor.equals(String)</code>, it is not
|
||||
* guaranteed that <code>ActivationDataFlavor</code>'s hash code is equal
|
||||
* to the hash code of the <code>String</code>.
|
||||
*
|
||||
* @return a hash code for this <code>ActivationDataFlavor</code>
|
||||
*/
|
||||
public int hashCode() {
|
||||
int total = 0;
|
||||
|
||||
if (representationClass != null) {
|
||||
total += representationClass.hashCode();
|
||||
}
|
||||
|
||||
// XXX - MIME type equality is too complicated so we don't
|
||||
// include it in the hashCode
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the string representation of the MIME type passed in equivalent
|
||||
* to the MIME type of this ActivationDataFlavor. <p>
|
||||
* <p>
|
||||
* ActivationDataFlavor delegates the comparison of MIME types to
|
||||
* the MimeType class included as part of Jakarta Activation.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @return true if the same MIME type
|
||||
*/
|
||||
public boolean isMimeTypeEqual(String mimeType) {
|
||||
MimeType mt = null;
|
||||
try {
|
||||
if (mimeObject == null)
|
||||
mimeObject = new MimeType(this.mimeType);
|
||||
mt = new MimeType(mimeType);
|
||||
} catch (MimeTypeParseException e) {
|
||||
// something didn't parse, do a crude comparison
|
||||
return this.mimeType.equalsIgnoreCase(mimeType);
|
||||
}
|
||||
|
||||
return mimeObject.match(mt);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* The CommandInfo class is used by CommandMap implementations to
|
||||
* describe the results of command requests. It provides the requestor
|
||||
* with both the verb requested, as well as an instance of the
|
||||
* bean. There is also a method that will return the name of the
|
||||
* class that implements the command but <i>it is not guaranteed to
|
||||
* return a valid value</i>. The reason for this is to allow CommandMap
|
||||
* implmentations that subclass CommandInfo to provide special
|
||||
* behavior. For example a CommandMap could dynamically generate
|
||||
* JavaBeans. In this case, it might not be possible to create an
|
||||
* object with all the correct state information solely from the class
|
||||
* name.
|
||||
*/
|
||||
|
||||
public class CommandInfo {
|
||||
private String verb;
|
||||
private String className;
|
||||
|
||||
/**
|
||||
* The Constructor for CommandInfo.
|
||||
*
|
||||
* @param verb The command verb this CommandInfo decribes.
|
||||
* @param className The command's fully qualified class name.
|
||||
*/
|
||||
public CommandInfo(String verb, String className) {
|
||||
this.verb = verb;
|
||||
this.className = className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the command verb.
|
||||
*
|
||||
* @return the command verb.
|
||||
*/
|
||||
public String getCommandName() {
|
||||
return verb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the command's class name. <i>This method MAY return null in
|
||||
* cases where a CommandMap subclassed CommandInfo for its
|
||||
* own purposes.</i> In other words, it might not be possible to
|
||||
* create the correct state in the command by merely knowing
|
||||
* its class name. <b>DO NOT DEPEND ON THIS METHOD RETURNING
|
||||
* A VALID VALUE!</b>
|
||||
*
|
||||
* @return The class name of the command, or <i>null</i>
|
||||
*/
|
||||
public String getCommandClass() {
|
||||
return className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the instantiated JavaBean component.
|
||||
* <p>
|
||||
* If the current runtime environment supports
|
||||
* <code>Beans.instantiate</code>,
|
||||
* use it to instantiate the JavaBeans component. Otherwise, use
|
||||
* {@link Class#forName(String)} Class.forName}.
|
||||
* <p>
|
||||
* The component class needs to be public.
|
||||
* On Java SE 9 and newer, if the component class is in a named module,
|
||||
* it needs to be in an exported package.
|
||||
* <p>
|
||||
* If the bean implements the <code>jakarta.activation.CommandObject</code>
|
||||
* interface, call its <code>setCommandContext</code> method.
|
||||
* <p>
|
||||
* If the DataHandler parameter is null, then the bean is
|
||||
* instantiated with no data. NOTE: this may be useful
|
||||
* if for some reason the DataHandler that is passed in
|
||||
* throws IOExceptions when this method attempts to
|
||||
* access its InputStream. It will allow the caller to
|
||||
* retrieve a reference to the bean if it can be
|
||||
* instantiated.
|
||||
* <p>
|
||||
* If the bean does NOT implement the CommandObject interface,
|
||||
* this method will check if it implements the
|
||||
* java.io.Externalizable interface. If it does, the bean's
|
||||
* readExternal method will be called if an InputStream
|
||||
* can be acquired from the DataHandler.
|
||||
*
|
||||
* @param dh The DataHandler that describes the data to be
|
||||
* passed to the command.
|
||||
* @param loader The ClassLoader to be used to instantiate the bean.
|
||||
* @return The bean
|
||||
* @throws IOException for failures reading data
|
||||
* @throws ClassNotFoundException if command object class can't
|
||||
* be found
|
||||
* @see CommandObject
|
||||
*/
|
||||
public Object getCommandObject(DataHandler dh, ClassLoader loader)
|
||||
throws IOException, ClassNotFoundException {
|
||||
Object new_bean = null;
|
||||
|
||||
// try to instantiate the bean
|
||||
new_bean = Beans.instantiate(loader, className);
|
||||
|
||||
// if we got one and it is a CommandObject
|
||||
if (new_bean != null) {
|
||||
if (new_bean instanceof CommandObject) {
|
||||
((CommandObject) new_bean).setCommandContext(verb, dh);
|
||||
}
|
||||
}
|
||||
return new_bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to invoke Beans.instantiate reflectively or the equivalent
|
||||
* with core reflection when module java.desktop is not readable.
|
||||
*/
|
||||
private static final class Beans {
|
||||
static final Method instantiateMethod;
|
||||
|
||||
static {
|
||||
Method m;
|
||||
try {
|
||||
Class<?> c = Class.forName("java.beans.Beans");
|
||||
m = c.getDeclaredMethod("instantiate", ClassLoader.class, String.class);
|
||||
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||
m = null;
|
||||
}
|
||||
instantiateMethod = m;
|
||||
}
|
||||
|
||||
/**
|
||||
* Equivalent to invoking java.beans.Beans.instantiate(loader, cn)
|
||||
*/
|
||||
static Object instantiate(ClassLoader loader, String cn)
|
||||
throws ClassNotFoundException {
|
||||
if (instantiateMethod != null) {
|
||||
// invoke Beans.instantiate
|
||||
try {
|
||||
return instantiateMethod.invoke(null, loader, cn);
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
//
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (loader == null) {
|
||||
loader = ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
Class<?> beanClass = Class.forName(cn, true, loader);
|
||||
try {
|
||||
return beanClass.getDeclaredConstructor().newInstance();
|
||||
} catch (Exception ex) {
|
||||
throw new ClassNotFoundException(beanClass + ": " + ex, ex);
|
||||
}
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,204 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
|
||||
/**
|
||||
* The CommandMap class provides an interface to a registry of
|
||||
* command objects available in the system.
|
||||
* Developers are expected to either use the CommandMap
|
||||
* implementation included with this package (MailcapCommandMap) or
|
||||
* develop their own. Note that some of the methods in this class are
|
||||
* abstract.
|
||||
*/
|
||||
public abstract class CommandMap {
|
||||
private static CommandMap defaultCommandMap = null;
|
||||
private static Map<ClassLoader, CommandMap> map = new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* Default (empty) constructor.
|
||||
*/
|
||||
protected CommandMap() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default CommandMap.
|
||||
*
|
||||
* <ul>
|
||||
* <li> In cases where a CommandMap instance has been previously set
|
||||
* to some value (via <i>setDefaultCommandMap</i>)
|
||||
* return the CommandMap.
|
||||
* <li>
|
||||
* In cases where no CommandMap has been set, the CommandMap
|
||||
* creates an instance of <code>MailcapCommandMap</code> and
|
||||
* set that to the default, returning its value.
|
||||
*
|
||||
* </ul>
|
||||
*
|
||||
* @return the CommandMap
|
||||
*/
|
||||
public static synchronized CommandMap getDefaultCommandMap() {
|
||||
if (defaultCommandMap != null)
|
||||
return defaultCommandMap;
|
||||
|
||||
// fetch per-thread-context-class-loader default
|
||||
ClassLoader tccl = Util.getContextClassLoader();
|
||||
CommandMap def = map.get(tccl);
|
||||
if (def == null) {
|
||||
def = new MailcapCommandMap();
|
||||
map.put(tccl, def);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the default CommandMap. Reset the CommandMap to the default by
|
||||
* calling this method with <code>null</code>.
|
||||
*
|
||||
* @param commandMap The new default CommandMap.
|
||||
*/
|
||||
public static synchronized void setDefaultCommandMap(CommandMap commandMap) {
|
||||
map.remove(Util.getContextClassLoader());
|
||||
defaultCommandMap = commandMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the preferred command list from a MIME Type. The actual semantics
|
||||
* are determined by the implementation of the CommandMap.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @return the CommandInfo classes that represent the command Beans.
|
||||
*/
|
||||
abstract public CommandInfo[] getPreferredCommands(String mimeType);
|
||||
|
||||
/**
|
||||
* Get the preferred command list from a MIME Type. The actual semantics
|
||||
* are determined by the implementation of the CommandMap. <p>
|
||||
* <p>
|
||||
* The <code>DataSource</code> provides extra information, such as
|
||||
* the file name, that a CommandMap implementation may use to further
|
||||
* refine the list of commands that are returned. The implementation
|
||||
* in this class simply calls the <code>getPreferredCommands</code>
|
||||
* method that ignores this argument.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @param ds a DataSource for the data
|
||||
* @return the CommandInfo classes that represent the command Beans.
|
||||
* @since JAF 1.1
|
||||
*/
|
||||
public CommandInfo[] getPreferredCommands(String mimeType, DataSource ds) {
|
||||
return getPreferredCommands(mimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the available commands for this type. This method
|
||||
* should return all the possible commands for this MIME type.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @return the CommandInfo objects representing all the commands.
|
||||
*/
|
||||
abstract public CommandInfo[] getAllCommands(String mimeType);
|
||||
|
||||
/**
|
||||
* Get all the available commands for this type. This method
|
||||
* should return all the possible commands for this MIME type. <p>
|
||||
* <p>
|
||||
* The <code>DataSource</code> provides extra information, such as
|
||||
* the file name, that a CommandMap implementation may use to further
|
||||
* refine the list of commands that are returned. The implementation
|
||||
* in this class simply calls the <code>getAllCommands</code>
|
||||
* method that ignores this argument.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @param ds a DataSource for the data
|
||||
* @return the CommandInfo objects representing all the commands.
|
||||
* @since JAF 1.1
|
||||
*/
|
||||
public CommandInfo[] getAllCommands(String mimeType, DataSource ds) {
|
||||
return getAllCommands(mimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default command corresponding to the MIME type.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @param cmdName the command name
|
||||
* @return the CommandInfo corresponding to the command.
|
||||
*/
|
||||
abstract public CommandInfo getCommand(String mimeType, String cmdName);
|
||||
|
||||
/**
|
||||
* Get the default command corresponding to the MIME type. <p>
|
||||
* <p>
|
||||
* The <code>DataSource</code> provides extra information, such as
|
||||
* the file name, that a CommandMap implementation may use to further
|
||||
* refine the command that is chosen. The implementation
|
||||
* in this class simply calls the <code>getCommand</code>
|
||||
* method that ignores this argument.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @param cmdName the command name
|
||||
* @param ds a DataSource for the data
|
||||
* @return the CommandInfo corresponding to the command.
|
||||
* @since JAF 1.1
|
||||
*/
|
||||
public CommandInfo getCommand(String mimeType, String cmdName,
|
||||
DataSource ds) {
|
||||
return getCommand(mimeType, cmdName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Locate a DataContentHandler that corresponds to the MIME type.
|
||||
* The mechanism and semantics for determining this are determined
|
||||
* by the implementation of the particular CommandMap.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @return the DataContentHandler for the MIME type
|
||||
*/
|
||||
abstract public DataContentHandler createDataContentHandler(String
|
||||
mimeType);
|
||||
|
||||
/**
|
||||
* Locate a DataContentHandler that corresponds to the MIME type.
|
||||
* The mechanism and semantics for determining this are determined
|
||||
* by the implementation of the particular CommandMap. <p>
|
||||
* <p>
|
||||
* The <code>DataSource</code> provides extra information, such as
|
||||
* the file name, that a CommandMap implementation may use to further
|
||||
* refine the choice of DataContentHandler. The implementation
|
||||
* in this class simply calls the <code>createDataContentHandler</code>
|
||||
* method that ignores this argument.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @param ds a DataSource for the data
|
||||
* @return the DataContentHandler for the MIME type
|
||||
* @since JAF 1.1
|
||||
*/
|
||||
public DataContentHandler createDataContentHandler(String mimeType,
|
||||
DataSource ds) {
|
||||
return createDataContentHandler(mimeType);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the MIME types known to this command map.
|
||||
* If the command map doesn't support this operation,
|
||||
* null is returned.
|
||||
*
|
||||
* @return array of MIME types as strings, or null if not supported
|
||||
* @since JAF 1.1
|
||||
*/
|
||||
public String[] getMimeTypes() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* JavaBeans components that are Jakarta Activation aware implement
|
||||
* this interface to find out which command verb they're being asked
|
||||
* to perform, and to obtain the DataHandler representing the
|
||||
* data they should operate on. JavaBeans that don't implement
|
||||
* this interface may be used as well. Such commands may obtain
|
||||
* the data using the Externalizable interface, or using an
|
||||
* application-specific method.
|
||||
*/
|
||||
public interface CommandObject {
|
||||
|
||||
/**
|
||||
* Initialize the Command with the verb it is requested to handle
|
||||
* and the DataHandler that describes the data it will
|
||||
* operate on. <b>NOTE:</b> it is acceptable for the caller
|
||||
* to pass <i>null</i> as the value for <code>DataHandler</code>.
|
||||
*
|
||||
* @param verb The Command Verb this object refers to.
|
||||
* @param dh The DataHandler.
|
||||
* @throws IOException for failures accessing data
|
||||
*/
|
||||
void setCommandContext(String verb, DataHandler dh)
|
||||
throws IOException;
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* The DataContentHandler interface is implemented by objects that can
|
||||
* be used to extend the capabilities of the DataHandler's implementation
|
||||
* of the Transferable interface. Through <code>DataContentHandlers</code>
|
||||
* the framework can be extended to convert streams in to objects, and
|
||||
* to write objects to streams. <p>
|
||||
* <p>
|
||||
* Applications don't generally call the methods in DataContentHandlers
|
||||
* directly. Instead, an application calls the equivalent methods in
|
||||
* DataHandler. The DataHandler will attempt to find an appropriate
|
||||
* DataContentHandler that corresponds to its MIME type using the
|
||||
* current DataContentHandlerFactory. The DataHandler then calls
|
||||
* through to the methods in the DataContentHandler.
|
||||
*/
|
||||
|
||||
public interface DataContentHandler {
|
||||
/**
|
||||
* Returns an array of ActivationDataFlavor objects indicating the flavors
|
||||
* the data can be provided in. The array should be ordered according to
|
||||
* preference for providing the data (from most richly descriptive to
|
||||
* least descriptive).
|
||||
*
|
||||
* @return The ActivationDataFlavors.
|
||||
*/
|
||||
ActivationDataFlavor[] getTransferDataFlavors();
|
||||
|
||||
/**
|
||||
* Returns an object which represents the data to be transferred.
|
||||
* The class of the object returned is defined by the representation class
|
||||
* of the flavor.
|
||||
*
|
||||
* @param df The ActivationDataFlavor representing the requested type.
|
||||
* @param ds The DataSource representing the data to be converted.
|
||||
* @return The constructed Object.
|
||||
* @throws IOException if the handler doesn't
|
||||
* support the requested flavor
|
||||
* @throws IOException if the data can't be accessed
|
||||
*/
|
||||
Object getTransferData(ActivationDataFlavor df, DataSource ds)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Return an object representing the data in its most preferred form.
|
||||
* Generally this will be the form described by the first
|
||||
* ActivationDataFlavor returned by the
|
||||
* <code>getTransferDataFlavors</code> method.
|
||||
*
|
||||
* @param ds The DataSource representing the data to be converted.
|
||||
* @return The constructed Object.
|
||||
* @throws IOException if the data can't be accessed
|
||||
*/
|
||||
Object getContent(DataSource ds) throws IOException;
|
||||
|
||||
/**
|
||||
* Convert the object to a byte stream of the specified MIME type
|
||||
* and write it to the output stream.
|
||||
*
|
||||
* @param obj The object to be converted.
|
||||
* @param mimeType The requested MIME type of the resulting byte stream.
|
||||
* @param os The output stream into which to write the converted
|
||||
* byte stream.
|
||||
* @throws IOException errors writing to the stream
|
||||
*/
|
||||
void writeTo(Object obj, String mimeType, OutputStream os)
|
||||
throws IOException;
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
/**
|
||||
* This interface defines a factory for <code>DataContentHandlers</code>. An
|
||||
* implementation of this interface should map a MIME type into an
|
||||
* instance of DataContentHandler. The design pattern for classes implementing
|
||||
* this interface is the same as for the ContentHandler mechanism used in
|
||||
* <code>java.net.URL</code>.
|
||||
*/
|
||||
|
||||
public interface DataContentHandlerFactory {
|
||||
|
||||
/**
|
||||
* Creates a new DataContentHandler object for the MIME type.
|
||||
*
|
||||
* @param mimeType the MIME type to create the DataContentHandler for.
|
||||
* @return The new <code>DataContentHandler</code>, or <i>null</i>
|
||||
* if none are found.
|
||||
*/
|
||||
DataContentHandler createDataContentHandler(String mimeType);
|
||||
}
|
|
@ -1,854 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PipedInputStream;
|
||||
import java.io.PipedOutputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.Charset;
|
||||
|
||||
/**
|
||||
* The DataHandler class provides a consistent interface to data
|
||||
* available in many different sources and formats.
|
||||
* It manages simple stream to string conversions and related operations
|
||||
* using DataContentHandlers.
|
||||
* It provides access to commands that can operate on the data.
|
||||
* The commands are found using a CommandMap. <p>
|
||||
*
|
||||
* <b>DataHandler and CommandMaps</b><p>
|
||||
* The DataHandler keeps track of the current CommandMap that it uses to
|
||||
* service requests for commands (<code>getCommand</code>,
|
||||
* <code>getAllCommands</code>, <code>getPreferredCommands</code>).
|
||||
* Each instance of a DataHandler may have a CommandMap associated with
|
||||
* it using the <code>setCommandMap</code> method. If a CommandMap was
|
||||
* not set, DataHandler calls the <code>getDefaultCommandMap</code>
|
||||
* method in CommandMap and uses the value it returns. See
|
||||
* <i>CommandMap</i> for more information. <p>
|
||||
*
|
||||
* <b>DataHandler and URLs</b><p>
|
||||
* The current DataHandler implementation creates a private
|
||||
* instance of URLDataSource when it is constructed with a URL.
|
||||
*
|
||||
* @see CommandMap
|
||||
* @see DataContentHandler
|
||||
* @see DataSource
|
||||
* @see URLDataSource
|
||||
*/
|
||||
|
||||
public class DataHandler {
|
||||
|
||||
// our transfer flavors
|
||||
private static final ActivationDataFlavor[] emptyFlavors =
|
||||
new ActivationDataFlavor[0];
|
||||
// our DataContentHandlerFactory
|
||||
private static DataContentHandlerFactory factory = null;
|
||||
// Use the datasource to indicate whether we were started via the
|
||||
// DataSource constructor or the object constructor.
|
||||
private DataSource dataSource = null;
|
||||
private DataSource objDataSource = null;
|
||||
// The Object and mimetype from the constructor (if passed in).
|
||||
// object remains null if it was instantiated with a
|
||||
// DataSource.
|
||||
private Object object = null;
|
||||
private String objectMimeType = null;
|
||||
// Keep track of the CommandMap
|
||||
private CommandMap currentCommandMap = null;
|
||||
private ActivationDataFlavor[] transferFlavors = emptyFlavors;
|
||||
// our DataContentHandler
|
||||
private DataContentHandler dataContentHandler = null;
|
||||
private DataContentHandler factoryDCH = null;
|
||||
private DataContentHandlerFactory oldFactory = null;
|
||||
// the short representation of the ContentType (sans params)
|
||||
private String shortType = null;
|
||||
|
||||
/**
|
||||
* Create a <code>DataHandler</code> instance referencing the
|
||||
* specified DataSource. The data exists in a byte stream form.
|
||||
* The DataSource will provide an InputStream to access the data.
|
||||
*
|
||||
* @param ds the DataSource
|
||||
*/
|
||||
public DataHandler(DataSource ds) {
|
||||
// save a reference to the incoming DS
|
||||
dataSource = ds;
|
||||
oldFactory = factory; // keep track of the factory
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a <code>DataHandler</code> instance representing an object
|
||||
* of this MIME type. This constructor is
|
||||
* used when the application already has an in-memory representation
|
||||
* of the data in the form of a Java Object.
|
||||
*
|
||||
* @param obj the Java Object
|
||||
* @param mimeType the MIME type of the object
|
||||
*/
|
||||
public DataHandler(Object obj, String mimeType) {
|
||||
object = obj;
|
||||
objectMimeType = mimeType;
|
||||
oldFactory = factory; // keep track of the factory
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a <code>DataHandler</code> instance referencing a URL.
|
||||
* The DataHandler internally creates a <code>URLDataSource</code>
|
||||
* instance to represent the URL.
|
||||
*
|
||||
* @param url a URL object
|
||||
*/
|
||||
public DataHandler(URL url) {
|
||||
dataSource = new URLDataSource(url);
|
||||
oldFactory = factory; // keep track of the factory
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the DataContentHandlerFactory. The DataContentHandlerFactory
|
||||
* is called first to find DataContentHandlers.
|
||||
* The DataContentHandlerFactory can only be set once.
|
||||
* <p>
|
||||
* If the DataContentHandlerFactory has already been set,
|
||||
* this method throws an Error.
|
||||
*
|
||||
* @param newFactory the DataContentHandlerFactory
|
||||
* @throws Error if the factory has already been defined.
|
||||
* @see DataContentHandlerFactory
|
||||
*/
|
||||
public static synchronized void setDataContentHandlerFactory(
|
||||
DataContentHandlerFactory newFactory) {
|
||||
if (factory != null)
|
||||
throw new Error("DataContentHandlerFactory already defined");
|
||||
factory = newFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the CommandMap for this instance of DataHandler.
|
||||
*/
|
||||
private synchronized CommandMap getCommandMap() {
|
||||
if (currentCommandMap != null)
|
||||
return currentCommandMap;
|
||||
else
|
||||
return CommandMap.getDefaultCommandMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the CommandMap for use by this DataHandler.
|
||||
* Setting it to <code>null</code> causes the CommandMap to revert
|
||||
* to the CommandMap returned by the
|
||||
* <code>CommandMap.getDefaultCommandMap</code> method.
|
||||
* Changing the CommandMap, or setting it to <code>null</code>,
|
||||
* clears out any data cached from the previous CommandMap.
|
||||
*
|
||||
* @param commandMap the CommandMap to use in this DataHandler
|
||||
* @see CommandMap#setDefaultCommandMap
|
||||
*/
|
||||
public synchronized void setCommandMap(CommandMap commandMap) {
|
||||
if (commandMap != currentCommandMap || commandMap == null) {
|
||||
// clear cached values...
|
||||
transferFlavors = emptyFlavors;
|
||||
dataContentHandler = null;
|
||||
|
||||
currentCommandMap = commandMap;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DataSource associated with this instance
|
||||
* of DataHandler.
|
||||
* <p>
|
||||
* For DataHandlers that have been instantiated with a DataSource,
|
||||
* this method returns the DataSource that was used to create the
|
||||
* DataHandler object. In other cases the DataHandler
|
||||
* constructs a DataSource from the data used to construct
|
||||
* the DataHandler. DataSources created for DataHandlers <b>not</b>
|
||||
* instantiated with a DataSource are cached for performance
|
||||
* reasons.
|
||||
*
|
||||
* @return a valid DataSource object for this DataHandler
|
||||
*/
|
||||
public DataSource getDataSource() {
|
||||
if (dataSource == null) {
|
||||
// create one on the fly
|
||||
if (objDataSource == null)
|
||||
objDataSource = new DataHandlerDataSource(this);
|
||||
return objDataSource;
|
||||
}
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the name of the data object. If this DataHandler
|
||||
* was created with a DataSource, this method calls through
|
||||
* to the <code>DataSource.getName</code> method, otherwise it
|
||||
* returns <i>null</i>.
|
||||
*
|
||||
* @return the name of the object
|
||||
*/
|
||||
public String getName() {
|
||||
if (dataSource != null)
|
||||
return dataSource.getName();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MIME type of this object as retrieved from
|
||||
* the source object. Note that this is the <i>full</i>
|
||||
* type with parameters.
|
||||
*
|
||||
* @return the MIME type
|
||||
*/
|
||||
public String getContentType() {
|
||||
if (dataSource != null) // data source case
|
||||
return dataSource.getContentType();
|
||||
else
|
||||
return objectMimeType; // obj/type case
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the InputStream for this object. <p>
|
||||
* <p>
|
||||
* For DataHandlers instantiated with a DataSource, the DataHandler
|
||||
* calls the <code>DataSource.getInputStream</code> method and
|
||||
* returns the result to the caller.
|
||||
* <p>
|
||||
* For DataHandlers instantiated with an Object, the DataHandler
|
||||
* first attempts to find a DataContentHandler for the Object. If
|
||||
* the DataHandler can not find a DataContentHandler for this MIME
|
||||
* type, it throws an UnsupportedDataTypeException. If it is
|
||||
* successful, it creates a pipe and a thread. The thread uses the
|
||||
* DataContentHandler's <code>writeTo</code> method to write the
|
||||
* stream data into one end of the pipe. The other end of the pipe
|
||||
* is returned to the caller. Because a thread is created to copy
|
||||
* the data, IOExceptions that may occur during the copy can not be
|
||||
* propagated back to the caller. The result is an empty stream.
|
||||
*
|
||||
* @return the InputStream representing this data
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @see DataContentHandler#writeTo
|
||||
* @see UnsupportedDataTypeException
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
InputStream ins = null;
|
||||
|
||||
if (dataSource != null) {
|
||||
ins = dataSource.getInputStream();
|
||||
} else {
|
||||
DataContentHandler dch = getDataContentHandler();
|
||||
// we won't even try if we can't get a dch
|
||||
if (dch == null)
|
||||
throw new UnsupportedDataTypeException(
|
||||
"no DCH for MIME type " + getBaseType());
|
||||
|
||||
if (dch instanceof ObjectDataContentHandler) {
|
||||
if (((ObjectDataContentHandler) dch).getDCH() == null)
|
||||
throw new UnsupportedDataTypeException(
|
||||
"no object DCH for MIME type " + getBaseType());
|
||||
}
|
||||
// there is none but the default^^^^^^^^^^^^^^^^
|
||||
final DataContentHandler fdch = dch;
|
||||
|
||||
// from bill s.
|
||||
// ce n'est pas une pipe!
|
||||
//
|
||||
// NOTE: This block of code needs to throw exceptions, but
|
||||
// can't because it is in another thread!!! ARG!
|
||||
//
|
||||
final PipedOutputStream pos = new PipedOutputStream();
|
||||
PipedInputStream pin = new PipedInputStream(pos);
|
||||
new Thread(
|
||||
new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
fdch.writeTo(object, objectMimeType, pos);
|
||||
} catch (IOException e) {
|
||||
|
||||
} finally {
|
||||
try {
|
||||
pos.close();
|
||||
} catch (IOException ie) {
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"DataHandler.getInputStream").start();
|
||||
ins = pin;
|
||||
}
|
||||
|
||||
return ins;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the data to an <code>OutputStream</code>.<p>
|
||||
* <p>
|
||||
* If the DataHandler was created with a DataSource, writeTo
|
||||
* retrieves the InputStream and copies the bytes from the
|
||||
* InputStream to the OutputStream passed in.
|
||||
* <p>
|
||||
* If the DataHandler was created with an object, writeTo
|
||||
* retrieves the DataContentHandler for the object's type.
|
||||
* If the DataContentHandler was found, it calls the
|
||||
* <code>writeTo</code> method on the <code>DataContentHandler</code>.
|
||||
*
|
||||
* @param os the OutputStream to write to
|
||||
* @throws IOException if an I/O error occurs
|
||||
*/
|
||||
public void writeTo(OutputStream os) throws IOException {
|
||||
// for the DataSource case
|
||||
if (dataSource != null) {
|
||||
InputStream is = null;
|
||||
byte[] data = new byte[8 * 1024];
|
||||
int bytes_read;
|
||||
|
||||
is = dataSource.getInputStream();
|
||||
|
||||
try {
|
||||
while ((bytes_read = is.read(data)) > 0) {
|
||||
os.write(data, 0, bytes_read);
|
||||
}
|
||||
} finally {
|
||||
is.close();
|
||||
is = null;
|
||||
}
|
||||
} else { // for the Object case
|
||||
DataContentHandler dch = getDataContentHandler();
|
||||
dch.writeTo(object, objectMimeType, os);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an OutputStream for this DataHandler to allow overwriting
|
||||
* the underlying data.
|
||||
* If the DataHandler was created with a DataSource, the
|
||||
* DataSource's <code>getOutputStream</code> method is called.
|
||||
* Otherwise, <code>null</code> is returned.
|
||||
*
|
||||
* @return the OutputStream
|
||||
* @throws IOException for failures creating the OutputStream
|
||||
* @see DataSource#getOutputStream
|
||||
* @see URLDataSource
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
if (dataSource != null)
|
||||
return dataSource.getOutputStream();
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ActivationDataFlavors in which this data is available. <p>
|
||||
* <p>
|
||||
* Returns an array of ActivationDataFlavor objects indicating the flavors
|
||||
* the data can be provided in. The array is usually ordered
|
||||
* according to preference for providing the data, from most
|
||||
* richly descriptive to least richly descriptive.<p>
|
||||
* <p>
|
||||
* The DataHandler attempts to find a DataContentHandler that
|
||||
* corresponds to the MIME type of the data. If one is located,
|
||||
* the DataHandler calls the DataContentHandler's
|
||||
* <code>getTransferDataFlavors</code> method. <p>
|
||||
* <p>
|
||||
* If a DataContentHandler can <i>not</i> be located, and if the
|
||||
* DataHandler was created with a DataSource (or URL), one
|
||||
* ActivationDataFlavor is returned that represents this object's MIME type
|
||||
* and the <code>java.io.InputStream</code> class. If the
|
||||
* DataHandler was created with an object and a MIME type,
|
||||
* getTransferDataFlavors returns one ActivationDataFlavor that represents
|
||||
* this object's MIME type and the object's class.
|
||||
*
|
||||
* @return an array of data flavors in which this data can be transferred
|
||||
* @see DataContentHandler#getTransferDataFlavors
|
||||
*/
|
||||
public synchronized ActivationDataFlavor[] getTransferDataFlavors() {
|
||||
if (factory != oldFactory) // if the factory has changed, clear cache
|
||||
transferFlavors = emptyFlavors;
|
||||
|
||||
// if it's not set, set it...
|
||||
if (transferFlavors == emptyFlavors)
|
||||
transferFlavors = getDataContentHandler().getTransferDataFlavors();
|
||||
return transferFlavors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the specified data flavor is supported
|
||||
* for this object.<p>
|
||||
* <p>
|
||||
* This method iterates through the ActivationDataFlavors returned from
|
||||
* <code>getTransferDataFlavors</code>, comparing each with
|
||||
* the specified flavor.
|
||||
*
|
||||
* @param flavor the requested flavor for the data
|
||||
* @return true if the data flavor is supported
|
||||
* @see DataHandler#getTransferDataFlavors
|
||||
*/
|
||||
public boolean isDataFlavorSupported(ActivationDataFlavor flavor) {
|
||||
ActivationDataFlavor[] lFlavors = getTransferDataFlavors();
|
||||
|
||||
for (int i = 0; i < lFlavors.length; i++) {
|
||||
if (lFlavors[i].equals(flavor))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an object that represents the data to be
|
||||
* transferred. The class of the object returned is defined by the
|
||||
* representation class of the data flavor.<p>
|
||||
*
|
||||
* <b>For DataHandler's created with DataSources or URLs:</b><p>
|
||||
* <p>
|
||||
* The DataHandler attempts to locate a DataContentHandler
|
||||
* for this MIME type. If one is found, the passed in ActivationDataFlavor
|
||||
* and the type of the data are passed to its <code>getTransferData</code>
|
||||
* method. If the DataHandler fails to locate a DataContentHandler
|
||||
* and the flavor specifies this object's MIME type and the
|
||||
* <code>java.io.InputStream</code> class, this object's InputStream
|
||||
* is returned.
|
||||
* Otherwise it throws an IOException. <p>
|
||||
*
|
||||
* <b>For DataHandler's created with Objects:</b><p>
|
||||
* <p>
|
||||
* The DataHandler attempts to locate a DataContentHandler
|
||||
* for this MIME type. If one is found, the passed in ActivationDataFlavor
|
||||
* and the type of the data are passed to its getTransferData
|
||||
* method. If the DataHandler fails to locate a DataContentHandler
|
||||
* and the flavor specifies this object's MIME type and its class,
|
||||
* this DataHandler's referenced object is returned.
|
||||
* Otherwise it throws an IOException.
|
||||
*
|
||||
* @param flavor the requested flavor for the data
|
||||
* @return the object
|
||||
* @throws IOException if the data could not be
|
||||
* converted to the requested flavor
|
||||
* @throws IOException if an I/O error occurs
|
||||
* @see ActivationDataFlavor
|
||||
*/
|
||||
public Object getTransferData(ActivationDataFlavor flavor)
|
||||
throws IOException {
|
||||
return getDataContentHandler().getTransferData(flavor, dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the <i>preferred</i> commands for this type of data.
|
||||
* This method calls the <code>getPreferredCommands</code> method
|
||||
* in the CommandMap associated with this instance of DataHandler.
|
||||
* This method returns an array that represents a subset of
|
||||
* available commands. In cases where multiple commands for the
|
||||
* MIME type represented by this DataHandler are present, the
|
||||
* installed CommandMap chooses the appropriate commands.
|
||||
*
|
||||
* @return the CommandInfo objects representing the preferred commands
|
||||
* @see CommandMap#getPreferredCommands
|
||||
*/
|
||||
public CommandInfo[] getPreferredCommands() {
|
||||
if (dataSource != null)
|
||||
return getCommandMap().getPreferredCommands(getBaseType(),
|
||||
dataSource);
|
||||
else
|
||||
return getCommandMap().getPreferredCommands(getBaseType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the commands for this type of data.
|
||||
* This method returns an array containing all commands
|
||||
* for the type of data represented by this DataHandler. The
|
||||
* MIME type for the underlying data represented by this DataHandler
|
||||
* is used to call through to the <code>getAllCommands</code> method
|
||||
* of the CommandMap associated with this DataHandler.
|
||||
*
|
||||
* @return the CommandInfo objects representing all the commands
|
||||
* @see CommandMap#getAllCommands
|
||||
*/
|
||||
public CommandInfo[] getAllCommands() {
|
||||
if (dataSource != null)
|
||||
return getCommandMap().getAllCommands(getBaseType(), dataSource);
|
||||
else
|
||||
return getCommandMap().getAllCommands(getBaseType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the command <i>cmdName</i>. Use the search semantics as
|
||||
* defined by the CommandMap installed in this DataHandler. The
|
||||
* MIME type for the underlying data represented by this DataHandler
|
||||
* is used to call through to the <code>getCommand</code> method
|
||||
* of the CommandMap associated with this DataHandler.
|
||||
*
|
||||
* @param cmdName the command name
|
||||
* @return the CommandInfo corresponding to the command
|
||||
* @see CommandMap#getCommand
|
||||
*/
|
||||
public CommandInfo getCommand(String cmdName) {
|
||||
if (dataSource != null)
|
||||
return getCommandMap().getCommand(getBaseType(), cmdName,
|
||||
dataSource);
|
||||
else
|
||||
return getCommandMap().getCommand(getBaseType(), cmdName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the data in its preferred Object form. <p>
|
||||
* <p>
|
||||
* If the DataHandler was instantiated with an object, return
|
||||
* the object. <p>
|
||||
* <p>
|
||||
* If the DataHandler was instantiated with a DataSource,
|
||||
* this method uses a DataContentHandler to return the content
|
||||
* object for the data represented by this DataHandler. If no
|
||||
* <code>DataContentHandler</code> can be found for the
|
||||
* the type of this data, the DataHandler returns an
|
||||
* InputStream for the data.
|
||||
*
|
||||
* @return the content.
|
||||
* @throws IOException if an IOException occurs during
|
||||
* this operation.
|
||||
*/
|
||||
public Object getContent() throws IOException {
|
||||
if (object != null)
|
||||
return object;
|
||||
else
|
||||
return getDataContentHandler().getContent(getDataSource());
|
||||
}
|
||||
|
||||
/**
|
||||
* A convenience method that takes a CommandInfo object
|
||||
* and instantiates the corresponding command, usually
|
||||
* a JavaBean component.
|
||||
* <p>
|
||||
* This method calls the CommandInfo's <code>getCommandObject</code>
|
||||
* method with the <code>ClassLoader</code> used to load
|
||||
* the <code>jakarta.activation.DataHandler</code> class itself.
|
||||
*
|
||||
* @param cmdinfo the CommandInfo corresponding to a command
|
||||
* @return the instantiated command object
|
||||
*/
|
||||
public Object getBean(CommandInfo cmdinfo) {
|
||||
Object bean = null;
|
||||
|
||||
try {
|
||||
// make the bean
|
||||
ClassLoader cld = null;
|
||||
// First try the "application's" class loader.
|
||||
cld = Util.getContextClassLoader();
|
||||
if (cld == null)
|
||||
cld = this.getClass().getClassLoader();
|
||||
bean = cmdinfo.getCommandObject(this, cld);
|
||||
} catch (IOException | ClassNotFoundException e) {
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the DataContentHandler for this DataHandler: <p>
|
||||
* <p>
|
||||
* If a DataContentHandlerFactory is set, use it.
|
||||
* Otherwise look for an object to serve DCH in the
|
||||
* following order: <p>
|
||||
* <p>
|
||||
* 1) if a factory is set, use it <p>
|
||||
* 2) if a CommandMap is set, use it <p>
|
||||
* 3) use the default CommandMap <p>
|
||||
* <p>
|
||||
* In any case, wrap the real DataContentHandler with one of our own
|
||||
* to handle any missing cases, fill in defaults, and to ensure that
|
||||
* we always have a non-null DataContentHandler.
|
||||
*
|
||||
* @return the requested DataContentHandler
|
||||
*/
|
||||
private synchronized DataContentHandler getDataContentHandler() {
|
||||
|
||||
// make sure the factory didn't change
|
||||
if (factory != oldFactory) {
|
||||
oldFactory = factory;
|
||||
factoryDCH = null;
|
||||
dataContentHandler = null;
|
||||
transferFlavors = emptyFlavors;
|
||||
}
|
||||
|
||||
if (dataContentHandler != null)
|
||||
return dataContentHandler;
|
||||
|
||||
String simpleMT = getBaseType();
|
||||
|
||||
if (factoryDCH == null && factory != null)
|
||||
factoryDCH = factory.createDataContentHandler(simpleMT);
|
||||
|
||||
if (factoryDCH != null)
|
||||
dataContentHandler = factoryDCH;
|
||||
|
||||
if (dataContentHandler == null) {
|
||||
if (dataSource != null)
|
||||
dataContentHandler = getCommandMap().
|
||||
createDataContentHandler(simpleMT, dataSource);
|
||||
else
|
||||
dataContentHandler = getCommandMap().
|
||||
createDataContentHandler(simpleMT);
|
||||
}
|
||||
|
||||
// getDataContentHandler always uses these 'wrapper' handlers
|
||||
// to make sure it returns SOMETHING meaningful...
|
||||
if (dataSource != null)
|
||||
dataContentHandler = new DataSourceDataContentHandler(
|
||||
dataContentHandler,
|
||||
dataSource);
|
||||
else
|
||||
dataContentHandler = new ObjectDataContentHandler(
|
||||
dataContentHandler,
|
||||
object,
|
||||
objectMimeType);
|
||||
return dataContentHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the MimeType class to extract the MIME type/subtype,
|
||||
* ignoring the parameters. The type is cached.
|
||||
*/
|
||||
private synchronized String getBaseType() {
|
||||
if (shortType == null) {
|
||||
String ct = getContentType();
|
||||
try {
|
||||
MimeType mt = new MimeType(ct);
|
||||
shortType = mt.getBaseType();
|
||||
} catch (MimeTypeParseException e) {
|
||||
shortType = ct;
|
||||
}
|
||||
}
|
||||
return shortType;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The DataHanderDataSource class implements the
|
||||
* DataSource interface when the DataHandler is constructed
|
||||
* with an Object and a mimeType string.
|
||||
*/
|
||||
class DataHandlerDataSource implements DataSource {
|
||||
DataHandler dataHandler = null;
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
*/
|
||||
public DataHandlerDataSource(DataHandler dh) {
|
||||
this.dataHandler = dh;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an <code>InputStream</code> representing this object.
|
||||
*
|
||||
* @return the <code>InputStream</code>
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return dataHandler.getInputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the <code>OutputStream</code> for this object.
|
||||
*
|
||||
* @return the <code>OutputStream</code>
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
return dataHandler.getOutputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the MIME type of the data represented by this object.
|
||||
*
|
||||
* @return the MIME type
|
||||
*/
|
||||
public String getContentType() {
|
||||
return dataHandler.getContentType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this object.
|
||||
*
|
||||
* @return the name of this object
|
||||
*/
|
||||
public String getName() {
|
||||
return dataHandler.getName(); // what else would it be?
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* DataSourceDataContentHandler
|
||||
*
|
||||
* This is a <i>private</i> DataContentHandler that wraps the real
|
||||
* DataContentHandler in the case where the DataHandler was instantiated
|
||||
* with a DataSource.
|
||||
*/
|
||||
class DataSourceDataContentHandler implements DataContentHandler {
|
||||
private DataSource ds = null;
|
||||
private ActivationDataFlavor[] transferFlavors = null;
|
||||
private DataContentHandler dch = null;
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
*/
|
||||
public DataSourceDataContentHandler(DataContentHandler dch, DataSource ds) {
|
||||
this.ds = ds;
|
||||
this.dch = dch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ActivationDataFlavors for this
|
||||
* <code>DataContentHandler</code>.
|
||||
*
|
||||
* @return the ActivationDataFlavors
|
||||
*/
|
||||
public ActivationDataFlavor[] getTransferDataFlavors() {
|
||||
|
||||
if (transferFlavors == null) {
|
||||
if (dch != null) { // is there a dch?
|
||||
transferFlavors = dch.getTransferDataFlavors();
|
||||
} else {
|
||||
transferFlavors = new ActivationDataFlavor[1];
|
||||
transferFlavors[0] =
|
||||
new ActivationDataFlavor(ds.getContentType(),
|
||||
ds.getContentType());
|
||||
}
|
||||
}
|
||||
return transferFlavors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Transfer Data of type ActivationDataFlavor from InputStream.
|
||||
*
|
||||
* @param df the ActivationDataFlavor
|
||||
* @param ds the DataSource
|
||||
* @return the constructed Object
|
||||
*/
|
||||
public Object getTransferData(ActivationDataFlavor df, DataSource ds)
|
||||
throws IOException {
|
||||
|
||||
if (dch != null)
|
||||
return dch.getTransferData(df, ds);
|
||||
else if (df.equals(getTransferDataFlavors()[0])) // only have one now
|
||||
return ds.getInputStream();
|
||||
else
|
||||
throw new IOException("Unsupported DataFlavor: " + df);
|
||||
}
|
||||
|
||||
public Object getContent(DataSource ds) throws IOException {
|
||||
|
||||
if (dch != null)
|
||||
return dch.getContent(ds);
|
||||
else
|
||||
return ds.getInputStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the object to the output stream.
|
||||
*/
|
||||
public void writeTo(Object obj, String mimeType, OutputStream os)
|
||||
throws IOException {
|
||||
if (dch != null)
|
||||
dch.writeTo(obj, mimeType, os);
|
||||
else
|
||||
throw new UnsupportedDataTypeException(
|
||||
"no DCH for content type " + ds.getContentType());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ObjectDataContentHandler
|
||||
*
|
||||
* This is a <i>private</i> DataContentHandler that wraps the real
|
||||
* DataContentHandler in the case where the DataHandler was instantiated
|
||||
* with an object.
|
||||
*/
|
||||
class ObjectDataContentHandler implements DataContentHandler {
|
||||
private ActivationDataFlavor[] transferFlavors = null;
|
||||
private Object obj;
|
||||
private String mimeType;
|
||||
private DataContentHandler dch = null;
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
*/
|
||||
public ObjectDataContentHandler(DataContentHandler dch,
|
||||
Object obj, String mimeType) {
|
||||
this.obj = obj;
|
||||
this.mimeType = mimeType;
|
||||
this.dch = dch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DataContentHandler for this object.
|
||||
* Used only by the DataHandler class.
|
||||
*/
|
||||
public DataContentHandler getDCH() {
|
||||
return dch;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the ActivationDataFlavors for this
|
||||
* <code>DataContentHandler</code>.
|
||||
*
|
||||
* @return the ActivationDataFlavors
|
||||
*/
|
||||
public synchronized ActivationDataFlavor[] getTransferDataFlavors() {
|
||||
if (transferFlavors == null) {
|
||||
if (dch != null) {
|
||||
transferFlavors = dch.getTransferDataFlavors();
|
||||
} else {
|
||||
transferFlavors = new ActivationDataFlavor[1];
|
||||
transferFlavors[0] = new ActivationDataFlavor(obj.getClass(),
|
||||
mimeType, mimeType);
|
||||
}
|
||||
}
|
||||
return transferFlavors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Transfer Data of type ActivationDataFlavor from InputStream.
|
||||
*
|
||||
* @param df the ActivationDataFlavor
|
||||
* @param ds the DataSource
|
||||
* @return the constructed Object
|
||||
*/
|
||||
public Object getTransferData(ActivationDataFlavor df, DataSource ds)
|
||||
throws IOException {
|
||||
|
||||
if (dch != null)
|
||||
return dch.getTransferData(df, ds);
|
||||
else if (df.equals(getTransferDataFlavors()[0])) // only have one now
|
||||
return obj;
|
||||
else
|
||||
throw new IOException("Unsupported DataFlavor: " + df);
|
||||
|
||||
}
|
||||
|
||||
public Object getContent(DataSource ds) {
|
||||
return obj;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write the object to the output stream.
|
||||
*/
|
||||
public void writeTo(Object obj, String mimeType, OutputStream os)
|
||||
throws IOException {
|
||||
if (dch != null)
|
||||
dch.writeTo(obj, mimeType, os);
|
||||
else if (obj instanceof byte[])
|
||||
os.write((byte[]) obj);
|
||||
else if (obj instanceof String) {
|
||||
OutputStreamWriter osw = new OutputStreamWriter(os, Charset.defaultCharset());
|
||||
osw.write((String) obj);
|
||||
osw.flush();
|
||||
} else
|
||||
throw new UnsupportedDataTypeException(
|
||||
"no object DCH for MIME type " + this.mimeType);
|
||||
}
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* The DataSource interface provides Jakarta Activation
|
||||
* with an abstraction of an arbitrary collection of data. It
|
||||
* provides a type for that data as well as access
|
||||
* to it in the form of <code>InputStreams</code> and
|
||||
* <code>OutputStreams</code> where appropriate.
|
||||
*/
|
||||
|
||||
public interface DataSource {
|
||||
|
||||
/**
|
||||
* This method returns an <code>InputStream</code> representing
|
||||
* the data and throws the appropriate exception if it can
|
||||
* not do so. Note that a new <code>InputStream</code> object must be
|
||||
* returned each time this method is called, and the stream must be
|
||||
* positioned at the beginning of the data.
|
||||
*
|
||||
* @return an InputStream
|
||||
* @throws IOException for failures creating the InputStream
|
||||
*/
|
||||
InputStream getInputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* This method returns an <code>OutputStream</code> where the
|
||||
* data can be written and throws the appropriate exception if it can
|
||||
* not do so. Note that a new <code>OutputStream</code> object must
|
||||
* be returned each time this method is called, and the stream must
|
||||
* be positioned at the location the data is to be written.
|
||||
*
|
||||
* @return an OutputStream
|
||||
* @throws IOException for failures creating the OutputStream
|
||||
*/
|
||||
OutputStream getOutputStream() throws IOException;
|
||||
|
||||
/**
|
||||
* This method returns the MIME type of the data in the form of a
|
||||
* string. It should always return a valid type. It is suggested
|
||||
* that getContentType return "application/octet-stream" if the
|
||||
* DataSource implementation can not determine the data type.
|
||||
*
|
||||
* @return the MIME Type
|
||||
*/
|
||||
String getContentType();
|
||||
|
||||
/**
|
||||
* Return the <i>name</i> of this object where the name of the object
|
||||
* is dependant on the nature of the underlying objects. DataSources
|
||||
* encapsulating files may choose to return the filename of the object.
|
||||
* (Typically this would be the last component of the filename, not an
|
||||
* entire pathname.)
|
||||
*
|
||||
* @return the name of the object.
|
||||
*/
|
||||
String getName();
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
class FactoryFinder {
|
||||
|
||||
private static final Logger logger = Logger.getLogger("jakarta.activation");
|
||||
|
||||
private static final ServiceLoaderUtil.ExceptionHandler<RuntimeException> EXCEPTION_HANDLER =
|
||||
new ServiceLoaderUtil.ExceptionHandler<>() {
|
||||
@Override
|
||||
public RuntimeException createException(Throwable throwable, String message) {
|
||||
return new IllegalStateException(message, throwable);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Finds the implementation {@code Class} object for the given
|
||||
* factory type.
|
||||
* <p>
|
||||
* This method is package private so that this code can be shared.
|
||||
*
|
||||
* @param factoryClass factory abstract class or interface to be found
|
||||
* @return the {@code Class} object of the specified message factory;
|
||||
* may not be {@code null}
|
||||
* @throws IllegalStateException if there is no factory found
|
||||
*/
|
||||
static <T> T find(Class<T> factoryClass) throws RuntimeException {
|
||||
for (ClassLoader l : getClassLoaders(Thread.class, FactoryFinder.class, System.class)) {
|
||||
T f = find(factoryClass, l);
|
||||
if (f != null) {
|
||||
return f;
|
||||
}
|
||||
}
|
||||
throw EXCEPTION_HANDLER.createException(null, "Provider for " + factoryClass.getName() + " cannot be found");
|
||||
}
|
||||
|
||||
static <T> T find(Class<T> factoryClass, ClassLoader loader) throws RuntimeException {
|
||||
String className = fromSystemProperty(factoryClass.getName());
|
||||
if (className != null) {
|
||||
T result = newInstance(className, factoryClass, loader);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return ServiceLoaderUtil.firstByServiceLoader(factoryClass, loader, logger, EXCEPTION_HANDLER);
|
||||
}
|
||||
|
||||
private static <T> T newInstance(String className,
|
||||
Class<? extends T> service, ClassLoader loader)
|
||||
throws RuntimeException {
|
||||
return ServiceLoaderUtil.newInstance(className, service, loader, EXCEPTION_HANDLER);
|
||||
}
|
||||
|
||||
private static String fromSystemProperty(String factoryId) {
|
||||
return getSystemProperty(factoryId);
|
||||
}
|
||||
|
||||
private static String getSystemProperty(final String property) {
|
||||
logger.log(Level.FINE, "Checking system property {0}", property);
|
||||
String value = System.getProperty(property);
|
||||
logFound(value);
|
||||
return value;
|
||||
}
|
||||
|
||||
private static void logFound(String value) {
|
||||
if (value != null) {
|
||||
logger.log(Level.FINE, " found {0}", value);
|
||||
} else {
|
||||
logger.log(Level.FINE, " not found");
|
||||
}
|
||||
}
|
||||
|
||||
private static ClassLoader[] getClassLoaders(final Class<?>... classes) {
|
||||
ClassLoader[] loaders = new ClassLoader[classes.length];
|
||||
int w = 0;
|
||||
for (Class<?> k : classes) {
|
||||
ClassLoader cl = null;
|
||||
if (k == Thread.class) {
|
||||
cl = Thread.currentThread().getContextClassLoader();
|
||||
} else if (k == System.class) {
|
||||
cl = ClassLoader.getSystemClassLoader();
|
||||
} else {
|
||||
cl = k.getClassLoader();
|
||||
}
|
||||
if (cl != null) {
|
||||
loaders[w++] = cl;
|
||||
}
|
||||
}
|
||||
if (loaders.length != w) {
|
||||
loaders = Arrays.copyOf(loaders, w);
|
||||
}
|
||||
return loaders;
|
||||
}
|
||||
}
|
|
@ -1,167 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
|
||||
/**
|
||||
* The FileDataSource class implements a simple DataSource object
|
||||
* that encapsulates a file. It provides data typing services via
|
||||
* a FileTypeMap object. <p>
|
||||
*
|
||||
* <b>FileDataSource Typing Semantics</b><p>
|
||||
* <p>
|
||||
* The FileDataSource class delegates data typing of files
|
||||
* to an object subclassed from the FileTypeMap class.
|
||||
* The <code>setFileTypeMap</code> method can be used to explicitly
|
||||
* set the FileTypeMap for an instance of FileDataSource. If no
|
||||
* FileTypeMap is set, the FileDataSource will call the FileTypeMap's
|
||||
* getDefaultFileTypeMap method to get the System's default FileTypeMap.
|
||||
* <p>
|
||||
* <b>API Note:</b>
|
||||
* It is recommended to construct a {@code FileDataSource} using a {@code Path}
|
||||
* instead of using a {@code File} since {@code Path} contains enhanced functionality.
|
||||
*
|
||||
* @see DataSource
|
||||
* @see FileTypeMap
|
||||
* @see MimetypesFileTypeMap
|
||||
*/
|
||||
public class FileDataSource implements DataSource {
|
||||
|
||||
// keep track of original 'ref' passed in, non-null
|
||||
// one indicated which was passed in:
|
||||
private Path _path = null;
|
||||
private FileTypeMap typeMap = null;
|
||||
|
||||
/**
|
||||
* Creates a FileDataSource from a File object. <i>Note:
|
||||
* The file will not actually be opened until a method is
|
||||
* called that requires the file to be opened.</i>
|
||||
* <p>
|
||||
* <b>API Note:</b>
|
||||
* {@code FileDataSource(Path)} constructor should be preferred over this one.
|
||||
*
|
||||
* @param file the file
|
||||
*/
|
||||
public FileDataSource(File file) {
|
||||
_path = file.toPath(); // save the file Object...
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a FileDataSource from a Path object. <i>Note: The file will not
|
||||
* actually be opened until a method is called that requires the file to be
|
||||
* opened.</i>
|
||||
*
|
||||
* @param path the file
|
||||
*/
|
||||
public FileDataSource(Path path) {
|
||||
_path = path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a FileDataSource from
|
||||
* the specified path name. <i>Note:
|
||||
* The file will not actually be opened until a method is
|
||||
* called that requires the file to be opened.</i>
|
||||
*
|
||||
* @param name the system-dependent file name.
|
||||
*/
|
||||
public FileDataSource(String name) {
|
||||
this(Paths.get(name)); // use the file constructor
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return an InputStream representing the
|
||||
* the data and will throw an IOException if it can
|
||||
* not do so. This method will return a new
|
||||
* instance of InputStream with each invocation.
|
||||
*
|
||||
* @return an InputStream
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return Files.newInputStream(_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return an OutputStream representing the
|
||||
* the data and will throw an IOException if it can
|
||||
* not do so. This method will return a new instance of
|
||||
* OutputStream with each invocation.
|
||||
*
|
||||
* @return an OutputStream
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
return Files.newOutputStream(_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns the MIME type of the data in the form of a
|
||||
* string. This method uses the currently installed FileTypeMap. If
|
||||
* there is no FileTypeMap explicitly set, the FileDataSource will
|
||||
* call the <code>getDefaultFileTypeMap</code> method on
|
||||
* FileTypeMap to acquire a default FileTypeMap. <i>Note: By
|
||||
* default, the FileTypeMap used will be a MimetypesFileTypeMap.</i>
|
||||
*
|
||||
* @return the MIME Type
|
||||
* @see FileTypeMap#getDefaultFileTypeMap
|
||||
*/
|
||||
public String getContentType() {
|
||||
// check to see if the type map is null?
|
||||
if (typeMap == null)
|
||||
return FileTypeMap.getDefaultFileTypeMap().getContentType(_path);
|
||||
else
|
||||
return typeMap.getContentType(_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the <i>name</i> of this object. The FileDataSource
|
||||
* will return the file name of the object.
|
||||
*
|
||||
* @return the name of the object.
|
||||
* @see DataSource
|
||||
*/
|
||||
public String getName() {
|
||||
return _path.getFileName().toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the File object that corresponds to this FileDataSource.
|
||||
*
|
||||
* @return the File object for the file represented by this object.
|
||||
*/
|
||||
public File getFile() {
|
||||
return _path.toFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Path object that corresponds to this FileDataSource.
|
||||
*
|
||||
* @return the Path object for the file represented by this object.
|
||||
*/
|
||||
public Path getPath() {
|
||||
return _path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the FileTypeMap to use with this FileDataSource
|
||||
*
|
||||
* @param map The FileTypeMap for this object.
|
||||
*/
|
||||
public void setFileTypeMap(FileTypeMap map) {
|
||||
typeMap = map;
|
||||
}
|
||||
}
|
|
@ -1,106 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* The FileTypeMap is an abstract class that provides a data typing
|
||||
* interface for files. Implementations of this class will
|
||||
* implement the getContentType methods which will derive a content
|
||||
* type from a file name or a File object. FileTypeMaps could use any
|
||||
* scheme to determine the data type, from examining the file extension
|
||||
* of a file (like the MimetypesFileTypeMap) to opening the file and
|
||||
* trying to derive its type from the contents of the file. The
|
||||
* FileDataSource class uses the default FileTypeMap (a MimetypesFileTypeMap
|
||||
* unless changed) to determine the content type of files.
|
||||
*
|
||||
* @see FileTypeMap
|
||||
* @see FileDataSource
|
||||
* @see MimetypesFileTypeMap
|
||||
*/
|
||||
|
||||
public abstract class FileTypeMap {
|
||||
|
||||
private static FileTypeMap defaultMap = null;
|
||||
|
||||
private static Map<ClassLoader, FileTypeMap> map = new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* The default constructor.
|
||||
*/
|
||||
public FileTypeMap() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default FileTypeMap for the system.
|
||||
* If setDefaultFileTypeMap was called, return
|
||||
* that instance, otherwise return an instance of
|
||||
* <code>MimetypesFileTypeMap</code>.
|
||||
*
|
||||
* @return The default FileTypeMap
|
||||
* @see FileTypeMap#setDefaultFileTypeMap
|
||||
*/
|
||||
public static synchronized FileTypeMap getDefaultFileTypeMap() {
|
||||
if (defaultMap != null) {
|
||||
return defaultMap;
|
||||
}
|
||||
ClassLoader tccl = Util.getContextClassLoader();
|
||||
FileTypeMap def = map.get(tccl);
|
||||
if (def == null) {
|
||||
def = new MimetypesFileTypeMap();
|
||||
map.put(tccl, def);
|
||||
}
|
||||
return def;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default FileTypeMap for the system. This instance
|
||||
* will be returned to callers of getDefaultFileTypeMap.
|
||||
*
|
||||
* @param fileTypeMap The FileTypeMap.
|
||||
*/
|
||||
public static synchronized void setDefaultFileTypeMap(FileTypeMap fileTypeMap) {
|
||||
map.remove(Util.getContextClassLoader());
|
||||
defaultMap = fileTypeMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of the file object. This method should
|
||||
* always return a valid MIME type.
|
||||
*
|
||||
* @param file A file to be typed.
|
||||
* @return The content type.
|
||||
*/
|
||||
abstract public String getContentType(File file);
|
||||
|
||||
/**
|
||||
* Return the type of the file Path object. This method should
|
||||
* always return a valid MIME type.
|
||||
*
|
||||
* @param path A file Path to be typed.
|
||||
* @return The content type.
|
||||
*/
|
||||
abstract public String getContentType(Path path);
|
||||
|
||||
/**
|
||||
* Return the type of the file passed in. This method should
|
||||
* always return a valid MIME type.
|
||||
*
|
||||
* @param filename the pathname of the file.
|
||||
* @return The content type.
|
||||
*/
|
||||
abstract public String getContentType(String filename);
|
||||
}
|
|
@ -1,667 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2024 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import jakarta.activation.spi.MailcapRegistryProvider;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.ServiceConfigurationError;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* MailcapCommandMap extends the CommandMap
|
||||
* abstract class. It implements a CommandMap whose configuration
|
||||
* is based on mailcap files
|
||||
* (<A HREF="http://www.ietf.org/rfc/rfc1524.txt">RFC 1524</A>).
|
||||
* The MailcapCommandMap can be configured both programmatically
|
||||
* and via configuration files.
|
||||
* <p>
|
||||
* <b>Mailcap file search order:</b><p>
|
||||
* The MailcapCommandMap looks in various places in the user's
|
||||
* system for mailcap file entries. When requests are made
|
||||
* to search for commands in the MailcapCommandMap, it searches
|
||||
* mailcap files in the following order:
|
||||
* <ol>
|
||||
* <li> Programatically added entries to the MailcapCommandMap instance.
|
||||
* <li> The file <code>.mailcap</code> in the user's home directory.
|
||||
* <li> The file <code>mailcap</code> in the Java runtime.
|
||||
* <li> The file or resources named <code>META-INF/mailcap</code>.
|
||||
* <li> The file or resource named <code>META-INF/mailcap.default</code>
|
||||
* (usually found only in the <code>activation.jar</code> file).
|
||||
* </ol>
|
||||
* <p>
|
||||
* (The current implementation looks for the <code>mailcap</code> file
|
||||
* in the Java runtime in the directory <code><i>java.home</i>/conf</code>
|
||||
* if it exists, and otherwise in the directory
|
||||
* <code><i>java.home</i>/lib</code>, where <i>java.home</i> is the value
|
||||
* of the "java.home" System property. Note that the "conf" directory was
|
||||
* introduced in JDK 9.)
|
||||
* <p>
|
||||
* <b>Mailcap file format:</b><p>
|
||||
* <p>
|
||||
* Mailcap files must conform to the mailcap
|
||||
* file specification (RFC 1524, <i>A User Agent Configuration Mechanism
|
||||
* For Multimedia Mail Format Information</i>).
|
||||
* The file format consists of entries corresponding to
|
||||
* particular MIME types. In general, the specification
|
||||
* specifies <i>applications</i> for clients to use when they
|
||||
* themselves cannot operate on the specified MIME type. The
|
||||
* MailcapCommandMap extends this specification by using a parameter mechanism
|
||||
* in mailcap files that allows JavaBeans(tm) components to be specified as
|
||||
* corresponding to particular commands for a MIME type.<p>
|
||||
* <p>
|
||||
* When a mailcap file is
|
||||
* parsed, the MailcapCommandMap recognizes certain parameter signatures,
|
||||
* specifically those parameter names that begin with <code>x-java-</code>.
|
||||
* The MailcapCommandMap uses this signature to find
|
||||
* command entries for inclusion into its registries.
|
||||
* Parameter names with the form <code>x-java-<name></code>
|
||||
* are read by the MailcapCommandMap as identifying a command
|
||||
* with the name <i>name</i>. When the <i>name</i> is <code>
|
||||
* content-handler</code> the MailcapCommandMap recognizes the class
|
||||
* signified by this parameter as a <i>DataContentHandler</i>.
|
||||
* All other commands are handled generically regardless of command
|
||||
* name. The command implementation is specified by a fully qualified
|
||||
* class name of a JavaBean(tm) component. For example; a command for viewing
|
||||
* some data can be specified as: <code>x-java-view=com.foo.ViewBean</code>.<p>
|
||||
* <p>
|
||||
* When the command name is <code>fallback-entry</code>, the value of
|
||||
* the command may be <code>true</code> or <code>false</code>. An
|
||||
* entry for a MIME type that includes a parameter of
|
||||
* <code>x-java-fallback-entry=true</code> defines fallback commands
|
||||
* for that MIME type that will only be used if no non-fallback entry
|
||||
* can be found. For example, an entry of the form <code>text/*; ;
|
||||
* x-java-fallback-entry=true; x-java-view=com.sun.TextViewer</code>
|
||||
* specifies a view command to be used for any text MIME type. This
|
||||
* view command would only be used if a non-fallback view command for
|
||||
* the MIME type could not be found.<p>
|
||||
* <p>
|
||||
* MailcapCommandMap aware mailcap files have the
|
||||
* following general form:<p>
|
||||
* <code>
|
||||
* # Comments begin with a '#' and continue to the end of the line.<br>
|
||||
* <mime type>; ; <parameter list><br>
|
||||
* # Where a parameter list consists of one or more parameters,<br>
|
||||
* # where parameters look like: x-java-view=com.sun.TextViewer<br>
|
||||
* # and a parameter list looks like: <br>
|
||||
* text/plain; ; x-java-view=com.sun.TextViewer; x-java-edit=com.sun.TextEdit
|
||||
* <br>
|
||||
* # Note that mailcap entries that do not contain 'x-java' parameters<br>
|
||||
* # and comply to RFC 1524 are simply ignored:<br>
|
||||
* image/gif; /usr/dt/bin/sdtimage %s<br>
|
||||
*
|
||||
* </code>
|
||||
*
|
||||
* @author Bart Calder
|
||||
* @author Bill Shannon
|
||||
*/
|
||||
|
||||
public class MailcapCommandMap extends CommandMap {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MailcapCommandMap.class.getName());
|
||||
|
||||
private static final int PROG = 0; // programmatically added entries
|
||||
private static final String confDir;
|
||||
|
||||
static {
|
||||
String dir = null;
|
||||
String home = System.getProperty("java.home");
|
||||
String newdir = home + File.separator + "conf";
|
||||
File conf = new File(newdir);
|
||||
if (conf.exists())
|
||||
dir = newdir + File.separator;
|
||||
else
|
||||
dir = home + File.separator + "lib" + File.separator;
|
||||
confDir = dir;
|
||||
}
|
||||
|
||||
/*
|
||||
* We manage a collection of databases, searched in order.
|
||||
*/
|
||||
private MailcapRegistry[] DB;
|
||||
|
||||
/**
|
||||
* The default Constructor.
|
||||
*/
|
||||
public MailcapCommandMap() {
|
||||
super();
|
||||
List<MailcapRegistry> dbv = new ArrayList<>(5); // usually 5 or less databases
|
||||
MailcapRegistry mf = null;
|
||||
dbv.add(null); // place holder for PROG entry
|
||||
|
||||
logger.log(Level.FINE, "MailcapCommandMap: load HOME");
|
||||
String user_home = System.getProperty("user.home");
|
||||
|
||||
if (user_home != null) {
|
||||
String path = user_home + File.separator + ".mailcap";
|
||||
mf = loadFile(path);
|
||||
if (mf != null)
|
||||
dbv.add(mf);
|
||||
}
|
||||
|
||||
logger.log(Level.FINE, "MailcapCommandMap: load SYS");
|
||||
// check system's home
|
||||
if (confDir != null) {
|
||||
mf = loadFile(confDir + "mailcap");
|
||||
if (mf != null)
|
||||
dbv.add(mf);
|
||||
}
|
||||
|
||||
logger.log(Level.FINE, "MailcapCommandMap: load JAR");
|
||||
// load from the app's jar file
|
||||
loadAllResources(dbv, "META-INF/mailcap");
|
||||
|
||||
logger.log(Level.FINE, "MailcapCommandMap: load DEF");
|
||||
mf = loadResource("/META-INF/mailcap.default");
|
||||
|
||||
if (mf != null)
|
||||
dbv.add(mf);
|
||||
|
||||
DB = new MailcapRegistry[dbv.size()];
|
||||
DB = dbv.toArray(DB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows the caller to specify the path
|
||||
* of a <i>mailcap</i> file.
|
||||
*
|
||||
* @param fileName The name of the <i>mailcap</i> file to open
|
||||
* @throws IOException if the file can't be accessed
|
||||
*/
|
||||
public MailcapCommandMap(String fileName) throws IOException {
|
||||
this();
|
||||
if (DB[PROG] == null) {
|
||||
try {
|
||||
DB[PROG] = getImplementation().getByFileName(fileName);
|
||||
} catch (NoSuchElementException | IllegalStateException | ServiceConfigurationError e) {
|
||||
String message = "Cannot find or load an implementation for MailcapRegistryProvider. " +
|
||||
"MailcapRegistry: can't load " + fileName;
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.log(Level.FINE, message, e);
|
||||
}
|
||||
throw new IOException(message, e);
|
||||
}
|
||||
}
|
||||
if (DB[PROG] != null && logger.isLoggable(Level.FINE)) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: load PROG from " + fileName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that allows the caller to specify an <i>InputStream</i>
|
||||
* containing a mailcap file.
|
||||
*
|
||||
* @param is InputStream of the <i>mailcap</i> file to open
|
||||
*/
|
||||
public MailcapCommandMap(InputStream is) {
|
||||
this();
|
||||
|
||||
if (DB[PROG] == null) {
|
||||
try {
|
||||
DB[PROG] = getImplementation().getByInputStream(is);
|
||||
} catch (IOException ex) {
|
||||
// XXX - should throw it
|
||||
} catch (NoSuchElementException | IllegalStateException | ServiceConfigurationError e) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.log(Level.FINE, "Cannot find or load an implementation for MailcapRegistryProvider." +
|
||||
"MailcapRegistry: can't load InputStream", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (DB[PROG] != null && logger.isLoggable(Level.FINE)) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: load PROG");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from the named resource.
|
||||
*/
|
||||
private MailcapRegistry loadResource(String name) {
|
||||
try (InputStream clis = Util.getResourceAsStream(this.getClass(), name)) {
|
||||
if (clis != null) {
|
||||
MailcapRegistry mf = getImplementation().getByInputStream(clis);
|
||||
logger.log(Level.FINE, "MailcapCommandMap: successfully loaded " +
|
||||
"mailcap file: " + name);
|
||||
return mf;
|
||||
} else {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: not loading " +
|
||||
"mailcap file: " + name);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: can't load " + name, e);
|
||||
} catch (NoSuchElementException | IllegalStateException | ServiceConfigurationError e) {
|
||||
logger.log(Level.FINE, "Cannot find or load an implementation for MailcapRegistryProvider. " +
|
||||
"MailcapRegistry: can't load " + name, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all of the named resource.
|
||||
*/
|
||||
private void loadAllResources(List<MailcapRegistry> v, String name) {
|
||||
boolean anyLoaded = false;
|
||||
try {
|
||||
URL[] urls;
|
||||
ClassLoader cld = null;
|
||||
// First try the "application's" class loader.
|
||||
cld = Util.getContextClassLoader();
|
||||
if (cld == null)
|
||||
cld = this.getClass().getClassLoader();
|
||||
if (cld != null)
|
||||
urls = Util.getResources(cld, name);
|
||||
else
|
||||
urls = Util.getSystemResources(name);
|
||||
if (urls != null) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: getResources");
|
||||
for (int i = 0; i < urls.length; i++) {
|
||||
URL url = urls[i];
|
||||
logger.log(Level.FINE, "MailcapCommandMap: URL " + url);
|
||||
try (InputStream clis = Util.openStream(url)) {
|
||||
if (clis != null) {
|
||||
v.add(getImplementation().getByInputStream(clis));
|
||||
anyLoaded = true;
|
||||
logger.log(Level.FINE, "MailcapCommandMap: " +
|
||||
"successfully loaded " +
|
||||
"mailcap file from URL: " +
|
||||
url);
|
||||
} else {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: " +
|
||||
"not loading mailcap " +
|
||||
"file from URL: " + url);
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: can't load " +
|
||||
url, ioex);
|
||||
} catch (NoSuchElementException | IllegalStateException | ServiceConfigurationError e) {
|
||||
logger.log(Level.FINE, "Cannot find or load an implementation for MailcapRegistryProvider. " +
|
||||
"MailcapRegistry: can't load " + name, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: can't load " + name, ex);
|
||||
}
|
||||
|
||||
// if failed to load anything, fall back to old technique, just in case
|
||||
if (!anyLoaded) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: !anyLoaded");
|
||||
MailcapRegistry mf = loadResource("/" + name);
|
||||
if (mf != null)
|
||||
v.add(mf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from the named file.
|
||||
*/
|
||||
private MailcapRegistry loadFile(String name) {
|
||||
MailcapRegistry mtf = null;
|
||||
|
||||
try {
|
||||
mtf = getImplementation().getByFileName(name);
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.FINE, "MailcapRegistry: can't load from file - " + name, e);
|
||||
} catch (NoSuchElementException | IllegalStateException | ServiceConfigurationError e) {
|
||||
logger.log(Level.FINE, "Cannot find or load an implementation for MailcapRegistryProvider. " +
|
||||
"MailcapRegistry: can't load " + name, e);
|
||||
}
|
||||
return mtf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the preferred command list for a MIME Type. The MailcapCommandMap
|
||||
* searches the mailcap files as described above under
|
||||
* <i>Mailcap file search order</i>.<p>
|
||||
* <p>
|
||||
* The result of the search is a proper subset of available
|
||||
* commands in all mailcap files known to this instance of
|
||||
* MailcapCommandMap. The first entry for a particular command
|
||||
* is considered the preferred command.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @return the CommandInfo objects representing the preferred commands.
|
||||
*/
|
||||
public synchronized CommandInfo[] getPreferredCommands(String mimeType) {
|
||||
List<CommandInfo> cmdList = new ArrayList<>();
|
||||
if (mimeType != null)
|
||||
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
continue;
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapList(mimeType);
|
||||
if (cmdMap != null)
|
||||
appendPrefCmdsToList(cmdMap, cmdList);
|
||||
}
|
||||
|
||||
// now add the fallback commands
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
continue;
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapFallbackList(mimeType);
|
||||
if (cmdMap != null)
|
||||
appendPrefCmdsToList(cmdMap, cmdList);
|
||||
}
|
||||
|
||||
CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()];
|
||||
cmdInfos = cmdList.toArray(cmdInfos);
|
||||
|
||||
return cmdInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the commands that are in the hash table, into the list.
|
||||
*/
|
||||
private void appendPrefCmdsToList(Map<String, List<String>> cmdHash, List<CommandInfo> cmdList) {
|
||||
Iterator<String> verb_enum = cmdHash.keySet().iterator();
|
||||
|
||||
while (verb_enum.hasNext()) {
|
||||
String verb = verb_enum.next();
|
||||
if (!checkForVerb(cmdList, verb)) {
|
||||
List<String> cmdList2 = cmdHash.get(verb); // get the list
|
||||
String className = cmdList2.get(0);
|
||||
cmdList.add(new CommandInfo(verb, className));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the cmdList to see if this command exists, return
|
||||
* true if the verb is there.
|
||||
*/
|
||||
private boolean checkForVerb(List<CommandInfo> cmdList, String verb) {
|
||||
Iterator<CommandInfo> ee = cmdList.iterator();
|
||||
while (ee.hasNext()) {
|
||||
String enum_verb = (ee.next()).getCommandName();
|
||||
if (enum_verb.equals(verb))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the available commands in all mailcap files known to
|
||||
* this instance of MailcapCommandMap for this MIME type.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @return the CommandInfo objects representing all the commands.
|
||||
*/
|
||||
public synchronized CommandInfo[] getAllCommands(String mimeType) {
|
||||
List<CommandInfo> cmdList = new ArrayList<>();
|
||||
if (mimeType != null)
|
||||
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
continue;
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapList(mimeType);
|
||||
if (cmdMap != null)
|
||||
appendCmdsToList(cmdMap, cmdList);
|
||||
}
|
||||
|
||||
// now add the fallback commands
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
continue;
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapFallbackList(mimeType);
|
||||
if (cmdMap != null)
|
||||
appendCmdsToList(cmdMap, cmdList);
|
||||
}
|
||||
|
||||
CommandInfo[] cmdInfos = new CommandInfo[cmdList.size()];
|
||||
cmdInfos = cmdList.toArray(cmdInfos);
|
||||
|
||||
return cmdInfos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Put the commands that are in the hash table, into the list.
|
||||
*/
|
||||
private void appendCmdsToList(Map<String, List<String>> typeHash, List<CommandInfo> cmdList) {
|
||||
Iterator<String> verb_enum = typeHash.keySet().iterator();
|
||||
|
||||
while (verb_enum.hasNext()) {
|
||||
String verb = verb_enum.next();
|
||||
List<String> cmdList2 = typeHash.get(verb);
|
||||
Iterator<String> cmd_enum = cmdList2.iterator();
|
||||
|
||||
while (cmd_enum.hasNext()) {
|
||||
String cmd = cmd_enum.next();
|
||||
cmdList.add(new CommandInfo(verb, cmd));
|
||||
// cmdList.add(0, new CommandInfo(verb, cmd));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the command corresponding to <code>cmdName</code> for the MIME type.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @param cmdName the command name
|
||||
* @return the CommandInfo object corresponding to the command.
|
||||
*/
|
||||
public synchronized CommandInfo getCommand(String mimeType,
|
||||
String cmdName) {
|
||||
if (mimeType != null)
|
||||
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
continue;
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapList(mimeType);
|
||||
if (cmdMap != null) {
|
||||
// get the cmd list for the cmd
|
||||
List<String> v = cmdMap.get(cmdName);
|
||||
if (v != null) {
|
||||
String cmdClassName = v.get(0);
|
||||
|
||||
if (cmdClassName != null)
|
||||
return new CommandInfo(cmdName, cmdClassName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now try the fallback list
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
continue;
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapFallbackList(mimeType);
|
||||
if (cmdMap != null) {
|
||||
// get the cmd list for the cmd
|
||||
List<String> v = cmdMap.get(cmdName);
|
||||
if (v != null) {
|
||||
String cmdClassName = v.get(0);
|
||||
|
||||
if (cmdClassName != null)
|
||||
return new CommandInfo(cmdName, cmdClassName);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add entries to the registry. Programmatically
|
||||
* added entries are searched before other entries.<p>
|
||||
* <p>
|
||||
* The string that is passed in should be in mailcap
|
||||
* format.
|
||||
*
|
||||
* @param mail_cap a correctly formatted mailcap string
|
||||
*/
|
||||
public synchronized void addMailcap(String mail_cap) {
|
||||
// check to see if one exists
|
||||
logger.log(Level.FINE, "MailcapCommandMap: add to PROG");
|
||||
try {
|
||||
if (DB[PROG] == null) {
|
||||
DB[PROG] = getImplementation().getInMemory();
|
||||
}
|
||||
DB[PROG].appendToMailcap(mail_cap);
|
||||
} catch (NoSuchElementException | IllegalStateException | ServiceConfigurationError e) {
|
||||
logger.log(Level.FINE, "Cannot find or load an implementation for MailcapRegistryProvider. " +
|
||||
"MailcapRegistry: can't load", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the DataContentHandler for the specified MIME type.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @return the DataContentHandler
|
||||
*/
|
||||
public synchronized DataContentHandler createDataContentHandler(
|
||||
String mimeType) {
|
||||
logger.log(Level.FINE, "MailcapCommandMap: createDataContentHandler for " + mimeType);
|
||||
if (mimeType != null)
|
||||
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
||||
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
continue;
|
||||
logger.log(Level.FINE, " search DB #" + i);
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapList(mimeType);
|
||||
if (cmdMap != null) {
|
||||
List<String> v = cmdMap.get("content-handler");
|
||||
if (v != null) {
|
||||
String name = v.get(0);
|
||||
DataContentHandler dch = getDataContentHandler(name);
|
||||
if (dch != null)
|
||||
return dch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// now try the fallback entries
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
continue;
|
||||
logger.log(Level.FINE, " search fallback DB #" + i);
|
||||
Map<String, List<String>> cmdMap = DB[i].getMailcapFallbackList(mimeType);
|
||||
if (cmdMap != null) {
|
||||
List<String> v = cmdMap.get("content-handler");
|
||||
if (v != null) {
|
||||
String name = v.get(0);
|
||||
DataContentHandler dch = getDataContentHandler(name);
|
||||
if (dch != null)
|
||||
return dch;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private DataContentHandler getDataContentHandler(String name) {
|
||||
logger.log(Level.FINE, " got content-handler");
|
||||
logger.log(Level.FINE, " class " + name);
|
||||
try {
|
||||
ClassLoader cld = null;
|
||||
// First try the "application's" class loader.
|
||||
cld = Util.getContextClassLoader();
|
||||
if (cld == null)
|
||||
cld = this.getClass().getClassLoader();
|
||||
Class<?> cl = null;
|
||||
try {
|
||||
cl = cld.loadClass(name);
|
||||
} catch (Exception ex) {
|
||||
// if anything goes wrong, do it the old way
|
||||
cl = Class.forName(name);
|
||||
}
|
||||
if (cl != null) // XXX - always true?
|
||||
return (DataContentHandler)
|
||||
cl.getConstructor().newInstance();
|
||||
} catch (ReflectiveOperationException e) {
|
||||
logger.log(Level.FINE, "Can't load DCH " + name, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the MIME types known to this command map.
|
||||
*
|
||||
* @return array of MIME types as strings
|
||||
* @since JAF 1.1
|
||||
*/
|
||||
public synchronized String[] getMimeTypes() {
|
||||
List<String> mtList = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < DB.length; i++) {
|
||||
if (DB[i] == null)
|
||||
continue;
|
||||
String[] ts = DB[i].getMimeTypes();
|
||||
if (ts != null) {
|
||||
for (int j = 0; j < ts.length; j++) {
|
||||
// eliminate duplicates
|
||||
if (!mtList.contains(ts[j]))
|
||||
mtList.add(ts[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
String[] mts = new String[mtList.size()];
|
||||
mts = mtList.toArray(mts);
|
||||
|
||||
return mts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the native commands for the given MIME type.
|
||||
* Returns an array of strings where each string is
|
||||
* an entire mailcap file entry. The application
|
||||
* will need to parse the entry to extract the actual
|
||||
* command as well as any attributes it needs. See
|
||||
* <A HREF="http://www.ietf.org/rfc/rfc1524.txt">RFC 1524</A>
|
||||
* for details of the mailcap entry syntax. Only mailcap
|
||||
* entries that specify a view command for the specified
|
||||
* MIME type are returned.
|
||||
*
|
||||
* @param mimeType the MIME type
|
||||
* @return array of native command entries
|
||||
* @since JAF 1.1
|
||||
*/
|
||||
public synchronized String[] getNativeCommands(String mimeType) {
|
||||
List<String> cmdList = new ArrayList<>();
|
||||
if (mimeType != null) {
|
||||
mimeType = mimeType.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
for (MailcapRegistry mailcapRegistry : DB) {
|
||||
if (mailcapRegistry == null) {
|
||||
continue;
|
||||
}
|
||||
String[] cmds = mailcapRegistry.getNativeCommands(mimeType);
|
||||
if (cmds != null) {
|
||||
for (String cmd : cmds) {
|
||||
if (!cmdList.contains(cmd)) {
|
||||
cmdList.add(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
String[] cmds = new String[cmdList.size()];
|
||||
cmds = cmdList.toArray(cmds);
|
||||
|
||||
return cmds;
|
||||
}
|
||||
|
||||
private MailcapRegistryProvider getImplementation() {
|
||||
return FactoryFinder.find(MailcapRegistryProvider.class);
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* The MailcapRegistry interface is implemented by objects that can
|
||||
* be used to store and retrieve MailcapEntries.
|
||||
* <p>
|
||||
* Application must implement {@link jakarta.activation.spi.MailcapRegistryProvider}
|
||||
* to create new instances of the MailcapRegistry. Implementation of the MailcapRegistry
|
||||
* can store MailcapEntries in different ways and that storage must be accessible through the
|
||||
* {@link jakarta.activation.spi.MailcapRegistryProvider} methods.
|
||||
* Implementation of the MailcapRegistry must contain in-memory storage for MailcapEntries.
|
||||
*/
|
||||
public interface MailcapRegistry {
|
||||
|
||||
/**
|
||||
* Get the Map of MailcapEntries based on the MIME type.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Semantics:</strong> First check for the literal mime type,
|
||||
* if that fails looks for wildcard <type>/\* and return that.
|
||||
* Return the list of all that hit.
|
||||
*
|
||||
* @param mime_type the MIME type
|
||||
* @return the map of MailcapEntries
|
||||
*/
|
||||
Map<String, List<String>> getMailcapList(String mime_type);
|
||||
|
||||
/**
|
||||
* Get the Map of fallback MailcapEntries based on the MIME type.
|
||||
*
|
||||
* <p>
|
||||
* <strong>Semantics:</strong> First check for the literal mime type,
|
||||
* if that fails looks for wildcard <type>/\* and return that.
|
||||
* Return the list of all that hit.
|
||||
*
|
||||
* @param mime_type the MIME type
|
||||
* @return the map of fallback MailcapEntries
|
||||
*/
|
||||
Map<String, List<String>> getMailcapFallbackList(String mime_type);
|
||||
|
||||
/**
|
||||
* Return all the MIME types known to this mailcap file.
|
||||
*
|
||||
* @return a String array of the MIME types
|
||||
*/
|
||||
String[] getMimeTypes();
|
||||
|
||||
/**
|
||||
* Return all the native comands for the given MIME type.
|
||||
*
|
||||
* @param mime_type the MIME type
|
||||
* @return a String array of the commands
|
||||
*/
|
||||
String[] getNativeCommands(String mime_type);
|
||||
|
||||
/**
|
||||
* appendToMailcap: Append to this Mailcap DB, use the mailcap
|
||||
* format:
|
||||
* Comment == "# <i>comment string</i>"
|
||||
* Entry == "mimetype; javabeanclass"
|
||||
* <p>
|
||||
* Example:
|
||||
* # this is a comment
|
||||
* image/gif jaf.viewers.ImageViewer
|
||||
*
|
||||
* @param mail_cap the mailcap string
|
||||
*/
|
||||
void appendToMailcap(String mail_cap);
|
||||
}
|
|
@ -1,275 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A Multipurpose Internet Mail Extension (MIME) type, as defined
|
||||
* in RFC 2045 and 2046.
|
||||
*/
|
||||
public class MimeType {
|
||||
|
||||
/**
|
||||
* A string that holds all the special chars.
|
||||
*/
|
||||
private static final String TSPECIALS = "()<>@,;:/[]?=\\\"";
|
||||
private String primaryType;
|
||||
private String subType;
|
||||
private MimeTypeParameterList parameters;
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public MimeType() {
|
||||
primaryType = "application";
|
||||
subType = "*";
|
||||
parameters = new MimeTypeParameterList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that builds a MimeType from a String.
|
||||
*
|
||||
* @param rawdata the MIME type string
|
||||
* @throws MimeTypeParseException if the MIME type can't be parsed
|
||||
*/
|
||||
public MimeType(String rawdata) throws MimeTypeParseException {
|
||||
parse(rawdata);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that builds a MimeType with the given primary and sub type
|
||||
* but has an empty parameter list.
|
||||
*
|
||||
* @param primary the primary MIME type
|
||||
* @param sub the MIME sub-type
|
||||
* @throws MimeTypeParseException if the primary type or subtype
|
||||
* is not a valid token
|
||||
*/
|
||||
public MimeType(String primary, String sub) throws MimeTypeParseException {
|
||||
// check to see if primary is valid
|
||||
if (isValidToken(primary)) {
|
||||
primaryType = primary.toLowerCase(Locale.ENGLISH);
|
||||
} else {
|
||||
throw new MimeTypeParseException("Primary type is invalid.");
|
||||
}
|
||||
|
||||
// check to see if sub is valid
|
||||
if (isValidToken(sub)) {
|
||||
subType = sub.toLowerCase(Locale.ENGLISH);
|
||||
} else {
|
||||
throw new MimeTypeParseException("Sub type is invalid.");
|
||||
}
|
||||
|
||||
parameters = new MimeTypeParameterList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether or not a given character belongs to a legal token.
|
||||
*/
|
||||
private static boolean isTokenChar(char c) {
|
||||
return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* A routine for parsing the MIME type out of a String.
|
||||
*/
|
||||
private void parse(String rawdata) throws MimeTypeParseException {
|
||||
int slashIndex = rawdata.indexOf('/');
|
||||
int semIndex = rawdata.indexOf(';');
|
||||
if ((slashIndex < 0) && (semIndex < 0)) {
|
||||
// neither character is present, so treat it
|
||||
// as an error
|
||||
throw new MimeTypeParseException("Unable to find a sub type.");
|
||||
} else if ((slashIndex < 0) && (semIndex >= 0)) {
|
||||
// we have a ';' (and therefore a parameter list),
|
||||
// but no '/' indicating a sub type is present
|
||||
throw new MimeTypeParseException("Unable to find a sub type.");
|
||||
} else if ((slashIndex >= 0) && (semIndex < 0)) {
|
||||
// we have a primary and sub type but no parameter list
|
||||
primaryType = rawdata.substring(0, slashIndex).trim().
|
||||
toLowerCase(Locale.ENGLISH);
|
||||
subType = rawdata.substring(slashIndex + 1).trim().
|
||||
toLowerCase(Locale.ENGLISH);
|
||||
parameters = new MimeTypeParameterList();
|
||||
} else if (slashIndex < semIndex) {
|
||||
// we have all three items in the proper sequence
|
||||
primaryType = rawdata.substring(0, slashIndex).trim().
|
||||
toLowerCase(Locale.ENGLISH);
|
||||
subType = rawdata.substring(slashIndex + 1, semIndex).trim().
|
||||
toLowerCase(Locale.ENGLISH);
|
||||
parameters = new MimeTypeParameterList(rawdata.substring(semIndex));
|
||||
} else {
|
||||
// we have a ';' lexically before a '/' which means we
|
||||
// have a primary type and a parameter list but no sub type
|
||||
throw new MimeTypeParseException("Unable to find a sub type.");
|
||||
}
|
||||
|
||||
// now validate the primary and sub types
|
||||
|
||||
// check to see if primary is valid
|
||||
if (!isValidToken(primaryType))
|
||||
throw new MimeTypeParseException("Primary type is invalid.");
|
||||
|
||||
// check to see if sub is valid
|
||||
if (!isValidToken(subType))
|
||||
throw new MimeTypeParseException("Sub type is invalid.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the primary type of this object.
|
||||
*
|
||||
* @return the primary MIME type
|
||||
*/
|
||||
public String getPrimaryType() {
|
||||
return primaryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the primary type for this object to the given String.
|
||||
*
|
||||
* @param primary the primary MIME type
|
||||
* @throws MimeTypeParseException if the primary type
|
||||
* is not a valid token
|
||||
*/
|
||||
public void setPrimaryType(String primary) throws MimeTypeParseException {
|
||||
// check to see if primary is valid
|
||||
if (!isValidToken(primaryType))
|
||||
throw new MimeTypeParseException("Primary type is invalid.");
|
||||
primaryType = primary.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the subtype of this object.
|
||||
*
|
||||
* @return the MIME subtype
|
||||
*/
|
||||
public String getSubType() {
|
||||
return subType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the subtype for this object to the given String.
|
||||
*
|
||||
* @param sub the MIME subtype
|
||||
* @throws MimeTypeParseException if the subtype
|
||||
* is not a valid token
|
||||
*/
|
||||
public void setSubType(String sub) throws MimeTypeParseException {
|
||||
// check to see if sub is valid
|
||||
if (!isValidToken(subType))
|
||||
throw new MimeTypeParseException("Sub type is invalid.");
|
||||
subType = sub.toLowerCase(Locale.ENGLISH);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve this object's parameter list.
|
||||
*
|
||||
* @return a MimeTypeParameterList object representing the parameters
|
||||
*/
|
||||
public MimeTypeParameterList getParameters() {
|
||||
return parameters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value associated with the given name, or null if there
|
||||
* is no current association.
|
||||
*
|
||||
* @param name the parameter name
|
||||
* @return the paramter's value
|
||||
*/
|
||||
public String getParameter(String name) {
|
||||
return parameters.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value to be associated with the given name, replacing
|
||||
* any previous association.
|
||||
*
|
||||
* @param name the parameter name
|
||||
* @param value the paramter's value
|
||||
*/
|
||||
public void setParameter(String name, String value) {
|
||||
parameters.set(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any value associated with the given name.
|
||||
*
|
||||
* @param name the parameter name
|
||||
*/
|
||||
public void removeParameter(String name) {
|
||||
parameters.remove(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the String representation of this object.
|
||||
*/
|
||||
public String toString() {
|
||||
return getBaseType() + parameters.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a String representation of this object
|
||||
* without the parameter list.
|
||||
*
|
||||
* @return the MIME type and sub-type
|
||||
*/
|
||||
public String getBaseType() {
|
||||
return primaryType + "/" + subType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if the primary and sub type of this object is
|
||||
* the same as what is in the given type.
|
||||
*
|
||||
* @param type the MimeType object to compare with
|
||||
* @return true if they match
|
||||
*/
|
||||
public boolean match(MimeType type) {
|
||||
return primaryType.equals(type.getPrimaryType())
|
||||
&& (subType.equals("*")
|
||||
|| type.getSubType().equals("*")
|
||||
|| (subType.equals(type.getSubType())));
|
||||
}
|
||||
|
||||
// below here be scary parsing related things
|
||||
|
||||
/**
|
||||
* Determine if the primary and sub type of this object is
|
||||
* the same as the content type described in rawdata.
|
||||
*
|
||||
* @param rawdata the MIME type string to compare with
|
||||
* @return true if they match
|
||||
* @throws MimeTypeParseException if the MIME type can't be parsed
|
||||
*/
|
||||
public boolean match(String rawdata) throws MimeTypeParseException {
|
||||
return match(new MimeType(rawdata));
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether or not a given string is a legal token.
|
||||
*/
|
||||
private boolean isValidToken(String s) {
|
||||
int len = s.length();
|
||||
if (len > 0) {
|
||||
for (int i = 0; i < len; ++i) {
|
||||
char c = s.charAt(i);
|
||||
if (!isTokenChar(c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
/**
|
||||
* Represents mapping between the file extension and the MIME type string.
|
||||
*/
|
||||
public class MimeTypeEntry {
|
||||
private String type;
|
||||
private String extension;
|
||||
|
||||
/**
|
||||
* Create new {@code MimeTypeEntry}
|
||||
*
|
||||
* @param mime_type the MIME type string
|
||||
* @param file_ext the file extension
|
||||
*/
|
||||
public MimeTypeEntry(String mime_type, String file_ext) {
|
||||
type = mime_type;
|
||||
extension = file_ext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MIME type string
|
||||
*
|
||||
* @return the MIME type string
|
||||
*/
|
||||
public String getMIMEType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file extension
|
||||
*
|
||||
* @return the file extension
|
||||
*/
|
||||
public String getFileExtension() {
|
||||
return extension;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MIMETypeEntry: " + type + ", " + extension;
|
||||
}
|
||||
}
|
|
@ -1,323 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A parameter list of a MimeType
|
||||
* as defined in RFC 2045 and 2046. The Primary type of the
|
||||
* object must already be stripped off.
|
||||
*
|
||||
* @see MimeType
|
||||
*/
|
||||
public class MimeTypeParameterList {
|
||||
/**
|
||||
* A string that holds all the special chars.
|
||||
*/
|
||||
private static final String TSPECIALS = "()<>@,;:/[]?=\\\"";
|
||||
private Hashtable<String, String> parameters;
|
||||
|
||||
|
||||
/**
|
||||
* Default constructor.
|
||||
*/
|
||||
public MimeTypeParameterList() {
|
||||
parameters = new Hashtable<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new MimeTypeParameterList with the passed in data.
|
||||
*
|
||||
* @param parameterList an RFC 2045, 2046 compliant parameter list.
|
||||
* @throws MimeTypeParseException if the MIME type can't be parsed
|
||||
*/
|
||||
public MimeTypeParameterList(String parameterList)
|
||||
throws MimeTypeParseException {
|
||||
parameters = new Hashtable<>();
|
||||
|
||||
// now parse rawdata
|
||||
parse(parameterList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether or not a given character belongs to a legal token.
|
||||
*/
|
||||
private static boolean isTokenChar(char c) {
|
||||
return ((c > 040) && (c < 0177)) && (TSPECIALS.indexOf(c) < 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* return the index of the first non white space character in
|
||||
* rawdata at or after index i.
|
||||
*/
|
||||
private static int skipWhiteSpace(String rawdata, int i) {
|
||||
int length = rawdata.length();
|
||||
while ((i < length) && Character.isWhitespace(rawdata.charAt(i)))
|
||||
i++;
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* A routine that knows how and when to quote and escape the given value.
|
||||
*/
|
||||
private static String quote(String value) {
|
||||
boolean needsQuotes = false;
|
||||
|
||||
// check to see if we actually have to quote this thing
|
||||
int length = value.length();
|
||||
for (int i = 0; (i < length) && !needsQuotes; i++) {
|
||||
needsQuotes = !isTokenChar(value.charAt(i));
|
||||
}
|
||||
|
||||
if (needsQuotes) {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.ensureCapacity((int) (length * 1.5));
|
||||
|
||||
// add the initial quote
|
||||
buffer.append('"');
|
||||
|
||||
// add the properly escaped text
|
||||
for (int i = 0; i < length; ++i) {
|
||||
char c = value.charAt(i);
|
||||
if ((c == '\\') || (c == '"'))
|
||||
buffer.append('\\');
|
||||
buffer.append(c);
|
||||
}
|
||||
|
||||
// add the closing quote
|
||||
buffer.append('"');
|
||||
|
||||
return buffer.toString();
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A routine that knows how to strip the quotes and
|
||||
* escape sequences from the given value.
|
||||
*/
|
||||
private static String unquote(String value) {
|
||||
int valueLength = value.length();
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.ensureCapacity(valueLength);
|
||||
|
||||
boolean escaped = false;
|
||||
for (int i = 0; i < valueLength; ++i) {
|
||||
char currentChar = value.charAt(i);
|
||||
if (!escaped && (currentChar != '\\')) {
|
||||
buffer.append(currentChar);
|
||||
} else if (escaped) {
|
||||
buffer.append(currentChar);
|
||||
escaped = false;
|
||||
} else {
|
||||
escaped = true;
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A routine for parsing the parameter list out of a String.
|
||||
*
|
||||
* @param parameterList an RFC 2045, 2046 compliant parameter list.
|
||||
* @throws MimeTypeParseException if the MIME type can't be parsed
|
||||
*/
|
||||
private void parse(String parameterList) throws MimeTypeParseException {
|
||||
if (parameterList == null)
|
||||
return;
|
||||
|
||||
int length = parameterList.length();
|
||||
if (length == 0)
|
||||
return;
|
||||
|
||||
int i;
|
||||
char c;
|
||||
for (i = skipWhiteSpace(parameterList, 0);
|
||||
i < length && (c = parameterList.charAt(i)) == ';';
|
||||
i = skipWhiteSpace(parameterList, i)) {
|
||||
int lastIndex;
|
||||
String name;
|
||||
String value;
|
||||
|
||||
// eat the ';'
|
||||
i++;
|
||||
|
||||
// now parse the parameter name
|
||||
|
||||
// skip whitespace
|
||||
i = skipWhiteSpace(parameterList, i);
|
||||
|
||||
// tolerate trailing semicolon, even though it violates the spec
|
||||
if (i >= length)
|
||||
return;
|
||||
|
||||
// find the end of the token char run
|
||||
lastIndex = i;
|
||||
while ((i < length) && isTokenChar(parameterList.charAt(i)))
|
||||
i++;
|
||||
|
||||
name = parameterList.substring(lastIndex, i).
|
||||
toLowerCase(Locale.ENGLISH);
|
||||
|
||||
// now parse the '=' that separates the name from the value
|
||||
i = skipWhiteSpace(parameterList, i);
|
||||
|
||||
if (i >= length || parameterList.charAt(i) != '=')
|
||||
throw new MimeTypeParseException(
|
||||
"Couldn't find the '=' that separates a " +
|
||||
"parameter name from its value.");
|
||||
|
||||
// eat it and parse the parameter value
|
||||
i++;
|
||||
i = skipWhiteSpace(parameterList, i);
|
||||
|
||||
if (i >= length)
|
||||
throw new MimeTypeParseException(
|
||||
"Couldn't find a value for parameter named " + name);
|
||||
|
||||
// now find out whether or not we have a quoted value
|
||||
c = parameterList.charAt(i);
|
||||
if (c == '"') {
|
||||
// yup it's quoted so eat it and capture the quoted string
|
||||
i++;
|
||||
if (i >= length)
|
||||
throw new MimeTypeParseException(
|
||||
"Encountered unterminated quoted parameter value.");
|
||||
|
||||
lastIndex = i;
|
||||
|
||||
// find the next unescaped quote
|
||||
while (i < length) {
|
||||
c = parameterList.charAt(i);
|
||||
if (c == '"')
|
||||
break;
|
||||
if (c == '\\') {
|
||||
// found an escape sequence
|
||||
// so skip this and the
|
||||
// next character
|
||||
i++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (c != '"')
|
||||
throw new MimeTypeParseException(
|
||||
"Encountered unterminated quoted parameter value.");
|
||||
|
||||
value = unquote(parameterList.substring(lastIndex, i));
|
||||
// eat the quote
|
||||
i++;
|
||||
} else if (isTokenChar(c)) {
|
||||
// nope it's an ordinary token so it
|
||||
// ends with a non-token char
|
||||
lastIndex = i;
|
||||
while (i < length && isTokenChar(parameterList.charAt(i)))
|
||||
i++;
|
||||
value = parameterList.substring(lastIndex, i);
|
||||
} else {
|
||||
// it ain't a value
|
||||
throw new MimeTypeParseException(
|
||||
"Unexpected character encountered at index " + i);
|
||||
}
|
||||
|
||||
// now put the data into the hashtable
|
||||
parameters.put(name, value);
|
||||
}
|
||||
if (i < length) {
|
||||
throw new MimeTypeParseException(
|
||||
"More characters encountered in input than expected.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of name-value pairs in this list.
|
||||
*
|
||||
* @return the number of parameters
|
||||
*/
|
||||
public int size() {
|
||||
return parameters.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether or not this list is empty.
|
||||
*
|
||||
* @return true if there are no parameters
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return parameters.isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the value associated with the given name, or null if there
|
||||
* is no current association.
|
||||
*
|
||||
* @param name the parameter name
|
||||
* @return the parameter's value
|
||||
*/
|
||||
public String get(String name) {
|
||||
return parameters.get(name.trim().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
// below here be scary parsing related things
|
||||
|
||||
/**
|
||||
* Set the value to be associated with the given name, replacing
|
||||
* any previous association.
|
||||
*
|
||||
* @param name the parameter name
|
||||
* @param value the parameter's value
|
||||
*/
|
||||
public void set(String name, String value) {
|
||||
parameters.put(name.trim().toLowerCase(Locale.ENGLISH), value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any value associated with the given name.
|
||||
*
|
||||
* @param name the parameter name
|
||||
*/
|
||||
public void remove(String name) {
|
||||
parameters.remove(name.trim().toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve an enumeration of all the names in this list.
|
||||
*
|
||||
* @return an enumeration of all parameter names
|
||||
*/
|
||||
public Enumeration<String> getNames() {
|
||||
return parameters.keys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of this object.
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
buffer.ensureCapacity(parameters.size() * 16);
|
||||
// heuristic: 8 characters per field
|
||||
|
||||
Enumeration<String> keys = parameters.keys();
|
||||
while (keys.hasMoreElements()) {
|
||||
String key = keys.nextElement();
|
||||
buffer.append("; ");
|
||||
buffer.append(key);
|
||||
buffer.append('=');
|
||||
buffer.append(quote(parameters.get(key)));
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
/**
|
||||
* A class to encapsulate MimeType parsing related exceptions.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MimeTypeParseException extends Exception {
|
||||
|
||||
/**
|
||||
* Constructs a MimeTypeParseException with no specified detail message.
|
||||
*/
|
||||
public MimeTypeParseException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MimeTypeParseException with the specified detail message.
|
||||
*
|
||||
* @param s the detail message.
|
||||
*/
|
||||
public MimeTypeParseException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
/**
|
||||
* The MimeTypeRegistry interface is implemented by objects that can
|
||||
* be used to store and retrieve MimeTypeEntries.
|
||||
* <p>
|
||||
* Application must implement {@link jakarta.activation.spi.MimeTypeRegistryProvider}
|
||||
* to create new instances of the MimeTypeRegistry. Implementation of the MimeTypeRegistry
|
||||
* can store MimeTypeEntries in different ways and that storage must be accessible through the
|
||||
* {@link jakarta.activation.spi.MimeTypeRegistryProvider} methods.
|
||||
* Implementation of the MimeTypeRegistry must contain in-memory storage for MimeTypeEntries.
|
||||
*/
|
||||
public interface MimeTypeRegistry {
|
||||
|
||||
/**
|
||||
* get the MimeTypeEntry based on the file extension
|
||||
*
|
||||
* @param file_ext the file extension
|
||||
* @return the MimeTypeEntry
|
||||
*/
|
||||
MimeTypeEntry getMimeTypeEntry(String file_ext);
|
||||
|
||||
/**
|
||||
* Get the MIME type string corresponding to the file extension.
|
||||
*
|
||||
* @param file_ext the file extension
|
||||
* @return the MIME type string
|
||||
*/
|
||||
default String getMIMETypeString(String file_ext) {
|
||||
MimeTypeEntry entry = this.getMimeTypeEntry(file_ext);
|
||||
|
||||
if (entry != null) {
|
||||
return entry.getMIMEType();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends string of entries to the types registry
|
||||
*
|
||||
* @param mime_types the mime.types string
|
||||
*/
|
||||
void appendToRegistry(String mime_types);
|
||||
}
|
|
@ -1,350 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2024 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import jakarta.activation.spi.MimeTypeRegistryProvider;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.nio.file.Path;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.ServiceConfigurationError;
|
||||
import java.util.Vector;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* This class extends FileTypeMap and provides data typing of files
|
||||
* via their file extension. It uses the <code>.mime.types</code> format. <p>
|
||||
*
|
||||
* <b>MIME types file search order:</b><p>
|
||||
* The MimetypesFileTypeMap looks in various places in the user's
|
||||
* system for MIME types file entries. When requests are made
|
||||
* to search for MIME types in the MimetypesFileTypeMap, it searches
|
||||
* MIME types files in the following order:
|
||||
* <ol>
|
||||
* <li> Programmatically added entries to the MimetypesFileTypeMap instance.
|
||||
* <li> The file <code>.mime.types</code> in the user's home directory.
|
||||
* <li> The file <code>mime.types</code> in the Java runtime.
|
||||
* <li> The file or resources named <code>META-INF/mime.types</code>.
|
||||
* <li> The file or resource named <code>META-INF/mimetypes.default</code>
|
||||
* (usually found only in the <code>activation.jar</code> file).
|
||||
* </ol>
|
||||
* <p>
|
||||
* (The current implementation looks for the <code>mime.types</code> file
|
||||
* in the Java runtime in the directory <code><i>java.home</i>/conf</code>
|
||||
* if it exists, and otherwise in the directory
|
||||
* <code><i>java.home</i>/lib</code>, where <i>java.home</i> is the value
|
||||
* of the "java.home" System property. Note that the "conf" directory was
|
||||
* introduced in JDK 9.)
|
||||
* <p>
|
||||
* <b>MIME types file format:</b><p>
|
||||
*
|
||||
* <code>
|
||||
* # comments begin with a '#'<br>
|
||||
* # the format is <mime type> <space separated file extensions><br>
|
||||
* # for example:<br>
|
||||
* text/plain txt text TXT<br>
|
||||
* # this would map file.txt, file.text, and file.TXT to<br>
|
||||
* # the mime type "text/plain"<br>
|
||||
* </code>
|
||||
*
|
||||
* @author Bart Calder
|
||||
* @author Bill Shannon
|
||||
*/
|
||||
public class MimetypesFileTypeMap extends FileTypeMap {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MimetypesFileTypeMap.class.getName());
|
||||
|
||||
private static final int PROG = 0;
|
||||
private static final String defaultType = "application/octet-stream";
|
||||
private static final String confDir;
|
||||
|
||||
static {
|
||||
String dir;
|
||||
String home = System.getProperty("java.home");
|
||||
String newdir = home + File.separator + "conf";
|
||||
File conf = new File(newdir);
|
||||
if (conf.exists()) {
|
||||
dir = newdir + File.separator;
|
||||
} else {
|
||||
dir = home + File.separator + "lib" + File.separator;
|
||||
}
|
||||
confDir = dir;
|
||||
}
|
||||
|
||||
private MimeTypeRegistry[] DB;
|
||||
|
||||
/**
|
||||
* The default constructor.
|
||||
*/
|
||||
public MimetypesFileTypeMap() {
|
||||
Vector<MimeTypeRegistry> dbv = new Vector<>(5);
|
||||
MimeTypeRegistry mf;
|
||||
dbv.addElement(null);
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: load HOME");
|
||||
String user_home = System.getProperty("user.home");
|
||||
if (user_home != null) {
|
||||
String path = user_home + File.separator + ".mime.types";
|
||||
mf = loadFile(path);
|
||||
if (mf != null)
|
||||
dbv.addElement(mf);
|
||||
}
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: load SYS");
|
||||
// check system's home
|
||||
if (confDir != null) {
|
||||
mf = loadFile(confDir + "mime.types");
|
||||
if (mf != null)
|
||||
dbv.addElement(mf);
|
||||
}
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: load JAR");
|
||||
// load from the app's jar file
|
||||
loadAllResources(dbv, "META-INF/mime.types");
|
||||
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: load DEF");
|
||||
mf = loadResource("/META-INF/mimetypes.default");
|
||||
|
||||
if (mf != null)
|
||||
dbv.addElement(mf);
|
||||
|
||||
DB = new MimeTypeRegistry[dbv.size()];
|
||||
dbv.copyInto(DB);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a MimetypesFileTypeMap with programmatic entries
|
||||
* added from the named file.
|
||||
*
|
||||
* @param mimeTypeFileName the file name
|
||||
* @throws IOException for errors reading the file
|
||||
*/
|
||||
public MimetypesFileTypeMap(String mimeTypeFileName) throws IOException {
|
||||
this();
|
||||
try {
|
||||
DB[PROG] = getImplementation().getByFileName(mimeTypeFileName);
|
||||
} catch (NoSuchElementException | IllegalStateException | ServiceConfigurationError e) {
|
||||
String errorMessage = "Cannot find or load an implementation for MimeTypeRegistryProvider." +
|
||||
"MimeTypeRegistry: can't load " + mimeTypeFileName;
|
||||
logger.log(Level.FINE, errorMessage, e);
|
||||
throw new IOException(errorMessage, e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a MimetypesFileTypeMap with programmatic entries
|
||||
* added from the InputStream.
|
||||
*
|
||||
* @param is the input stream to read from
|
||||
*/
|
||||
public MimetypesFileTypeMap(InputStream is) {
|
||||
this();
|
||||
try {
|
||||
DB[PROG] = getImplementation().getByInputStream(is);
|
||||
} catch (IOException ex) {
|
||||
// XXX - really should throw it
|
||||
} catch (NoSuchElementException | IllegalStateException | ServiceConfigurationError e) {
|
||||
logger.log(Level.FINE, "Cannot find or load an implementation for MimeTypeRegistryProvider." +
|
||||
"MimeTypeRegistry: can't load InputStream", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load from the named resource.
|
||||
*/
|
||||
private MimeTypeRegistry loadResource(String name) {
|
||||
InputStream clis = null;
|
||||
try {
|
||||
clis = Util.getResourceAsStream(this.getClass(), name);
|
||||
if (clis != null) {
|
||||
MimeTypeRegistry mf = getImplementation().getByInputStream(clis);
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: successfully " +
|
||||
"loaded mime types file: " + name);
|
||||
return mf;
|
||||
} else {
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: not loading " +
|
||||
"mime types file: " + name);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: can't load " + name, e);
|
||||
} catch (NoSuchElementException | IllegalStateException | ServiceConfigurationError e) {
|
||||
logger.log(Level.FINE, "Cannot find or load an implementation for MimeTypeRegistryProvider." +
|
||||
"MimeTypeRegistry: can't load " + name, e);
|
||||
} finally {
|
||||
try {
|
||||
if (clis != null)
|
||||
clis.close();
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.FINE, "InputStream cannot be close for " + name, ex);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load all of the named resource.
|
||||
*/
|
||||
private void loadAllResources(Vector<MimeTypeRegistry> v, String name) {
|
||||
boolean anyLoaded = false;
|
||||
try {
|
||||
URL[] urls;
|
||||
ClassLoader cld = null;
|
||||
// First try the "application's" class loader.
|
||||
cld = Util.getContextClassLoader();
|
||||
if (cld == null)
|
||||
cld = this.getClass().getClassLoader();
|
||||
if (cld != null)
|
||||
urls = Util.getResources(cld, name);
|
||||
else
|
||||
urls = Util.getSystemResources(name);
|
||||
if (urls != null) {
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: getResources");
|
||||
for (int i = 0; i < urls.length; i++) {
|
||||
URL url = urls[i];
|
||||
InputStream clis = null;
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: URL " + url);
|
||||
try {
|
||||
clis = Util.openStream(url);
|
||||
if (clis != null) {
|
||||
v.addElement(
|
||||
getImplementation().getByInputStream(clis)
|
||||
);
|
||||
anyLoaded = true;
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: " +
|
||||
"successfully loaded " +
|
||||
"mime types from URL: " + url);
|
||||
} else {
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: " +
|
||||
"not loading " +
|
||||
"mime types from URL: " + url);
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: can't load " +
|
||||
url, ioex);
|
||||
} catch (NoSuchElementException | IllegalStateException | ServiceConfigurationError e) {
|
||||
logger.log(Level.FINE, "Cannot find or load an implementation for MimeTypeRegistryProvider." +
|
||||
"MimeTypeRegistry: can't load " + url, e);
|
||||
} finally {
|
||||
try {
|
||||
if (clis != null)
|
||||
clis.close();
|
||||
} catch (IOException cex) {
|
||||
logger.log(Level.FINE, "InputStream cannot be close for " + name, cex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: can't load " + name, ex);
|
||||
}
|
||||
|
||||
// if failed to load anything, fall back to old technique, just in case
|
||||
if (!anyLoaded) {
|
||||
logger.log(Level.FINE, "MimetypesFileTypeMap: !anyLoaded");
|
||||
MimeTypeRegistry mf = loadResource("/" + name);
|
||||
if (mf != null)
|
||||
v.addElement(mf);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the named file.
|
||||
*/
|
||||
private MimeTypeRegistry loadFile(String name) {
|
||||
MimeTypeRegistry mtf = null;
|
||||
|
||||
try {
|
||||
mtf = getImplementation().getByFileName(name);
|
||||
} catch (IOException e) {
|
||||
logger.log(Level.FINE, "MimeTypeRegistry: can't load from file - " + name, e);
|
||||
} catch (NoSuchElementException | IllegalStateException | ServiceConfigurationError e) {
|
||||
logger.log(Level.FINE, "Cannot find or load an implementation for MimeTypeRegistryProvider." +
|
||||
"MimeTypeRegistry: can't load " + name, e);
|
||||
}
|
||||
return mtf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepend the MIME type values to the registry.
|
||||
*
|
||||
* @param mime_types A .mime.types formatted string of entries.
|
||||
*/
|
||||
public synchronized void addMimeTypes(String mime_types) {
|
||||
try {
|
||||
if (DB[PROG] == null) {
|
||||
DB[PROG] = getImplementation().getInMemory();
|
||||
}
|
||||
DB[PROG].appendToRegistry(mime_types);
|
||||
} catch (NoSuchElementException | IllegalStateException | ServiceConfigurationError e) {
|
||||
logger.log(Level.FINE, "Cannot find or load an implementation for MimeTypeRegistryProvider." +
|
||||
"MimeTypeRegistry: can't add " + mime_types, e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MIME type of the <Code>File</Code> object.
|
||||
* The implementation in this class calls
|
||||
* <code>getContentType(f.getName())</code>.
|
||||
*
|
||||
* @param f the file
|
||||
* @return the file's MIME type
|
||||
*/
|
||||
public String getContentType(File f) {
|
||||
return this.getContentType(f.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MIME type of the <Code>Path</Code> object.
|
||||
* The implementation in this class calls
|
||||
* <code>getContentType(p.getFileName().toString())</code>.
|
||||
*
|
||||
* @param p the file <Code>Path</Code>
|
||||
* @return the file's MIME type
|
||||
*/
|
||||
public String getContentType(Path p) {
|
||||
return this.getContentType(p.getFileName().toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MIME type based on the specified file name.
|
||||
* The MIME type entries are searched as described above under
|
||||
* <i>MIME types file search order</i>.
|
||||
* If no entry is found, the type "application/octet-stream" is returned.
|
||||
*
|
||||
* @param filename the file name
|
||||
* @return the file's MIME type
|
||||
*/
|
||||
public synchronized String getContentType(String filename) {
|
||||
int dot_pos = filename.lastIndexOf("."); // period index
|
||||
if (dot_pos < 0) {
|
||||
return defaultType;
|
||||
}
|
||||
String file_ext = filename.substring(dot_pos + 1);
|
||||
if (file_ext.isEmpty()) {
|
||||
return defaultType;
|
||||
}
|
||||
for (MimeTypeRegistry mimeTypeRegistry : DB) {
|
||||
if (mimeTypeRegistry == null) {
|
||||
continue;
|
||||
}
|
||||
String result = mimeTypeRegistry.getMIMETypeString(file_ext);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return defaultType;
|
||||
}
|
||||
|
||||
private MimeTypeRegistryProvider getImplementation() {
|
||||
return FactoryFinder.find(MimeTypeRegistryProvider.class);
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021, 2024 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.util.ServiceLoader;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Shared ServiceLoader/FactoryFinder Utils. JAF and MAIL use the same loading
|
||||
* logic of thread context class loader, calling class loader, and finally the
|
||||
* system class loader.
|
||||
*
|
||||
* @author Miroslav.Kos@oracle.com
|
||||
*/
|
||||
class ServiceLoaderUtil {
|
||||
|
||||
static <P, T extends Exception> P firstByServiceLoader(Class<P> spiClass,
|
||||
ClassLoader loader,
|
||||
Logger logger,
|
||||
ExceptionHandler<T> handler) throws T {
|
||||
logger.log(Level.FINE, "Using java.util.ServiceLoader to find {0}", spiClass.getName());
|
||||
try {
|
||||
ServiceLoader<P> serviceLoader = ServiceLoader.load(spiClass, loader);
|
||||
for (P impl : serviceLoader) {
|
||||
logger.log(Level.FINE, "ServiceProvider loading Facility used; returning object [{0}]", impl.getClass().getName());
|
||||
return impl;
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
throw handler.createException(t, "Error while searching for service [" + spiClass.getName() + "]");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
static <P> Class<P> nullSafeLoadClass(String className, ClassLoader classLoader) throws ClassNotFoundException {
|
||||
if (classLoader == null) {
|
||||
classLoader = ClassLoader.getSystemClassLoader();
|
||||
}
|
||||
return (Class<P>) Class.forName(className, false, classLoader);
|
||||
}
|
||||
|
||||
static <P, T extends Exception> P newInstance(String className,
|
||||
Class<P> service, ClassLoader classLoader,
|
||||
final ExceptionHandler<T> handler) throws T {
|
||||
try {
|
||||
Class<P> cls = safeLoadClass(className, classLoader);
|
||||
return service.cast(cls.getConstructor().newInstance());
|
||||
} catch (ClassNotFoundException x) {
|
||||
throw handler.createException(x, "Provider " + className + " not found");
|
||||
} catch (Exception x) {
|
||||
throw handler.createException(x, "Provider " + className + " could not be instantiated: " + x);
|
||||
}
|
||||
}
|
||||
|
||||
static <P> Class<P> safeLoadClass(String className,
|
||||
ClassLoader classLoader) throws ClassNotFoundException {
|
||||
return nullSafeLoadClass(className, classLoader);
|
||||
}
|
||||
|
||||
static abstract class ExceptionHandler<T extends Exception> {
|
||||
|
||||
public abstract T createException(Throwable throwable, String message);
|
||||
|
||||
}
|
||||
}
|
|
@ -1,121 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
|
||||
/**
|
||||
* The URLDataSource class provides an object that wraps a <code>URL</code>
|
||||
* object in a DataSource interface. URLDataSource simplifies the handling
|
||||
* of data described by URLs within Jakarta Activation
|
||||
* because this class can be used to create new DataHandlers. <i>NOTE: The
|
||||
* DataHandler object creates a URLDataSource internally,
|
||||
* when it is constructed with a URL.</i>
|
||||
*
|
||||
* @see DataSource
|
||||
* @see DataHandler
|
||||
*/
|
||||
public class URLDataSource implements DataSource {
|
||||
private URL url = null;
|
||||
private URLConnection url_conn = null;
|
||||
|
||||
/**
|
||||
* URLDataSource constructor. The URLDataSource class will
|
||||
* not open a connection to the URL until a method requiring it
|
||||
* to do so is called.
|
||||
*
|
||||
* @param url The URL to be encapsulated in this object.
|
||||
*/
|
||||
public URLDataSource(URL url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the URL content-type header field.
|
||||
* It calls the URL's <code>URLConnection.getContentType</code> method
|
||||
* after retrieving a URLConnection object.
|
||||
* <i>Note: this method attempts to call the <code>openConnection</code>
|
||||
* method on the URL. If this method fails, or if a content type is not
|
||||
* returned from the URLConnection, getContentType returns
|
||||
* "application/octet-stream" as the content type.</i>
|
||||
*
|
||||
* @return the content type.
|
||||
*/
|
||||
public String getContentType() {
|
||||
String type = null;
|
||||
|
||||
try {
|
||||
if (url_conn == null)
|
||||
url_conn = url.openConnection();
|
||||
} catch (IOException e) {
|
||||
}
|
||||
|
||||
if (url_conn != null)
|
||||
type = url_conn.getContentType();
|
||||
|
||||
if (type == null)
|
||||
type = "application/octet-stream";
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the <code>getFile</code> method on the URL used to
|
||||
* instantiate the object.
|
||||
*
|
||||
* @return the result of calling the URL's getFile method.
|
||||
*/
|
||||
public String getName() {
|
||||
return url.getFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* The getInputStream method from the URL. Calls the
|
||||
* <code>openStream</code> method on the URL.
|
||||
*
|
||||
* @return the InputStream.
|
||||
*/
|
||||
public InputStream getInputStream() throws IOException {
|
||||
return url.openStream();
|
||||
}
|
||||
|
||||
/**
|
||||
* The getOutputStream method from the URL. First an attempt is
|
||||
* made to get the URLConnection object for the URL. If that
|
||||
* succeeds, the getOutputStream method on the URLConnection
|
||||
* is returned.
|
||||
*
|
||||
* @return the OutputStream.
|
||||
*/
|
||||
public OutputStream getOutputStream() throws IOException {
|
||||
// get the url connection if it is available
|
||||
url_conn = url.openConnection();
|
||||
|
||||
if (url_conn != null) {
|
||||
url_conn.setDoOutput(true);
|
||||
return url_conn.getOutputStream();
|
||||
} else
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the URL used to create this DataSource.
|
||||
*
|
||||
* @return The URL.
|
||||
*/
|
||||
public URL getURL() {
|
||||
return url;
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Signals that the requested operation does not support the
|
||||
* requested data type.
|
||||
*
|
||||
* @see DataHandler
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class UnsupportedDataTypeException extends IOException {
|
||||
|
||||
/**
|
||||
* Constructs an UnsupportedDataTypeException with no detail
|
||||
* message.
|
||||
*/
|
||||
public UnsupportedDataTypeException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an UnsupportedDataTypeException with the specified
|
||||
* message.
|
||||
*
|
||||
* @param s The detail message.
|
||||
*/
|
||||
public UnsupportedDataTypeException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.List;
|
||||
|
||||
class Util {
|
||||
|
||||
private Util() {
|
||||
// private constructor, can't create an instance
|
||||
}
|
||||
|
||||
public static ClassLoader getContextClassLoader() {
|
||||
return Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
|
||||
public static InputStream getResourceAsStream(final Class<?> c,
|
||||
final String name) throws IOException {
|
||||
return c.getResourceAsStream(name);
|
||||
}
|
||||
|
||||
public static URL[] getResources(final ClassLoader cl, final String name) {
|
||||
URL[] ret = null;
|
||||
try {
|
||||
List<URL> v = new ArrayList<>();
|
||||
Enumeration<URL> e = cl.getResources(name);
|
||||
while (e != null && e.hasMoreElements()) {
|
||||
URL url = e.nextElement();
|
||||
if (url != null)
|
||||
v.add(url);
|
||||
}
|
||||
if (!v.isEmpty()) {
|
||||
ret = new URL[v.size()];
|
||||
ret = v.toArray(ret);
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
//
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static URL[] getSystemResources(final String name) {
|
||||
URL[] ret = null;
|
||||
try {
|
||||
List<URL> v = new ArrayList<>();
|
||||
Enumeration<URL> e = ClassLoader.getSystemResources(name);
|
||||
while (e != null && e.hasMoreElements()) {
|
||||
URL url = e.nextElement();
|
||||
if (url != null)
|
||||
v.add(url);
|
||||
}
|
||||
if (!v.isEmpty()) {
|
||||
ret = new URL[v.size()];
|
||||
ret = v.toArray(ret);
|
||||
}
|
||||
} catch (IOException ioex) {
|
||||
//
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static InputStream openStream(final URL url) throws IOException {
|
||||
return url.openStream();
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**
|
||||
* Jakarta Activation is used by Jakarta Mail to manage MIME data.
|
||||
*/
|
||||
package jakarta.activation;
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation.spi;
|
||||
|
||||
import jakarta.activation.MailcapRegistry;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.ServiceConfigurationError;
|
||||
|
||||
/**
|
||||
* This interface defines a factory for <code>MailcapRegistry</code>. An
|
||||
* implementation of this interface should provide instances of the MailcapRegistry
|
||||
* based on the way how to access the storage for MailcapEntries.
|
||||
* <p>
|
||||
* Jakarta Activation uses Service Provider Interface and <code>ServiceLoader</code>
|
||||
* to obtain an instance of the implementation of the <code>MailcapRegistryProvider</code>.
|
||||
*/
|
||||
public interface MailcapRegistryProvider {
|
||||
|
||||
/**
|
||||
* Retrieve an instance of the MailcapRegistry based on the name of the file where the MailcapEntries are stored.
|
||||
*
|
||||
* @param name The name of the file that stores MailcapEntries.
|
||||
* @return The instance of the <code>MailcapRegistry</code>, or <i>null</i> if none are found.
|
||||
* @throws IOException If an instance of the MailcapRegistry class cannot be found or loaded.
|
||||
*/
|
||||
MailcapRegistry getByFileName(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Retrieve an instance of the MailcapRegistry based on the InputStream
|
||||
* that is used to read data from some named resource.
|
||||
*
|
||||
* @param inputStream InputStream for some resource that contains MailcapEntries.
|
||||
* @return The instance of the <code>MailcapRegistry</code>, or <i>null</i> if none are found.
|
||||
* @throws IOException If an instance of the MailcapRegistry class cannot be found or loaded.
|
||||
*/
|
||||
MailcapRegistry getByInputStream(InputStream inputStream) throws IOException;
|
||||
|
||||
/**
|
||||
* Retrieve an instance of the in-memory implementation of the MailcapRegistry.
|
||||
*
|
||||
* @return In-memory implementation of the MailcapRegistry.
|
||||
* @throws NoSuchElementException If no implementations were found.
|
||||
* @throws ServiceConfigurationError If no implementations were loaded.
|
||||
*/
|
||||
MailcapRegistry getInMemory();
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
package jakarta.activation.spi;
|
||||
|
||||
import jakarta.activation.MimeTypeRegistry;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.ServiceConfigurationError;
|
||||
|
||||
/**
|
||||
* This interface defines a factory for <code>MimeTypeRegistry</code>. An
|
||||
* implementation of this interface should provide instances of the MimeTypeRegistry
|
||||
* based on the way how to access the storage for MimeTypeEntries.
|
||||
* <p>
|
||||
* Jakarta Activation uses Service Provider Interface and <code>ServiceLoader</code>
|
||||
* to obtain an instance of the implementation of the <code>MimeTypeRegistryProvider</code>.
|
||||
*/
|
||||
public interface MimeTypeRegistryProvider {
|
||||
|
||||
/**
|
||||
* Retrieve an instance of the MimeTypeRegistry based on the name of the file where the MimeTypeEntries are stored.
|
||||
*
|
||||
* @param name The name of the file that stores MimeTypeEntries.
|
||||
* @return The instance of the <code>MimeTypeRegistry</code>, or <i>null</i> if none are found.
|
||||
* @throws IOException If an instance of the MailcapRegistry class cannot be found or loaded.
|
||||
*/
|
||||
MimeTypeRegistry getByFileName(String name) throws IOException;
|
||||
|
||||
/**
|
||||
* Retrieve an instance of the MimeTypeRegistry based on the InputStream
|
||||
* that is used to read data from some named resource.
|
||||
*
|
||||
* @param inputStream InputStream for some resource that contains MimeTypeEntries.
|
||||
* @return The instance of the <code>MimeTypeRegistry</code>, or <i>null</i> if none are found.
|
||||
* @throws IOException If an instance of the MailcapRegistry class cannot be found or loaded.
|
||||
*/
|
||||
MimeTypeRegistry getByInputStream(InputStream inputStream) throws IOException;
|
||||
|
||||
/**
|
||||
* Retrieve an instance of the in-memory implementation of the MimeTypeRegistry.
|
||||
* Jakarta Activation can throw <code>NoSuchElementException</code> or <code>ServiceConfigurationError</code>
|
||||
* if no implementations were found.
|
||||
*
|
||||
* @return In-memory implementation of the MimeTypeRegistry.
|
||||
* @throws NoSuchElementException If no implementations were found.
|
||||
* @throws ServiceConfigurationError If no implementations were loaded.
|
||||
*/
|
||||
MimeTypeRegistry getInMemory();
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Distribution License v. 1.0, which is available at
|
||||
* http://www.eclipse.org/org/documents/edl-v10.php.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/**
|
||||
* <p>Provides interfaces which implementations will be used as service providers for other services
|
||||
* that used by Jakarta Activation.</p>
|
||||
* <p>Implementation of Jakarta Activation must implement interfaces declared in this package.
|
||||
* Jakarta Activation uses {@link java.util.ServiceLoader} class to discover
|
||||
* and load implementations of the interfaces from this package using standard Java SPI mechanism.</p>
|
||||
*/
|
||||
package jakarta.activation.spi;
|
|
@ -1,68 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* This abstract class models the addresses in a message.
|
||||
* Subclasses provide specific implementations. Subclasses
|
||||
* will typically be serializable so that (for example) the
|
||||
* use of Address objects in search terms can be serialized
|
||||
* along with the search terms.
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Bill Shannon
|
||||
*/
|
||||
|
||||
public abstract class Address {
|
||||
|
||||
/**
|
||||
* Creates a default {@code Address}.
|
||||
*/
|
||||
public Address() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a type string that identifies this address type.
|
||||
*
|
||||
* @return address type
|
||||
* @see jakarta.mail.internet.InternetAddress
|
||||
*/
|
||||
public abstract String getType();
|
||||
|
||||
/**
|
||||
* Return a String representation of this address object.
|
||||
*
|
||||
* @return string representation of this address
|
||||
*/
|
||||
@Override
|
||||
public abstract String toString();
|
||||
|
||||
/**
|
||||
* The equality operator. Subclasses should provide an
|
||||
* implementation of this method that supports value equality
|
||||
* (do the two Address objects represent the same destination?),
|
||||
* not object reference equality. A subclass must also provide
|
||||
* a corresponding implementation of the <code>hashCode</code>
|
||||
* method that preserves the general contract of
|
||||
* <code>equals</code> and <code>hashCode</code> - objects that
|
||||
* compare as equal must have the same hashCode.
|
||||
*
|
||||
* @param address Address object
|
||||
*/
|
||||
@Override
|
||||
public abstract boolean equals(Object address);
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* This exception is thrown when the connect method on a Store or
|
||||
* Transport object fails due to an authentication failure (e.g.,
|
||||
* bad user name or password).
|
||||
*
|
||||
* @author Bill Shannon
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class AuthenticationFailedException extends MessagingException {
|
||||
|
||||
/**
|
||||
* Constructs an AuthenticationFailedException.
|
||||
*/
|
||||
public AuthenticationFailedException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an AuthenticationFailedException with the specified
|
||||
* detail message.
|
||||
*
|
||||
* @param message The detailed error message
|
||||
*/
|
||||
public AuthenticationFailedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an AuthenticationFailedException with the specified
|
||||
* detail message and embedded exception. The exception is chained
|
||||
* to this exception.
|
||||
*
|
||||
* @param message The detailed error message
|
||||
* @param e The embedded exception
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public AuthenticationFailedException(String message, Exception e) {
|
||||
super(message, e);
|
||||
}
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import java.net.InetAddress;
|
||||
|
||||
/**
|
||||
* The class Authenticator represents an object that knows how to obtain
|
||||
* authentication for a network connection. Usually, it will do this
|
||||
* by prompting the user for information.
|
||||
* <p>
|
||||
* Applications use this class by creating a subclass, and registering
|
||||
* an instance of that subclass with the session when it is created.
|
||||
* When authentication is required, the system will invoke a method
|
||||
* on the subclass (like getPasswordAuthentication). The subclass's
|
||||
* method can query about the authentication being requested with a
|
||||
* number of inherited methods (getRequestingXXX()), and form an
|
||||
* appropriate message for the user.
|
||||
* <p>
|
||||
* All methods that request authentication have a default implementation
|
||||
* that fails.
|
||||
*
|
||||
* @author Bill Foote
|
||||
* @author Bill Shannon
|
||||
* @see java.net.Authenticator
|
||||
* @see Session#getInstance(java.util.Properties,
|
||||
* Authenticator)
|
||||
* @see Session#getDefaultInstance(java.util.Properties,
|
||||
* Authenticator)
|
||||
* @see Session#requestPasswordAuthentication
|
||||
* @see PasswordAuthentication
|
||||
*/
|
||||
public abstract class Authenticator {
|
||||
|
||||
private InetAddress requestingSite;
|
||||
private int requestingPort;
|
||||
private String requestingProtocol;
|
||||
private String requestingPrompt;
|
||||
private String requestingUserName;
|
||||
|
||||
/**
|
||||
* Creates a default {@code Authenticator}.
|
||||
* There are no abstract methods, but to be useful the user must subclass.
|
||||
*
|
||||
* @see #getPasswordAuthentication()
|
||||
*/
|
||||
public Authenticator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ask the authenticator for a password.
|
||||
* <p>
|
||||
*
|
||||
* @param addr The InetAddress of the site requesting authorization,
|
||||
* or null if not known.
|
||||
* @param port the port for the requested connection
|
||||
* @param protocol The protocol that's requesting the connection
|
||||
* (@see java.net.Authenticator.getProtocol())
|
||||
* @param prompt A prompt string for the user
|
||||
* @return The username/password, or null if one can't be gotten.
|
||||
*/
|
||||
final synchronized PasswordAuthentication requestPasswordAuthentication(
|
||||
InetAddress addr, int port, String protocol,
|
||||
String prompt, String defaultUserName) {
|
||||
requestingSite = addr;
|
||||
requestingPort = port;
|
||||
requestingProtocol = protocol;
|
||||
requestingPrompt = prompt;
|
||||
requestingUserName = defaultUserName;
|
||||
return getPasswordAuthentication();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the InetAddress of the site requesting authorization, or null
|
||||
* if it's not available.
|
||||
*/
|
||||
protected final InetAddress getRequestingSite() {
|
||||
return requestingSite;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the port for the requested connection
|
||||
*/
|
||||
protected final int getRequestingPort() {
|
||||
return requestingPort;
|
||||
}
|
||||
|
||||
/**
|
||||
* Give the protocol that's requesting the connection. Often this
|
||||
* will be based on a URLName.
|
||||
*
|
||||
* @return the protcol
|
||||
* @see URLName#getProtocol
|
||||
*/
|
||||
protected final String getRequestingProtocol() {
|
||||
return requestingProtocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the prompt string given by the requestor
|
||||
*/
|
||||
protected final String getRequestingPrompt() {
|
||||
return requestingPrompt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the default user name given by the requestor
|
||||
*/
|
||||
protected final String getDefaultUserName() {
|
||||
return requestingUserName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when password authentication is needed. Subclasses should
|
||||
* override the default implementation, which returns null. <p>
|
||||
* <p>
|
||||
* Note that if this method uses a dialog to prompt the user for this
|
||||
* information, the dialog needs to block until the user supplies the
|
||||
* information. This method can not simply return after showing the
|
||||
* dialog.
|
||||
*
|
||||
* @return The PasswordAuthentication collected from the
|
||||
* user, or null if none is provided.
|
||||
*/
|
||||
protected PasswordAuthentication getPasswordAuthentication() {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import jakarta.mail.util.StreamProvider;
|
||||
|
||||
/**
|
||||
* This class models a Part that is contained within a Multipart.
|
||||
* This is an abstract class. Subclasses provide actual implementations.<p>
|
||||
* <p>
|
||||
* BodyPart implements the Part interface. Thus, it contains a set of
|
||||
* attributes and a "content".
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Bill Shannon
|
||||
*/
|
||||
|
||||
public abstract class BodyPart implements Part {
|
||||
|
||||
/**
|
||||
* Instance of stream provider.
|
||||
*
|
||||
* @since JavaMail 2.1
|
||||
*/
|
||||
protected final StreamProvider streamProvider = StreamProvider.provider();
|
||||
/**
|
||||
* The <code>Multipart</code> object containing this <code>BodyPart</code>,
|
||||
* if known.
|
||||
*
|
||||
* @since JavaMail 1.1
|
||||
*/
|
||||
protected Multipart parent;
|
||||
|
||||
/**
|
||||
* Creates a default {@code BodyPart}.
|
||||
*/
|
||||
public BodyPart() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the containing <code>Multipart</code> object,
|
||||
* or <code>null</code> if not known.
|
||||
*
|
||||
* @return the parent Multipart
|
||||
*/
|
||||
public Multipart getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parent of this <code>BodyPart</code> to be the specified
|
||||
* <code>Multipart</code>. Normally called by <code>Multipart</code>'s
|
||||
* <code>addBodyPart</code> method. <code>parent</code> may be
|
||||
* <code>null</code> if the <code>BodyPart</code> is being removed
|
||||
* from its containing <code>Multipart</code>.
|
||||
*
|
||||
* @since JavaMail 1.1
|
||||
*/
|
||||
void setParent(Multipart parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* A {@link jakarta.activation.DataSource DataSource} that also implements
|
||||
* <code>EncodingAware</code> may specify the Content-Transfer-Encoding
|
||||
* to use for its data. Valid Content-Transfer-Encoding values specified
|
||||
* by RFC 2045 are "7bit", "8bit", "quoted-printable", "base64", and "binary".
|
||||
* <p>
|
||||
* For example, a {@link jakarta.activation.FileDataSource FileDataSource}
|
||||
* could be created that forces all files to be base64 encoded:
|
||||
* <blockquote><pre>
|
||||
* public class Base64FileDataSource extends FileDataSource
|
||||
* implements EncodingAware {
|
||||
* public Base64FileDataSource(File file) {
|
||||
* super(file);
|
||||
* }
|
||||
*
|
||||
* // implements EncodingAware.getEncoding()
|
||||
* public String getEncoding() {
|
||||
* return "base64";
|
||||
* }
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @author Bill Shannon
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
|
||||
public interface EncodingAware {
|
||||
|
||||
/**
|
||||
* Return the MIME Content-Transfer-Encoding to use for this data,
|
||||
* or null to indicate that an appropriate value should be chosen
|
||||
* by the caller.
|
||||
*
|
||||
* @return the Content-Transfer-Encoding value, or null
|
||||
*/
|
||||
String getEncoding();
|
||||
}
|
|
@ -1,165 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import jakarta.mail.event.MailEvent;
|
||||
import java.util.EventListener;
|
||||
import java.util.Objects;
|
||||
import java.util.Vector;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Package private class used by Store & Folder to dispatch events.
|
||||
* This class implements an event queue, and a dispatcher thread that
|
||||
* dequeues and dispatches events from the queue.
|
||||
*
|
||||
* @author Bill Shannon
|
||||
*/
|
||||
class EventQueue implements Runnable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(EventQueue.class.getName());
|
||||
|
||||
private static WeakHashMap<ClassLoader, EventQueue> appq;
|
||||
|
||||
private volatile BlockingQueue<QueueElement> q;
|
||||
|
||||
private final Executor executor;
|
||||
|
||||
/**
|
||||
* Construct an EventQueue using the specified Executor.
|
||||
* If the Executor is null, threads will be created as needed.
|
||||
*/
|
||||
EventQueue(Executor ex) {
|
||||
this.executor = Objects.requireNonNull(ex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create (if necessary) an application-scoped event queue.
|
||||
* Application scoping is based on the thread's context class loader.
|
||||
*/
|
||||
static synchronized EventQueue getApplicationEventQueue(Executor ex) {
|
||||
Objects.requireNonNull(ex);
|
||||
ClassLoader cl = Thread.currentThread().getContextClassLoader();
|
||||
if (appq == null) {
|
||||
appq = new WeakHashMap<>();
|
||||
}
|
||||
return appq.computeIfAbsent(cl, k -> new EventQueue(ex));
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue an event.
|
||||
*/
|
||||
synchronized void enqueue(MailEvent event,
|
||||
Vector<? extends EventListener> vector) {
|
||||
// if this is the first event, create the queue and start the event task
|
||||
if (q == null) {
|
||||
q = new LinkedBlockingQueue<>();
|
||||
logger.log(Level.INFO, "starting event queue");
|
||||
executor.execute(this);
|
||||
/*else {
|
||||
Thread qThread = new Thread(this, "Jakarta-Mail-EventQueue");
|
||||
qThread.setDaemon(true); // not a user thread
|
||||
qThread.start();
|
||||
}*/
|
||||
}
|
||||
q.add(new QueueElement(event, vector));
|
||||
}
|
||||
|
||||
/**
|
||||
* Terminate the task running the queue, but only if there is a queue.
|
||||
*/
|
||||
synchronized void terminateQueue() {
|
||||
if (q != null) {
|
||||
Vector<EventListener> dummyListeners = new Vector<>();
|
||||
dummyListeners.setSize(1); // need atleast one listener
|
||||
q.add(new QueueElement(new TerminatorEvent(), dummyListeners));
|
||||
q = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull events off the queue and dispatch them.
|
||||
*/
|
||||
@Override
|
||||
public void run() {
|
||||
BlockingQueue<QueueElement> bq = q;
|
||||
if (bq == null)
|
||||
return;
|
||||
try {
|
||||
logger.log(Level.INFO, "entering event queue");
|
||||
loop:
|
||||
for (; ; ) {
|
||||
// block until an item is available
|
||||
QueueElement qe = bq.take();
|
||||
MailEvent e = qe.event;
|
||||
Vector<? extends EventListener> v = qe.vector;
|
||||
|
||||
for (int i = 0; i < v.size(); i++)
|
||||
try {
|
||||
e.dispatch(v.elementAt(i));
|
||||
} catch (Throwable t) {
|
||||
if (t instanceof InterruptedException)
|
||||
break loop;
|
||||
// ignore anything else thrown by the listener
|
||||
}
|
||||
|
||||
qe = null;
|
||||
e = null;
|
||||
v = null;
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// just die
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A special event that causes the queue processing task to terminate.
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
static class TerminatorEvent extends MailEvent {
|
||||
|
||||
TerminatorEvent() {
|
||||
super(new Object());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(Object listener) {
|
||||
// Kill the event dispatching thread.
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A "struct" to put on the queue.
|
||||
*/
|
||||
static class QueueElement {
|
||||
|
||||
MailEvent event;
|
||||
|
||||
Vector<? extends EventListener> vector;
|
||||
|
||||
QueueElement(MailEvent event, Vector<? extends EventListener> vector) {
|
||||
this.event = event;
|
||||
this.vector = vector;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,223 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Clients use a FetchProfile to list the Message attributes that
|
||||
* it wishes to prefetch from the server for a range of messages.<p>
|
||||
* <p>
|
||||
* Messages obtained from a Folder are light-weight objects that
|
||||
* typically start off as empty references to the actual messages.
|
||||
* Such a Message object is filled in "on-demand" when the appropriate
|
||||
* get*() methods are invoked on that particular Message. Certain
|
||||
* server-based message access protocols (Ex: IMAP) allow batch
|
||||
* fetching of message attributes for a range of messages in a single
|
||||
* request. Clients that want to use message attributes for a range of
|
||||
* Messages (Example: to display the top-level headers in a headerlist)
|
||||
* might want to use the optimization provided by such servers. The
|
||||
* <code>FetchProfile</code> allows the client to indicate this desire
|
||||
* to the server. <p>
|
||||
* <p>
|
||||
* Note that implementations are not obligated to support
|
||||
* FetchProfiles, since there might be cases where the backend service
|
||||
* does not allow easy, efficient fetching of such profiles. <p>
|
||||
* <p>
|
||||
* Sample code that illustrates the use of a FetchProfile is given
|
||||
* below:
|
||||
* <blockquote>
|
||||
* <pre>
|
||||
*
|
||||
* Message[] msgs = folder.getMessages();
|
||||
*
|
||||
* FetchProfile fp = new FetchProfile();
|
||||
* fp.add(FetchProfile.Item.ENVELOPE);
|
||||
* fp.add("X-mailer");
|
||||
* folder.fetch(msgs, fp);
|
||||
*
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Bill Shannon
|
||||
* @see Folder#fetch
|
||||
*/
|
||||
|
||||
public class FetchProfile {
|
||||
|
||||
private Vector<Item> specials; // specials
|
||||
private Vector<String> headers; // vector of header names
|
||||
|
||||
/**
|
||||
* Create an empty FetchProfile.
|
||||
*/
|
||||
public FetchProfile() {
|
||||
specials = null;
|
||||
headers = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given special item as one of the attributes to
|
||||
* be prefetched.
|
||||
*
|
||||
* @param item the special item to be fetched
|
||||
* @see Item#ENVELOPE
|
||||
* @see Item#CONTENT_INFO
|
||||
* @see Item#FLAGS
|
||||
*/
|
||||
public void add(Item item) {
|
||||
if (specials == null)
|
||||
specials = new Vector<>();
|
||||
specials.addElement(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified header-field to the list of attributes
|
||||
* to be prefetched.
|
||||
*
|
||||
* @param headerName header to be prefetched
|
||||
*/
|
||||
public void add(String headerName) {
|
||||
if (headers == null)
|
||||
headers = new Vector<>();
|
||||
headers.addElement(headerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the fetch profile contains the given special item.
|
||||
*
|
||||
* @param item the Item to test
|
||||
* @return true if the fetch profile contains the given special item
|
||||
*/
|
||||
public boolean contains(Item item) {
|
||||
return specials != null && specials.contains(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the fetch profile contains the given header name.
|
||||
*
|
||||
* @param headerName the header to test
|
||||
* @return true if the fetch profile contains the given header name
|
||||
*/
|
||||
public boolean contains(String headerName) {
|
||||
return headers != null && headers.contains(headerName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the items set in this profile.
|
||||
*
|
||||
* @return items set in this profile
|
||||
*/
|
||||
public Item[] getItems() {
|
||||
if (specials == null)
|
||||
return new Item[0];
|
||||
|
||||
Item[] s = new Item[specials.size()];
|
||||
specials.copyInto(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the names of the header-fields set in this profile.
|
||||
*
|
||||
* @return headers set in this profile
|
||||
*/
|
||||
public String[] getHeaderNames() {
|
||||
if (headers == null)
|
||||
return new String[0];
|
||||
|
||||
String[] s = new String[headers.size()];
|
||||
headers.copyInto(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* This inner class is the base class of all items that
|
||||
* can be requested in a FetchProfile. The items currently
|
||||
* defined here are <code>ENVELOPE</code>, <code>CONTENT_INFO</code>
|
||||
* and <code>FLAGS</code>. The <code>UIDFolder</code> interface
|
||||
* defines the <code>UID</code> Item as well. <p>
|
||||
* <p>
|
||||
* Note that this class only has a protected constructor, therby
|
||||
* restricting new Item types to either this class or subclasses.
|
||||
* This effectively implements a enumeration of allowed Item types.
|
||||
*
|
||||
* @see UIDFolder
|
||||
*/
|
||||
|
||||
public static class Item {
|
||||
/**
|
||||
* This is the Envelope item. <p>
|
||||
* <p>
|
||||
* The Envelope is an aggregration of the common attributes
|
||||
* of a Message. Implementations should include the following
|
||||
* attributes: From, To, Cc, Bcc, ReplyTo, Subject and Date.
|
||||
* More items may be included as well. <p>
|
||||
* <p>
|
||||
* For implementations of the IMAP4 protocol (RFC 2060), the
|
||||
* Envelope should include the ENVELOPE data item. More items
|
||||
* may be included too.
|
||||
*/
|
||||
public static final Item ENVELOPE = new Item("ENVELOPE");
|
||||
|
||||
/**
|
||||
* This item is for fetching information about the
|
||||
* content of the message. <p>
|
||||
* <p>
|
||||
* This includes all the attributes that describe the content
|
||||
* of the message. Implementations should include the following
|
||||
* attributes: ContentType, ContentDisposition,
|
||||
* ContentDescription, Size and LineCount. Other items may be
|
||||
* included as well.
|
||||
*/
|
||||
public static final Item CONTENT_INFO = new Item("CONTENT_INFO");
|
||||
|
||||
/**
|
||||
* SIZE is a fetch profile item that can be included in a
|
||||
* <code>FetchProfile</code> during a fetch request to a Folder.
|
||||
* This item indicates that the sizes of the messages in the specified
|
||||
* range should be prefetched.
|
||||
*
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public static final Item SIZE = new Item("SIZE");
|
||||
|
||||
/**
|
||||
* This is the Flags item.
|
||||
*/
|
||||
public static final Item FLAGS = new Item("FLAGS");
|
||||
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Constructor for an item. The name is used only for debugging.
|
||||
*
|
||||
* @param name the item name
|
||||
*/
|
||||
protected Item(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Include the name in the toString return value for debugging.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getName() + "[" + name + "]";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,650 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import java.util.Enumeration;
|
||||
import java.util.Hashtable;
|
||||
import java.util.Locale;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* The Flags class represents the set of flags on a Message. Flags
|
||||
* are composed of predefined system flags, and user defined flags. <p>
|
||||
* <p>
|
||||
* A System flag is represented by the <code>Flags.Flag</code>
|
||||
* inner class. A User defined flag is represented as a String.
|
||||
* User flags are case-independent. <p>
|
||||
* <p>
|
||||
* A set of standard system flags are predefined. Most folder
|
||||
* implementations are expected to support these flags. Some
|
||||
* implementations may also support arbitrary user-defined flags. The
|
||||
* <code>getPermanentFlags</code> method on a Folder returns a Flags
|
||||
* object that holds all the flags that are supported by that folder
|
||||
* implementation. <p>
|
||||
* <p>
|
||||
* A Flags object is serializable so that (for example) the
|
||||
* use of Flags objects in search terms can be serialized
|
||||
* along with the search terms. <p>
|
||||
*
|
||||
* <strong>Warning:</strong>
|
||||
* Serialized objects of this class may not be compatible with future
|
||||
* Jakarta Mail API releases. The current serialization support is
|
||||
* appropriate for short term storage. <p>
|
||||
* <p>
|
||||
* The below code sample illustrates how to set, examine, and get the
|
||||
* flags for a message.
|
||||
* <pre>
|
||||
*
|
||||
* Message m = folder.getMessage(1);
|
||||
* m.setFlag(Flags.Flag.DELETED, true); // set the DELETED flag
|
||||
*
|
||||
* // Check if DELETED flag is set on this message
|
||||
* if (m.isSet(Flags.Flag.DELETED))
|
||||
* System.out.println("DELETED message");
|
||||
*
|
||||
* // Examine ALL system flags for this message
|
||||
* Flags flags = m.getFlags();
|
||||
* Flags.Flag[] sf = flags.getSystemFlags();
|
||||
* for (int i = 0; i < sf.length; i++) {
|
||||
* if (sf[i] == Flags.Flag.DELETED)
|
||||
* System.out.println("DELETED message");
|
||||
* else if (sf[i] == Flags.Flag.SEEN)
|
||||
* System.out.println("SEEN message");
|
||||
* ......
|
||||
* ......
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Bill Shannon
|
||||
* @see Folder#getPermanentFlags
|
||||
*/
|
||||
|
||||
public class Flags {
|
||||
|
||||
private final static int ANSWERED_BIT = 0x01;
|
||||
private final static int DELETED_BIT = 0x02;
|
||||
private final static int DRAFT_BIT = 0x04;
|
||||
private final static int FLAGGED_BIT = 0x08;
|
||||
private final static int RECENT_BIT = 0x10;
|
||||
private final static int SEEN_BIT = 0x20;
|
||||
private final static int USER_BIT = 0x80000000;
|
||||
private int system_flags = 0;
|
||||
// used as a case-independent Set that preserves the original case,
|
||||
// the key is the lowercase flag name and the value is the original
|
||||
private Hashtable<String, String> user_flags = null;
|
||||
|
||||
/**
|
||||
* Construct an empty Flags object.
|
||||
*/
|
||||
public Flags() {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a Flags object initialized with the given flags.
|
||||
*
|
||||
* @param flags the flags for initialization
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Flags(Flags flags) {
|
||||
this.system_flags = flags.system_flags;
|
||||
if (flags.user_flags != null) {
|
||||
this.user_flags = flags.user_flags;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Flags object initialized with the given system flag.
|
||||
*
|
||||
* @param flag the flag for initialization
|
||||
*/
|
||||
public Flags(Flag flag) {
|
||||
this.system_flags |= flag.bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a Flags object initialized with the given user flag.
|
||||
*
|
||||
* @param flag the flag for initialization
|
||||
*/
|
||||
public Flags(String flag) {
|
||||
user_flags = new Hashtable<>(1);
|
||||
user_flags.put(flag.toLowerCase(Locale.ENGLISH), flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified system flag to this Flags object.
|
||||
*
|
||||
* @param flag the flag to add
|
||||
*/
|
||||
public void add(Flag flag) {
|
||||
system_flags |= flag.bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the specified user flag to this Flags object.
|
||||
*
|
||||
* @param flag the flag to add
|
||||
*/
|
||||
public void add(String flag) {
|
||||
if (user_flags == null)
|
||||
user_flags = new Hashtable<>(1);
|
||||
user_flags.put(flag.toLowerCase(Locale.ENGLISH), flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add all the flags in the given Flags object to this
|
||||
* Flags object.
|
||||
*
|
||||
* @param f Flags object
|
||||
*/
|
||||
public void add(Flags f) {
|
||||
system_flags |= f.system_flags; // add system flags
|
||||
|
||||
if (f.user_flags != null) { // add user-defined flags
|
||||
if (user_flags == null)
|
||||
user_flags = new Hashtable<>(1);
|
||||
|
||||
Enumeration<String> e = f.user_flags.keys();
|
||||
|
||||
while (e.hasMoreElements()) {
|
||||
String s = e.nextElement();
|
||||
user_flags.put(s, f.user_flags.get(s));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified system flag from this Flags object.
|
||||
*
|
||||
* @param flag the flag to be removed
|
||||
*/
|
||||
public void remove(Flag flag) {
|
||||
system_flags &= ~flag.bit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified user flag from this Flags object.
|
||||
*
|
||||
* @param flag the flag to be removed
|
||||
*/
|
||||
public void remove(String flag) {
|
||||
if (user_flags != null)
|
||||
user_flags.remove(flag.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all flags in the given Flags object from this
|
||||
* Flags object.
|
||||
*
|
||||
* @param f the flag to be removed
|
||||
*/
|
||||
public void remove(Flags f) {
|
||||
system_flags &= ~f.system_flags; // remove system flags
|
||||
|
||||
if (f.user_flags != null) {
|
||||
if (user_flags == null)
|
||||
return;
|
||||
|
||||
Enumeration<String> e = f.user_flags.keys();
|
||||
while (e.hasMoreElements())
|
||||
user_flags.remove(e.nextElement());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove any flags <strong>not</strong> in the given Flags object.
|
||||
* Useful for clearing flags not supported by a server. If the
|
||||
* given Flags object includes the Flags.Flag.USER flag, all user
|
||||
* flags in this Flags object are retained.
|
||||
*
|
||||
* @param f the flags to keep
|
||||
* @return true if this Flags object changed
|
||||
* @since JavaMail 1.6
|
||||
*/
|
||||
public boolean retainAll(Flags f) {
|
||||
boolean changed = false;
|
||||
int sf = system_flags & f.system_flags;
|
||||
if (system_flags != sf) {
|
||||
system_flags = sf;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
// if we have user flags, and the USER flag is not set in "f",
|
||||
// determine which user flags to clear
|
||||
if (user_flags != null && (f.system_flags & USER_BIT) == 0) {
|
||||
if (f.user_flags != null) {
|
||||
Enumeration<String> e = user_flags.keys();
|
||||
while (e.hasMoreElements()) {
|
||||
String key = e.nextElement();
|
||||
if (!f.user_flags.containsKey(key)) {
|
||||
user_flags.remove(key);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// if anything in user_flags, throw them away
|
||||
changed = user_flags.size() > 0;
|
||||
user_flags = null;
|
||||
}
|
||||
}
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the specified system flag is present in this Flags object.
|
||||
*
|
||||
* @param flag the flag to test
|
||||
* @return true of the given flag is present, otherwise false.
|
||||
*/
|
||||
public boolean contains(Flag flag) {
|
||||
return (system_flags & flag.bit) != 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the specified user flag is present in this Flags object.
|
||||
*
|
||||
* @param flag the flag to test
|
||||
* @return true of the given flag is present, otherwise false.
|
||||
*/
|
||||
public boolean contains(String flag) {
|
||||
if (user_flags == null)
|
||||
return false;
|
||||
else
|
||||
return user_flags.containsKey(flag.toLowerCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether all the flags in the specified Flags object are
|
||||
* present in this Flags object.
|
||||
*
|
||||
* @param f the flags to test
|
||||
* @return true if all flags in the given Flags object are present,
|
||||
* otherwise false.
|
||||
*/
|
||||
public boolean contains(Flags f) {
|
||||
// Check system flags
|
||||
if ((f.system_flags & system_flags) != f.system_flags)
|
||||
return false;
|
||||
|
||||
// Check user flags
|
||||
if (f.user_flags != null) {
|
||||
if (user_flags == null)
|
||||
return false;
|
||||
Enumeration<String> e = f.user_flags.keys();
|
||||
|
||||
while (e.hasMoreElements()) {
|
||||
if (!user_flags.containsKey(e.nextElement()))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we've made it till here, return true
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the two Flags objects are equal.
|
||||
*
|
||||
* @return true if they're equal
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof Flags))
|
||||
return false;
|
||||
|
||||
Flags f = (Flags) obj;
|
||||
|
||||
// Check system flags
|
||||
if (f.system_flags != this.system_flags)
|
||||
return false;
|
||||
|
||||
// Check user flags
|
||||
int size = this.user_flags == null ? 0 : this.user_flags.size();
|
||||
int fsize = f.user_flags == null ? 0 : f.user_flags.size();
|
||||
if (size == 0 && fsize == 0)
|
||||
return true;
|
||||
if (f.user_flags != null && this.user_flags != null && fsize == size)
|
||||
return user_flags.keySet().equals(f.user_flags.keySet());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute a hash code for this Flags object.
|
||||
*
|
||||
* @return the hash code
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int hash = system_flags;
|
||||
if (user_flags != null) {
|
||||
Enumeration<String> e = user_flags.keys();
|
||||
while (e.hasMoreElements())
|
||||
hash += e.nextElement().hashCode();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the system flags in this Flags object. Returns
|
||||
* an array of size zero if no flags are set.
|
||||
*
|
||||
* @return array of Flags.Flag objects representing system flags
|
||||
*/
|
||||
public Flag[] getSystemFlags() {
|
||||
Vector<Flag> v = new Vector<>();
|
||||
if ((system_flags & ANSWERED_BIT) != 0)
|
||||
v.addElement(Flag.ANSWERED);
|
||||
if ((system_flags & DELETED_BIT) != 0)
|
||||
v.addElement(Flag.DELETED);
|
||||
if ((system_flags & DRAFT_BIT) != 0)
|
||||
v.addElement(Flag.DRAFT);
|
||||
if ((system_flags & FLAGGED_BIT) != 0)
|
||||
v.addElement(Flag.FLAGGED);
|
||||
if ((system_flags & RECENT_BIT) != 0)
|
||||
v.addElement(Flag.RECENT);
|
||||
if ((system_flags & SEEN_BIT) != 0)
|
||||
v.addElement(Flag.SEEN);
|
||||
if ((system_flags & USER_BIT) != 0)
|
||||
v.addElement(Flag.USER);
|
||||
|
||||
Flag[] f = new Flag[v.size()];
|
||||
v.copyInto(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the user flags in this Flags object. Returns
|
||||
* an array of size zero if no flags are set.
|
||||
*
|
||||
* @return array of Strings, each String represents a flag.
|
||||
*/
|
||||
public String[] getUserFlags() {
|
||||
Vector<String> v = new Vector<>();
|
||||
if (user_flags != null) {
|
||||
Enumeration<String> e = user_flags.elements();
|
||||
|
||||
while (e.hasMoreElements())
|
||||
v.addElement(e.nextElement());
|
||||
}
|
||||
|
||||
String[] f = new String[v.size()];
|
||||
v.copyInto(f);
|
||||
return f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all of the system flags.
|
||||
*
|
||||
* @since JavaMail 1.6
|
||||
*/
|
||||
public void clearSystemFlags() {
|
||||
system_flags = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all of the user flags.
|
||||
*
|
||||
* @since JavaMail 1.6
|
||||
*/
|
||||
public void clearUserFlags() {
|
||||
user_flags = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a string representation of this Flags object.
|
||||
* Note that the exact format of the string is subject to change.
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if ((system_flags & ANSWERED_BIT) != 0)
|
||||
sb.append("\\Answered ");
|
||||
if ((system_flags & DELETED_BIT) != 0)
|
||||
sb.append("\\Deleted ");
|
||||
if ((system_flags & DRAFT_BIT) != 0)
|
||||
sb.append("\\Draft ");
|
||||
if ((system_flags & FLAGGED_BIT) != 0)
|
||||
sb.append("\\Flagged ");
|
||||
if ((system_flags & RECENT_BIT) != 0)
|
||||
sb.append("\\Recent ");
|
||||
if ((system_flags & SEEN_BIT) != 0)
|
||||
sb.append("\\Seen ");
|
||||
if ((system_flags & USER_BIT) != 0)
|
||||
sb.append("\\* ");
|
||||
|
||||
boolean first = true;
|
||||
if (user_flags != null) {
|
||||
Enumeration<String> e = user_flags.elements();
|
||||
|
||||
while (e.hasMoreElements()) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
sb.append(' ');
|
||||
sb.append(e.nextElement());
|
||||
}
|
||||
}
|
||||
|
||||
if (first && !sb.isEmpty())
|
||||
sb.setLength(sb.length() - 1); // smash trailing space
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* This inner class represents an individual system flag. A set
|
||||
* of standard system flag objects are predefined here.
|
||||
*/
|
||||
public static final class Flag {
|
||||
/**
|
||||
* This message has been answered. This flag is set by clients
|
||||
* to indicate that this message has been answered to.
|
||||
*/
|
||||
public static final Flag ANSWERED = new Flag(ANSWERED_BIT);
|
||||
|
||||
/**
|
||||
* This message is marked deleted. Clients set this flag to
|
||||
* mark a message as deleted. The expunge operation on a folder
|
||||
* removes all messages in that folder that are marked for deletion.
|
||||
*/
|
||||
public static final Flag DELETED = new Flag(DELETED_BIT);
|
||||
|
||||
/**
|
||||
* This message is a draft. This flag is set by clients
|
||||
* to indicate that the message is a draft message.
|
||||
*/
|
||||
public static final Flag DRAFT = new Flag(DRAFT_BIT);
|
||||
|
||||
/**
|
||||
* This message is flagged. No semantic is defined for this flag.
|
||||
* Clients alter this flag.
|
||||
*/
|
||||
public static final Flag FLAGGED = new Flag(FLAGGED_BIT);
|
||||
|
||||
/**
|
||||
* This message is recent. Folder implementations set this flag
|
||||
* to indicate that this message is new to this folder, that is,
|
||||
* it has arrived since the last time this folder was opened. <p>
|
||||
* <p>
|
||||
* Clients cannot alter this flag.
|
||||
*/
|
||||
public static final Flag RECENT = new Flag(RECENT_BIT);
|
||||
|
||||
/**
|
||||
* This message is seen. This flag is implicitly set by the
|
||||
* implementation when this Message's content is returned
|
||||
* to the client in some form. The <code>getInputStream</code>
|
||||
* and <code>getContent</code> methods on Message cause this
|
||||
* flag to be set. <p>
|
||||
* <p>
|
||||
* Clients can alter this flag.
|
||||
*/
|
||||
public static final Flag SEEN = new Flag(SEEN_BIT);
|
||||
|
||||
/**
|
||||
* A special flag that indicates that this folder supports
|
||||
* user defined flags. <p>
|
||||
* <p>
|
||||
* The implementation sets this flag. Clients cannot alter
|
||||
* this flag but can use it to determine if a folder supports
|
||||
* user defined flags by using
|
||||
* <code>folder.getPermanentFlags().contains(Flags.Flag.USER)</code>.
|
||||
*/
|
||||
public static final Flag USER = new Flag(USER_BIT);
|
||||
|
||||
// flags are stored as bits for efficiency
|
||||
private int bit;
|
||||
|
||||
private Flag(int bit) {
|
||||
this.bit = bit;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
public static void main(String argv[]) throws Exception {
|
||||
// a new flags object
|
||||
Flags f1 = new Flags();
|
||||
f1.add(Flags.Flag.DELETED);
|
||||
f1.add(Flags.Flag.SEEN);
|
||||
f1.add(Flags.Flag.RECENT);
|
||||
f1.add(Flags.Flag.ANSWERED);
|
||||
|
||||
// check copy constructor with only system flags
|
||||
Flags fc = new Flags(f1);
|
||||
if (f1.equals(fc) && fc.equals(f1))
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
|
||||
// check clone with only system flags
|
||||
fc = (Flags)f1;
|
||||
if (f1.equals(fc) && fc.equals(f1))
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
|
||||
// add a user flag and make sure it still works right
|
||||
f1.add("MyFlag");
|
||||
|
||||
// shouldn't be equal here
|
||||
if (!f1.equals(fc) && !fc.equals(f1))
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
|
||||
// check
|
||||
fc = (Flags)f1;
|
||||
if (f1.equals(fc) && fc.equals(f1))
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
|
||||
// make sure user flag hash tables are separate
|
||||
fc.add("AnotherFlag");
|
||||
if (!f1.equals(fc) && !fc.equals(f1))
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
|
||||
// check copy constructor
|
||||
fc = new Flags(f1);
|
||||
if (f1.equals(fc) && fc.equals(f1))
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
|
||||
// another new flags object
|
||||
Flags f2 = new Flags(Flags.Flag.ANSWERED);
|
||||
f2.add("MyFlag");
|
||||
|
||||
if (f1.contains(Flags.Flag.DELETED))
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
|
||||
if (f1.contains(Flags.Flag.SEEN))
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
|
||||
if (f1.contains(Flags.Flag.RECENT))
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
|
||||
if (f1.contains("MyFlag"))
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
|
||||
if (f2.contains(Flags.Flag.ANSWERED))
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
|
||||
|
||||
System.out.println("----------------");
|
||||
|
||||
String[] s = f1.getUserFlags();
|
||||
for (int i = 0; i < s.length; i++)
|
||||
System.out.println(s[i]);
|
||||
System.out.println("----------------");
|
||||
s = f2.getUserFlags();
|
||||
for (int i = 0; i < s.length; i++)
|
||||
System.out.println(s[i]);
|
||||
|
||||
System.out.println("----------------");
|
||||
|
||||
if (f1.contains(f2)) // this should be true
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
|
||||
if (!f2.contains(f1)) // this should be false
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
|
||||
Flags f3 = new Flags();
|
||||
f3.add(Flags.Flag.DELETED);
|
||||
f3.add(Flags.Flag.SEEN);
|
||||
f3.add(Flags.Flag.RECENT);
|
||||
f3.add(Flags.Flag.ANSWERED);
|
||||
f3.add("ANOTHERFLAG");
|
||||
f3.add("MYFLAG");
|
||||
|
||||
f1.add("AnotherFlag");
|
||||
|
||||
if (f1.equals(f3))
|
||||
System.out.println("equals success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
if (f3.equals(f1))
|
||||
System.out.println("equals success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
System.out.println("f1 hash code " + f1.hashCode());
|
||||
System.out.println("f3 hash code " + f3.hashCode());
|
||||
if (f1.hashCode() == f3.hashCode())
|
||||
System.out.println("success");
|
||||
else
|
||||
System.out.println("fail");
|
||||
}
|
||||
****/
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* This exception is thrown when a method is invoked on a Messaging object
|
||||
* and the Folder that owns that object has died due to some reason. <p>
|
||||
* <p>
|
||||
* Following the exception, the Folder is reset to the "closed" state.
|
||||
* All messaging objects owned by the Folder should be considered invalid.
|
||||
* The Folder can be reopened using the "open" method to reestablish the
|
||||
* lost connection. <p>
|
||||
* <p>
|
||||
* The getMessage() method returns more detailed information about the
|
||||
* error that caused this exception.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class FolderClosedException extends MessagingException {
|
||||
transient private Folder folder;
|
||||
|
||||
/**
|
||||
* Constructs a FolderClosedException.
|
||||
*
|
||||
* @param folder The Folder
|
||||
*/
|
||||
public FolderClosedException(Folder folder) {
|
||||
this(folder, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a FolderClosedException with the specified
|
||||
* detail message.
|
||||
*
|
||||
* @param folder The Folder
|
||||
* @param message The detailed error message
|
||||
*/
|
||||
public FolderClosedException(Folder folder, String message) {
|
||||
super(message);
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a FolderClosedException with the specified
|
||||
* detail message and embedded exception. The exception is chained
|
||||
* to this exception.
|
||||
*
|
||||
* @param folder The Folder
|
||||
* @param message The detailed error message
|
||||
* @param e The embedded exception
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public FolderClosedException(Folder folder, String message, Exception e) {
|
||||
super(message, e);
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dead Folder object
|
||||
*
|
||||
* @return the dead Folder object
|
||||
*/
|
||||
public Folder getFolder() {
|
||||
return folder;
|
||||
}
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* This exception is thrown by Folder methods, when those
|
||||
* methods are invoked on a non existent folder.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class FolderNotFoundException extends MessagingException {
|
||||
transient private Folder folder;
|
||||
|
||||
/**
|
||||
* Constructs a FolderNotFoundException with no detail message.
|
||||
*/
|
||||
public FolderNotFoundException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a FolderNotFoundException.
|
||||
*
|
||||
* @param folder The Folder
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public FolderNotFoundException(Folder folder) {
|
||||
super();
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a FolderNotFoundException with the specified
|
||||
* detail message.
|
||||
*
|
||||
* @param folder The Folder
|
||||
* @param s The detailed error message
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public FolderNotFoundException(Folder folder, String s) {
|
||||
super(s);
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a FolderNotFoundException with the specified
|
||||
* detail message and embedded exception. The exception is chained
|
||||
* to this exception.
|
||||
*
|
||||
* @param folder The Folder
|
||||
* @param s The detailed error message
|
||||
* @param e The embedded exception
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public FolderNotFoundException(Folder folder, String s, Exception e) {
|
||||
super(s, e);
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a FolderNotFoundException with the specified detail message
|
||||
* and the specified folder.
|
||||
*
|
||||
* @param s The detail message
|
||||
* @param folder The Folder
|
||||
*/
|
||||
public FolderNotFoundException(String s, Folder folder) {
|
||||
super(s);
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the offending Folder object.
|
||||
*
|
||||
* @return the Folder object. Note that the returned value can be
|
||||
* <code>null</code>.
|
||||
*/
|
||||
public Folder getFolder() {
|
||||
return folder;
|
||||
}
|
||||
}
|
|
@ -1,91 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* The Header class stores a name/value pair to represent headers.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
|
||||
public class Header {
|
||||
|
||||
/**
|
||||
* The name of the header.
|
||||
*
|
||||
* @since JavaMail 1.4
|
||||
*/
|
||||
protected String name;
|
||||
|
||||
/**
|
||||
* The value of the header.
|
||||
*
|
||||
* @since JavaMail 1.4
|
||||
*/
|
||||
protected String value;
|
||||
|
||||
/**
|
||||
* Construct a Header object.
|
||||
*
|
||||
* @param name name of the header
|
||||
* @param value value of the header
|
||||
*/
|
||||
public Header(String name, String value) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this header.
|
||||
*
|
||||
* @return name of the header
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this header.
|
||||
*
|
||||
* @return value of the header
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
} else if (obj == null) {
|
||||
return false;
|
||||
} else if (getClass() != obj.getClass()) {
|
||||
return false;
|
||||
} else {
|
||||
Header other = (Header) obj;
|
||||
return Objects.equals(name, other.getName()) && Objects.equals(value, other.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
|
||||
/**
|
||||
* The exception thrown when a write is attempted on a read-only attribute
|
||||
* of any Messaging object.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class IllegalWriteException extends MessagingException {
|
||||
|
||||
/**
|
||||
* Constructs an IllegalWriteException with no detail message.
|
||||
*/
|
||||
public IllegalWriteException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an IllegalWriteException with the specified
|
||||
* detail message.
|
||||
*
|
||||
* @param s The detailed error message
|
||||
*/
|
||||
public IllegalWriteException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an IllegalWriteException with the specified
|
||||
* detail message and embedded exception. The exception is chained
|
||||
* to this exception.
|
||||
*
|
||||
* @param s The detailed error message
|
||||
* @param e The embedded exception
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public IllegalWriteException(String s, Exception e) {
|
||||
super(s, e);
|
||||
}
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Repeatable;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation used by Jakarta EE applications to define a <code>MailSession</code>
|
||||
* to be registered with JNDI. The <code>MailSession</code> may be configured
|
||||
* by setting the annotation elements for commonly used <code>Session</code>
|
||||
* properties. Additional standard and vendor-specific properties may be
|
||||
* specified using the <code>properties</code> element.
|
||||
* <p>
|
||||
* The session will be registered under the name specified in the
|
||||
* <code>name</code> element. It may be defined to be in any valid
|
||||
* <code>Jakarta EE</code> namespace, and will determine the accessibility of
|
||||
* the session from other components.
|
||||
*
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Repeatable(MailSessionDefinitions.class)
|
||||
public @interface MailSessionDefinition {
|
||||
|
||||
/**
|
||||
* Description of this mail session.
|
||||
*
|
||||
* @return the description
|
||||
*/
|
||||
String description() default "";
|
||||
|
||||
/**
|
||||
* JNDI name by which the mail session will be registered.
|
||||
*
|
||||
* @return the JNDI name
|
||||
*/
|
||||
String name();
|
||||
|
||||
/**
|
||||
* Store protocol name.
|
||||
*
|
||||
* @return the store protocol name
|
||||
*/
|
||||
String storeProtocol() default "";
|
||||
|
||||
/**
|
||||
* Transport protocol name.
|
||||
*
|
||||
* @return the transport protocol name
|
||||
*/
|
||||
String transportProtocol() default "";
|
||||
|
||||
/**
|
||||
* Host name for the mail server.
|
||||
*
|
||||
* @return the host name
|
||||
*/
|
||||
String host() default "";
|
||||
|
||||
/**
|
||||
* User name to use for authentication.
|
||||
*
|
||||
* @return the user name
|
||||
*/
|
||||
String user() default "";
|
||||
|
||||
/**
|
||||
* Password to use for authentication.
|
||||
*
|
||||
* @return the password
|
||||
*/
|
||||
String password() default "";
|
||||
|
||||
/**
|
||||
* From address for the user.
|
||||
*
|
||||
* @return the from address
|
||||
*/
|
||||
String from() default "";
|
||||
|
||||
/**
|
||||
* Properties to include in the Session.
|
||||
* Properties are specified using the format:
|
||||
* <i>propertyName=propertyValue</i> with one property per array element.
|
||||
*
|
||||
* @return the properties
|
||||
*/
|
||||
String[] properties() default {};
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2012, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Declares one or more <code>MailSessionDefinition</code> annotations.
|
||||
*
|
||||
* @see MailSessionDefinition
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface MailSessionDefinitions {
|
||||
MailSessionDefinition[] value();
|
||||
}
|
|
@ -1,678 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import jakarta.mail.search.SearchTerm;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* This class models an email message. This is an abstract class.
|
||||
* Subclasses provide actual implementations. <p>
|
||||
* <p>
|
||||
* Message implements the Part interface. Message contains a set of
|
||||
* attributes and a "content". Messages within a folder also have a
|
||||
* set of flags that describe its state within the folder.<p>
|
||||
* <p>
|
||||
* Message defines some new attributes in addition to those defined
|
||||
* in the <code>Part</code> interface. These attributes specify meta-data
|
||||
* for the message - i.e., addressing and descriptive information about
|
||||
* the message. <p>
|
||||
* <p>
|
||||
* Message objects are obtained either from a Folder or by constructing
|
||||
* a new Message object of the appropriate subclass. Messages that have
|
||||
* been received are normally retrieved from a folder named "INBOX". <p>
|
||||
* <p>
|
||||
* A Message object obtained from a folder is just a lightweight
|
||||
* reference to the actual message. The Message is 'lazily' filled
|
||||
* up (on demand) when each item is requested from the message. Note
|
||||
* that certain folder implementations may return Message objects that
|
||||
* are pre-filled with certain user-specified items.
|
||||
* <p>
|
||||
* To send a message, an appropriate subclass of Message (e.g.,
|
||||
* MimeMessage) is instantiated, the attributes and content are
|
||||
* filled in, and the message is sent using the <code>Transport.send</code>
|
||||
* method.
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Bill Shannon
|
||||
* @author Max Spivak
|
||||
* @see Part
|
||||
*/
|
||||
|
||||
public abstract class Message implements Part {
|
||||
|
||||
/**
|
||||
* The number of this message within its folder, or zero if
|
||||
* the message was not retrieved from a folder.
|
||||
*/
|
||||
protected int msgnum = 0;
|
||||
|
||||
/**
|
||||
* True if this message has been expunged.
|
||||
*/
|
||||
protected boolean expunged = false;
|
||||
|
||||
/**
|
||||
* The containing folder, if this message is obtained from a folder
|
||||
*/
|
||||
protected Folder folder = null;
|
||||
|
||||
/**
|
||||
* The Session object for this Message
|
||||
*/
|
||||
protected Session session = null;
|
||||
|
||||
/**
|
||||
* No-arg version of the constructor.
|
||||
*/
|
||||
protected Message() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes a Folder and a message number.
|
||||
* Used by Folder implementations.
|
||||
*
|
||||
* @param folder containing folder
|
||||
* @param msgnum this message's sequence number within this folder
|
||||
*/
|
||||
protected Message(Folder folder, int msgnum) {
|
||||
this.folder = folder;
|
||||
this.msgnum = msgnum;
|
||||
session = folder.store.session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes a Session. Used for client created
|
||||
* Message objects.
|
||||
*
|
||||
* @param session A Session object
|
||||
*/
|
||||
protected Message(Session session) {
|
||||
this.session = session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Session used when this message was created.
|
||||
*
|
||||
* @return the message's Session
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public Session getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the "From" attribute. The "From" attribute contains
|
||||
* the identity of the person(s) who wished this message to
|
||||
* be sent. <p>
|
||||
* <p>
|
||||
* In certain implementations, this may be different
|
||||
* from the entity that actually sent the message. <p>
|
||||
* <p>
|
||||
* This method returns <code>null</code> if this attribute
|
||||
* is not present in this message. Returns an empty array if
|
||||
* this attribute is present, but contains no addresses.
|
||||
*
|
||||
* @return array of Address objects
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
public abstract Address[] getFrom() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Set the "From" attribute in this Message.
|
||||
*
|
||||
* @param address the sender
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws IllegalStateException if this message is
|
||||
* obtained from a READ_ONLY folder.
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public abstract void setFrom(Address address)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Set the "From" attribute in this Message. The value of this
|
||||
* attribute is obtained from the property "mail.user". If this
|
||||
* property is absent, the system property "user.name" is used.
|
||||
*
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws IllegalStateException if this message is
|
||||
* obtained from a READ_ONLY folder.
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public abstract void setFrom() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Add these addresses to the existing "From" attribute
|
||||
*
|
||||
* @param addresses the senders
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws IllegalStateException if this message is
|
||||
* obtained from a READ_ONLY folder.
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public abstract void addFrom(Address[] addresses)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get all the recipient addresses of the given type. <p>
|
||||
* <p>
|
||||
* This method returns <code>null</code> if no recipients of
|
||||
* the given type are present in this message. It may return an
|
||||
* empty array if the header is present, but contains no addresses.
|
||||
*
|
||||
* @param type the recipient type
|
||||
* @return array of Address objects
|
||||
* @throws MessagingException for failures
|
||||
* @see RecipientType#TO
|
||||
* @see RecipientType#CC
|
||||
* @see RecipientType#BCC
|
||||
*/
|
||||
public abstract Address[] getRecipients(RecipientType type)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get all the recipient addresses for the message.
|
||||
* The default implementation extracts the TO, CC, and BCC
|
||||
* recipients using the <code>getRecipients</code> method. <p>
|
||||
* <p>
|
||||
* This method returns <code>null</code> if none of the recipient
|
||||
* headers are present in this message. It may Return an empty array
|
||||
* if any recipient header is present, but contains no addresses.
|
||||
*
|
||||
* @return array of Address objects
|
||||
* @throws MessagingException for failures
|
||||
* @see RecipientType#TO
|
||||
* @see RecipientType#CC
|
||||
* @see RecipientType#BCC
|
||||
* @see #getRecipients
|
||||
*/
|
||||
public Address[] getAllRecipients() throws MessagingException {
|
||||
Address[] to = getRecipients(RecipientType.TO);
|
||||
Address[] cc = getRecipients(RecipientType.CC);
|
||||
Address[] bcc = getRecipients(RecipientType.BCC);
|
||||
|
||||
if (cc == null && bcc == null)
|
||||
return to; // a common case
|
||||
|
||||
int numRecip =
|
||||
(to != null ? to.length : 0) +
|
||||
(cc != null ? cc.length : 0) +
|
||||
(bcc != null ? bcc.length : 0);
|
||||
Address[] addresses = new Address[numRecip];
|
||||
int pos = 0;
|
||||
if (to != null) {
|
||||
System.arraycopy(to, 0, addresses, pos, to.length);
|
||||
pos += to.length;
|
||||
}
|
||||
if (cc != null) {
|
||||
System.arraycopy(cc, 0, addresses, pos, cc.length);
|
||||
pos += cc.length;
|
||||
}
|
||||
if (bcc != null) {
|
||||
System.arraycopy(bcc, 0, addresses, pos, bcc.length);
|
||||
// pos += bcc.length;
|
||||
}
|
||||
return addresses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the recipient addresses. All addresses of the specified
|
||||
* type are replaced by the addresses parameter.
|
||||
*
|
||||
* @param type the recipient type
|
||||
* @param addresses the addresses
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws IllegalStateException if this message is
|
||||
* obtained from a READ_ONLY folder.
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public abstract void setRecipients(RecipientType type, Address[] addresses)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Set the recipient address. All addresses of the specified
|
||||
* type are replaced by the address parameter. <p>
|
||||
* <p>
|
||||
* The default implementation uses the <code>setRecipients</code> method.
|
||||
*
|
||||
* @param type the recipient type
|
||||
* @param address the address
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public void setRecipient(RecipientType type, Address address)
|
||||
throws MessagingException {
|
||||
if (address == null)
|
||||
setRecipients(type, null);
|
||||
else {
|
||||
Address[] a = new Address[1];
|
||||
a[0] = address;
|
||||
setRecipients(type, a);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add these recipient addresses to the existing ones of the given type.
|
||||
*
|
||||
* @param type the recipient type
|
||||
* @param addresses the addresses
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws IllegalStateException if this message is
|
||||
* obtained from a READ_ONLY folder.
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public abstract void addRecipients(RecipientType type, Address[] addresses)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Add this recipient address to the existing ones of the given type. <p>
|
||||
* <p>
|
||||
* The default implementation uses the <code>addRecipients</code> method.
|
||||
*
|
||||
* @param type the recipient type
|
||||
* @param address the address
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public void addRecipient(RecipientType type, Address address)
|
||||
throws MessagingException {
|
||||
Address[] a = new Address[1];
|
||||
a[0] = address;
|
||||
addRecipients(type, a);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the addresses to which replies should be directed.
|
||||
* This will usually be the sender of the message, but
|
||||
* some messages may direct replies to a different address. <p>
|
||||
* <p>
|
||||
* The default implementation simply calls the <code>getFrom</code>
|
||||
* method. <p>
|
||||
* <p>
|
||||
* This method returns <code>null</code> if the corresponding
|
||||
* header is not present. Returns an empty array if the header
|
||||
* is present, but contains no addresses.
|
||||
*
|
||||
* @return addresses to which replies should be directed
|
||||
* @throws MessagingException for failures
|
||||
* @see #getFrom
|
||||
*/
|
||||
public Address[] getReplyTo() throws MessagingException {
|
||||
return getFrom();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the addresses to which replies should be directed.
|
||||
* (Normally only a single address will be specified.)
|
||||
* Not all message types allow this to be specified separately
|
||||
* from the sender of the message. <p>
|
||||
* <p>
|
||||
* The default implementation provided here just throws the
|
||||
* MethodNotSupportedException.
|
||||
*
|
||||
* @param addresses addresses to which replies should be directed
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws IllegalStateException if this message is
|
||||
* obtained from a READ_ONLY folder.
|
||||
* @throws MethodNotSupportedException if the underlying
|
||||
* implementation does not support setting this
|
||||
* attribute
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public void setReplyTo(Address[] addresses) throws MessagingException {
|
||||
throw new MethodNotSupportedException("setReplyTo not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the subject of this message.
|
||||
*
|
||||
* @return the subject
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
public abstract String getSubject() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Set the subject of this message.
|
||||
*
|
||||
* @param subject the subject
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws IllegalStateException if this message is
|
||||
* obtained from a READ_ONLY folder.
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public abstract void setSubject(String subject)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get the date this message was sent.
|
||||
*
|
||||
* @return the date this message was sent
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
public abstract Date getSentDate() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Set the sent date of this message.
|
||||
*
|
||||
* @param date the sent date of this message
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws IllegalStateException if this message is
|
||||
* obtained from a READ_ONLY folder.
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public abstract void setSentDate(Date date) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get the date this message was received.
|
||||
*
|
||||
* @return the date this message was received
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
public abstract Date getReceivedDate() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Returns a <code>Flags</code> object containing the flags for
|
||||
* this message. <p>
|
||||
* <p>
|
||||
* Modifying any of the flags in this returned Flags object will
|
||||
* not affect the flags of this message. Use <code>setFlags()</code>
|
||||
* to do that.
|
||||
*
|
||||
* @return Flags object containing the flags for this message
|
||||
* @throws MessagingException for failures
|
||||
* @see Flags
|
||||
* @see #setFlags
|
||||
*/
|
||||
public abstract Flags getFlags() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Check whether the flag specified in the <code>flag</code>
|
||||
* argument is set in this message. <p>
|
||||
* <p>
|
||||
* The default implementation uses <code>getFlags</code>.
|
||||
*
|
||||
* @param flag the flag
|
||||
* @return value of the specified flag for this message
|
||||
* @throws MessagingException for failures
|
||||
* @see Flags.Flag#ANSWERED
|
||||
* @see Flags.Flag#DELETED
|
||||
* @see Flags.Flag#DRAFT
|
||||
* @see Flags.Flag#FLAGGED
|
||||
* @see Flags.Flag#RECENT
|
||||
* @see Flags.Flag#SEEN
|
||||
* @see Flags.Flag
|
||||
*/
|
||||
public boolean isSet(Flags.Flag flag) throws MessagingException {
|
||||
return getFlags().contains(flag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the specified flags on this message to the specified value.
|
||||
* Note that any flags in this message that are not specified in
|
||||
* the given <code>Flags</code> object are unaffected. <p>
|
||||
* <p>
|
||||
* This will result in a <code>MessageChangedEvent</code> being
|
||||
* delivered to any MessageChangedListener registered on this
|
||||
* Message's containing folder.
|
||||
*
|
||||
* @param flag Flags object containing the flags to be set
|
||||
* @param set the value to be set
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values.
|
||||
* @throws IllegalStateException if this message is
|
||||
* obtained from a READ_ONLY folder.
|
||||
* @throws MessagingException for other failures
|
||||
* @see jakarta.mail.event.MessageChangedEvent
|
||||
*/
|
||||
public abstract void setFlags(Flags flag, boolean set)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Set the specified flag on this message to the specified value.
|
||||
* <p>
|
||||
* This will result in a <code>MessageChangedEvent</code> being
|
||||
* delivered to any MessageChangedListener registered on this
|
||||
* Message's containing folder. <p>
|
||||
* <p>
|
||||
* The default implementation uses the <code>setFlags</code> method.
|
||||
*
|
||||
* @param flag Flags.Flag object containing the flag to be set
|
||||
* @param set the value to be set
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values.
|
||||
* @throws IllegalStateException if this message is
|
||||
* obtained from a READ_ONLY folder.
|
||||
* @throws MessagingException for other failures
|
||||
* @see jakarta.mail.event.MessageChangedEvent
|
||||
*/
|
||||
public void setFlag(Flags.Flag flag, boolean set)
|
||||
throws MessagingException {
|
||||
Flags f = new Flags(flag);
|
||||
setFlags(f, set);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Message number for this Message.
|
||||
* A Message object's message number is the relative
|
||||
* position of this Message in its Folder. Note that the message
|
||||
* number for a particular Message can change during a session
|
||||
* if other messages in the Folder are deleted and expunged. <p>
|
||||
* <p>
|
||||
* Valid message numbers start at 1. Messages that do not belong
|
||||
* to any folder (like newly composed or derived messages) have 0
|
||||
* as their message number.
|
||||
*
|
||||
* @return the message number
|
||||
*/
|
||||
public int getMessageNumber() {
|
||||
return msgnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Message number for this Message. This method is
|
||||
* invoked only by the implementation classes.
|
||||
*
|
||||
* @param msgnum the message number
|
||||
*/
|
||||
protected void setMessageNumber(int msgnum) {
|
||||
this.msgnum = msgnum;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the folder from which this message was obtained. If
|
||||
* this is a new message or nested message, this method returns
|
||||
* null.
|
||||
*
|
||||
* @return the containing folder
|
||||
*/
|
||||
public Folder getFolder() {
|
||||
return folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether this message is expunged. All other methods except
|
||||
* <code>getMessageNumber()</code> are invalid on an expunged
|
||||
* Message object. <p>
|
||||
* <p>
|
||||
* Messages that are expunged due to an explict <code>expunge()</code>
|
||||
* request on the containing Folder are removed from the Folder
|
||||
* immediately. Messages that are externally expunged by another source
|
||||
* are marked "expunged" and return true for the isExpunged() method,
|
||||
* but they are not removed from the Folder until an explicit
|
||||
* <code>expunge()</code> is done on the Folder. <p>
|
||||
* <p>
|
||||
* See the description of <code>expunge()</code> for more details on
|
||||
* expunge handling.
|
||||
*
|
||||
* @return true if the message is expunged
|
||||
* @see Folder#expunge
|
||||
*/
|
||||
public boolean isExpunged() {
|
||||
return expunged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the expunged flag for this Message. This method is to
|
||||
* be used only by the implementation classes.
|
||||
*
|
||||
* @param expunged the expunged flag
|
||||
*/
|
||||
protected void setExpunged(boolean expunged) {
|
||||
this.expunged = expunged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new Message suitable for a reply to this message.
|
||||
* The new Message will have its attributes and headers
|
||||
* set up appropriately. Note that this new message object
|
||||
* will be empty, that is, it will <strong>not</strong> have a "content".
|
||||
* These will have to be suitably filled in by the client. <p>
|
||||
* <p>
|
||||
* If <code>replyToAll</code> is set, the new Message will be addressed
|
||||
* to all recipients of this message. Otherwise, the reply will be
|
||||
* addressed to only the sender of this message (using the value
|
||||
* of the <code>getReplyTo</code> method). <p>
|
||||
* <p>
|
||||
* The "Subject" field is filled in with the original subject
|
||||
* prefixed with "Re:" (unless it already starts with "Re:"). <p>
|
||||
* <p>
|
||||
* The reply message will use the same session as this message.
|
||||
*
|
||||
* @param replyToAll reply should be sent to all recipients
|
||||
* of this message
|
||||
* @return the reply Message
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
public abstract Message reply(boolean replyToAll) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Save any changes made to this message into the message-store
|
||||
* when the containing folder is closed, if the message is contained
|
||||
* in a folder. (Some implementations may save the changes
|
||||
* immediately.) Update any header fields to be consistent with the
|
||||
* changed message contents. If any part of a message's headers or
|
||||
* contents are changed, saveChanges must be called to ensure that
|
||||
* those changes are permanent. If saveChanges is not called, any
|
||||
* such modifications may or may not be saved, depending on the
|
||||
* message store and folder implementation. <p>
|
||||
* <p>
|
||||
* Messages obtained from folders opened READ_ONLY should not be
|
||||
* modified and saveChanges should not be called on such messages.
|
||||
*
|
||||
* @throws IllegalStateException if this message is
|
||||
* obtained from a READ_ONLY folder.
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values.
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public abstract void saveChanges() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Apply the specified Search criterion to this message.
|
||||
*
|
||||
* @param term the Search criterion
|
||||
* @return true if the Message matches this search
|
||||
* criterion, false otherwise.
|
||||
* @throws MessagingException for failures
|
||||
* @see SearchTerm
|
||||
*/
|
||||
public boolean match(SearchTerm term) throws MessagingException {
|
||||
return term.match(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* This inner class defines the types of recipients allowed by
|
||||
* the Message class. The currently defined types are TO,
|
||||
* CC and BCC.
|
||||
* <p>
|
||||
* Note that this class only has a protected constructor, thereby
|
||||
* restricting new Recipient types to either this class or subclasses.
|
||||
* This effectively implements an enumeration of the allowed Recipient
|
||||
* types.
|
||||
* <p>
|
||||
* The following code sample shows how to use this class to obtain
|
||||
* the "TO" recipients from a message.
|
||||
* <blockquote><pre>
|
||||
*
|
||||
* Message msg = folder.getMessages(1);
|
||||
* Address[] a = m.getRecipients(Message.RecipientType.TO);
|
||||
*
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @see Message#getRecipients
|
||||
* @see Message#setRecipients
|
||||
* @see Message#addRecipients
|
||||
*/
|
||||
public static class RecipientType {
|
||||
/**
|
||||
* The "To" (primary) recipients.
|
||||
*/
|
||||
public static final RecipientType TO = new RecipientType("To");
|
||||
/**
|
||||
* The "Cc" (carbon copy) recipients.
|
||||
*/
|
||||
public static final RecipientType CC = new RecipientType("Cc");
|
||||
/**
|
||||
* The "Bcc" (blind carbon copy) recipients.
|
||||
*/
|
||||
public static final RecipientType BCC = new RecipientType("Bcc");
|
||||
|
||||
/**
|
||||
* The type of recipient, usually the name of a corresponding
|
||||
* Internet standard header.
|
||||
*/
|
||||
protected String type;
|
||||
|
||||
/**
|
||||
* Constructor for use by subclasses.
|
||||
*
|
||||
* @param type the recipient type
|
||||
*/
|
||||
protected RecipientType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* An interface optionally implemented by <code>DataSources</code> to
|
||||
* supply information to a <code>DataContentHandler</code> about the
|
||||
* message context in which the data content object is operating.
|
||||
*
|
||||
* @see MessageContext
|
||||
* @see jakarta.activation.DataSource
|
||||
* @see jakarta.activation.DataContentHandler
|
||||
* @since JavaMail 1.1
|
||||
*/
|
||||
public interface MessageAware {
|
||||
/**
|
||||
* Return the message context.
|
||||
*
|
||||
* @return the message context
|
||||
*/
|
||||
MessageContext getMessageContext();
|
||||
}
|
|
@ -1,100 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* The context in which a piece of Message content is contained. A
|
||||
* <code>MessageContext</code> object is returned by the
|
||||
* <code>getMessageContext</code> method of the
|
||||
* <code>MessageAware</code> interface. <code>MessageAware</code> is
|
||||
* typically implemented by <code>DataSources</code> to allow a
|
||||
* <code>DataContentHandler</code> to pass on information about the
|
||||
* context in which a data content object is operating.
|
||||
*
|
||||
* @see MessageAware
|
||||
* @see jakarta.activation.DataSource
|
||||
* @see jakarta.activation.DataContentHandler
|
||||
* @since JavaMail 1.1
|
||||
*/
|
||||
public class MessageContext {
|
||||
private Part part;
|
||||
|
||||
/**
|
||||
* Create a MessageContext object describing the context of the given Part.
|
||||
*
|
||||
* @param part the Part
|
||||
*/
|
||||
public MessageContext(Part part) {
|
||||
this.part = part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Message containing an arbitrary Part.
|
||||
* Follows the parent chain up through containing Multipart
|
||||
* objects until it comes to a Message object, or null.
|
||||
*
|
||||
* @return the containing Message, or null if none
|
||||
* @see BodyPart#getParent
|
||||
* @see Multipart#getParent
|
||||
*/
|
||||
private static Message getMessage(Part p) throws MessagingException {
|
||||
while (p != null) {
|
||||
if (p instanceof Message)
|
||||
return (Message) p;
|
||||
BodyPart bp = (BodyPart) p;
|
||||
Multipart mp = bp.getParent();
|
||||
if (mp == null) // MimeBodyPart might not be in a MimeMultipart
|
||||
return null;
|
||||
p = mp.getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Part that contains the content.
|
||||
*
|
||||
* @return the containing Part, or null if not known
|
||||
*/
|
||||
public Part getPart() {
|
||||
return part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Message that contains the content.
|
||||
* Follows the parent chain up through containing Multipart
|
||||
* objects until it comes to a Message object, or null.
|
||||
*
|
||||
* @return the containing Message, or null if not known
|
||||
*/
|
||||
public Message getMessage() {
|
||||
try {
|
||||
return getMessage(part);
|
||||
} catch (MessagingException ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Session we're operating in.
|
||||
*
|
||||
* @return the Session, or null if not known
|
||||
*/
|
||||
public Session getSession() {
|
||||
Message msg = getMessage();
|
||||
return msg != null ? msg.getSession() : null;
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* The exception thrown when an invalid method is invoked on an expunged
|
||||
* Message. The only valid methods on an expunged Message are
|
||||
* <code>isExpunged()</code> and <code>getMessageNumber()</code>.
|
||||
*
|
||||
* @author John Mani
|
||||
* @see Message#isExpunged()
|
||||
* @see Message#getMessageNumber()
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MessageRemovedException extends MessagingException {
|
||||
|
||||
/**
|
||||
* Constructs a MessageRemovedException with no detail message.
|
||||
*/
|
||||
public MessageRemovedException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MessageRemovedException with the specified
|
||||
* detail message.
|
||||
*
|
||||
* @param s The detailed error message
|
||||
*/
|
||||
public MessageRemovedException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MessageRemovedException with the specified
|
||||
* detail message and embedded exception. The exception is chained
|
||||
* to this exception.
|
||||
*
|
||||
* @param s The detailed error message
|
||||
* @param e The embedded exception
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public MessageRemovedException(String s, Exception e) {
|
||||
super(s, e);
|
||||
}
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* The base class for all exceptions thrown by the Messaging classes
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Bill Shannon
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MessagingException extends Exception {
|
||||
|
||||
/**
|
||||
* The next exception in the chain.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
private Exception next;
|
||||
|
||||
/**
|
||||
* Constructs a MessagingException with no detail message.
|
||||
*/
|
||||
public MessagingException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MessagingException with the specified detail message.
|
||||
*
|
||||
* @param s the detail message
|
||||
*/
|
||||
public MessagingException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MessagingException with the specified
|
||||
* Exception and detail message. The specified exception is chained
|
||||
* to this exception.
|
||||
*
|
||||
* @param s the detail message
|
||||
* @param e the embedded exception
|
||||
* @see #getNextException
|
||||
* @see #setNextException
|
||||
* @see #getCause
|
||||
*/
|
||||
public MessagingException(String s, Exception e) {
|
||||
super(s);
|
||||
next = e;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next exception chained to this one. If the
|
||||
* next exception is a MessagingException, the chain
|
||||
* may extend further.
|
||||
*
|
||||
* @return next Exception, null if none.
|
||||
*/
|
||||
public synchronized Exception getNextException() {
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides the <code>getCause</code> method of <code>Throwable</code>
|
||||
* to return the next exception in the chain of nested exceptions.
|
||||
*
|
||||
* @return next Exception, null if none.
|
||||
*/
|
||||
@Override
|
||||
public synchronized Throwable getCause() {
|
||||
return next;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an exception to the end of the chain. If the end
|
||||
* is <strong>not</strong> a MessagingException, this
|
||||
* exception cannot be added to the end.
|
||||
*
|
||||
* @param ex the new end of the Exception chain
|
||||
* @return <code>true</code> if this Exception
|
||||
* was added, <code>false</code> otherwise.
|
||||
*/
|
||||
public synchronized boolean setNextException(Exception ex) {
|
||||
Exception theEnd = this;
|
||||
while (theEnd instanceof MessagingException &&
|
||||
((MessagingException) theEnd).next != null) {
|
||||
theEnd = ((MessagingException) theEnd).next;
|
||||
}
|
||||
// If the end is a MessagingException, we can add this
|
||||
// exception to the chain.
|
||||
if (theEnd instanceof MessagingException) {
|
||||
((MessagingException) theEnd).next = ex;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Override toString method to provide information on
|
||||
* nested exceptions.
|
||||
*/
|
||||
@Override
|
||||
public synchronized String toString() {
|
||||
String s = super.toString();
|
||||
Exception n = next;
|
||||
if (n == null)
|
||||
return s;
|
||||
StringBuilder sb = new StringBuilder(s == null ? "" : s);
|
||||
while (n != null) {
|
||||
sb.append(";\n nested exception is:\n\t");
|
||||
if (n instanceof MessagingException) {
|
||||
MessagingException mex = (MessagingException) n;
|
||||
sb.append(mex.superToString());
|
||||
n = mex.next;
|
||||
} else {
|
||||
sb.append(n);
|
||||
n = null;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "toString" information for this exception,
|
||||
* without any information on nested exceptions.
|
||||
*/
|
||||
private final String superToString() {
|
||||
return super.toString();
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
|
||||
/**
|
||||
* The exception thrown when a method is not supported by the
|
||||
* implementation
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MethodNotSupportedException extends MessagingException {
|
||||
|
||||
/**
|
||||
* Constructs a MethodNotSupportedException with no detail message.
|
||||
*/
|
||||
public MethodNotSupportedException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MethodNotSupportedException with the specified
|
||||
* detail message.
|
||||
*
|
||||
* @param s The detailed error message
|
||||
*/
|
||||
public MethodNotSupportedException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a MethodNotSupportedException with the specified
|
||||
* detail message and embedded exception. The exception is chained
|
||||
* to this exception.
|
||||
*
|
||||
* @param s The detailed error message
|
||||
* @param e The embedded exception
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public MethodNotSupportedException(String s, Exception e) {
|
||||
super(s, e);
|
||||
}
|
||||
}
|
|
@ -1,265 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import jakarta.mail.util.StreamProvider;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* Multipart is a container that holds multiple body parts. Multipart
|
||||
* provides methods to retrieve and set its subparts. <p>
|
||||
* <p>
|
||||
* Multipart also acts as the base class for the content object returned
|
||||
* by most Multipart DataContentHandlers. For example, invoking getContent()
|
||||
* on a DataHandler whose source is a "multipart/signed" data source may
|
||||
* return an appropriate subclass of Multipart. <p>
|
||||
* <p>
|
||||
* Some messaging systems provide different subtypes of Multiparts. For
|
||||
* example, MIME specifies a set of subtypes that include "alternative",
|
||||
* "mixed", "related", "parallel", "signed", etc. <p>
|
||||
* <p>
|
||||
* Multipart is an abstract class. Subclasses provide actual implementations.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
|
||||
public abstract class Multipart {
|
||||
|
||||
/**
|
||||
* Instance of stream provider.
|
||||
*
|
||||
* @since JavaMail 2.1
|
||||
*/
|
||||
protected final StreamProvider streamProvider = StreamProvider.provider();
|
||||
/**
|
||||
* Vector of BodyPart objects.
|
||||
*/
|
||||
protected Vector<BodyPart> parts = new Vector<>(); // Holds BodyParts
|
||||
/**
|
||||
* This field specifies the content-type of this multipart
|
||||
* object. It defaults to "multipart/mixed".
|
||||
*/
|
||||
protected String contentType = "multipart/mixed"; // Content-Type
|
||||
/**
|
||||
* The <code>Part</code> containing this <code>Multipart</code>,
|
||||
* if known.
|
||||
*
|
||||
* @since JavaMail 1.1
|
||||
*/
|
||||
protected Part parent;
|
||||
|
||||
/**
|
||||
* Default constructor. An empty Multipart object is created.
|
||||
*/
|
||||
protected Multipart() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup this Multipart object from the given MultipartDataSource. <p>
|
||||
* <p>
|
||||
* The method adds the MultipartDataSource's BodyPart
|
||||
* objects into this Multipart. This Multipart's contentType is
|
||||
* set to that of the MultipartDataSource. <p>
|
||||
* <p>
|
||||
* This method is typically used in those cases where one
|
||||
* has a multipart data source that has already been pre-parsed into
|
||||
* the individual body parts (for example, an IMAP datasource), but
|
||||
* needs to create an appropriate Multipart subclass that represents
|
||||
* a specific multipart subtype.
|
||||
*
|
||||
* @param mp Multipart datasource
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
protected synchronized void setMultipartDataSource(MultipartDataSource mp)
|
||||
throws MessagingException {
|
||||
contentType = mp.getContentType();
|
||||
|
||||
int count = mp.getCount();
|
||||
for (int i = 0; i < count; i++)
|
||||
addBodyPart(mp.getBodyPart(i));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the content-type of this Multipart. <p>
|
||||
* <p>
|
||||
* This implementation just returns the value of the
|
||||
* <code>contentType</code> field.
|
||||
*
|
||||
* @return content-type
|
||||
* @see #contentType
|
||||
*/
|
||||
public synchronized String getContentType() {
|
||||
return contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the number of enclosed BodyPart objects.
|
||||
*
|
||||
* @return number of parts
|
||||
* @throws MessagingException for failures
|
||||
* @see #parts
|
||||
*/
|
||||
public synchronized int getCount() throws MessagingException {
|
||||
if (parts == null)
|
||||
return 0;
|
||||
|
||||
return parts.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the specified Part. Parts are numbered starting at 0.
|
||||
*
|
||||
* @param index the index of the desired Part
|
||||
* @return the Part
|
||||
* @throws IndexOutOfBoundsException if the given index
|
||||
* is out of range.
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public synchronized BodyPart getBodyPart(int index)
|
||||
throws MessagingException {
|
||||
if (parts == null)
|
||||
throw new IndexOutOfBoundsException("No such BodyPart");
|
||||
|
||||
return parts.elementAt(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the specified part from the multipart message.
|
||||
* Shifts all the parts after the removed part down one.
|
||||
*
|
||||
* @param part The part to remove
|
||||
* @return true if part removed, false otherwise
|
||||
* @throws MessagingException if no such Part exists
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
*/
|
||||
public synchronized boolean removeBodyPart(BodyPart part)
|
||||
throws MessagingException {
|
||||
if (parts == null)
|
||||
throw new MessagingException("No such body part");
|
||||
|
||||
boolean ret = parts.removeElement(part);
|
||||
part.setParent(null);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the part at specified location (starting from 0).
|
||||
* Shifts all the parts after the removed part down one.
|
||||
*
|
||||
* @param index Index of the part to remove
|
||||
* @throws IndexOutOfBoundsException if the given index
|
||||
* is out of range.
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public synchronized void removeBodyPart(int index)
|
||||
throws MessagingException {
|
||||
if (parts == null)
|
||||
throw new IndexOutOfBoundsException("No such BodyPart");
|
||||
|
||||
BodyPart part = parts.elementAt(index);
|
||||
parts.removeElementAt(index);
|
||||
part.setParent(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a Part to the multipart. The BodyPart is appended to
|
||||
* the list of existing Parts.
|
||||
*
|
||||
* @param part The Part to be appended
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public synchronized void addBodyPart(BodyPart part)
|
||||
throws MessagingException {
|
||||
if (parts == null)
|
||||
parts = new Vector<>();
|
||||
|
||||
parts.addElement(part);
|
||||
part.setParent(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a BodyPart at position <code>index</code>.
|
||||
* If <code>index</code> is not the last one in the list,
|
||||
* the subsequent parts are shifted up. If <code>index</code>
|
||||
* is larger than the number of parts present, the
|
||||
* BodyPart is appended to the end.
|
||||
*
|
||||
* @param part The BodyPart to be inserted
|
||||
* @param index Location where to insert the part
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public synchronized void addBodyPart(BodyPart part, int index)
|
||||
throws MessagingException {
|
||||
if (parts == null)
|
||||
parts = new Vector<>();
|
||||
|
||||
parts.insertElementAt(part, index);
|
||||
part.setParent(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output an appropriately encoded bytestream to the given
|
||||
* OutputStream. The implementation subclass decides the
|
||||
* appropriate encoding algorithm to be used. The bytestream
|
||||
* is typically used for sending.
|
||||
*
|
||||
* @param os the stream to write to
|
||||
* @throws IOException if an IO related exception occurs
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public abstract void writeTo(OutputStream os)
|
||||
throws IOException, MessagingException;
|
||||
|
||||
/**
|
||||
* Return the <code>Part</code> that contains this <code>Multipart</code>
|
||||
* object, or <code>null</code> if not known.
|
||||
*
|
||||
* @return the parent Part
|
||||
* @since JavaMail 1.1
|
||||
*/
|
||||
public synchronized Part getParent() {
|
||||
return parent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parent of this <code>Multipart</code> to be the specified
|
||||
* <code>Part</code>. Normally called by the <code>Message</code>
|
||||
* or <code>BodyPart</code> <code>setContent(Multipart)</code> method.
|
||||
* <code>parent</code> may be <code>null</code> if the
|
||||
* <code>Multipart</code> is being removed from its containing
|
||||
* <code>Part</code>.
|
||||
*
|
||||
* @param parent the parent Part
|
||||
* @since JavaMail 1.1
|
||||
*/
|
||||
public synchronized void setParent(Part parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
}
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import jakarta.activation.DataSource;
|
||||
|
||||
/**
|
||||
* MultipartDataSource is a <code>DataSource</code> that contains body
|
||||
* parts. This allows "mail aware" <code>DataContentHandlers</code> to
|
||||
* be implemented more efficiently by being aware of such
|
||||
* <code>DataSources</code> and using the appropriate methods to access
|
||||
* <code>BodyParts</code>. <p>
|
||||
* <p>
|
||||
* Note that the data of a MultipartDataSource is also available as
|
||||
* an input stream. <p>
|
||||
* <p>
|
||||
* This interface will typically be implemented by providers that
|
||||
* preparse multipart bodies, for example an IMAP provider.
|
||||
*
|
||||
* @author John Mani
|
||||
* @see jakarta.activation.DataSource
|
||||
*/
|
||||
|
||||
public interface MultipartDataSource extends DataSource {
|
||||
|
||||
/**
|
||||
* Return the number of enclosed BodyPart objects.
|
||||
*
|
||||
* @return number of parts
|
||||
*/
|
||||
int getCount();
|
||||
|
||||
/**
|
||||
* Get the specified Part. Parts are numbered starting at 0.
|
||||
*
|
||||
* @param index the index of the desired Part
|
||||
* @return the Part
|
||||
* @throws IndexOutOfBoundsException if the given index
|
||||
* is out of range.
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
BodyPart getBodyPart(int index) throws MessagingException;
|
||||
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* This exception is thrown when Session attempts to instantiate a
|
||||
* Provider that doesn't exist.
|
||||
*
|
||||
* @author Max Spivak
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class NoSuchProviderException extends MessagingException {
|
||||
|
||||
/**
|
||||
* Constructs a NoSuchProviderException with no detail message.
|
||||
*/
|
||||
public NoSuchProviderException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a NoSuchProviderException with the specified
|
||||
* detail message.
|
||||
*
|
||||
* @param message The detailed error message
|
||||
*/
|
||||
public NoSuchProviderException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a NoSuchProviderException with the specified
|
||||
* detail message and embedded exception. The exception is chained
|
||||
* to this exception.
|
||||
*
|
||||
* @param message The detailed error message
|
||||
* @param e The embedded exception
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public NoSuchProviderException(String message, Exception e) {
|
||||
super(message, e);
|
||||
}
|
||||
}
|
|
@ -1,454 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import jakarta.activation.DataHandler;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* The <code>Part</code> interface is the common base interface for
|
||||
* Messages and BodyParts. <p>
|
||||
* <p>
|
||||
* Part consists of a set of attributes and a "Content".<p>
|
||||
*
|
||||
* <strong> Attributes: </strong> <p>
|
||||
* <p>
|
||||
* The Jakarta Mail API defines a set of standard Part attributes that are
|
||||
* considered to be common to most existing Mail systems. These
|
||||
* attributes have their own settor and gettor methods. Mail systems
|
||||
* may support other Part attributes as well, these are represented as
|
||||
* name-value pairs where both the name and value are Strings.<p>
|
||||
*
|
||||
* <strong> Content: </strong> <p>
|
||||
* <p>
|
||||
* The <strong>data type</strong> of the "content" is returned by
|
||||
* the <code>getContentType()</code> method. The MIME typing system
|
||||
* is used to name data types. <p>
|
||||
* <p>
|
||||
* The "content" of a Part is available in various formats:
|
||||
* <ul>
|
||||
* <li> As a DataHandler - using the <code>getDataHandler()</code> method.
|
||||
* The "content" of a Part is also available through a
|
||||
* <code>jakarta.activation.DataHandler</code> object. The DataHandler
|
||||
* object allows clients to discover the operations available on the
|
||||
* content, and to instantiate the appropriate component to perform
|
||||
* those operations.
|
||||
*
|
||||
* <li> As an input stream - using the <code>getInputStream()</code> method.
|
||||
* Any mail-specific encodings are decoded before this stream is returned.
|
||||
*
|
||||
* <li> As a Java object - using the <code>getContent()</code> method.
|
||||
* This method returns the "content" as a Java object.
|
||||
* The returned object is of course dependent on the content
|
||||
* itself. In particular, a "multipart" Part's content is always a
|
||||
* Multipart or subclass thereof. That is, <code>getContent()</code> on a
|
||||
* "multipart" type Part will always return a Multipart (or subclass) object.
|
||||
* </ul>
|
||||
* <p>
|
||||
* Part provides the <code>writeTo()</code> method that streams
|
||||
* out its bytestream in mail-safe form suitable for transmission.
|
||||
* This bytestream is typically an aggregation of the Part attributes
|
||||
* and its content's bytestream. <p>
|
||||
* <p>
|
||||
* Message and BodyPart implement the Part interface. Note that in
|
||||
* MIME parlance, Part models an Entity (RFC 2045, Section 2.4).
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
|
||||
public interface Part {
|
||||
|
||||
/**
|
||||
* This part should be presented as an attachment.
|
||||
*
|
||||
* @see #getDisposition
|
||||
* @see #setDisposition
|
||||
*/
|
||||
String ATTACHMENT = "attachment";
|
||||
/**
|
||||
* This part should be presented inline.
|
||||
*
|
||||
* @see #getDisposition
|
||||
* @see #setDisposition
|
||||
*/
|
||||
String INLINE = "inline";
|
||||
|
||||
/**
|
||||
* Return the size of the content of this part in bytes.
|
||||
* Return -1 if the size cannot be determined. <p>
|
||||
* <p>
|
||||
* Note that the size may not be an exact measure of the content
|
||||
* size and may or may not account for any transfer encoding
|
||||
* of the content. The size is appropriate for display in a
|
||||
* user interface to give the user a rough idea of the size
|
||||
* of this part.
|
||||
*
|
||||
* @return size of content in bytes
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
int getSize() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Return the number of lines in the content of this part.
|
||||
* Return -1 if the number cannot be determined.
|
||||
* <p>
|
||||
* Note that this number may not be an exact measure of the
|
||||
* content length and may or may not account for any transfer
|
||||
* encoding of the content.
|
||||
*
|
||||
* @return number of lines in the content.
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
int getLineCount() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Returns the Content-Type of the content of this part.
|
||||
* Returns null if the Content-Type could not be determined. <p>
|
||||
* <p>
|
||||
* The MIME typing system is used to name Content-types.
|
||||
*
|
||||
* @return The ContentType of this part
|
||||
* @throws MessagingException for failures
|
||||
* @see jakarta.activation.DataHandler
|
||||
*/
|
||||
String getContentType() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Is this Part of the specified MIME type? This method
|
||||
* compares <strong>only the <code>primaryType</code> and
|
||||
* <code>subType</code></strong>.
|
||||
* The parameters of the content types are ignored. <p>
|
||||
* <p>
|
||||
* For example, this method will return <code>true</code> when
|
||||
* comparing a Part of content type <strong>"text/plain"</strong>
|
||||
* with <strong>"text/plain; charset=foobar"</strong>. <p>
|
||||
* <p>
|
||||
* If the <code>subType</code> of <code>mimeType</code> is the
|
||||
* special character '*', then the subtype is ignored during the
|
||||
* comparison.
|
||||
*
|
||||
* @param mimeType the MIME type to test
|
||||
* @return true if this part is of the specified type
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
boolean isMimeType(String mimeType) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Return the disposition of this part. The disposition
|
||||
* describes how the part should be presented to the user.
|
||||
* (See RFC 2183.) The return value should be considered
|
||||
* without regard to case. For example:
|
||||
* <blockquote><pre>
|
||||
* String disp = part.getDisposition();
|
||||
* if (disp == null || disp.equalsIgnoreCase(Part.ATTACHMENT))
|
||||
* // treat as attachment if not first part
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @return disposition of this part, or null if unknown
|
||||
* @throws MessagingException for failures
|
||||
* @see #ATTACHMENT
|
||||
* @see #INLINE
|
||||
* @see #getFileName
|
||||
*/
|
||||
String getDisposition() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Set the disposition of this part.
|
||||
*
|
||||
* @param disposition disposition of this part
|
||||
* @throws IllegalWriteException if the underlying implementation
|
||||
* does not support modification of this header
|
||||
* @throws IllegalStateException if this Part is obtained
|
||||
* from a READ_ONLY folder
|
||||
* @throws MessagingException for other failures
|
||||
* @see #ATTACHMENT
|
||||
* @see #INLINE
|
||||
* @see #setFileName
|
||||
*/
|
||||
void setDisposition(String disposition) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Return a description String for this part. This typically
|
||||
* associates some descriptive information with this part.
|
||||
* Returns null if none is available.
|
||||
*
|
||||
* @return description of this part
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
String getDescription() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Set a description String for this part. This typically
|
||||
* associates some descriptive information with this part.
|
||||
*
|
||||
* @param description description of this part
|
||||
* @throws IllegalWriteException if the underlying implementation
|
||||
* does not support modification of this header
|
||||
* @throws IllegalStateException if this Part is obtained
|
||||
* from a READ_ONLY folder
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
void setDescription(String description) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get the filename associated with this part, if possible.
|
||||
* Useful if this part represents an "attachment" that was
|
||||
* loaded from a file. The filename will usually be a simple
|
||||
* name, not including directory components.
|
||||
*
|
||||
* @return Filename to associate with this part
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
String getFileName() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Set the filename associated with this part, if possible.
|
||||
* Useful if this part represents an "attachment" that was
|
||||
* loaded from a file. The filename will usually be a simple
|
||||
* name, not including directory components.
|
||||
*
|
||||
* @param filename Filename to associate with this part
|
||||
* @throws IllegalWriteException if the underlying implementation
|
||||
* does not support modification of this header
|
||||
* @throws IllegalStateException if this Part is obtained
|
||||
* from a READ_ONLY folder
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
void setFileName(String filename) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Return an input stream for this part's "content". Any
|
||||
* mail-specific transfer encodings will be decoded before the
|
||||
* input stream is provided. <p>
|
||||
* <p>
|
||||
* This is typically a convenience method that just invokes
|
||||
* the DataHandler's <code>getInputStream()</code> method.
|
||||
*
|
||||
* @return an InputStream
|
||||
* @throws IOException this is typically thrown by the
|
||||
* DataHandler. Refer to the documentation for
|
||||
* jakarta.activation.DataHandler for more details.
|
||||
* @throws MessagingException for other failures
|
||||
* @see #getDataHandler
|
||||
* @see jakarta.activation.DataHandler#getInputStream
|
||||
*/
|
||||
InputStream getInputStream()
|
||||
throws IOException, MessagingException;
|
||||
|
||||
/**
|
||||
* Return a DataHandler for the content within this part. The
|
||||
* DataHandler allows clients to operate on as well as retrieve
|
||||
* the content.
|
||||
*
|
||||
* @return DataHandler for the content
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
DataHandler getDataHandler() throws MessagingException;
|
||||
|
||||
/**
|
||||
* This method provides the mechanism to set this part's content.
|
||||
* The DataHandler wraps around the actual content.
|
||||
*
|
||||
* @param dh The DataHandler for the content.
|
||||
* @throws IllegalWriteException if the underlying implementation
|
||||
* does not support modification of existing values
|
||||
* @throws IllegalStateException if this Part is obtained
|
||||
* from a READ_ONLY folder
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
void setDataHandler(DataHandler dh) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Return the content as a Java object. The type of the returned
|
||||
* object is of course dependent on the content itself. For example,
|
||||
* the object returned for "text/plain" content is usually a String
|
||||
* object. The object returned for a "multipart" content is always a
|
||||
* Multipart subclass. For content-types that are unknown to the
|
||||
* DataHandler system, an input stream is returned as the content <p>
|
||||
* <p>
|
||||
* This is a convenience method that just invokes the DataHandler's
|
||||
* getContent() method
|
||||
*
|
||||
* @return Object
|
||||
* @throws IOException this is typically thrown by the
|
||||
* DataHandler. Refer to the documentation for
|
||||
* jakarta.activation.DataHandler for more details.
|
||||
* @throws MessagingException for other failures
|
||||
* @see jakarta.activation.DataHandler#getContent
|
||||
*/
|
||||
Object getContent() throws IOException, MessagingException;
|
||||
|
||||
/**
|
||||
* This method sets the given Multipart object as this message's
|
||||
* content.
|
||||
*
|
||||
* @param mp The multipart object that is the Message's content
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification of
|
||||
* existing values
|
||||
* @throws IllegalStateException if this Part is obtained
|
||||
* from a READ_ONLY folder
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
void setContent(Multipart mp) throws MessagingException;
|
||||
|
||||
/**
|
||||
* A convenience method for setting this part's content. The part
|
||||
* internally wraps the content in a DataHandler. <p>
|
||||
* <p>
|
||||
* Note that a DataContentHandler class for the specified type should
|
||||
* be available to the Jakarta Mail implementation for this to work right.
|
||||
* i.e., to do <code>setContent(foobar, "application/x-foobar")</code>,
|
||||
* a DataContentHandler for "application/x-foobar" should be installed.
|
||||
* Refer to the Java Activation Framework for more information.
|
||||
*
|
||||
* @param obj A java object.
|
||||
* @param type MIME type of this object.
|
||||
* @throws IllegalWriteException if the underlying implementation
|
||||
* does not support modification of existing values
|
||||
* @throws IllegalStateException if this Part is obtained
|
||||
* from a READ_ONLY folder
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
void setContent(Object obj, String type)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* A convenience method that sets the given String as this
|
||||
* part's content with a MIME type of "text/plain".
|
||||
*
|
||||
* @param text The text that is the Message's content.
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification of
|
||||
* existing values
|
||||
* @throws IllegalStateException if this Part is obtained
|
||||
* from a READ_ONLY folder
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
void setText(String text) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Output a bytestream for this Part. This bytestream is
|
||||
* typically an aggregration of the Part attributes and
|
||||
* an appropriately encoded bytestream from its 'content'. <p>
|
||||
* <p>
|
||||
* Classes that implement the Part interface decide on
|
||||
* the appropriate encoding algorithm to be used. <p>
|
||||
* <p>
|
||||
* The bytestream is typically used for sending.
|
||||
*
|
||||
* @param os the stream to write to
|
||||
* @throws IOException if an error occurs writing to the
|
||||
* stream or if an error is generated
|
||||
* by the jakarta.activation layer.
|
||||
* @throws MessagingException if an error occurs fetching the
|
||||
* data to be written
|
||||
* @see jakarta.activation.DataHandler#writeTo
|
||||
*/
|
||||
void writeTo(OutputStream os) throws IOException, MessagingException;
|
||||
|
||||
/**
|
||||
* Get all the headers for this header name. Returns <code>null</code>
|
||||
* if no headers for this header name are available.
|
||||
*
|
||||
* @param header_name the name of this header
|
||||
* @return the value fields for all headers with
|
||||
* this name
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
String[] getHeader(String header_name)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Set the value for this header_name. Replaces all existing
|
||||
* header values with this new value.
|
||||
*
|
||||
* @param header_name the name of this header
|
||||
* @param header_value the value for this header
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws IllegalStateException if this Part is
|
||||
* obtained from a READ_ONLY folder
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
void setHeader(String header_name, String header_value)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Add this value to the existing values for this header_name.
|
||||
*
|
||||
* @param header_name the name of this header
|
||||
* @param header_value the value for this header
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws IllegalStateException if this Part is
|
||||
* obtained from a READ_ONLY folder
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
void addHeader(String header_name, String header_value)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Remove all headers with this name.
|
||||
*
|
||||
* @param header_name the name of this header
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* of existing values
|
||||
* @throws IllegalStateException if this Part is
|
||||
* obtained from a READ_ONLY folder
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
void removeHeader(String header_name)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Return all the headers from this part as an Enumeration of
|
||||
* Header objects.
|
||||
*
|
||||
* @return enumeration of Header objects
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
Enumeration<Header> getAllHeaders() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Return matching headers from this part as an Enumeration of
|
||||
* Header objects.
|
||||
*
|
||||
* @param header_names the headers to match
|
||||
* @return enumeration of Header objects
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
Enumeration<Header> getMatchingHeaders(String[] header_names)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Return non-matching headers from this envelope as an Enumeration
|
||||
* of Header objects.
|
||||
*
|
||||
* @param header_names the headers to not match
|
||||
* @return enumeration of Header objects
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
Enumeration<Header> getNonMatchingHeaders(String[] header_names)
|
||||
throws MessagingException;
|
||||
}
|
|
@ -1,59 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
|
||||
/**
|
||||
* The class PasswordAuthentication is a data holder that is used by
|
||||
* Authenticator. It is simply a repository for a user name and a password.
|
||||
*
|
||||
* @author Bill Foote
|
||||
* @see java.net.PasswordAuthentication
|
||||
* @see Authenticator
|
||||
* @see Authenticator#getPasswordAuthentication()
|
||||
*/
|
||||
|
||||
public final class PasswordAuthentication {
|
||||
|
||||
private final String userName;
|
||||
private final String password;
|
||||
|
||||
/**
|
||||
* Initialize a new PasswordAuthentication
|
||||
*
|
||||
* @param userName the user name
|
||||
* @param password The user's password
|
||||
*/
|
||||
public PasswordAuthentication(String userName, String password) {
|
||||
this.userName = userName;
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the user name
|
||||
*/
|
||||
public String getUserName() {
|
||||
return userName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the password
|
||||
*/
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
}
|
|
@ -1,145 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* The Provider is a class that describes a protocol
|
||||
* implementation. The values typically come from the
|
||||
* javamail.providers and javamail.default.providers
|
||||
* resource files. An application may also create and
|
||||
* register a Provider object to dynamically add support
|
||||
* for a new provider.
|
||||
*
|
||||
* @author Max Spivak
|
||||
* @author Bill Shannon
|
||||
*/
|
||||
public class Provider {
|
||||
|
||||
private Type type;
|
||||
private String protocol, className, vendor, version;
|
||||
/**
|
||||
* Create a new provider of the specified type for the specified
|
||||
* protocol. The specified class implements the provider.
|
||||
*
|
||||
* @param type Type.STORE or Type.TRANSPORT
|
||||
* @param protocol valid protocol for the type
|
||||
* @param classname class name that implements this protocol
|
||||
* @param vendor optional string identifying the vendor (may be null)
|
||||
* @param version optional implementation version string (may be null)
|
||||
* @since JavaMail 1.4
|
||||
*/
|
||||
public Provider(Type type, String protocol, String classname,
|
||||
String vendor, String version) {
|
||||
this.type = type;
|
||||
this.protocol = protocol;
|
||||
this.className = classname;
|
||||
this.vendor = vendor;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of this Provider.
|
||||
*
|
||||
* @return the provider type
|
||||
*/
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the protocol supported by this Provider.
|
||||
*
|
||||
* @return the protocol
|
||||
*/
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the class that implements the protocol.
|
||||
*
|
||||
* @return the class name
|
||||
*/
|
||||
public String getClassName() {
|
||||
return className;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the vendor associated with this implementation
|
||||
* or null.
|
||||
*
|
||||
* @return the vendor
|
||||
*/
|
||||
public String getVendor() {
|
||||
return vendor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version of this implementation or null if no version.
|
||||
*
|
||||
* @return the version
|
||||
*/
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides Object.toString()
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
String s = "jakarta.mail.Provider[" + type + "," +
|
||||
protocol + "," + className;
|
||||
|
||||
if (vendor != null)
|
||||
s += "," + vendor;
|
||||
|
||||
if (version != null)
|
||||
s += "," + version;
|
||||
|
||||
s += "]";
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* This inner class defines the Provider type.
|
||||
* Currently, STORE and TRANSPORT are the only two provider types
|
||||
* supported.
|
||||
*/
|
||||
|
||||
public static class Type {
|
||||
/**
|
||||
* The Provider of type {@code STORE}.
|
||||
*/
|
||||
public static final Type STORE = new Type("STORE");
|
||||
/**
|
||||
* The Provider of type {@code TRANSPORT}.
|
||||
*/
|
||||
public static final Type TRANSPORT = new Type("TRANSPORT");
|
||||
|
||||
private String type;
|
||||
|
||||
private Type(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* This class represents a set of quotas for a given quota root.
|
||||
* Each quota root has a set of resources, represented by the
|
||||
* <code>Quota.Resource</code> class. Each resource has a name
|
||||
* (for example, "STORAGE"), a current usage, and a usage limit.
|
||||
* See RFC 2087.
|
||||
*
|
||||
* @author Bill Shannon
|
||||
* @since JavaMail 1.4
|
||||
*/
|
||||
|
||||
public class Quota {
|
||||
|
||||
/**
|
||||
* The name of the quota root.
|
||||
*/
|
||||
public String quotaRoot;
|
||||
/**
|
||||
* The set of resources associated with this quota root.
|
||||
*/
|
||||
public Resource[] resources;
|
||||
|
||||
/**
|
||||
* Create a Quota object for the named quotaroot with no associated
|
||||
* resources.
|
||||
*
|
||||
* @param quotaRoot the name of the quota root
|
||||
*/
|
||||
public Quota(String quotaRoot) {
|
||||
this.quotaRoot = quotaRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a resource limit for this quota root.
|
||||
*
|
||||
* @param name the name of the resource
|
||||
* @param limit the resource limit
|
||||
*/
|
||||
public void setResourceLimit(String name, long limit) {
|
||||
if (resources == null) {
|
||||
resources = new Resource[1];
|
||||
resources[0] = new Resource(name, 0, limit);
|
||||
return;
|
||||
}
|
||||
for (int i = 0; i < resources.length; i++) {
|
||||
if (resources[i].name.equalsIgnoreCase(name)) {
|
||||
resources[i].limit = limit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
Resource[] ra = new Resource[resources.length + 1];
|
||||
System.arraycopy(resources, 0, ra, 0, resources.length);
|
||||
ra[ra.length - 1] = new Resource(name, 0, limit);
|
||||
resources = ra;
|
||||
}
|
||||
|
||||
/**
|
||||
* An individual resource in a quota root.
|
||||
*
|
||||
* @since JavaMail 1.4
|
||||
*/
|
||||
public static class Resource {
|
||||
/**
|
||||
* The name of the resource.
|
||||
*/
|
||||
public String name;
|
||||
/**
|
||||
* The current usage of the resource.
|
||||
*/
|
||||
public long usage;
|
||||
/**
|
||||
* The usage limit for the resource.
|
||||
*/
|
||||
public long limit;
|
||||
|
||||
/**
|
||||
* Construct a Resource object with the given name,
|
||||
* usage, and limit.
|
||||
*
|
||||
* @param name the resource name
|
||||
* @param usage the current usage of the resource
|
||||
* @param limit the usage limit for the resource
|
||||
*/
|
||||
public Resource(String name, long usage, long limit) {
|
||||
this.name = name;
|
||||
this.usage = usage;
|
||||
this.limit = limit;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* An interface implemented by Stores that support quotas.
|
||||
* The {@link #getQuota getQuota} and {@link #setQuota setQuota} methods
|
||||
* support the quota model defined by the IMAP QUOTA extension.
|
||||
* Refer to <A HREF="http://www.ietf.org/rfc/rfc2087.txt">RFC 2087</A>
|
||||
* for more information.
|
||||
*
|
||||
* @since JavaMail 1.4
|
||||
*/
|
||||
public interface QuotaAwareStore {
|
||||
/**
|
||||
* Get the quotas for the named folder.
|
||||
* Quotas are controlled on the basis of a quota root, not
|
||||
* (necessarily) a folder. The relationship between folders
|
||||
* and quota roots depends on the server. Some servers
|
||||
* might implement a single quota root for all folders owned by
|
||||
* a user. Other servers might implement a separate quota root
|
||||
* for each folder. A single folder can even have multiple
|
||||
* quota roots, perhaps controlling quotas for different
|
||||
* resources.
|
||||
*
|
||||
* @param folder the name of the folder
|
||||
* @return array of Quota objects
|
||||
* @throws MessagingException if the server doesn't support the
|
||||
* QUOTA extension
|
||||
*/
|
||||
Quota[] getQuota(String folder) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Set the quotas for the quota root specified in the quota argument.
|
||||
* Typically this will be one of the quota roots obtained from the
|
||||
* <code>getQuota</code> method, but it need not be.
|
||||
*
|
||||
* @param quota the quota to set
|
||||
* @throws MessagingException if the server doesn't support the
|
||||
* QUOTA extension
|
||||
*/
|
||||
void setQuota(Quota quota) throws MessagingException;
|
||||
}
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* This exception is thrown when an attempt is made to open a folder
|
||||
* read-write access when the folder is marked read-only. <p>
|
||||
* <p>
|
||||
* The getMessage() method returns more detailed information about the
|
||||
* error that caused this exception.
|
||||
*
|
||||
* @author Jim Glennon
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ReadOnlyFolderException extends MessagingException {
|
||||
transient private Folder folder;
|
||||
|
||||
/**
|
||||
* Constructs a ReadOnlyFolderException with the specified
|
||||
* folder and no detail message.
|
||||
*
|
||||
* @param folder the Folder
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public ReadOnlyFolderException(Folder folder) {
|
||||
this(folder, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a ReadOnlyFolderException with the specified
|
||||
* detail message.
|
||||
*
|
||||
* @param folder The Folder
|
||||
* @param message The detailed error message
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public ReadOnlyFolderException(Folder folder, String message) {
|
||||
super(message);
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a ReadOnlyFolderException with the specified
|
||||
* detail message and embedded exception. The exception is chained
|
||||
* to this exception.
|
||||
*
|
||||
* @param folder The Folder
|
||||
* @param message The detailed error message
|
||||
* @param e The embedded exception
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public ReadOnlyFolderException(Folder folder, String message, Exception e) {
|
||||
super(message, e);
|
||||
this.folder = folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Folder object.
|
||||
*
|
||||
* @return the Folder
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public Folder getFolder() {
|
||||
return folder;
|
||||
}
|
||||
}
|
|
@ -1,127 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* This exception is thrown when the message cannot be sent.<p>
|
||||
* <p>
|
||||
* The exception includes those addresses to which the message could not be
|
||||
* sent as well as the valid addresses to which the message was sent and
|
||||
* valid addresses to which the message was not sent.
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Max Spivak
|
||||
* @see Transport#send
|
||||
* @see Transport#sendMessage
|
||||
* @see jakarta.mail.event.TransportEvent
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class SendFailedException extends MessagingException {
|
||||
|
||||
/**
|
||||
* The invalid addresses.
|
||||
*/
|
||||
transient protected Address[] invalid;
|
||||
/**
|
||||
* Valid addresses to which message was sent.
|
||||
*/
|
||||
transient protected Address[] validSent;
|
||||
/**
|
||||
* Valid addresses to which message was not sent.
|
||||
*/
|
||||
transient protected Address[] validUnsent;
|
||||
|
||||
/**
|
||||
* Constructs a SendFailedException with no detail message.
|
||||
*/
|
||||
public SendFailedException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a SendFailedException with the specified detail message.
|
||||
*
|
||||
* @param s the detail message
|
||||
*/
|
||||
public SendFailedException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a SendFailedException with the specified
|
||||
* Exception and detail message. The specified exception is chained
|
||||
* to this exception.
|
||||
*
|
||||
* @param s the detail message
|
||||
* @param e the embedded exception
|
||||
* @see #getNextException
|
||||
* @see #setNextException
|
||||
*/
|
||||
public SendFailedException(String s, Exception e) {
|
||||
super(s, e);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructs a SendFailedException with the specified string
|
||||
* and the specified address objects.
|
||||
*
|
||||
* @param msg the detail message
|
||||
* @param ex the embedded exception
|
||||
* @param validSent valid addresses to which message was sent
|
||||
* @param validUnsent valid addresses to which message was not sent
|
||||
* @param invalid the invalid addresses
|
||||
* @see #getNextException
|
||||
* @see #setNextException
|
||||
*/
|
||||
public SendFailedException(String msg, Exception ex, Address[] validSent,
|
||||
Address[] validUnsent, Address[] invalid) {
|
||||
super(msg, ex);
|
||||
this.validSent = validSent;
|
||||
this.validUnsent = validUnsent;
|
||||
this.invalid = invalid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the addresses to which this message was sent succesfully.
|
||||
*
|
||||
* @return Addresses to which the message was sent successfully or null
|
||||
*/
|
||||
public Address[] getValidSentAddresses() {
|
||||
return validSent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the addresses that are valid but to which this message
|
||||
* was not sent.
|
||||
*
|
||||
* @return Addresses that are valid but to which the message was
|
||||
* not sent successfully or null
|
||||
*/
|
||||
public Address[] getValidUnsentAddresses() {
|
||||
return validUnsent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the addresses to which this message could not be sent.
|
||||
*
|
||||
* @return Addresses to which the message sending failed or null;
|
||||
*/
|
||||
public Address[] getInvalidAddresses() {
|
||||
return invalid;
|
||||
}
|
||||
}
|
|
@ -1,630 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import jakarta.mail.event.ConnectionEvent;
|
||||
import jakarta.mail.event.ConnectionListener;
|
||||
import jakarta.mail.event.MailEvent;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.EventListener;
|
||||
import java.util.Vector;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* An abstract class that contains the functionality
|
||||
* common to messaging services, such as stores and transports. <p>
|
||||
* A messaging service is created from a <code>Session</code> and is
|
||||
* named using a <code>URLName</code>. A service must be connected
|
||||
* before it can be used. Connection events are sent to reflect
|
||||
* its connection status.
|
||||
*
|
||||
* @author Christopher Cotton
|
||||
* @author Bill Shannon
|
||||
* @author Kanwar Oberoi
|
||||
*/
|
||||
|
||||
public abstract class Service implements AutoCloseable {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(Service.class.getName());
|
||||
|
||||
/*
|
||||
* connectionListeners is a Vector, initialized here,
|
||||
* because we depend on it always existing and depend
|
||||
* on the synchronization that Vector provides.
|
||||
* (Sychronizing on the Service object itself can cause
|
||||
* deadlocks when notifying listeners.)
|
||||
*/
|
||||
private final Vector<ConnectionListener> connectionListeners = new Vector<>();
|
||||
/**
|
||||
* The queue of events to be delivered.
|
||||
*/
|
||||
private final EventQueue q;
|
||||
/**
|
||||
* The session from which this service was created.
|
||||
*/
|
||||
protected Session session;
|
||||
/**
|
||||
* The <code>URLName</code> of this service.
|
||||
*/
|
||||
protected volatile URLName url;
|
||||
|
||||
private boolean connected = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param session Session object for this service
|
||||
* @param urlname URLName object to be used for this service
|
||||
*/
|
||||
protected Service(Session session, URLName urlname) {
|
||||
this.session = session;
|
||||
url = urlname;
|
||||
|
||||
/*
|
||||
* Initialize the URLName with default values.
|
||||
* The URLName will be updated when connect is called.
|
||||
*/
|
||||
String protocol = null;
|
||||
String host = null;
|
||||
int port = -1;
|
||||
String user = null;
|
||||
String password = null;
|
||||
String file = null;
|
||||
|
||||
// get whatever information we can from the URL
|
||||
// XXX - url should always be non-null here, Session
|
||||
// passes it into the constructor
|
||||
if (url != null) {
|
||||
protocol = url.getProtocol();
|
||||
host = url.getHost();
|
||||
port = url.getPort();
|
||||
user = url.getUsername();
|
||||
password = url.getPassword();
|
||||
file = url.getFile();
|
||||
}
|
||||
|
||||
// try to get protocol-specific default properties
|
||||
if (protocol != null) {
|
||||
if (host == null)
|
||||
host = session.getProperty("mail." + protocol + ".host");
|
||||
if (user == null)
|
||||
user = session.getProperty("mail." + protocol + ".user");
|
||||
}
|
||||
|
||||
// try to get mail-wide default properties
|
||||
if (host == null)
|
||||
host = session.getProperty("mail.host");
|
||||
|
||||
if (user == null)
|
||||
user = session.getProperty("mail.user");
|
||||
|
||||
// try using the system username
|
||||
if (user == null) {
|
||||
user = System.getProperty("user.name");
|
||||
}
|
||||
url = new URLName(protocol, host, port, file, user, password);
|
||||
// create or choose the appropriate event queue
|
||||
String scope = session.getProperties().getProperty("mail.event.scope", "folder");
|
||||
Executor executor = (Executor) session.getProperties().get("mail.event.executor");
|
||||
if (executor == null) {
|
||||
executor = Executors.newSingleThreadExecutor();
|
||||
}
|
||||
if (scope.equalsIgnoreCase("application")) {
|
||||
q = EventQueue.getApplicationEventQueue(executor);
|
||||
} else if (scope.equalsIgnoreCase("session")) {
|
||||
q = session.getEventQueue();
|
||||
} else {
|
||||
q = new EventQueue(executor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A generic connect method that takes no parameters. Subclasses
|
||||
* can implement the appropriate authentication schemes. Subclasses
|
||||
* that need additional information might want to use some properties
|
||||
* or might get it interactively using a popup window. <p>
|
||||
* <p>
|
||||
* If the connection is successful, an "open" <code>ConnectionEvent</code>
|
||||
* is delivered to any <code>ConnectionListeners</code> on this service. <p>
|
||||
* <p>
|
||||
* Most clients should just call this method to connect to the service.<p>
|
||||
* <p>
|
||||
* It is an error to connect to an already connected service. <p>
|
||||
* <p>
|
||||
* The implementation provided here simply calls the following
|
||||
* <code>connect(String, String, String)</code> method with nulls.
|
||||
*
|
||||
* @throws AuthenticationFailedException for authentication failures
|
||||
* @throws IllegalStateException if the service is already connected
|
||||
* @throws MessagingException for other failures
|
||||
* @see ConnectionEvent
|
||||
*/
|
||||
public void connect() throws MessagingException {
|
||||
connect(null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the specified address. This method provides a simple
|
||||
* authentication scheme that requires a username and password. <p>
|
||||
* <p>
|
||||
* If the connection is successful, an "open" <code>ConnectionEvent</code>
|
||||
* is delivered to any <code>ConnectionListeners</code> on this service. <p>
|
||||
* <p>
|
||||
* It is an error to connect to an already connected service. <p>
|
||||
* <p>
|
||||
* The implementation in the Service class will collect defaults
|
||||
* for the host, user, and password from the session, from the
|
||||
* <code>URLName</code> for this service, and from the supplied
|
||||
* parameters and then call the <code>protocolConnect</code> method.
|
||||
* If the <code>protocolConnect</code> method returns <code>false</code>,
|
||||
* the user will be prompted for any missing information and the
|
||||
* <code>protocolConnect</code> method will be called again. The
|
||||
* subclass should override the <code>protocolConnect</code> method.
|
||||
* The subclass should also implement the <code>getURLName</code>
|
||||
* method, or use the implementation in this class. <p>
|
||||
* <p>
|
||||
* On a successful connection, the <code>setURLName</code> method is
|
||||
* called with a URLName that includes the information used to make
|
||||
* the connection, including the password. <p>
|
||||
* <p>
|
||||
* If the username passed in is null, a default value will be chosen
|
||||
* as described above.
|
||||
* <p>
|
||||
* If the password passed in is null and this is the first successful
|
||||
* connection to this service, the user name and the password
|
||||
* collected from the user will be saved as defaults for subsequent
|
||||
* connection attempts to this same service when using other Service object
|
||||
* instances (the connection information is typically always saved within
|
||||
* a particular Service object instance). The password is saved using the
|
||||
* Session method <code>setPasswordAuthentication</code>. If the
|
||||
* password passed in is not null, it is not saved, on the assumption
|
||||
* that the application is managing passwords explicitly.
|
||||
*
|
||||
* @param host the host to connect to
|
||||
* @param user the user name
|
||||
* @param password this user's password
|
||||
* @throws AuthenticationFailedException for authentication failures
|
||||
* @throws IllegalStateException if the service is already connected
|
||||
* @throws MessagingException for other failures
|
||||
* @see ConnectionEvent
|
||||
* @see Session#setPasswordAuthentication
|
||||
*/
|
||||
public void connect(String host, String user, String password)
|
||||
throws MessagingException {
|
||||
connect(host, -1, user, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Connect to the current host using the specified username
|
||||
* and password. This method is equivalent to calling the
|
||||
* <code>connect(host, user, password)</code> method with null
|
||||
* for the host name.
|
||||
*
|
||||
* @param user the user name
|
||||
* @param password this user's password
|
||||
* @throws AuthenticationFailedException for authentication failures
|
||||
* @throws IllegalStateException if the service is already connected
|
||||
* @throws MessagingException for other failures
|
||||
* @see ConnectionEvent
|
||||
* @see Session#setPasswordAuthentication
|
||||
* @see #connect(String, String, String)
|
||||
* @since JavaMail 1.4
|
||||
*/
|
||||
public void connect(String user, String password)
|
||||
throws MessagingException {
|
||||
connect(null, user, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Similar to connect(host, user, password) except a specific port
|
||||
* can be specified.
|
||||
*
|
||||
* @param host the host to connect to
|
||||
* @param port the port to connect to (-1 means the default port)
|
||||
* @param user the user name
|
||||
* @param password this user's password
|
||||
* @throws AuthenticationFailedException for authentication failures
|
||||
* @throws IllegalStateException if the service is already connected
|
||||
* @throws MessagingException for other failures
|
||||
* @see #connect(String, String, String)
|
||||
* @see ConnectionEvent
|
||||
*/
|
||||
public synchronized void connect(String host, int port,
|
||||
String user, String password) throws MessagingException {
|
||||
|
||||
// see if the service is already connected
|
||||
if (isConnected())
|
||||
throw new IllegalStateException("already connected");
|
||||
|
||||
PasswordAuthentication pw;
|
||||
boolean connected = false;
|
||||
boolean save = false;
|
||||
String protocol = null;
|
||||
String file = null;
|
||||
|
||||
// get whatever information we can from the URL
|
||||
// XXX - url should always be non-null here, Session
|
||||
// passes it into the constructor
|
||||
if (url != null) {
|
||||
protocol = url.getProtocol();
|
||||
if (host == null)
|
||||
host = url.getHost();
|
||||
if (port == -1)
|
||||
port = url.getPort();
|
||||
|
||||
if (user == null) {
|
||||
user = url.getUsername();
|
||||
if (password == null) // get password too if we need it
|
||||
password = url.getPassword();
|
||||
} else {
|
||||
if (password == null && user.equals(url.getUsername()))
|
||||
// only get the password if it matches the username
|
||||
password = url.getPassword();
|
||||
}
|
||||
|
||||
file = url.getFile();
|
||||
}
|
||||
|
||||
// try to get protocol-specific default properties
|
||||
if (protocol != null) {
|
||||
if (host == null)
|
||||
host = session.getProperty("mail." + protocol + ".host");
|
||||
if (user == null)
|
||||
user = session.getProperty("mail." + protocol + ".user");
|
||||
}
|
||||
|
||||
// try to get mail-wide default properties
|
||||
if (host == null)
|
||||
host = session.getProperty("mail.host");
|
||||
|
||||
if (user == null)
|
||||
user = session.getProperty("mail.user");
|
||||
|
||||
// try using the system username
|
||||
if (user == null) {
|
||||
user = System.getProperty("user.name");
|
||||
}
|
||||
|
||||
// if we don't have a password, look for saved authentication info
|
||||
if (password == null && url != null) {
|
||||
// canonicalize the URLName
|
||||
setURLName(new URLName(protocol, host, port, file, user, null));
|
||||
pw = session.getPasswordAuthentication(getURLName());
|
||||
if (pw != null) {
|
||||
if (user == null) {
|
||||
user = pw.getUserName();
|
||||
password = pw.getPassword();
|
||||
} else if (user.equals(pw.getUserName())) {
|
||||
password = pw.getPassword();
|
||||
}
|
||||
} else
|
||||
save = true;
|
||||
}
|
||||
|
||||
// try connecting, if the protocol needs some missing
|
||||
// information (user, password) it will not connect.
|
||||
// if it tries to connect and fails, remember why for later.
|
||||
AuthenticationFailedException authEx = null;
|
||||
try {
|
||||
connected = protocolConnect(host, port, user, password);
|
||||
} catch (AuthenticationFailedException ex) {
|
||||
authEx = ex;
|
||||
}
|
||||
|
||||
// if not connected, ask the user and try again
|
||||
if (!connected) {
|
||||
InetAddress addr;
|
||||
try {
|
||||
addr = InetAddress.getByName(host);
|
||||
} catch (UnknownHostException e) {
|
||||
addr = null;
|
||||
}
|
||||
pw = session.requestPasswordAuthentication(
|
||||
addr, port,
|
||||
protocol,
|
||||
null, user);
|
||||
if (pw != null) {
|
||||
user = pw.getUserName();
|
||||
password = pw.getPassword();
|
||||
|
||||
// have the service connect again
|
||||
connected = protocolConnect(host, port, user, password);
|
||||
}
|
||||
}
|
||||
|
||||
// if we're not connected by now, we give up
|
||||
if (!connected) {
|
||||
if (authEx != null)
|
||||
throw authEx;
|
||||
else if (user == null)
|
||||
throw new AuthenticationFailedException(
|
||||
"failed to connect, no user name specified?");
|
||||
else if (password == null)
|
||||
throw new AuthenticationFailedException(
|
||||
"failed to connect, no password specified?");
|
||||
else
|
||||
throw new AuthenticationFailedException("failed to connect");
|
||||
}
|
||||
|
||||
setURLName(new URLName(protocol, host, port, file, user, password));
|
||||
|
||||
if (save)
|
||||
session.setPasswordAuthentication(getURLName(),
|
||||
new PasswordAuthentication(user, password));
|
||||
|
||||
// set our connected state
|
||||
setConnected(true);
|
||||
|
||||
// finally, deliver the connection event
|
||||
notifyConnectionListeners(ConnectionEvent.OPENED);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The service implementation should override this method to
|
||||
* perform the actual protocol-specific connection attempt.
|
||||
* The default implementation of the <code>connect</code> method
|
||||
* calls this method as needed. <p>
|
||||
* <p>
|
||||
* The <code>protocolConnect</code> method should return
|
||||
* <code>false</code> if a user name or password is required
|
||||
* for authentication but the corresponding parameter is null;
|
||||
* the <code>connect</code> method will prompt the user when
|
||||
* needed to supply missing information. This method may
|
||||
* also return <code>false</code> if authentication fails for
|
||||
* the supplied user name or password. Alternatively, this method
|
||||
* may throw an AuthenticationFailedException when authentication
|
||||
* fails. This exception may include a String message with more
|
||||
* detail about the failure. <p>
|
||||
* <p>
|
||||
* The <code>protocolConnect</code> method should throw an
|
||||
* exception to report failures not related to authentication,
|
||||
* such as an invalid host name or port number, loss of a
|
||||
* connection during the authentication process, unavailability
|
||||
* of the server, etc.
|
||||
*
|
||||
* @param host the name of the host to connect to
|
||||
* @param port the port to use (-1 means use default port)
|
||||
* @param user the name of the user to login as
|
||||
* @param password the user's password
|
||||
* @return true if connection successful, false if authentication failed
|
||||
* @throws AuthenticationFailedException for authentication failures
|
||||
* @throws MessagingException for non-authentication failures
|
||||
*/
|
||||
protected boolean protocolConnect(String host, int port, String user,
|
||||
String password) throws MessagingException {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this service currently connected? <p>
|
||||
* <p>
|
||||
* This implementation uses a private boolean field to
|
||||
* store the connection state. This method returns the value
|
||||
* of that field. <p>
|
||||
* <p>
|
||||
* Subclasses may want to override this method to verify that any
|
||||
* connection to the message store is still alive.
|
||||
*
|
||||
* @return true if the service is connected, false if it is not connected
|
||||
*/
|
||||
public synchronized boolean isConnected() {
|
||||
return connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the connection state of this service. The connection state
|
||||
* will automatically be set by the service implementation during the
|
||||
* <code>connect</code> and <code>close</code> methods.
|
||||
* Subclasses will need to call this method to set the state
|
||||
* if the service was automatically disconnected. <p>
|
||||
* <p>
|
||||
* The implementation in this class merely sets the private field
|
||||
* returned by the <code>isConnected</code> method.
|
||||
*
|
||||
* @param connected true if the service is connected,
|
||||
* false if it is not connected
|
||||
*/
|
||||
protected synchronized void setConnected(boolean connected) {
|
||||
this.connected = connected;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close this service and terminate its connection. A close
|
||||
* ConnectionEvent is delivered to any ConnectionListeners. Any
|
||||
* Messaging components (Folders, Messages, etc.) belonging to this
|
||||
* service are invalid after this service is closed. Note that the service
|
||||
* is closed even if this method terminates abnormally by throwing
|
||||
* a MessagingException. <p>
|
||||
* <p>
|
||||
* This implementation uses <code>setConnected(false)</code> to set
|
||||
* this service's connected state to <code>false</code>. It will then
|
||||
* send a close ConnectionEvent to any registered ConnectionListeners.
|
||||
* Subclasses overriding this method to do implementation specific
|
||||
* cleanup should call this method as a last step to insure event
|
||||
* notification, probably by including a call to <code>super.close()</code>
|
||||
* in a <code>finally</code> clause.
|
||||
*
|
||||
* @throws MessagingException for errors while closing
|
||||
* @see ConnectionEvent
|
||||
*/
|
||||
public synchronized void close() throws MessagingException {
|
||||
setConnected(false);
|
||||
notifyConnectionListeners(ConnectionEvent.CLOSED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a URLName representing this service. The returned URLName
|
||||
* does <em>not</em> include the password field. <p>
|
||||
* <p>
|
||||
* Subclasses should only override this method if their
|
||||
* URLName does not follow the standard format. <p>
|
||||
* <p>
|
||||
* The implementation in the Service class returns (usually a copy of)
|
||||
* the <code>url</code> field with the password and file information
|
||||
* stripped out.
|
||||
*
|
||||
* @return the URLName representing this service
|
||||
* @see URLName
|
||||
*/
|
||||
public URLName getURLName() {
|
||||
URLName url = this.url; // snapshot
|
||||
if (url != null && (url.getPassword() != null || url.getFile() != null))
|
||||
return new URLName(url.getProtocol(), url.getHost(),
|
||||
url.getPort(), null /* no file */,
|
||||
url.getUsername(), null /* no password */);
|
||||
else
|
||||
return url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URLName representing this service.
|
||||
* Normally used to update the <code>url</code> field
|
||||
* after a service has successfully connected. <p>
|
||||
* <p>
|
||||
* Subclasses should only override this method if their
|
||||
* URL does not follow the standard format. In particular,
|
||||
* subclasses should override this method if their URL
|
||||
* does not require all the possible fields supported by
|
||||
* <code>URLName</code>; a new <code>URLName</code> should
|
||||
* be constructed with any unneeded fields removed. <p>
|
||||
* <p>
|
||||
* The implementation in the Service class simply sets the
|
||||
* <code>url</code> field.
|
||||
*
|
||||
* @param url the URLName
|
||||
* @see URLName
|
||||
*/
|
||||
protected void setURLName(URLName url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener for Connection events on this service. <p>
|
||||
* <p>
|
||||
* The default implementation provided here adds this listener
|
||||
* to an internal list of ConnectionListeners.
|
||||
*
|
||||
* @param l the Listener for Connection events
|
||||
* @see ConnectionEvent
|
||||
*/
|
||||
public void addConnectionListener(ConnectionListener l) {
|
||||
connectionListeners.addElement(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a Connection event listener. <p>
|
||||
* <p>
|
||||
* The default implementation provided here removes this listener
|
||||
* from the internal list of ConnectionListeners.
|
||||
*
|
||||
* @param l the listener
|
||||
* @see #addConnectionListener
|
||||
*/
|
||||
public void removeConnectionListener(ConnectionListener l) {
|
||||
connectionListeners.removeElement(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all ConnectionListeners. Service implementations are
|
||||
* expected to use this method to broadcast connection events. <p>
|
||||
* <p>
|
||||
* The provided default implementation queues the event into
|
||||
* an internal event queue. An event dispatcher thread dequeues
|
||||
* events from the queue and dispatches them to the registered
|
||||
* ConnectionListeners. Note that the event dispatching occurs
|
||||
* in a separate thread, thus avoiding potential deadlock problems.
|
||||
*
|
||||
* @param type the ConnectionEvent type
|
||||
*/
|
||||
protected void notifyConnectionListeners(int type) {
|
||||
/*
|
||||
* Don't bother queuing an event if there's no listeners.
|
||||
* Yes, listeners could be removed after checking, which
|
||||
* just makes this an expensive no-op.
|
||||
*/
|
||||
if (!connectionListeners.isEmpty()) {
|
||||
ConnectionEvent e = new ConnectionEvent(this, type);
|
||||
queueEvent(e, connectionListeners);
|
||||
}
|
||||
|
||||
/* Fix for broken JDK1.1.x Garbage collector :
|
||||
* The 'conservative' GC in JDK1.1.x occasionally fails to
|
||||
* garbage-collect Threads which are in the wait state.
|
||||
* This would result in thread (and consequently memory) leaks.
|
||||
*
|
||||
* We attempt to fix this by sending a 'terminator' event
|
||||
* to the queue, after we've sent the CLOSED event. The
|
||||
* terminator event causes the event-dispatching thread to
|
||||
* self destruct.
|
||||
*/
|
||||
if (type == ConnectionEvent.CLOSED) {
|
||||
logger.log(Level.INFO, "sending terminator event");
|
||||
q.terminateQueue();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return <code>getURLName.toString()</code> if this service has a URLName,
|
||||
* otherwise it will return the default <code>toString</code>.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
URLName url = getURLName();
|
||||
if (url != null)
|
||||
return url.toString();
|
||||
else
|
||||
return super.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the event and vector of listeners to the queue to be delivered.
|
||||
*
|
||||
* @param event the event
|
||||
* @param vector the vector of listeners
|
||||
*/
|
||||
protected void queueEvent(MailEvent event, Vector<? extends EventListener> vector) {
|
||||
/*
|
||||
* Copy the vector in order to freeze the state of the set
|
||||
* of EventListeners the event should be delivered to prior
|
||||
* to delivery. This ensures that any changes made to the
|
||||
* Vector from a target listener's method during the delivery
|
||||
* of this event will not take effect until after the event is
|
||||
* delivered.
|
||||
*/
|
||||
Vector<? extends EventListener> v = new Vector<>(vector);
|
||||
q.enqueue(event, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Package private method to allow Folder to get the Session for a Store.
|
||||
*/
|
||||
Session getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Package private method to allow Folder to get the EventQueue for a Store.
|
||||
*/
|
||||
EventQueue getEventQueue() {
|
||||
return q;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,300 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import jakarta.mail.event.FolderEvent;
|
||||
import jakarta.mail.event.FolderListener;
|
||||
import jakarta.mail.event.StoreEvent;
|
||||
import jakarta.mail.event.StoreListener;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* An abstract class that models a message store and its
|
||||
* access protocol, for storing and retrieving messages.
|
||||
* Subclasses provide actual implementations. <p>
|
||||
* <p>
|
||||
* Note that <code>Store</code> extends the <code>Service</code>
|
||||
* class, which provides many common methods for naming stores,
|
||||
* connecting to stores, and listening to connection events.
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Bill Shannon
|
||||
* @see Service
|
||||
* @see jakarta.mail.event.ConnectionEvent
|
||||
* @see StoreEvent
|
||||
*/
|
||||
|
||||
public abstract class Store extends Service {
|
||||
|
||||
// Vector of Store listeners
|
||||
private volatile Vector<StoreListener> storeListeners = null;
|
||||
// Vector of folder listeners
|
||||
private volatile Vector<FolderListener> folderListeners = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param session Session object for this Store.
|
||||
* @param urlname URLName object to be used for this Store
|
||||
*/
|
||||
protected Store(Session session, URLName urlname) {
|
||||
super(session, urlname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a Folder object that represents the 'root' of
|
||||
* the default namespace presented to the user by the Store.
|
||||
*
|
||||
* @return the root Folder
|
||||
* @throws IllegalStateException if this Store is not connected.
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
public abstract Folder getDefaultFolder() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Return the Folder object corresponding to the given name. Note
|
||||
* that a Folder object is returned even if the named folder does
|
||||
* not physically exist on the Store. The <code>exists()</code>
|
||||
* method on the folder object indicates whether this folder really
|
||||
* exists. <p>
|
||||
* <p>
|
||||
* Folder objects are not cached by the Store, so invoking this
|
||||
* method on the same name multiple times will return that many
|
||||
* distinct Folder objects.
|
||||
*
|
||||
* @param name The name of the Folder. In some Stores, name can
|
||||
* be an absolute path if it starts with the
|
||||
* hierarchy delimiter. Else it is interpreted
|
||||
* relative to the 'root' of this namespace.
|
||||
* @return Folder object
|
||||
* @throws IllegalStateException if this Store is not connected.
|
||||
* @throws MessagingException for other failures
|
||||
* @see Folder#create
|
||||
* @see Folder#exists
|
||||
*/
|
||||
public abstract Folder getFolder(String name)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Return a closed Folder object, corresponding to the given
|
||||
* URLName. The store specified in the given URLName should
|
||||
* refer to this Store object. <p>
|
||||
* <p>
|
||||
* Implementations of this method may obtain the name of the
|
||||
* actual folder using the <code>getFile()</code> method on
|
||||
* URLName, and use that name to create the folder.
|
||||
*
|
||||
* @param url URLName that denotes a folder
|
||||
* @return Folder object
|
||||
* @throws IllegalStateException if this Store is not connected.
|
||||
* @throws MessagingException for other failures
|
||||
* @see URLName
|
||||
*/
|
||||
public abstract Folder getFolder(URLName url)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Return a set of folders representing the <i>personal</i> namespaces
|
||||
* for the current user. A personal namespace is a set of names that
|
||||
* is considered within the personal scope of the authenticated user.
|
||||
* Typically, only the authenticated user has access to mail folders
|
||||
* in their personal namespace. If an INBOX exists for a user, it
|
||||
* must appear within the user's personal namespace. In the
|
||||
* typical case, there should be only one personal namespace for each
|
||||
* user in each Store. <p>
|
||||
* <p>
|
||||
* This implementation returns an array with a single entry containing
|
||||
* the return value of the <code>getDefaultFolder</code> method.
|
||||
* Subclasses should override this method to return appropriate information.
|
||||
*
|
||||
* @return array of Folder objects
|
||||
* @throws IllegalStateException if this Store is not connected.
|
||||
* @throws MessagingException for other failures
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public Folder[] getPersonalNamespaces() throws MessagingException {
|
||||
return new Folder[]{getDefaultFolder()};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a set of folders representing the namespaces for
|
||||
* <code>user</code>. The namespaces returned represent the
|
||||
* personal namespaces for the user. To access mail folders in the
|
||||
* other user's namespace, the currently authenticated user must be
|
||||
* explicitly granted access rights. For example, it is common for
|
||||
* a manager to grant to their secretary access rights to their
|
||||
* mail folders. <p>
|
||||
* <p>
|
||||
* This implementation returns an empty array. Subclasses should
|
||||
* override this method to return appropriate information.
|
||||
*
|
||||
* @param user the user name
|
||||
* @return array of Folder objects
|
||||
* @throws IllegalStateException if this Store is not connected.
|
||||
* @throws MessagingException for other failures
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public Folder[] getUserNamespaces(String user)
|
||||
throws MessagingException {
|
||||
return new Folder[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a set of folders representing the <i>shared</i> namespaces.
|
||||
* A shared namespace is a namespace that consists of mail folders
|
||||
* that are intended to be shared amongst users and do not exist
|
||||
* within a user's personal namespace. <p>
|
||||
* <p>
|
||||
* This implementation returns an empty array. Subclasses should
|
||||
* override this method to return appropriate information.
|
||||
*
|
||||
* @return array of Folder objects
|
||||
* @throws IllegalStateException if this Store is not connected.
|
||||
* @throws MessagingException for other failures
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public Folder[] getSharedNamespaces() throws MessagingException {
|
||||
return new Folder[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener for StoreEvents on this Store. <p>
|
||||
* <p>
|
||||
* The default implementation provided here adds this listener
|
||||
* to an internal list of StoreListeners.
|
||||
*
|
||||
* @param l the Listener for Store events
|
||||
* @see StoreEvent
|
||||
*/
|
||||
public synchronized void addStoreListener(StoreListener l) {
|
||||
if (storeListeners == null)
|
||||
storeListeners = new Vector<>();
|
||||
storeListeners.addElement(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a listener for Store events. <p>
|
||||
* <p>
|
||||
* The default implementation provided here removes this listener
|
||||
* from the internal list of StoreListeners.
|
||||
*
|
||||
* @param l the listener
|
||||
* @see #addStoreListener
|
||||
*/
|
||||
public synchronized void removeStoreListener(StoreListener l) {
|
||||
if (storeListeners != null)
|
||||
storeListeners.removeElement(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all StoreListeners. Store implementations are
|
||||
* expected to use this method to broadcast StoreEvents. <p>
|
||||
* <p>
|
||||
* The provided default implementation queues the event into
|
||||
* an internal event queue. An event dispatcher thread dequeues
|
||||
* events from the queue and dispatches them to the registered
|
||||
* StoreListeners. Note that the event dispatching occurs
|
||||
* in a separate thread, thus avoiding potential deadlock problems.
|
||||
*
|
||||
* @param type the StoreEvent type
|
||||
* @param message a message for the StoreEvent
|
||||
*/
|
||||
protected void notifyStoreListeners(int type, String message) {
|
||||
if (storeListeners == null)
|
||||
return;
|
||||
|
||||
StoreEvent e = new StoreEvent(this, type, message);
|
||||
queueEvent(e, storeListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a listener for Folder events on any Folder object
|
||||
* obtained from this Store. FolderEvents are delivered to
|
||||
* FolderListeners on the affected Folder as well as to
|
||||
* FolderListeners on the containing Store. <p>
|
||||
* <p>
|
||||
* The default implementation provided here adds this listener
|
||||
* to an internal list of FolderListeners.
|
||||
*
|
||||
* @param l the Listener for Folder events
|
||||
* @see FolderEvent
|
||||
*/
|
||||
public synchronized void addFolderListener(FolderListener l) {
|
||||
if (folderListeners == null)
|
||||
folderListeners = new Vector<>();
|
||||
folderListeners.addElement(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a listener for Folder events. <p>
|
||||
* <p>
|
||||
* The default implementation provided here removes this listener
|
||||
* from the internal list of FolderListeners.
|
||||
*
|
||||
* @param l the listener
|
||||
* @see #addFolderListener
|
||||
*/
|
||||
public synchronized void removeFolderListener(FolderListener l) {
|
||||
if (folderListeners != null)
|
||||
folderListeners.removeElement(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all FolderListeners. Store implementations are
|
||||
* expected to use this method to broadcast Folder events. <p>
|
||||
* <p>
|
||||
* The provided default implementation queues the event into
|
||||
* an internal event queue. An event dispatcher thread dequeues
|
||||
* events from the queue and dispatches them to the registered
|
||||
* FolderListeners. Note that the event dispatching occurs
|
||||
* in a separate thread, thus avoiding potential deadlock problems.
|
||||
*
|
||||
* @param type type of FolderEvent
|
||||
* @param folder affected Folder
|
||||
* @see #notifyFolderRenamedListeners
|
||||
*/
|
||||
protected void notifyFolderListeners(int type, Folder folder) {
|
||||
if (folderListeners == null)
|
||||
return;
|
||||
|
||||
FolderEvent e = new FolderEvent(this, folder, type);
|
||||
queueEvent(e, folderListeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all FolderListeners about the renaming of a folder.
|
||||
* Store implementations are expected to use this method to broadcast
|
||||
* Folder events indicating the renaming of folders. <p>
|
||||
* <p>
|
||||
* The provided default implementation queues the event into
|
||||
* an internal event queue. An event dispatcher thread dequeues
|
||||
* events from the queue and dispatches them to the registered
|
||||
* FolderListeners. Note that the event dispatching occurs
|
||||
* in a separate thread, thus avoiding potential deadlock problems.
|
||||
*
|
||||
* @param oldF the folder being renamed
|
||||
* @param newF the folder representing the new name.
|
||||
* @since JavaMail 1.1
|
||||
*/
|
||||
protected void notifyFolderRenamedListeners(Folder oldF, Folder newF) {
|
||||
if (folderListeners == null)
|
||||
return;
|
||||
|
||||
FolderEvent e = new FolderEvent(this, oldF, newF, FolderEvent.RENAMED);
|
||||
queueEvent(e, folderListeners);
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
/**
|
||||
* This exception is thrown when a method is invoked on a Messaging object
|
||||
* and the Store that owns that object has died due to some reason.
|
||||
* This exception should be treated as a fatal error; in particular any
|
||||
* messaging object belonging to that Store must be considered invalid. <p>
|
||||
* <p>
|
||||
* The connect method may be invoked on the dead Store object to
|
||||
* revive it. <p>
|
||||
* <p>
|
||||
* The getMessage() method returns more detailed information about the
|
||||
* error that caused this exception.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class StoreClosedException extends MessagingException {
|
||||
transient private Store store;
|
||||
|
||||
/**
|
||||
* Constructs a StoreClosedException with no detail message.
|
||||
*
|
||||
* @param store The dead Store object
|
||||
*/
|
||||
public StoreClosedException(Store store) {
|
||||
this(store, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a StoreClosedException with the specified
|
||||
* detail message.
|
||||
*
|
||||
* @param store The dead Store object
|
||||
* @param message The detailed error message
|
||||
*/
|
||||
public StoreClosedException(Store store, String message) {
|
||||
super(message);
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a StoreClosedException with the specified
|
||||
* detail message and embedded exception. The exception is chained
|
||||
* to this exception.
|
||||
*
|
||||
* @param store The dead Store object
|
||||
* @param message The detailed error message
|
||||
* @param e The embedded exception
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public StoreClosedException(Store store, String message, Exception e) {
|
||||
super(message, e);
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the dead Store object.
|
||||
*
|
||||
* @return the dead Store object
|
||||
*/
|
||||
public Store getStore() {
|
||||
return store;
|
||||
}
|
||||
}
|
|
@ -1,397 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import jakarta.mail.event.TransportEvent;
|
||||
import jakarta.mail.event.TransportListener;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Vector;
|
||||
|
||||
/**
|
||||
* An abstract class that models a message transport.
|
||||
* Subclasses provide actual implementations. <p>
|
||||
* <p>
|
||||
* Note that <code>Transport</code> extends the <code>Service</code>
|
||||
* class, which provides many common methods for naming transports,
|
||||
* connecting to transports, and listening to connection events.
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Max Spivak
|
||||
* @author Bill Shannon
|
||||
* @see Service
|
||||
* @see jakarta.mail.event.ConnectionEvent
|
||||
* @see TransportEvent
|
||||
*/
|
||||
|
||||
public abstract class Transport extends Service {
|
||||
|
||||
// Vector of Transport listeners
|
||||
private volatile Vector<TransportListener> transportListeners = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param session Session object for this Transport.
|
||||
* @param urlname URLName object to be used for this Transport
|
||||
*/
|
||||
public Transport(Session session, URLName urlname) {
|
||||
super(session, urlname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message. The message will be sent to all recipient
|
||||
* addresses specified in the message (as returned from the
|
||||
* <code>Message</code> method <code>getAllRecipients</code>),
|
||||
* using message transports appropriate to each address. The
|
||||
* <code>send</code> method calls the <code>saveChanges</code>
|
||||
* method on the message before sending it. <p>
|
||||
* <p>
|
||||
* If any of the recipient addresses is detected to be invalid by
|
||||
* the Transport during message submission, a SendFailedException
|
||||
* is thrown. Clients can get more detail about the failure by examining
|
||||
* the exception. Whether or not the message is still sent successfully
|
||||
* to any valid addresses depends on the Transport implementation. See
|
||||
* SendFailedException for more details. Note also that success does
|
||||
* not imply that the message was delivered to the ultimate recipient,
|
||||
* as failures may occur in later stages of delivery. Once a Transport
|
||||
* accepts a message for delivery to a recipient, failures that occur later
|
||||
* should be reported to the user via another mechanism, such as
|
||||
* returning the undeliverable message. <p>
|
||||
* <p>
|
||||
* In typical usage, a SendFailedException reflects an error detected
|
||||
* by the server. The details of the SendFailedException will usually
|
||||
* contain the error message from the server (such as an SMTP error
|
||||
* message). An address may be detected as invalid for a variety of
|
||||
* reasons - the address may not exist, the address may have invalid
|
||||
* syntax, the address may have exceeded its quota, etc. <p>
|
||||
* <p>
|
||||
* Note that <code>send</code> is a static method that creates and
|
||||
* manages its own connection. Any connection associated with any
|
||||
* Transport instance used to invoke this method is ignored and not
|
||||
* used. This method should only be invoked using the form
|
||||
* <code>Transport.send(msg);</code>, and should never be invoked
|
||||
* using an instance variable.
|
||||
*
|
||||
* @param msg the message to send
|
||||
* @throws SendFailedException if the message could not
|
||||
* be sent to some or any of the recipients.
|
||||
* @throws MessagingException for other failures
|
||||
* @see Message#saveChanges
|
||||
* @see Message#getAllRecipients
|
||||
* @see #send(Message, Address[])
|
||||
* @see SendFailedException
|
||||
*/
|
||||
public static void send(Message msg) throws MessagingException {
|
||||
msg.saveChanges(); // do this first
|
||||
send0(msg, msg.getAllRecipients(), null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message to the specified addresses, ignoring any
|
||||
* recipients specified in the message itself. The
|
||||
* <code>send</code> method calls the <code>saveChanges</code>
|
||||
* method on the message before sending it.
|
||||
*
|
||||
* @param msg the message to send
|
||||
* @param addresses the addresses to which to send the message
|
||||
* @throws SendFailedException if the message could not
|
||||
* be sent to some or any of the recipients.
|
||||
* @throws MessagingException for other failures
|
||||
* @see Message#saveChanges
|
||||
* @see SendFailedException
|
||||
* @see #send(Message)
|
||||
*/
|
||||
public static void send(Message msg, Address[] addresses)
|
||||
throws MessagingException {
|
||||
|
||||
msg.saveChanges();
|
||||
send0(msg, addresses, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a message. The message will be sent to all recipient
|
||||
* addresses specified in the message (as returned from the
|
||||
* <code>Message</code> method <code>getAllRecipients</code>).
|
||||
* The <code>send</code> method calls the <code>saveChanges</code>
|
||||
* method on the message before sending it. <p>
|
||||
* <p>
|
||||
* Use the specified user name and password to authenticate to
|
||||
* the mail server.
|
||||
*
|
||||
* @param msg the message to send
|
||||
* @param user the user name
|
||||
* @param password this user's password
|
||||
* @throws SendFailedException if the message could not
|
||||
* be sent to some or any of the recipients.
|
||||
* @throws MessagingException for other failures
|
||||
* @see Message#saveChanges
|
||||
* @see SendFailedException
|
||||
* @see #send(Message)
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public static void send(Message msg,
|
||||
String user, String password) throws MessagingException {
|
||||
|
||||
msg.saveChanges();
|
||||
send0(msg, msg.getAllRecipients(), user, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message to the specified addresses, ignoring any
|
||||
* recipients specified in the message itself. The
|
||||
* <code>send</code> method calls the <code>saveChanges</code>
|
||||
* method on the message before sending it. <p>
|
||||
* <p>
|
||||
* Use the specified user name and password to authenticate to
|
||||
* the mail server.
|
||||
*
|
||||
* @param msg the message to send
|
||||
* @param addresses the addresses to which to send the message
|
||||
* @param user the user name
|
||||
* @param password this user's password
|
||||
* @throws SendFailedException if the message could not
|
||||
* be sent to some or any of the recipients.
|
||||
* @throws MessagingException for other failures
|
||||
* @see Message#saveChanges
|
||||
* @see SendFailedException
|
||||
* @see #send(Message)
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public static void send(Message msg, Address[] addresses,
|
||||
String user, String password) throws MessagingException {
|
||||
|
||||
msg.saveChanges();
|
||||
send0(msg, addresses, user, password);
|
||||
}
|
||||
|
||||
// send, but without the saveChanges
|
||||
private static void send0(Message msg, Address[] addresses,
|
||||
String user, String password) throws MessagingException {
|
||||
|
||||
if (addresses == null || addresses.length == 0)
|
||||
throw new SendFailedException("No recipient addresses");
|
||||
|
||||
/*
|
||||
* protocols is a map containing the addresses
|
||||
* indexed by address type
|
||||
*/
|
||||
Map<String, List<Address>> protocols
|
||||
= new HashMap<>();
|
||||
|
||||
// Lists of addresses
|
||||
List<Address> invalid = new ArrayList<>();
|
||||
List<Address> validSent = new ArrayList<>();
|
||||
List<Address> validUnsent = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < addresses.length; i++) {
|
||||
// is this address type already in the map?
|
||||
if (protocols.containsKey(addresses[i].getType())) {
|
||||
List<Address> v = protocols.get(addresses[i].getType());
|
||||
v.add(addresses[i]);
|
||||
} else {
|
||||
// need to add a new protocol
|
||||
List<Address> w = new ArrayList<>();
|
||||
w.add(addresses[i]);
|
||||
protocols.put(addresses[i].getType(), w);
|
||||
}
|
||||
}
|
||||
|
||||
int dsize = protocols.size();
|
||||
if (dsize == 0)
|
||||
throw new SendFailedException("No recipient addresses");
|
||||
|
||||
Session s = (msg.session != null) ? msg.session :
|
||||
Session.getDefaultInstance(System.getProperties(), null);
|
||||
Transport transport;
|
||||
|
||||
/*
|
||||
* Optimize the case of a single protocol.
|
||||
*/
|
||||
if (dsize == 1) {
|
||||
transport = s.getTransport(addresses[0]);
|
||||
try {
|
||||
if (user != null)
|
||||
transport.connect(user, password);
|
||||
else
|
||||
transport.connect();
|
||||
transport.sendMessage(msg, addresses);
|
||||
} finally {
|
||||
transport.close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* More than one protocol. Have to do them one at a time
|
||||
* and collect addresses and chain exceptions.
|
||||
*/
|
||||
MessagingException chainedEx = null;
|
||||
boolean sendFailed = false;
|
||||
|
||||
for (List<Address> v : protocols.values()) {
|
||||
Address[] protaddresses = new Address[v.size()];
|
||||
v.toArray(protaddresses);
|
||||
|
||||
// Get a Transport that can handle this address type.
|
||||
if ((transport = s.getTransport(protaddresses[0])) == null) {
|
||||
// Could not find an appropriate Transport ..
|
||||
// Mark these addresses invalid.
|
||||
Collections.addAll(invalid, protaddresses);
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
transport.connect();
|
||||
transport.sendMessage(msg, protaddresses);
|
||||
} catch (SendFailedException sex) {
|
||||
sendFailed = true;
|
||||
// chain the exception we're catching to any previous ones
|
||||
if (chainedEx == null)
|
||||
chainedEx = sex;
|
||||
else
|
||||
chainedEx.setNextException(sex);
|
||||
|
||||
// retrieve invalid addresses
|
||||
Address[] a = sex.getInvalidAddresses();
|
||||
if (a != null)
|
||||
Collections.addAll(invalid, a);
|
||||
|
||||
// retrieve validSent addresses
|
||||
a = sex.getValidSentAddresses();
|
||||
if (a != null)
|
||||
Collections.addAll(validSent, a);
|
||||
|
||||
// retrieve validUnsent addresses
|
||||
Address[] c = sex.getValidUnsentAddresses();
|
||||
if (c != null)
|
||||
Collections.addAll(validUnsent, c);
|
||||
} catch (MessagingException mex) {
|
||||
sendFailed = true;
|
||||
// chain the exception we're catching to any previous ones
|
||||
if (chainedEx == null)
|
||||
chainedEx = mex;
|
||||
else
|
||||
chainedEx.setNextException(mex);
|
||||
} finally {
|
||||
transport.close();
|
||||
}
|
||||
}
|
||||
|
||||
// done with all protocols. throw exception if something failed
|
||||
if (sendFailed || invalid.size() != 0 || validUnsent.size() != 0) {
|
||||
Address[] a = null, b = null, c = null;
|
||||
|
||||
// copy address lists into arrays
|
||||
if (validSent.size() > 0) {
|
||||
a = new Address[validSent.size()];
|
||||
validSent.toArray(a);
|
||||
}
|
||||
if (validUnsent.size() > 0) {
|
||||
b = new Address[validUnsent.size()];
|
||||
validUnsent.toArray(b);
|
||||
}
|
||||
if (invalid.size() > 0) {
|
||||
c = new Address[invalid.size()];
|
||||
invalid.toArray(c);
|
||||
}
|
||||
throw new SendFailedException("Sending failed", chainedEx,
|
||||
a, b, c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the Message to the specified list of addresses. An appropriate
|
||||
* TransportEvent indicating the delivery status is delivered to any
|
||||
* TransportListener registered on this Transport. Also, if any of
|
||||
* the addresses is invalid, a SendFailedException is thrown.
|
||||
* Whether or not the message is still sent succesfully to
|
||||
* any valid addresses depends on the Transport implementation. <p>
|
||||
* <p>
|
||||
* Unlike the static <code>send</code> method, the <code>sendMessage</code>
|
||||
* method does <em>not</em> call the <code>saveChanges</code> method on
|
||||
* the message; the caller should do so.
|
||||
*
|
||||
* @param msg The Message to be sent
|
||||
* @param addresses array of addresses to send this message to
|
||||
* @throws SendFailedException if the send failed because of
|
||||
* invalid addresses.
|
||||
* @throws MessagingException if the connection is dead or not in the
|
||||
* connected state
|
||||
* @see TransportEvent
|
||||
*/
|
||||
public abstract void sendMessage(Message msg, Address[] addresses)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Add a listener for Transport events. <p>
|
||||
* <p>
|
||||
* The default implementation provided here adds this listener
|
||||
* to an internal list of TransportListeners.
|
||||
*
|
||||
* @param l the Listener for Transport events
|
||||
* @see TransportEvent
|
||||
*/
|
||||
public synchronized void addTransportListener(TransportListener l) {
|
||||
if (transportListeners == null)
|
||||
transportListeners = new Vector<>();
|
||||
transportListeners.addElement(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a listener for Transport events. <p>
|
||||
* <p>
|
||||
* The default implementation provided here removes this listener
|
||||
* from the internal list of TransportListeners.
|
||||
*
|
||||
* @param l the listener
|
||||
* @see #addTransportListener
|
||||
*/
|
||||
public synchronized void removeTransportListener(TransportListener l) {
|
||||
if (transportListeners != null)
|
||||
transportListeners.removeElement(l);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify all TransportListeners. Transport implementations are
|
||||
* expected to use this method to broadcast TransportEvents.<p>
|
||||
* <p>
|
||||
* The provided default implementation queues the event into
|
||||
* an internal event queue. An event dispatcher thread dequeues
|
||||
* events from the queue and dispatches them to the registered
|
||||
* TransportListeners. Note that the event dispatching occurs
|
||||
* in a separate thread, thus avoiding potential deadlock problems.
|
||||
*
|
||||
* @param type the TransportEvent type
|
||||
* @param validSent valid addresses to which message was sent
|
||||
* @param validUnsent valid addresses to which message was not sent
|
||||
* @param invalid the invalid addresses
|
||||
* @param msg the message
|
||||
*/
|
||||
protected void notifyTransportListeners(int type, Address[] validSent,
|
||||
Address[] validUnsent,
|
||||
Address[] invalid, Message msg) {
|
||||
if (transportListeners == null)
|
||||
return;
|
||||
|
||||
TransportEvent e = new TransportEvent(this, type, validSent,
|
||||
validUnsent, invalid, msg);
|
||||
queueEvent(e, transportListeners);
|
||||
}
|
||||
}
|
|
@ -1,210 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* The <code>UIDFolder</code> interface is implemented by Folders
|
||||
* that can support the "disconnected" mode of operation, by providing
|
||||
* unique-ids for messages in the folder. This interface is based on
|
||||
* the IMAP model for supporting disconnected operation. <p>
|
||||
* <p>
|
||||
* A Unique identifier (UID) is a positive long value, assigned to
|
||||
* each message in a specific folder. Unique identifiers are assigned
|
||||
* in a strictly <strong>ascending</strong> fashion in the mailbox.
|
||||
* That is, as each message is added to the mailbox it is assigned a
|
||||
* higher UID than the message(s) which were added previously. Unique
|
||||
* identifiers persist across sessions. This permits a client to
|
||||
* resynchronize its state from a previous session with the server. <p>
|
||||
* <p>
|
||||
* Associated with every mailbox is a unique identifier validity value.
|
||||
* If unique identifiers from an earlier session fail to persist to
|
||||
* this session, the unique identifier validity value
|
||||
* <strong>must</strong> be greater than the one used in the earlier
|
||||
* session. <p>
|
||||
* <p>
|
||||
* Refer to <A HREF="http://www.ietf.org/rfc/rfc2060.txt">RFC 2060</A>
|
||||
* for more information.
|
||||
* <p>
|
||||
* All the Folder objects returned by the default IMAP provider implement
|
||||
* the UIDFolder interface. Use it as follows:
|
||||
* <blockquote><pre>
|
||||
*
|
||||
* Folder f = store.getFolder("whatever");
|
||||
* UIDFolder uf = (UIDFolder)f;
|
||||
* long uid = uf.getUID(msg);
|
||||
*
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @author Bill Shannon
|
||||
* @author John Mani
|
||||
*/
|
||||
|
||||
public interface UIDFolder {
|
||||
|
||||
/**
|
||||
* This is a special value that can be used as the <code>end</code>
|
||||
* parameter in <code>getMessagesByUID(start, end)</code>, to denote the
|
||||
* UID of the last message in the folder.
|
||||
*
|
||||
* @see #getMessagesByUID
|
||||
*/
|
||||
long LASTUID = -1;
|
||||
/**
|
||||
* The largest value possible for a UID, a 32-bit unsigned integer.
|
||||
* This can be used to fetch all new messages by keeping track of the
|
||||
* last UID that was seen and using:
|
||||
* <blockquote><pre>
|
||||
*
|
||||
* Folder f = store.getFolder("whatever");
|
||||
* UIDFolder uf = (UIDFolder)f;
|
||||
* Message[] newMsgs =
|
||||
* uf.getMessagesByUID(lastSeenUID + 1, UIDFolder.MAXUID);
|
||||
*
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @since JavaMail 1.6
|
||||
*/
|
||||
long MAXUID = 0xffffffffL; // max 32-bit unsigned int
|
||||
|
||||
/**
|
||||
* Returns the UIDValidity value associated with this folder. <p>
|
||||
* <p>
|
||||
* Clients typically compare this value against a UIDValidity
|
||||
* value saved from a previous session to insure that any cached
|
||||
* UIDs are not stale.
|
||||
*
|
||||
* @return UIDValidity
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
long getUIDValidity() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get the Message corresponding to the given UID. If no such
|
||||
* message exists, <code>null</code> is returned.
|
||||
*
|
||||
* @param uid UID for the desired message
|
||||
* @return the Message object. <code>null</code> is returned
|
||||
* if no message corresponding to this UID is obtained.
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
Message getMessageByUID(long uid) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get the Messages specified by the given range. The special
|
||||
* value LASTUID can be used for the <code>end</code> parameter
|
||||
* to indicate the UID of the last message in the folder. <p>
|
||||
* <p>
|
||||
* Note that <code>end</code> need not be greater than <code>start</code>;
|
||||
* the order of the range doesn't matter.
|
||||
* Note also that, unless the folder is empty, use of LASTUID ensures
|
||||
* that at least one message will be returned - the last message in the
|
||||
* folder.
|
||||
*
|
||||
* @param start start UID
|
||||
* @param end end UID
|
||||
* @return array of Message objects
|
||||
* @throws MessagingException for failures
|
||||
* @see #LASTUID
|
||||
*/
|
||||
Message[] getMessagesByUID(long start, long end)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get the Messages specified by the given array of UIDs. If any UID is
|
||||
* invalid, <code>null</code> is returned for that entry. <p>
|
||||
* <p>
|
||||
* Note that the returned array will be of the same size as the specified
|
||||
* array of UIDs, and <code>null</code> entries may be present in the
|
||||
* array to indicate invalid UIDs.
|
||||
*
|
||||
* @param uids array of UIDs
|
||||
* @return array of Message objects
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
Message[] getMessagesByUID(long[] uids)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get the UID for the specified message. Note that the message
|
||||
* <strong>must</strong> belong to this folder. Otherwise
|
||||
* java.util.NoSuchElementException is thrown.
|
||||
*
|
||||
* @param message Message from this folder
|
||||
* @return UID for this message
|
||||
* @throws NoSuchElementException if the given Message
|
||||
* is not in this Folder.
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
long getUID(Message message) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Returns the predicted UID that will be assigned to the
|
||||
* next message that is appended to this folder.
|
||||
* Messages might be appended to the folder after this value
|
||||
* is retrieved, causing this value to be out of date.
|
||||
* This value might only be updated when a folder is first opened.
|
||||
* Note that messages may have been appended to the folder
|
||||
* while it was open and thus this value may be out of
|
||||
* date. <p>
|
||||
* <p>
|
||||
* If the value is unknown, -1 is returned.
|
||||
*
|
||||
* @return the UIDNEXT value, or -1 if unknown
|
||||
* @throws MessagingException for failures
|
||||
* @since JavaMail 1.6
|
||||
*/
|
||||
long getUIDNext() throws MessagingException;
|
||||
|
||||
/**
|
||||
* A fetch profile item for fetching UIDs.
|
||||
* This inner class extends the <code>FetchProfile.Item</code>
|
||||
* class to add new FetchProfile item types, specific to UIDFolders.
|
||||
* The only item currently defined here is the <code>UID</code> item.
|
||||
*
|
||||
* @see FetchProfile
|
||||
*/
|
||||
class FetchProfileItem extends FetchProfile.Item {
|
||||
/**
|
||||
* UID is a fetch profile item that can be included in a
|
||||
* <code>FetchProfile</code> during a fetch request to a Folder.
|
||||
* This item indicates that the UIDs for messages in the specified
|
||||
* range are desired to be prefetched. <p>
|
||||
* <p>
|
||||
* An example of how a client uses this is below:
|
||||
* <blockquote><pre>
|
||||
*
|
||||
* FetchProfile fp = new FetchProfile();
|
||||
* fp.add(UIDFolder.FetchProfileItem.UID);
|
||||
* folder.fetch(msgs, fp);
|
||||
*
|
||||
* </pre></blockquote>
|
||||
*/
|
||||
public static final FetchProfileItem UID =
|
||||
new FetchProfileItem("UID");
|
||||
|
||||
/**
|
||||
* Constructor for an item.
|
||||
*
|
||||
* @param name the item name
|
||||
*/
|
||||
protected FetchProfileItem(String name) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,774 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.InetAddress;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.BitSet;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
/**
|
||||
* The name of a URL. This class represents a URL name and also
|
||||
* provides the basic parsing functionality to parse most internet
|
||||
* standard URL schemes. <p>
|
||||
* <p>
|
||||
* Note that this class differs from <code>java.net.URL</code>
|
||||
* in that this class just represents the name of a URL, it does
|
||||
* not model the connection to a URL.
|
||||
*
|
||||
* @author Christopher Cotton
|
||||
* @author Bill Shannon
|
||||
*/
|
||||
|
||||
public class URLName {
|
||||
|
||||
static final int caseDiff = ('a' - 'A');
|
||||
/**
|
||||
* The class contains a utility method for converting a
|
||||
* <code>String</code> into a MIME format called
|
||||
* "<code>x-www-form-urlencoded</code>" format.
|
||||
* <p>
|
||||
* To convert a <code>String</code>, each character is examined in turn:
|
||||
* <ul>
|
||||
* <li>The ASCII characters '<code>a</code>' through '<code>z</code>',
|
||||
* '<code>A</code>' through '<code>Z</code>', '<code>0</code>'
|
||||
* through '<code>9</code>', and ".", "-",
|
||||
* "*", "_" remain the same.
|
||||
* <li>The space character '<code> </code>' is converted into a
|
||||
* plus sign '<code>+</code>'.
|
||||
* <li>All other characters are converted into the 3-character string
|
||||
* "<code>%<i>xy</i></code>", where <i>xy</i> is the two-digit
|
||||
* hexadecimal representation of the lower 8-bits of the character.
|
||||
* </ul>
|
||||
*
|
||||
* @author Herb Jellinek
|
||||
* @since JDK1.0
|
||||
*/
|
||||
static BitSet dontNeedEncoding;
|
||||
/**
|
||||
* A way to turn off encoding, just in case...
|
||||
*/
|
||||
private static boolean doEncode = true;
|
||||
|
||||
static {
|
||||
try {
|
||||
doEncode = !Boolean.getBoolean("mail.URLName.dontencode");
|
||||
} catch (Exception ex) {
|
||||
// ignore any errors
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
dontNeedEncoding = new BitSet(256);
|
||||
int i;
|
||||
for (i = 'a'; i <= 'z'; i++) {
|
||||
dontNeedEncoding.set(i);
|
||||
}
|
||||
for (i = 'A'; i <= 'Z'; i++) {
|
||||
dontNeedEncoding.set(i);
|
||||
}
|
||||
for (i = '0'; i <= '9'; i++) {
|
||||
dontNeedEncoding.set(i);
|
||||
}
|
||||
/* encoding a space to a + is done in the encode() method */
|
||||
dontNeedEncoding.set(' ');
|
||||
dontNeedEncoding.set('-');
|
||||
dontNeedEncoding.set('_');
|
||||
dontNeedEncoding.set('.');
|
||||
dontNeedEncoding.set('*');
|
||||
}
|
||||
|
||||
/**
|
||||
* The full version of the URL
|
||||
*/
|
||||
protected String fullURL;
|
||||
/**
|
||||
* The protocol to use (ftp, http, nntp, imap, pop3 ... etc.) .
|
||||
*/
|
||||
private String protocol;
|
||||
/**
|
||||
* The username to use when connecting
|
||||
*/
|
||||
private String username;
|
||||
/**
|
||||
* The password to use when connecting.
|
||||
*/
|
||||
private String password;
|
||||
/**
|
||||
* The host name to which to connect.
|
||||
*/
|
||||
private String host;
|
||||
/**
|
||||
* The host's IP address, used in equals and hashCode.
|
||||
* Computed on demand.
|
||||
*/
|
||||
private InetAddress hostAddress;
|
||||
private boolean hostAddressKnown = false;
|
||||
/**
|
||||
* The protocol port to connect to.
|
||||
*/
|
||||
private int port = -1;
|
||||
/**
|
||||
* The specified file name on that host.
|
||||
*/
|
||||
private String file;
|
||||
/**
|
||||
* # reference.
|
||||
*/
|
||||
private String ref;
|
||||
/**
|
||||
* Our hash code.
|
||||
*/
|
||||
private int hashCode = 0;
|
||||
|
||||
/**
|
||||
* Creates a URLName object from the specified protocol,
|
||||
* host, port number, file, username, and password. Specifying a port
|
||||
* number of -1 indicates that the URL should use the default port for
|
||||
* the protocol.
|
||||
*
|
||||
* @param protocol the protocol
|
||||
* @param host the host name
|
||||
* @param port the port number
|
||||
* @param file the file
|
||||
* @param username the user name
|
||||
* @param password the password
|
||||
*/
|
||||
public URLName(
|
||||
String protocol,
|
||||
String host,
|
||||
int port,
|
||||
String file,
|
||||
String username,
|
||||
String password
|
||||
) {
|
||||
this.protocol = protocol;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
int refStart;
|
||||
if (file != null && (refStart = file.indexOf('#')) != -1) {
|
||||
this.file = file.substring(0, refStart);
|
||||
this.ref = file.substring(refStart + 1);
|
||||
} else {
|
||||
this.file = file;
|
||||
this.ref = null;
|
||||
}
|
||||
this.username = doEncode ? encode(username) : username;
|
||||
this.password = doEncode ? encode(password) : password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a URLName from a java.net.URL object.
|
||||
*
|
||||
* @param url the URL
|
||||
*/
|
||||
public URLName(URL url) {
|
||||
this(url.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a URLName from the string. Parses out all the possible
|
||||
* information (protocol, host, port, file, username, password).
|
||||
*
|
||||
* @param url the URL string
|
||||
*/
|
||||
public URLName(String url) {
|
||||
parseString(url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates a string into <code>x-www-form-urlencoded</code> format.
|
||||
*
|
||||
* @param s <code>String</code> to be translated.
|
||||
* @return the translated <code>String</code>.
|
||||
*/
|
||||
static String encode(String s) {
|
||||
if (s == null)
|
||||
return null;
|
||||
// the common case is no encoding is needed
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
int c = s.charAt(i);
|
||||
if (c == ' ' || !dontNeedEncoding.get(c))
|
||||
return _encode(s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
private static String _encode(String s) {
|
||||
int maxBytesPerChar = 10;
|
||||
StringBuilder out = new StringBuilder(s.length());
|
||||
ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar);
|
||||
OutputStreamWriter writer = new OutputStreamWriter(buf);
|
||||
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
int c = s.charAt(i);
|
||||
if (dontNeedEncoding.get(c)) {
|
||||
if (c == ' ') {
|
||||
c = '+';
|
||||
}
|
||||
out.append((char) c);
|
||||
} else {
|
||||
// convert to external encoding before hex conversion
|
||||
try {
|
||||
writer.write(c);
|
||||
writer.flush();
|
||||
} catch (IOException e) {
|
||||
buf.reset();
|
||||
continue;
|
||||
}
|
||||
byte[] ba = buf.toByteArray();
|
||||
for (int j = 0; j < ba.length; j++) {
|
||||
out.append('%');
|
||||
char ch = Character.forDigit((ba[j] >> 4) & 0xF, 16);
|
||||
// converting to use uppercase letter as part of
|
||||
// the hex value if ch is a letter.
|
||||
if (Character.isLetter(ch)) {
|
||||
ch -= caseDiff;
|
||||
}
|
||||
out.append(ch);
|
||||
ch = Character.forDigit(ba[j] & 0xF, 16);
|
||||
if (Character.isLetter(ch)) {
|
||||
ch -= caseDiff;
|
||||
}
|
||||
out.append(ch);
|
||||
}
|
||||
buf.reset();
|
||||
}
|
||||
}
|
||||
|
||||
return out.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a "x-www-form-urlencoded"
|
||||
* to a <code>String</code>.
|
||||
*
|
||||
* @param s the <code>String</code> to decode
|
||||
* @return the newly decoded <code>String</code>
|
||||
*/
|
||||
static String decode(String s) {
|
||||
if (s == null)
|
||||
return null;
|
||||
if (indexOfAny(s, "+%") == -1)
|
||||
return s; // the common case
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char c = s.charAt(i);
|
||||
switch (c) {
|
||||
case '+':
|
||||
sb.append(' ');
|
||||
break;
|
||||
case '%':
|
||||
try {
|
||||
sb.append((char) Integer.parseInt(
|
||||
s.substring(i + 1, i + 3), 16));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(
|
||||
"Illegal URL encoded value: " +
|
||||
s.substring(i, i + 3));
|
||||
}
|
||||
i += 2;
|
||||
break;
|
||||
default:
|
||||
sb.append(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Undo conversion to external encoding
|
||||
String result = sb.toString();
|
||||
byte[] inputBytes = result.getBytes(StandardCharsets.ISO_8859_1);
|
||||
result = new String(inputBytes);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the first index of any of the characters in "any" in "s",
|
||||
* or -1 if none are found.
|
||||
* <p>
|
||||
* This should be a method on String.
|
||||
*/
|
||||
private static int indexOfAny(String s, String any) {
|
||||
return indexOfAny(s, any, 0);
|
||||
}
|
||||
|
||||
private static int indexOfAny(String s, String any, int start) {
|
||||
try {
|
||||
int len = s.length();
|
||||
for (int i = start; i < len; i++) {
|
||||
if (any.indexOf(s.charAt(i)) >= 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
} catch (StringIndexOutOfBoundsException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a string representation of this URLName.
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if (fullURL == null) {
|
||||
// add the "protocol:"
|
||||
StringBuilder tempURL = new StringBuilder();
|
||||
if (protocol != null) {
|
||||
tempURL.append(protocol);
|
||||
tempURL.append(":");
|
||||
}
|
||||
|
||||
if (username != null || host != null) {
|
||||
// add the "//"
|
||||
tempURL.append("//");
|
||||
|
||||
// add the user:password@
|
||||
// XXX - can you just have a password? without a username?
|
||||
if (username != null) {
|
||||
tempURL.append(username);
|
||||
|
||||
if (password != null) {
|
||||
tempURL.append(":");
|
||||
tempURL.append(password);
|
||||
}
|
||||
|
||||
tempURL.append("@");
|
||||
}
|
||||
|
||||
// add host
|
||||
if (host != null) {
|
||||
tempURL.append(host);
|
||||
}
|
||||
|
||||
// add port (if needed)
|
||||
if (port != -1) {
|
||||
tempURL.append(":");
|
||||
tempURL.append(port);
|
||||
}
|
||||
if (file != null)
|
||||
tempURL.append("/");
|
||||
}
|
||||
|
||||
// add the file
|
||||
if (file != null) {
|
||||
tempURL.append(file);
|
||||
}
|
||||
|
||||
// add the ref
|
||||
if (ref != null) {
|
||||
tempURL.append("#");
|
||||
tempURL.append(ref);
|
||||
}
|
||||
|
||||
// create the fullURL now
|
||||
fullURL = tempURL.toString();
|
||||
}
|
||||
|
||||
return fullURL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Method which does all of the work of parsing the string.
|
||||
*
|
||||
* @param url the URL string to parse
|
||||
*/
|
||||
private void parseString(String url) {
|
||||
// initialize everything in case called from subclass
|
||||
// (URLName really should be a final class)
|
||||
protocol = file = ref = host = username = password = null;
|
||||
port = -1;
|
||||
|
||||
int len = url.length();
|
||||
|
||||
// find the protocol
|
||||
// XXX - should check for only legal characters before the colon
|
||||
// (legal: a-z, A-Z, 0-9, "+", ".", "-")
|
||||
int protocolEnd = url.indexOf(':');
|
||||
if (protocolEnd != -1)
|
||||
protocol = url.substring(0, protocolEnd);
|
||||
|
||||
// is this an Internet standard URL that contains a host name?
|
||||
if (url.regionMatches(protocolEnd + 1, "//", 0, 2)) {
|
||||
// find where the file starts
|
||||
String fullhost = null;
|
||||
int fileStart = url.indexOf('/', protocolEnd + 3);
|
||||
if (fileStart != -1) {
|
||||
fullhost = url.substring(protocolEnd + 3, fileStart);
|
||||
if (fileStart + 1 < len)
|
||||
file = url.substring(fileStart + 1);
|
||||
else
|
||||
file = "";
|
||||
} else
|
||||
fullhost = url.substring(protocolEnd + 3);
|
||||
|
||||
// examine the fullhost, for username password etc.
|
||||
int i = fullhost.indexOf('@');
|
||||
if (i != -1) {
|
||||
String fulluserpass = fullhost.substring(0, i);
|
||||
fullhost = fullhost.substring(i + 1);
|
||||
|
||||
// get user and password
|
||||
int passindex = fulluserpass.indexOf(':');
|
||||
if (passindex != -1) {
|
||||
username = fulluserpass.substring(0, passindex);
|
||||
password = fulluserpass.substring(passindex + 1);
|
||||
} else {
|
||||
username = fulluserpass;
|
||||
}
|
||||
}
|
||||
|
||||
// get the port (if there)
|
||||
int portindex;
|
||||
if (fullhost.length() > 0 && fullhost.charAt(0) == '[') {
|
||||
// an IPv6 address?
|
||||
portindex = fullhost.indexOf(':', fullhost.indexOf(']'));
|
||||
} else {
|
||||
portindex = fullhost.indexOf(':');
|
||||
}
|
||||
if (portindex != -1) {
|
||||
String portstring = fullhost.substring(portindex + 1);
|
||||
if (portstring.length() > 0) {
|
||||
try {
|
||||
port = Integer.parseInt(portstring);
|
||||
} catch (NumberFormatException nfex) {
|
||||
port = -1;
|
||||
}
|
||||
}
|
||||
|
||||
host = fullhost.substring(0, portindex);
|
||||
} else {
|
||||
host = fullhost;
|
||||
}
|
||||
} else {
|
||||
if (protocolEnd + 1 < len)
|
||||
file = url.substring(protocolEnd + 1);
|
||||
}
|
||||
|
||||
// extract the reference from the file name, if any
|
||||
int refStart;
|
||||
if (file != null && (refStart = file.indexOf('#')) != -1) {
|
||||
ref = file.substring(refStart + 1);
|
||||
file = file.substring(0, refStart);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the port number of this URLName.
|
||||
* Returns -1 if the port is not set.
|
||||
*
|
||||
* @return the port number
|
||||
*/
|
||||
public int getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the protocol of this URLName.
|
||||
* Returns null if this URLName has no protocol.
|
||||
*
|
||||
* @return the protocol
|
||||
*/
|
||||
public String getProtocol() {
|
||||
return protocol;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the file name of this URLName.
|
||||
* Returns null if this URLName has no file name.
|
||||
*
|
||||
* @return the file name of this URLName
|
||||
*/
|
||||
public String getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reference of this URLName.
|
||||
* Returns null if this URLName has no reference.
|
||||
*
|
||||
* @return the reference part of the URLName
|
||||
*/
|
||||
public String getRef() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the host of this URLName.
|
||||
* Returns null if this URLName has no host.
|
||||
*
|
||||
* @return the host name
|
||||
*/
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
/* The list of characters that are not encoded have been determined by
|
||||
referencing O'Reilly's "HTML: The Definitive Guide" (page 164). */
|
||||
|
||||
/**
|
||||
* Returns the user name of this URLName.
|
||||
* Returns null if this URLName has no user name.
|
||||
*
|
||||
* @return the user name
|
||||
*/
|
||||
public String getUsername() {
|
||||
return doEncode ? decode(username) : username;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the password of this URLName.
|
||||
* Returns null if this URLName has no password.
|
||||
*
|
||||
* @return the password
|
||||
*/
|
||||
public String getPassword() {
|
||||
return doEncode ? decode(password) : password;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a URL from the URLName.
|
||||
*
|
||||
* @return the URL
|
||||
* @throws MalformedURLException if the URL is malformed
|
||||
*/
|
||||
public URL getURL() throws MalformedURLException {
|
||||
// URL expects the file to include the separating "/"
|
||||
String f = getFile();
|
||||
if (f == null)
|
||||
f = "";
|
||||
else
|
||||
f = "/" + f;
|
||||
return URI.create(getProtocol() + "://" + getHost() + ":" + getPort() + "/" + f).toURL();
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The class contains a utility method for converting from
|
||||
* a MIME format called "<code>x-www-form-urlencoded</code>"
|
||||
* to a <code>String</code>
|
||||
* <p>
|
||||
* To convert to a <code>String</code>, each character is examined in turn:
|
||||
* <ul>
|
||||
* <li>The ASCII characters '<code>a</code>' through '<code>z</code>',
|
||||
* '<code>A</code>' through '<code>Z</code>', and '<code>0</code>'
|
||||
* through '<code>9</code>' remain the same.
|
||||
* <li>The plus sign '<code>+</code>'is converted into a
|
||||
* space character '<code> </code>'.
|
||||
* <li>The remaining characters are represented by 3-character
|
||||
* strings which begin with the percent sign,
|
||||
* "<code>%<i>xy</i></code>", where <i>xy</i> is the two-digit
|
||||
* hexadecimal representation of the lower 8-bits of the character.
|
||||
* </ul>
|
||||
*
|
||||
* @author Mark Chamness
|
||||
* @author Michael McCloskey
|
||||
* @since 1.2
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compares two URLNames. The result is true if and only if the
|
||||
* argument is not null and is a URLName object that represents the
|
||||
* same URLName as this object. Two URLName objects are equal if
|
||||
* they have the same protocol and the same host,
|
||||
* the same port number on the host, the same username,
|
||||
* and the same file on the host. The fields (host, username,
|
||||
* file) are also considered the same if they are both
|
||||
* null. <p>
|
||||
* <p>
|
||||
* Hosts are considered equal if the names are equal (case independent)
|
||||
* or if host name lookups for them both succeed and they both reference
|
||||
* the same IP address. <p>
|
||||
* <p>
|
||||
* Note that URLName has no knowledge of default port numbers for
|
||||
* particular protocols, so "imap://host" and "imap://host:143"
|
||||
* would not compare as equal. <p>
|
||||
* <p>
|
||||
* Note also that the password field is not included in the comparison,
|
||||
* nor is any reference field appended to the filename.
|
||||
*/
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof URLName))
|
||||
return false;
|
||||
URLName u2 = (URLName) obj;
|
||||
|
||||
// compare protocols
|
||||
if (!(Objects.equals(protocol, u2.protocol)))
|
||||
return false;
|
||||
|
||||
// compare hosts
|
||||
InetAddress a1 = getHostAddress(), a2 = u2.getHostAddress();
|
||||
// if we have internet address for both, and they're not the same, fail
|
||||
if (a1 != null && a2 != null) {
|
||||
if (!a1.equals(a2))
|
||||
return false;
|
||||
// else, if we have host names for both, and they're not the same, fail
|
||||
} else if (host != null && u2.host != null) {
|
||||
if (!host.equalsIgnoreCase(u2.host))
|
||||
return false;
|
||||
// else, if not both null
|
||||
} else if (host != u2.host) {
|
||||
return false;
|
||||
}
|
||||
// at this point, hosts match
|
||||
|
||||
// compare usernames
|
||||
if (!(Objects.equals(username, u2.username)))
|
||||
return false;
|
||||
|
||||
// Forget about password since it doesn't
|
||||
// really denote a different store.
|
||||
|
||||
// compare files
|
||||
String f1 = file == null ? "" : file;
|
||||
String f2 = u2.file == null ? "" : u2.file;
|
||||
|
||||
if (!f1.equals(f2))
|
||||
return false;
|
||||
|
||||
// compare ports
|
||||
if (port != u2.port)
|
||||
return false;
|
||||
|
||||
// all comparisons succeeded, they're equal
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute the hash code for this URLName.
|
||||
*/
|
||||
@Override
|
||||
public int hashCode() {
|
||||
if (hashCode != 0)
|
||||
return hashCode;
|
||||
if (protocol != null)
|
||||
hashCode += protocol.hashCode();
|
||||
InetAddress addr = getHostAddress();
|
||||
if (addr != null)
|
||||
hashCode += addr.hashCode();
|
||||
else if (host != null)
|
||||
hashCode += host.toLowerCase(Locale.ENGLISH).hashCode();
|
||||
if (username != null)
|
||||
hashCode += username.hashCode();
|
||||
if (file != null)
|
||||
hashCode += file.hashCode();
|
||||
hashCode += port;
|
||||
return hashCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the IP address of our host. Look up the
|
||||
* name the first time and remember that we've done
|
||||
* so, whether the lookup fails or not.
|
||||
*/
|
||||
private synchronized InetAddress getHostAddress() {
|
||||
if (hostAddressKnown)
|
||||
return hostAddress;
|
||||
if (host == null)
|
||||
return null;
|
||||
try {
|
||||
hostAddress = InetAddress.getByName(host);
|
||||
} catch (UnknownHostException ex) {
|
||||
hostAddress = null;
|
||||
}
|
||||
hostAddressKnown = true;
|
||||
return hostAddress;
|
||||
}
|
||||
|
||||
/*
|
||||
// Do not remove, this is needed when testing new URL cases
|
||||
public static void main(String[] argv) {
|
||||
String [] testURLNames = {
|
||||
"protocol://userid:password@host:119/file",
|
||||
"http://funny/folder/file.html",
|
||||
"http://funny/folder/file.html#ref",
|
||||
"http://funny/folder/file.html#",
|
||||
"http://funny/#ref",
|
||||
"imap://jmr:secret@labyrinth//var/mail/jmr",
|
||||
"nntp://fred@labyrinth:143/save/it/now.mbox",
|
||||
"imap://jmr@labyrinth/INBOX",
|
||||
"imap://labryrinth",
|
||||
"imap://labryrinth/",
|
||||
"file:",
|
||||
"file:INBOX",
|
||||
"file:/home/shannon/mail/foo",
|
||||
"/tmp/foo",
|
||||
"//host/tmp/foo",
|
||||
":/tmp/foo",
|
||||
"/really/weird:/tmp/foo#bar",
|
||||
""
|
||||
};
|
||||
|
||||
URLName url =
|
||||
new URLName("protocol", "host", 119, "file", "userid", "password");
|
||||
System.out.println("Test URL: " + url.toString());
|
||||
if (argv.length == 0) {
|
||||
for (int i = 0; i < testURLNames.length; i++) {
|
||||
print(testURLNames[i]);
|
||||
System.out.println();
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < argv.length; i++) {
|
||||
print(argv[i]);
|
||||
System.out.println();
|
||||
}
|
||||
if (argv.length == 2) {
|
||||
URLName u1 = new URLName(argv[0]);
|
||||
URLName u2 = new URLName(argv[1]);
|
||||
System.out.println("URL1 hash code: " + u1.hashCode());
|
||||
System.out.println("URL2 hash code: " + u2.hashCode());
|
||||
if (u1.equals(u2))
|
||||
System.out.println("success, equal");
|
||||
else
|
||||
System.out.println("fail, not equal");
|
||||
if (u2.equals(u1))
|
||||
System.out.println("success, equal");
|
||||
else
|
||||
System.out.println("fail, not equal");
|
||||
if (u1.hashCode() == u2.hashCode())
|
||||
System.out.println("success, hashCodes equal");
|
||||
else
|
||||
System.out.println("fail, hashCodes not equal");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void print(String name) {
|
||||
URLName url = new URLName(name);
|
||||
System.out.println("Original URL: " + name);
|
||||
System.out.println("The fullUrl : " + url.toString());
|
||||
if (!name.equals(url.toString()))
|
||||
System.out.println(" : NOT EQUAL!");
|
||||
System.out.println("The protocol is: " + url.getProtocol());
|
||||
System.out.println("The host is: " + url.getHost());
|
||||
System.out.println("The port is: " + url.getPort());
|
||||
System.out.println("The user is: " + url.getUsername());
|
||||
System.out.println("The password is: " + url.getPassword());
|
||||
System.out.println("The file is: " + url.getFile());
|
||||
System.out.println("The ref is: " + url.getRef());
|
||||
}
|
||||
*/
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
/**
|
||||
* The adapter which receives connection events.
|
||||
* The methods in this class are empty; this class is provided as a
|
||||
* convenience for easily creating listeners by extending this class
|
||||
* and overriding only the methods of interest.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
public abstract class ConnectionAdapter implements ConnectionListener {
|
||||
|
||||
|
||||
/**
|
||||
* Creates a default {@code ConnectionAdapter}.
|
||||
*/
|
||||
public ConnectionAdapter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void opened(ConnectionEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnected(ConnectionEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closed(ConnectionEvent e) {
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
/**
|
||||
* This class models Connection events.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class ConnectionEvent extends MailEvent {
|
||||
|
||||
/**
|
||||
* A connection was opened.
|
||||
*/
|
||||
public static final int OPENED = 1;
|
||||
/**
|
||||
* A connection was disconnected (not currently used).
|
||||
*/
|
||||
public static final int DISCONNECTED = 2;
|
||||
/**
|
||||
* A connection was closed.
|
||||
*/
|
||||
public static final int CLOSED = 3;
|
||||
|
||||
/**
|
||||
* The event type.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected int type;
|
||||
|
||||
/**
|
||||
* Construct a ConnectionEvent.
|
||||
*
|
||||
* @param source The source object
|
||||
* @param type the event type
|
||||
*/
|
||||
public ConnectionEvent(Object source, int type) {
|
||||
super(source);
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of this event
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the appropriate ConnectionListener method
|
||||
*/
|
||||
@Override
|
||||
public void dispatch(Object listener) {
|
||||
if (type == OPENED)
|
||||
((ConnectionListener) listener).opened(this);
|
||||
else if (type == DISCONNECTED)
|
||||
((ConnectionListener) listener).disconnected(this);
|
||||
else if (type == CLOSED)
|
||||
((ConnectionListener) listener).closed(this);
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
/**
|
||||
* This is the Listener interface for Connection events.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
|
||||
public interface ConnectionListener extends java.util.EventListener {
|
||||
|
||||
/**
|
||||
* Invoked when a Store/Folder/Transport is opened.
|
||||
*
|
||||
* @param e the ConnectionEvent
|
||||
*/
|
||||
void opened(ConnectionEvent e);
|
||||
|
||||
/**
|
||||
* Invoked when a Store is disconnected. Note that a folder
|
||||
* cannot be disconnected, so a folder will not fire this event
|
||||
*
|
||||
* @param e the ConnectionEvent
|
||||
*/
|
||||
void disconnected(ConnectionEvent e);
|
||||
|
||||
/**
|
||||
* Invoked when a Store/Folder/Transport is closed.
|
||||
*
|
||||
* @param e the ConnectionEvent
|
||||
*/
|
||||
void closed(ConnectionEvent e);
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
/**
|
||||
* The adapter which receives Folder events.
|
||||
* The methods in this class are empty; this class is provided as a
|
||||
* convenience for easily creating listeners by extending this class
|
||||
* and overriding only the methods of interest.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
public abstract class FolderAdapter implements FolderListener {
|
||||
|
||||
/**
|
||||
* Creates a default {@code FolderAdapter}.
|
||||
*/
|
||||
public FolderAdapter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void folderCreated(FolderEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void folderRenamed(FolderEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void folderDeleted(FolderEvent e) {
|
||||
}
|
||||
}
|
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
import jakarta.mail.Folder;
|
||||
|
||||
/**
|
||||
* This class models Folder <em>existence</em> events. FolderEvents are
|
||||
* delivered to FolderListeners registered on the affected Folder as
|
||||
* well as the containing Store. <p>
|
||||
* <p>
|
||||
* Service providers vary widely in their ability to notify clients of
|
||||
* these events. At a minimum, service providers must notify listeners
|
||||
* registered on the same Store or Folder object on which the operation
|
||||
* occurs. Service providers may also notify listeners when changes
|
||||
* are made through operations on other objects in the same virtual
|
||||
* machine, or by other clients in the same or other hosts. Such
|
||||
* notifications are not required and are typically not supported
|
||||
* by mail protocols (including IMAP).
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Bill Shannon
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class FolderEvent extends MailEvent {
|
||||
|
||||
/**
|
||||
* The folder was created.
|
||||
*/
|
||||
public static final int CREATED = 1;
|
||||
/**
|
||||
* The folder was deleted.
|
||||
*/
|
||||
public static final int DELETED = 2;
|
||||
/**
|
||||
* The folder was renamed.
|
||||
*/
|
||||
public static final int RENAMED = 3;
|
||||
|
||||
/**
|
||||
* The event type.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected int type;
|
||||
|
||||
/**
|
||||
* The folder the event occurred on.
|
||||
*/
|
||||
transient protected Folder folder;
|
||||
|
||||
/**
|
||||
* The folder that represents the new name, in case of a RENAMED event.
|
||||
*
|
||||
* @since JavaMail 1.1
|
||||
*/
|
||||
transient protected Folder newFolder;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param source The source of the event
|
||||
* @param folder The affected folder
|
||||
* @param type The event type
|
||||
*/
|
||||
public FolderEvent(Object source, Folder folder, int type) {
|
||||
this(source, folder, folder, type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. Use for RENAMED events.
|
||||
*
|
||||
* @param source The source of the event
|
||||
* @param oldFolder The folder that is renamed
|
||||
* @param newFolder The folder that represents the new name
|
||||
* @param type The event type
|
||||
* @since JavaMail 1.1
|
||||
*/
|
||||
public FolderEvent(Object source, Folder oldFolder,
|
||||
Folder newFolder, int type) {
|
||||
super(source);
|
||||
this.folder = oldFolder;
|
||||
this.newFolder = newFolder;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of this event.
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the affected folder.
|
||||
*
|
||||
* @return the affected folder
|
||||
* @see #getNewFolder
|
||||
*/
|
||||
public Folder getFolder() {
|
||||
return folder;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this event indicates that a folder is renamed, (i.e, the event type
|
||||
* is RENAMED), then this method returns the Folder object representing the
|
||||
* new name. <p>
|
||||
* <p>
|
||||
* The <code>getFolder()</code> method returns the folder that is renamed.
|
||||
*
|
||||
* @return Folder representing the new name.
|
||||
* @see #getFolder
|
||||
* @since JavaMail 1.1
|
||||
*/
|
||||
public Folder getNewFolder() {
|
||||
return newFolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the appropriate FolderListener method
|
||||
*/
|
||||
@Override
|
||||
public void dispatch(Object listener) {
|
||||
if (type == CREATED)
|
||||
((FolderListener) listener).folderCreated(this);
|
||||
else if (type == DELETED)
|
||||
((FolderListener) listener).folderDeleted(this);
|
||||
else if (type == RENAMED)
|
||||
((FolderListener) listener).folderRenamed(this);
|
||||
}
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
/**
|
||||
* This is the Listener interface for Folder events.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
|
||||
public interface FolderListener extends java.util.EventListener {
|
||||
/**
|
||||
* Invoked when a Folder is created.
|
||||
*
|
||||
* @param e the FolderEvent
|
||||
*/
|
||||
void folderCreated(FolderEvent e);
|
||||
|
||||
/**
|
||||
* Invoked when a folder is deleted.
|
||||
*
|
||||
* @param e the FolderEvent
|
||||
*/
|
||||
void folderDeleted(FolderEvent e);
|
||||
|
||||
/**
|
||||
* Invoked when a folder is renamed.
|
||||
*
|
||||
* @param e the FolderEvent
|
||||
*/
|
||||
void folderRenamed(FolderEvent e);
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
import java.util.EventObject;
|
||||
|
||||
/**
|
||||
* Common base class for mail events, defining the dispatch method.
|
||||
*
|
||||
* @author Bill Shannon
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public abstract class MailEvent extends EventObject {
|
||||
|
||||
/**
|
||||
* Construct a MailEvent referring to the given source.
|
||||
*
|
||||
* @param source the source of the event
|
||||
*/
|
||||
public MailEvent(Object source) {
|
||||
super(source);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method invokes the appropriate method on a listener for
|
||||
* this event. Subclasses provide the implementation.
|
||||
*
|
||||
* @param listener the listener to invoke on
|
||||
*/
|
||||
public abstract void dispatch(Object listener);
|
||||
}
|
|
@ -1,88 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
import jakarta.mail.Message;
|
||||
|
||||
/**
|
||||
* This class models Message change events.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MessageChangedEvent extends MailEvent {
|
||||
|
||||
/**
|
||||
* The message's flags changed.
|
||||
*/
|
||||
public static final int FLAGS_CHANGED = 1;
|
||||
/**
|
||||
* The message's envelope (headers, but not body) changed.
|
||||
*/
|
||||
public static final int ENVELOPE_CHANGED = 2;
|
||||
|
||||
/**
|
||||
* The event type.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected int type;
|
||||
|
||||
/**
|
||||
* The message that changed.
|
||||
*/
|
||||
transient protected Message msg;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param source The folder that owns the message
|
||||
* @param type The change type
|
||||
* @param msg The changed message
|
||||
*/
|
||||
public MessageChangedEvent(Object source, int type, Message msg) {
|
||||
super(source);
|
||||
this.msg = msg;
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of this event.
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public int getMessageChangeType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the changed Message.
|
||||
*
|
||||
* @return the message
|
||||
*/
|
||||
public Message getMessage() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the appropriate MessageChangedListener method.
|
||||
*/
|
||||
@Override
|
||||
public void dispatch(Object listener) {
|
||||
((MessageChangedListener) listener).messageChanged(this);
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
/**
|
||||
* This is the Listener interface for MessageChanged events
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
|
||||
public interface MessageChangedListener extends java.util.EventListener {
|
||||
/**
|
||||
* Invoked when a message is changed. The change-type specifies
|
||||
* what changed.
|
||||
*
|
||||
* @param e the MessageChangedEvent
|
||||
* @see MessageChangedEvent#FLAGS_CHANGED
|
||||
* @see MessageChangedEvent#ENVELOPE_CHANGED
|
||||
*/
|
||||
void messageChanged(MessageChangedEvent e);
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
/**
|
||||
* The adapter which receives MessageCount events.
|
||||
* The methods in this class are empty; this class is provided as a
|
||||
* convenience for easily creating listeners by extending this class
|
||||
* and overriding only the methods of interest.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
public abstract class MessageCountAdapter implements MessageCountListener {
|
||||
|
||||
/**
|
||||
* Creates a default {@code MessageCountAdapter}.
|
||||
*/
|
||||
public MessageCountAdapter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messagesAdded(MessageCountEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messagesRemoved(MessageCountEvent e) {
|
||||
}
|
||||
}
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
import jakarta.mail.Folder;
|
||||
import jakarta.mail.Message;
|
||||
|
||||
/**
|
||||
* This class notifies changes in the number of messages in a folder. <p>
|
||||
* <p>
|
||||
* Note that some folder types may only deliver MessageCountEvents at
|
||||
* certain times or after certain operations. IMAP in particular will
|
||||
* only notify the client of MessageCountEvents when a client issues a
|
||||
* new command. Refer to
|
||||
* <A HREF="http://www.ietf.org/rfc/rfc3501.txt" TARGET="_top">RFC 3501</A>
|
||||
* for details.
|
||||
* A client may want to "poll" the folder by occasionally calling the
|
||||
* {@link Folder#getMessageCount getMessageCount} or
|
||||
* {@link Folder#isOpen isOpen} methods
|
||||
* to solicit any such notifications.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MessageCountEvent extends MailEvent {
|
||||
|
||||
/**
|
||||
* The messages were added to their folder
|
||||
*/
|
||||
public static final int ADDED = 1;
|
||||
/**
|
||||
* The messages were removed from their folder
|
||||
*/
|
||||
public static final int REMOVED = 2;
|
||||
|
||||
/**
|
||||
* The event type.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected int type;
|
||||
|
||||
/**
|
||||
* If true, this event is the result of an explicit
|
||||
* expunge by this client, and the messages in this
|
||||
* folder have been renumbered to account for this.
|
||||
* If false, this event is the result of an expunge
|
||||
* by external sources.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected boolean removed;
|
||||
|
||||
/**
|
||||
* The messages.
|
||||
*/
|
||||
transient protected Message[] msgs;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param folder The containing folder
|
||||
* @param type The event type
|
||||
* @param removed If true, this event is the result of an explicit
|
||||
* expunge by this client, and the messages in this
|
||||
* folder have been renumbered to account for this.
|
||||
* If false, this event is the result of an expunge
|
||||
* by external sources.
|
||||
* @param msgs The messages added/removed
|
||||
*/
|
||||
public MessageCountEvent(Folder folder, int type,
|
||||
boolean removed, Message[] msgs) {
|
||||
super(folder);
|
||||
this.type = type;
|
||||
this.removed = removed;
|
||||
this.msgs = msgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of this event.
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this event is the result of an explicit
|
||||
* expunge by this client, or due to an expunge from external
|
||||
* sources. If <code>true</code>, this event is due to an
|
||||
* explicit expunge and hence all remaining messages in this
|
||||
* folder have been renumbered. If <code>false</code>, this event
|
||||
* is due to an external expunge. <p>
|
||||
* <p>
|
||||
* Note that this method is valid only if the type of this event
|
||||
* is <code>REMOVED</code>
|
||||
*
|
||||
* @return true if the message has been removed
|
||||
*/
|
||||
public boolean isRemoved() {
|
||||
return removed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the array of messages added or removed.
|
||||
*
|
||||
* @return array of messages
|
||||
*/
|
||||
public Message[] getMessages() {
|
||||
return msgs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the appropriate MessageCountListener method.
|
||||
*/
|
||||
@Override
|
||||
public void dispatch(Object listener) {
|
||||
if (type == ADDED)
|
||||
((MessageCountListener) listener).messagesAdded(this);
|
||||
else // REMOVED
|
||||
((MessageCountListener) listener).messagesRemoved(this);
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
/**
|
||||
* This is the Listener interface for MessageCount events.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
|
||||
public interface MessageCountListener extends java.util.EventListener {
|
||||
/**
|
||||
* Invoked when messages are added into a folder.
|
||||
*
|
||||
* @param e the MessageCountEvent
|
||||
*/
|
||||
void messagesAdded(MessageCountEvent e);
|
||||
|
||||
/**
|
||||
* Invoked when messages are removed (expunged) from a folder.
|
||||
*
|
||||
* @param e the MessageCountEvent
|
||||
*/
|
||||
void messagesRemoved(MessageCountEvent e);
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
import jakarta.mail.Store;
|
||||
|
||||
/**
|
||||
* This class models notifications from the Store connection. These
|
||||
* notifications can be ALERTS or NOTICES. ALERTS must be presented
|
||||
* to the user in a fashion that calls the user's attention to the
|
||||
* message.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class StoreEvent extends MailEvent {
|
||||
|
||||
/**
|
||||
* Indicates that this message is an ALERT.
|
||||
*/
|
||||
public static final int ALERT = 1;
|
||||
|
||||
/**
|
||||
* Indicates that this message is a NOTICE.
|
||||
*/
|
||||
public static final int NOTICE = 2;
|
||||
|
||||
/**
|
||||
* The event type.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected int type;
|
||||
|
||||
/**
|
||||
* The message text to be presented to the user.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected String message;
|
||||
|
||||
/**
|
||||
* Construct a StoreEvent.
|
||||
*
|
||||
* @param store the source Store
|
||||
* @param type the event type
|
||||
* @param message a message assoicated with the event
|
||||
*/
|
||||
public StoreEvent(Store store, int type, String message) {
|
||||
super(store);
|
||||
this.type = type;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of this event.
|
||||
*
|
||||
* @return type
|
||||
* @see #ALERT
|
||||
* @see #NOTICE
|
||||
*/
|
||||
public int getMessageType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the message from the Store.
|
||||
*
|
||||
* @return message from the Store
|
||||
*/
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the appropriate StoreListener method.
|
||||
*/
|
||||
@Override
|
||||
public void dispatch(Object listener) {
|
||||
((StoreListener) listener).notification(this);
|
||||
}
|
||||
}
|
|
@ -1,35 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
/**
|
||||
* This is the Listener interface for Store Notifications.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
|
||||
public interface StoreListener extends java.util.EventListener {
|
||||
|
||||
/**
|
||||
* Invoked when the Store generates a notification event.
|
||||
*
|
||||
* @param e the StoreEvent
|
||||
* @see StoreEvent#ALERT
|
||||
* @see StoreEvent#NOTICE
|
||||
*/
|
||||
void notification(StoreEvent e);
|
||||
}
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
/**
|
||||
* The adapter which receives Transport events.
|
||||
* The methods in this class are empty; this class is provided as a
|
||||
* convenience for easily creating listeners by extending this class
|
||||
* and overriding only the methods of interest.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
public abstract class TransportAdapter implements TransportListener {
|
||||
|
||||
/**
|
||||
* Creates a default {@code TransportAdapter}.
|
||||
*/
|
||||
public TransportAdapter() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageDelivered(TransportEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messageNotDelivered(TransportEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void messagePartiallyDelivered(TransportEvent e) {
|
||||
}
|
||||
}
|
|
@ -1,164 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
import jakarta.mail.Address;
|
||||
import jakarta.mail.Message;
|
||||
import jakarta.mail.Transport;
|
||||
|
||||
/**
|
||||
* This class models Transport events.
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Max Spivak
|
||||
* @see Transport
|
||||
* @see TransportListener
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class TransportEvent extends MailEvent {
|
||||
|
||||
/**
|
||||
* Message has been successfully delivered to all recipients by the
|
||||
* transport firing this event. validSent[] contains all the addresses
|
||||
* this transport sent to successfully. validUnsent[] and invalid[]
|
||||
* should be null,
|
||||
*/
|
||||
public static final int MESSAGE_DELIVERED = 1;
|
||||
|
||||
/**
|
||||
* Message was not sent for some reason. validSent[] should be null.
|
||||
* validUnsent[] may have addresses that are valid (but the message
|
||||
* wasn't sent to them). invalid[] should likely contain invalid addresses.
|
||||
*/
|
||||
public static final int MESSAGE_NOT_DELIVERED = 2;
|
||||
|
||||
/**
|
||||
* Message was successfully sent to some recipients but not to all.
|
||||
* validSent[] holds addresses of recipients to whom the message was sent.
|
||||
* validUnsent[] holds valid addresses to which the message was not sent.
|
||||
* invalid[] holds invalid addresses, if any.
|
||||
*/
|
||||
public static final int MESSAGE_PARTIALLY_DELIVERED = 3;
|
||||
|
||||
|
||||
/**
|
||||
* The event type.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected int type;
|
||||
|
||||
/**
|
||||
* The valid address to which the message was sent.
|
||||
*/
|
||||
transient protected Address[] validSent;
|
||||
/**
|
||||
* The valid address to which the message was not sent.
|
||||
*/
|
||||
transient protected Address[] validUnsent;
|
||||
/**
|
||||
* The invalid addresses.
|
||||
*/
|
||||
transient protected Address[] invalid;
|
||||
/**
|
||||
* The Message to which this event applies.
|
||||
*/
|
||||
transient protected Message msg;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param transport The Transport object
|
||||
* @param type the event type (MESSAGE_DELIVERED, etc.)
|
||||
* @param validSent the valid addresses to which the message was sent
|
||||
* @param validUnsent the valid addresses to which the message was
|
||||
* not sent
|
||||
* @param invalid the invalid addresses
|
||||
* @param msg the message being sent
|
||||
*/
|
||||
public TransportEvent(Transport transport, int type, Address[] validSent,
|
||||
Address[] validUnsent, Address[] invalid,
|
||||
Message msg) {
|
||||
super(transport);
|
||||
this.type = type;
|
||||
this.validSent = validSent;
|
||||
this.validUnsent = validUnsent;
|
||||
this.invalid = invalid;
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of this event.
|
||||
*
|
||||
* @return type
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the addresses to which this message was sent succesfully.
|
||||
*
|
||||
* @return Addresses to which the message was sent successfully or null
|
||||
*/
|
||||
public Address[] getValidSentAddresses() {
|
||||
return validSent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the addresses that are valid but to which this message
|
||||
* was not sent.
|
||||
*
|
||||
* @return Addresses that are valid but to which the message was
|
||||
* not sent successfully or null
|
||||
*/
|
||||
public Address[] getValidUnsentAddresses() {
|
||||
return validUnsent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the addresses to which this message could not be sent.
|
||||
*
|
||||
* @return Addresses to which the message sending failed or null
|
||||
*/
|
||||
public Address[] getInvalidAddresses() {
|
||||
return invalid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Message object associated with this Transport Event.
|
||||
*
|
||||
* @return the Message object
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public Message getMessage() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the appropriate TransportListener method.
|
||||
*/
|
||||
@Override
|
||||
public void dispatch(Object listener) {
|
||||
if (type == MESSAGE_DELIVERED)
|
||||
((TransportListener) listener).messageDelivered(this);
|
||||
else if (type == MESSAGE_NOT_DELIVERED)
|
||||
((TransportListener) listener).messageNotDelivered(this);
|
||||
else // MESSAGE_PARTIALLY_DELIVERED
|
||||
((TransportListener) listener).messagePartiallyDelivered(this);
|
||||
}
|
||||
}
|
|
@ -1,52 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.event;
|
||||
|
||||
/**
|
||||
* This is the Listener interface for Transport events
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Max Spivak
|
||||
* @see jakarta.mail.Transport
|
||||
* @see TransportEvent
|
||||
*/
|
||||
|
||||
public interface TransportListener extends java.util.EventListener {
|
||||
|
||||
/**
|
||||
* Invoked when a Message is succesfully delivered.
|
||||
*
|
||||
* @param e TransportEvent
|
||||
*/
|
||||
void messageDelivered(TransportEvent e);
|
||||
|
||||
/**
|
||||
* Invoked when a Message is not delivered.
|
||||
*
|
||||
* @param e TransportEvent
|
||||
* @see TransportEvent
|
||||
*/
|
||||
void messageNotDelivered(TransportEvent e);
|
||||
|
||||
/**
|
||||
* Invoked when a Message is partially delivered.
|
||||
*
|
||||
* @param e TransportEvent
|
||||
* @see TransportEvent
|
||||
*/
|
||||
void messagePartiallyDelivered(TransportEvent e);
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Listeners and events for the Jakarta Mail API.
|
||||
* This package defines listener classes and event classes used by the classes
|
||||
* defined in the <code>jakarta.mail</code> package.
|
||||
*/
|
||||
package jakarta.mail.event;
|
|
@ -1,113 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.internet;
|
||||
|
||||
/**
|
||||
* The exception thrown when a wrongly formatted address is encountered.
|
||||
*
|
||||
* @author Bill Shannon
|
||||
* @author Max Spivak
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class AddressException extends ParseException {
|
||||
/**
|
||||
* The string being parsed.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected String ref = null;
|
||||
|
||||
/**
|
||||
* The index in the string where the error occurred, or -1 if not known.
|
||||
*
|
||||
* @serial
|
||||
*/
|
||||
protected int pos = -1;
|
||||
|
||||
/**
|
||||
* Constructs an AddressException with no detail message.
|
||||
*/
|
||||
public AddressException() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an AddressException with the specified detail message.
|
||||
*
|
||||
* @param s the detail message
|
||||
*/
|
||||
public AddressException(String s) {
|
||||
super(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an AddressException with the specified detail message
|
||||
* and reference info.
|
||||
*
|
||||
* @param s the detail message
|
||||
* @param ref the string being parsed
|
||||
*/
|
||||
public AddressException(String s, String ref) {
|
||||
super(s);
|
||||
this.ref = ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs an AddressException with the specified detail message
|
||||
* and reference info.
|
||||
*
|
||||
* @param s the detail message
|
||||
* @param ref the string being parsed
|
||||
* @param pos the position of the error
|
||||
*/
|
||||
public AddressException(String s, String ref, int pos) {
|
||||
super(s);
|
||||
this.ref = ref;
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the string that was being parsed when the error was detected
|
||||
* (null if not relevant).
|
||||
*
|
||||
* @return the string that was being parsed
|
||||
*/
|
||||
public String getRef() {
|
||||
return ref;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the position with the reference string where the error was
|
||||
* detected (-1 if not relevant).
|
||||
*
|
||||
* @return the position within the string of the error
|
||||
*/
|
||||
public int getPos() {
|
||||
return pos;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String s = super.toString();
|
||||
if (ref == null)
|
||||
return s;
|
||||
s += " in string ``" + ref + "''";
|
||||
if (pos < 0)
|
||||
return s;
|
||||
return s + " at position " + pos;
|
||||
}
|
||||
}
|
|
@ -1,185 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.internet;
|
||||
|
||||
/**
|
||||
* This class represents a MIME ContentDisposition value. It provides
|
||||
* methods to parse a ContentDisposition string into individual components
|
||||
* and to generate a MIME style ContentDisposition string.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
|
||||
public class ContentDisposition {
|
||||
|
||||
private static final boolean contentDispositionStrict =
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.contentdisposition.strict", true);
|
||||
|
||||
private String disposition; // disposition
|
||||
private ParameterList list; // parameter list
|
||||
|
||||
/**
|
||||
* No-arg Constructor.
|
||||
*/
|
||||
public ContentDisposition() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param disposition disposition
|
||||
* @param list ParameterList
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public ContentDisposition(String disposition, ParameterList list) {
|
||||
this.disposition = disposition;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes a ContentDisposition string. The String
|
||||
* is parsed into its constituents: dispostion and parameters.
|
||||
* A ParseException is thrown if the parse fails.
|
||||
*
|
||||
* @param s the ContentDisposition string.
|
||||
* @throws ParseException if the parse fails.
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public ContentDisposition(String s) throws ParseException {
|
||||
HeaderTokenizer h = new HeaderTokenizer(s, HeaderTokenizer.MIME);
|
||||
HeaderTokenizer.Token tk;
|
||||
|
||||
// First "disposition" ..
|
||||
tk = h.next();
|
||||
if (tk.getType() != HeaderTokenizer.Token.ATOM) {
|
||||
if (contentDispositionStrict) {
|
||||
throw new ParseException("Expected disposition, got " +
|
||||
tk.getValue());
|
||||
}
|
||||
} else {
|
||||
disposition = tk.getValue();
|
||||
}
|
||||
|
||||
// Then parameters ..
|
||||
String rem = h.getRemainder();
|
||||
if (rem != null) {
|
||||
try {
|
||||
list = new ParameterList(rem);
|
||||
} catch (ParseException px) {
|
||||
if (contentDispositionStrict) {
|
||||
throw px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the disposition value.
|
||||
*
|
||||
* @return the disposition
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public String getDisposition() {
|
||||
return disposition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the disposition. Replaces the existing disposition.
|
||||
*
|
||||
* @param disposition the disposition
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public void setDisposition(String disposition) {
|
||||
this.disposition = disposition;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the specified parameter value. Returns <code>null</code>
|
||||
* if this parameter is absent.
|
||||
*
|
||||
* @param name the parameter name
|
||||
* @return parameter value
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public String getParameter(String name) {
|
||||
if (list == null)
|
||||
return null;
|
||||
|
||||
return list.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a ParameterList object that holds all the available
|
||||
* parameters. Returns null if no parameters are available.
|
||||
*
|
||||
* @return ParameterList
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public ParameterList getParameterList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new ParameterList.
|
||||
*
|
||||
* @param list ParameterList
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public void setParameterList(ParameterList list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the specified parameter. If this parameter already exists,
|
||||
* it is replaced by this new value.
|
||||
*
|
||||
* @param name parameter name
|
||||
* @param value parameter value
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
public void setParameter(String name, String value) {
|
||||
if (list == null)
|
||||
list = new ParameterList();
|
||||
|
||||
list.set(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a RFC2045 style string representation of
|
||||
* this ContentDisposition. Returns an empty string if
|
||||
* the conversion failed.
|
||||
*
|
||||
* @return RFC2045 style string
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if (disposition == null)
|
||||
return "";
|
||||
|
||||
if (list == null)
|
||||
return disposition;
|
||||
|
||||
StringBuilder sb = new StringBuilder(disposition);
|
||||
|
||||
// append the parameter list
|
||||
// use the length of the string buffer + the length of
|
||||
// the header name formatted as follows "Content-Disposition: "
|
||||
sb.append(list.toString(sb.length() + 21));
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -1,276 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.internet;
|
||||
|
||||
/**
|
||||
* This class represents a MIME Content-Type value. It provides
|
||||
* methods to parse a Content-Type string into individual components
|
||||
* and to generate a MIME style Content-Type string.
|
||||
*
|
||||
* @author John Mani
|
||||
*/
|
||||
|
||||
public class ContentType {
|
||||
|
||||
private String primaryType; // primary type
|
||||
private String subType; // subtype
|
||||
private ParameterList list; // parameter list
|
||||
|
||||
/**
|
||||
* No-arg Constructor.
|
||||
*/
|
||||
public ContentType() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param primaryType primary type
|
||||
* @param subType subType
|
||||
* @param list ParameterList
|
||||
*/
|
||||
public ContentType(String primaryType, String subType,
|
||||
ParameterList list) {
|
||||
this.primaryType = primaryType;
|
||||
this.subType = subType;
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes a Content-Type string. The String
|
||||
* is parsed into its constituents: primaryType, subType
|
||||
* and parameters. A ParseException is thrown if the parse fails.
|
||||
*
|
||||
* @param s the Content-Type string.
|
||||
* @throws ParseException if the parse fails.
|
||||
*/
|
||||
public ContentType(String s) throws ParseException {
|
||||
HeaderTokenizer h = new HeaderTokenizer(s, HeaderTokenizer.MIME);
|
||||
HeaderTokenizer.Token tk;
|
||||
|
||||
// First "type" ..
|
||||
tk = h.next();
|
||||
if (tk.getType() != HeaderTokenizer.Token.ATOM)
|
||||
throw new ParseException("In Content-Type string <" + s + ">" +
|
||||
", expected MIME type, got " +
|
||||
tk.getValue());
|
||||
primaryType = tk.getValue();
|
||||
|
||||
// The '/' separator ..
|
||||
tk = h.next();
|
||||
if ((char) tk.getType() != '/')
|
||||
throw new ParseException("In Content-Type string <" + s + ">" +
|
||||
", expected '/', got " + tk.getValue());
|
||||
|
||||
// Then "subType" ..
|
||||
tk = h.next();
|
||||
if (tk.getType() != HeaderTokenizer.Token.ATOM)
|
||||
throw new ParseException("In Content-Type string <" + s + ">" +
|
||||
", expected MIME subtype, got " +
|
||||
tk.getValue());
|
||||
subType = tk.getValue();
|
||||
|
||||
// Finally parameters ..
|
||||
String rem = h.getRemainder();
|
||||
if (rem != null)
|
||||
list = new ParameterList(rem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the primary type.
|
||||
*
|
||||
* @return the primary type
|
||||
*/
|
||||
public String getPrimaryType() {
|
||||
return primaryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the primary type. Overrides existing primary type.
|
||||
*
|
||||
* @param primaryType primary type
|
||||
*/
|
||||
public void setPrimaryType(String primaryType) {
|
||||
this.primaryType = primaryType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the subType.
|
||||
*
|
||||
* @return the subType
|
||||
*/
|
||||
public String getSubType() {
|
||||
return subType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the subType. Replaces the existing subType.
|
||||
*
|
||||
* @param subType the subType
|
||||
*/
|
||||
public void setSubType(String subType) {
|
||||
this.subType = subType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the MIME type string, without the parameters.
|
||||
* The returned value is basically the concatenation of
|
||||
* the primaryType, the '/' character and the secondaryType.
|
||||
*
|
||||
* @return the type
|
||||
*/
|
||||
public String getBaseType() {
|
||||
if (primaryType == null || subType == null)
|
||||
return "";
|
||||
return primaryType + '/' + subType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the specified parameter value. Returns <code>null</code>
|
||||
* if this parameter is absent.
|
||||
*
|
||||
* @param name the parameter name
|
||||
* @return parameter value
|
||||
*/
|
||||
public String getParameter(String name) {
|
||||
if (list == null)
|
||||
return null;
|
||||
|
||||
return list.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a ParameterList object that holds all the available
|
||||
* parameters. Returns null if no parameters are available.
|
||||
*
|
||||
* @return ParameterList
|
||||
*/
|
||||
public ParameterList getParameterList() {
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a new ParameterList.
|
||||
*
|
||||
* @param list ParameterList
|
||||
*/
|
||||
public void setParameterList(ParameterList list) {
|
||||
this.list = list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the specified parameter. If this parameter already exists,
|
||||
* it is replaced by this new value.
|
||||
*
|
||||
* @param name parameter name
|
||||
* @param value parameter value
|
||||
*/
|
||||
public void setParameter(String name, String value) {
|
||||
if (list == null)
|
||||
list = new ParameterList();
|
||||
|
||||
list.set(name, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a RFC2045 style string representation of
|
||||
* this Content-Type. Returns an empty string if
|
||||
* the conversion failed.
|
||||
*
|
||||
* @return RFC2045 style string
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
if (primaryType == null || subType == null) // need both
|
||||
return "";
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(primaryType).append('/').append(subType);
|
||||
if (list != null)
|
||||
// append the parameter list
|
||||
// use the length of the string buffer + the length of
|
||||
// the header name formatted as follows "Content-Type: "
|
||||
sb.append(list.toString(sb.length() + 14));
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Match with the specified ContentType object. This method
|
||||
* compares <strong>only the <code>primaryType</code> and
|
||||
* <code>subType</code> </strong>. The parameters of both operands
|
||||
* are ignored. <p>
|
||||
* <p>
|
||||
* For example, this method will return <code>true</code> when
|
||||
* comparing the ContentTypes for <strong>"text/plain"</strong>
|
||||
* and <strong>"text/plain; charset=foobar"</strong>.
|
||||
* <p>
|
||||
* If the <code>subType</code> of either operand is the special
|
||||
* character '*', then the subtype is ignored during the match.
|
||||
* For example, this method will return <code>true</code> when
|
||||
* comparing the ContentTypes for <strong>"text/plain"</strong>
|
||||
* and <strong>"text/*" </strong>
|
||||
*
|
||||
* @param cType ContentType to compare this against
|
||||
* @return true if it matches
|
||||
*/
|
||||
public boolean match(ContentType cType) {
|
||||
// Match primaryType
|
||||
if (!((primaryType == null && cType.getPrimaryType() == null) ||
|
||||
(primaryType != null &&
|
||||
primaryType.equalsIgnoreCase(cType.getPrimaryType()))))
|
||||
return false;
|
||||
|
||||
String sType = cType.getSubType();
|
||||
|
||||
// If either one of the subTypes is wildcarded, return true
|
||||
if ((subType != null && subType.startsWith("*")) ||
|
||||
(sType != null && sType.startsWith("*")))
|
||||
return true;
|
||||
|
||||
// Match subType
|
||||
return (subType == null && sType == null) ||
|
||||
(subType != null && subType.equalsIgnoreCase(sType));
|
||||
}
|
||||
|
||||
/**
|
||||
* Match with the specified content-type string. This method
|
||||
* compares <strong>only the <code>primaryType</code> and
|
||||
* <code>subType</code> </strong>.
|
||||
* The parameters of both operands are ignored. <p>
|
||||
* <p>
|
||||
* For example, this method will return <code>true</code> when
|
||||
* comparing the ContentType for <strong>"text/plain"</strong>
|
||||
* with <strong>"text/plain; charset=foobar"</strong>.
|
||||
* <p>
|
||||
* If the <code>subType</code> of either operand is the special
|
||||
* character '*', then the subtype is ignored during the match.
|
||||
* For example, this method will return <code>true</code> when
|
||||
* comparing the ContentType for <strong>"text/plain"</strong>
|
||||
* with <strong>"text/*" </strong>
|
||||
*
|
||||
* @param s the content-type string to match
|
||||
* @return true if it matches
|
||||
*/
|
||||
public boolean match(String s) {
|
||||
try {
|
||||
return match(new ContentType(s));
|
||||
} catch (ParseException pex) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,463 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.internet;
|
||||
|
||||
/**
|
||||
* This class tokenizes RFC822 and MIME headers into the basic
|
||||
* symbols specified by RFC822 and MIME. <p>
|
||||
* <p>
|
||||
* This class handles folded headers (ie headers with embedded
|
||||
* CRLF SPACE sequences). The folds are removed in the returned
|
||||
* tokens.
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Bill Shannon
|
||||
*/
|
||||
|
||||
public class HeaderTokenizer {
|
||||
|
||||
/**
|
||||
* RFC822 specials
|
||||
*/
|
||||
public final static String RFC822 = "()<>@,;:\\\"\t .[]";
|
||||
/**
|
||||
* MIME specials
|
||||
*/
|
||||
public final static String MIME = "()<>@,;:\\\"\t []/?=";
|
||||
// The EOF Token
|
||||
private final static Token EOFToken = new Token(Token.EOF, null);
|
||||
private String string; // the string to be tokenized
|
||||
private boolean skipComments; // should comments be skipped ?
|
||||
private String delimiters; // delimiter string
|
||||
private int currentPos; // current parse position
|
||||
private int maxPos; // string length
|
||||
private int nextPos; // track start of next Token for next()
|
||||
private int peekPos; // track start of next Token for peek()
|
||||
|
||||
/**
|
||||
* Constructor that takes a rfc822 style header.
|
||||
*
|
||||
* @param skipComments If true, comments are skipped and
|
||||
* not returned as tokens
|
||||
* @param header The rfc822 header to be tokenized
|
||||
* @param delimiters Set of delimiter characters
|
||||
* to be used to delimit ATOMS. These
|
||||
* are usually <code>RFC822</code> or
|
||||
* <code>MIME</code>
|
||||
*/
|
||||
public HeaderTokenizer(String header, String delimiters,
|
||||
boolean skipComments) {
|
||||
string = (header == null) ? "" : header; // paranoia ?!
|
||||
this.skipComments = skipComments;
|
||||
this.delimiters = delimiters;
|
||||
currentPos = nextPos = peekPos = 0;
|
||||
maxPos = string.length();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. Comments are ignored and not returned as tokens
|
||||
*
|
||||
* @param header The header that is tokenized
|
||||
* @param delimiters The delimiters to be used
|
||||
*/
|
||||
public HeaderTokenizer(String header, String delimiters) {
|
||||
this(header, delimiters, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor. The RFC822 defined delimiters - RFC822 - are
|
||||
* used to delimit ATOMS. Also comments are skipped and not
|
||||
* returned as tokens
|
||||
*
|
||||
* @param header the header string
|
||||
*/
|
||||
public HeaderTokenizer(String header) {
|
||||
this(header, RFC822);
|
||||
}
|
||||
|
||||
// Trim SPACE, HT, CR and NL from end of string
|
||||
private static String trimWhiteSpace(String s) {
|
||||
char c;
|
||||
int i;
|
||||
for (i = s.length() - 1; i >= 0; i--) {
|
||||
if (((c = s.charAt(i)) != ' ') &&
|
||||
(c != '\t') && (c != '\r') && (c != '\n'))
|
||||
break;
|
||||
}
|
||||
if (i <= 0)
|
||||
return "";
|
||||
else
|
||||
return s.substring(0, i + 1);
|
||||
}
|
||||
|
||||
/* Process escape sequences and embedded LWSPs from a comment or
|
||||
* quoted string.
|
||||
*/
|
||||
private static String filterToken(String s, int start, int end,
|
||||
boolean keepEscapes) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
char c;
|
||||
boolean gotEscape = false;
|
||||
boolean gotCR = false;
|
||||
|
||||
for (int i = start; i < end; i++) {
|
||||
c = s.charAt(i);
|
||||
if (c == '\n' && gotCR) {
|
||||
// This LF is part of an unescaped
|
||||
// CRLF sequence (i.e, LWSP). Skip it.
|
||||
gotCR = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
gotCR = false;
|
||||
if (!gotEscape) {
|
||||
// Previous character was NOT '\'
|
||||
if (c == '\\') // skip this character
|
||||
gotEscape = true;
|
||||
else if (c == '\r') // skip this character
|
||||
gotCR = true;
|
||||
else // append this character
|
||||
sb.append(c);
|
||||
} else {
|
||||
// Previous character was '\'. So no need to
|
||||
// bother with any special processing, just
|
||||
// append this character. If keepEscapes is
|
||||
// set, keep the backslash. IE6 fails to escape
|
||||
// backslashes in quoted strings in HTTP headers,
|
||||
// e.g., in the filename parameter.
|
||||
if (keepEscapes)
|
||||
sb.append('\\');
|
||||
sb.append(c);
|
||||
gotEscape = false;
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the next token from this String. <p>
|
||||
* <p>
|
||||
* Clients sit in a loop calling next() to parse successive
|
||||
* tokens until an EOF Token is returned.
|
||||
*
|
||||
* @return the next Token
|
||||
* @throws ParseException if the parse fails
|
||||
*/
|
||||
public Token next() throws ParseException {
|
||||
return next('\0', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the next token from this String.
|
||||
* If endOfAtom is not NUL, the token extends until the
|
||||
* endOfAtom character is seen, or to the end of the header.
|
||||
* This method is useful when parsing headers that don't
|
||||
* obey the MIME specification, e.g., by failing to quote
|
||||
* parameter values that contain spaces.
|
||||
*
|
||||
* @param endOfAtom if not NUL, character marking end of token
|
||||
* @return the next Token
|
||||
* @throws ParseException if the parse fails
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public Token next(char endOfAtom) throws ParseException {
|
||||
return next(endOfAtom, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the next token from this String.
|
||||
* endOfAtom is handled as above. If keepEscapes is true,
|
||||
* any backslash escapes are preserved in the returned string.
|
||||
* This method is useful when parsing headers that don't
|
||||
* obey the MIME specification, e.g., by failing to escape
|
||||
* backslashes in the filename parameter.
|
||||
*
|
||||
* @param endOfAtom if not NUL, character marking end of token
|
||||
* @param keepEscapes keep all backslashes in returned string?
|
||||
* @return the next Token
|
||||
* @throws ParseException if the parse fails
|
||||
* @since JavaMail 1.5
|
||||
*/
|
||||
public Token next(char endOfAtom, boolean keepEscapes)
|
||||
throws ParseException {
|
||||
Token tk;
|
||||
|
||||
currentPos = nextPos; // setup currentPos
|
||||
tk = getNext(endOfAtom, keepEscapes);
|
||||
nextPos = peekPos = currentPos; // update currentPos and peekPos
|
||||
return tk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Peek at the next token, without actually removing the token
|
||||
* from the parse stream. Invoking this method multiple times
|
||||
* will return successive tokens, until <code>next()</code> is
|
||||
* called.
|
||||
*
|
||||
* @return the next Token
|
||||
* @throws ParseException if the parse fails
|
||||
*/
|
||||
public Token peek() throws ParseException {
|
||||
Token tk;
|
||||
|
||||
currentPos = peekPos; // setup currentPos
|
||||
tk = getNext('\0', false);
|
||||
peekPos = currentPos; // update peekPos
|
||||
return tk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the rest of the Header.
|
||||
*
|
||||
* @return String rest of header. null is returned if we are
|
||||
* already at end of header
|
||||
*/
|
||||
public String getRemainder() {
|
||||
if (nextPos >= string.length())
|
||||
return null;
|
||||
return string.substring(nextPos);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next token starting from 'currentPos'. After the
|
||||
* parse, 'currentPos' is updated to point to the start of the
|
||||
* next token.
|
||||
*/
|
||||
private Token getNext(char endOfAtom, boolean keepEscapes)
|
||||
throws ParseException {
|
||||
// If we're already at end of string, return EOF
|
||||
if (currentPos >= maxPos)
|
||||
return EOFToken;
|
||||
|
||||
// Skip white-space, position currentPos beyond the space
|
||||
if (skipWhiteSpace() == Token.EOF)
|
||||
return EOFToken;
|
||||
|
||||
char c;
|
||||
int start;
|
||||
boolean filter = false;
|
||||
|
||||
c = string.charAt(currentPos);
|
||||
|
||||
// Check or Skip comments and position currentPos
|
||||
// beyond the comment
|
||||
while (c == '(') {
|
||||
// Parsing comment ..
|
||||
int nesting;
|
||||
for (start = ++currentPos, nesting = 1;
|
||||
nesting > 0 && currentPos < maxPos;
|
||||
currentPos++) {
|
||||
c = string.charAt(currentPos);
|
||||
if (c == '\\') { // Escape sequence
|
||||
currentPos++; // skip the escaped character
|
||||
filter = true;
|
||||
} else if (c == '\r')
|
||||
filter = true;
|
||||
else if (c == '(')
|
||||
nesting++;
|
||||
else if (c == ')')
|
||||
nesting--;
|
||||
}
|
||||
if (nesting != 0)
|
||||
throw new ParseException("Unbalanced comments");
|
||||
|
||||
if (!skipComments) {
|
||||
// Return the comment, if we are asked to.
|
||||
// Note that the comment start & end markers are ignored.
|
||||
String s;
|
||||
if (filter) // need to go thru the token again.
|
||||
s = filterToken(string, start, currentPos - 1, keepEscapes);
|
||||
else
|
||||
s = string.substring(start, currentPos - 1);
|
||||
|
||||
return new Token(Token.COMMENT, s);
|
||||
}
|
||||
|
||||
// Skip any whitespace after the comment.
|
||||
if (skipWhiteSpace() == Token.EOF)
|
||||
return EOFToken;
|
||||
c = string.charAt(currentPos);
|
||||
}
|
||||
|
||||
// Check for quoted-string and position currentPos
|
||||
// beyond the terminating quote
|
||||
if (c == '"') {
|
||||
currentPos++; // skip initial quote
|
||||
return collectString('"', keepEscapes);
|
||||
}
|
||||
|
||||
// Check for SPECIAL or CTL
|
||||
if (c < 040 || c >= 0177 || delimiters.indexOf(c) >= 0) {
|
||||
if (endOfAtom > 0 && c != endOfAtom) {
|
||||
// not expecting a special character here,
|
||||
// pretend it's a quoted string
|
||||
return collectString(endOfAtom, keepEscapes);
|
||||
}
|
||||
currentPos++; // re-position currentPos
|
||||
char[] ch = new char[1];
|
||||
ch[0] = c;
|
||||
return new Token(c, new String(ch));
|
||||
}
|
||||
|
||||
// Check for ATOM
|
||||
for (start = currentPos; currentPos < maxPos; currentPos++) {
|
||||
c = string.charAt(currentPos);
|
||||
// ATOM is delimited by either SPACE, CTL, "(", <">
|
||||
// or the specified SPECIALS
|
||||
if (c < 040 || c >= 0177 || c == '(' || c == ' ' ||
|
||||
c == '"' || delimiters.indexOf(c) >= 0) {
|
||||
if (endOfAtom > 0 && c != endOfAtom) {
|
||||
// not the expected atom after all;
|
||||
// back up and pretend it's a quoted string
|
||||
currentPos = start;
|
||||
return collectString(endOfAtom, keepEscapes);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return new Token(Token.ATOM, string.substring(start, currentPos));
|
||||
}
|
||||
|
||||
private Token collectString(char eos, boolean keepEscapes)
|
||||
throws ParseException {
|
||||
int start;
|
||||
boolean filter = false;
|
||||
for (start = currentPos; currentPos < maxPos; currentPos++) {
|
||||
char c = string.charAt(currentPos);
|
||||
if (c == '\\') { // Escape sequence
|
||||
currentPos++;
|
||||
filter = true;
|
||||
} else if (c == '\r')
|
||||
filter = true;
|
||||
else if (c == eos) {
|
||||
currentPos++;
|
||||
String s;
|
||||
|
||||
if (filter)
|
||||
s = filterToken(string, start, currentPos - 1, keepEscapes);
|
||||
else
|
||||
s = string.substring(start, currentPos - 1);
|
||||
|
||||
if (c != '"') { // not a real quoted string
|
||||
s = trimWhiteSpace(s);
|
||||
currentPos--; // back up before the eos char
|
||||
}
|
||||
|
||||
return new Token(Token.QUOTEDSTRING, s);
|
||||
}
|
||||
}
|
||||
|
||||
// ran off the end of the string
|
||||
|
||||
// if we're looking for a matching quote, that's an error
|
||||
if (eos == '"')
|
||||
throw new ParseException("Unbalanced quoted string");
|
||||
|
||||
// otherwise, just return whatever's left
|
||||
String s;
|
||||
if (filter)
|
||||
s = filterToken(string, start, currentPos, keepEscapes);
|
||||
else
|
||||
s = string.substring(start, currentPos);
|
||||
s = trimWhiteSpace(s);
|
||||
return new Token(Token.QUOTEDSTRING, s);
|
||||
}
|
||||
|
||||
// Skip SPACE, HT, CR and NL
|
||||
private int skipWhiteSpace() {
|
||||
char c;
|
||||
for (; currentPos < maxPos; currentPos++)
|
||||
if (((c = string.charAt(currentPos)) != ' ') &&
|
||||
(c != '\t') && (c != '\r') && (c != '\n'))
|
||||
return currentPos;
|
||||
return Token.EOF;
|
||||
}
|
||||
|
||||
/**
|
||||
* The Token class represents tokens returned by the
|
||||
* HeaderTokenizer.
|
||||
*/
|
||||
public static class Token {
|
||||
|
||||
/**
|
||||
* Token type indicating an ATOM.
|
||||
*/
|
||||
public static final int ATOM = -1;
|
||||
/**
|
||||
* Token type indicating a quoted string. The value
|
||||
* field contains the string without the quotes.
|
||||
*/
|
||||
public static final int QUOTEDSTRING = -2;
|
||||
/**
|
||||
* Token type indicating a comment. The value field
|
||||
* contains the comment string without the comment
|
||||
* start and end symbols.
|
||||
*/
|
||||
public static final int COMMENT = -3;
|
||||
/**
|
||||
* Token type indicating end of input.
|
||||
*/
|
||||
public static final int EOF = -4;
|
||||
private int type;
|
||||
private String value;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param type Token type
|
||||
* @param value Token value
|
||||
*/
|
||||
public Token(int type, String value) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the type of the token. If the token represents a
|
||||
* delimiter or a control character, the type is that character
|
||||
* itself, converted to an integer. Otherwise, it's value is
|
||||
* one of the following:
|
||||
* <ul>
|
||||
* <li><code>ATOM</code> A sequence of ASCII characters
|
||||
* delimited by either SPACE, CTL, "(", <"> or the
|
||||
* specified SPECIALS
|
||||
* <li><code>QUOTEDSTRING</code> A sequence of ASCII characters
|
||||
* within quotes
|
||||
* <li><code>COMMENT</code> A sequence of ASCII characters
|
||||
* within "(" and ")".
|
||||
* <li><code>EOF</code> End of header
|
||||
* </ul>
|
||||
*
|
||||
* @return the token type
|
||||
*/
|
||||
public int getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of the token just read. When the current
|
||||
* token is a quoted string, this field contains the body of the
|
||||
* string, without the quotes. When the current token is a comment,
|
||||
* this field contains the body of the comment.
|
||||
*
|
||||
* @return token value
|
||||
*/
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,690 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.internet;
|
||||
|
||||
import jakarta.mail.Header;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.util.LineInputStream;
|
||||
import jakarta.mail.util.StreamProvider;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
|
||||
/**
|
||||
* InternetHeaders is a utility class that manages RFC822 style
|
||||
* headers. Given an RFC822 format message stream, it reads lines
|
||||
* until the blank line that indicates end of header. The input stream
|
||||
* is positioned at the start of the body. The lines are stored
|
||||
* within the object and can be extracted as either Strings or
|
||||
* {@link Header} objects. <p>
|
||||
* <p>
|
||||
* This class is mostly intended for service providers. MimeMessage
|
||||
* and MimeBody use this class for holding their headers.
|
||||
*
|
||||
* <hr> <strong>A note on RFC822 and MIME headers</strong><p>
|
||||
* <p>
|
||||
* RFC822 and MIME header fields <strong>must</strong> contain only
|
||||
* US-ASCII characters. If a header contains non US-ASCII characters,
|
||||
* it must be encoded as per the rules in RFC 2047. The MimeUtility
|
||||
* class provided in this package can be used to to achieve this.
|
||||
* Callers of the <code>setHeader</code>, <code>addHeader</code>, and
|
||||
* <code>addHeaderLine</code> methods are responsible for enforcing
|
||||
* the MIME requirements for the specified headers. In addition, these
|
||||
* header fields must be folded (wrapped) before being sent if they
|
||||
* exceed the line length limitation for the transport (1000 bytes for
|
||||
* SMTP). Received headers may have been folded. The application is
|
||||
* responsible for folding and unfolding headers as appropriate. <p>
|
||||
* <p>
|
||||
* The current implementation supports the System property
|
||||
* <code>mail.mime.ignorewhitespacelines</code>, which if set to true
|
||||
* will cause a line containing only whitespace to be considered
|
||||
* a blank line terminating the header.
|
||||
*
|
||||
* @author John Mani
|
||||
* @author Bill Shannon
|
||||
* @see MimeUtility
|
||||
*/
|
||||
|
||||
public class InternetHeaders {
|
||||
private static final boolean ignoreWhitespaceLines =
|
||||
MimeUtility.getBooleanSystemProperty("mail.mime.ignorewhitespacelines",
|
||||
false);
|
||||
/**
|
||||
* The actual list of Headers, including placeholder entries.
|
||||
* Placeholder entries are Headers with a null value and
|
||||
* are never seen by clients of the InternetHeaders class.
|
||||
* Placeholder entries are used to keep track of the preferred
|
||||
* order of headers. Headers are never actually removed from
|
||||
* the list, they're converted into placeholder entries.
|
||||
* New headers are added after existing headers of the same name
|
||||
* (or before in the case of <code>Received</code> and
|
||||
* <code>Return-Path</code> headers). If no existing header
|
||||
* or placeholder for the header is found, new headers are
|
||||
* added after the special placeholder with the name ":".
|
||||
*
|
||||
* @since JavaMail 1.4
|
||||
*/
|
||||
protected List<InternetHeader> headers;
|
||||
|
||||
/**
|
||||
* Create an empty InternetHeaders object. Placeholder entries
|
||||
* are inserted to indicate the preferred order of headers.
|
||||
*/
|
||||
public InternetHeaders() {
|
||||
headers = new ArrayList<>(40);
|
||||
headers.add(new InternetHeader("Return-Path", null));
|
||||
headers.add(new InternetHeader("Received", null));
|
||||
headers.add(new InternetHeader("Resent-Date", null));
|
||||
headers.add(new InternetHeader("Resent-From", null));
|
||||
headers.add(new InternetHeader("Resent-Sender", null));
|
||||
headers.add(new InternetHeader("Resent-To", null));
|
||||
headers.add(new InternetHeader("Resent-Cc", null));
|
||||
headers.add(new InternetHeader("Resent-Bcc", null));
|
||||
headers.add(new InternetHeader("Resent-Message-Id", null));
|
||||
headers.add(new InternetHeader("Date", null));
|
||||
headers.add(new InternetHeader("From", null));
|
||||
headers.add(new InternetHeader("Sender", null));
|
||||
headers.add(new InternetHeader("Reply-To", null));
|
||||
headers.add(new InternetHeader("To", null));
|
||||
headers.add(new InternetHeader("Cc", null));
|
||||
headers.add(new InternetHeader("Bcc", null));
|
||||
headers.add(new InternetHeader("Message-Id", null));
|
||||
headers.add(new InternetHeader("In-Reply-To", null));
|
||||
headers.add(new InternetHeader("References", null));
|
||||
headers.add(new InternetHeader("Subject", null));
|
||||
headers.add(new InternetHeader("Comments", null));
|
||||
headers.add(new InternetHeader("Keywords", null));
|
||||
headers.add(new InternetHeader("Errors-To", null));
|
||||
headers.add(new InternetHeader("MIME-Version", null));
|
||||
headers.add(new InternetHeader("Content-Type", null));
|
||||
headers.add(new InternetHeader("Content-Transfer-Encoding", null));
|
||||
headers.add(new InternetHeader("Content-MD5", null));
|
||||
headers.add(new InternetHeader(":", null));
|
||||
headers.add(new InternetHeader("Content-Length", null));
|
||||
headers.add(new InternetHeader("Status", null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse the given RFC822 message stream till the
|
||||
* blank line separating the header from the body. The input
|
||||
* stream is left positioned at the start of the body. The
|
||||
* header lines are stored internally. <p>
|
||||
* <p>
|
||||
* For efficiency, wrap a BufferedInputStream around the actual
|
||||
* input stream and pass it as the parameter. <p>
|
||||
* <p>
|
||||
* No placeholder entries are inserted; the original order of
|
||||
* the headers is preserved.
|
||||
*
|
||||
* @param is RFC822 input stream
|
||||
* @throws MessagingException for any I/O error reading the stream
|
||||
*/
|
||||
public InternetHeaders(InputStream is) throws MessagingException {
|
||||
this(is, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse the given RFC822 message stream till the
|
||||
* blank line separating the header from the body. The input
|
||||
* stream is left positioned at the start of the body. The
|
||||
* header lines are stored internally. <p>
|
||||
* <p>
|
||||
* For efficiency, wrap a BufferedInputStream around the actual
|
||||
* input stream and pass it as the parameter. <p>
|
||||
* <p>
|
||||
* No placeholder entries are inserted; the original order of
|
||||
* the headers is preserved.
|
||||
*
|
||||
* @param is RFC822 input stream
|
||||
* @param allowutf8 if UTF-8 encoded headers are allowed
|
||||
* @throws MessagingException for any I/O error reading the stream
|
||||
* @since JavaMail 1.6
|
||||
*/
|
||||
@SuppressWarnings("this-escape")
|
||||
public InternetHeaders(InputStream is, boolean allowutf8)
|
||||
throws MessagingException {
|
||||
headers = new ArrayList<>(40);
|
||||
load(is, allowutf8);
|
||||
}
|
||||
|
||||
/**
|
||||
* Is this line an empty (blank) line?
|
||||
*/
|
||||
private static boolean isEmpty(String line) {
|
||||
return line.isEmpty() || (ignoreWhitespaceLines && line.trim().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse the given RFC822 message stream till the
|
||||
* blank line separating the header from the body. Store the
|
||||
* header lines inside this InternetHeaders object. The order
|
||||
* of header lines is preserved. <p>
|
||||
* <p>
|
||||
* Note that the header lines are added into this InternetHeaders
|
||||
* object, so any existing headers in this object will not be
|
||||
* affected. Headers are added to the end of the existing list
|
||||
* of headers, in order.
|
||||
*
|
||||
* @param is RFC822 input stream
|
||||
* @throws MessagingException for any I/O error reading the stream
|
||||
*/
|
||||
public void load(InputStream is) throws MessagingException {
|
||||
load(is, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read and parse the given RFC822 message stream till the
|
||||
* blank line separating the header from the body. Store the
|
||||
* header lines inside this InternetHeaders object. The order
|
||||
* of header lines is preserved. <p>
|
||||
* <p>
|
||||
* Note that the header lines are added into this InternetHeaders
|
||||
* object, so any existing headers in this object will not be
|
||||
* affected. Headers are added to the end of the existing list
|
||||
* of headers, in order.
|
||||
*
|
||||
* @param is RFC822 input stream
|
||||
* @param allowutf8 if UTF-8 encoded headers are allowed
|
||||
* @throws MessagingException for any I/O error reading the stream
|
||||
* @since JavaMail 1.6
|
||||
*/
|
||||
public void load(InputStream is, boolean allowutf8)
|
||||
throws MessagingException {
|
||||
// Read header lines until a blank line. It is valid
|
||||
// to have BodyParts with no header lines.
|
||||
String line;
|
||||
LineInputStream lis = StreamProvider.provider().inputLineStream(is, allowutf8);
|
||||
String prevline = null; // the previous header line, as a string
|
||||
// a buffer to accumulate the header in, when we know it's needed
|
||||
StringBuilder lineBuffer = new StringBuilder();
|
||||
|
||||
try {
|
||||
// if the first line being read is a continuation line,
|
||||
// we ignore it if it's otherwise empty or we treat it as
|
||||
// a non-continuation line if it has non-whitespace content
|
||||
boolean first = true;
|
||||
do {
|
||||
line = lis.readLine();
|
||||
if (line != null &&
|
||||
(line.startsWith(" ") || line.startsWith("\t"))) {
|
||||
// continuation of header
|
||||
if (prevline != null) {
|
||||
lineBuffer.append(prevline);
|
||||
prevline = null;
|
||||
}
|
||||
if (first) {
|
||||
String lt = line.trim();
|
||||
if (lt.length() > 0)
|
||||
lineBuffer.append(lt);
|
||||
} else {
|
||||
if (lineBuffer.length() > 0)
|
||||
lineBuffer.append("\r\n");
|
||||
lineBuffer.append(line);
|
||||
}
|
||||
} else {
|
||||
// new header
|
||||
if (prevline != null)
|
||||
addHeaderLine(prevline);
|
||||
else if (lineBuffer.length() > 0) {
|
||||
// store previous header first
|
||||
addHeaderLine(lineBuffer.toString());
|
||||
lineBuffer.setLength(0);
|
||||
}
|
||||
prevline = line;
|
||||
}
|
||||
first = false;
|
||||
} while (line != null && !isEmpty(line));
|
||||
} catch (IOException ioex) {
|
||||
throw new MessagingException("Error in input stream", ioex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the values for the specified header. The
|
||||
* values are String objects. Returns <code>null</code>
|
||||
* if no headers with the specified name exist.
|
||||
*
|
||||
* @param name header name
|
||||
* @return array of header values, or null if none
|
||||
*/
|
||||
public String[] getHeader(String name) {
|
||||
Iterator<InternetHeader> e = headers.iterator();
|
||||
// XXX - should we just step through in index order?
|
||||
List<String> v = new ArrayList<>(); // accumulate return values
|
||||
|
||||
while (e.hasNext()) {
|
||||
InternetHeader h = e.next();
|
||||
if (name.equalsIgnoreCase(h.getName()) && h.line != null) {
|
||||
v.add(h.getValue());
|
||||
}
|
||||
}
|
||||
if (v.size() == 0)
|
||||
return (null);
|
||||
// convert List to an array for return
|
||||
String[] r = new String[v.size()];
|
||||
r = v.toArray(r);
|
||||
return (r);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the headers for this header name, returned as a single
|
||||
* String, with headers separated by the delimiter. If the
|
||||
* delimiter is <code>null</code>, only the first header is
|
||||
* returned. Returns <code>null</code>
|
||||
* if no headers with the specified name exist.
|
||||
*
|
||||
* @param delimiter delimiter
|
||||
* @param name header name
|
||||
* @return the value fields for all headers with
|
||||
* this name, or null if none
|
||||
*/
|
||||
public String getHeader(String name, String delimiter) {
|
||||
String[] s = getHeader(name);
|
||||
|
||||
if (s == null)
|
||||
return null;
|
||||
|
||||
if ((s.length == 1) || delimiter == null)
|
||||
return s[0];
|
||||
|
||||
StringBuilder r = new StringBuilder(s[0]);
|
||||
for (int i = 1; i < s.length; i++) {
|
||||
r.append(delimiter);
|
||||
r.append(s[i]);
|
||||
}
|
||||
return r.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the first header line that matches name
|
||||
* to have value, adding a new header if no existing header
|
||||
* matches. Remove all matching headers but the first. <p>
|
||||
* <p>
|
||||
* Note that RFC822 headers can only contain US-ASCII characters
|
||||
*
|
||||
* @param name header name
|
||||
* @param value header value
|
||||
*/
|
||||
public void setHeader(String name, String value) {
|
||||
boolean found = false;
|
||||
|
||||
for (int i = 0; i < headers.size(); i++) {
|
||||
InternetHeader h = headers.get(i);
|
||||
if (name.equalsIgnoreCase(h.getName())) {
|
||||
if (!found) {
|
||||
int j;
|
||||
if (h.line != null && (j = h.line.indexOf(':')) >= 0) {
|
||||
h.line = h.line.substring(0, j + 1) + " " + value;
|
||||
// preserves capitalization, spacing
|
||||
} else {
|
||||
h.line = name + ": " + value;
|
||||
}
|
||||
found = true;
|
||||
} else {
|
||||
headers.remove(i);
|
||||
i--; // have to look at i again
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!found) {
|
||||
addHeader(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a header with the specified name and value to the header list. <p>
|
||||
* <p>
|
||||
* The current implementation knows about the preferred order of most
|
||||
* well-known headers and will insert headers in that order. In
|
||||
* addition, it knows that <code>Received</code> headers should be
|
||||
* inserted in reverse order (newest before oldest), and that they
|
||||
* should appear at the beginning of the headers, preceeded only by
|
||||
* a possible <code>Return-Path</code> header. <p>
|
||||
* <p>
|
||||
* Note that RFC822 headers can only contain US-ASCII characters.
|
||||
*
|
||||
* @param name header name
|
||||
* @param value header value
|
||||
*/
|
||||
public void addHeader(String name, String value) {
|
||||
int pos = headers.size();
|
||||
boolean addReverse =
|
||||
name.equalsIgnoreCase("Received") ||
|
||||
name.equalsIgnoreCase("Return-Path");
|
||||
if (addReverse)
|
||||
pos = 0;
|
||||
for (int i = headers.size() - 1; i >= 0; i--) {
|
||||
InternetHeader h = headers.get(i);
|
||||
if (name.equalsIgnoreCase(h.getName())) {
|
||||
if (addReverse) {
|
||||
pos = i;
|
||||
} else {
|
||||
headers.add(i + 1, new InternetHeader(name, value));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// marker for default place to add new headers
|
||||
if (!addReverse && h.getName().equals(":"))
|
||||
pos = i;
|
||||
}
|
||||
headers.add(pos, new InternetHeader(name, value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove all header entries that match the given name
|
||||
*
|
||||
* @param name header name
|
||||
*/
|
||||
public void removeHeader(String name) {
|
||||
for (int i = 0; i < headers.size(); i++) {
|
||||
InternetHeader h = headers.get(i);
|
||||
if (name.equalsIgnoreCase(h.getName())) {
|
||||
h.line = null;
|
||||
//headers.remove(i);
|
||||
//i--; // have to look at i again
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the headers as an Enumeration of
|
||||
* {@link Header} objects.
|
||||
*
|
||||
* @return Enumeration of Header objects
|
||||
*/
|
||||
public Enumeration<Header> getAllHeaders() {
|
||||
return (new MatchHeaderEnum(headers, null, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all matching {@link Header} objects.
|
||||
*
|
||||
* @param names the headers to return
|
||||
* @return Enumeration of matching Header objects
|
||||
*/
|
||||
public Enumeration<Header> getMatchingHeaders(String[] names) {
|
||||
return (new MatchHeaderEnum(headers, names, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all non-matching {@link Header} objects.
|
||||
*
|
||||
* @param names the headers to not return
|
||||
* @return Enumeration of non-matching Header objects
|
||||
*/
|
||||
public Enumeration<Header> getNonMatchingHeaders(String[] names) {
|
||||
return (new MatchHeaderEnum(headers, names, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an RFC822 header line to the header store.
|
||||
* If the line starts with a space or tab (a continuation line),
|
||||
* add it to the last header line in the list. Otherwise,
|
||||
* append the new header line to the list. <p>
|
||||
* <p>
|
||||
* Note that RFC822 headers can only contain US-ASCII characters
|
||||
*
|
||||
* @param line raw RFC822 header line
|
||||
*/
|
||||
public void addHeaderLine(String line) {
|
||||
try {
|
||||
char c = line.charAt(0);
|
||||
if (c == ' ' || c == '\t') {
|
||||
InternetHeader h = headers.get(headers.size() - 1);
|
||||
h.line += "\r\n" + line;
|
||||
} else
|
||||
headers.add(new InternetHeader(line));
|
||||
} catch (StringIndexOutOfBoundsException e) {
|
||||
// line is empty, ignore it
|
||||
return;
|
||||
} catch (NoSuchElementException e) {
|
||||
// XXX - list is empty?
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all the header lines as an Enumeration of Strings.
|
||||
*
|
||||
* @return Enumeration of Strings of all header lines
|
||||
*/
|
||||
public Enumeration<String> getAllHeaderLines() {
|
||||
return (getNonMatchingHeaderLines(null));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all matching header lines as an Enumeration of Strings.
|
||||
*
|
||||
* @param names the headers to return
|
||||
* @return Enumeration of Strings of all matching header lines
|
||||
*/
|
||||
public Enumeration<String> getMatchingHeaderLines(String[] names) {
|
||||
return (new MatchStringEnum(headers, names, true));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return all non-matching header lines
|
||||
*
|
||||
* @param names the headers to not return
|
||||
* @return Enumeration of Strings of all non-matching header lines
|
||||
*/
|
||||
public Enumeration<String> getNonMatchingHeaderLines(String[] names) {
|
||||
return (new MatchStringEnum(headers, names, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* An individual internet header. This class is only used by
|
||||
* subclasses of InternetHeaders. <p>
|
||||
* <p>
|
||||
* An InternetHeader object with a null value is used as a placeholder
|
||||
* for headers of that name, to preserve the order of headers.
|
||||
* A placeholder InternetHeader object with a name of ":" marks
|
||||
* the location in the list of headers where new headers are
|
||||
* added by default.
|
||||
*
|
||||
* @since JavaMail 1.4
|
||||
*/
|
||||
protected static final class InternetHeader extends Header {
|
||||
/*
|
||||
* Note that the value field from the superclass
|
||||
* isn't used in this class. We extract the value
|
||||
* from the line field as needed. We store the line
|
||||
* rather than just the value to ensure that we can
|
||||
* get back the exact original line, with the original
|
||||
* whitespace, etc.
|
||||
*/
|
||||
String line; // the entire RFC822 header "line",
|
||||
// or null if placeholder
|
||||
|
||||
/**
|
||||
* Constructor that takes a line and splits out
|
||||
* the header name.
|
||||
*
|
||||
* @param l the header line
|
||||
*/
|
||||
public InternetHeader(String l) {
|
||||
super("", ""); // XXX - we'll change it later
|
||||
int i = l.indexOf(':');
|
||||
if (i < 0) {
|
||||
// should never happen
|
||||
name = l.trim();
|
||||
} else {
|
||||
name = l.substring(0, i).trim();
|
||||
}
|
||||
line = l;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor that takes a header name and value.
|
||||
*
|
||||
* @param n the name of the header
|
||||
* @param v the value of the header
|
||||
*/
|
||||
public InternetHeader(String n, String v) {
|
||||
super(n, "");
|
||||
if (v != null)
|
||||
line = n + ": " + v;
|
||||
else
|
||||
line = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the "value" part of the header line.
|
||||
*/
|
||||
@Override
|
||||
public String getValue() {
|
||||
int i = line.indexOf(':');
|
||||
if (i < 0)
|
||||
return line;
|
||||
// skip whitespace after ':'
|
||||
int j;
|
||||
for (j = i + 1; j < line.length(); j++) {
|
||||
char c = line.charAt(j);
|
||||
if (!(c == ' ' || c == '\t' || c == '\r' || c == '\n'))
|
||||
break;
|
||||
}
|
||||
return line.substring(j);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* The enumeration object used to enumerate an
|
||||
* InternetHeaders object. Can return
|
||||
* either a String or a Header object.
|
||||
*/
|
||||
static class MatchEnum {
|
||||
private Iterator<InternetHeader> e; // enum object of headers List
|
||||
// XXX - is this overkill? should we step through in index
|
||||
// order instead?
|
||||
private String[] names; // names to match, or not
|
||||
private boolean match; // return matching headers?
|
||||
private boolean want_line; // return header lines?
|
||||
private InternetHeader next_header; // the next header to be returned
|
||||
|
||||
/*
|
||||
* Constructor. Initialize the enumeration for the entire
|
||||
* List of headers, the set of headers, whether to return
|
||||
* matching or non-matching headers, and whether to return
|
||||
* header lines or Header objects.
|
||||
*/
|
||||
MatchEnum(List<InternetHeader> v, String[] n, boolean m, boolean l) {
|
||||
e = v.iterator();
|
||||
names = n;
|
||||
match = m;
|
||||
want_line = l;
|
||||
next_header = null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Any more elements in this enumeration?
|
||||
*/
|
||||
public boolean hasMoreElements() {
|
||||
// if necessary, prefetch the next matching header,
|
||||
// and remember it.
|
||||
if (next_header == null)
|
||||
next_header = nextMatch();
|
||||
return next_header != null;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next element.
|
||||
*/
|
||||
public Object nextElement() {
|
||||
if (next_header == null)
|
||||
next_header = nextMatch();
|
||||
|
||||
if (next_header == null)
|
||||
throw new NoSuchElementException("No more headers");
|
||||
|
||||
InternetHeader h = next_header;
|
||||
next_header = null;
|
||||
if (want_line)
|
||||
return h.line;
|
||||
else
|
||||
return new Header(h.getName(), h.getValue());
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the next Header object according to the match
|
||||
* criteria, or null if none left.
|
||||
*/
|
||||
private InternetHeader nextMatch() {
|
||||
next:
|
||||
while (e.hasNext()) {
|
||||
InternetHeader h = e.next();
|
||||
|
||||
// skip "place holder" headers
|
||||
if (h.line == null)
|
||||
continue;
|
||||
|
||||
// if no names to match against, return appropriately
|
||||
if (names == null)
|
||||
return match ? null : h;
|
||||
|
||||
// check whether this header matches any of the names
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
if (names[i].equalsIgnoreCase(h.getName())) {
|
||||
if (match)
|
||||
return h;
|
||||
else
|
||||
// found a match, but we're
|
||||
// looking for non-matches.
|
||||
// try next header.
|
||||
continue next;
|
||||
}
|
||||
}
|
||||
// found no matches. if that's what we wanted, return it.
|
||||
if (!match)
|
||||
return h;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
static class MatchStringEnum extends MatchEnum
|
||||
implements Enumeration<String> {
|
||||
|
||||
MatchStringEnum(List<InternetHeader> v, String[] n, boolean m) {
|
||||
super(v, n, m, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String nextElement() {
|
||||
return (String) super.nextElement();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static class MatchHeaderEnum extends MatchEnum
|
||||
implements Enumeration<Header> {
|
||||
|
||||
MatchHeaderEnum(List<InternetHeader> v, String[] n, boolean m) {
|
||||
super(v, n, m, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Header nextElement() {
|
||||
return (Header) super.nextElement();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -1,990 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.internet;
|
||||
|
||||
import java.text.DateFormatSymbols;
|
||||
import java.text.FieldPosition;
|
||||
import java.text.NumberFormat;
|
||||
import java.text.ParseException;
|
||||
import java.text.ParsePosition;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.TimeZone;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Formats and parses date specification based on
|
||||
* <a href="http://www.ietf.org/rfc/rfc2822.txt" target="_top">RFC 2822</a>. <p>
|
||||
* <p>
|
||||
* This class does not support methods that influence the format. It always
|
||||
* formats the date based on the specification below.<p>
|
||||
* <p>
|
||||
* 3.3. Date and Time Specification
|
||||
* <p>
|
||||
* Date and time occur in several header fields. This section specifies
|
||||
* the syntax for a full date and time specification. Though folding
|
||||
* white space is permitted throughout the date-time specification, it is
|
||||
* RECOMMENDED that a single space be used in each place that FWS appears
|
||||
* (whether it is required or optional); some older implementations may
|
||||
* not interpret other occurrences of folding white space correctly.
|
||||
* <pre>
|
||||
* date-time = [ day-of-week "," ] date FWS time [CFWS]
|
||||
*
|
||||
* day-of-week = ([FWS] day-name) / obs-day-of-week
|
||||
*
|
||||
* day-name = "Mon" / "Tue" / "Wed" / "Thu" /
|
||||
* "Fri" / "Sat" / "Sun"
|
||||
*
|
||||
* date = day month year
|
||||
*
|
||||
* year = 4*DIGIT / obs-year
|
||||
*
|
||||
* month = (FWS month-name FWS) / obs-month
|
||||
*
|
||||
* month-name = "Jan" / "Feb" / "Mar" / "Apr" /
|
||||
* "May" / "Jun" / "Jul" / "Aug" /
|
||||
* "Sep" / "Oct" / "Nov" / "Dec"
|
||||
*
|
||||
* day = ([FWS] 1*2DIGIT) / obs-day
|
||||
*
|
||||
* time = time-of-day FWS zone
|
||||
*
|
||||
* time-of-day = hour ":" minute [ ":" second ]
|
||||
*
|
||||
* hour = 2DIGIT / obs-hour
|
||||
*
|
||||
* minute = 2DIGIT / obs-minute
|
||||
*
|
||||
* second = 2DIGIT / obs-second
|
||||
*
|
||||
* zone = (( "+" / "-" ) 4DIGIT) / obs-zone
|
||||
* </pre>
|
||||
* The day is the numeric day of the month. The year is any numeric year
|
||||
* 1900 or later.
|
||||
* <p>
|
||||
* The time-of-day specifies the number of hours, minutes, and optionally
|
||||
* seconds since midnight of the date indicated.
|
||||
* <p>
|
||||
* The date and time-of-day SHOULD express local time.
|
||||
* <p>
|
||||
* The zone specifies the offset from Coordinated Universal Time (UTC,
|
||||
* formerly referred to as "Greenwich Mean Time") that the date and
|
||||
* time-of-day represent. The "+" or "-" indicates whether the
|
||||
* time-of-day is ahead of (i.e., east of) or behind (i.e., west of)
|
||||
* Universal Time. The first two digits indicate the number of hours
|
||||
* difference from Universal Time, and the last two digits indicate the
|
||||
* number of minutes difference from Universal Time. (Hence, +hhmm means
|
||||
* +(hh * 60 + mm) minutes, and -hhmm means -(hh * 60 + mm) minutes). The
|
||||
* form "+0000" SHOULD be used to indicate a time zone at Universal Time.
|
||||
* Though "-0000" also indicates Universal Time, it is used to indicate
|
||||
* that the time was generated on a system that may be in a local time
|
||||
* zone other than Universal Time and therefore indicates that the
|
||||
* date-time contains no information about the local time zone.
|
||||
* <p>
|
||||
* A date-time specification MUST be semantically valid. That is, the
|
||||
* day-of-the-week (if included) MUST be the day implied by the date, the
|
||||
* numeric day-of-month MUST be between 1 and the number of days allowed
|
||||
* for the specified month (in the specified year), the time-of-day MUST
|
||||
* be in the range 00:00:00 through 23:59:60 (the number of seconds
|
||||
* allowing for a leap second; see [STD12]), and the zone MUST be within
|
||||
* the range -9959 through +9959.
|
||||
*
|
||||
* <h2><a id="synchronization">Synchronization</a></h2>
|
||||
*
|
||||
* <p>
|
||||
* Date formats are not synchronized.
|
||||
* It is recommended to create separate format instances for each thread.
|
||||
* If multiple threads access a format concurrently, it must be synchronized
|
||||
* externally.
|
||||
*
|
||||
* @author Anthony Vanelverdinghe
|
||||
* @author Max Spivak
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MailDateFormat extends SimpleDateFormat {
|
||||
|
||||
private static final String PATTERN = "EEE, d MMM yyyy HH:mm:ss Z (z)";
|
||||
|
||||
private static final Logger logger = Logger.getLogger(MailDateFormat.class.getName());
|
||||
|
||||
private static final int UNKNOWN_DAY_NAME = -1;
|
||||
private static final TimeZone UTC = TimeZone.getTimeZone("UTC");
|
||||
private static final int LEAP_SECOND = 60;
|
||||
|
||||
/**
|
||||
* Create a new date format for the RFC2822 specification with lenient
|
||||
* parsing.
|
||||
*/
|
||||
public MailDateFormat() {
|
||||
super(PATTERN, Locale.US);
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the given date in the format specified by
|
||||
* RFC 2822 in the current TimeZone.
|
||||
*
|
||||
* @param date the Date object
|
||||
* @param dateStrBuf the formatted string
|
||||
* @param fieldPosition the current field position
|
||||
* @return StringBuffer the formatted String
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
@Override
|
||||
public StringBuffer format(Date date, StringBuffer dateStrBuf,
|
||||
FieldPosition fieldPosition) {
|
||||
return super.format(date, dateStrBuf, fieldPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given date in the format specified by
|
||||
* RFC 2822.
|
||||
* <ul>
|
||||
* <li>With strict parsing, obs-* tokens are unsupported. Lenient parsing
|
||||
* supports obs-year and obs-zone, with the exception of the 1-character
|
||||
* military time zones.
|
||||
* <li>The optional CFWS token at the end is not parsed.
|
||||
* <li>RFC 2822 specifies that a zone of "-0000" indicates that the
|
||||
* date-time contains no information about the local time zone. This class
|
||||
* uses the UTC time zone in this case.
|
||||
* </ul>
|
||||
*
|
||||
* @param text the formatted date to be parsed
|
||||
* @param pos the current parse position
|
||||
* @return Date the parsed date. In case of error, returns null.
|
||||
* @since JavaMail 1.2
|
||||
*/
|
||||
@Override
|
||||
public Date parse(String text, ParsePosition pos) {
|
||||
if (text == null || pos == null) {
|
||||
throw new NullPointerException();
|
||||
} else if (0 > pos.getIndex() || pos.getIndex() >= text.length()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return isLenient()
|
||||
? new Rfc2822LenientParser(text, pos).parse()
|
||||
: new Rfc2822StrictParser(text, pos).parse();
|
||||
}
|
||||
|
||||
/**
|
||||
* This method always throws an UnsupportedOperationException and should not
|
||||
* be used because RFC 2822 mandates a specific calendar.
|
||||
*
|
||||
* @throws UnsupportedOperationException if this method is invoked
|
||||
*/
|
||||
@Override
|
||||
public void setCalendar(Calendar newCalendar) {
|
||||
throw new UnsupportedOperationException("Method "
|
||||
+ "setCalendar() shouldn't be called");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method always throws an UnsupportedOperationException and should not
|
||||
* be used because RFC 2822 mandates a specific number format.
|
||||
*
|
||||
* @throws UnsupportedOperationException if this method is invoked
|
||||
*/
|
||||
@Override
|
||||
public void setNumberFormat(NumberFormat newNumberFormat) {
|
||||
throw new UnsupportedOperationException("Method "
|
||||
+ "setNumberFormat() shouldn't be called");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method always throws an UnsupportedOperationException and should not
|
||||
* be used because RFC 2822 mandates a specific pattern.
|
||||
*
|
||||
* @throws UnsupportedOperationException if this method is invoked
|
||||
* @since JavaMail 1.6
|
||||
*/
|
||||
@Override
|
||||
public void applyLocalizedPattern(String pattern) {
|
||||
throw new UnsupportedOperationException("Method "
|
||||
+ "applyLocalizedPattern() shouldn't be called");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method always throws an UnsupportedOperationException and should not
|
||||
* be used because RFC 2822 mandates a specific pattern.
|
||||
*
|
||||
* @throws UnsupportedOperationException if this method is invoked
|
||||
* @since JavaMail 1.6
|
||||
*/
|
||||
@Override
|
||||
public void applyPattern(String pattern) {
|
||||
throw new UnsupportedOperationException("Method "
|
||||
+ "applyPattern() shouldn't be called");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method allows serialization to change the pattern.
|
||||
*/
|
||||
private void superApplyPattern(String pattern) {
|
||||
super.applyPattern(pattern);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method always throws an UnsupportedOperationException and should not
|
||||
* be used because RFC 2822 mandates another strategy for interpreting
|
||||
* 2-digits years.
|
||||
*
|
||||
* @return the start of the 100-year period into which two digit years are
|
||||
* parsed
|
||||
* @throws UnsupportedOperationException if this method is invoked
|
||||
* @since JavaMail 1.6
|
||||
*/
|
||||
@Override
|
||||
public Date get2DigitYearStart() {
|
||||
throw new UnsupportedOperationException("Method "
|
||||
+ "get2DigitYearStart() shouldn't be called");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method always throws an UnsupportedOperationException and should not
|
||||
* be used because RFC 2822 mandates another strategy for interpreting
|
||||
* 2-digits years.
|
||||
*
|
||||
* @throws UnsupportedOperationException if this method is invoked
|
||||
* @since JavaMail 1.6
|
||||
*/
|
||||
@Override
|
||||
public void set2DigitYearStart(Date startDate) {
|
||||
throw new UnsupportedOperationException("Method "
|
||||
+ "set2DigitYearStart() shouldn't be called");
|
||||
}
|
||||
|
||||
/**
|
||||
* This method always throws an UnsupportedOperationException and should not
|
||||
* be used because RFC 2822 mandates specific date format symbols.
|
||||
*
|
||||
* @throws UnsupportedOperationException if this method is invoked
|
||||
* @since JavaMail 1.6
|
||||
*/
|
||||
@Override
|
||||
public void setDateFormatSymbols(DateFormatSymbols newFormatSymbols) {
|
||||
throw new UnsupportedOperationException("Method "
|
||||
+ "setDateFormatSymbols() shouldn't be called");
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date, as specified by the parameters.
|
||||
*
|
||||
* @return the date, as specified by the parameters
|
||||
* @throws IllegalArgumentException if this instance's Calendar is
|
||||
* non-lenient and any of the parameters have invalid values, or if dayName
|
||||
* is not consistent with day-month-year
|
||||
*/
|
||||
private Date toDate(int dayName, int day, int month, int year,
|
||||
int hour, int minute, int second, int zone) {
|
||||
if (second == LEAP_SECOND) {
|
||||
second = 59;
|
||||
}
|
||||
|
||||
TimeZone tz = calendar.getTimeZone();
|
||||
try {
|
||||
calendar.setTimeZone(UTC);
|
||||
calendar.clear();
|
||||
calendar.set(year, month, day, hour, minute, second);
|
||||
|
||||
if (dayName == UNKNOWN_DAY_NAME
|
||||
|| dayName == calendar.get(Calendar.DAY_OF_WEEK)) {
|
||||
calendar.add(Calendar.MINUTE, zone);
|
||||
return calendar.getTime();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Inconsistent day-name");
|
||||
}
|
||||
} finally {
|
||||
calendar.setTimeZone(tz);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This class provides the building blocks for date parsing.
|
||||
* <p>
|
||||
* It has the following invariants:
|
||||
* <ul>
|
||||
* <li>no exceptions are thrown, except for java.text.ParseException from
|
||||
* parse* methods
|
||||
* <li>when parse* throws ParseException OR get* returns INVALID_CHAR OR
|
||||
* skip* returns false OR peek* is invoked, then pos.getIndex() on method
|
||||
* exit is the same as it was on method entry
|
||||
* </ul>
|
||||
*/
|
||||
private static abstract class AbstractDateParser {
|
||||
|
||||
static final int INVALID_CHAR = -1;
|
||||
static final int MAX_YEAR_DIGITS = 8; // guarantees that:
|
||||
// year < new GregorianCalendar().getMaximum(Calendar.YEAR)
|
||||
|
||||
final String text;
|
||||
final ParsePosition pos;
|
||||
|
||||
AbstractDateParser(String text, ParsePosition pos) {
|
||||
this.text = text;
|
||||
this.pos = pos;
|
||||
}
|
||||
|
||||
final Date parse() {
|
||||
int startPosition = pos.getIndex();
|
||||
try {
|
||||
return tryParse();
|
||||
} catch (Exception e) { // == ParseException | RuntimeException e
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.log(Level.FINE, "Bad date: '" + text + "'", e);
|
||||
}
|
||||
pos.setErrorIndex(pos.getIndex());
|
||||
pos.setIndex(startPosition);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
abstract Date tryParse() throws ParseException;
|
||||
|
||||
/**
|
||||
* @return the java.util.Calendar constant for the parsed day name
|
||||
*/
|
||||
final int parseDayName() throws ParseException {
|
||||
switch (getChar()) {
|
||||
case 'S':
|
||||
if (skipPair('u', 'n')) {
|
||||
return Calendar.SUNDAY;
|
||||
} else if (skipPair('a', 't')) {
|
||||
return Calendar.SATURDAY;
|
||||
}
|
||||
break;
|
||||
case 'T':
|
||||
if (skipPair('u', 'e')) {
|
||||
return Calendar.TUESDAY;
|
||||
} else if (skipPair('h', 'u')) {
|
||||
return Calendar.THURSDAY;
|
||||
}
|
||||
break;
|
||||
case 'M':
|
||||
if (skipPair('o', 'n')) {
|
||||
return Calendar.MONDAY;
|
||||
}
|
||||
break;
|
||||
case 'W':
|
||||
if (skipPair('e', 'd')) {
|
||||
return Calendar.WEDNESDAY;
|
||||
}
|
||||
break;
|
||||
case 'F':
|
||||
if (skipPair('r', 'i')) {
|
||||
return Calendar.FRIDAY;
|
||||
}
|
||||
break;
|
||||
case INVALID_CHAR:
|
||||
throw new ParseException("Invalid day-name",
|
||||
pos.getIndex());
|
||||
}
|
||||
pos.setIndex(pos.getIndex() - 1);
|
||||
throw new ParseException("Invalid day-name", pos.getIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the java.util.Calendar constant for the parsed month name
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
final int parseMonthName(boolean caseSensitive) throws ParseException {
|
||||
switch (getChar()) {
|
||||
case 'j':
|
||||
if (caseSensitive) {
|
||||
break;
|
||||
}
|
||||
case 'J':
|
||||
if (skipChar('u') || (!caseSensitive && skipChar('U'))) {
|
||||
if (skipChar('l') || (!caseSensitive
|
||||
&& skipChar('L'))) {
|
||||
return Calendar.JULY;
|
||||
} else if (skipChar('n') || (!caseSensitive
|
||||
&& skipChar('N'))) {
|
||||
return Calendar.JUNE;
|
||||
} else {
|
||||
pos.setIndex(pos.getIndex() - 1);
|
||||
}
|
||||
} else if (skipPair('a', 'n') || (!caseSensitive
|
||||
&& skipAlternativePair('a', 'A', 'n', 'N'))) {
|
||||
return Calendar.JANUARY;
|
||||
}
|
||||
break;
|
||||
case 'm':
|
||||
if (caseSensitive) {
|
||||
break;
|
||||
}
|
||||
case 'M':
|
||||
if (skipChar('a') || (!caseSensitive && skipChar('A'))) {
|
||||
if (skipChar('r') || (!caseSensitive
|
||||
&& skipChar('R'))) {
|
||||
return Calendar.MARCH;
|
||||
} else if (skipChar('y') || (!caseSensitive
|
||||
&& skipChar('Y'))) {
|
||||
return Calendar.MAY;
|
||||
} else {
|
||||
pos.setIndex(pos.getIndex() - 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'a':
|
||||
if (caseSensitive) {
|
||||
break;
|
||||
}
|
||||
case 'A':
|
||||
if (skipPair('u', 'g') || (!caseSensitive
|
||||
&& skipAlternativePair('u', 'U', 'g', 'G'))) {
|
||||
return Calendar.AUGUST;
|
||||
} else if (skipPair('p', 'r') || (!caseSensitive
|
||||
&& skipAlternativePair('p', 'P', 'r', 'R'))) {
|
||||
return Calendar.APRIL;
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
if (caseSensitive) {
|
||||
break;
|
||||
}
|
||||
case 'D':
|
||||
if (skipPair('e', 'c') || (!caseSensitive
|
||||
&& skipAlternativePair('e', 'E', 'c', 'C'))) {
|
||||
return Calendar.DECEMBER;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
if (caseSensitive) {
|
||||
break;
|
||||
}
|
||||
case 'O':
|
||||
if (skipPair('c', 't') || (!caseSensitive
|
||||
&& skipAlternativePair('c', 'C', 't', 'T'))) {
|
||||
return Calendar.OCTOBER;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (caseSensitive) {
|
||||
break;
|
||||
}
|
||||
case 'S':
|
||||
if (skipPair('e', 'p') || (!caseSensitive
|
||||
&& skipAlternativePair('e', 'E', 'p', 'P'))) {
|
||||
return Calendar.SEPTEMBER;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
if (caseSensitive) {
|
||||
break;
|
||||
}
|
||||
case 'N':
|
||||
if (skipPair('o', 'v') || (!caseSensitive
|
||||
&& skipAlternativePair('o', 'O', 'v', 'V'))) {
|
||||
return Calendar.NOVEMBER;
|
||||
}
|
||||
break;
|
||||
case 'f':
|
||||
if (caseSensitive) {
|
||||
break;
|
||||
}
|
||||
case 'F':
|
||||
if (skipPair('e', 'b') || (!caseSensitive
|
||||
&& skipAlternativePair('e', 'E', 'b', 'B'))) {
|
||||
return Calendar.FEBRUARY;
|
||||
}
|
||||
break;
|
||||
case INVALID_CHAR:
|
||||
throw new ParseException("Invalid month", pos.getIndex());
|
||||
}
|
||||
pos.setIndex(pos.getIndex() - 1);
|
||||
throw new ParseException("Invalid month", pos.getIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the number of minutes to be added to the time in the local
|
||||
* time zone, in order to obtain the equivalent time in the UTC time
|
||||
* zone. Returns 0 if the date-time contains no information about the
|
||||
* local time zone.
|
||||
*/
|
||||
final int parseZoneOffset() throws ParseException {
|
||||
int sign = getChar();
|
||||
if (sign == '+' || sign == '-') {
|
||||
int offset = parseAsciiDigits(4, 4, true);
|
||||
if (!isValidZoneOffset(offset)) {
|
||||
pos.setIndex(pos.getIndex() - 5);
|
||||
throw new ParseException("Invalid zone", pos.getIndex());
|
||||
}
|
||||
|
||||
return ((sign == '+') ? -1 : 1)
|
||||
* (offset / 100 * 60 + offset % 100);
|
||||
} else if (sign != INVALID_CHAR) {
|
||||
pos.setIndex(pos.getIndex() - 1);
|
||||
}
|
||||
throw new ParseException("Invalid zone", pos.getIndex());
|
||||
}
|
||||
|
||||
boolean isValidZoneOffset(int offset) {
|
||||
return (offset % 100) < 60;
|
||||
}
|
||||
|
||||
final int parseAsciiDigits(int count) throws ParseException {
|
||||
return parseAsciiDigits(count, count);
|
||||
}
|
||||
|
||||
final int parseAsciiDigits(int min, int max) throws ParseException {
|
||||
return parseAsciiDigits(min, max, false);
|
||||
}
|
||||
|
||||
final int parseAsciiDigits(int min, int max, boolean isEOF)
|
||||
throws ParseException {
|
||||
int result = 0;
|
||||
int nbDigitsParsed = 0;
|
||||
while (nbDigitsParsed < max && peekAsciiDigit()) {
|
||||
result = result * 10 + getAsciiDigit();
|
||||
nbDigitsParsed++;
|
||||
}
|
||||
|
||||
if ((nbDigitsParsed < min)
|
||||
|| (nbDigitsParsed == max && !isEOF && peekAsciiDigit())) {
|
||||
pos.setIndex(pos.getIndex() - nbDigitsParsed);
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
|
||||
String range = (min == max)
|
||||
? Integer.toString(min)
|
||||
: "between " + min + " and " + max;
|
||||
throw new ParseException("Invalid input: expected "
|
||||
+ range + " ASCII digits", pos.getIndex());
|
||||
}
|
||||
|
||||
final void parseFoldingWhiteSpace() throws ParseException {
|
||||
if (!skipFoldingWhiteSpace()) {
|
||||
throw new ParseException("Invalid input: expected FWS",
|
||||
pos.getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
final void parseChar(char ch) throws ParseException {
|
||||
if (!skipChar(ch)) {
|
||||
throw new ParseException("Invalid input: expected '" + ch + "'",
|
||||
pos.getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
final int getAsciiDigit() {
|
||||
int ch = getChar();
|
||||
if ('0' <= ch && ch <= '9') {
|
||||
return Character.digit((char) ch, 10);
|
||||
} else {
|
||||
if (ch != INVALID_CHAR) {
|
||||
pos.setIndex(pos.getIndex() - 1);
|
||||
}
|
||||
return INVALID_CHAR;
|
||||
}
|
||||
}
|
||||
|
||||
final int getChar() {
|
||||
if (pos.getIndex() < text.length()) {
|
||||
char ch = text.charAt(pos.getIndex());
|
||||
pos.setIndex(pos.getIndex() + 1);
|
||||
return ch;
|
||||
} else {
|
||||
return INVALID_CHAR;
|
||||
}
|
||||
}
|
||||
|
||||
boolean skipFoldingWhiteSpace() {
|
||||
// fast paths: a single ASCII space or no FWS
|
||||
if (skipChar(' ')) {
|
||||
if (!peekFoldingWhiteSpace()) {
|
||||
return true;
|
||||
} else {
|
||||
pos.setIndex(pos.getIndex() - 1);
|
||||
}
|
||||
} else if (!peekFoldingWhiteSpace()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// normal path
|
||||
int startIndex = pos.getIndex();
|
||||
if (skipWhiteSpace()) {
|
||||
while (skipNewline()) {
|
||||
if (!skipWhiteSpace()) {
|
||||
pos.setIndex(startIndex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else if (skipNewline() && skipWhiteSpace()) {
|
||||
return true;
|
||||
} else {
|
||||
pos.setIndex(startIndex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final boolean skipWhiteSpace() {
|
||||
int startIndex = pos.getIndex();
|
||||
while (skipAlternative(' ', '\t')) { /* empty */ }
|
||||
return pos.getIndex() > startIndex;
|
||||
}
|
||||
|
||||
final boolean skipNewline() {
|
||||
return skipPair('\r', '\n');
|
||||
}
|
||||
|
||||
final boolean skipAlternativeTriple(
|
||||
char firstStandard, char firstAlternative,
|
||||
char secondStandard, char secondAlternative,
|
||||
char thirdStandard, char thirdAlternative
|
||||
) {
|
||||
if (skipAlternativePair(firstStandard, firstAlternative,
|
||||
secondStandard, secondAlternative)) {
|
||||
if (skipAlternative(thirdStandard, thirdAlternative)) {
|
||||
return true;
|
||||
} else {
|
||||
pos.setIndex(pos.getIndex() - 2);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean skipAlternativePair(
|
||||
char firstStandard, char firstAlternative,
|
||||
char secondStandard, char secondAlternative
|
||||
) {
|
||||
if (skipAlternative(firstStandard, firstAlternative)) {
|
||||
if (skipAlternative(secondStandard, secondAlternative)) {
|
||||
return true;
|
||||
} else {
|
||||
pos.setIndex(pos.getIndex() - 1);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean skipAlternative(char standard, char alternative) {
|
||||
return skipChar(standard) || skipChar(alternative);
|
||||
}
|
||||
|
||||
final boolean skipPair(char first, char second) {
|
||||
if (skipChar(first)) {
|
||||
if (skipChar(second)) {
|
||||
return true;
|
||||
} else {
|
||||
pos.setIndex(pos.getIndex() - 1);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
final boolean skipChar(char ch) {
|
||||
if (pos.getIndex() < text.length()
|
||||
&& text.charAt(pos.getIndex()) == ch) {
|
||||
pos.setIndex(pos.getIndex() + 1);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
final boolean peekAsciiDigit() {
|
||||
return (pos.getIndex() < text.length()
|
||||
&& '0' <= text.charAt(pos.getIndex())
|
||||
&& text.charAt(pos.getIndex()) <= '9');
|
||||
}
|
||||
|
||||
boolean peekFoldingWhiteSpace() {
|
||||
return (pos.getIndex() < text.length()
|
||||
&& (text.charAt(pos.getIndex()) == ' '
|
||||
|| text.charAt(pos.getIndex()) == '\t'
|
||||
|| text.charAt(pos.getIndex()) == '\r'));
|
||||
}
|
||||
|
||||
final boolean peekChar(char ch) {
|
||||
return (pos.getIndex() < text.length()
|
||||
&& text.charAt(pos.getIndex()) == ch);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class Rfc2822StrictParser extends AbstractDateParser {
|
||||
|
||||
Rfc2822StrictParser(String text, ParsePosition pos) {
|
||||
super(text, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
Date tryParse() throws ParseException {
|
||||
int dayName = parseOptionalBegin();
|
||||
|
||||
int day = parseDay();
|
||||
int month = parseMonth();
|
||||
int year = parseYear();
|
||||
|
||||
parseFoldingWhiteSpace();
|
||||
|
||||
int hour = parseHour();
|
||||
parseChar(':');
|
||||
int minute = parseMinute();
|
||||
int second = (skipChar(':')) ? parseSecond() : 0;
|
||||
|
||||
parseFwsBetweenTimeOfDayAndZone();
|
||||
|
||||
int zone = parseZone();
|
||||
|
||||
try {
|
||||
return MailDateFormat.this.toDate(dayName, day, month, year,
|
||||
hour, minute, second, zone);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ParseException("Invalid input: some of the calendar "
|
||||
+ "fields have invalid values, or day-name is "
|
||||
+ "inconsistent with date", pos.getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the java.util.Calendar constant for the parsed day name, or
|
||||
* UNKNOWN_DAY_NAME iff the begin is missing
|
||||
*/
|
||||
int parseOptionalBegin() throws ParseException {
|
||||
int dayName;
|
||||
if (!peekAsciiDigit()) {
|
||||
skipFoldingWhiteSpace();
|
||||
dayName = parseDayName();
|
||||
parseChar(',');
|
||||
} else {
|
||||
dayName = UNKNOWN_DAY_NAME;
|
||||
}
|
||||
return dayName;
|
||||
}
|
||||
|
||||
int parseDay() throws ParseException {
|
||||
skipFoldingWhiteSpace();
|
||||
return parseAsciiDigits(1, 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the java.util.Calendar constant for the parsed month name
|
||||
*/
|
||||
int parseMonth() throws ParseException {
|
||||
parseFwsInMonth();
|
||||
int month = parseMonthName(isMonthNameCaseSensitive());
|
||||
parseFwsInMonth();
|
||||
return month;
|
||||
}
|
||||
|
||||
void parseFwsInMonth() throws ParseException {
|
||||
parseFoldingWhiteSpace();
|
||||
}
|
||||
|
||||
boolean isMonthNameCaseSensitive() {
|
||||
return true;
|
||||
}
|
||||
|
||||
int parseYear() throws ParseException {
|
||||
int year = parseAsciiDigits(4, MAX_YEAR_DIGITS);
|
||||
if (year >= 1900) {
|
||||
return year;
|
||||
} else {
|
||||
pos.setIndex(pos.getIndex() - 4);
|
||||
while (text.charAt(pos.getIndex() - 1) == '0') {
|
||||
pos.setIndex(pos.getIndex() - 1);
|
||||
}
|
||||
throw new ParseException("Invalid year", pos.getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
int parseHour() throws ParseException {
|
||||
return parseAsciiDigits(2);
|
||||
}
|
||||
|
||||
int parseMinute() throws ParseException {
|
||||
return parseAsciiDigits(2);
|
||||
}
|
||||
|
||||
int parseSecond() throws ParseException {
|
||||
return parseAsciiDigits(2);
|
||||
}
|
||||
|
||||
void parseFwsBetweenTimeOfDayAndZone() throws ParseException {
|
||||
parseFoldingWhiteSpace();
|
||||
}
|
||||
|
||||
int parseZone() throws ParseException {
|
||||
return parseZoneOffset();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class Rfc2822LenientParser extends Rfc2822StrictParser {
|
||||
|
||||
private Boolean hasDefaultFws;
|
||||
|
||||
Rfc2822LenientParser(String text, ParsePosition pos) {
|
||||
super(text, pos);
|
||||
}
|
||||
|
||||
@Override
|
||||
int parseOptionalBegin() {
|
||||
while (pos.getIndex() < text.length() && !peekAsciiDigit()) {
|
||||
pos.setIndex(pos.getIndex() + 1);
|
||||
}
|
||||
|
||||
return UNKNOWN_DAY_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
int parseDay() throws ParseException {
|
||||
skipFoldingWhiteSpace();
|
||||
return parseAsciiDigits(1, 3);
|
||||
}
|
||||
|
||||
@Override
|
||||
void parseFwsInMonth() throws ParseException {
|
||||
// '-' is allowed to accomodate for the date format as specified in
|
||||
// <a href="http://www.ietf.org/rfc/rfc3501.txt">RFC 3501</a>
|
||||
if (hasDefaultFws == null) {
|
||||
hasDefaultFws = !skipChar('-');
|
||||
skipFoldingWhiteSpace();
|
||||
} else if (hasDefaultFws) {
|
||||
skipFoldingWhiteSpace();
|
||||
} else {
|
||||
parseChar('-');
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isMonthNameCaseSensitive() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
int parseYear() throws ParseException {
|
||||
int year = parseAsciiDigits(1, MAX_YEAR_DIGITS);
|
||||
if (year >= 1000) {
|
||||
return year;
|
||||
} else if (year >= 50) {
|
||||
return year + 1900;
|
||||
} else {
|
||||
return year + 2000;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
int parseHour() throws ParseException {
|
||||
return parseAsciiDigits(1, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
int parseMinute() throws ParseException {
|
||||
return parseAsciiDigits(1, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
int parseSecond() throws ParseException {
|
||||
return parseAsciiDigits(1, 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
void parseFwsBetweenTimeOfDayAndZone() throws ParseException {
|
||||
skipFoldingWhiteSpace();
|
||||
}
|
||||
|
||||
@Override
|
||||
int parseZone() throws ParseException {
|
||||
try {
|
||||
if (pos.getIndex() >= text.length()) {
|
||||
throw new ParseException("Missing zone", pos.getIndex());
|
||||
}
|
||||
|
||||
if (peekChar('+') || peekChar('-')) {
|
||||
return parseZoneOffset();
|
||||
} else if (skipAlternativePair('U', 'u', 'T', 't')) {
|
||||
return 0;
|
||||
} else if (skipAlternativeTriple('G', 'g', 'M', 'm',
|
||||
'T', 't')) {
|
||||
return 0;
|
||||
} else {
|
||||
int hoursOffset;
|
||||
if (skipAlternative('E', 'e')) {
|
||||
hoursOffset = 4;
|
||||
} else if (skipAlternative('C', 'c')) {
|
||||
hoursOffset = 5;
|
||||
} else if (skipAlternative('M', 'm')) {
|
||||
hoursOffset = 6;
|
||||
} else if (skipAlternative('P', 'p')) {
|
||||
hoursOffset = 7;
|
||||
} else {
|
||||
throw new ParseException("Invalid zone",
|
||||
pos.getIndex());
|
||||
}
|
||||
if (skipAlternativePair('S', 's', 'T', 't')) {
|
||||
hoursOffset += 1;
|
||||
} else if (skipAlternativePair('D', 'd', 'T', 't')) {
|
||||
} else {
|
||||
pos.setIndex(pos.getIndex() - 1);
|
||||
throw new ParseException("Invalid zone",
|
||||
pos.getIndex());
|
||||
}
|
||||
return hoursOffset * 60;
|
||||
}
|
||||
} catch (ParseException e) {
|
||||
if (logger.isLoggable(Level.FINE)) {
|
||||
logger.log(Level.FINE, "No timezone? : '" + text + "'", e);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean isValidZoneOffset(int offset) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean skipFoldingWhiteSpace() {
|
||||
boolean result = peekFoldingWhiteSpace();
|
||||
|
||||
skipLoop:
|
||||
while (pos.getIndex() < text.length()) {
|
||||
switch (text.charAt(pos.getIndex())) {
|
||||
case ' ':
|
||||
case '\t':
|
||||
case '\r':
|
||||
case '\n':
|
||||
pos.setIndex(pos.getIndex() + 1);
|
||||
break;
|
||||
default:
|
||||
break skipLoop;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean peekFoldingWhiteSpace() {
|
||||
return super.peekFoldingWhiteSpace()
|
||||
|| (pos.getIndex() < text.length()
|
||||
&& text.charAt(pos.getIndex()) == '\n');
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,225 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 1997, 2023 Oracle and/or its affiliates. All rights reserved.
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Eclipse Public License v. 2.0, which is available at
|
||||
* http://www.eclipse.org/legal/epl-2.0.
|
||||
*
|
||||
* This Source Code may also be made available under the following Secondary
|
||||
* Licenses when the conditions for such availability set forth in the
|
||||
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
|
||||
* version 2 with the GNU Classpath Exception, which is available at
|
||||
* https://www.gnu.org/software/classpath/license.html.
|
||||
*
|
||||
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
|
||||
*/
|
||||
|
||||
package jakarta.mail.internet;
|
||||
|
||||
import jakarta.mail.IllegalWriteException;
|
||||
import jakarta.mail.MessagingException;
|
||||
import jakarta.mail.Part;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* The MimePart interface models an <strong>Entity</strong> as defined
|
||||
* by MIME (RFC2045, Section 2.4). <p>
|
||||
* <p>
|
||||
* MimePart extends the Part interface to add additional RFC822 and MIME
|
||||
* specific semantics and attributes. It provides the base interface for
|
||||
* the MimeMessage and MimeBodyPart classes
|
||||
*
|
||||
* <hr> <strong>A note on RFC822 and MIME headers</strong><p>
|
||||
* <p>
|
||||
* RFC822 and MIME header fields <strong>must</strong> contain only
|
||||
* US-ASCII characters. If a header contains non US-ASCII characters,
|
||||
* it must be encoded as per the rules in RFC 2047. The MimeUtility
|
||||
* class provided in this package can be used to to achieve this.
|
||||
* Callers of the <code>setHeader</code>, <code>addHeader</code>, and
|
||||
* <code>addHeaderLine</code> methods are responsible for enforcing
|
||||
* the MIME requirements for the specified headers. In addition, these
|
||||
* header fields must be folded (wrapped) before being sent if they
|
||||
* exceed the line length limitation for the transport (1000 bytes for
|
||||
* SMTP). Received headers may have been folded. The application is
|
||||
* responsible for folding and unfolding headers as appropriate.
|
||||
*
|
||||
* @author John Mani
|
||||
* @see MimeUtility
|
||||
* @see Part
|
||||
*/
|
||||
|
||||
public interface MimePart extends Part {
|
||||
|
||||
/**
|
||||
* Get the values of all header fields available for this header,
|
||||
* returned as a single String, with the values separated by the
|
||||
* delimiter. If the delimiter is <code>null</code>, only the
|
||||
* first value is returned.
|
||||
*
|
||||
* @param name the name of this header
|
||||
* @param delimiter delimiter between fields in returned string
|
||||
* @return the value fields for all headers with
|
||||
* this name
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
String getHeader(String name, String delimiter)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Add a raw RFC822 header-line.
|
||||
*
|
||||
* @param line the line to add
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* @throws IllegalStateException if this Part is
|
||||
* obtained from a READ_ONLY folder
|
||||
* @throws MessagingException for other failures
|
||||
*/
|
||||
void addHeaderLine(String line) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get all header lines as an Enumeration of Strings. A Header
|
||||
* line is a raw RFC822 header-line, containing both the "name"
|
||||
* and "value" field.
|
||||
*
|
||||
* @return an Enumeration of Strings
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
Enumeration<String> getAllHeaderLines() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get matching header lines as an Enumeration of Strings.
|
||||
* A Header line is a raw RFC822 header-line, containing both
|
||||
* the "name" and "value" field.
|
||||
*
|
||||
* @param names the headers to return
|
||||
* @return an Enumeration of Strings
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
Enumeration<String> getMatchingHeaderLines(String[] names)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get non-matching header lines as an Enumeration of Strings.
|
||||
* A Header line is a raw RFC822 header-line, containing both
|
||||
* the "name" and "value" field.
|
||||
*
|
||||
* @param names the headers to not return
|
||||
* @return an Enumeration of Strings
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
Enumeration<String> getNonMatchingHeaderLines(String[] names)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get the transfer encoding of this part.
|
||||
*
|
||||
* @return content-transfer-encoding
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
String getEncoding() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get the Content-ID of this part. Returns null if none present.
|
||||
*
|
||||
* @return content-ID
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
String getContentID() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get the Content-MD5 digest of this part. Returns null if
|
||||
* none present.
|
||||
*
|
||||
* @return content-MD5
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
String getContentMD5() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Set the Content-MD5 of this part.
|
||||
*
|
||||
* @param md5 the MD5 value
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* @throws IllegalStateException if this Part is
|
||||
* obtained from a READ_ONLY folder
|
||||
*/
|
||||
void setContentMD5(String md5) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Get the language tags specified in the Content-Language header
|
||||
* of this MimePart. The Content-Language header is defined by
|
||||
* RFC 1766. Returns <code>null</code> if this header is not
|
||||
* available.
|
||||
*
|
||||
* @return array of content language strings
|
||||
* @throws MessagingException for failures
|
||||
*/
|
||||
String[] getContentLanguage() throws MessagingException;
|
||||
|
||||
/**
|
||||
* Set the Content-Language header of this MimePart. The
|
||||
* Content-Language header is defined by RFC1766.
|
||||
*
|
||||
* @param languages array of language tags
|
||||
* @throws IllegalWriteException if the underlying
|
||||
* implementation does not support modification
|
||||
* @throws IllegalStateException if this Part is
|
||||
* obtained from a READ_ONLY folder
|
||||
*/
|
||||
void setContentLanguage(String[] languages)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Convenience method that sets the given String as this
|
||||
* part's content, with a MIME type of "text/plain". If the
|
||||
* string contains non US-ASCII characters. it will be encoded
|
||||
* using the platform's default charset. The charset is also
|
||||
* used to set the "charset" parameter. <p>
|
||||
* <p>
|
||||
* Note that there may be a performance penalty if
|
||||
* <code>text</code> is large, since this method may have
|
||||
* to scan all the characters to determine what charset to
|
||||
* use. <p>
|
||||
* <p>
|
||||
* If the charset is already known, use the
|
||||
* <code>setText</code> method that takes the charset parameter.
|
||||
*
|
||||
* @param text the text content to set
|
||||
* @throws MessagingException if an error occurs
|
||||
* @see #setText(String text, String charset)
|
||||
*/
|
||||
@Override
|
||||
void setText(String text) throws MessagingException;
|
||||
|
||||
/**
|
||||
* Convenience method that sets the given String as this part's
|
||||
* content, with a MIME type of "text/plain" and the specified
|
||||
* charset. The given Unicode string will be charset-encoded
|
||||
* using the specified charset. The charset is also used to set
|
||||
* "charset" parameter.
|
||||
*
|
||||
* @param text the text content to set
|
||||
* @param charset the charset to use for the text
|
||||
* @throws MessagingException if an error occurs
|
||||
*/
|
||||
void setText(String text, String charset)
|
||||
throws MessagingException;
|
||||
|
||||
/**
|
||||
* Convenience method that sets the given String as this part's
|
||||
* content, with a primary MIME type of "text" and the specified
|
||||
* MIME subtype. The given Unicode string will be charset-encoded
|
||||
* using the specified charset. The charset is also used to set
|
||||
* the "charset" parameter.
|
||||
*
|
||||
* @param text the text content to set
|
||||
* @param charset the charset to use for the text
|
||||
* @param subtype the MIME subtype to use (e.g., "html")
|
||||
* @throws MessagingException if an error occurs
|
||||
* @since JavaMail 1.4
|
||||
*/
|
||||
void setText(String text, String charset, String subtype)
|
||||
throws MessagingException;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue